/*
 * Componenten.
 *
 * Elke component traceert naar ux-onderzoek/steal-sheet-home.md. Waarden komen uit
 * het brandbook (afgelezen uit het vorige thema en geverifieerd) of uit een
 * gemeten referentie; waar het laatste geldt staat de bron in het commentaar.
 *
 * Beweging: alles op transform en opacity, duren uit het brandbook, easing
 * gemeten bij Moooi. Wie beweging vermijdt krijgt geen beweging, zie base.css.
 */

/* =======================================================================
 * Typografische bouwstenen
 * ======================================================================= */

/* De wordmark. De getypeerde vorm is sinds 20 augustus de terugval: als het
   logobestand ontbreekt staat er tekst in plaats van een lege link. */
.wordmark {
	font-family: var(--font-serif);
	font-size: 1.5rem;
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-tighter);
	line-height: 1;
	text-transform: uppercase;
	margin: 0;
}

.wordmark a {
	display: inline-block;
	text-decoration: none;

	/* Het enige klikbare element dat geen hover had. Fase 5b vraagt hover op alles
	   klikbaars, en een logo dat naar home leidt hoort dat te laten merken. */
	transition: opacity var(--duration-base) var(--ease-out);
}

.wordmark a:focus-visible {
	opacity: 0.7;
}

@media (hover: hover) {

	.wordmark a:hover {
		opacity: 0.7;
	}
}

/*
 * Het logo is staand: FABRIEK klein boven een grote 59. Onder de 40px valt het
 * bovenwoord weg, gemeten op de proef van 20 augustus, dus 40px is de bodem en
 * niet een gekozen ronde waarde. De hoogte staat in CSS en de breedte op auto,
 * zodat de verhouding klopt bij elke maat.
 */
.wordmark--logo {
	display: flex;
	line-height: 0;
}

.wordmark__logo {
	display: block;
	width: auto;
	height: 40px;
	transition: height var(--duration-chrome) var(--ease-out);
}

/* In em, om dezelfde reden als de navigatie verderop: het woordmerk hoort bij
   de balk en die wisselt op 56.25em. */
@media (min-width: 56.25em) {
	.wordmark__logo { height: 48px; }
}

/* Meegekrompen met de header, zodat de balk bij het scrollen echt dunner wordt
   in plaats van dat het logo de oude hoogte vasthoudt. */
.site-header.is-scrolled .wordmark__logo { height: 36px; }

@media (min-width: 56.25em) {
	.site-header.is-scrolled .wordmark__logo { height: 40px; }
}

/* De 59 in het rood, zoals het oude thema deed. Alleen op licht leesbaar, dus
   op donker blijft de wordmark eenkleurig: rood op donker haalt 2,9:1. */
.section-light .wordmark em,
.wordmark--red em {
	color: var(--color-red);
	font-family: inherit;
	font-style: normal;
}

/*
 * Label, twee maten.
 * .label      12px/0.1em  voor een badge of knoptekst van een of twee woorden
 * .label--lg  14px/0.08em voor een categorielabel dat gelezen moet worden
 * Bron voor de 14px-variant: Moooi h3, gemeten op 14px/700/0.06em uppercase.
 */
.label {
	display: inline-block;
	font-family: var(--font-sans);
	font-size: var(--text-button);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-widest);
	line-height: 1.2;
	text-transform: uppercase;
}

.label--lg {
	font-size: var(--text-label);
	letter-spacing: var(--tracking-wide);
}

.label--red { color: var(--color-red); }

/*
 * Het categorielabel op een bedrijfskaart: gedempte tekst met een rode streep
 * erboven, zoals in het goedgekeurde prototype.
 *
 * Het stond in --color-red, en dat haalt op de kaartgrond 2,9:1 waar 4,5:1 nodig
 * is. Rood draagt hier nu de streep en niet de letters, en dat is precies de
 * regel uit tokens.css: dit rood is decoratie, geen tekst.
 *
 * DE STREEP IS 3,5REM, DE TEKST NIET. Dat onderscheid heeft twee keer een woord
 * gebroken voordat het hier stond.
 *
 * Deze regel stond op `width: 3.5rem`, dus de streepmaat was ook de tekstmaat: 56px
 * voor het woord eronder. Zolang er niets brak viel dat niet op, want een woord dat
 * niet past liep gewoon door over de kaart. Sinds `overflow-wrap: anywhere` op de
 * body (zie base.css) breekt het wel, en dan staat er "HOREC / A" en "SHOW / ROOM".
 * Gemeten op 8 september 2026 op de bedrijvenband van de homepage: labelhoogte 31px
 * met de oude CSS tegen 48px met de nieuwe, dus een regel erbij op drie van de vier
 * kaarten.
 *
 * Op 8 september was ditzelfde al een keer gerepareerd voor de datum op een
 * nieuwskaart, die over drie regels brak ("6", "SEPTEMBER", "2026"), maar toen
 * alleen voor `.card__datum` en niet voor het categoriewoord ernaast. Nu draagt de
 * basisregel de oplossing: de streep zit in een ::before op 3,5rem, en het label
 * zelf is zo breed als de kaartbody. Een tweede uitzondering voor de datum is
 * daarmee overbodig geworden.
 */
.card .label--red {
	display: block;
	color: var(--text-on-dark-muted);
}

.card .label--red::before {
	content: '';
	display: block;
	width: 3.5rem;
	margin-bottom: 0.75rem;
	border-top: 2px solid var(--color-red);
}

.section-light .card .label--red {
	color: var(--text-on-light-muted);
}

/* Op donker wordt het label niet rood maar crème: rood haalt daar 2,9:1. */
.section-dark .label--red,
.section-shadow .label--red,
.section-deep .label--red {
	color: var(--color-cream);
}

/* De eyebrow-pill: een label boven een kop, met een rode linkerrand. */
/*
 * De eyebrow zoals in het goedgekeurde prototype: gedempte tekst met een rode
 * streep erachter, geen plaatje met een rode kantlijn.
 *
 * De plaat-variant stond hier eerst en werd nergens gebruikt; deze component is
 * op 21 augustus 2026 pas op drie secties gezet, en toen bleek dat de plaat er
 * naast de kop uitspringt terwijl het ontwerp juist een rustige aankondiging
 * wil. De streep draagt het rood, de letters niet: op donker haalt #b22222 maar
 * 2,9:1.
 */
.eyebrow {
	display: flex;
	align-items: center;
	gap: 0.875rem;
	margin: 0 0 var(--gap-sm);
	font-family: var(--font-sans);
	font-size: var(--text-label);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-widest);
	text-transform: uppercase;
	color: var(--text-on-dark-muted);
}

.eyebrow::after {
	content: '';
	height: 2px;
	width: 3.5rem;
	background-color: var(--color-red);
}

.section-light .eyebrow,
.section-brick-light .eyebrow {
	color: var(--text-on-light-muted);
}

/* Sectietitel, statement en label: de drie kopvarianten uit het brandbook. */
.section-title {
	font-family: var(--font-serif);
	font-size: var(--text-h2-large);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-tighter);
	line-height: var(--leading-tight);
	text-transform: uppercase;
	margin: 0;
}

.section-statement {
	font-family: var(--font-serif);
	font-size: var(--text-h2);
	font-weight: var(--weight-semibold);
	letter-spacing: var(--tracking-tighter);
	line-height: var(--leading-snug);
	margin: 0;
}

/*
 * De italic serif als sectielabel, met een rode linkerrand. Merksignaal. Sinds
 * 14 oktober 2026 door geen template meer gebruikt: de binnenpagina's staan op
 * .section-title met .divider eronder, zoals Home. Zie de styleguide, 5.5.
 */
.section-label {
	font-family: var(--font-serif);
	font-size: var(--text-h2-label);
	font-style: italic;
	font-weight: var(--weight-semibold);
	text-transform: uppercase;
	line-height: var(--leading-snug);
	border-left: 2px solid var(--color-red);
	padding-left: 1.5rem;
	margin: 0;
}

/* Het rode divider-streepje onder een gecentreerde kop. */
.divider {
	width: 60px;
	height: 3px;
	background-color: var(--color-red);
	border: 0;
	margin-block: var(--gap-sm);
}

.divider--center { margin-inline: auto; }

/* Lopende tekst binnen een sectie. */
.prose {
	max-width: var(--container-text);
}

.prose > * + * { margin-top: 1.25em; }

.prose p {
	line-height: var(--leading-loosest);
}

.lead {
	font-size: var(--text-body-lg);
	line-height: var(--leading-loose);
}

.muted { color: var(--text-on-dark-muted); }
.section-light .muted { color: var(--text-on-light-muted); }

/* De pull quote. */
.quote {
	font-family: var(--font-serif);
	font-style: italic;
	font-size: var(--text-h2);
	font-weight: var(--weight-semibold);
	line-height: var(--leading-relaxed);
	letter-spacing: var(--tracking-tighter);
	margin: 0;
}

/*
 * De bronregel stond op --text-button, dus 12px, terwijl de lopende tekst
 * eronder op 16px staat. Wie het citaat uitspreekt woog daarmee lichter dan de
 * uitleg erna, en bij een familiecitaat is dat de verkeerde volgorde. Punt H5 van
 * de feedback van 18 augustus: "de titel is kleiner dan de tekst die eronder
 * staat en dat vind ik een beetje raar". Nu groter dan de body, met de streepjes
 * uit het drukwerk van de periode ernaast.
 */
.quote__source {
	display: inline-flex;
	align-items: center;
	gap: var(--gap-sm);
	margin-top: var(--gap-md);
	font-family: var(--font-sans);
	font-size: clamp(1rem, 1.6vw, 1.25rem);
	font-style: normal;
	font-weight: var(--weight-semibold);
	letter-spacing: var(--tracking-wide);
	text-transform: uppercase;
	color: var(--text-on-light);
}

.quote__source::before,
.quote__source::after {
	content: '';
	flex: 0 0 auto;
	width: clamp(1.5rem, 5vw, 4rem);
	height: 1px;
	background-color: var(--color-red);
}

.section-dark .quote__source,
.section-shadow .quote__source,
.section-deep .quote__source {
	color: var(--text-on-dark);
}

/* =======================================================================
 * Knoppen
 *
 * Geen ronde hoeken, want scherp is de doctrine. Minimale raakhoogte 48px.
 * ======================================================================= */

.btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--gap-xs);
	min-height: var(--touch-min);
	padding: var(--button-py) var(--button-px);
	border: 0;
	border-radius: var(--radius-none);
	font-family: var(--font-sans);
	font-size: var(--text-button);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-widest);
	line-height: var(--leading-none);
	text-transform: uppercase;
	text-align: center;
	text-decoration: none;
	cursor: pointer;

	/*
	 * Twee regels tegen hetzelfde: een knop mag nooit breder worden dan zijn vak,
	 * en zijn opschrift breekt per WOORD en niet per letter.
	 *
	 * De body staat op `overflow-wrap: anywhere` (zie base.css) en dat is daar
	 * precies goed, maar op een knop pakt het verkeerd uit: bij 200 procent
	 * tekstvergroting werd "STUUR JE BERICHT" in een paneel van 182px een kolom
	 * van losse letters onder elkaar, omdat de knop dan 96px zijpadding draagt en
	 * er 86px overblijft. Met `break-word` valt hij terug op woorden.
	 *
	 * max-width houdt hem daarbij binnen zijn vak in plaats van de pagina op te
	 * rekken.
	 */
	max-width: 100%;
	overflow-wrap: break-word;

	transition:
		background-color var(--duration-button) var(--ease-out),
		box-shadow var(--duration-button) var(--ease-out),
		transform var(--duration-base) var(--ease-out);
}

/*
 * De hover is een stempel die over de knop wordt gezet, geen kleurwissel.
 *
 * Mechanisme gestolen bij Speakeasy (speakeasy.com, gemeten 18 augustus 2026): hun
 * navigatie-items hebben een ::before die van opacity 0 naar 1 gaat, dus het vlak
 * zit in een aparte laag en niet in background-color van de knop zelf. Dat is wat
 * een richting mogelijk maakt.
 *
 * De richting is van ons: scaleX vanaf de linkerrand, want dit merk gaat over
 * sorteren en stempelen op een baal, en een stempel komt van één kant. De duur en
 * de curve staan al vast in de tokens: 0.5s met de bij Moooi gemeten
 * cubic-bezier(0.19, 1, 0.22, 1).
 *
 * De pijl schuift 6px mee. Phantom (phantom.com, gemeten) doet zijn primaire knop
 * op 0.4s met dezelfde curve-familie en krimpt naar 0.985; dat krimpen zit hier al
 * op :active en wordt niet ook op hover gezet, want dan wordt het effect troebel.
 *
 * Een negatieve z-index tekent boven de eigen achtergrond en onder de tekst, dus
 * het label blijft leesbaar. isolation houdt de laag binnen de knop.
 */
.btn--primary {
	position: relative;
	isolation: isolate;
	overflow: hidden;
	background-color: var(--color-red);
	color: #ffffff;
	box-shadow: var(--shadow-button);
}

.btn--primary::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background-color: var(--color-red-hover);
	transform: scaleX(0);
	transform-origin: left center;
	transition: transform var(--duration-button) var(--ease-out);
}

.btn--primary:focus-visible::before {
	transform: scaleX(1);
}

@media (hover: hover) {

	.btn--primary:hover::before {
		transform: scaleX(1);
	}
}

.btn--primary:focus-visible {
	box-shadow: var(--shadow-button-hover);
}

@media (hover: hover) {

	.btn--primary:hover {
		box-shadow: var(--shadow-button-hover);
	}
}

.btn--primary .btn__arrow {
	transition: transform var(--duration-base) var(--ease-out);
}

.btn--primary:focus-visible .btn__arrow {
	transform: translateX(6px);
}

@media (hover: hover) {

	.btn--primary:hover .btn__arrow {
		transform: translateX(6px);
	}
}

.btn:active { transform: scale(0.98); }

/*
 * Ghost, voor donkere secties. Bij hover keert hij om: wit vlak, donkere tekst.
 * De rand staat op 0.35 en niet op 0.20 zoals in het oude thema: op 0.20 haalde
 * de rand geen 3:1 tegen de donkere grond en was de knop dus onzichtbaar tot
 * hover. Dat staat als must-fix op de anti-default-lijst.
 */
.btn--ghost {
	position: relative;
	isolation: isolate;
	overflow: hidden;
	background-color: transparent;
	color: var(--color-white);
	border: 1px solid color-mix(in srgb, var(--color-white) 35%, transparent);
	transition:
		color var(--duration-button) var(--ease-out),
		border-color var(--duration-button) var(--ease-out),
		transform var(--duration-base) var(--ease-out);
}

/* Dezelfde stempel, maar van onderaf: de ghost staat op donker en dit leest als
   inkt die optrekt. Één mechanisme, twee richtingen, zodat de twee knoppen naast
   elkaar niet hetzelfde doen. */
.btn--ghost::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background-color: var(--color-white);
	transform: scaleY(0);
	transform-origin: center bottom;
	transition: transform var(--duration-button) var(--ease-out);
}

.btn--ghost:focus-visible::before {
	transform: scaleY(1);
}

@media (hover: hover) {

	.btn--ghost:hover::before {
		transform: scaleY(1);
	}
}

.btn--ghost:focus-visible {
	color: var(--color-black);
	border-color: var(--color-white);
}

@media (hover: hover) {

	.btn--ghost:hover {
		color: var(--color-black);
		border-color: var(--color-white);
	}
}

/* Tekstlink met een pijl die opschuift. Voor secundaire acties op licht. */
.btn--text {
	min-height: auto;
	padding: 0.25rem 0;
	background: none;
	color: inherit;
	border-bottom: 2px solid var(--color-red);
	letter-spacing: var(--tracking-wide);
}

.btn--text .btn__arrow {
	transition: transform var(--duration-base) var(--ease-out);
}

.btn--text:focus-visible .btn__arrow {
	transform: translateX(4px);
}

@media (hover: hover) {

	.btn--text:hover .btn__arrow {
		transform: translateX(4px);
	}
}

/* =======================================================================
 * Beeld
 * ======================================================================= */

/* Ingelijst beeld: 4/3, kleine radius, schaduw en een scrim van onderaf. */
.frame {
	position: relative;
	overflow: hidden;
	border-radius: var(--radius-sm);
	box-shadow: var(--shadow-frame-dark);
	aspect-ratio: 4 / 3;
}

.section-light .frame { box-shadow: var(--shadow-frame-light); }

.frame img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.frame::after {
	content: '';
	position: absolute;
	inset: auto 0 0 0;
	height: 40%;
	background: linear-gradient(to top, color-mix(in srgb, var(--color-deep) 55%, transparent), transparent);
	pointer-events: none;
}

.frame--tall { aspect-ratio: 3 / 4; }
.frame--wide { aspect-ratio: 16 / 9; }

/* Het weefpatroon: diagonale hatch op 3 procent over een donkere sectie. */
.weave {
	position: relative;
	isolation: isolate;
}

.weave::before {
	content: '';
	position: absolute;
	inset: 0;
	z-index: -1;
	background-image: var(--pattern-weave);
	opacity: var(--pattern-weave-opacity);
	pointer-events: none;
}

/* Radiale gloed in de hoek van een lichte sectie. */
.glow {
	position: relative;
	isolation: isolate;
	overflow: hidden;
}

.glow::before {
	content: '';
	position: absolute;
	top: -12rem;
	right: -10rem;
	z-index: -1;
	width: 31.25rem;
	height: 31.25rem;
	border-radius: var(--radius-pill);
	background: radial-gradient(circle, var(--wash-red-soft), transparent 70%);
	pointer-events: none;
}

.gradient-dark { background: var(--gradient-dark); }

/* =======================================================================
 * De hero
 *
 * Drie lagen: beeld, waas, inhoud. De overscan van 1.05 zorgt dat de randen bij
 * de reveal nooit zichtbaar worden, en de container heeft daarom overflow hidden.
 * Dat staat hier op de hero en niet op de body: overflow op de body verbergt
 * horizontaal overloop overal, en dan kan de mobiele controle niet meer rood
 * worden.
 * ======================================================================= */

/*
 * De hero houdt zijn inhoud onder de vaste header vandaan.
 *
 * De padding zat op .hero__content en dat werkt niet: deze hero is een flexbox
 * met align-items: flex-end, en zodra de tekst hoger wordt dan de hero duwt die
 * uitlijning de inhoud omhoog, dwars door de padding en dwars door de header.
 * Op Contact bij 390 stond het label "CONTACT" daardoor precies over het logo,
 * en dat was geen randgeval: vijf van de zeven pagina's hadden het, op 390 én op
 * 1440. Alleen Home en Bedankt niet, want daar is de tekst korter.
 *
 * Op de container werkt het wel. De hero groeit dan mee met lange tekst in
 * plaats van eroverheen te lopen, want min-height rekent met border-box.
 * Gemeten op 20 augustus 2026 op alle zeven pagina's.
 */
.hero {
	position: relative;
	display: flex;
	align-items: flex-end;
	overflow: hidden;
	isolation: isolate;
	padding-top: var(--header-hoogte);
}

.hero--home {
	min-height: 100vh;
	min-height: 100dvh;
}

/*
 * Een binnenpagina-hero is sinds 28 augustus 2026 net zo hoog als de homepage.
 *
 * Hij stond op 50vh en 60vh, met als reden: op een binnenpagina is de bezoeker al
 * binnen en wil hij verder. Greg vroeg het omgekeerde en Sepp bevestigde het:
 * "altijd fullscreen op ieder scherm, en zorg dat de hero in zijn geheel in beeld
 * is". Dat tweede was ook een echte fout, geen smaak: op Bedrijfsruimte huren was
 * de hero 920px in een venster van 810, dus de knop viel eronder. min-height lost
 * dat niet op, want een hero groeit met zijn inhoud. Wat het wel oplost is de
 * ademruimte hieronder, die bij een laag venster als eerste weggaat.
 *
 * 100dvh erachter om dezelfde reden als op de homepage: op iOS rekent 100vh met
 * de balk weg die er nog staat.
 */
.hero--page {
	min-height: 100vh;
	min-height: 100dvh;
}

.hero__media {
	position: absolute;
	inset: 0;
	z-index: -2;
}

.hero__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transform: scale(var(--hero-overscan));
}

/*
 * Een hero waarvan het beeld aan de bovenrand hangt, sinds 15 september 2026.
 *
 * `object-fit: cover` snijdt gecentreerd, en de overscan snijdt daar nog 2,5
 * procent per rand bovenop. Op de balenfoto van de wandelroute staat de man boven
 * op de lading zo dicht bij de bovenrand (30 van 533 pixels op de 800-variant)
 * dat gecentreerd snijden op 1440x900 zijn hoofd wegneemt, en op 1920x1080 nog
 * meer. De bron heeft daar geen extra ruimte: de uitsnede begint al op 0.
 *
 * 20 procent en niet 0: bij 0 verliest de man vooraan op 1080p zijn benen tot
 * de dij, bij 20 procent houdt de man boven zijn hoofd op 1440 en op 1920 (57
 * respectievelijk 76 pixels marge tegen 22 en 53 pixels snede) en gaat er
 * vooraan alleen een schoen af. De transform-origin staat op hetzelfde punt,
 * anders schuift de overscan het anker alsnog naar het midden.
 *
 * De variant hoort bij deze foto en niet bij de pagina: kiest Greg via de
 * editor een andere hero, dan is 20 procent nog steeds een redelijk anker, maar
 * geen gemeten. Zet in `template-wandelroute.php` de 'variant' dan uit.
 */
.hero--boven .hero__media img {
	object-position: 50% 20%;
	transform-origin: 50% 20%;
}

/*
 * De waas over het hero-beeld is een GERICHTE scrim en niet een plat vlak.
 *
 * Het brandbook zet hier `rgba(0,0,0,0.50)` plat over het hele beeld, en dat is
 * gemeten te weinig. Met de tekst weggehaald en de lichtste pixel achter elk
 * tekstvlak opgezocht, haalde het hero-label van 14px op alle vier de
 * beeld-pagina's geen 4,5:1 (3,23 tot 4,03) en de intro van 18px zakte op twee
 * pagina's. Het gemiddelde contrast was overal ruim in orde, 6,7 tot 15, en dat is
 * precies waarom een gemiddelde hier niet de juiste maat is: één lichte plek in de
 * foto zit onder een regel tekst en de rest van het vlak compenseert dat niet.
 *
 * Een zwaardere platte waas zou het beeld verzuipen. Daarom een verloop dat onderaan
 * zwaar is, want daar staat de tekst (align-items: flex-end), en bovenaan licht,
 * waar het beeld het werk doet. Dat is hetzelfde mechanisme als de deuren gebruiken.
 *
 * Bij een nieuwe foto moet dit opnieuw gemeten worden, en het is bewust een
 * mechanisme dat niet van déze foto afhangt: ook een lichte foto van de binnenplaats
 * blijft hiermee leesbaar.
 */
/*
 * De waas is een KOLOM-scrim, en dat is de derde poging. De eerste twee staan hier
 * omdat ze allebei gemeten fout waren en dat de reden is dat het nu zo is.
 *
 * Poging 1, plat 0.50 over het hele beeld (zoals het brandbook voorschrijft): het
 * hero-label van 14px haalde op alle vier de beeld-pagina's geen 4,5:1, gemeten met
 * de tekst weggehaald en de lichtste pixel achter elk tekstvlak opgezocht. Het
 * gemiddelde contrast was ruim in orde (6,7 tot 15) en juist dat verbergt het: één
 * lichte plek in de foto zit onder een regel tekst en de rest compenseert niet.
 *
 * Poging 2, een verticaal verloop dat onderaan zwaar is: het tekstblok is hoog en
 * het label staat bovenaan, dus juist daar werd de dekking het laagst. Het label
 * ging van 3,23-4,03 naar 2,29-3,83. Slechter.
 *
 * Poging 3, een scrim op .hero__content zelf: contrast prima, maar dat blok beslaat
 * op de homepage bijna de hele hero-hoogte, dus de foto was alsnog verzopen. Dat is
 * precies de fout waar de les over gaat: een contrast-eis zonder tegenwicht op de
 * leesbaarheid van het beeld.
 *
 * Wat nu staat: de tekst staat links, dus de scrim loopt van links naar rechts. De
 * tekstkolom (container plus 40rem, dus tot 52 à 54 procent van de breedte vanaf
 * 1280px) zit onder het donkere deel, en rechts daarvan loopt de waas in een korte
 * schouder naar nul, zodat de rechterhelft van de foto op eigen kracht staat.
 *
 * OP 17 SEPTEMBER 2026 IS DE FOTO OP NORMALE HELDERHEID GEZET, op aanwijzing van
 * Greg na een doorloop met testlezers: te donker, en als het een keuze is dan
 * liever lichter dan het lampeffect. Sepp koos lamp eraf, 59 blijft, foto lichter.
 * Er lagen tot die dag drie lagen over elke hero-foto: deze scrim, de sluier van
 * de lamp (0 tot 44 procent deep buiten de bundel) en op Home het rasterpuntfilter
 * (multiply op 0,55). De lamp en het raster zijn weg, en van deze scrim is het
 * verticale verloop (34/22/18 procent over de volle breedte, "voor de sfeer")
 * vervallen en loopt het horizontale nu naar nul: de fotokant stond op 26/12 en
 * staat op 0. De tekstkolom zelf is niet lichter geworden, want daar staat het
 * wordmark van 14px en dat is de maat. Worst-pixel-contrast na de wissel staat in
 * ROADMAP fase 1.31; de eis is 4,5 voor wordmark, kop én intro.
 *
 * Onder 768px vult de tekst de volle breedte, en dan werkt een kolom-scrim niet. Daar
 * kantelt hij naar verticaal, zie de media-query onderaan dit blok.
 */
.hero__overlay {
	position: absolute;
	inset: 0;
	z-index: -1;
	/*
	 * De stops hangen aan de rechterrand van de tekstkolom en niet aan een
	 * percentage van de breedte. Die rand ligt op (breedte - container) / 2 plus
	 * de containermarge plus 40rem, dus vanaf 1280px op 50% + 3rem, en daaronder
	 * op een vaste 43rem. Een percentage-stop schoof op 1920 de schouder over de
	 * tagline heen (4,19 op het slechtste pixel) en liet op 1024 de intro in de
	 * lichte kant staan; met de rand als anker staat de schouder overal net
	 * voorbij de laatste letter.
	 */
	--scrim-rand: max(calc(50% + 3rem), 43rem);
	background-image: linear-gradient(
		to right,
		color-mix(in srgb, var(--color-deep) 84%, transparent) 0,
		color-mix(in srgb, var(--color-deep) 78%, transparent) calc(var(--scrim-rand) - 18rem),
		color-mix(in srgb, var(--color-deep) 64%, transparent) var(--scrim-rand),
		color-mix(in srgb, var(--color-deep) 10%, transparent) calc(var(--scrim-rand) + 12rem),
		color-mix(in srgb, var(--color-deep) 0%, transparent) calc(var(--scrim-rand) + 20rem)
	);
}

/*
 * De band achter de header. De balk is bovenaan doorzichtig (pas bij scrollen
 * krijgt hij --overlay-header) en de navigatie staat dus op de foto. Tot 17
 * september 2026 droegen het verticale verloop en de sluier van de lamp die tekst
 * onbedoeld mee; zonder die twee stond "WANDELROUTE" op de lucht van de balenfoto
 * op 1,3:1 en haalde de navigatie op geen van de vier hero's met foto de 4,5.
 *
 * De band dekt alleen de hoogte van de balk (vlak tot onder de navigatieregel,
 * dan uit over de hoogte van nog een balk) en niet de foto zelf: onder 11rem ligt
 * er niets meer. Alleen vanaf 900px, want daaronder is de navigatie een knop met
 * eigen grond en staat er bovenin niets dan het logo.
 *
 * Het vlakke deel staat op 84 procent deep: dezelfde waarde als de voet van de
 * kolom-scrim hierboven, zodat er in de hero één grondwaarde is en niet twee.
 * Tot de verse-ogen-review van 17 september 2026 stond hier 82, en dat getal
 * kwam nergens vandaan; de styleguide (2.4) noemt de band nu met deze waarde.
 */
.hero__overlay::before {
	content: '';
	position: absolute;
	inset: 0 0 auto 0;
	height: 11rem;
	background-image: linear-gradient(
		to bottom,
		color-mix(in srgb, var(--color-deep) 84%, transparent) 0,
		color-mix(in srgb, var(--color-deep) 84%, transparent) 4.5rem,
		color-mix(in srgb, var(--color-deep) 0%, transparent) 100%
	);
}

@media (max-width: 899px) {

	.hero__overlay::before {
		display: none;
	}
}

/*
 * De tagline van Home mag 46rem breed zijn en niet 40 (zie .hero--home
 * .hero__tagline), dus daar schuift de rand 6rem mee. Zonder deze regel stond
 * "plek die weer bruist" op 1920 met zijn laatste letters in de schouder: 4,27 op
 * het slechtste pixel bij een eis van 4,5.
 */
.hero--home .hero__overlay {
	--scrim-rand: max(calc(50% + 9rem), 49rem);
}

@media (max-width: 767px) {

	/*
	 * De bovenkant is verzwaard van 0,30 naar 0,62.
	 *
	 * Het hero-label stond tot 20 augustus 2026 ONDER de vaste header, en de
	 * contrastmeting daarvan liep dus tegen de headerbalk aan in plaats van tegen
	 * de foto. De 4,74 die daaruit kwam heeft nooit iets over dit label gezegd.
	 * Zodra de hero zijn inhoud onder de header vandaan houdt, staat het label
	 * boven in de foto en haalde het daar 3,96 bij een eis van 4,5.
	 * Nagemeten dat de foto niet verzuipt.
	 *
	 * 11 september 2026: van 90/84/74/62 naar 84/76/68/58. Een grotere stap
	 * (76/68/60/52) liet het wordmark op Contact zakken tot 4,19 op 390px; het
	 * staat daar niet bovenin maar tussen de stops van 50 en 80 procent.
	 *
	 * 17 september 2026: de lamp en het raster zijn weg, en de vraag was hoeveel
	 * de bovenkant hier kon zakken. Eerste poging 84/74/36/8: het wordmark zakte op
	 * Home naar 4,22 en op Historie naar 3,90, want de tekst vult op 390 bijna de
	 * hele hoogte en het wordmark staat op Home rond 78 procent. De stop op 80
	 * procent staat daarom bijna terug (64 tegen 68) en alleen de bovenste rand,
	 * boven alle tekst, is echt lichter (40 tegen 58). Nagemeten op Home, Historie
	 * en Contact, zie ROADMAP fase 1.31.
	 */
	.hero__overlay {
		background-image: linear-gradient(
			to top,
			color-mix(in srgb, var(--color-deep) 84%, transparent) 0%,
			color-mix(in srgb, var(--color-deep) 76%, transparent) 50%,
			color-mix(in srgb, var(--color-deep) 64%, transparent) 80%,
			color-mix(in srgb, var(--color-deep) 40%, transparent) 100%
		);
	}
}

.hero--cta .hero__overlay {
	background-image: linear-gradient(
		to top,
		color-mix(in srgb, var(--color-deep) 86%, transparent) 0%,
		color-mix(in srgb, var(--color-deep) 72%, transparent) 50%,
		color-mix(in srgb, var(--color-deep) 58%, transparent) 100%
	);
}

.hero__content {
	position: relative;
	width: 100%;
	padding-block: var(--section-md);
}

/* De tekstkolom blijft binnen de donkere kant van de scrim. */
.hero__content > .container > * {
	max-width: 40rem;
}

/*
 * De hero-kop weegt de vensterHOOGTE mee en niet alleen de breedte.
 *
 * --text-hero is clamp(3rem, 8vw, 8rem) en dus puur aan de breedte gekoppeld. Op
 * een laptop is het venster breed maar laag, en dan groeit de kop door terwijl de
 * ruimte eronder verdwijnt. Gemeten op 17 augustus, zie
 * ux-onderzoek/meting-2026-08-18: op 1440 bij 789 was de kop vier regels van
 * 115px, werd de hero 952px hoog in een venster van 789, en viel de knop 67px
 * onder de vouw. Op 1512 bij 835 net zo. Op 1920 bij 1080 viel het niet op, en
 * daarom is het bij het bouwen gemist.
 *
 * 12vh is bewust gekozen: op 1080 komt min() uit op de volle 8rem, dus het grote
 * scherm verandert niet, en op een laag venster krimpt de kop wel.
 */
.hero__tagline {
	font-family: var(--font-serif);
	font-size: min(var(--text-hero), 12vh);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-tighter);
	line-height: var(--leading-none);
	text-wrap: balance;
	margin: 0;
}

.hero__wordmark {
	font-family: var(--font-sans);
	font-size: var(--text-label);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-widest);
	text-transform: uppercase;
	margin: 0 0 var(--gap-sm);
	color: var(--color-cream);
}

.hero__intro {
	max-width: 34rem;
	margin-top: var(--gap-sm);
	font-size: var(--text-body-lg);
	line-height: var(--leading-loose);
}

.hero__actions {
	margin-top: var(--gap-md);
}

/*
 * Laag venster: de hero moet in één schermhoogte passen, kop, tekst én knop.
 * Dat is een harde eis en geen smaak, want de knop is de primaire actie van de
 * hele site. De ademruimte gaat er als eerste af, daarna pas de tekstmaat.
 */
@media (max-height: 900px) {

	.hero--home .hero__content,
	.hero--page .hero__content {
		padding-block: 2.5rem 3rem;
	}

	/*
	 * De regelafstand blijft ruim. Die is er voor doelgroep 2, de oud-medewerkers
	 * van 60 tot 90, en die eis wordt niet ingeleverd om ruimte te winnen.
	 *
	 * De tekstmaat gaat er sinds 21 augustus 2026 ook niet meer af. De kop van de
	 * homepage weegt de vensterhoogte nu zelf mee via min(7.5vw, 10.5svh), en dan
	 * kromp de tekst hier een tweede keer. Gevolg: 16px waar het goedgekeurde
	 * ontwerp 18px heeft. De ademruimte hierboven is genoeg om te passen.
	 */
	.hero--home .hero__intro,
	.hero--page .hero__intro {
		margin-top: var(--gap-xs);
	}

	.hero--home .hero__actions,
	.hero--page .hero__actions {
		margin-top: var(--gap-sm);
	}
}

/*
 * DE HERO HOUDT ONDERAAN DE ZWEVENDE BESTURING VRIJ.
 *
 * .hero staat op align-items: flex-end, dus de inhoud plakt tegen de onderrand.
 * Daar staan ook de zwevende bezoek-pil en de menuknop, en die zijn fixed. Op
 * /bedrijfsruimte-huren/ op 390x844 lag de pil daardoor dwars over de heroknop:
 * 157 bij 22 pixels overlap, gemeten op 8 september 2026 op staging, met de tekst
 * "Vraag een rondleiding aan" er half onder. Op home op 360x640 lag hij over de
 * muis-aanwijzing.
 *
 * --zwevend-vrij is precies het token dat daarvoor bestaat: de knop plus twee keer
 * de containermarge. De voet rekent er al mee, de hero deed dat niet.
 *
 * Alleen onder 1120px, want daarboven staat de CTA in de balk en is de pil weg.
 * Zie de regel bij .visit-cta. En de twee liggend-blokken hierna zetten padding-block
 * als geheel opnieuw en winnen dus van deze regel; dat klopt, want daar is de pil
 * ook weg.
 */
@media (max-width: 1119px) {

	.hero--home .hero__content,
	.hero--page .hero__content {
		padding-bottom: var(--zwevend-vrij);
	}
}

/*
 * Liggende telefoon, de tweede stap. 844x390 is de maat waarop de knop op vier
 * pagina's onder de vouw viel: home op 420, route op 416, bezoekers op 477 en
 * Bedrijfsruimte huren op 513, allemaal in een venster van 390.
 *
 * Het blok hierboven (max-height: 900px) is de eerste stap en pakt de laptop.
 * Deze is dieper en geldt alleen liggend, want een staand venster van 390 breed
 * heeft de hoogte wel. Wat eraf gaat is uitsluitend lucht: de balk hierboven,
 * de padding van het hero-blok, de ruimte onder het woordmerk en boven de knop.
 * De tekstmaten blijven staan, om dezelfde reden als in het blok hierboven.
 */
@media (max-height: 520px) and (orientation: landscape) {

	.hero--home .hero__content,
	.hero--page .hero__content {
		padding-block: 1rem 1.5rem;
	}

	.hero__wordmark {
		margin-bottom: var(--gap-xs);
	}

	/*
	 * En hier gaat de tekstmaat er WEL af, anders dan in het blok hierboven.
	 *
	 * Dat blok houdt de intro bewust op 18px, want daar gaat het over een laptop
	 * met 700 tot 900px hoogte en dan is er lucht genoeg. Liggend op een telefoon
	 * is er 390px en past het niet: op /bedrijfsruimte-huren/ stond de knop op
	 * 417 in een venster van 390, met de intro als grootste blok (153px over vijf
	 * regels). Op 16px zijn dat vier regels en komt de knop boven de vouw.
	 *
	 * 16px is de bodymaat van de site en niet een uitzonderingsmaat, en de
	 * regelafstand blijft --leading-loose. De leesbaarheid voor doelgroep 2 zit in
	 * die regelafstand, en die wordt hier niet ingeleverd.
	 */
	.hero--home .hero__intro,
	.hero--page .hero__intro {
		font-size: var(--text-body);
	}

	.hero--home .hero__actions,
	.hero--page .hero__actions {
		margin-top: 1rem;
	}
}

/*
 * En nog een stap dieper, voor een kleine telefoon in liggende stand.
 *
 * Het blok hierboven pakt 520px hoogte en is afgeregeld op een venster van 390.
 * Een iPhone SE of 8 is liggend 667 bij 375, en die 15px scheelden net te veel:
 * gemeten op 8 september 2026 op staging was de hero op /bedrijfsruimte-huren/
 * 424px hoog in een venster van 375, met de knop op 400 en dus 25px onder de
 * vouw. Op de acht andere hero's stond hij daar wel boven, dus het is één pagina
 * en het is de langste intro van de site: 305 tekens over vijf regels.
 *
 * Wat er af gaat is opnieuw alleen lucht, plus de ondergrens van de kop. Die
 * ondergrens van 2.25rem is er voor een SMALLE telefoon, waar de kop anders over
 * te veel regels breekt. Liggend is het venster juist breed en laag, dus daar is
 * hij niets waard en kost hij alleen hoogte.
 *
 * De intro blijft op 16px met --leading-loose, net als in het blok hierboven, en
 * om dezelfde reden: de leesbaarheid voor doelgroep 2 zit in die regelafstand.
 */
@media (max-height: 420px) and (orientation: landscape) {

	.hero--home .hero__content,
	.hero--page .hero__content {
		padding-block: 0.5rem;
	}

	/*
	 * Het label is één woord in kapitalen op 14px, en het stond op de regelafstand
	 * van lopende tekst. Dat is 25px doos om 14px letter. Hier is dat lucht die
	 * niets doet, en het is de laatste 11px die de knop op /bedrijfsruimte-huren/
	 * boven de vouw brengt.
	 */
	.hero__wordmark {
		line-height: var(--leading-none);
	}

	.hero--home .hero__intro,
	.hero--page .hero__intro {
		margin-top: 0.25rem;
	}

	.hero--home .hero__actions,
	.hero--page .hero__actions {
		margin-top: 0.5rem;
	}
}

/*
 * De intro-choreografie speelt één keer bij het laden. Staat achter
 * (scripting: enabled) zodat de inhoud zichtbaar is als er geen JavaScript is,
 * en achter .is-ready zodat hij niet begint voordat de letters er zijn.
 */
@media (scripting: enabled) {

	.hero__wordmark,
	.hero__tagline,
	.hero__intro,
	.hero__actions {
		opacity: 0;
	}

	.hero.is-ready .hero__wordmark,
	.hero.is-ready .hero__tagline {
		animation: f59-hero-in 1.2s var(--ease-out) forwards;
	}

	.hero.is-ready .hero__intro {
		animation: f59-hero-up 1s var(--ease-out) 0.5s forwards;
	}

	.hero.is-ready .hero__actions {
		animation: f59-hero-fade 1s var(--ease-out) 1s forwards;
	}
}

@keyframes f59-hero-in {
	from { opacity: 0; transform: scale(0.94); }
	to   { opacity: 1; transform: none; }
}

@keyframes f59-hero-up {
	from { opacity: 0; transform: translateY(20px); }
	to   { opacity: 1; transform: none; }
}

@keyframes f59-hero-fade {
	from { opacity: 0; }
	to   { opacity: 1; }
}

/* =======================================================================
 * De deuren
 *
 * Drie ongelijke klikbare panelen. Het formaat draagt de hiërarchie, zie
 * layout.css. Elk paneel is één link, zodat het hele vlak klikbaar is en niet
 * alleen de tekst.
 * ======================================================================= */

.door {
	position: relative;
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	min-height: 15rem;
	padding: var(--card-padding);
	overflow: hidden;
	isolation: isolate;
	color: var(--color-white);
	text-decoration: none;
	background-color: var(--color-shadow);
}

.door__media {
	position: absolute;
	inset: 0;
	z-index: -2;
}

.door__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform var(--duration-image) var(--ease-out);
}

/*
 * De scrim over een deur, met een hoge bodem.
 *
 * Hier stond een verloop van 0.85 onderaan naar 0.15 bovenaan. Dat werkt op de
 * grote deur en zakt op de twee kleine: die zijn 15 tot 18rem hoog en hun tekst
 * vult bijna de hele hoogte, dus de bovenste regels landen op 0.35 en dan haalt de
 * kop 2,01 tot 2,19 waar 3:1 nodig is. Gemeten met de tekst weggehaald en de
 * lichtste pixel achter elk vlak opgezocht.
 *
 * De bodem van het verloop staat daarom op 0.58, ongeacht de hoogte van de deur.
 * De foto blijft daarmee zichtbaar (nagemeten) maar de tekst staat nooit meer op
 * een lichte plek.
 */
.door::before {
	content: '';
	position: absolute;
	inset: 0;
	z-index: -1;
	background: linear-gradient(
		to top,
		color-mix(in srgb, var(--color-deep) 92%, transparent) 0%,
		color-mix(in srgb, var(--color-deep) 84%, transparent) 45%,
		color-mix(in srgb, var(--color-deep) 68%, transparent) 75%,
		color-mix(in srgb, var(--color-deep) 58%, transparent) 100%
	);
	transition: background var(--duration-base) var(--ease-out);
}

/*
 * De grote deur had een lichtere sluier omdat hij hoog was en de tekst er laag
 * in stond. Sinds de drie deuren gelijk zijn, staat de titel hoog in het beeld en
 * haalde "Bezoek het terrein" daar 2,03:1 op 1920, 1440 en 1512, bij een eis van
 * 3:1. Gemeten op 21 augustus 2026. Alle drie de deuren delen nu dezelfde sluier.
 */


.door__title {
	font-family: var(--font-serif);
	font-size: var(--text-h3);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-tighter);
	line-height: var(--leading-normal);
	margin: 0;
}

/*
 * De grote deur had een grotere titel, want hij was ook groter. Sinds de drie
 * deuren gelijk zijn (zie layout.css) heeft één afwijkende titel geen grond meer.
 */

.door__text {
	margin-top: var(--gap-xs);
	max-width: 26rem;
	color: var(--text-on-dark-muted);
}

.door__action {
	margin-top: var(--gap-sm);
	display: inline-flex;
	align-items: center;
	gap: var(--gap-xs);
	font-family: var(--font-sans);
	font-size: var(--text-button);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-widest);
	text-transform: uppercase;
}

.door__arrow {
	transition: transform var(--duration-base) var(--ease-out);
}

/* Hover: het beeld zoomt in 1s, de waas wordt zwaarder, de pijl schuift. */
/*
 * De zoom hoort bij een deur die je kunt openen. Op de huren-pagina zijn de
 * "waarom hier"-blokken div's en geen links, en die zoomden mee: zelfde visuele
 * taal, ander gedrag, en dus een belofte die niet ingelost wordt. `a.door` beperkt
 * het effect tot wat echt klikbaar is.
 */
a.door:focus-visible .door__media img {
	transform: scale(var(--image-zoom));
}

@media (hover: hover) {

	a.door:hover .door__media img {
		transform: scale(var(--image-zoom));
	}
}

a.door:focus-visible::before {
	background: linear-gradient(to top, color-mix(in srgb, var(--color-deep) 92%, transparent) 0%, color-mix(in srgb, var(--color-deep) 50%, transparent) 60%, color-mix(in srgb, var(--color-deep) 25%, transparent) 100%);
}

@media (hover: hover) {

	a.door:hover::before {
		background: linear-gradient(to top, color-mix(in srgb, var(--color-deep) 92%, transparent) 0%, color-mix(in srgb, var(--color-deep) 50%, transparent) 60%, color-mix(in srgb, var(--color-deep) 25%, transparent) 100%);
	}
}

a.door:focus-visible .door__arrow {
	transform: translateX(6px);
}

@media (hover: hover) {

	a.door:hover .door__arrow {
		transform: translateX(6px);
	}
}

/* =======================================================================
 * De kaart op de sorteerband
 *
 * De kaart is in beide dichtheden identiek. Het omhulsel mag met de tekstlengte
 * meebewegen, de kaart niet: dat is de anti-default over een component dat op de
 * ene pagina werkt en op de andere niet.
 * ======================================================================= */

.card {
	display: flex;
	flex-direction: column;
	height: 100%;
	background-color: var(--color-shadow);
	border: 1px solid var(--border-light);
	text-decoration: none;
	color: inherit;
	transition:
		transform var(--duration-base) var(--ease-out),
		box-shadow var(--duration-base) var(--ease-out),
		border-color var(--duration-base) var(--ease-out);
}

.section-light .card {
	background-color: #ffffff;
	border-color: var(--border-dark);
	box-shadow: var(--shadow-card);
}

/*
 * De hover zet licht achter de plaat, de warme gloed uit --color-lamp. Op een
 * donkere grond is een schaduw onzichtbaar, dus daar doet gloed het werk dat een
 * schaduw elders doet.
 */
.card:focus-visible {
	transform: translateY(-10px);
	border-color: color-mix(in srgb, var(--color-white) 18%, transparent);
	box-shadow: 0 0 3.75rem color-mix(in srgb, var(--color-lamp) 12%, transparent);
}

@media (hover: hover) {

	.card:hover {
		transform: translateY(-10px);
		border-color: color-mix(in srgb, var(--color-white) 18%, transparent);
		box-shadow: 0 0 3.75rem color-mix(in srgb, var(--color-lamp) 12%, transparent);
	}
}

.section-light .card:focus-visible {
	box-shadow: var(--shadow-card-hover);
}

@media (hover: hover) {

	.section-light .card:hover {
		box-shadow: var(--shadow-card-hover);
	}
}

/*
 * 3:2, en de hoogte is hier de hele reden.
 *
 * Sepp keurde de band af omdat hij niet in één schermhoogte paste en de kaarten
 * daarvoor te groot waren. Nagemeten op 1440 bij 789: de sectie was 861px en moest
 * onder 789. Bij een kaart van 370 breed scheelt 3:2 tegenover 4:3 dertig pixels
 * beeldhoogte, en samen met de voet die eruit ging en een krappere body-padding
 * haalt dat het.
 *
 * De gemeten referentie gaat verder de andere kant op: Battersea zet zijn
 * huurderkaart op een vierkant beeld van 280px. Dat kan daar, want hun kaarten
 * zijn smal en hun beeldslot is altijd gevuld. Bij ons is het negen keer leeg, en
 * een vierkant leeg vlak zou het dominante element op de pagina worden.
 */
.card__media {
	position: relative;
	overflow: hidden;
	aspect-ratio: 3 / 2;
	background-color: var(--color-black);
}

.card__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform var(--duration-image) var(--ease-out);
}

.card:focus-visible .card__media img {
	transform: scale(var(--image-zoom));
}

@media (hover: hover) {

	.card:hover .card__media img {
		transform: scale(var(--image-zoom));
	}
}

/*
 * De ontworpen lege staat, en dit is een besluit en geen kapotte staat.
 *
 * Negen bedrijven hebben nul foto's. Het vorige thema vulde dat op met één
 * stockfoto voor vier verschillende bedrijven. Een stockfoto bij een bedrijf met
 * naam is een verzonnen weergave van de ruimte van een derde partij, dus dat
 * gebeurt hier niet. In plaats daarvan: het weefpatroon met de eerste letter van
 * de naam groot in de serif. Zodra er een foto is, vult het slot zich zonder dat
 * de layout verandert.
 */
.card__media--empty {
	display: grid;
	place-items: center;
	background-color: var(--color-black);
	background-image: var(--pattern-weave);
	background-blend-mode: overlay;
}

/*
 * De initiaal als stencil, zoals een sjabloon op een kist of een baal.
 *
 * Stond als gevulde letter op 22 procent dekking, en dat leest als een lichte
 * letter in plaats van als een merkteken. In omtrek is hij even rustig maar wel
 * herkenbaar als iets dat op materiaal is aangebracht.
 *
 * Zonder ondersteuning voor -webkit-text-stroke blijft de letter transparant en
 * is er dus niets te zien. Dat mag: het is decoratie, de naam staat eronder.
 */
.card__initial {
	font-family: var(--font-serif);
	font-size: clamp(2.5rem, 9vw, 4rem);
	font-weight: var(--weight-bold);
	line-height: 1;
	color: transparent;
	-webkit-text-stroke: 1px color-mix(in srgb, var(--color-white) 28%, transparent);
	letter-spacing: var(--tracking-tighter);
	transition: -webkit-text-stroke-color var(--duration-base) var(--ease-out);
}

.section-light .card__initial {
	-webkit-text-stroke-color: color-mix(in srgb, var(--color-black) 22%, transparent);
}

.card:focus-visible .card__initial {
	-webkit-text-stroke-color: color-mix(in srgb, var(--color-lamp) 55%, transparent);
}

@media (hover: hover) {

	.card:hover .card__initial {
		-webkit-text-stroke-color: color-mix(in srgb, var(--color-lamp) 55%, transparent);
	}
}

.card__body {
	display: flex;
	flex-direction: column;
	flex-grow: 1;
	gap: var(--gap-xs);
	padding: 1.5rem;
}

.card__title {
	font-family: var(--font-serif);
	font-size: var(--text-h3);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-normal);
	line-height: var(--leading-normal);
	margin: 0;
}

/*
 * flex-grow op de tekst, zodat de voettekst van elke kaart in een rij op dezelfde
 * lijn ligt ongeacht de tekstlengte. Dat kleine detail is de reden dat een rij
 * kaarten strak oogt.
 */
.card__text {
	flex-grow: 1;
	margin: 0;
	color: var(--text-on-dark-muted);
}

.section-light .card__text { color: var(--text-on-light-muted); }

.card__foot {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--gap-xs);
	padding-top: var(--gap-xs);
	border-top: 1px solid var(--border-light);
}

.section-light .card__foot { border-top-color: var(--border-dark); }

/*
 * De pijl zit in de hoek van het beeld en niet in een voet onder de tekst. Dat
 * scheelt de voethoogte, en die was nodig om de sectie binnen één schermhoogte te
 * krijgen. Op de lege beeldstaat valt hij op het weefpatroon, en dat werkt: het
 * lege slot is dan niet alleen leeg maar ook duidelijk klikbaar.
 */
.card__hoek {
	position: absolute;
	right: 1rem;
	bottom: 1rem;
	display: grid;
	place-items: center;
	width: 2rem;
	height: 2rem;
	border-radius: var(--radius-pill);
	background-color: color-mix(in srgb, var(--color-black) 55%, transparent);
	color: var(--color-white);
	backdrop-filter: blur(4px);
	transition:
		background-color var(--duration-base) var(--ease-out),
		color var(--duration-base) var(--ease-out);
}

.card:focus-visible .card__hoek {
	background-color: var(--color-red);
}

@media (hover: hover) {

	.card:hover .card__hoek {
		background-color: var(--color-red);
	}
}

.card__arrow { transition: transform var(--duration-base) var(--ease-out); }

.card:focus-visible .card__arrow { transform: translateX(6px); }

@media (hover: hover) {

	.card:hover .card__arrow { transform: translateX(6px); }
}

/* =======================================================================
 * De bediening van de sorteerband
 *
 * Gemeten op phantom.com/learn, 20 augustus 2026: pijlknop 40 bij 40, volledig
 * rond, 4px tussenruimte, rechtsboven op de hoogte van de sectiekop. Uitgeschakeld
 * is daar transparant op 40 procent dekking met `cursor: default`, ingeschakeld
 * een vol gevuld vlak. Dat verschil is met opzet groot: het moet in één oogopslag
 * te zien zijn, niet bij nader inzien.
 *
 * Onze invulling van "gevuld": cream met een donkere glyph, en op hover het rood.
 * Rood als rustvlak kan hier niet, want #b22222 op #12100e haalt 2,9:1 en zakt
 * daarmee door de 3:1 die WCAG 1.4.11 voor een UI-onderdeel vraagt. Cream haalt
 * ruim, en de glyph op cream haalt ruim. Een uitgeschakelde knop is van 1.4.11
 * uitgezonderd, dus daar mag de hairline subtiel blijven.
 * ======================================================================= */

.section-head--split {
	display: flex;
	gap: var(--gap-sm);
}

/*
 * Uitlijnen en spreiden pas vanaf 768px, want pas daar staat de richting op `row`.
 *
 * Deze twee regels stonden hierboven zonder mediaquery, terwijl `layout.css` de
 * richting pas vanaf 768px van `column` naar `row` schakelt. In een kolom duwt
 * `align-items: flex-end` alles naar de RECHTERrand, en dan begint de sectiekop op
 * x=139 terwijl elke andere kop op de pagina op x=24 staat. Gevonden in ronde 3 op
 * 26 augustus 2026 op Instagram en Home, blijven staan omdat er geen ronde meer
 * kwam, en op 28 augustus geërfd door de galerij.
 */
@media (min-width: 768px) {

	.section-head--split {
		align-items: flex-end;
		justify-content: space-between;
	}
}

/* De pijlen zijn muis- en toetsenbordwerk. Op een smal scherm swipe je, en dan is
   een knoppenpaar dat ruimte kost naast een kop die al krap staat alleen maar in
   de weg. */
.band__nav {
	display: none;
	flex-shrink: 0;
	gap: 4px;
}

@media (min-width: 768px) {
	.band__nav { display: flex; }
}

/*
 * En `hidden` moet van die mediaquery winnen.
 *
 * `[hidden] { display: none }` staat in de stylesheet van de browser, en die
 * verliest van elke auteursregel, ongeacht specificiteit. Zonder deze regel stond
 * er dus vanaf 768px een knoppenpaar dat niets doet, in twee gevallen: zonder
 * JavaScript (band.js haalt het attribuut nooit weg) en zodra band.js de rij als
 * passend bestempelt, want `ververs()` zet `nav.hidden = past`. Gemeten op
 * 28 augustus 2026 met javaScriptEnabled: false, hidden=true en display=flex, op
 * de galerij en de bedrijvenrij tegelijk.
 */
.band__nav[hidden] { display: none; }

.band__arrow {
	display: grid;
	place-items: center;
	width: 2.5rem;
	height: 2.5rem;
	padding: 0;
	border: 1px solid var(--border-light);
	border-radius: var(--radius-pill);
	background-color: var(--color-white);
	color: var(--color-black);
	cursor: pointer;
	transition:
		background-color var(--duration-base) var(--ease-out),
		color var(--duration-base) var(--ease-out),
		opacity var(--duration-base) var(--ease-out);
}

.band__arrow:focus-visible {
	background-color: var(--color-red);
	color: var(--color-white);
}

@media (hover: hover) {

	.band__arrow:hover {
		background-color: var(--color-red);
		color: var(--color-white);
	}
}

.band__arrow[disabled] {
	background-color: transparent;
	border-color: var(--border-light);
	color: var(--text-on-dark-muted);
	opacity: 0.4;
	cursor: default;
}

.section-light .band__arrow {
	background-color: var(--color-black);
	color: var(--color-white);
	border-color: var(--border-dark);
}

.section-light .band__arrow[disabled] {
	background-color: transparent;
	color: var(--text-on-light-muted);
}

/* De terug-pijl is dezelfde glyph, gespiegeld. Eén svg in het thema, twee
   richtingen, zodat ze nooit uit elkaar kunnen lopen. */
.band__arrow--terug .band__arrow-glyph {
	transform: scaleX(-1);
}

/* Slepen. Alleen aangezet waar een echte muis is; op touch doet de browser het
   zelf beter dan wij kunnen. */
.band__track.is-sleepbaar {
	cursor: grab;
}

.band__track.is-gegrepen {
	cursor: grabbing;
	scroll-snap-type: none;
	user-select: none;
}

/* =======================================================================
 * Het tijdlijn-station
 *
 * Jaartal groot in de serif, stad als label. Beeld alleen waar er echt
 * archiefmateriaal ligt: een stockfoto naast een jaartal is een verzonnen
 * historisch document, zie het beeldplan.
 * ======================================================================= */

.station {
	position: relative;
	padding: var(--gap-md) var(--gap-sm) var(--gap-md) 0;
	border-top: 1px solid var(--border-light);
}

.station__year {
	font-family: var(--font-serif);
	font-size: clamp(2.5rem, 6vw, 4rem);
	font-weight: var(--weight-black);
	letter-spacing: var(--tracking-tighter);
	line-height: 1;
	margin: 0;
	color: var(--color-cream);
}

.station__place {
	display: block;
	margin-top: var(--gap-xs);
	color: var(--text-on-dark-muted);
}

/*
 * Een vaste 16:9 voor elk archiefbeeld. Niet omdat de originelen dat toevallig
 * zijn, maar omdat de stations in een rij naast elkaar staan: laat je de hoogte
 * door het bestand bepalen, dan springt de tekst per kolom op een andere lijn.
 *
 * De hairline eromheen maakt er een document van in plaats van een sfeerbeeld.
 * Een halte zonder foto krijgt bewust géén vervangend vlak.
 */
.station__media {
	margin: var(--gap-sm) 0 0;
	aspect-ratio: 16 / 9;
	overflow: hidden;
	border: 1px solid var(--border-light);
}

.station__media img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Alleen ruimte, geen vlak. En alleen waar de haltes naast elkaar staan. */
.station__media--leeg {
	display: none;
	border: 0;
}

@media (min-width: 900px) {
	.station__media--leeg { display: block; }
}

.station__title {
	margin-top: var(--gap-sm);
	font-family: var(--font-serif);
	font-size: var(--text-h3);
	font-weight: var(--weight-semibold);
	line-height: var(--leading-normal);
}

.station__text {
	margin-top: var(--gap-xs);
	color: var(--text-on-dark-muted);
}

@media (min-width: 900px) {

	.station {
		padding-right: var(--gap-lg);
	}

	/* Het rode stipje op de tafelrand, één per station. */
	.station::before {
		content: '';
		position: absolute;
		top: -0.3125rem;
		left: 0;
		width: 0.625rem;
		height: 0.625rem;
		background-color: var(--color-red);
	}
}

/* =======================================================================
 * De faciliteit-rij
 * ======================================================================= */

.facility {
	display: flex;
	align-items: baseline;
	gap: var(--gap-sm);
	padding-block: 1rem;
	border-top: 1px solid var(--border-light);
	counter-increment: facility;
}

.facility::before {
	content: counter(facility, decimal-leading-zero);
	flex: 0 0 auto;
	font-family: var(--font-sans);
	font-size: var(--text-button);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-widest);
	color: var(--color-red);
}

/* =======================================================================
 * Kanalen: mail, bellen, vinden
 *
 * Op donker, en daarom nooit een donkere outline: die is onzichtbaar tot hover.
 * De rand staat op crème met 0.35 dekking, dat haalt de 3:1 voor een
 * UI-onderdeel.
 * ======================================================================= */

/*
 * De drie kanalen als regels op een tabel, niet als doosjes.
 *
 * De vorige versie omkaderde elk kanaal, en die rand bestond alleen omdat de
 * grond donker was. Op de lichte bakstenen grond is een omkaderd vak zwaar en
 * telt het drie keer mee. Hairlines dragen de indeling en de hiërarchie komt uit
 * het formaat van de waarde.
 *
 * De hover ligt op de waarde en niet op het vak: een rode streep die vanaf links
 * onder de tekst doorschuift, dezelfde richting als de stempelveeg op de knop.
 */
/*
 * De scheidingslijn tussen de kanalen staat als lokale variabele, en de standaard
 * is de LICHTE lijn. Reden: .channels wordt op twee gronden gebruikt. Op Bedankt
 * staat hij op section-shadow en daar was de lijn hardgecodeerd op rgba(18,16,14),
 * dus donker op donker en daarmee onzichtbaar. Gevonden op 28 augustus 2026, bij
 * het terugzetten van de kanalen op Contact.
 *
 * Dit is exact dezelfde valkuil die twintig regels lager voor .channel .label al
 * was opgelost, en de reden dat de opmerking daar staat dat wie hier een kleur
 * zet, beide kanten moet regelen. De lijn was toen over het hoofd gezien.
 *
 * De waarden staan niet in tokens.css omdat --border-light en --border-dark op
 * 0.05 staan en dat is een haarlijn; deze tabel vraagt een zichtbare regel.
 */
.channels {
	--channel-lijn: color-mix(in srgb, var(--color-white) 25%, transparent);

	display: grid;
	grid-template-columns: minmax(0, 1fr);
	border-top: 1px solid var(--channel-lijn);

	/* De waarden binnenin meten zich aan de breedte van deze rij, niet aan die
	   van het venster. Waarom dat verschil hier uitmaakt staat bij het blok dat
	   `min(var(--text-h3), 3cqw)` zet, verderop in dit bestand. */
	container-type: inline-size;
}

.section-light .channels {
	--channel-lijn: color-mix(in srgb, var(--color-black) 25%, transparent);
}

@media (min-width: 768px) {
	.channels { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.channel {
	display: flex;
	flex-direction: column;
	gap: var(--gap-xs);
	min-height: var(--touch-min);
	padding: var(--gap-sm) var(--gap-sm) var(--gap-sm) 0;
	border-bottom: 1px solid var(--channel-lijn);
	text-decoration: none;
	color: inherit;
}

@media (min-width: 768px) {

	.channel + .channel {
		padding-left: var(--gap-sm);
		border-left: 1px solid var(--channel-lijn);
	}
}

/*
 * Het label van een kanaal is gedempt ten opzichte van de waarde eronder, en
 * die demping moet PER GROND gezet worden.
 *
 * Hier stond alleen de lichte variant, onvoorwaardelijk. .channel wordt ook op
 * Bedankt gebruikt, daar op section-shadow, en die labels kregen daardoor
 * donkere tekst op een donkere grond: 1,06:1, dus onzichtbaar. Gevonden op
 * 21 augustus 2026 met ux-onderzoek/meet.mjs, nadat het op vier breedtes
 * hetzelfde getal gaf en dat altijd verdacht is.
 *
 * .label zelf heeft met opzet geen eigen kleur en erft van de sectie. Wie hem
 * een kleur geeft, moet dus beide kanten regelen.
 */
.channel .label {
	color: var(--text-on-dark-muted);
}

.section-light .channel .label {
	color: var(--text-on-light-muted);
}

.channel__value {
	position: relative;
	display: inline-block;
	font-family: var(--font-serif);
	font-size: var(--text-h3);
	font-weight: var(--weight-semibold);
	letter-spacing: var(--tracking-normal);
}

/*
 * DE ONDERSTREEP LOOPT OVER ALLE REGELS VAN HET KANAAL, NIET ALLEEN DE EERSTE.
 *
 * Het adreskanaal draagt twee regels: de straat in .channel__value en de
 * postcode plus plaats in .muted. De streep hing tot 8 september 2026 alleen
 * onder de eerste, en omdat die twee regels op elkaar staan (.channel .muted
 * trekt de gap weer weg met een negatieve marge) kwam hij op de hover uit op
 * y 556 met de straat op 510-553 en de plaats op 553-596. Dus precies ertussen,
 * en dan leest een rode lijn niet als onderstreping maar als doorhaling.
 * Gemeten op 8 september op 1440.
 *
 * Sepp: "dat niet alleen Lovense Kanaaldijk 47 wordt onderlijnd op hover, maar
 * ook 5013 BJ Tilburg. Dus allebei die teksten."
 *
 * Beide regels krijgen daarom hun eigen streep. Wie hier ooit een derde regel
 * bij zet, krijgt die vanzelf mee: de selector noemt geen positie in de rij.
 */
.channel__value::after,
.channel .muted::after {
	content: '';
	position: absolute;
	left: 0;
	bottom: -3px;
	width: 100%;
	height: 2px;
	background-color: var(--color-red);
	transform: scaleX(0);
	transform-origin: left;
	transition: transform var(--duration-base) var(--ease-out);
}

.channel:focus-visible .channel__value::after,
.channel:focus-visible .muted::after {
	transform: scaleX(1);
}

@media (hover: hover) {

	.channel:hover .channel__value::after,
	.channel:hover .muted::after {
		transform: scaleX(1);
	}
}

/* =======================================================================
 * HET PANEEL
 *
 * Een vlak op de grond, zonder linkgedrag. Precies de receptuur van .card
 * (donker: --color-shadow met --border-light; licht: wit met --border-dark en
 * --shadow-card), maar zonder de dingen die .card tot een kaart maken:
 * height 100%, de translateY op hover en de vaste onderdelen .card__media en
 * .card__body. Een formulier is geen link en mag niet zweven.
 *
 * Radius 0, want dat is huisstijlwet: --radius-none is de standaard voor
 * knoppen, kaarten, secties en beeld. --radius-sm is uitsluitend ingelijst
 * beeld en --radius-md uitsluitend de FAQ-accordeon.
 *
 * Gebouwd op 1 september 2026 voor het formulier. Greg: "het formulier moet
 * echt beter gedesignd worden, ik wil het gewoon in een aparte container
 * hebben, ik vind hem er zo heel lelijk in staan." Steal sheet met de gemeten
 * referentie: ux-onderzoek/steal-sheet-formulierpaneel.md.
 * ======================================================================= */

.paneel {
	padding: var(--card-padding);
	background-color: var(--color-shadow);
	border: 1px solid var(--border-light);
}

.section-light .paneel {
	background-color: #ffffff;
	border-color: var(--border-dark);
	box-shadow: var(--shadow-card);
}

/* =======================================================================
 * Formulier
 * ======================================================================= */

/* =======================================================================
 * HET LABEL LIGT IN HET VELD EN KEEPT DE RAND IN
 *
 * Sepp koos deze vorm op 8 september 2026 uit drie varianten in
 * prototype-formulier-2.html, na "ik vind geen van alle goed" op de ronde
 * daarvoor. Variant D: de ingekeepte rand.
 *
 * Het mechanisme komt van strijp-s.nl/contact, live gemeten op 8 september 2026:
 * acht velden in 423px hoogte, tegen onze zeven in 1013px. Twee zetten dragen dat
 * verschil, en allebei zitten ze hieronder.
 *
 * 1. Het label ligt in het veld en klapt op focus EN bij inhoud de bovenrand in.
 *    Daar heeft het een eigen achtergrond in de paneelkleur, dus het snijdt een
 *    gat in de rand. Dat scheelt per veld een hele labelregel. Het blijft staan
 *    zodra er iets is ingevuld, want :not(:placeholder-shown) is de tweede haak
 *    naast :focus. Zonder die tweede haak zakt het label terug over de invoer.
 *
 * 2. Geen enkel veld spant de volle breedte, het tekstvak ook niet. Dat is één
 *    cel die alleen hoger is, en daardoor schuift het akkoord-vinkje er vanzelf
 *    naast in plaats van eronder. Alleen de knop spant beide kolommen.
 *
 * Wat bewust NIET is overgenomen van strijp-s.nl: daar is de focus-staat op het
 * veld onzichtbaar (rand, achtergrond, outline en schaduw zijn in rust en op focus
 * identiek gemeten), staat de tekst op 13,33px, is de radius 3,33px en is de knop
 * een pil. Hier houdt de rand zijn rode focus-kleur, staat de tekst op --text-body
 * en blijft --radius-none de wet.
 *
 * Gemeten hoogte van kop tot en met de zijkolom, op 1440 en 390:
 *
 *              huren 1440   contact 1440   huren 390   contact 390
 *   voorheen        1355           1044        2193          1473
 *   deze vorm        711            437        1538          1023
 * ======================================================================= */

/*
 * De maat staat als eigenschap en niet als kale max-width, want het paneel moet
 * er zijn eigen padding bij optellen. box-sizing staat op border-box, dus zonder
 * die correctie versmalt de invulkolom met 2 * --card-padding.
 *
 * --veld-gap is lokaal en geen token, want er is geen 1rem-gap-token: de schaal
 * springt van --gap-xs (0.5rem) naar --gap-sm (2rem). Op 0.5rem plakken de velden
 * aan elkaar nu ze een rand dragen, op 2rem valt het formulier uit elkaar. Het
 * prototype dat is goedgekeurd staat op 1rem.
 *
 * --label-grond is de kleur ACHTER het zwevende label, en dat is de kleur van het
 * vlak waar het veld in ligt. Dat is het paneel en niet de sectie: met de
 * sectiekleur wordt het label een donkerder vlekje op de paneelrand. De vier
 * regels lopen op in specificiteit (0,1,0 / 0,2,0 / 0,2,0 / 0,3,0) en staan in die
 * volgorde, want de twee middelste zijn gelijk en dan wint de laatste.
 */
.form {
	--form-maat: 46rem;
	--veld-gap: 1rem;
	--label-grond: var(--color-black);

	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--veld-gap);
	align-items: start;
	max-width: var(--form-maat);
}

.form.paneel {
	--label-grond: var(--color-shadow);

	max-width: calc(var(--form-maat) + 2 * var(--card-padding));
}

.section-light .form { --label-grond: var(--color-white); }

.section-light .form.paneel { --label-grond: #ffffff; }

/*
 * De knop is het enige dat wel over beide kolommen loopt, en het is geen veld.
 * "Vraag een rondleiding aan" is in 12px met de brede letterafstand breder dan een
 * kolom van 290px, dus in een kolom brak hij over twee regels en vulde hij die
 * kolom helemaal. justify-self houdt hem op zijn eigen breedte.
 */
.form > button { justify-self: start; }

@media (min-width: 640px) {

	.form { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }

	.form__meldingen,
	.form > button {
		grid-column: 1 / -1;
	}

	/*
	 * Landt het tekstvak in de rechterkolom, dan spant het twee rijen.
	 *
	 * Het raster vult van links naar rechts, dus een tekstvak op een oneven index
	 * komt rechts te staan. Zonder deze regel blijft er een gat onder het veld
	 * links ernaast. section-formulier.php leidt de klasse af uit de veldvolgorde
	 * in f59_form_configs(), dus een veld erbij valt vanzelf de goede kant op.
	 */
	.form--tekstvak-rechts .field--tekstvak {
		grid-column: 2;
		grid-row: span 2;
	}
}

/*
 * position: relative draagt het zwevende label. De flexkolom blijft staan voor de
 * foutmelding, die forms.js met appendChild onder het veld hangt; label en hint
 * staan allebei buiten de flow, dus die kolom heeft nog maar twee kinderen.
 */
.field {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
	margin: 0;
}

/*
 * --label-lucht is de ruimte links en rechts van de labeltekst. Die lucht is wat de
 * inkeping maakt: de labelgrond overschildert de rand een streepje breder dan de
 * letters zelf, zodat het geen tekst-op-een-lijn wordt maar een echte onderbreking.
 *
 * left is daarom niet los gekozen. De labelTEKST hoort op de tekstinspring van het
 * veld te beginnen (padding 1rem), dus het KADER begint een lucht eerder.
 * 1rem - 0.35rem is de 0.65rem die hier tot 8 september 2026 als kaal getal stond.
 */
.field__label {
	--label-lucht: 0.35rem;

	position: absolute;
	left: calc(1rem - var(--label-lucht));
	top: 1.75rem;
	transform: translateY(-50%);
	padding: 0 var(--label-lucht);
	background-color: var(--label-grond);
	color: var(--text-on-dark-muted);
	font-family: var(--font-sans);
	font-size: var(--text-button);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-widest);
	line-height: 1;
	text-transform: uppercase;

	/*
	 * Hier stond `white-space: nowrap`. Dat hield het label op één regel, en dat
	 * is ook wat de inkeping vraagt, maar bij 200 procent tekstvergroting liep
	 * "TELEFOON (OPTIONEEL)" daardoor 36px buiten het venster: het label is dan
	 * 300px breed in een veld van 270. Gemeten op 8 september 2026 op /contact/
	 * en /bedrijfsruimte-huren/, op 390px met een wortelmaat van 32px.
	 *
	 * Met een max-width en gewoon wikkelen blijft het label bij normale maat op
	 * één regel (hij past dan ruim) en zakt hij bij vergroting naar twee regels
	 * over de veldrand heen. Dat is lelijker dan de inkeping, maar het is de
	 * enige vorm waarin de labeltekst helemaal leesbaar blijft; afkappen met een
	 * ellips zou tekst weghalen en dat is precies wat WCAG 1.4.4 verbiedt.
	 *
	 * De aftrek is twee keer de eigen inspring, zodat de rechterkant van het
	 * label op dezelfde lijn stopt als de linkerkant begint.
	 */
	max-width: calc(100% - 2 * (1rem - var(--label-lucht)));
	/* Breekt tussen "TELEFOON" en "(optioneel)" en niet middenin een woord. */
	overflow-wrap: break-word;

	/* Het label ligt op het veld, dus een klik erop moet in het veld landen. */
	pointer-events: none;
	transition:
		transform var(--duration-base) var(--ease-out),
		color var(--duration-base) var(--ease-out);
}

.section-light .field__label { color: var(--text-on-light-muted); }

/* Het "(optioneel)" valt uit de labelmaat, anders leest het als een tweede label. */
.field__label .muted {
	font-weight: var(--weight-regular);
	letter-spacing: 0;
	text-transform: none;
}

/*
 * Twee haken, en de tweede is de belangrijkste. :focus tilt het label op zodra je
 * in het veld staat; :not(:placeholder-shown) houdt het daar zodra er iets in
 * staat. Elk veld draagt daarom een placeholder, desnoods een spatie, want zonder
 * dat attribuut matcht die selector nooit en zakt het label over de invoer heen.
 */
.field__control:focus + .field__label,
.field__control:not(:placeholder-shown) + .field__label {
	transform: translateY(-1.75rem);
	color: var(--color-cream);
}

/*
 * Op licht wordt het opgetilde label rood. Dat mag hier wel en op donker niet:
 * #b22222 op wit haalt 6,4:1, op #1a1614 blijft het op 2,9:1 steken. Vandaar
 * --color-cream aan de donkere kant.
 */
.section-light .field__control:focus + .field__label,
.section-light .field__control:not(:placeholder-shown) + .field__label {
	color: var(--color-red);
}

/* Het tekstvak heeft eigen padding, dus zijn label ligt hoger en reist minder ver. */
.field--tekstvak .field__label { top: 1.5rem; }

.field--tekstvak .field__control:focus + .field__label,
.field--tekstvak .field__control:not(:placeholder-shown) + .field__label {
	transform: translateY(-1.5rem);
}

/*
 * Een tekstvak knipt zijn inhoud pas op de padding-box en niet op de content-box.
 * Scroll je in een vol berichtveld, dan komt de bovenste regel dus de padding-band
 * van 16px in en botst hij tegen het labelplaatje: op 8 september 2026 gemeten en
 * ingezoomd bekeken, "vullen" liep dwars door "BERICHT (optioneel)" heen.
 *
 * Deze strip dekt precies die band af. Hij begint op 1px, dus BINNEN de rand: de
 * rand blijft staan en de inkeping die het label maakt blijft onaangeroerd. Dat is
 * de reden dat hij niet de volle veldbreedte krijgt maar de volle binnenbreedte.
 * Een strip die de rand wel raakt zou de inkeping wegpoetsen, en die inkeping is
 * precies waar variant D om is gekozen.
 *
 * De hoogte is de padding-top van het tekstvak. Wijzigt die, dan wijzigt deze mee.
 */
.field--tekstvak::before {
	content: "";
	position: absolute;
	top: 1px;
	left: 1px;
	right: 1px;
	height: 1rem;
	background-color: var(--label-grond);
	pointer-events: none;
	z-index: 1;
}

/* Het label ligt boven de strip, anders dekt de strip de labeltekst af. */
.field--tekstvak .field__label { z-index: 2; }

/* =======================================================================
 * HET VELD IS EEN RAND EN GEEN VLAK
 *
 * Hier stond tot 8 september 2026 het blok "HET VELD IN HET PANEEL GAAT EEN TRAP
 * NAAR BENEDEN": vier regels die het veld in een paneel een tint donkerder zetten
 * dan het paneel zelf, omdat een veld dat lichter is dan zijn grond binnen een
 * paneel onzichtbaar wordt.
 *
 * Dat probleem bestaat niet meer, want er is geen vlak meer om zichtbaar te maken.
 * Het veld is nu transparant en de rand draagt de veldgrens in zijn eentje. Het
 * moet ook transparant zijn: het zwevende label heeft de PANEELkleur achter zich
 * en snijdt daarmee een gat in de rand. Zou het veld een eigen kleur hebben, dan
 * zou het label een blokje van de verkeerde tint in dat veld worden.
 *
 * De hoogte is 3,5rem (56px) en dat is met opzet meer dan --touch-min (48px): het
 * label moet er in rust in passen zonder de tekst te raken.
 * ======================================================================= */

.field__control {
	display: block;
	width: 100%;
	height: 3.5rem;
	padding: 0 1rem;
	background-color: transparent;
	/*
	 * 38 procent en niet de 25 die hier stond, en niet de 28 uit het prototype.
	 * De rand is het enige dat de veldgrens nog draagt, en WCAG 1.4.11 vraagt 3:1
	 * voor de omtrek van een invoerveld. Gerekend op de paneelkleur: 25% geeft
	 * 2,15:1, 35% haalt 3,02:1 en 38% geeft 3,34:1. De marge zit erin omdat het
	 * formulier ook buiten een paneel kan staan, en dan is de grond een tint
	 * donkerder.
	 */
	border: 1px solid color-mix(in srgb, var(--color-white) 38%, transparent);
	border-radius: var(--radius-none);
	color: inherit;
	font-family: var(--font-sans);
	/*
	 * 16px en niet de 0,875rem die het brandbook bij het invoerveld noteert. Onder
	 * 16px zoomt iOS Safari in zodra je in een veld tikt, en die zoom gaat er daarna
	 * niet vanzelf af: de hele pagina verspringt en de bezoeker moet terugknijpen.
	 * Dit is de enige plek waar de bouw bewust van de brandbook-schaal afwijkt, en
	 * de referentie doet het fout: Strijp-S staat op 13,33px.
	 */
	font-size: var(--text-body);
	transition: border-color var(--duration-base) var(--ease-out);
}

/* Op licht is er meer nodig voor dezelfde 3:1: 45% haalt 3,06:1, 48% geeft 3,36:1. */
.section-light .field__control {
	border-color: color-mix(in srgb, var(--color-black) 48%, transparent);
}

/*
 * De rand trekt aan bij hover. Zonder dit reageert het veld nergens op tot je erin
 * klikt, en de rand is bij deze vorm het enige dat het veld begrenst.
 *
 * :not(:focus) erbij omdat de licht-variant hieronder een selector hoger scoort dan
 * de focus-regel. Zonder die uitsluiting zou de muis boven een gefocust veld de rode
 * rand terugzetten naar grijs.
 */
@media (hover: hover) {

	.field__control:hover:not(:focus) {
		border-color: color-mix(in srgb, var(--color-white) 58%, transparent);
	}

	.section-light .field__control:hover:not(:focus) {
		border-color: color-mix(in srgb, var(--color-black) 70%, transparent);
	}
}

.field__control:focus {
	outline: none;
	border-color: var(--color-red);
}

/*
 * De placeholder draagt de hint, en die hint is de reden dat het formulier klein
 * blijft. Hij is onzichtbaar tot je in het veld staat, want tot dat moment ligt
 * het label er nog overheen. De span met dezelfde tekst blijft bestaan voor
 * aria-describedby, zie section-formulier.php.
 */
.field__control::placeholder { color: transparent; }

.field__control:focus::placeholder { color: var(--text-on-dark-faint); }

/*
 * 45% haalde 3,05:1 op de witte paneelgrond, en dat is de drempel voor grote tekst
 * en niet voor deze. Een placeholder is hier geen sierlijke hulptekst: hij draagt
 * Gregs vraag, en zodra het label omhoog staat is dit de enige plek waar die vraag
 * nog te lezen is. Dus geldt gewoon 4,5:1. 58% zet hem op rgb(118,116,115) en
 * daarmee op 4,64:1. Op donker staat hij op --text-on-dark-faint, 5,58:1, en die
 * hoeft dus niet mee.
 */
.section-light .field__control:focus::placeholder {
	color: color-mix(in srgb, var(--color-black) 58%, transparent);
}

/* De focus blijft ook zichtbaar via de globale focus-ring, zie base.css. */
.field__control:focus-visible {
	outline: var(--focus-width) solid var(--focus-color);
	outline-offset: var(--focus-offset);
}

textarea.field__control {
	height: 9.5rem;
	padding: 1rem;
	line-height: 1.55;
	resize: vertical;
}

.field--checkbox {
	flex-direction: row;
	align-items: flex-start;
	gap: 0.75rem;
	/* Zodat een foutmelding onder het vinkje valt en niet ernaast. */
	flex-wrap: wrap;
}

/*
 * margin-top is een optische nudge en geen centrering. Het vakje is 20px en de
 * eerste regelbox van het label is 21px (14px maal 1,5), dus rekenkundig centreren
 * zou 0,5px zijn. Die regelhoogte legt haar lucht boven en onder de letters, en
 * daardoor lijkt het vakje dan te hoog te staan. 0.2rem zet hem op de x-hoogte van
 * de eerste regel, wat is waar het oog hem verwacht.
 */
.field--checkbox input {
	width: 1.25rem;
	height: 1.25rem;
	margin-top: 0.2rem;
	accent-color: var(--color-red);
	flex: 0 0 auto;
}

/*
 * Het vinkje staat sinds 8 september 2026 náást het tekstvak in plaats van eronder,
 * dus zijn tekst moet in een halve kolom passen. Zonder flex: 1 1 0 houdt het label
 * zijn eigen breedte en springt het door de flex-wrap hierboven naar een tweede
 * regel onder het vakje. min-width: 0 laat de tekst binnen die kolom afbreken.
 */
.field--checkbox > label {
	flex: 1 1 0;
	/*
	 * Het label is het raakvlak, want het vakje zelf is maar 20 bij 20. Gemeten op
	 * 8 september 2026 was het 251 bij 42 op elke breedte van 390 tot 2560, dus ruim
	 * boven de 24px van WCAG 2.5.8 maar zes pixels onder de --touch-min die dit thema
	 * zichzelf oplegt en die op de knop en het veld wel wordt gehaald. Met flex-start
	 * op de rij groeit alleen de klikbare doos naar beneden en verschuift er geen tekst.
	 */
	min-height: var(--touch-min);
	min-width: 0;
	font-size: var(--text-body-sm);
	line-height: 1.5;
}

.field--error .field__control { border-color: var(--color-error); }

/*
 * Het akkoord-vinkje draagt geen .field__control, dus de randregel hierboven raakt
 * het niet. Zonder deze regel is het enige teken dat er iets mis is de tekst
 * eronder, en dat is precies het veld dat het vaakst wordt overgeslagen.
 */
.field--error input[type="checkbox"] {
	outline: var(--focus-width) solid var(--color-error);
	outline-offset: 2px;
}

.section-dark .field--error input[type="checkbox"],
.section-shadow .field--error input[type="checkbox"],
.section-deep .field--error input[type="checkbox"] {
	outline-color: var(--color-error-on-dark);
}

.field__error {
	font-size: var(--text-body-sm);
	color: var(--color-error);
}

.field--checkbox .field__error { flex: 0 0 100%; }

.section-dark .field__error,
.section-shadow .field__error,
.section-deep .field__error {
	/* #dc2626 op donker haalt geen 4,5:1, dus de fouttekst wordt lichter. */
	color: var(--color-error-on-dark);
}

/*
 * De houder van de statusmelding staat altijd in het document, ook leeg, want een
 * live region die pas bij de melding wordt aangemaakt wordt door een schermlezer
 * niet voorgelezen. `:empty` houdt hem uit de weg zolang er niets in zit; hij mag
 * dus geen eigen padding of marge krijgen.
 */
.form__meldingen:empty { display: none; }

.form__status {
	margin-bottom: var(--gap-sm);
	padding: var(--gap-sm);
	border-left: 3px solid var(--color-red);
	background-color: var(--wash-red);
}

.form__status--ok { border-left-color: var(--color-success); }

/*
 * De knop tijdens het versturen. Zonder dit ziet een trage verbinding er precies
 * hetzelfde uit als een knop die niets doet, en dan klikt iemand nog een keer. De
 * snelheidsbegrenzing staat op vijf inzendingen per uur, dus elke dubbele klik kost
 * de bezoeker er twee.
 */
.btn[disabled] {
	opacity: 0.6;
	cursor: wait;
}

/* Het honeypot-veld staat buiten beeld met een klasse, niet met een inline stijl. */
.form-honeypot {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/* De Instagram-band als tegelrij: leeg met de 59, of gevuld met de berichten. */
.tiles {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--gap-xs);
}

/*
 * Onder 768px maar drie tegels, op één rij.
 *
 * Op twee kolommen stapelden zes vierkanten tot drie rijen, en op 390px was dat
 * 725px van een pagina van 3927: zwaarder dan elk van de drie lege staten op deze
 * pagina afzonderlijk. Dat viel pas op nadat die lege staten in de revisie van
 * 26 augustus 2026 waren gekrompen. De tegels zijn decoratief en aria-hidden, dus
 * er gaat geen informatie verloren als er drie wegvallen.
 *
 * Drie kolommen en niet twee, want drie tegels op twee kolommen laat er een alleen
 * op een tweede rij achter. Op desktop blijven het er zes: daar lezen ze als
 * textuur en niet als een blok.
 */
@media (max-width: 767px) {

	.tiles {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}

	.tiles .tile:nth-child(n+4) {
		display: none;
	}
}

@media (min-width: 640px) {
	.tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/*
 * Zes kolommen vanaf 768 en niet vanaf 1024, en dat is een gemeten keuze.
 *
 * De tegels zijn vierkant, dus hun hoogte volgt de kolombreedte. Met drie
 * kolommen stonden de zes tegels tussen 768 en 1023 in twee rijen van ruim 320px,
 * en op 1024 sprongen ze naar een rij van 160. Gemeten op de grens 1023/1024:
 * de sectie ging van 872px naar 388px, een verschil van 484px op één pixel
 * vensterbreedte. Dat was het zwaarste blok van de hele nieuwspagina op tablet,
 * zwaarder dan op 390px, en het stond als open besluit in ROADMAP.md.
 *
 * Met deze grens springen de tegels op 1023/1024 niet meer, nagemeten op
 * 8 september 2026: op die grens bewegen op de nieuwspagina alleen nog
 * .agenda__raster (2 naar 3 kolommen) en .doelen (3 naar 5), en .tiles staat er
 * niet meer bij. Let op wat dat NIET zegt: de grens 1023/1024 zelf bestaat nog
 * wel, want die twee rasters wisselen daar hun kolomaantal.
 *
 * Wat ervoor terugkomt is een sprong van 168px op 767/768, gemeten op home en op
 * nieuws. Dat is de breedte waar de hele indeling toch al van één naar twee
 * kolommen gaat, dus daar valt hij niet op als een losse hik.
 */
@media (min-width: 768px) {
	.tiles { grid-template-columns: repeat(6, minmax(0, 1fr)); }
}

.tile {
	aspect-ratio: 1;
	background-color: var(--color-black);
	background-image: var(--pattern-weave);
	display: grid;
	place-items: center;
	color: var(--text-on-dark-faint);
	font-size: var(--text-button);
	letter-spacing: var(--tracking-widest);
	text-transform: uppercase;
}

/* =======================================================================
 * Header en navigatie
 *
 * De header staat vast bovenaan en doet drie dingen: na 50px scroll een donker
 * vlak met blur en krimpende padding, bij naar beneden scrollen verdwijnt hij,
 * bij omhoog komt hij terug.
 *
 * Eén transitieduur voor vlak en beweging samen. In het oude thema stond die op
 * twee plekken verschillend (0.4s en 0.5s), waardoor ze niet synchroon liepen.
 * ======================================================================= */

.site-header {
	position: fixed;
	inset: 0 0 auto 0;
	z-index: var(--z-header);
	padding-block: var(--gap-sm);
	transition:
		background-color var(--duration-chrome) var(--ease-out),
		backdrop-filter var(--duration-chrome) var(--ease-out),
		padding var(--duration-chrome) var(--ease-out),
		transform var(--duration-chrome) var(--ease-out);
}

/*
 * Liggende telefoon: 16px lucht in plaats van 32, dus een balk van 72px in
 * plaats van 104. Op 844x390 was de balk meer dan een kwart van het scherm.
 *
 * Deze regel MOET na .site-header hierboven staan en niet in het hero-blok waar
 * de rest van deze stand zit: een media-query telt niet mee in de specificiteit,
 * dus daar verloor hij van de padding-block een paar honderd regels verderop.
 * Gemeten toen de balk 104px bleef terwijl --header-hoogte al 72 zei.
 *
 * --header-hoogte staat in tokens.css op dezelfde voorwaarde. Verandert er een,
 * dan liegt de ander.
 */
@media (max-height: 520px) and (orientation: landscape) {

	.site-header {
		padding-block: 1rem;
	}
}

.site-header.is-scrolled {
	padding-block: 0.75rem;
	background-color: var(--overlay-header);
	backdrop-filter: blur(var(--overlay-header-blur));
}

.site-header.is-hidden {
	transform: translateY(-100%);
}

.site-header__inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--gap-sm);
}

.nav-primary { display: none; }

/*
 * DE HEADERGRENZEN STAAN IN EM EN NIET IN PX, EN DAT IS EEN MEETRESULTAAT
 *
 * 56.25em is bij de standaard 16px exact 900px en 70em exact 1120px, dus bij een
 * bezoeker die niets heeft ingesteld verandert er niets. Wat wel verandert is de
 * bezoeker die zijn lettergrootte opschroeft: een em-grens rekent met de
 * browserinstelling, dus bij 200 procent staat de wissel op 1800px en 2240px.
 *
 * Waarom dat moet, gemeten op 8 september 2026 op 1440x900 met Chrome zijn eigen
 * standaardlettergrootte op 32px (via CDP Page.setFontSizes, en niet met een
 * font-size op <html>, want dat laatste laat een em-query juist koud):
 * de balk stond in desktopstand, het menu stak 215px buiten het venster en de
 * header-CTA "Plan je route" liep van 1719 tot 2045. Beide onbereikbaar, want de
 * pagina scrolt niet horizontaal: ze zaten afgeknipt en niet naast de rand.
 *
 * De grens hangt af van hoeveel tekst er in de balk past, en dat is geen
 * vensterbreedte maar een verhouding tussen vensterbreedte en lettergrootte. Een
 * px-grens kan dat niet uitdrukken.
 *
 * Alle acht de header-blokken staan hierdoor in em: deze drie voor de navigatie,
 * twee voor de header-CTA en de zwevende pil, twee voor het woordmerk, en
 * --header-hoogte in tokens.css. Zet er nooit een terug naar px: dan valt de
 * balk halverwege uit elkaar.
 */
@media (min-width: 56.25em) {

	.nav-primary { display: block; }

	/* De tussenruimte zit nu in de padding van het item zelf, want daar staat ook
	   het hover-vlak op. Blijft de gap op 2rem staan, dan telt de ruimte dubbel
	   en wordt de header-CTA klemgedrukt tot twee regels. */
	.nav-primary__list {
		display: flex;
		align-items: center;
		gap: 0.25rem;
		list-style: none;
		margin: 0;
		padding: 0;
	}

	/*
	 * De tracking gaat van 0.1em naar 0.08em en de tekstmaat mag krimpen tot
	 * 11px. Zes menu-items waarvan twee van twee woorden ("Nieuws en events",
	 * "Bedrijfsruimte huren") vulden op 1440 samen 793px, en dat las als een
	 * opgepropte rij. 0.08em is dezelfde waarde als het kaartlabel, dus het is
	 * een bestaand token en geen nieuwe uitzondering.
	 */
	.nav-primary__list a {
		position: relative;
		isolation: isolate;
		display: inline-block;
		padding: 0.5rem 0.75rem;
		font-family: var(--font-sans);
		font-size: clamp(0.6875rem, 0.78vw, var(--text-button));
		font-weight: var(--weight-bold);
		letter-spacing: var(--tracking-wide);
		text-transform: uppercase;
		text-decoration: none;
		white-space: nowrap;
		transition: color var(--duration-base) var(--ease-out);
	}

	/*
	 * Hover is een vlak dat achter het label opkomt, niet alleen een kleur.
	 * Gestolen bij Speakeasy (gemeten 18 augustus 2026): hun navigatie zet een
	 * ::before van opacity 0 naar 1. Hier met een schaal erbij, zodat het vlak
	 * ook echt aankomt in plaats van te verschijnen.
	 */
	.nav-primary__list a::before {
		content: "";
		position: absolute;
		inset: 0;
		z-index: -1;
		background-color: color-mix(in srgb, var(--color-white) 12%, transparent);
		opacity: 0;
		transform: scaleY(0.6);
		transition:
			opacity var(--duration-base) var(--ease-out),
			transform var(--duration-base) var(--ease-out);
	}

	.nav-primary__list a:focus-visible::before {
		opacity: 1;
		transform: none;
	}

	@media (hover: hover) {

		.nav-primary__list a:hover::before {
			opacity: 1;
			transform: none;
		}
	}

		@media (hover: hover) {

		.nav-primary__list a:hover { color: var(--color-cream); }
	}

	.nav-primary__list .current-menu-item > a {
		box-shadow: inset 0 -2px 0 var(--color-red);
	}
}

/*
 * De header-CTA staat naast het menu en verdwijnt zodra hij niet meer past,
 * want dan staat de zwevende pil er.
 *
 * 1120 EN NIET 900, EN DAT IS GEMETEN. De hele balk heeft logo plus zes
 * menu-items plus deze knop nodig, en dat is op 8 september 2026 per pagina
 * opgemeten op staging: 1079px op negen pagina's, 1098 op de homepage en
 * 1109 op /route/, waar de knop "Open je navigatie" heet in plaats van
 * "Plan je route".
 *
 * De knop stond tot die dag vanaf 900px in de balk. Van 900 tot 1035 stak hij
 * daardoor buiten het venster: op precies 900 hing hij er 135px naast en dus
 * grotendeels onzichtbaar, op 1024 nog 11px. Dat is de primaire actie van de
 * site, op de breedte van een iPad in landschap.
 *
 * Alleen de knop schuift op. De navigatie blijft op 900 desktop worden, want
 * die past daar wel (858px nodig zonder de knop). Onder 1120 draagt de
 * zwevende bezoek-pil de actie, en die blijft daarom even lang staan.
 */
.header-cta { display: none; }

@media (min-width: 70em) {
	/* nowrap is hier geen detail: op 1440 brak "Plan je bezoek" over twee regels
	   en dat is precies wat de header opgepropt liet lijken. */
	.header-cta {
		display: inline-flex;
		flex: 0 0 auto;
		white-space: nowrap;
	}
}

/*
 * De zwevende menuknop, rechtsonder. Duimvriendelijk en direct herkenbaar: een
 * cirkel van 64px in rood met een contour die hem van de achtergrond losknipt.
 */
.menu-toggle {
	position: fixed;
	right: var(--container-px);
	bottom: var(--container-px);
	z-index: var(--z-menu-toggle);
	display: grid;
	place-items: center;
	width: var(--zwevend-knop);
	height: var(--zwevend-knop);
	border-radius: var(--radius-pill);
	background-color: var(--color-red);
	border: 4px solid var(--color-deep);
	color: #ffffff;
	transition:
		background-color var(--duration-base) var(--ease-out),
		transform var(--duration-base) var(--ease-out);
}

@media (hover: hover) {

	.menu-toggle:hover { background-color: var(--color-red-hover); }
}
.menu-toggle:active { transform: scale(0.95); }

@media (min-width: 56.25em) {
	.menu-toggle { display: none; }
}

/*
 * Zolang het menu open staat ligt de knop erboven, want hij is dan de sluitknop.
 * De reden en de meting staan bij --z-menu-sluit in tokens.css.
 */
body.has-menu-open .menu-toggle {
	z-index: var(--z-menu-sluit);
}

/* De sticky bezoek-CTA op mobiel, linksonder, naast de menuknop en niet eronder. */
.visit-cta {
	position: fixed;
	left: var(--container-px);
	bottom: var(--container-px);
	z-index: var(--z-menu-toggle);
	max-width: calc(100vw - var(--zwevend-knop) - var(--container-px) * 3);
	border-radius: var(--radius-pill);
	/* In pixels om dezelfde reden als --zwevend-knop: de ruimte rond de tekst is
	   een aanraakvlak en hoort niet mee te verdubbelen met de tekst zelf. Op
	   1rem 1.5rem was bij 200 procent 96px van de 142px beschikbare breedte
	   padding, en dan is er voor het woord zelf niets meer over. */
	padding: 16px 24px;
}

/* Even lang als de header-CTA weg is, want samen dekken ze elke breedte:
   onder 1120 de pil, erboven de knop in de balk. Zie de uitleg bij
   .header-cta hierboven. */
@media (min-width: 70em) {
	.visit-cta { display: none; }
}

/*
 * LIGGEND OP EEN TELEFOON VERHUIST DE BEZOEK-CTA NAAR DE BALK.
 *
 * De pil staat vast linksonder, en dat is precies waar de hero zijn eigen knop
 * heeft staan. Staand valt dat niet op, want de hero is dan een volle schermhoogte
 * en die knop staat halverwege. Liggend is er 375 tot 430px hoogte en komen ze op
 * elkaar. Gemeten op 8 september 2026 op staging: op 667x375 lag de pil 157 bij 48
 * pixels over de heroknop van de homepage en 157 bij 30 over die van
 * /bedrijfsruimte-huren/, en elementFromPoint midden op de heroknop gaf in beide
 * gevallen de pil terug. Op 932x430 gold hetzelfde voor huren. Twee rode blokken
 * over elkaar, met de tekst van de onderste onleesbaar.
 *
 * Weghalen was de eerste gedachte, maar dan heeft een liggende telefoon als enige
 * stand geen doorlopende bezoek-CTA meer. De balk heeft liggend juist ruimte in
 * overvloed: onder 900px draagt hij alleen het woordmerk, want de navigatie zit
 * dan in het mobiele menu. Dus daar gaat hij heen, precies zoals hij dat boven
 * 1120px ook al doet.
 */
@media (max-height: 520px) and (orientation: landscape) {

	.visit-cta { display: none; }

	.header-cta {
		display: inline-flex;
		flex: 0 0 auto;
		white-space: nowrap;
	}
}

/*
 * EN STAAND OP EEN KORTE TELEFOON GAAT HIJ OM DEZELFDE REDEN MEE.
 *
 * Het blok hierboven zegt dat het staand niet opvalt omdat de hero dan een volle
 * schermhoogte is en de knop halverwege staat. Dat geldt voor een telefoon van nu
 * en niet voor 320x568 of 360x640. Gemeten op 8 september 2026 op staging, nadat
 * de hero op die twee standen was ingekort: op 360x640 lag de pil 157 bij 28
 * pixels over de heroknop van home en gaf elementFromPoint midden op die knop de
 * pil terug, op 320x568 was dat 157 bij 42 op Bezoekers. De knop was daarmee niet
 * meer aan te tikken.
 *
 * Nagemeten of de balk hem draagt op de smalste stand: op 320px staat de CTA van
 * 157px op x 142 tot 299 met nul horizontale overloop, en de menuknop zweeft en
 * staat niet in de balk. De balk wordt daarmee 112px in plaats van 104, en dat
 * staat als eigen regel in tokens.css; zonder die regel liegt --header-hoogte
 * 8px, precies zoals dat tussen 900 en 1024 gebeurde.
 *
 * 700px is dezelfde grens als bij de hero-blokken: een telefoon van nu is 844 tot
 * 932 hoog en valt er buiten.
 */
@media (max-height: 700px) and (orientation: portrait) {

	.visit-cta { display: none; }

	.header-cta {
		display: inline-flex;
		flex: 0 0 auto;
		white-space: nowrap;
	}
}

/* Het mobiele menu: schermvullend, items in serif italic op 36px. */
.nav-mobile {
	position: fixed;
	inset: 0;
	z-index: var(--z-menu);
	display: flex;
	flex-direction: column;
	justify-content: center;
	/* Op een liggende telefoon is de lijst hoger dan het venster. Zonder deze
	   twee regels is er niet naartoe te scrollen, en snijdt een gecentreerde
	   flexkolom bovendien de bovenkant af op een plek die onbereikbaar is.
	   safe center valt in een oudere browser terug op de regel erboven. */
	justify-content: safe center;
	overflow-y: auto;
	overscroll-behavior: contain;
	padding: var(--section-md) var(--container-px);
	background-color: var(--color-deep);
	opacity: 0;
	visibility: hidden;
	transform: translateY(1rem);
	transition:
		opacity var(--duration-chrome) var(--ease-out),
		transform var(--duration-chrome) var(--ease-out),
		visibility var(--duration-chrome);
}

.nav-mobile.is-open {
	opacity: 1;
	visibility: visible;
	transform: none;
}

.nav-mobile__list {
	list-style: none;
	margin: 0;
	padding: 0;
}

.nav-mobile__list a {
	display: block;
	padding: 0.5rem 0;
	font-family: var(--font-serif);
	font-size: var(--text-mobile-menu);
	font-style: italic;
	font-weight: var(--weight-semibold);
	letter-spacing: var(--tracking-tighter);
	text-decoration: none;
	transition: color var(--duration-base) var(--ease-out);
}

@media (hover: hover) {

	.nav-mobile__list a:hover { color: var(--color-cream); }
}

@media (min-width: 56.25em) {
	.nav-mobile { display: none; }
}

/*
 * Liggend op een telefoon krimpt het menu mee, want daar is de HOOGTE de krappe
 * maat en niet de breedte.
 *
 * --text-mobile-menu is een clamp op vw en loopt omlaag naarmate het venster
 * SMALLER wordt. Liggend is het venster juist breed (844) en laag (390), dus die
 * clamp geeft er zijn maximum van 36px, precies in de stand waar het niet past.
 * Gemeten op 8 september 2026 op staging, op 844x390: de lijst was 628px hoog in
 * een venster van 390, dus de laatste twee items stonden onder de vouw. Scrollen
 * kon wel, daar is .nav-mobile op ingericht, maar een menu van zes items hoort in
 * één blik te passen. Na deze drie regels is de lijst 315px en de padding 2 keer
 * 31,8, samen 379 in een venster van 390.
 *
 * De regelafstand gaat mee omlaag en de padding op het item blijft staan. Dat is
 * de volgorde die het aanraakvlak spaart: 24,4px op 1,5 plus 2 keer 8px padding is
 * 53px per item, gemeten, en dat blijft boven de 48px van --touch-min. Andersom,
 * met de padding eraf, was het 48px net niet geworden.
 *
 * DIT BLOK MOET NA DE BASISREGEL VAN .nav-mobile STAAN. Die zet `padding` als
 * shorthand, en een media-query telt niet mee in de specificiteit. Stond het bij
 * de andere liggend-regels een paar honderd regels hierboven, dan won de shorthand
 * en bleef de padding op 71px staan. Dat is hier gemeten en het is dezelfde val
 * als bij .site-header, zie de uitleg daar.
 */
@media (max-height: 520px) and (orientation: landscape) {

	.nav-mobile {
		--text-mobile-menu: var(--text-h3);
		padding-block: var(--gap-md);
	}

	.nav-mobile__list a {
		line-height: var(--leading-relaxed);
	}
}

/*
 * Staand op een KORTE telefoon past het menu ook niet, en om een andere reden.
 *
 * Liggend is --text-mobile-menu het probleem, want die clamp staat op zijn
 * maximum juist als het venster laag is. Staand op 320x568 staat die maat op zijn
 * minimum en is de lijst 499px, dus de letter is hier niet de dader: de padding
 * is dat. Die staat op --section-md, en dat is 48px per kant op 320. Samen 595px
 * in een venster van 568, dus het laatste item stond onder de vouw. Scrollen kon
 * wel, maar een menu van acht items hoort in een blik te passen.
 *
 * Met --gap-md staat er 24px per kant en is het geheel 547px in 568. Gemeten op
 * 8 september 2026 op staging, op 320x568. De letter en de regelafstand blijven
 * hier onaangeroerd, want het aanraakvlak per item is op deze stand al het
 * krapst.
 *
 * Ook dit blok moet NA de basisregel van .nav-mobile staan, om dezelfde reden als
 * het liggende blok hierboven: die zet `padding` als shorthand.
 */
@media (max-height: 700px) and (orientation: portrait) {

	.nav-mobile {
		padding-block: var(--gap-md);
	}
}

/* Het scrollen van de pagina blokkeren zolang het menu open is. */
body.has-menu-open { overflow: hidden; }

/* =======================================================================
 * Footer
 *
 * DE COMBINATIE VAN 28 AUGUSTUS 2026: de vier kolommen uit variant A, het
 * massieve woordmerk uit variant B, de rode streep bij de openingstijden uit het
 * museumbordje. De onderbouwing per onderdeel staat in footer.php.
 *
 * De voet is nu een EIGEN VLAK. Hij stond op --color-deep, de sectie erboven op
 * --color-dark of --color-shadow, en op een screenshot liepen die zonder overgang
 * in elkaar over. Het weefpatroon geeft hem een eigen materiaal zonder dat er een
 * scheidingslijn of een extra sectie voor nodig is.
 * ======================================================================= */

.site-footer {
	position: relative;
	/*
	 * Geen bodemruimte meer onder de kolommen: het woordmerk sluit de voet af en
	 * die draagt zijn eigen marge. Onder 900px komt de zwevende strook er wel bij,
	 * zie hieronder.
	 */
	padding-block: var(--section-md) 0;
	overflow: hidden;
}

/*
 * Het weefpatroon als grond. Als ::before en niet als background op .site-footer
 * zelf, want dan zou de sectiekleur eronder verdwijnen.
 */
.site-footer::before {
	content: '';
	position: absolute;
	inset: 0;
	background-image: var(--pattern-weave);
	opacity: 0.05;
	pointer-events: none;
}

/* Alles boven de grond, anders ligt het patroon over de tekst. */
.site-footer > * {
	position: relative;
}

.site-footer__inner {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--gap-lg);
}

@media (min-width: 768px) {

	/*
	 * Vier kolommen, en de openingstijden krijgen de brede. Dit is de indeling
	 * van variant A: het antwoord dat iemand onderaan een pagina nog zoekt staat
	 * vooraan en niet weggestopt achter de menulinks.
	 */
	.site-footer__inner {
		grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr);
		gap: var(--gap-lg);
	}
}

.site-footer__address {
	font-style: normal;
	line-height: var(--leading-loose);
	/* 0.55 en niet 0.40: op 0.40 haalde de footer circa 3,9:1 en zakte door AA. */
	color: var(--text-on-dark-faint);
}

.site-footer__address a { text-decoration: none; }
@media (hover: hover) {

	.site-footer__address a:hover { color: var(--color-white); }
}

/*
 * De openingstijden: de rode streep van het museumbordje, en een maat groter dan
 * de rest van de voet. "Iets duidelijker, maar niet zo prominent als in variant
 * C", en dat is precies het verschil tussen --text-body hier en --text-body-lg
 * daar.
 */
.site-footer__tijden {
	border-left: 2px solid var(--color-red);
	padding-left: var(--gap-sm);
}

.site-footer__uren {
	font-size: var(--text-body);
	line-height: var(--leading-loose);
	color: var(--text-on-dark);
	margin: 0;
}

.site-footer__door {
	margin: 0.75rem 0 0;
	font-size: var(--text-body-sm);
}

.site-footer__door a {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	text-decoration: none;
	color: var(--text-on-dark-faint);
	transition: color var(--duration-base) var(--ease-out);
}

@media (hover: hover) {

	.site-footer__door a:hover { color: var(--color-white); }
}

.site-footer__pijl {
	transition: transform var(--duration-base) var(--ease-out);
}

@media (hover: hover) {

	.site-footer__door a:hover .site-footer__pijl {
		transform: translateX(4px);
	}
}

.nav-footer__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
}

.nav-footer__list a {
	font-size: var(--text-body-sm);
	text-decoration: none;
	color: var(--text-on-dark-faint);
	transition: color var(--duration-base) var(--ease-out);
}

@media (hover: hover) {

	.nav-footer__list a:hover { color: var(--color-white); }
}

.footer-heading {
	font-family: var(--font-sans);
	font-size: var(--text-button);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-widest);
	text-transform: uppercase;
	margin-bottom: var(--gap-xs);
}

/*
 * Een tweede kop in dezelfde kolom heeft lucht boven zich nodig.
 *
 * "Volgen" plakte tegen de laatste menulink van "Op deze site", want een
 * .footer-heading heeft alleen een ondermarge. Op een screenshot van 28 augustus
 * 2026 zag je twee kopjes die bij elkaar leken te horen. Gemeten en niet geschat.
 *
 * Sinds de vier kolommen staan die twee koppen niet meer onder elkaar, maar de
 * regel blijft: hij dekt elke kolom waar dat wel gebeurt, bijvoorbeeld als het
 * footermenu niet is toegewezen.
 */
.site-footer :is( nav, ul ) + .footer-heading {
	margin-top: var(--gap-sm);
}

/* De slotregel: wat dit is, links, en het copyright rechts. */
.site-footer__slot {
	display: flex;
	flex-wrap: wrap;
	justify-content: space-between;
	gap: 0.5rem var(--gap-sm);
	margin-top: var(--gap-lg);
	padding-top: var(--gap-sm);
	border-top: 1px solid var(--border-light);
}

.site-footer__wat,
.site-footer__credit {
	margin: 0;
	font-size: var(--text-body-sm);
	color: var(--text-on-dark-faint);
}

/* =======================================================================
 * Het woordmerk in de vloer
 *
 * Massief en niet als omtrek, links op de containergoot, en het loopt rechts van
 * de pagina af. Dat laatste is hetzelfde mechanisme als de 59 in de hero: de naam
 * is groter dan het venster en je ziet er een uitsnede van.
 *
 * Waarom een lage dekking en niet vol wit: vol wit was variant B en die was "te
 * aanwezig". Op 0.14 leest hij als een naam die in de vloer is gegoten. Dat is de
 * zet van het foot-watermerk bij Netwerk de Kempen, waar hij op 0.07 staat, hier
 * een tik sterker omdat de grond hier bijna zwart is en daar groen.
 *
 * De negatieve ondermarge duwt de romp van de letters tegen de onderrand van het
 * document aan, zodat de naam op de rand staat in plaats van erboven te zweven.
 * .site-footer heeft overflow: hidden en snijdt hem daar af.
 * ======================================================================= */

.site-footer__merk {
	margin-top: var(--gap-lg);
	user-select: none;
	pointer-events: none;
}

.site-footer__merk span {
	display: block;
	font-family: var(--font-serif);
	font-weight: var(--weight-bold);
	/*
	 * DE MAAT VOLGT DE CONTAINER EN NIET HET VENSTER, en dat is gemeten.
	 *
	 * Op een kale 17.4vw liep de naam op 1920 en 2560 rechts van de pagina af (57
	 * en 282 pixels), stopte hij op 1024 juist 129 pixels voor de rand, en raakte
	 * hij op 390 bijna precies de zijkant. Drie verschillende uitkomsten, want de
	 * maat groeide met het venster terwijl de kolommen erboven op 1280 blijven
	 * staan. Zo leest het als een ongeluk in plaats van als een keuze.
	 *
	 * De deler 4.91 is de gemeten verhouding tussen de inktbreedte van FABRIEK59
	 * en de lettergrootte in deze letter bij deze tracking: 1640 bij 334.08,
	 * 1291 bij 263.09 en 875 bij 178.18. Verander je de letter of de
	 * letter-spacing, dan klopt hij niet meer en moet je hem opnieuw meten.
	 */
	font-size: calc( ( min( var(--container), 100vw ) - var(--container-px) * 2 ) / 4.91 );
	line-height: 0.78;
	letter-spacing: -0.055em;
	white-space: nowrap;
	color: color-mix(in srgb, var(--color-white) 14%, transparent);
	margin-bottom: -0.14em;
	/* De linkerzijkant van een F staat optisch iets in; dit trekt hem op de goot. */
	margin-left: -0.02em;
}

/*
 * Onder 900px zweven de menuknop en de bezoek-pil over de onderkant van het
 * scherm. Op maximale scrollpositie liggen ze daarmee op de laatste footerlink,
 * en dan is er geen scrollruimte meer om eronderuit te komen: de link is niet
 * meer aan te tikken. Deze bodemruimte houdt die strook vrij.
 *
 * De ruimte staat ONDER het woordmerk en niet op .site-footer, want anders zou de
 * naam ver boven de onderrand komen te hangen en is de hele zet weg.
 *
 * Het breekpunt is 900px omdat beide knoppen daarboven op display: none staan.
 */
/* Tot 1119 en niet tot 899: de zwevende bezoek-pil blijft nu even lang staan
   als de header-CTA weg is, en ook die pil legt zich anders over de laatste
   footerlinks heen. De menuknop rechtsonder verdwijnt wel al op 900. */
@media (max-width: 1119px) {

	.site-footer__merk {
		padding-bottom: var(--zwevend-vrij);
	}
}

@media (max-width: 699px) {

	/*
	 * Fraunces is een variabele letter met optical sizing: op 65px zijn de letters
	 * relatief breder dan op 250px. Met de deler van hierboven liep de naam op een
	 * telefoon 26px buiten de container. Gemeten verhouding op deze maat: 5.3.
	 */
	.site-footer__merk span {
		font-size: calc( ( 100vw - var(--container-px) * 2 ) / 5.3 );
	}
}

/* =======================================================================
 * Mobiele fijnafstemming van de hero
 *
 * Op een klein venster is de hero-hoogte krap: de aangeleverde intro is vijf
 * regels en die kan niet korter, want het is klantcopy. Daarom hier minder lucht
 * rond het tekstblok, en de sticky bezoek-pil houdt de primaire actie bereikbaar
 * ook als de knop in de hero net onder de vouw valt.
 * ======================================================================= */

@media (max-width: 767px) {

	.hero__content {
		padding-block: var(--gap-lg);
	}

	.hero__intro {
		margin-top: var(--gap-xs);
	}

	.hero__actions {
		margin-top: var(--gap-sm);
	}

	/* De scroll-aanwijzer kost hoogte die hier niet is. */}

/* =======================================================================
 * De bedrijfspagina
 *
 * Eigen paginatype sinds 20 augustus 2026, gegrond op de huurder-detailpagina van
 * Battersea Power Station. Zie `ux-onderzoek/steal-sheet-elementen.md` sectie 4.
 *
 * De vondst daar zit in de tracking: 0,214em op het kleine label, 0,300em op de
 * tagline en 0,333em op de H1. De letterafstand wordt dus RUIMER naarmate de kop
 * groter wordt, terwijl de gangbare regel het omgekeerde is. Dat is wat die
 * pagina's laat lezen als een inscriptie op een gebouw in plaats van als een
 * winkelvermelding, en het is precies de "instelling en geen verhuurbrochure" die
 * het concept vraagt.
 *
 * Wij zetten die ladder op het categorielabel en niet op de naam. Onze kop is
 * Fraunces, een serif: 0,33em breekt daar de schreefverbindingen en leest als een
 * fout. De naam houdt dus zijn eigen krappe tracking, en het label eronder draagt
 * het monumentale ritme.
 * ======================================================================= */

/*
 * De bovenpadding houdt rekening met de vaste header, en dat is geen smaak.
 *
 * De header is fixed en 112px hoog op desktop, 104 op mobiel. Met de gewone
 * sectie-padding van 6rem begon de kruimel op y 95 en lag hij dus onder die
 * header: `document.elementFromPoint` gaf op zijn midden de header terug en van de
 * 26px hoogte was er nog 7 raakbaar. De enige weg terug naar het overzicht was
 * daarmee grotendeels onklikbaar.
 *
 * Andere pagina's hebben dit niet omdat hun hero hoog genoeg is om zijn tekst
 * vanzelf onder de header te zetten. Deze kop is laag, dus hij moet het zelf doen.
 * Hertoetsen met elementFromPoint en niet met het oog.
 */
.bedrijf__kop {
	padding-block: 9rem var(--gap-lg);
}

/*
 * De foto op de grens van kop en tekst, sinds 18 september 2026.
 *
 * Sepp: "Ik heb liever dat die foto op de grens van de eerste en de tweede sectie
 * zo halverwege zit, dat die foto zo overlapt op die twee secties." Tot die dag
 * stond het kader rechts ONDER de kop, een storytelling-offset lager dan de tekst
 * ernaast, en dat is de verspringing van een band en niet van een detailpagina
 * (zie --gelijk in layout.css). Nu trekt de rechterkolom zichzelf omhoog tot de
 * onderrand van de kop door het midden van het kader loopt.
 *
 * De som: de kolom stond een sectie-padding plus een halve kaderhoogte te laag.
 * Het kader is 4/3 van de kolombreedte, dus de halve hoogte is 37,5 procent van
 * die breedte, en een procentmarge op een grid-item rekent precies daarmee: met
 * de breedte van zijn grid-area. Geen vaste pixel, dus het klopt op elke breedte
 * en volgt de vloeiende padding mee.
 *
 * De kop reserveert daarvoor zijn rechterhelft: zijn container krijgt dezelfde
 * twee kolommen als het grid eronder en zet kruimel, label, naam en tagline in
 * de linker. Zonder dat liep een lange naam onder de foto door, want de H1 was
 * de volle containerbreedte (1196px gemeten op 1729).
 *
 * De hele tweede kolom gaat mee omhoog en niet alleen het kader, want die kolom
 * is sticky en het kader hoort erin te blijven. Onder 768px staat de pagina in
 * één kolom met de tekst eerst, en daar blijft de foto onder de tekst.
 */
@media (min-width: 768px) {

	.bedrijf__kop .container {
		display: grid;
		grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
		column-gap: var(--gap-xl);
	}

	.bedrijf__kop .container > * {
		grid-column: 1;
	}

	.bedrijf__grid > *:nth-child(2) {
		margin-top: calc(-1 * (var(--section-lg) + 37.5%));
	}
}

.kruimel {
	margin-bottom: var(--gap-md);
}

.kruimel__terug {
	display: inline-flex;
	align-items: center;
	gap: var(--gap-xs);

	/* Het raakvlak was 22px hoog en dat is net onder de 24 die WCAG 2.2 op
	   AA-niveau vraagt (2.5.8). De padding tilt hem naar 26 zonder dat de regel
	   optisch verschuift, want de negatieve marge haalt hem er weer af. */
	padding-block: 0.125rem;
	margin-block: -0.125rem;
	min-height: 1.625rem;
	font-family: var(--font-sans);
	font-size: var(--text-button);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-widest);
	text-transform: uppercase;
	text-decoration: none;
	color: var(--text-on-dark-muted);
	transition: color var(--duration-base) var(--ease-out);
}

.kruimel__terug:focus-visible {
	color: var(--text-on-dark);
}

@media (hover: hover) {

	.kruimel__terug:hover {
		color: var(--text-on-dark);
	}
}

/* De pijl wijst terug, en schuift op hover die kant op. Dezelfde beweging als de
   kaartpijl, gespiegeld, zodat de richting het gedrag draagt. */
.kruimel__pijl {
	transform: scaleX(-1);
	transition: transform var(--duration-base) var(--ease-out);
}

.kruimel__terug:focus-visible .kruimel__pijl {
	transform: scaleX(-1) translateX(6px);
}

@media (hover: hover) {

	.kruimel__terug:hover .kruimel__pijl {
		transform: scaleX(-1) translateX(6px);
	}
}

/* De tracking-ladder van Battersea, op ons label. 0,18em is ruimer dan de 0,1em
   van --tracking-widest en blijft onder hun 0,33em, want die maat halen wij niet:
   hun label staat op 27px, dit op 14px, en op 14px wordt 0,33em een rij losse
   letters in plaats van een woord. */
.bedrijf__categorie {
	margin: 0 0 var(--gap-sm);
	letter-spacing: 0.18em;
}

.bedrijf__naam {
	margin: 0;
}

/*
 * De tweede stem onder de naam. Bij Battersea staat die op 27px tegen een kop van
 * 54, dus ongeveer de helft, in dezelfde familie. Hier is de kop een serif die met
 * clamp meeschaalt, dus de tagline schaalt mee op de helft en houdt dezelfde
 * familie. Gedempt, want hij ondersteunt de naam en concurreert er niet mee.
 */
.bedrijf__tagline {
	max-width: 34rem;
	margin: var(--gap-sm) 0 0;
	font-family: var(--font-serif);
	font-size: clamp(1.125rem, 2.5vw, 1.875rem);
	font-style: italic;
	font-weight: var(--weight-semibold);
	line-height: var(--leading-normal);
	color: var(--text-on-dark-muted);
}

.bedrijf__actie {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--gap-sm);
	margin-top: var(--gap-md);
}

/* Een link die de site verlaat zegt dat ook. Niet als waarschuwing maar als
   verwachting: de bezoeker weet dan waar hij uitkomt voor hij klikt. */
.bedrijf__actie-noot {
	font-size: var(--text-body-sm);
	color: var(--text-on-dark-muted);
}

.section-light .bedrijf__actie-noot { color: var(--text-on-light-muted); }

/*
 * De praktische gegevens. Alleen de rijen die er zijn: bij tien bedrijven staat
 * de website er altijd en de locatie altijd, maar e-mail bij één en telefoon bij
 * twee. Een lege rij met een streepje oogt als een fout in de gegevens, terwijl
 * er gewoon niets is aangeleverd.
 */
.gegevens {
	margin: var(--gap-md) 0 0;
	padding: 0;

	/*
	 * DEZE LIJST WISSELT OP ZIJN EIGEN BREEDTE EN NIET OP DIE VAN HET VENSTER.
	 *
	 * [ hij stond op @media (min-width: 480px), en dat is fout zodra de lijst in
	 *   de zijkolom staat in plaats van over de volle breedte. Gemeten op staging
	 *   op 8 september 2026, op /bedrijven/fijn-nl/: de zijkolom is 647px op een
	 *   venster van 700 en 323px op 768, want daar wisselt .storytelling-grid van
	 *   een naar twee kolommen. Het label houdt zijn vaste 11rem, dus de waarde
	 *   zakte van 439 naar 115px en het adres viel over vijf regels met
	 *   "Lovensekanaal / dijk" midden in het woord gebroken. Pas rond 1280 was de
	 *   waardekolom weer zo breed als op 600.
	 *
	 *   Met een container query staat de lijst gestapeld zolang zijn eigen kolom
	 *   smaller is dan 27rem, dus van 768 tot ongeveer 1000, en dan heeft de waarde
	 *   de volle 323 tot 430px in plaats van 115. Boven die grens houdt de waarde
	 *   224px of meer over.
	 *
	 *   27rem en niet de 23rem waar deze fix mee begon. Het langste adres,
	 *   "Lovensekanaaldijk 47-13, 5013 BJ Tilburg, Nederland", is per pixel
	 *   nagemeten: op 200px valt hij over drie regels, vanaf 210px over twee. Op
	 *   23rem kwam de waardekolom op de grens uit op 175px, dus dan brak er geen
	 *   woord meer maar viel het adres nog steeds een regel verder open dan
	 *   gestapeld. 27rem geeft 224px op de grens, veertien pixels boven die 210.
	 *
	 *   De grens is de container en niet het venster, want de zijkolom is niet
	 *   monotoon in de vensterbreedte: hij groeit tot 700, klapt terug op 768 en
	 *   groeit daarna opnieuw. Een breekpunt op het venster kan zoiets niet
	 *   volgen. De container-type staat op de dl en niet op .bedrijf__zijkant,
	 *   want container-type zet ook layout-containment aan en dat maakt van het
	 *   element een containing block voor alles wat er absoluut in staat; de dl
	 *   heeft zulke kinderen niet, de zijkolom wel.
	 *
	 *   Nameten: scratchpad/gegevens.mjs. ]
	 */
	container-type: inline-size;
}

.gegevens__rij {
	display: grid;
	gap: 0.25rem;
	padding-block: 1rem;
	border-top: 1px solid var(--border-light);
}

@container (min-width: 27rem) {
	.gegevens__rij {
		grid-template-columns: 11rem minmax(0, 1fr);
		gap: var(--gap-sm);
		align-items: baseline;
	}
}

.section-light .gegevens__rij { border-top-color: var(--border-dark); }

.gegevens__rij dt {
	color: var(--text-on-dark-muted);
}

.section-light .gegevens__rij dt { color: var(--text-on-light-muted); }

.gegevens__waarde {
	margin: 0;
}

/*
 * De zijkant van de bedrijfspagina.
 *
 * Sticky, zodat het bezoekblok in beeld blijft terwijl de beschrijving langs
 * scrollt. Dat is hier geen effect om het effect: de actie "plan je bezoek" is het
 * ene doel van de site, en die hoort bereikbaar te blijven op het moment dat de
 * bezoeker net gelezen heeft wat er te zien is.
 */
/*
 * De lege staat van het beeldslot, dezelfde als op de kaart. Het slot staat er
 * altijd zodat de layout niet verschuift zodra Greg een foto levert.
 */
.frame--leeg {
	display: grid;
	place-items: center;
	background-color: var(--color-black);
	background-image: var(--pattern-weave);
	background-blend-mode: overlay;
	box-shadow: none;
	border: 1px solid var(--border-light);
}

/*
 * De initiaal in het lege beeldkader, en dit is dezelfde correctie als bij de
 * bedrijfskaart, alleen een component later.
 *
 * Hij stond hier nog als GEVULDE letter op 22 procent dekking. Dat is precies de
 * vorm waar `.card__initial` in augustus vanaf is gestapt, met de reden erbij in
 * de commentaarkop daar: een gevulde letter op lage dekking leest als een lichte
 * letter, een omtrek leest als een merkteken dat op materiaal is aangebracht.
 * De kaart kreeg de omtrek, dit kader niet, en daardoor stonden er twee
 * verschillende lege staten voor hetzelfde probleem op dezelfde site.
 *
 * De maat gaat wel omhoog, en dat is gemeten en niet geschat. Het kader is 426px
 * hoog vanaf 1440 en 257px op 390. De letter vulde daar 64 en 38px van, 15 procent,
 * terwijl het haltenummer op Bezoekers 45px in 164px doet en de kaart op home 83px
 * in 320px, allebei 27 procent. Op 27 procent komt dit kader uit op 115px letter
 * boven 1440 en 69px op een telefoon, en dat is wat de clamp hieronder geeft.
 */
.frame__initial {
	font-size: clamp(5.5rem, 10vw, 9rem);
}

.bedrijf__zijkant {
	display: grid;
	gap: var(--gap-md);
	align-content: start;
}

/* De dl heeft een eigen bovenmarge voor als hij ergens onder een tekst staat.
   Hier is hij het eerste element van de kolom en moet hij op dezelfde regel
   beginnen als de tekst ernaast. */
.bedrijf__zijkant > .gegevens { margin-top: 0; }

@media (min-width: 900px) {
	/* De offset rekent met de hoogte van de vaste header, niet met een gap.
	   Rekende hij met --gap-xl, dan zou een vloeiende gap de marge onder de
	   balk laten meekrimpen tot een paar pixels op precies deze breedte. */
	.bedrijf__zijkant {
		position: sticky;
		top: calc(var(--header-hoogte) + var(--gap-sm));
	}
}

.bezoekblok {
	padding: var(--gap-md);
	background-color: var(--color-black);
	border: 1px solid var(--border-light);
}

.section-light .bezoekblok {
	background-color: var(--color-white);
	border-color: var(--border-dark);
}

.bezoekblok > * + * { margin-top: var(--gap-sm); }
.bezoekblok > :first-child { margin-top: 0; }

.bezoekblok__adres {
	font-family: var(--font-serif);
	font-size: var(--text-h3);
	line-height: var(--leading-normal);
	margin: 0;
}

/* =======================================================================
 * De evenementpagina en de artikelpagina
 *
 * Twee nieuwe detailpaginatypen, 9 september 2026. Zie de koppen van
 * single-evenement.php en single.php voor de gronding, en
 * ux-onderzoek/steal-sheet-detailpaginas-agenda-en-nieuws.md voor de metingen.
 *
 * Ze delen hun kop-zone met de bedrijfspagina en verschillen daaronder: het
 * evenement is tweekoloms met een gegevensblok, het artikel eenkoloms met een
 * brede kop. Dat onderscheid is het antwoord op de vraag "wat moet je hier kunnen
 * opzoeken zonder te lezen", en bij een bericht is dat antwoord: niets.
 * ======================================================================= */

/*
 * Dezelfde kop-padding als .bedrijf__kop, en om dezelfde reden die daar staat: deze
 * koppen zijn laag, dus ze moeten hun tekst zelf onder de vaste header duwen. Eén
 * regel voor de drie, want drie kopieën van hetzelfde getal lopen uit elkaar.
 */
.evenement__kop,
.artikel__kop {
	padding-block: 9rem var(--gap-lg);
}

/* Zelfde ladder als .bedrijf__categorie: het label boven de kop draagt de
   tracking van Battersea op onze labelmaat. */
.evenement__datum,
.artikel__datum {
	margin: 0 0 var(--gap-sm);
	letter-spacing: 0.18em;
}

.evenement__titel,
.artikel__titel {
	margin: 0;
}

/*
 * De melding dat een evenement geweest is.
 *
 * Geen kaart, geen icoon en geen gekleurd vlak: een regel op een rode streep, in
 * dezelfde vorm als de streep boven een label. Dit is geen waarschuwing over iets
 * wat fout ging maar een feit over de datum, en het hoort dus bij de kop-zone en
 * niet als banner over de pagina.
 *
 * Rood draagt de streep en niet de letters. Op --color-black haalt #b22222 2,9:1 en
 * dat zakt door de 3:1 die WCAG voor grote tekst vraagt; als decoratie zonder
 * informatiewaarde mag het wel. Zelfde regel als bij .card .label--red.
 */
.evenement__geweest {
	max-width: 34rem;
	margin: var(--gap-sm) 0 0;
	padding-top: var(--gap-sm);
	border-top: 2px solid var(--color-red);
	font-size: var(--text-body-lg);
	line-height: var(--leading-loose);
	color: var(--text-on-dark-muted);
}

.section-light .evenement__geweest { color: var(--text-on-light-muted); }

/* Zelfde vorm als .bedrijf__actie: de knop en de noot ernaast op één regel, en
   ze breken samen om op een smal scherm. */
.evenement__actie {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--gap-sm);
	margin-top: var(--gap-md);
}

/*
 * HET BEELD VAN EEN EVENEMENT STAAT IN DE HOOFDKOLOM EN NIET IN DE ZIJKOLOM.
 *
 * Op 9 september 2026 verplaatst, en het is een correctie op de eigen steal sheet
 * en niet een nieuwe keuze. Die schrijft de leesvolgorde voor als "eyebrow, kop,
 * beeld, tekst links, gegevensblok rechts", en Battersea meet daar als
 * `.eventLeaderVisual` met `img { margin: 0 auto }`, dus in de kolom. De bouw zette
 * het beeld in de zijkolom omdat dat blok van single-bedrijf.php was overgenomen.
 *
 * Wat dat kostte, gemeten op /agenda/open-dag-op-het-terrein/ op 1440px: de
 * linkerkolom droeg twee zinnen en de rechterkolom het beeld, het gegevensblok en
 * het bezoekblok, dat laatste ook nog twaalf rem lager door --storytelling-offset.
 * Ruim zevenhonderd pixels lege linkerkolom, en dat is letterlijk het anti-patroon
 * "dode kolom" uit de skill.
 *
 * De reden die op de bedrijfspagina wél geldt, geldt hier niet. Daar staat het slot
 * altijd omdat negen van de negen bedrijven nog geen foto hebben en de layout niet
 * mag verspringen zodra er één komt. Dat argument gaat over de PLEK van het slot en
 * niet over welke kolom hem draagt: in de hoofdkolom staat hij er net zo goed
 * altijd, met dezelfde frame--leeg eronder, en verspringt er dus net zomin iets.
 */
.evenement__beeld {
	margin-bottom: var(--gap-md);
}

/*
 * DE ARTIKELPAGINA HEEFT TWEE BREEDTES: 1280 voor kop en beeld, 640 voor de tekst.
 *
 * HIER STOND een ladder van drie treden, "kop 1280, beeld 768, tekst 640", met als
 * onderbouwing "bij Strijp-S is de gemeten ladder 1137, 707, 554". Die middelste
 * maat bestaat daar niet. Hun artikelbeeld meet 1137 bij 736 op x=384, precies de
 * containerbreedte en precies de linkerrand van hun H1; de 707 bij 460 kwam uit een
 * verborgen hoverbeeld van hun menu. Nagemeten op 9 september 2026 in de verse-
 * ogen-ronde. De volledige afweging staat in de kop van single.php.
 *
 * Beide maten zijn .container en .container-text uit base.css, dus hier staat
 * alleen wat ze bij elkaar houdt. De containers staan onder elkaar in dezelfde
 * sectie, dus de sectie zelf draagt geen container en de afstand tussen beeld en
 * tekst staat hier.
 */
.artikel__figuur {
	margin: 0 0 var(--gap-lg);
}

/*
 * 3:2 en niet de 4:3 van .frame. Gemeten bij Strijp-S: 1137 bij 736 is 1,54. Het is
 * ook de verhouding die .card__media al draagt, dus het beeld boven een artikel en
 * het beeld op de kaart die ernaartoe linkt hebben dezelfde vorm.
 */
.artikel__beeld {
	aspect-ratio: 3 / 2;
}

/*
 * Het bijschrift onder het beeld, met de herkomst erin. Overgenomen van Zollverein,
 * die onder elk beeld "Bild: © ..." zet. Lichter dan de body en kleiner: het is een
 * voetnoot bij het beeld en geen tweede alinea.
 */
/* De afsluiter staat een sectie-adem onder de tekst en niet een alinea-adem: hij
   hoort bij de pagina en niet bij het laatste stukje lopende tekst. */
.artikel__afsluiter {
	margin-top: var(--gap-lg);
}

.artikel__bijschrift {
	margin: var(--gap-xs) 0 0;
	font-size: var(--text-body-sm);
	line-height: var(--leading-loose);
	color: var(--text-on-dark-muted);
}

.section-light .artikel__bijschrift { color: var(--text-on-light-muted); }

/*
 * DE ARTIKELBODY OP 18PX, EN DAT IS DE ENIGE ECHTE CORRECTIE UIT DE MEETRONDE.
 *
 * .prose erft --text-body, en dat is 16px. Strijp-S staat op 17,8px met een
 * line-height van 1,5. Voor een artikel van zes alinea's is 16px te klein: dit is de
 * enige plek op de site waar iemand langer dan een halve minuut achter elkaar leest.
 *
 * --text-body-lg is 18px en bestaat al, als de maat van de intro-alinea. Hij komt
 * hier dus niet bij, hij wordt gebruikt waar hij voor is. --leading-loose (1,7) is
 * ruimer dan hun 1,5, en dat is met opzet: onze regel is 640px waar die van hen 554
 * is, en een langere regel vraagt meer lucht om de terugsprong te vinden.
 */
.artikel__tekst {
	max-width: none;
	font-size: var(--text-body-lg);
}

.artikel__tekst p {
	line-height: var(--leading-loose);
}

/*
 * De tussenkoppen die de klant zelf in de editor zet. Ze staan er nu nog niet, want
 * de acht berichten zijn kale alinea's, maar zodra Greg er een aanmaakt hoort hij
 * op de serif te staan en niet op de standaard van de browser.
 */
.artikel__tekst h2,
.artikel__tekst h3 {
	font-family: var(--font-serif);
	font-weight: var(--weight-semibold);
	line-height: var(--leading-snug);
	margin-top: var(--gap-lg);
}

.artikel__tekst h2 { font-size: var(--text-h3); }
.artikel__tekst h3 { font-size: var(--text-body-lg); }

/* =======================================================================
 * Het ruimte-overzicht
 *
 * Een echte tabel, want dit is tabeldata: drie kolommen met een kop, en een
 * schermlezer moet "45-4, oppervlakte 850, status beschikbaar" kunnen voorlezen.
 * Geen div-raster dat eruitziet als een tabel.
 *
 * Hij past op 390px zonder horizontale scroll, en dat is een eis: de bezoeker die
 * dit leest staat vaak op zijn telefoon naast het pand. Drie smalle kolommen
 * passen daar precies in, dus er is geen omklap-truc nodig. (Van 11 tot 17
 * september 2026 stond er een vierde kolom voor, een volgnummer 01, 02, 03 als
 * stencilcijfer. Dat was een misverstand over wat Greg met "de nummering"
 * bedoelde, namelijk de unitnummers zelf; hij is er in de call van 17 september
 * af gegaan, zie section-ruimtes.php.)
 *
 * De rijen liggen op hairlines, zoals de faciliteiten en de tijdlijn. Dat is de
 * sorteertafel: alles ligt uitgespreid op een oppervlak en heeft een label.
 * ======================================================================= */

.ruimtes {
	width: 100%;
	border-collapse: collapse;
	margin-top: var(--gap-md);
	font-variant-numeric: tabular-nums;
}

/*
 * De twee datakolommen zijn zo smal als hun inhoud, de status duwt naar de
 * rechterrand. Zonder deze breedtes verdeelt de browser de tabel in gelijke delen
 * en staat op 1440 de oppervlakte een halve schermbreedte van zijn unit af.
 */
.ruimtes__unit { width: 1%; }
.ruimtes__oppervlak { width: 1%; padding-right: var(--gap-md); }

.ruimtes th,
.ruimtes td {
	padding-block: 1rem;
	text-align: left;
	vertical-align: baseline;
	border-bottom: 1px solid var(--border-light);
}

.section-light .ruimtes th,
.section-light .ruimtes td { border-bottom-color: var(--border-dark); }

.ruimtes thead th {
	font-family: var(--font-sans);
	font-size: var(--text-button);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-widest);
	text-transform: uppercase;
	color: var(--text-on-dark-muted);
	padding-bottom: 0.75rem;
}

.section-light .ruimtes thead th { color: var(--text-on-light-muted); }

.ruimtes__unit {
	font-family: var(--font-serif);
	font-size: var(--text-h3);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-tighter);
	white-space: nowrap;
}

.ruimtes__oppervlak {
	color: var(--text-on-dark-muted);
	white-space: nowrap;
}

.section-light .ruimtes__oppervlak { color: var(--text-on-light-muted); }

/* De selector moet specifieker zijn dan `.ruimtes th, .ruimtes td`, anders wint
   die zijn text-align: left en blijft de badge midden in de tabel hangen. */
.ruimtes td.ruimtes__status,
.ruimtes thead th:last-child { text-align: right; }

/* =======================================================================
 * De ruimtetabel op een smal scherm
 *
 * Drie kolommen naast elkaar passen daar niet, en niet vanwege de data maar
 * vanwege de koppen en de badge. Gemeten op staging, 8 september 2026, op een
 * venster van 320: de kop "Oppervlakte" is 127px breed (12px, uppercase, met
 * --tracking-widest), de kop "Ruimte" 68px, en de breedste statusbadge 128px.
 * Alleen dat is al 347px, terwijl er binnen de container 272px is. De tabel
 * stak daardoor op ELKE mobiele breedte buiten zijn container, en op 320 en
 * 360 trok hij de hele pagina 50 respectievelijk 10px scheef.
 *
 * Kleiner zetten haalt het niet: zonder letterafstand en op 10px komt het
 * totaal op 274px en dat past nog steeds niet, met koppen die dan onleesbaar
 * klein zijn.
 *
 * Dus stapelt de rij hier naar twee regels, met de status rechts naast het
 * ruimtenummer omdat dat de twee zijn waarop iemand scant:
 *
 *     43                [In gebruik]
 *     ± 120 m²
 *
 * De koppen gaan visueel weg en blijven staan voor een schermlezer. Dat mag
 * hier omdat elke waarde zichzelf uitlegt: een getal, een oppervlakte met m²
 * erachter, en een status in woorden. De rollen op de tabel in
 * section-ruimtes.php houden de kolomkoppeling in stand.
 *
 * 479 en niet 599: op 414px past de tabelvorm weer (369px beschikbaar tegen
 * 347 nodig), en 479/480 is een grens die dit stylesheet al kent.
 * ======================================================================= */

@media (max-width: 479px) {

	.ruimtes thead {
		position: absolute;
		width: 1px;
		height: 1px;
		margin: -1px;
		padding: 0;
		overflow: hidden;
		clip-path: inset(50%);
		border: 0;
		white-space: nowrap;
	}

	.ruimtes tbody tr {
		display: grid;
		grid-template-columns: minmax(0, 1fr) auto;
		align-items: baseline;
		column-gap: var(--gap-sm);
		padding-block: 1rem;
		border-bottom: 1px solid var(--border-light);
	}

	.section-light .ruimtes tbody tr { border-bottom-color: var(--border-dark); }

	/* De cellen dragen hun rand niet meer zelf, de rij doet dat nu. */
	.ruimtes tbody th,
	.ruimtes tbody td {
		padding-block: 0;
		border-bottom: 0;
	}

	.ruimtes tbody .ruimtes__unit {
		grid-column: 1;
		grid-row: 1;
	}

	.ruimtes tbody .ruimtes__status {
		grid-column: 2;
		grid-row: 1;
	}

	.ruimtes td.ruimtes__oppervlak {
		grid-column: 1;
		grid-row: 2;
		/* De ademruimte naar de statuskolom is hier niet nodig, want die staat
		   een regel hoger. Terug naar de gewone celpadding. */
		padding-right: 0.75rem;
		margin-top: 0.25rem;
	}

	/*
	 * Het accent van een vrije of aanvraag-rij zat op de cellen, met
	 * :first-child en :last-child voor de zijkanten. In de gestapelde vorm
	 * staan die twee kinderen naast elkaar op de eerste regel en de derde
	 * eronder, dus dat kader zou dwars door de rij lopen. Het accent verhuist
	 * daarom naar de rij zelf, waar het in deze vorm ook hoort. De cellen
	 * houden hun 0.75rem, zodat de rand net als op desktop OM de tekst ligt
	 * en niet ertegenaan.
	 */
	.ruimtes tbody tr.ruimtes__rij--vrij > *,
	.ruimtes tbody tr.ruimtes__rij--aanvraag > * {
		border: 0;
		background-color: transparent;
	}

	.ruimtes tbody tr.ruimtes__rij--vrij {
		border: 2px solid var(--color-red);
		background-color: var(--wash-red);
	}

	.ruimtes tbody tr.ruimtes__rij--aanvraag {
		border: 1px solid var(--border-light);
		background-color: color-mix(in srgb, var(--color-white) 4%, transparent);
	}

	.section-light .ruimtes tbody tr.ruimtes__rij--aanvraag {
		border-color: var(--border-dark);
		background-color: color-mix(in srgb, var(--color-black) 4%, transparent);
	}
}

/*
 * Een vrije ruimte is het enige dat deze tabel commercieel doet, dus die springt
 * eruit met een gevulde badge. Bezet is bewust rustig: gedempte tekst zonder vlak.
 * Rood als vlak kan alleen mét cream erop, want #b22222 haalt op de donkere grond
 * 2,9:1 en zakt door de 3:1 voor UI-onderdelen. Cream op rood haalt 5,8:1.
 */
.status {
	display: inline-block;
	font-family: var(--font-sans);
	font-size: var(--text-button);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-widest);
	line-height: 1.2;
	text-transform: uppercase;
	white-space: nowrap;
}

.status--vrij {
	padding: 0.375rem 0.75rem;
	background-color: var(--color-red);
	color: var(--color-white);
}

.status--aanvraag {
	padding: 0.3125rem 0.6875rem;
	border: 1px solid var(--border-light);
	color: var(--text-on-dark-muted);
}

.section-light .status--aanvraag {
	border-color: var(--border-dark);
	color: var(--text-on-light-muted);
}

.status--bezet { color: var(--text-on-dark-faint); }

.section-light .status--bezet { color: var(--text-on-light-muted); }

/* =======================================================================
 * WAT VRIJ IS EN WAT OP AANVRAAG IS, MOET JE ZIEN ZONDER TE LEZEN
 *
 * Punt 5 van 28 augustus 2026. Sepp: "de ruimtes op het terrein die beschikbaar
 * zijn nog iets duidelijker maken met een border eromheen bijvoorbeeld. Of wat op
 * aanvraag is, want nu blendt het allemaal een beetje weg."
 *
 * Dat klopte en het is te tellen: zeventien rijen, waarvan er veertien bezet zijn
 * en een vrij, in een sectie van 1724px. De vrije rij had wel een rood streepje op
 * de eerste cel, maar dat is drie pixels in een tabel die je van boven naar beneden
 * moet aflezen om hem te vinden.
 *
 * De rand gaat nu om de HELE rij. In een tabel met border-collapse kan dat niet op
 * de <tr>, want die verliest van de randen van de cellen; het moet dus per cel,
 * met links en rechts alleen op de buitenste twee. De vulling is bewust licht
 * (`--wash-red`, 0.10): zwaarder en de rij wordt een knop, lichter en je bent
 * terug bij het streepje.
 *
 * "Op aanvraag" krijgt dezelfde vorm in een neutrale toon. Dat is het verschil
 * tussen "dit kan" en "dit kan misschien", en allebei zijn ze meer waard dan de
 * veertien die niets kunnen.
 * ======================================================================= */

/*
 * ER STAAT EEN `.ruimtes tr` VOOR ELKE SELECTOR HIERONDER, EN DAT IS GEEN OPSMUK.
 *
 * Greg zag op 1 september dat de rode rand om de vrije rij zijn ONDERKANT miste:
 * boven, links en rechts stonden er wel. Dat is een specificiteitsconflict en geen
 * tekenfout, want drie regels vechten om dezelfde `border-bottom`:
 *
 *   `.ruimtes th, .ruimtes td`                       (0,1,1)  1px --border-light
 *   `.section-light .ruimtes th, .section-light td`  (0,2,1)  kleur --border-dark
 *   `.ruimtes__rij--vrij > *`                        (0,1,0)  2px rood
 *
 * De rijregel had de laagste van de drie, dus hij verloor ongeacht bronvolgorde.
 * Boven, links en rechts hadden geen concurrent en bleven daarom wel staan, en op
 * de donkere grond is 5 procent wit vrijwel onzichtbaar. Vandaar het kader met een
 * open onderkant. `border-collapse: collapse` maakt het scherper, want dan is er
 * per lijn maar een winnaar.
 *
 * Met `.ruimtes tr` ervoor telt `.ruimtes` als tweede klasse en `tr` als element,
 * dus (0,2,1). Gelijk aan de zwaarste concurrent, en bij gelijkspel wint de laatste
 * regel in het bestand. Dat is deze. Geen !important nodig.
 *
 * DE AANVRAAG-RIJ HAD EXACT DEZELFDE FOUT en die was alleen niet te zien omdat hij
 * met dezelfde kleur verloor als hij zelf zette. Op `section-light` was dat niet zo
 * geweest: daar wint --border-dark van de --border-light die de rij vraagt. De
 * tabel staat vandaag alleen op section-dark, dus het is nu onzichtbaar. Een fout
 * die je ziet en laat liggen komt terug op de dag dat iemand de grond omzet.
 */

.ruimtes tr.ruimtes__rij--vrij > * {
	border-top: 2px solid var(--color-red);
	border-bottom: 2px solid var(--color-red);
	background-color: var(--wash-red);
}

.ruimtes tr.ruimtes__rij--vrij > *:first-child { border-left: 2px solid var(--color-red); }
.ruimtes tr.ruimtes__rij--vrij > *:last-child { border-right: 2px solid var(--color-red); }

.ruimtes tr.ruimtes__rij--aanvraag > * {
	border-top: 1px solid var(--border-light);
	border-bottom: 1px solid var(--border-light);
	background-color: color-mix(in srgb, var(--color-white) 4%, transparent);
}

.ruimtes tr.ruimtes__rij--aanvraag > *:first-child { border-left: 1px solid var(--border-light); }
.ruimtes tr.ruimtes__rij--aanvraag > *:last-child { border-right: 1px solid var(--border-light); }

.section-light .ruimtes tr.ruimtes__rij--aanvraag > * {
	border-top-color: var(--border-dark);
	border-bottom-color: var(--border-dark);
	background-color: color-mix(in srgb, var(--color-black) 4%, transparent);
}

.section-light .ruimtes tr.ruimtes__rij--aanvraag > *:first-child { border-left-color: var(--border-dark); }
.section-light .ruimtes tr.ruimtes__rij--aanvraag > *:last-child { border-right-color: var(--border-dark); }

/*
 * DE LUCHT BINNEN DE RAND ZIT OP DE HELE TABEL EN NIET OP DE OMRANDE RIJ.
 *
 * Eerst stond hier `padding-inline: 0.75rem` op de cellen van een omrande rij. Dat
 * gaf lucht binnen de rand, maar het verschoof ook de tekst: 45-4 begon 11px verder
 * naar rechts dan 45-3, en de badge 11px naar links. In een tabel die je verticaal
 * scant is dat precies de misalignment die je wel ziet en niet kunt plaatsen.
 *
 * Nu krijgt elke cel diezelfde lucht en trekt de tabel zichzelf er met een negatieve
 * marge weer overheen. Alle rijen lijnen dus uit met de kop erboven, en de omrande
 * rijen steken 12px buiten de tekstkolom uit. Dat laatste is geen bijwerking maar
 * het gewenste effect: de rand ligt om de rij heen en niet erin.
 */
.ruimtes {
	margin-inline: -0.75rem;
	width: calc( 100% + 1.5rem );
}

.ruimtes th,
.ruimtes td {
	padding-inline: 0.75rem;
}

/* De ademruimte tussen oppervlakte en status blijft, en moet de regel hierboven
   verslaan: gelijke specificiteit betekent dat de laatste wint, dus deze staat er
   met een extra klasse bij. */
.ruimtes td.ruimtes__oppervlak {
	padding-right: var(--gap-md);
}

/*
 * De teller boven de tabel. Hij hergebruikt de badges uit de tabel zelf, zodat hij
 * tegelijk een legenda is: je leert de drie vormen hier en herkent ze een rij later.
 */
.ruimtes__telling {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--gap-xs) 0.75rem;
	margin: var(--gap-sm) 0 0;
}

.ruimtes__noot {
	margin-top: var(--gap-sm);
	font-size: var(--text-body-sm);
	color: var(--text-on-dark-faint);
}

.section-light .ruimtes__noot { color: var(--text-on-light-muted); }

@media (max-width: 479px) {
	.ruimtes__unit { font-size: var(--text-body-lg); }
	.ruimtes th,
	.ruimtes td { padding-block: 0.875rem; }
}

/*
 * Tabel links, uitnodiging rechts. Op volle breedte stond de statuskolom bijna
 * negenhonderd pixels van zijn unit af; met een leesbare tabelbreedte staat een
 * rij weer als één regel bij elkaar, en de overgebleven ruimte draagt de vraag in
 * plaats van leeg te blijven.
 */
.ruimtes-grid {
	display: grid;
	gap: var(--gap-lg);
	align-items: start;
}

@media (min-width: 900px) {
	.ruimtes-grid {
		grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
		gap: var(--gap-xl);
	}

	/* Zelfde reden als bij .bedrijf__zijkant: de offset hangt aan de header. */
	.ruimtes-zij {
		position: sticky;
		top: calc(var(--header-hoogte) + var(--gap-sm));
	}
}

.ruimtes-zij > * + * { margin-top: var(--gap-sm); }
.ruimtes-zij > :first-child { margin-top: 0; }


/* =======================================================================
 * Het stencilcijfer
 *
 * Een cijfer of letter in omtrek, zoals een sjabloon op een baal of een kist.
 * Draagt geen informatie, dus altijd aria-hidden en pointer-events uit; wie
 * hem als volgnummer gebruikt, zet het nummer ook in de tekst.
 *
 * -webkit-text-stroke heeft geen standaard-tegenhanger, maar de terugval is
 * onschadelijk: zonder ondersteuning krijg je transparante tekst en dus niets,
 * en er ging geen informatie verloren.
 * ======================================================================= */

.stencil {
	font-family: var(--font-serif);
	font-weight: var(--weight-bold);
	letter-spacing: -0.06em;
	line-height: 0.8;
	color: transparent;
	-webkit-text-stroke: 1px color-mix(in srgb, var(--color-white) 20%, transparent);
	user-select: none;
	pointer-events: none;
}

.section-light .stencil,
.section-brick-light .stencil {
	-webkit-text-stroke-color: color-mix(in srgb, var(--color-black) 18%, transparent);
}

.stencil--groot {
	-webkit-text-stroke-width: 2px;
}

/*
 * Alleen de 59 in de hero, sinds 7 september 2026. Videopac kent alleen cijfers,
 * dus deze modifier hangt bewust niet aan .stencil zelf: die klasse staat op acht
 * andere plekken en zet er drie keer een letter mee (de bedrijfsinitiaal op
 * single-bedrijf.php en card-bedrijf.php). Die vallen door de unicode-range
 * vanzelf terug op de serif, maar dan zou de tracking hieronder wel op ze slaan.
 *
 * Staat hier onder .stencil--groot en niet erboven, zodat .section-light .stencil
 * met zijn hogere specificiteit over de omtrekkleur heen blijft gaan.
 *
 * font-weight: 400 is geen opmaak maar een reparatie. .stencil vraagt om
 * var(--weight-bold) en Videopac heeft één gewicht, dus zonder deze regel verzint
 * de browser een vet en verdikt hij de glyph voordat de omtrek eroverheen gaat.
 *
 * De twee waarden zijn nagemeten op de glyph-randen van beide fonts en niet op
 * het oog, want ze waren allebei op Fraunces afgeregeld:
 *
 *   letter-spacing  Fraunces houdt bij opsz 144 een inktkloof tussen de 5 en de 9
 *                   van 0,058em op een kaphoogte van 0,7305em, dus 0,079 kap. Na
 *                   de -0,06em die er stond blijft daar 0,0125em van over.
 *                   Videopac begint op 0,0732em kloof bij 0,6836em kap, dus die
 *                   heeft aan -0,019em genoeg voor dezelfde verhouding. De oude
 *                   -0,06em zou de 5 en de 9 bijna tegen elkaar aan zetten.
 *   line-height     0,8 op Fraunces geeft een blok van 1,095 keer de kaphoogte.
 *                   Bij de grotere font-size hieronder komt Videopac op dezelfde
 *                   verhouding uit met 0,75.
 */
.stencil--display {
	font-family: var(--font-stencil);
	font-weight: 400;
	letter-spacing: -0.019em;
	line-height: 0.75;
}

/* =======================================================================
 * Het museumbordje stond hier tot 13 oktober 2026: .beeldbijschrift, een
 * donker bordje met een rode linkerrand voor een bijschrift op een archieffoto,
 * met de varianten in de hero, de tijdlijn, de route en de luchtfoto. Julia vroeg
 * op 8 oktober om alles weg te laten, en Greg besliste op 13 oktober: alle
 * tekstvakken over de foto's weg ("Ja, die mogen er allemaal weg"). Zie
 * template-parts/hero/hero-page.php.
 * ======================================================================= */


/* =======================================================================
 * Het citaatblok
 *
 * Het citaat is de these van dit merk in de woorden van de familie zelf, en
 * stond weggedrukt in een halve kolom naast een foto. Nu draagt het de sectie:
 * gecentreerd, groot, en met de tekst als enige op die regel.
 *
 * De schaduw is een inkeping in plaats van een slagschaduw: een lichte rand
 * boven en donker eronder, zodat de letters in de steen gehakt lijken. Dat werkt
 * alleen op de bakstenen grond, en daarom hangt het aan die klasse.
 * ======================================================================= */

.quote-blok {
	max-width: 60rem;
	margin-inline: auto;
	margin-bottom: var(--gap-xl);
	text-align: center;
}

.quote-blok__teken {
	display: block;
	font-family: var(--font-serif);
	font-size: clamp(6rem, 14vw, 12rem);
	line-height: 0.6;
	color: var(--color-red);
	opacity: 0.55;
	margin-bottom: var(--gap-sm);
}

.quote--groot {
	font-size: clamp(2rem, 5.2vw, 4rem);
	line-height: var(--leading-tight);
	font-weight: var(--weight-regular);
	text-wrap: balance;
}

.section-brick-warm .quote--groot {
	text-shadow:
		0 1px 0 rgba(255, 235, 205, 0.16),
		0 -1px 0 rgba(0, 0, 0, 0.55);
}

/*
 * Beeld op de warme bakstenen grond krijgt dezelfde temperatuur als de muur.
 *
 * De gesorteerde stapel is van zichzelf geelgroen en verzadigd, en dat vloekte
 * tegen het warme bruin: de foto sprong eruit als een los plaatje in plaats van
 * als onderdeel van de sectie. Licht sepia trekt hem naar dezelfde kant zonder
 * dat het beeld zijn eigen kleur verliest.
 */
.section-brick-warm .frame img {
	filter: sepia(0.35) saturate(0.8) contrast(1.05) brightness(0.95);
}

/* =======================================================================
 * De aanwijzing en het bijschrift in de hero
 *
 * Allebei absoluut onderin, want ze horen bij het beeld en niet bij de leesregel.
 * Ze staan buiten .hero__content zodat ze de hoogte van de tekstkolom niet
 * beïnvloeden: die kolom moet in één scherm passen en dat is een harde eis.
 * ======================================================================= */

/*
 * Aanwijzing en bijschrift staan samen rechtsonder, in één kolom.
 *
 * De aanwijzing stond eerst linksonder en botste daar op de primaire knop, die
 * onderaan dezelfde tekstkolom eindigt. Rechts is de enige hoek die vrij is: de
 * tekstkolom loopt tot ongeveer de helft en het beeld draagt de rest.
 *
 * Buiten .hero__content, zodat ze de hoogte van de tekstkolom niet beïnvloeden.
 * Die kolom moet in één scherm passen en dat is een harde eis.
 */
/*
 * De homepage-hero volgt het goedgekeurde prototype tot op de waarde.
 *
 * Drie dingen weken af en dat was met het blote oog te zien zodra je de twee
 * naast elkaar zette, wat de reden is dat het zo hoort:
 *
 * 1. align-items stond op flex-end in plaats van center. Daardoor zakte het hele
 *    tekstblok naar de onderrand en was er onderin geen ruimte meer voor de
 *    aanwijzing. Ik had die toen naar rechts verplaatst omdat ik dacht dat hij op
 *    de knop botste; de botsing kwam door de uitlijning, niet door de plek.
 * 2. De tekstkolom was 40rem en niet 46rem, waardoor de titel over drie regels
 *    brak in plaats van twee.
 * 3. De type-schaal woog de hoogte anders, waardoor de kop groter werd terwijl de
 *    kolom smaller was. Dat is de verkeerde kant op.
 */
.hero--home {
	align-items: center;
	padding-bottom: 4rem;
}

.hero--home .hero__content {
	padding-block: 0;
}

.hero--home .hero__tagline {
	max-width: 46rem;
	font-size: clamp(2.5rem, min(7.5vw, 10.5svh), 7.5rem);
	text-shadow: 0 2px 2.5rem color-mix(in srgb, var(--color-deep) 85%, transparent);
}

/*
 * De kolombreedte verschilt per element, en dat is niet toevallig: de titel
 * krijgt de volle 46rem zodat hij over twee regels valt, de alinea blijft op
 * 38rem omdat een leesregel breder dan dat oncomfortabel wordt.
 */
.hero--home .hero__intro {
	max-width: 38rem;
	line-height: var(--leading-loosest);
	text-shadow: 0 1px 1.5rem color-mix(in srgb, var(--color-deep) 90%, transparent);
}

/*
 * STAAND OP EEN KORTE TELEFOON, DE DERDE HOOGTESTAP.
 *
 * De twee blokken bovenin dit bestand staan op `orientation: landscape`, met als
 * onderbouwing dat een staande telefoon de hoogte wel heeft. Dat klopt voor de
 * telefoons van nu en niet voor de kleinere: gemeten op 8 september 2026 op
 * staging stond de heroknop op 360x640 op 613 en dus 21px onder de vouw op home
 * en 26px op Bezoekers, en op /bedrijfsruimte-huren/ 66px. De zwevende bezoek-pil
 * staat daar linksonder op 571 tot 619 en lag met 6px over diezelfde knop, twee
 * rode pillen over elkaar. Precies de botsing die het liggend-blok beschrijft,
 * alleen dan staand.
 *
 * 700px is de grens omdat een telefoon van nu 844 tot 932 hoog is en hier dus
 * buiten valt. Wat eronder zit is 320x568 en 360x640, en daar is 104px kopbalk
 * plus een hero van 557px meer dan het venster draagt.
 *
 * Dit blok MOET hier staan en niet bij de twee andere: `.hero--home` en
 * `.hero--home .hero__content` staan hierboven als gewone regel, en een
 * media-query telt niet mee in de specificiteit. Bovenin het bestand verliest hij
 * dus, en dat is de val die in dit bestand al drie keer is gezet.
 *
 * De tekstmaat van de intro gaat er hier WEL af, net als in het liggend-blok en
 * om dezelfde reden: 16px is de bodymaat van de site en geen uitzonderingsmaat,
 * en --leading-loose blijft staan, want daar zit de leesbaarheid voor doelgroep 2
 * in.
 */
@media (max-height: 700px) and (orientation: portrait) {

	.hero--home {
		padding-bottom: var(--gap-md);
	}

	/*
	 * Dezelfde ondergrens-verlaging als bij .hero--page .section-title verderop, en
	 * om dezelfde reden: 2.5rem is er voor een smalle telefoon zodat de kop niet
	 * over te veel regels breekt, maar op 320x568 brak hij toch al over vier regels
	 * van 40px en was hij daarmee 160px van de 464px onder de balk. Op 32px zijn
	 * dat nog steeds vier regels en scheelt het 32px.
	 */
	.hero--home .hero__tagline {
		font-size: clamp(2rem, min(7.5vw, 10.5svh), 7.5rem);
	}

	/* Geen --zwevend-vrij hier: de pil is op deze stand naar de balk verhuisd, en
	   de menuknop die overblijft zweeft rechtsonder terwijl de heroknop links staat. */
	.hero--page .hero__content {
		padding-block: 1.5rem 2.5rem;
	}

	.hero__wordmark {
		line-height: var(--leading-none);
	}

	.hero--home .hero__intro,
	.hero--page .hero__intro {
		margin-top: var(--gap-xs);
		font-size: var(--text-body);
	}

	.hero--home .hero__actions,
	.hero--page .hero__actions {
		margin-top: var(--gap-md);
	}
}

/* Hier stond .hero__bijschrift, het bordje rechtsonder in de hero; vervallen op
   13 oktober 2026, zie het museumbordje hierboven. */

/* =======================================================================
 * De lijn die zichzelf tekent
 *
 * Twee paden over elkaar: een gestippeld spoor dat er altijd staat, en een rode
 * lijn die eroverheen wordt getrokken naarmate je scrolt.
 *
 * De rode lijn is decoratie en draagt geen informatie, en dat is precies waarom
 * rood hier mag: op donker haalt #b22222 maar 2,9:1, te weinig voor tekst en
 * voor een UI-onderdeel, maar genoeg voor een streep die niets zegt.
 *
 * Zonder JavaScript staat de lijn volledig getekend: stroke-dasharray wordt pas
 * door het script gezet. De faalrichting is dus "geen animatie" en nooit "geen
 * lijn".
 * ======================================================================= */

.route-lijn svg {
	display: block;
	width: 100%;
	height: auto;
	overflow: visible;
}

/*
 * Onder 768px staat de lijn ONDER de tekst in plaats van ernaast, en dan neemt hij
 * op volle breedte 223px in beslag voor iets dat niets zegt. Dat is geen smaak maar
 * een meetuitkomst: op de wandelroute-pagina kwam de sectie daardoor op 848px bij
 * een venster van 844. Vier pixels, en precies vier pixels te veel.
 *
 * Smaller in plaats van weg. Een lijn die zich ontrolt is het enige beweeglijke op
 * die pagina en het signaal dat er iets te lopen valt; hem op mobiel verbergen zou
 * dat weghalen op het apparaat waarop mensen naar een wandeling kijken. Op 18rem
 * wordt hij ongeveer 188px en houdt de sectie 35px over.
 *
 * Dit raakt ook Home en Historie, waar dezelfde sectie draait. Daar maakt het de
 * pagina alleen korter.
 */
@media (max-width: 767px) {

	.route-lijn {
		max-width: 18rem;
		margin-inline: auto;
	}
}

.route-lijn__spoor {
	fill: none;
	stroke: color-mix(in srgb, var(--color-white) 28%, transparent);
	stroke-width: 2;
	stroke-dasharray: 4 8;
	stroke-linecap: round;
}

.route-lijn__getekend {
	fill: none;
	stroke: var(--color-red);
	stroke-width: 3;
	stroke-linecap: round;
}

.route-lijn__halte {
	fill: var(--color-black);
	stroke: color-mix(in srgb, var(--color-white) 50%, transparent);
	stroke-width: 2;
}

.section-light .route-lijn__spoor {
	stroke: color-mix(in srgb, var(--color-black) 28%, transparent);
}

.section-light .route-lijn__halte {
	fill: var(--color-white);
	stroke: color-mix(in srgb, var(--color-black) 50%, transparent);
}


/* =======================================================================
 * De onderdelen uit het prototype die nog ontbraken
 *
 * Toegevoegd op 21 augustus 2026. Ik had ze bij het overzetten weggelaten omdat
 * ik ze als versiering las; het prototype was goedgekeurd zoals het was en dat
 * is de maat.
 * ======================================================================= */

/*
 * HIER STOND TOT 17 SEPTEMBER 2026 HET RASTERPUNTFILTER over de homepage-hero
 * (`.hero--home .hero__media::after`, een puntraster van 3px op multiply, 0,55),
 * als verwijzing naar de krantendruk. Het was de derde verdonkerende laag op die
 * foto, naast de scrim en de lamp, en Greg vroeg om de foto op normale kleur. Het
 * beantwoordt meteen de open vraag van 28 augustus of de binnenpagina's het ook
 * moesten krijgen: nergens. Terughalen is die ene regelset; de bron van de foto is
 * ontrasterd en blijft dat, want dat stond los van dit filter.
 */

/*
 * Het cijfer dat van de rechterrand afloopt. Boven de waas en onder de tekst,
 * zodat het over de foto ligt maar nooit met de leesregel vecht.
 *
 * De drie waarden hieronder zijn op 7 september 2026 herrekend voor Videopac,
 * met .stencil--display erbij op de twee hero-templates. Ze horen bij elkaar:
 * haal je die klasse weg, dan staat het cijfer te groot en te ver naar links.
 *
 *   font-size  Videopac heeft een kaphoogte van 0,6836em tegen 0,7305em bij
 *              Fraunces op opsz 144, dus 1,0686 keer groter houdt het cijfer
 *              exact even hoog als voor de wissel. De randvoorwaarde hieronder
 *              blijft daarmee gehaald: op 1920x1080 is de inkt 397px in een hero
 *              van een volle schermhoogte, en het blok zelf gaat van 435 naar
 *              436px.
 *   right      De 9 van Videopac heeft een rechter zijmarge van 0,0732em tegen
 *              0,0285em bij Fraunces, en daar komt de naijlende letter-spacing
 *              bovenop. Die telt namelijk ook na het laatste teken mee, dus de
 *              afstand van de inktrand tot de blokrand is zijmarge plus tracking:
 *              bij Fraunces -0,0315em en bij Videopac +0,0542em. Zonder correctie
 *              staat het cijfer 19px te ver naar binnen.
 *   bottom     Zelfde verhaal onderlangs, via de basislijn in het regelblok.
 *
 * Let op de valkuil in die tracking-term. De eerste berekening hier rekende alleen
 * met de zijmarge van de glyph en kwam op -0,047em en +0,042em uit; nagemeten in
 * de pagina stond de inkt daarmee 19px en 15px verkeerd. Reken dus nooit op de
 * glyph-randen alleen als er tracking op staat.
 *
 * Nagemeten in de pagina op 1440x765, met .stencil--display eraf en de vier oude
 * waarden erop als nulmeting: kaphoogte 357,6 tegen 357,8px, inktrand rechts 43,8
 * tegen 44,0px, inktrand onder 16,6 tegen 16,7px. Alle drie binnen 0,2px, dus het
 * cijfer staat waar het stond. De correcties zijn in em uitgedrukt en niet in px,
 * want ze hangen aan de letter en niet aan het venster.
 */
.hero__cijfer {
	position: absolute;
	right: calc(-2vw - 0.083em);
	bottom: calc(-4vh + 0.014em);
	z-index: var(--z-base);
	font-size: clamp(14.96rem, 36.33vw, 36.33rem);
	-webkit-text-stroke-color: color-mix(in srgb, var(--color-white) 40%, transparent);
}

/*
 * DE OMTREK VAN DE 59 STAAT SINDS 17 SEPTEMBER 2026 OP 40 PROCENT WIT, en niet op
 * de 20 procent van .stencil. Tot die dag lag er over de fotokant een sluier van
 * 26 tot 12 procent deep, met aan de voet nog een tweede van 34 procent, en op
 * die grond tekende een lijn van 20 procent wit prima af. Die sluier is er af (de
 * foto staat op eigen helderheid, zie de kolom-scrim hierboven) en op de lichte
 * balen van Huren was de 59 daarna vrijwel weg:
 * nagemeten in de verse-ogen-review van die dag, en zelf bevestigd met een
 * voor-en-na-uitsnede op 1440.
 *
 * Geprobeerd en afgewezen: een drop-shadow als halo (een tweede techniek voor
 * hetzelfde werk) en een verloop aan de voet van de foto (dat is de sluier
 * terugbrengen door de achterdeur). De omtrek zwaarder maken is de enige ingreep
 * die binnen het bestaande systeem blijft: dezelfde 2px van .stencil--groot,
 * alleen de dekking hoger. Op de 59 zelf, niet op .stencil, want het getal van de
 * faciliteitenstrook staat op een egale sectiegrond en heeft die 20 procent
 * precies goed.
 */

/*
 * HET CIJFER IS OP ELKE PAGINA EVEN GROOT, en dat is de tweede helft van hetzelfde
 * besluit als de hero-hoogte hierboven.
 *
 * Tot 28 augustus 2026 stond hier `clamp(9rem, 20vw, 20rem)` voor een binnenpagina,
 * en dat was toen een meetuitkomst: de hero was 60vh, op 1512x765 dus 459px hoog,
 * terwijl 34vw uitkomt op 514px. Het cijfer zou hoger zijn geweest dan het vlak
 * waar het in hangt, en dan is het geen detail dat van de rand afloopt maar een
 * vlak met een cijfer erin.
 *
 * Die reden is vervallen op het moment dat de binnenpagina-hero een volle
 * schermhoogte kreeg. Sepp zag het verschil zelf: "die is op die andere pagina's
 * om een of andere reden een heel stuk kleiner". Het cijfer erft nu gewoon de maat
 * hierboven, dus er staat hier geen regel meer.
 */

@media (max-width: 768px) {

	/* Op een telefoon vult het cijfer het halve scherm en vecht het met de tekst. */
	.hero__cijfer {
		display: none;
	}
}

/* Het volgnummer op een deur. Draagt geen informatie: de volgorde staat al in
   de leesrichting, dit is het sjabloon op de kist. */
.door__nummer {
	position: absolute;
	top: 1.75rem;
	right: 2rem;
	z-index: var(--z-base);
	font-size: 5rem;
}

/*
 * Het licht dat onder de deur door valt bij hover.
 *
 * Een eigen element en geen ::after, want ::after draagt op deze deuren het
 * luik. Twee dingen op één pseudo-element gaat stil mis.
 */
.door__streep {
	position: absolute;
	left: 0;
	right: 0;
    bottom: 0;
	z-index: var(--z-base);
	height: 3px;
	background-color: var(--color-red);
	transform: scaleX(0);
	transform-origin: left;
	transition: transform var(--duration-chrome) var(--ease-out);
	pointer-events: none;
}

.door:focus-visible .door__streep {
	transform: scaleX(1);
}

@media (hover: hover) {

	.door:hover .door__streep {
		transform: scaleX(1);
	}
}

/* De twee knoppen onder de afsluiter. */
.outro-acties {
	display: flex;
	flex-wrap: wrap;
	gap: var(--gap-sm);
	margin-top: var(--gap-lg);
}

/*
 * De omlijnde knop op een lichte grond. .btn--ghost is voor donker: die heeft
 * een lichte rand en wordt op crème onzichtbaar. Dat staat als must-fix op de
 * anti-default-lijst en is precies de fout die hier zou ontstaan.
 */
.btn--outline-dark {
	position: relative;
	isolation: isolate;
	overflow: hidden;
	border: 1px solid color-mix(in srgb, var(--color-black) 35%, transparent);
	color: var(--color-black);
	background-color: transparent;
	transition: color var(--duration-button) var(--ease-out);
}

.btn--outline-dark::before {
	content: '';
	position: absolute;
	inset: 0;
	z-index: -1;
	background-color: var(--color-black);
	transform: scaleX(0);
	transform-origin: left;
	transition: transform var(--duration-button) var(--ease-out);
}

.btn--outline-dark:focus-visible {
	color: var(--color-white);
}

@media (hover: hover) {

	.btn--outline-dark:hover {
		color: var(--color-white);
	}
}

.btn--outline-dark:focus-visible::before {
	transform: scaleX(1);
}

@media (hover: hover) {

	.btn--outline-dark:hover::before {
		transform: scaleX(1);
	}
}

/*
 * De Instagram-tegel.
 *
 * Hier stond een gloed die op hover aanging. Die is op 26 augustus 2026
 * weggehaald: de lege tegels staan in een container met aria-hidden, ze zijn
 * niet focusbaar en ze gaan nergens heen. Beweging op iets dat niet klikbaar is
 * belooft een handeling die niet bestaat, en dat is motion omdat het kon.
 *
 * Sinds 15 september 2026 is er een echte koppeling en zijn de gevulde tegels
 * links. Voor die tegels staat de hover terug, achter @media (hover: hover),
 * in het blok .tile--post verderop. De lege tegel blijft zonder.
 */
.tile {
	position: relative;
	isolation: isolate;
	overflow: hidden;
}

/* De lopende tekst onder het citaat: één smalle kolom, gecentreerd op de sectie
   maar links uitgelijnd, zoals in het goedgekeurde prototype. */
.quote-body {
	max-width: var(--container-text);
	margin-inline: auto;
}

/* Met het portret van Greg ernaast (16 oktober 2026) is het een storytelling-grid
   over de hele container: tekst links, beeld rechts. Sinds 17 oktober 2026 zonder
   verspringing: het portret staat verticaal gecentreerd naast de tekst en zakt er
   niet meer onder (Sepp, bij de livegang). */
.quote-body--beeld {
	max-width: none;
}

@media (min-width: 768px) {

	.quote-body--beeld {
		align-items: center;
	}

	.quote-body--beeld > *:nth-child(2) {
		margin-top: 0;
	}
}

/*
 * De kaart als één vlak.
 *
 * Het beeldvlak stond op --color-black en het lijf op --color-shadow, waardoor
 * een kaart zonder foto als twee gestapelde vlakken las. In het goedgekeurde
 * prototype is de plaat één oppervlak met de stencilletter bovenin. Zodra er wél
 * een foto is, doet die het onderscheid vanzelf.
 */
.card__media--empty {
	background-color: transparent;

	/*
	 * Het weefpatroon gaat er ook af. Het stond op --color-black met
	 * background-blend-mode: overlay, en dat blijft rustig zolang er een donkere
	 * grond onder ligt. Met een doorzichtige grond mengt overlay met de kaart
	 * eronder en springen de diagonalen er als brede strepen uit. In het
	 * goedgekeurde prototype is de plaat een vlak oppervlak met alleen de
	 * stencilletter.
	 */
	background-image: none;
}

/*
 * De kaart zonder foto is de plaat uit het goedgekeurde prototype, en dat is een
 * herstel en geen nieuw ontwerp.
 *
 * De gebouwde kaart was op drie punten afgedreven van `prototype-home.html`,
 * nagemeten op 1 september 2026 op 1440 bij 900. De plaat daar is 320px hoog
 * (`min-height: 20rem`), heeft 2rem rondom, en zet de letter op 6,5rem linksboven
 * met de naam onderaan. Wat er stond was 428px hoog, met een gereserveerd
 * beeldslot van 245px waarin een letter van 64px in het midden hing. Dat is 181px
 * leeg vlak op een donkere grond, en het leest als een kaart die op zijn foto
 * wacht in plaats van als een ontworpen staat.
 *
 * De letter mocht ook nooit klein zijn: de commentaarkop bij `.card__media--empty`
 * hierboven schrijft zelf "de eerste letter van de naam GROOT in de serif". Dat
 * stond er als bedoeling en is nooit uitgevoerd.
 *
 * Waarom het beeldslot in deze staat geen hoogte meer reserveert: dat slot is er
 * voor een foto van 3:2, en zolang er geen foto is reserveert het niets anders dan
 * leegte. Tot 11 september 2026 gold bij het CPT "alle negen een foto of geen
 * enkele", dus de rij was nooit half gevuld. Die regel is gevallen (zie
 * `inc/cpt-bedrijf.php`): de band draagt nu vier foto's en vijf letters. Nagekeken
 * op 1440: de band rekt elke kaart tot de hoogte van de fotokaarten, de letter
 * blijft linksboven en de naam onderaan, dus er valt geen kaart uit de pas. Komt
 * er een foto bij, dan vervalt `card--leeg` op die kaart vanzelf.
 */
.card--leeg {
	justify-content: space-between;
	min-height: 20rem;
	padding: var(--gap-sm);
}

/*
 * Geen aspect-ratio meer, dus de plaat is precies zo hoog als de letter. De letter
 * mag niet meer gecentreerd staan maar linksboven, en `overflow: visible` houdt de
 * onderkant van een letter met staart (de G, de J) heel.
 */
.card--leeg .card__media--empty {
	place-items: start;
	overflow: visible;
	aspect-ratio: auto;
}

/*
 * 6,5rem is de waarde uit het prototype, niet een eigen schatting. De omtrek gaat
 * naar de dikte van `.stencil` (1px op 0,20) in plaats van de 0,28 die hier stond:
 * hoe groter het merkteken, hoe rustiger de omtrek, en dat is dezelfde richting die
 * het faciliteitencijfer (tot 13 oktober 2026) op 26rem naar 0,11 nam.
 */
.card--leeg .card__initial {
	font-size: 6.5rem;
	-webkit-text-stroke: 1px color-mix(in srgb, var(--color-white) 20%, transparent);
}

.section-light .card--leeg .card__initial {
	-webkit-text-stroke-color: color-mix(in srgb, var(--color-black) 18%, transparent);
}

/*
 * Het lijf draagt de padding van de kaart, dus hier niet nog een keer.
 *
 * En het groeit hier niet mee. `.card__body` staat op `flex-grow: 1`, want in de
 * staat met foto moet het lijf de kaart tot onderaan vullen. Zonder foto slokt die
 * groei alle vrije ruimte op, waardoor `justify-content: space-between` niets meer
 * te verdelen heeft en de staart van de G op de rode streep van het label komt te
 * liggen. Nagemeten op 1 september 2026: lijf 150px waar het prototype er 114 heeft,
 * dus 36px die tussen de letter en het label hoorden te staan.
 */
.card--leeg .card__body {
	flex-grow: 0;
	padding: 0;
}

/* De pijl onder de naam: een gewone pijl, geen badge op het beeld. */
.card__pijl {
	display: inline-block;
	margin-top: var(--gap-xs);
	color: var(--text-on-dark-muted);
	transition: transform var(--duration-base) var(--ease-out), color var(--duration-base) var(--ease-out);
}

.section-light .card__pijl {
	color: var(--text-on-light-muted);
}

.card:focus-visible .card__pijl {
	transform: translateX(6px);
	color: var(--color-white);
}

@media (hover: hover) {

	.card:hover .card__pijl {
		transform: translateX(6px);
		color: var(--color-white);
	}
}

/*
 * De regel hierboven zet de pijl op wit, en dat klopt op een donkere grond.
 * In een lichte sectie is het wit op crème en dus onleesbaar. Voor hover werd
 * dat al teruggedraaid, voor toetsenbordfocus niet: wie met Tab door de
 * kaarten liep zag de pijl verdwijnen op precies het moment dat hij hem moest
 * kunnen volgen.
 */
.section-light .card:focus-visible .card__pijl {
	color: var(--color-black);
}

@media (hover: hover) {

	.section-light .card:hover .card__pijl {
		color: var(--color-black);
	}
}

/* De kop van de bedrijvenband breekt over twee regels, zoals in het ontwerp.
   Zonder deze grens loopt hij op een breed scherm op één regel door en verliest
   hij de verhouding met de pijlen ernaast. */
.section-statement--smal {
	max-width: 22ch;
}

/*
 * De losse regel onder een sectielabel, een trede kleiner. Sinds 9 september 2026.
 *
 * Sepp, kijkend naar Nieuws en events: "Het is niet mooi dat agenda en nieuws beide
 * zo groot zijn in lettertype in die secties, want (...) goede doelen (...) je krijgt
 * een beetje dubbele titeling als je dat doet, en het ziet er gewoon een beetje raar
 * uit daar."
 *
 * WAT ER GEMETEN AAN DE HAND WAS. Het brandbook kent drie kopvarianten (.section-title,
 * .section-statement, .section-label) en die zijn er alle drie om ALLEEN te staan.
 * Agenda en nieuws droegen er twee tegelijk, en dan valt de schaal om: .section-label
 * loopt tot 37,5px en .section-statement tot 48px, dus de h3 stond groter dan de h2
 * erboven. Twee koppen van bijna dezelfde maat onder elkaar lezen als twee titels,
 * en de sectie ernaast (goede doelen) draagt er maar één. Vandaar "dubbele titeling".
 *
 * De ingreep is een modifier en geen wijziging aan .section-statement zelf, want die
 * klasse staat op zeven andere plekken waar hij wél de enige kop is en waar 48px dus
 * klopt. De regel eronder heeft ook maar één taak: de ladder weer laten dalen.
 * 37,5 naar 30 naar 18, in plaats van 37,5 naar 48 naar 18.
 *
 * De copy blijft ongemoeid. Het is Julia's tweede regel en die gaat letterlijk de
 * site op; dit is opmaak en geen tekstingreep.
 */
.section-statement--onderkop {
	font-size: var(--text-h3);
	font-weight: var(--weight-medium);
	color: var(--text-on-light-muted);
}

.section-dark .section-statement--onderkop,
.section-shadow .section-statement--onderkop,
.section-deep .section-statement--onderkop {
	color: var(--text-on-dark-muted);
}

/* =======================================================================
 * De laatste drie secties, gelijkgetrokken met het prototype
 * ======================================================================= */

/*
 * Een kop die staat zoals de copywriter hem schreef.
 *
 * .section-title zet alles in kapitalen. Dat klopt voor "BELEEF FABRIEK59",
 * want zo staat het in de aanlever van 14 augustus. "Wandel door de
 * geschiedenis" staat daar in een gewone zin, en die hoort dus ook zo op het
 * scherm. Kapitalen zijn hier opmaak, geen schrijfwijze.
 */
.section-title--zoals-geschreven {
	text-transform: none;
}

/* De wandelroute-sectie met een foto van het terrein erachter. */
.route-sectie {
	position: relative;
	isolation: isolate;
}

.route-sectie__media {
	position: absolute;
	inset: 0;
	z-index: -2;
}

.route-sectie__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	filter: grayscale(0.7) sepia(0.3) brightness(0.4) contrast(1.15);
}

.route-sectie__waas {
	position: absolute;
	inset: 0;
	z-index: -1;
	background: linear-gradient(to right, color-mix(in srgb, var(--color-deep) 95%, transparent) 0%, color-mix(in srgb, var(--color-deep) 88%, transparent) 40%, color-mix(in srgb, var(--color-deep) 55%, transparent) 100%);
}

/* START en EINDE op het pad. Decoratie, dus het pad blijft aria-hidden. */
.route-lijn__merk {
	font-family: var(--font-sans);
	font-size: 11px;
	font-weight: var(--weight-semibold);
	letter-spacing: var(--tracking-wide);
	fill: var(--text-on-dark-muted);
}

/*
 * De Instagram-tegels zijn vlak, met de 59 als merkteken.
 *
 * Ze droegen het weefpatroon, en dat sprong er als brede diagonalen uit zodra ik
 * er isolation: isolate op zette voor de gloed: die maakt een eigen
 * stapelingscontext en dan mengt background-blend-mode met de tegel zelf in
 * plaats van met de grond eronder. Zelfde valkuil als bij de bedrijfskaart.
 */
.tile {
	background-image: none;
	font-family: var(--font-serif);
	font-size: 2.5rem;
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-tighter);
	color: color-mix(in srgb, var(--color-white) 18%, transparent);
}

/*
 * De tegel als bericht, sinds 15 september 2026.
 *
 * Met de koppeling (inc/instagram.php) wordt de tegel een link naar het bericht
 * op Instagram, met het gecachte beeld erin. Het raster, de maat en de mobiele
 * regel (drie van de zes) blijven van .tiles en .tile; dit blok zet alleen het
 * beeld erin en haalt het merkteken en het weefpatroon weg.
 *
 * De hover is terug, zoals de aantekening bij .tile het vroeg, en achter
 * @media (hover: hover). Hij spreekt de taal van de bedrijfskaart: het beeld
 * zoomt met --image-zoom en de tegel krijgt dezelfde lampgloed als de kaart op
 * de donkere grond. Geen lift, want zes kleine vierkanten in een strak raster
 * gaan niet los van elkaar omhoog zonder dat het raster gaat rammelen.
 */
.tile--post {
	display: block;
	background-image: none;
	transition: box-shadow var(--duration-image) var(--ease-out);
}

.tile--post img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform var(--duration-image) var(--ease-out);
}

.tile--post:focus-visible {
	box-shadow: 0 0 3.75rem color-mix(in srgb, var(--color-lamp) 12%, transparent);
}

.tile--post:focus-visible img {
	transform: scale(var(--image-zoom));
}

@media (hover: hover) {

	.tile--post:hover {
		box-shadow: 0 0 3.75rem color-mix(in srgb, var(--color-lamp) 12%, transparent);
	}

	.tile--post:hover img {
		transform: scale(var(--image-zoom));
	}
}

/* De kop van de afsluiter breekt over twee regels, zoals in het ontwerp. */
.outro-kop {
	max-width: 18ch;
}

/* Het adres staat als één blok in de schreefletter, niet met een gedempte
   tweede regel eronder. */
.channel .muted {
	/* Twee regels van hetzelfde adres horen op elkaar te staan, niet als twee
	   losse gegevens met lucht ertussen. */
	position: relative;
	margin-top: calc(var(--gap-xs) * -1);
	font-family: var(--font-serif);
	font-size: var(--text-h3);
	font-weight: var(--weight-semibold);
	letter-spacing: var(--tracking-normal);
	color: inherit;
}

/*
 * DE WAARDE VAN EEN KANAAL SCHAALT MET ZIJN EIGEN KOLOM, NIET MET HET VENSTER.
 *
 * Vanaf 768px staan de drie kanalen naast elkaar. In die stand is de kolom van
 * "Stuur een mail" 206px breed op een venster van 768, en `info@fabriek59.nl` is
 * op --text-h3 (24px) 214,5px. Dus 8,5px te breed. `body` draagt
 * `overflow-wrap: anywhere`, en dat is een van de drie regels die de nul
 * horizontale scroll dragen, dus die mag er niet af. Gevolg: het mailadres brak
 * middenin het woord over twee regels. Gemeten op 8 september 2026 op staging,
 * op /route/, /contact/, / en /wandelroute/, op 768 en op 800.
 *
 * De maat hoort dus bij de KOLOM en niet bij het venster: diezelfde kolom is op
 * 768 breed 206px en op 1024 breed 288px, terwijl het venster in beide gevallen
 * hetzelfde component toont. Daarom een container query en geen vw-clamp. Dit is
 * het ene geval dat het plan van deze ronde toestaat: een component dat
 * aantoonbaar in twee verschillende kolombreedtes voorkomt.
 *
 * 3cqw komt uit de meting: op 768 geeft dat 21,4px en een inktbreedte van 191px
 * in 206px, dus 15px lucht. Boven ongeveer 880px breed wint --text-h3 weer en
 * verandert er niets aan wat er nu staat.
 *
 * Ook de tweede adresregel gaat mee, anders staat "5013 BJ Tilburg" groter dan
 * de straat erboven. DIT BLOK MOET NA .channel .muted STAAN: die selector is
 * even specifiek en staat later in het bestand, en een media-query telt niet mee
 * in de specificiteit. Dezelfde val als bij .site-header en .nav-mobile.
 */
@media (min-width: 768px) {

	.channel__value,
	.channel .muted {
		font-size: min(var(--text-h3), 3cqw);
	}
}

/* ==========================================================================
   BEZOEKERS: de route-intro, de rondgang en de praktische informatie.

   Overgenomen uit het goedgekeurde prototype `app/public/prototype-bezoekers.html`
   (bron in `ux-onderzoek/prototype-bezoekers-bron/`). De maten en de kleuren
   komen daar letterlijk vandaan; wat hier anders is, is dat de kaart en de
   bediening de componenten van het thema hergebruiken in plaats van eigen
   varianten. Sepp: "gebruik dezelfde styling en hetzelfde hover-effect, zodat
   het één geheel wordt."
   ========================================================================== */

/* --------------------------------------------------------------------------
   De hero van elke binnenpagina luistert nu ook naar de schermHOOGTE.

   Dit staat hier en niet bij Bezoekers alleen, want het is de oorzaak van punt
   S1 op alle vijf de binnenpagina's. De hero-doos schaalt op HOOGTE, terwijl de
   kop op `--text-h2-large` stond en dat is `clamp(2.25rem, 5vw, 3.75rem)`, dus
   breedte. Die twee lopen de verkeerde kant op uit elkaar: van 1920x1080 naar
   1512x765 krimpt de doos met een derde terwijl de kop op 60px blijft staan, en
   alles eronder moet in een steeds kleinere rest.

   De doos was toen `min-height: 60vh`. Sinds 28 augustus 2026 is hij een volle
   schermhoogte, en die svh in de regel hieronder is daarmee nog belangrijker
   geworden en niet minder: de kop deelt nu de hele schermhoogte met de intro en
   de knop, en die drie moeten er samen in passen.

   De homepage had dit al goed via `min(7.5vw, 10.5svh)` in zijn eigen hero-maat;
   de binnenpagina's hadden die svh nooit gekregen. Gemeten bij Zeche Zollverein,
   die het met een media-query op `max-height: 820px` doet, zie
   `ux-onderzoek/steal-sheet-bezoekers.md`.
   -------------------------------------------------------------------------- */

.hero--page .section-title {
	font-size: clamp(2.25rem, min(6.5vw, 9svh), 5rem);
	line-height: 0.98;
}

/*
 * Liggend op een kleine telefoon zakt de ondergrens van die clamp.
 *
 * 2.25rem is er voor een SMALLE telefoon, waar de kop anders over te veel regels
 * breekt. Liggend is het venster juist breed en laag, dus daar is die ondergrens
 * niets waard en kost hij alleen hoogte. De rest van deze stand staat bij de
 * hero-blokken bovenin dit bestand; alleen deze regel moet hier staan, want een
 * media-query telt niet mee in de specificiteit en de regel hierboven staat later
 * in het bestand dan die blokken. Dezelfde val als bij .site-header en .nav-mobile.
 */
@media (max-height: 420px) and (orientation: landscape) {

	.hero--page .section-title {
		font-size: clamp(1.75rem, min(6.5vw, 9svh), 5rem);
	}
}

/*
 * En staand op een korte telefoon zakt diezelfde ondergrens, om de spiegelbeeldige
 * reden. Op 320x568 was de paginakop 176px hoog over vijf regels van 36px, in een
 * venster van 568 met een kopbalk van 104. Op 28px zijn dat vier regels. Gemeten
 * op 8 september 2026 op staging. Zelfde plaatsingsregel als het blok hierboven:
 * dit moet ná .hero--page .section-title staan.
 */
@media (max-height: 700px) and (orientation: portrait) {

	.hero--page .section-title {
		font-size: clamp(1.75rem, min(7vw, 9svh), 5rem);
	}
}

/* --------------------------------------------------------------------------
   De route-intro
   -------------------------------------------------------------------------- */

.route-intro__kop {
	font-family: var(--font-serif);
	font-size: var(--text-h2-large);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-tighter);
	line-height: var(--leading-tight);
	margin: 0.35rem 0 0;
	max-width: 16ch;
}

.route-intro__subkop {
	font-family: var(--font-serif);
	font-size: clamp(1.375rem, 2.2vw, 1.875rem);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-tighter);
	line-height: var(--leading-tight);
	margin: 0;
}

.route-intro__blok {
	display: grid;
	gap: var(--gap-md) var(--gap-xl, 4rem);
	margin-top: var(--gap-xl, 3rem);
	align-items: start;
}

@media (min-width: 900px) {
	.route-intro__blok { grid-template-columns: minmax(0, 0.75fr) minmax(0, 1.6fr); }
}

.route-intro__tekst p { margin: 0; }
.route-intro__tekst p + p { margin-top: 1rem; }

@media (min-width: 1100px) {
	/* Twee kolommen zetsel: bij zes regels per alinea leest dat prettiger dan
	   een regel van honderd tekens, en het vult de breedte zonder lege helft. */
	.route-intro__tekst { column-count: 2; column-gap: 3rem; }
	.route-intro__tekst p { break-inside: avoid; }
}

/* --------------------------------------------------------------------------
   De rondgang
   -------------------------------------------------------------------------- */

/* Breder dan de band op de homepage, want er moet een beeldslot naast de tekst
   passen. Zonder dat beeldslot zou de kaart hoog worden, en dan zie je de rij
   niet meer; dat was de fout van een eerdere versie. */
/*
 * Een kaartbreedte in plaats van drie, want de drie stappen sprongen.
 *
 * Hier stonden 86%, dan minmax(20rem, 24rem) vanaf 700 en minmax(22rem, 26rem)
 * vanaf 1100. Op 699/700 ging de kaart van 556px naar 320px breed en werd hij
 * 77px hoger; op 1099/1100 kwam daar nog 54px bij. Gemeten op /bezoekers/ op
 * 8 september 2026.
 *
 * De min() doet nu wat de drie stappen samen deden: onder de 500px vensterbreedte
 * is 86% smaller dan de bovengrens en houdt de kaart zijn kijkje op de volgende,
 * daarboven neemt de bovengrens het stil over. Die bovengrens loopt zelf van
 * 24rem naar 26rem tussen 1100 en 1600 in plaats van op 1100 te wisselen.
 */
.rondgang__band .band__track {
	grid-auto-columns: min(86%, clamp(24rem, 19.6rem + 6.4vw, 26rem));
}

/* De kaart is de kaart van de homepage. Alleen de indeling verschilt: het
   beeldslot staat rechts in plaats van bovenop. Alles wat de hover doet, de
   lift, de warme gloed, de zoom op het beeld en de initiaal die oplicht, komt
   ongewijzigd uit `.card` hierboven. */
/*
 * DE NAAM MOET IN DE TEKSTKOLOM PASSEN, ANDERS BREEKT HIJ MIDDEN IN HET WOORD.
 *
 * [ gemeten op staging op 8 september 2026, negen kaarten maal veertien breedtes,
 *   met het langste woord per naam tegen de gerenderde tekstkolom. Voor deze fix
 *   braken er 9 van 9 op 320, 8 op 360, 4 op 390, 1 van 1024 tot 1280, 2 op 1440
 *   en 4 op 1920 en 2560, met "HOOGSP / OOR" als ergste geval.
 *
 *   Twee maten liepen met het VENSTER mee terwijl de kaart dat niet doet. Het
 *   beeldslot stond op clamp(6.5rem, 9vw, 9.5rem) en groeide van 104 naar 152px,
 *   de padding stond op --gap-md en groeide van 24 naar 40px. De kaart zelf gaat
 *   maar van 384 naar 416px, dus die 72px kwamen allebei uit de tekstkolom: die
 *   zakte van 191px op 600 naar 150px op 1920. Tegelijk is --text-h3 deze ronde
 *   van vast 24px naar 24 tot 30px gaan lopen, en daarmee werd HOOGSPOOR in
 *   Fraunces bold 167px breed op 24px en 208px op 30px.
 *
 *   Daarom staan het beeldslot en de padding nu vast. 7rem beeld plus 1.5rem
 *   padding houdt op elke breedte vanaf 480 minstens 11px over boven het langste
 *   woord: 190px tekstkolom tegen 179px op 1100 (de krapste), 222 tegen 208 op
 *   1920. Die 1.5rem is dezelfde 1.5rem als .card__body hierboven, dus de kaart
 *   op de band houdt de binnenmarge van de kaart op home.
 *
 *   Onder 480 past er geen enkele indeling naast elkaar. De kaart is daar 86
 *   procent van de container, dus 239px op 320, en na padding, voeg en beeldslot
 *   blijft er 53px tekst over. Daar stapelt hij. Dat is de enige plek waar het
 *   argument hierboven, dat een beeld onderaan de kaart hoog maakt, niet opgaat:
 *   op een telefoon staat er toch maar een kaart tegelijk in beeld.
 *
 *   Nameten: scratchpad/halte.mjs, of elk script dat het langste woord per naam
 *   tegen de breedte van .card__title legt. Komt er een huurder bij met een naam
 *   die langer is dan HOOGSPOOR, meet dan opnieuw. ]
 */
.card--halte {
	display: grid;
	grid-template-columns: minmax(0, 1fr) 7rem;
	gap: var(--gap-sm);
	align-items: stretch;
	padding: 1.5rem;
}

.card--halte .card__body {
	padding: 0;
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	min-width: 0;
}

.card__media--halte {
	aspect-ratio: auto;
	align-self: stretch;
	border: 1px solid var(--border-light);
}

@media (max-width: 479px) {

	.card--halte {
		grid-template-columns: minmax(0, 1fr);
	}

	.card__media--halte {
		aspect-ratio: 3 / 2;
		align-self: auto;
	}
}

.card--halte .card__initial { font-size: clamp(2.5rem, 4vw, 3.5rem); }

/* --------------------------------------------------------------------------
   Het categoriefilter boven de band

   De chips zijn ghost-knoppen: dezelfde omkering van transparant-met-rand naar
   een vol vlak die `.btn--ghost` op elke donkere sectie doet. Hier staat die
   omkering uitgeschreven in plaats van dat `.btn--ghost` wordt hergebruikt,
   want een chip is geen knop: hij is 12px, hij heeft geen knop-padding en de
   actieve stand is een derde toestand die `.btn` niet kent.

   HET ROOD IS EEN VLAK EN NOOIT DE LETTERS. `--color-red` op de donkere grond
   haalt 2,9:1 en zakt daarmee door de 3:1 die WCAG 1.4.11 voor een
   UI-onderdeel vraagt. Wit op dat rood haalt 5,6:1 en dat mag wel. Dezelfde
   regel staat in tokens.css en op `.card .label--red`, die om dezelfde reden
   de streep rood maakt en de tekst niet.
   -------------------------------------------------------------------------- */

.filter {
	display: flex;
	flex-wrap: wrap;
	gap: var(--gap-xs);
	margin-bottom: var(--gap-md);

	/* Boven de band, om dezelfde reden als [data-band-nav] in layout.css: de
	   track schuift 72px omhoog voor de ruimte van zijn hover. Op mobiel lag hij
	   zo over de onderste rij chips, en een tik op Kunst of Woontextiel kwam bij
	   de band uit. Gemeten op 13 oktober 2026, elementFromPoint gaf de track. */
	position: relative;
	z-index: var(--z-base);
}

.filter__knop {
	position: relative;
	isolation: isolate;
	overflow: hidden;
	display: inline-flex;
	align-items: center;
	gap: 0.75rem;
	min-height: var(--touch-min);
	padding: 0 1.25rem;
	/* 40 procent en niet de 35 van `.btn--ghost`. Gemeten op de sectiegrond haalt
	   35 procent 2,99:1 en 40 procent 4,00:1, en WCAG 1.4.11 vraagt 3:1 voor de
	   omtrek waarmee je een UI-onderdeel herkent. Bij deze chip doet die rand dat
	   werk alleen: zonder hem is het een rij losse woorden en geen bediening. */
	border: 1px solid color-mix(in srgb, var(--color-white) 40%, transparent);
	border-radius: var(--radius-none);
	background-color: transparent;
	color: var(--color-white);
	font-family: var(--font-sans);
	font-size: var(--text-button);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-widest);
	line-height: 1.2;
	text-transform: uppercase;
	text-decoration: none;
	transition:
		color var(--duration-button) var(--ease-out),
		background-color var(--duration-button) var(--ease-out),
		border-color var(--duration-button) var(--ease-out);
}

/* Het vlak schuift van onderaf omhoog, precies zoals bij `.btn--ghost`. Een
   los element en geen background-transition, want een kleurovergang op een
   transparante achtergrond loopt door grijs en dat oogt vuil. */
.filter__knop::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background-color: var(--color-white);
	transform: scaleY(0);
	transform-origin: center bottom;
	transition: transform var(--duration-button) var(--ease-out);
}

.filter__knop:focus-visible::before { transform: scaleY(1); }

.filter__knop:focus-visible {
	color: var(--color-black);
	border-color: var(--color-white);
}

@media (hover: hover) {

	.filter__knop:hover::before { transform: scaleY(1); }

	.filter__knop:hover {
		color: var(--color-black);
		border-color: var(--color-white);
	}
}

/* Het aantal. Gedempt, want het is een bijzin bij de naam en geen tweede label. */
.filter__aantal {
	font-size: var(--text-badge);
	letter-spacing: var(--tracking-wide);
	color: var(--text-on-dark-muted);
	transition: color var(--duration-button) var(--ease-out);
}

.filter__knop:focus-visible .filter__aantal { color: var(--text-on-light-muted); }

@media (hover: hover) {
	.filter__knop:hover .filter__aantal { color: var(--text-on-light-muted); }
}

/* De actieve stand. Staat NA de hover-regels, zodat de actieve chip niet onder
   de muis van rood naar wit springt: die stand is een mededeling en geen
   uitnodiging.

   DE RAND IS WIT EN NIET ROOD, en dat is gemeten en geen smaak. Het rode vlak
   haalt tegen de sectiegrond 2,84:1, en WCAG 1.4.11 vraagt 3:1 voor de
   omtrek waarmee je een UI-onderdeel en zijn stand herkent. Met een rode rand
   is de enige grens van deze chip dus te zwak, en juist deze chip DRAAGT
   informatie: hij zegt welk filter aanstaat. De witte rand haalt 16,8:1 tegen
   de grond en 5,98:1 tegen het rood, dus de vorm is onmiskenbaar en het rood
   blijft doen wat het brandbook hem geeft: de actieve staat markeren.

   Dit is dezelfde regel die op `.card .label--red` de tekst dempt en de
   streep rood laat: rood op donker is nooit de drager. */
.filter__knop.is-actief,
.filter__knop.is-actief:hover,
.filter__knop.is-actief:focus-visible {
	background-color: var(--color-red);
	border-color: var(--color-white);
	color: var(--color-white);
}

/* Expliciet ook op :hover en :focus-visible, want zonder die twee zit de
   actieve chip op gelijke specificiteit met de ghost-omkering hierboven en
   beslist alleen de volgorde in dit bestand. Dat is te stil om op te bouwen. */
.filter__knop.is-actief::before,
.filter__knop.is-actief:hover::before,
.filter__knop.is-actief:focus-visible::before { transform: scaleY(0); }

/* Op het rood mag het aantal NIET gedempt worden. Wit op 80 procent haalt daar
   2,83:1 op 10px, en dat is ver onder de 4,5:1 die kleine tekst nodig heeft.
   Vol wit haalt 5,98:1. De nuance van een gedempt cijfer is hier minder waard
   dan een leesbaar cijfer, en dat is niet onderhandelbaar in dit project. */
.filter__knop.is-actief .filter__aantal,
.filter__knop.is-actief:hover .filter__aantal,
.filter__knop.is-actief:focus-visible .filter__aantal {
	color: var(--color-white);
}

/* De plattegrond met de bedrijven erop. Vanaf 768px is dit de rondgang en staat
   de band met zijn pijlen uit; daaronder is het andersom (Sepp, 13 oktober 2026:
   "dan is heel de slider op pc niet meer nodig"). De kaart is begrensd op
   --rondgang-kaart-max zodat de legenda in het beeld leesbaar is zonder dat hij
   het hele scherm vult. Mobiel is hij weg, ook op verzoek van Sepp: daar is de
   legenda niet te lezen, en de band wordt er een verticale afdaling. */
.rondgang__plattegrond {
	display: none;
}

@media (min-width: 768px) {

	.rondgang__band,
	.rondgang .band__nav {
		display: none;
	}

	.rondgang__plattegrond {
		display: grid;
		gap: var(--gap-md);
		margin-top: var(--gap-md);
	}
}

/* Kaart en lijst naast elkaar vanaf 1100px, het breekpunt dat de band hierboven
   al kent. Gemeten op 13 oktober 2026: op 1024 kreeg de kaart naast een lijst van
   16rem nog 670px en werd de lijst 773px hoog naast een kaart van 503. Daaronder
   staat de lijst daarom in drie kolommen onder de kaart. */
.rondgang__kaart {
	justify-self: center;
	width: min(100%, var(--rondgang-kaart-max));
}

@media (min-width: 1100px) {

	.rondgang__plattegrond {
		grid-template-columns: minmax(0, var(--rondgang-kaart-max)) minmax(18rem, 1fr);
		align-items: start;
	}

	.rondgang__kaart {
		width: 100%;
	}
}

.rondgang__kaart {
	position: relative;
	margin: 0;
	overflow: hidden;
	border-radius: var(--radius-sm);
	box-shadow: var(--shadow-frame-dark);
}

.rondgang__kaart img {
	display: block;
	width: 100%;
	height: auto;
}

/* Dezelfde viewBox als het beeld, 1400 bij 1050, dus de punten schalen mee. De
   laag zelf vangt geen muis, alleen de punten, anders is het beeld eronder een
   dode vlek voor wie wil rechtsklikken of slepen. */
.kaartpunten {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	pointer-events: none;
}

.kaartpunt {
	pointer-events: auto;
	cursor: pointer;
}

/* Een unit zonder pagina op de site: wel de naam bij aanwijzen, geen link. */
.kaartpunt--los {
	cursor: default;
}

/* De pin van een bedrijf: rood, dunne witte rand, het unitnummer in wit, met de
   punt op de plek. Op 13 oktober 2026 was het een rode druppel zoals de haltes
   op Gregs routekaart; op 16 oktober werd hij zwart om van die haltes af te
   steken, en in de doorloop van die middag ging de route van de ondergrond en
   kwam het unitnummer erin in plaats van het volgnummer (Greg: "dat is
   eigenlijk 45-3"). Zonder haltes op de kaart werd hij die avond weer rood,
   op Sepps verzoek: "Ik denk dat rood beter is." Wit op --color-red haalt
   ruim 5:1. De pad en de breedte komen
   uit f59_plattegrond_pin(), want een unitnummer is breder dan twee cijfers.

   De vorm schaalt vanuit de punt, zodat hij bij aanwijzen groeit zonder van
   zijn plek te schuiven. */
.kaartpunt__vorm {
	transform-box: view-box;
	transform-origin: 0 0;
	transition: transform var(--duration-base) var(--ease-out);
}

.kaartpunt__vlak {
	fill: var(--color-red);
	stroke: var(--color-white);
	stroke-width: 3;
	stroke-linejoin: round;
}

.kaartpunt__nr {
	fill: var(--color-white);
	font-family: var(--font-sans);
	font-size: 19px;
	font-weight: var(--weight-bold);
	letter-spacing: -0.02em;
}

/* De naam staat er pas bij aanwijzen. Negen namen tegelijk liggen over elkaar
   heen rond de lichtkoepels rechtsboven. De zwarte rand om de letters houdt hem
   leesbaar op elke plek van de foto. */
.kaartpunt__naam {
	fill: var(--color-white);
	stroke: var(--color-black);
	stroke-width: 6px;
	stroke-linejoin: round;
	paint-order: stroke;
	font-family: var(--font-sans);
	font-size: 26px;
	font-weight: var(--weight-bold);
	opacity: 0;
	pointer-events: none;
	transition: opacity var(--duration-base) var(--ease-out);
}

.kaartpunt.is-licht .kaartpunt__vorm,
.kaartpunt:focus-visible .kaartpunt__vorm {
	transform: scale(1.3);
}

.kaartpunt.is-licht .kaartpunt__naam,
.kaartpunt:focus-visible .kaartpunt__naam {
	opacity: 1;
}

@media (hover: hover) {

	.kaartpunt:hover .kaartpunt__vorm {
		transform: scale(1.3);
	}

	.kaartpunt:hover .kaartpunt__naam {
		opacity: 1;
	}
}

/* Het filter zet `hidden` op wie niet bij de categorie hoort. Een SVG-element
   kent dat attribuut niet uit zichzelf, en voor de regel in de lijst geldt de
   val die bij .card[hidden] staat. */
.kaartpunt[hidden],
.rondgang__lijst > li[hidden] {
	display: none;
}

.rondgang__lijst {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: var(--gap-xs);
	margin: 0;
	padding: 0;
	list-style: none;
}

@media (min-width: 1100px) {

	.rondgang__lijst {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* De kaart van de homepage, als regel. Lift, gloed en pijl komen ongewijzigd uit
   `.card`, zodat dit één geheel blijft met de band op mobiel. Alleen de indeling
   is anders: een rij in plaats van een kolom. */
.card--kaartlijst {
	flex-direction: row;
	align-items: center;
	gap: var(--gap-xs);
	height: auto;
	padding: var(--gap-xs) 0.75rem;
}

.card--kaartlijst .card__pijl {
	flex: none;
	margin-top: 0;
}

/* De lift van .card schuift de regel 10px onder de muis vandaan. In een dichte
   lijst staat de muis dan vaak op de onderrand: de regel zakt terug, wordt weer
   aangewezen, en flikkert. Gemeten op 13 oktober 2026, de test kon er niet op
   klikken. Deze strook vult het gat dat de lift achterlaat. */
.card--kaartlijst {
	position: relative;
}

.card--kaartlijst::after {
	content: "";
	position: absolute;
	inset: 0 0 -10px;
}

/* Breed genoeg voor "45-3" en de regels lijnen uit; een langere pin zoals
   "47-1 t/m 3" duwt zijn eigen regel op. */
.kaartlijst__nr {
	flex: none;
	display: block;
	min-width: 3.5rem;
	height: 2.5rem;
	transform-origin: 50% 100%;
	transition: transform var(--duration-base) var(--ease-out);
}

.kaartlijst__nr svg {
	display: block;
	width: auto;
	height: 100%;
	overflow: visible;
}

/* In drie kolommen onder de 900px is een regel zo smal dat "47-1 t/m 3" de naam
   ernaast liet breken tot "Block01 3" (gemeten op 768, 16 oktober 2026). Daar staat
   de pin boven de naam, en de naam met de pijl op de regel eronder. */
@media (max-width: 899.98px) {

	.card--kaartlijst {
		flex-wrap: wrap;
		align-items: flex-end;
		row-gap: 0.5rem;
	}

	/* Met de kaart ervoor, want de `flex: 1` hieronder staat later in het bestand. */
	.card--kaartlijst .kaartlijst__tekst {
		flex: 1 1 calc(100% - 3rem);
	}
}

.kaartlijst__tekst {
	flex: 1;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 0.125rem;
}

.kaartlijst__naam {
	margin: 0;
	font-family: var(--font-serif);
	font-size: var(--text-body);
	font-weight: var(--weight-bold);
	line-height: 1.2;
	color: var(--text-on-dark);
}

.kaartlijst__categorie {
	font-family: var(--font-sans);
	font-size: var(--text-body-sm);
	color: var(--text-on-dark-muted);
}

/* Wijs je een punt op de kaart aan, dan doet de regel wat hij bij zijn eigen
   hover doet. */
.card--kaartlijst.is-licht {
	transform: translateY(-10px);
	border-color: color-mix(in srgb, var(--color-white) 18%, transparent);
	box-shadow: 0 0 3.75rem color-mix(in srgb, var(--color-lamp) 12%, transparent);
}

.card--kaartlijst.is-licht .card__pijl {
	transform: translateX(6px);
	color: var(--color-white);
}

.card--kaartlijst.is-licht .kaartlijst__nr,
.card--kaartlijst:focus-visible .kaartlijst__nr {
	transform: scale(1.12);
}

@media (hover: hover) {

	.card--kaartlijst:hover .kaartlijst__nr {
		transform: scale(1.12);
	}
}

/* Een bedrijf dat na een klik op een filterchip in beeld komt, schuift kort
   omhoog in plaats van er ineens te staan. Zonder dit zie je op de kaart niet
   wat er veranderd is. */
.is-erbij {
	animation: rondgang-erbij var(--duration-base) var(--ease-out);
}

@keyframes rondgang-erbij {
	from {
		opacity: 0;
		translate: 0 0.5rem;
	}
}

@media (prefers-reduced-motion: reduce) {

	.is-erbij {
		animation: none;
	}
}

/* --------------------------------------------------------------------------
   De praktische informatie
   -------------------------------------------------------------------------- */

.praktisch__kop {
	display: grid;
	gap: var(--gap-md) var(--gap-lg);
	align-items: end;
	margin-bottom: var(--gap-lg);
}

@media (min-width: 768px) {
	.praktisch__kop { grid-template-columns: minmax(0, 1fr) auto; }
}

.praktisch__titel {
	font-family: var(--font-serif);
	font-size: var(--text-h2);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-tighter);
	line-height: var(--leading-tight);
	margin: 0.5rem 0 0;
}

.praktisch__actie { margin: 0; }

.praktisch__lijst {
	list-style: none;
	margin: 0;
	padding: 0;
	border-top: 1px solid var(--border-dark);
}

.praktisch__rij {
	display: grid;
	/*
	 * Expliciet, want een raster zonder kolomsjabloon krijgt een impliciete
	 * `auto`-kolom en die wordt zo breed als zijn inhoud. Bij 200 procent
	 * tekstvergroting was dat 351px in een container van 310.
	 */
	grid-template-columns: minmax(0, 1fr);
	gap: 0.5rem var(--gap-lg);
	padding-block: var(--gap-md);
	border-bottom: 1px solid var(--border-dark);
}

@media (min-width: 768px) {
	.praktisch__rij { grid-template-columns: 14rem minmax(0, 1fr); }
}

.praktisch__label {
	font-family: var(--font-sans);
	font-size: var(--text-label);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-widest);
	text-transform: uppercase;
	margin: 0;
	display: flex;
	align-items: baseline;
	gap: 0.75rem;
}

/* Het rode streepje van de eyebrow, maar dan voor de regel. Zelfde taal, en
   rood draagt hier geen tekst: het is decoratie. */
.praktisch__label::before {
	content: "";
	width: 1.25rem;
	height: 2px;
	background: var(--color-red);
	flex: none;
	transform: translateY(-0.3em);
}

.praktisch__waarde { margin: 0; }
.praktisch__waarde p { margin: 0; }
.praktisch__waarde p + p { margin-top: 1rem; }

/* Tot 13 oktober 2026 stonden de openingstijden vanaf 1100px in twee kolommen.
   Julia en Greg in de feedback van 8 oktober: "ik zou persoonlijk meer van boven
   naar onder willen lezen i.p.v. van links naar rechts". Ze staan nu onder elkaar,
   op dezelfde regellengte als de andere rijen van dit blok. */


/* =======================================================================
 * DE TIJDLIJN OP HISTORIE, verticale vertelling
 *
 * Overgenomen uit app/public/prototype-historie.html, goedgekeurd op
 * 26 augustus 2026. Vervangt de horizontale band van .timeline__track.
 *
 * De vorm komt niet van buiten maar uit deze site zelf: het zelf-tekenende
 * SVG-pad draait al op de wandelroute-sectie en de bol-per-halte op de
 * bezoekerspagina. De tijdlijn was de enige plek waar een reeks momenten
 * zonder lijn werd getoond, en daarom las hij als losse tekstkolommen.
 *
 * Onderbouwing en gemeten waarden: ux-onderzoek/steal-sheet-tijdlijn.md
 * ======================================================================= */

/*
 * Wit en niet rood. Rood op donker haalt 2,69:1 en de site eist 3:1 voor grote
 * tekst, dus --color-red mag hier nooit tekst dragen. Dat staat zo in
 * website/CLAUDE.md en het gold ook voor dit beoordelingskader, dat ik er
 * aanvankelijk buiten had gelaten. De meetlat ving het.
 */
/* =========================================================================
   1. DE TIJDLIJN ALS VERTICALE VERTELLING
   =========================================================================

   Vervangt de horizontale band. De lijn staat links en loopt over de volle
   hoogte van de sectie; per halte een bol, het jaartal als stencil, en rechts
   de inhoud op leesbreedte.

   Waarom links en niet in het midden: een middenlijn met haltes om en om is de
   tijdlijn-default van het hele internet, en hij dwingt de tekst in twee halve
   kolommen. Dat is precies het probleem dat we oplossen. Links geeft een
   leesrichting, volle breedte voor de tekst, en op mobiel verandert de
   structuur niet.
   ========================================================================= */

/*
 * De lijn ligt absoluut over de volle hoogte, de haltes zijn gewone blokken
 * met ruimte links.
 *
 * Eerst geprobeerd met een grid van twee kolommen waarin de lijn grid-row 1/-1
 * kreeg. Dat werkte niet: de haltes namen met grid-column 1/-1 beide kolommen
 * in en overlapten de lijn, en de SVG bleef op zijn intrinsieke 1000px staan
 * terwijl het raster 5453px hoog was. Absoluut is hier eenvoudiger en het kan
 * niet stilletjes fout gaan.
 */
.tijdlijn {
	position: relative;
	padding-left: 4.5rem;
}

.tijdlijn__lijn {
	position: absolute;
	left: 0;
	top: 0.75rem;
	bottom: 0;
	width: 2rem;
}
.tijdlijn__lijn svg {
	display: block;
	width: 100%;
	height: 100%;
	overflow: visible;
}

/*
 * Twee paden over elkaar, precies zoals de route-lijn op de wandelroute-sectie.
 * Het eerste is het stippelspoor dat er altijd staat, het tweede wordt getekend.
 * De dasharray wordt pas in JS gezet, dus zonder script staat de rode lijn er
 * gewoon helemaal: geen animatie, nooit geen inhoud.
 */
.tijdlijn__spoor {
	fill: none;
	stroke: color-mix(in srgb, var(--color-white) 28%, transparent);
	stroke-width: 2;
	stroke-dasharray: 4 8;
	stroke-linecap: round;
}
.tijdlijn__getekend {
	fill: none;
	stroke: var(--color-red);
	stroke-width: 3;
	stroke-linecap: round;
}

.halte {
	position: relative;
	padding-block: var(--gap-lg);
}
.halte:first-of-type { padding-top: 0; }
.halte:last-of-type { padding-bottom: 0; }

/*
 * De bol staat op de lijn, ter hoogte van het jaartal. Niet sticky: hij markeert
 * een MOMENT op de lijn en niet waar de bezoeker is. Waar je bent lees je af aan
 * welke bol rood is.
 *
 * left: -4.5rem haalt hem terug uit de padding van .tijdlijn, +1rem centreert
 * hem op de 2rem brede lijn, min de halve bolbreedte.
 */
.halte__merk {
	position: absolute;
	left: -4.5rem;
	top: var(--gap-lg);
	width: 2rem;
	display: flex;
	justify-content: center;
}
.halte:first-of-type .halte__merk { top: 0; }

.halte__bol {
	display: block;
	margin-top: 0.75rem;
	width: 1rem;
	height: 1rem;
	border-radius: 50%;
	background: var(--color-black);
	border: 2px solid color-mix(in srgb, var(--color-white) 50%, transparent);
	transition:
		background-color var(--duration-base) var(--ease-out),
		border-color var(--duration-base) var(--ease-out),
		transform var(--duration-base) var(--ease-out);
}

/*
 * De signature move: de bol van de halte die je leest kleurt rood. De lijn is
 * daarmee niet alleen versiering maar laat zien waar je in het verhaal staat.
 * Zelfde idee als de routelijn die tot 13 oktober 2026 op Bezoekers stond, waar
 * "waar je bent op het terrein" en "waar je bent op de route" hetzelfde ding waren.
 */
.halte.is-actief .halte__bol {
	background: var(--color-red);
	border-color: var(--color-red);
	transform: scale(1.35);
}

/*
 * De inhoud gebruikt de volle kolom; alleen de LOPENDE TEKST wordt begrensd tot
 * de leesregel. Stond eerst op --container-narrow (768px) voor het hele blok, en
 * dan bleef er rechts ruim 400px leeg naast het beeld. Dat is de dode kolom waar
 * de skill voor waarschuwt: body-content in een smalle kolom met een lege
 * paginahelft ernaast.
 *
 * Nu draagt het beeld de volle breedte en blijft de tekst leesbaar. Dat is
 * bovendien de klassieke redactionele opzet: breed beeld, smalle kolom eronder.
 */
.halte__inhoud {
	max-width: none;
}

/* Het jaartal als stencil, de zet die de deuren op home ook gebruiken. */
.halte__jaar {
	display: block;
	font-family: var(--font-serif);
	font-size: clamp(2.5rem, 6vw, 4rem);
	font-weight: var(--weight-bold);
	line-height: 1;
	letter-spacing: var(--tracking-tighter);
	color: transparent;
	-webkit-text-stroke: 1px color-mix(in srgb, var(--color-white) 45%, transparent);
	margin-bottom: var(--gap-xs);
	transition: -webkit-text-stroke-color var(--duration-base) var(--ease-out);
}
.halte.is-actief .halte__jaar {
	-webkit-text-stroke-color: var(--color-white);
}

.halte__plek {
	display: block;
	font-family: var(--font-sans);
	font-size: var(--text-body-sm);
	font-weight: var(--weight-semibold);
	letter-spacing: var(--tracking-wide);
	text-transform: uppercase;
	color: var(--text-on-dark-muted);
	margin-bottom: var(--gap-sm);
}

.halte__titel {
	font-family: var(--font-serif);
	font-size: var(--text-h2-large);
	font-weight: var(--weight-bold);
	line-height: var(--leading-tight, 1.1);
	letter-spacing: var(--tracking-tighter);
	margin: 0 0 var(--gap-sm);
	max-width: 24ch;
}

/*
 * Het beeld is een voorwerp en geen achtergrond: ingelijst, met het
 * museumbordje eronder. Dat is de regel uit het concept, en de reden dat de
 * archieffoto's hier van 335px naar volle kolombreedte gingen. Ze zijn het
 * waardevolste materiaal van deze site.
 *
 * Sinds 11 september 2026 is die breedte begrensd op --halte-beeld-max (50rem,
 * ongeveer twee derde van de kolom op 1440), op verzoek van Sepp. Het beeld
 * blijft links op de leesregel staan; de tekst eronder is toch al 40rem, dus
 * beeld en tekst lezen nu als één kolom in plaats van een breed vlak met een
 * smalle kolom eronder. Onder 900px valt de grens weg en vult het beeld de
 * breedte, want daar is de kolom zelf al smaller dan het token. De sizes-hint
 * in section-tijdlijn.php rekent met dezelfde 50rem.
 */
.halte__beeld {
	position: relative;
	margin: 0 0 var(--gap-sm);
	max-width: min(100%, var(--halte-beeld-max));
}

@media (max-width: 899px) {
	.halte__beeld { max-width: 100%; }
}
.halte__beeld img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: var(--radius-sm);
}

/* Hier stond het bordje linksonder op de foto; vervallen op 13 oktober 2026. */

.halte__tekst {
	max-width: var(--container-text);
}
.halte__tekst p { margin: 0 0 1.25rem; }
.halte__tekst p:last-child { margin-bottom: 0; }

/*
 * Een halte zonder beeld krijgt geen vervangend vlak; de leegte is daar het
 * eerlijke antwoord, en dat staat al zo in section-tijdlijn.php. Halte 4 (1989)
 * was tot 11 september 2026 de enige zonder; sindsdien dragen alle vijf beeld en
 * vangt deze regel een halte waarvan de foto via de editor is weggehaald.
 */
.halte--zonder-beeld .halte__tekst { max-width: var(--container-text); }

@media (max-width: 768px) {
	.tijdlijn { padding-left: 2.5rem; }
	.tijdlijn__lijn { width: 1.25rem; }
	.halte { padding-block: var(--gap-md); }
	.halte__merk { left: -2.5rem; width: 1.25rem; top: var(--gap-md); }
	.halte__bol { width: 0.75rem; height: 0.75rem; }
}

/* =========================================================================
   HET PROCES: de foto naast de tekst in plaats van eronder
   =========================================================================
   .storytelling-grid zet zijn tweede kolom met --storytelling-offset omlaag.
   Dat werkt waar een beeld tegen lopende tekst moet afsteken, maar hier zakt de
   foto daardoor tegen de stappen-kaarten aan. Voor deze ene sectie lijnt hij
   bovenaan uit, en er komt lucht tussen het blok en de kaarten.
   ========================================================================= */

.proces-grid > *:nth-child(2) {
	margin-top: 0;
}
.proces-grid {
	margin-bottom: var(--gap-xl);
}

/* =========================================================================
   2. DE VIER SORTEERSTAPPEN ALS KAARTEN
   =========================================================================
   Punt G3 uit de feedback van 18 augustus. Ze stonden als lijstregels op
   hairlines. De labels zijn LETTERLIJK uit de aangeleverde alinea gehaald en
   zijn geen nieuwe copy; er is ook geen groepskop bij verzonnen.
   ========================================================================= */

.stappen {
	display: grid;
	/*
	 * min(15rem, 100%) en niet 15rem kaal: de ondergrens van een minmax is hard,
	 * dus bij 200 procent tekstvergroting eist 15rem een kolom van 480px in een
	 * container van 310 en loopt het raster het venster uit. Met min() zakt de
	 * ondergrens mee naar de beschikbare breedte.
	 */
	grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
	gap: 1px;
	background: color-mix(in srgb, var(--color-black) 12%, transparent);
	border: 1px solid color-mix(in srgb, var(--color-black) 12%, transparent);
	margin: 0;
	padding: 0;
	list-style: none;
}

/*
 * VIER STAPPEN STAAN OP EEN RIJ OF TWEE BIJ TWEE, NOOIT OP DRIE PLUS EEN.
 *
 * De auto-fit hierboven telt zelf uit hoeveel kolommen van 15rem er passen, en
 * daar zit een band in waar er precies drie passen. De vierde stap staat dan
 * alleen op een tweede rij, met twee derde van die rij als kale rasterlijn
 * ernaast. Dat leest als een fout en niet als een opzet.
 *
 * Gemeten op staging op 8 september 2026, op /historie/, per pixel:
 * tot en met 779px twee kolommen, van 780 tot en met 1027 drie, vanaf 1028 vier.
 * De rasterbreedte op 1026 is 963px en dat is precies een pixel te weinig voor
 * vier kolommen van 240 plus drie voegen van 1.
 *
 * De bovengrens hangt dus aan --container-px en aan de 15rem hierboven. Verandert
 * er een van de twee, meet dan opnieuw waar de derde kolom begint en eindigt; de
 * grens is geen ontwerpkeuze maar de uitkomst van die twee waarden.
 */
@media (min-width: 780px) and (max-width: 1027px) {

	.stappen {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}
.stap {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: var(--gap-xs);
	padding: var(--gap-sm) 1.5rem 1.5rem;
	background: var(--color-white);
	transition: background-color var(--duration-base) var(--ease-out);
}
@media (hover: hover) {

	.stap:hover { background: var(--color-stap-hover); }
}

/* Het volgnummer als stencil, dezelfde zet als de haltes op Bezoekers. */
.stap__nr {
	font-family: var(--font-serif);
	font-size: 2rem;
	font-weight: var(--weight-bold);
	line-height: 1;
	color: transparent;
	-webkit-text-stroke: 1px color-mix(in srgb, var(--color-black) 30%, transparent);
	transition: -webkit-text-stroke-color var(--duration-base) var(--ease-out);
}
@media (hover: hover) {

	.stap:hover .stap__nr { -webkit-text-stroke-color: var(--color-red); }
}

.stap__label {
	font-family: var(--font-sans);
	font-size: var(--text-label);
	font-weight: var(--weight-semibold);
	letter-spacing: var(--tracking-wide);
	text-transform: uppercase;
	color: var(--text-on-light);
}
.stap__tekst {
	font-family: var(--font-sans);
	font-size: var(--text-body);
	color: var(--text-on-light-muted);
}



/* =======================================================================
 * DE LEGE STAAT ALS STROOK
 *
 * Vervangt het gestippelde .empty-kader op Nieuws en events, gekozen op
 * 26 augustus 2026.
 *
 * Dat kader was bijna paginabreed en 285px hoog voor drie regels tekst, met de
 * rechterhelft leeg, en het stond er twee keer onder elkaar. Een stippelrand
 * zegt "hier hoort iets dat er niet is": bouwplaats-esthetiek. Twee keer achter
 * elkaar las de pagina als een gat.
 *
 * Dit is een regel in plaats van een vlak: EEN hairline met de tekst erboven en de
 * knop rechts, zoals een uithangbord boven een poort. 144px in plaats van 285px, en
 * de knop vult de rechterkant zodat er geen dode kolom overblijft.
 *
 * HIER STOND "twee hairlines met de tekst ertussen", en dat is de vorm van vóór de
 * herziening van 26 augustus 2026 die twee alinea's verderop wordt beschreven. Er is
 * alleen een `border-bottom`; `border-top` is 0. Nagemeten in de verse-ogen-ronde van
 * 9 september 2026.
 * ======================================================================= */

/*
 * De strook stond eerst in een kader van twee haarlijnen over de volle breedte.
 * Op 26 augustus 2026 herzien naar een onderstreping, variant C, gekozen door
 * Sepp uit drie varianten.
 *
 * Twee dingen zijn hier gerepareerd.
 *
 * DE DODE KOLOM. De lijnen liepen door tot 1232px terwijl `.strook__tekst` op
 * 52rem stopt, dus er stond 400px lijn met niets eronder. Dat is precies de dode
 * kolom waarvoor de strook op 26 augustus juist was gebouwd, terug op de variant
 * zonder knop. Het mechanisme komt van de agenda van Zeche Zollverein, live
 * gemeten diezelfde dag: daar hangt de haarlijn aan de INHOUDSKOLOM (`flex-1
 * border-t`) en niet aan de rij, en dan kan die situatie niet ontstaan. Zie
 * `ux-onderzoek/steal-sheet-lege-staat.md`.
 *
 * HET GEWICHT. Drie lege staten op een pagina met hetzelfde skelet lazen als drie
 * keer hetzelfde. Eén lijn in plaats van twee, en de sectie eromheen op --sm,
 * brengt de drie samen van 1580 naar ongeveer 1050px.
 */
.strook {
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto;
	align-items: end;
	gap: var(--gap-md);
	padding-bottom: var(--gap-xs);
	border-bottom: 1px solid color-mix(in srgb, var(--color-black) 18%, transparent);
}

.section-dark .strook,
.section-shadow .strook {
	border-color: color-mix(in srgb, var(--color-white) 18%, transparent);
}

.strook__tekst {
	margin: 0;
	max-width: 52rem;
}

.strook__titel {
	font-family: var(--font-serif);
	font-size: var(--text-h3);
	font-weight: var(--weight-semibold);
	margin: 0 0 0.35rem;
}

.strook__regel {
	margin: 0;
	color: var(--text-on-light-muted);
}

.section-dark .strook__regel,
.section-shadow .strook__regel {
	color: var(--text-on-dark-muted);
}

/*
 * Zonder knop: een kolom, en de hele strook krimpt mee tot de leesbreedte. Dat
 * tweede is het punt: zo stopt de haarlijn waar de tekst stopt, in plaats van
 * door te lopen over een kolom waar niets staat.
 *
 * Mét knop mag de lijn wel de volle breedte houden, want dan ankert de knop de
 * rechterkant en draagt die kolom dus iets.
 */
.strook--enkel {
	grid-template-columns: minmax(0, 1fr);
	max-width: 52rem;
}

@media (max-width: 700px) {
	/* Onder de knop in plaats van ernaast; naast elkaar wordt de tekst te smal. */
	.strook {
		grid-template-columns: minmax(0, 1fr);
		gap: var(--gap-sm);
	}
}


/* =======================================================================
 * DE FACILITEITEN ALS SET, EN NIET ALS LIJST
 *
 * Variant C uit de vormronde van 28 augustus 2026, plus wat Sepp erbij vroeg.
 * De onderbouwing per onderdeel staat in section-faciliteiten.php.
 *
 * De vorige twee vormen staan daar ook: genummerde rijen (afgekeurd 18 augustus)
 * en een bordje met vinkjes (afgekeurd 28 augustus, "heel lelijk"). Beide waren
 * veertien even zware regels, en dat is het probleem dat deze vorm oplost: als
 * blok neem je hem in een oogopslag op.
 *
 * .facilities blijft bestaan: die staat ook op de bezoekerspagina.
 * ======================================================================= */

.faciliteiten {
	position: relative;
}

.faciliteiten__blok {
	position: relative;
}

/*
 * De set. position: relative doet hier twee dingen: het legt de plaatjes boven
 * het stencilcijfer, en het maakt van de lijst de offsetParent van de plaatjes.
 * Dat tweede is wat spat.js gebruikt om de afstand tot het midden te meten, dus
 * haal het niet weg zonder dat script erbij te pakken.
 */
.spatlijst {
	position: relative;
	z-index: 1;
	list-style: none;
	margin: var(--gap-md) 0 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: 0.85rem;
}

/*
 * Het plaatje hangt aan een spijker.
 *
 * Twee lagen, en dat is geen stijlkeuze. De li draagt de VLUCHT vanuit het midden
 * en de spijkerkop; de span draagt de PLAAT die eraan hangt. Zo blijft de spijker
 * staan terwijl de plaat eraan zwaait, en zo kunnen de twee bewegingen elk hun
 * eigen duur hebben: de vlucht op --duration-reveal, het rechtzwaaien bij hover
 * op --duration-base. In één transform zou de tweede de eerste overschrijven,
 * want transition is een shorthand.
 */
.spat {
	position: relative;
}

/* De kop van de spijker, boven de plaat. */
.spat::before {
	content: '';
	position: absolute;
	left: 0.8rem;
	top: 0.8rem;
	z-index: 2;
	width: 7px;
	height: 7px;
	border-radius: var(--radius-pill);
	background-color: color-mix(in srgb, var(--color-white) 38%, transparent);
	box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.55);
}

.spat__tekst {
	position: relative;
	z-index: 1;
	display: block;
	padding: 0.7rem 1.1rem 0.7rem 2rem;
	border: 1px solid color-mix(in srgb, var(--color-white) 18%, transparent);
	background-color: color-mix(in srgb, var(--color-deep) 55%, transparent);
	font-size: var(--text-body);
	line-height: 1.3;
	color: var(--text-on-dark);
	transition:
		transform var(--duration-base) var(--ease-out),
		border-color var(--duration-base) var(--ease-out),
		background-color var(--duration-base) var(--ease-out),
		box-shadow var(--duration-base) var(--ease-out);
}

/*
 * Tot 13 oktober 2026 hing elk plaatje een tot twee graden scheef, in een cyclus
 * van vijf. Julia en Greg vroegen ze rechtop (feedback van 8 oktober, R4).
 */

@media (hover: hover) {

	/*
	 * Aanraken en hij komt iets omhoog. De hover zit op de plaat en niet op de li,
	 * zodat het raakvlak gelijk is aan wat je ziet staan.
	 */
	.spat__tekst:hover {
		transform: translateY(-2px);
		border-color: var(--color-red);
		background-color: color-mix(in srgb, var(--color-deep) 78%, transparent);
		box-shadow: 0 8px 20px rgba(0, 0, 0, 0.45);
	}
}

/* =======================================================================
 * De twee hallen, recht naast elkaar
 *
 * Sinds 13 oktober 2026 recht en naast elkaar, op verzoek van Julia en Greg
 * ("Foto's ook rechtop graag", feedback van 8 oktober). Hieronder de vorm die
 * er tot die dag stond:
 *
 * Ze liggen over elkaar heen als afdrukken op een tafel, met de eerste (de
 * showroom, een wijde opname) bovenop en de detailopname er half achter. Bij
 * hover komt er een naar voren en gaat recht liggen: dezelfde zet als bij de
 * plaatjes hierboven, zodat de sectie één gebaar heeft en niet twee.
 *
 * Het waren er drie tot 11 september 2026, met de middelste bovenop. Sepp haalde
 * de linker eruit; de nth-child-regels hieronder zijn daarop herschreven.
 * ======================================================================= */

.faciliteiten__strook {
	position: relative;
	z-index: 1;
	margin-top: var(--gap-lg);
	display: flex;
	justify-content: center;
	align-items: center;
	gap: var(--gap-md);
}

.strookfoto {
	position: relative;
	margin: 0;
	flex: 0 1 26rem;
	min-width: 0;
	/*
	 * De haarlijn in de schaduw is het randje van een afdruk. Zonder die lijn
	 * lopen twee foto's op een donkere grond in elkaar over en lees je één brede
	 * band in plaats van twee losse opnames; de slagschaduw alleen is daar te
	 * donker voor.
	 */
	box-shadow:
		0 0 0 1px color-mix(in srgb, var(--color-white) 16%, transparent),
		0 16px 44px rgba(0, 0, 0, 0.55);
	transition:
		transform var(--duration-base) var(--ease-out),
		box-shadow var(--duration-base) var(--ease-out);
}

.strookfoto img {
	display: block;
	width: 100%;
	height: auto;
	/*
	 * 16 op 9 is de EIGEN verhouding van deze opnames, allebei 1600x900.
	 * Op 4 op 3 sneed de object-fit een kwart van de zijkanten weg, en dat is bij
	 * een hal precies de ruimte die je wil laten zien. Het scheelt bovendien 90px
	 * sectiehoogte.
	 */
	aspect-ratio: 16 / 9;
	object-fit: cover;
}


@media (hover: hover) {

	/*
	 * Aanraken en hij komt naar voren: hetzelfde gebaar als bij de plaatjes
	 * hierboven, zodat de sectie één beweging heeft en niet twee.
	 */
	.strookfoto:hover {
		transform: translateY(-8px);
		box-shadow:
			0 0 0 1px color-mix(in srgb, var(--color-white) 30%, transparent),
			0 26px 64px rgba(0, 0, 0, 0.65);
	}
}

@media (max-width: 699px) {

	/*
	 * Twee foto's naast elkaar op een telefoon worden twee postzegels. Onder
	 * elkaar, recht.
	 */
	.faciliteiten__strook {
		flex-direction: column;
		align-items: stretch;
		gap: var(--gap-sm);
	}

	.strookfoto {
		flex: 0 1 auto;
	}

}


/* =======================================================================
 * HIER STONDEN TWEE BLOKKEN DIE OP 8 SEPTEMBER 2026 ZIJN VERVALLEN
 *
 * "HET FORMULIER IN TWEE KOLOMMEN" (.form--breed, 18 augustus) legde alleen het
 * huurder-formulier over twee kolommen, vanaf zes velden. Dat zit nu op .form
 * zelf en geldt voor elk formulier, zie het formulierblok hierboven.
 *
 * "DE VELDEN LIJNEN UIT, OOK ALS ER EEN HINTREGEL ONDER EEN LABEL STAAT"
 * (subgrid, 28 augustus) loste Sepps punt op dat alles scheef stond: twee velden
 * naast elkaar waarvan er maar een een hint had, kregen hun invulveld op een
 * andere hoogte, 33 en 59 pixels verschil. Subgrid gaf label, hint en veld elk
 * hun eigen rij.
 *
 * Dat blok is niet stukgegaan maar overbodig geworden: er is geen labelregel en
 * geen hintregel meer om uit te lijnen. Het label ligt in het veld en de hint is
 * de placeholder. Elk veld is nu even hoog, dus ze lijnen uit omdat ze dezelfde
 * maat hebben en niet omdat een raster ze dwingt.
 *
 * De vierde rij van dat subgrid was voor de foutmelding, en die had een echte
 * reden: forms.js doet veld.appendChild( melding ), en zonder eigen rij landde de
 * melding bij een veld MET hint bovenop het invulveld, gemeten op exact dezelfde
 * top van 836px. Ook dat is weg: .field is weer een gewone flexkolom met nog maar
 * twee kinderen in de flow, het veld en de melding eronder.
 * ======================================================================= */

/* =======================================================================
 * DE TOESTEMMINGSSTROOK
 *
 * Een strook onder aan het scherm, geen venster met een waas eroverheen. Dat is
 * geen smaakkwestie: een melding die de pagina afsluit tot je kiest is een
 * cookiemuur, en die mag in Nederland niet. De bezoeker moet gewoon door kunnen
 * lezen en later beslissen.
 *
 * De twee knoppen dragen bewust bestaande klassen, .btn--ghost en .btn--primary,
 * met dezelfde maat en hetzelfde raakvlak. Weigeren staat vooraan in de DOM en
 * krijgt dus ook als eerste de focus. Een weigerknop die kleiner of grijzer is
 * maakt de toestemming ongeldig, en dat is de meest gemaakte fout in dit soort
 * stroken.
 * ======================================================================= */

.consent {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: var(--z-consent);
	background-color: var(--color-deep);
	border-top: 1px solid color-mix(in srgb, var(--color-white) 15%, transparent);
	padding: var(--gap-sm) var(--container-px);
	color: var(--text-on-dark);
	/* Ruststand: net onder de rand, zodat hij binnenschuift in plaats van te knallen. */
	transform: translateY(100%);
	transition: transform var(--duration-base) var(--ease-out);
}

.consent.is-open { transform: translateY(0); }

/* Wie beweging vermijdt krijgt hem gewoon op zijn plek. */
@media (prefers-reduced-motion: reduce) {
	.consent { transition: none; }
}

/*
 * Zonder JavaScript geen strook.
 *
 * De knoppen leggen de keuze vast met een script, dus zonder script kan er niets
 * gekozen worden en blijft de strook staan waar hij staat: op 390px is dat 246px
 * die niet weg te klikken is, gemeten. En de vraag heeft daar sowieso geen doel,
 * want de poort in PHP laat zonder geldige keuze niets door, dus er wordt bij deze
 * bezoeker toch al niet gemeten. Een vraag stellen aan iemand die niet kan
 * antwoorden is alleen maar in de weg staan.
 *
 * Dezelfde media-query als bij de scroll-onthulling in base.css.
 */
@media (scripting: none) {
	.consent { display: none; }
}

.consent__inner {
	max-width: var(--container);
	margin-inline: auto;
	display: flex;
	flex-direction: column;
	gap: var(--gap-sm);
}

.consent__tekst {
	font-size: var(--text-body-sm);
	margin: 0;
	max-width: 60ch;
}

.consent__acties {
	display: flex;
	flex-wrap: wrap;
	gap: var(--gap-xs);
}

/*
 * De knoppen even breed, zodat geen van beide de makkelijkste is, en smal genoeg
 * om op 390px naast elkaar te passen. Op 12rem stapelden ze en werd de strook 327px
 * hoog; met 8rem staan ze naast elkaar en scheelt dat de helft.
 */
.consent__acties .btn { flex: 1 1 8rem; }

/* Exact even breed, zodat ook de maat geen van beide voortrekt. */
.consent__acties .btn { min-width: 0; }

@media (min-width: 700px) {

	.consent__inner {
		flex-direction: row;
		align-items: center;
		justify-content: space-between;
		gap: var(--gap-md);
	}

	.consent__acties { flex: 0 0 auto; }
	.consent__acties .btn { flex: 0 0 auto; }
}

/*
 * De zwevende besturing wijkt voor de strook.
 *
 * Onder 900px staan de menuknop en de bezoek-pil vast in de onderhoeken, precies
 * waar de strook komt. Zonder deze regel liggen ze eronder en is de menuknop niet
 * meer te raken; gemeten op 390px met elementFromPoint, negen punten op nul vrij.
 *
 * De verschuiving hangt aan --consent-hoogte, en die zet consent.js met een
 * ResizeObserver op de echte hoogte van de strook. Eerst stond hier een vaste 11rem
 * als schatting, en die was fout: de strook was 327px en de knoppen schoven 200px,
 * dus ze bleven eronder liggen. Een maat die van de inhoud afhangt hoort niet
 * geraden te worden.
 *
 * De terugval van 0px is bewust: laadt het script niet, dan is er ook geen strook
 * die opengaat, want die krijgt zijn is-open van PHP alleen als er iets te vragen
 * valt. Dan hoeft er niets te wijken.
 */
@media (max-width: 899px) {

	body:has(.consent.is-open) .menu-toggle,
	body:has(.consent.is-open) .visit-cta {
		bottom: calc( var(--container-px) + var(--consent-hoogte, 0px) );
		transition: bottom var(--duration-base) var(--ease-out);
	}
}


/* =======================================================================
 * De luchtfoto-sectie
 *
 * Het beeld leunt volledig op .frame, dat de 4:3-verhouding, de radius, de
 * schaduw en het onderverloop al draagt. Er komt hier dus geen tweede sluier
 * bovenop: dat verloop van .frame::after bestaat juist om een bijschrift onderop
 * leesbaar te houden.
 *
 * Het bordje linksonder op de foto is op 13 oktober 2026 vervallen.
 * Het bordje staat LINKSONDER. Rechtsonder zou rijmen met de hero van deze
 * pagina, die zijn museumbordje daar heeft staan; de tijdlijn maakt dezelfde
 * keuze om dezelfde reden.
 * ======================================================================= */

.luchtfoto__beeld {
	margin: 0;
}



/* =======================================================================
 * De videosectie, met de facade ervoor
 *
 * FULLSCREEN SINDS 28 AUGUSTUS 2026, na het gesprek met Greg. Het vlak stond
 * begrensd op 46rem in het midden met een kop erboven; het is nu precies één
 * schermhoogte, zonder kop en zonder sectie-padding.
 *
 * Dat maakt de schermhoogte-eis van meet.mjs niet losser maar strakker: de
 * sectie raakt de grens in plaats van eronder te blijven. Alles wat er stond
 * moest daarom NAAR BINNEN. Het label lag al over het beeld; de AVG-regel stond
 * eronder en ligt er nu ook overheen. Zet hier nooit iets buiten het beeld bij,
 * want elke pixel eronder duwt de sectie er direct overheen.
 *
 * De .frame-behandeling is eraf. Die maakt van een beeld een voorwerp op een
 * tafel: afgeronde hoek, slagschaduw, 16:9-kader. Een film die het hele scherm
 * vult is geen voorwerp op een tafel. Het onderverloop van .frame::after is wél
 * overgenomen, want dat droeg de leesbaarheid van het label en die eis blijft.
 *
 * De hover zit achter @media (hover: hover) en de focus-ring er nadrukkelijk
 * BUITEN. Op een tapscherm blijft een hover-stand anders hangen na een tik, en
 * wie de twee in één regel zet haalt de toetsenbordfocus van elk touch-apparaat
 * weg. Zie todo 8ab2f1f1, die dit voor de overige 34 hover-regels nog moet doen.
 * ======================================================================= */

.video--vol {
	position: relative;
	min-height: 100vh;
	/* dvh voor mobiel, waar de browserbalk in- en uitschuift. Zelfde paar als .hero--home. */
	min-height: 100dvh;
	overflow: hidden;
	isolation: isolate;
}

.video__start {
	position: absolute;
	inset: 0;
	display: block;
	color: inherit;
	text-decoration: none;
}

.video__start img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform var(--duration-image) var(--ease-out);
}

/*
 * Het onderverloop dat .frame::after leverde toen dit vlak nog een kader had.
 * Het label en de AVG-regel liggen allebei in de onderste strook, en de poster is
 * daar niet gegarandeerd donker.
 */
.video__start::after {
	content: '';
	position: absolute;
	inset: auto 0 0 0;
	height: 40%;
	background: linear-gradient(to top, var(--scrim-onder), transparent);
	pointer-events: none;
}

/* De afspeelknop. Donkere schijf met een witte rand, zodat hij op elk beeld
 * leest; het rood komt pas bij hover en draagt daar geen informatie. */
.video__knop {
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	z-index: var(--z-base);
	display: flex;
	align-items: center;
	justify-content: center;
	width: var(--touch-min);
	height: var(--touch-min);
	border: 2px solid var(--color-white);
	border-radius: var(--radius-pill);
	background-color: var(--overlay-cta);
	color: var(--color-white);
	transition:
		background-color var(--duration-base) var(--ease-out),
		transform var(--duration-base) var(--ease-out);
}

.video__knop svg {
	width: 45%;
	height: 45%;
	margin-left: 6%; /* optisch midden: een driehoek weegt naar links */
}

/*
 * Het label draagt de naam van de link, dus het moet leesbaar zijn en niet alleen
 * mooi. Wit op het kale beeld haalde 4,08:1 op 1512 en 4,12:1 op 1920, bij een eis
 * van 4,5. Het onderverloop van .frame::after is daar niet genoeg, want de poster
 * is een luchtfoto met lichte daken op precies die plek.
 *
 * Daarom een eigen plaat, dezelfde oplossing die .beeldbijschrift tot 13 oktober had. Wel
 * ZONDER de rode linkerrand: die is het signaal van het museumbordje en dit is een
 * knop-naam, geen bijschrift.
 */
.video__label {
	position: absolute;
	left: var(--container-px);
	bottom: var(--container-px);
	z-index: var(--z-base);
	max-width: 22rem;
	padding: 0.5rem 0.75rem;
	background-color: var(--overlay-cta);
	font-size: var(--text-body-sm);
	font-weight: var(--weight-medium);
	letter-spacing: var(--tracking-widest);
	text-transform: uppercase;
	color: var(--color-white);
}

/*
 * Onder 768px is het kader 342px breed en had het label geen rechter anker, terwijl
 * --container-px op mobiel niet meekrimpt. Het label mat daar 310px en de tekst komt
 * uit de leeslaag, dus een iets langere titel van Greg liep het kader uit en werd door
 * overflow: hidden van .frame afgesneden. Dezelfde regel die .beeldbijschrift had.
 */
@media (max-width: 767px) {

	.video__label {
		left: var(--gap-xs);
		right: var(--gap-xs);
		bottom: var(--gap-xs);
		max-width: none;
	}
}

/*
 * De AVG-regel ligt over het beeld, rechtsonder, tegenover het label linksonder.
 * Hij stond eronder met een margin-top, en onder het beeld is er op een sectie van
 * precies één schermhoogte niets meer.
 *
 * Zelfde plaat als het label en ook wit, niet gedempt. Dit is de regel die de klik
 * tot geïnformeerde toestemming maakt, dus hij moet leesbaar zijn en niet
 * bescheiden. Het onderscheid met het label komt van de vorm: dat is uppercase met
 * brede spatiëring, dit is een gewone zin.
 *
 * De grond-varianten die hier stonden (.section-light, .section-brick-light) zijn
 * weg: deze regel ligt nooit meer op de sectiegrond, altijd op de plaat.
 */
.video__avg {
	position: absolute;
	right: var(--container-px);
	bottom: var(--container-px);
	z-index: var(--z-base);
	max-width: 26rem;
	margin: 0;
	padding: 0.5rem 0.75rem;
	background-color: var(--overlay-cta);
	font-size: var(--text-body-sm);
	line-height: var(--leading-normal);
	color: var(--color-white);
	text-align: right;
}

/*
 * Onder 768px passen twee platen niet naast elkaar. Ze stapelen dan linksonder,
 * de AVG-regel onder het label, allebei over de volle breedte. Zelfde anker als
 * het label daar al gebruikt.
 */
@media (max-width: 767px) {

	.video__avg {
		left: var(--gap-xs);
		right: var(--gap-xs);
		bottom: var(--gap-xs);
		max-width: none;
		text-align: left;
	}

	.video__label {
		bottom: calc( var(--gap-xs) + 5.5rem );
	}
}

/* De speler die video.js op de plek van de facade zet. */
.video--vol .video__speler {
	position: absolute;
	inset: 0;
	/* De frame-klassen die video.js meegeeft dragen 16:9 en een kader; hier vult hij. */
	aspect-ratio: auto;
	border-radius: 0;
	box-shadow: none;
}

.video__speler iframe {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	border: 0;
}

@media (min-width: 768px) {

	.video__knop {
		width: var(--touch-lg);
		height: var(--touch-lg);
	}
}

@media (hover: hover) {

	.video__start:hover .video__knop {
		background-color: var(--color-red);
		transform: translate(-50%, -50%) scale(var(--knop-zoom));
	}

	.video__start:hover img {
		transform: scale(var(--image-zoom));
	}
}

@media (prefers-reduced-motion: reduce) {

	.video__start img,
	.video__knop {
		transition: none;
	}

	.video__start:hover img {
		transform: none;
	}
}

/* =======================================================================
 * De kaartsectie, met de facade ervoor
 *
 * Zelfde opzet als de videosectie en om dezelfde reden: zolang de bezoeker niet
 * klikt staat er geen iframe in de pagina en gaat er geen byte naar Google. De
 * facade draagt de entree van het terrein, niet een uitsnede van een kaart: een
 * kaart-screenshot belooft de kaart die er nog niet is, en de entree doet werk dat
 * de kaart niet doet, namelijk het pand herkenbaar maken bij aankomst.
 *
 * Het paneel ligt IN het kader en niet eronder. Reden: .frame draagt
 * overflow: hidden, dus alles wat eronder zou staan valt buiten beeld of dwingt
 * een tweede blok af. Gevolg is dat de kader-verhouding ruim genoeg moet zijn om
 * het paneel te dragen, en dat is precies waarom hij op mobiel kantelt naar 4:5.
 * ======================================================================= */

.kaart__kop {
	margin-bottom: var(--gap-md);
}

/*
 * DE VERHOUDING IS EEN MEETUITKOMST EN GEEN SMAAK.
 *
 * Op .frame--wide (16:9) werd de sectie 1043px hoog en zakte hij op 1440x900 en op
 * 1512x765, de krapste van de vier gemeten breedtes. De rekensom op 1512x765:
 * sectie-padding 160 (--section-sm, twee kanten) plus de kop 110 plus de AVG-regel
 * 28 is 298 vast, dus het kader mag 467px. Bij een container van 1232 is dat een
 * verhouding van 2,6:1 of wijder.
 *
 * Op 3:1 wordt het kader 411px en de sectie 709px, dus 56px marge. Dat is bewust
 * ruimer dan strikt nodig: de kop komt uit de leeslaag, en één langere titel van
 * Greg mag de sectie niet over de rand duwen. Dat is precies de fout die de
 * videosectie op 48rem maakte, met vijftien pixels over.
 *
 * Een brede strook past bovendien bij wat het is. Een kaart is een strook langs een
 * kanaal, geen vierkant portret, en het maakt deze sectie meteen anders van vorm
 * dan de luchtfoto (twee kolommen) en de video (volledig scherm).
 */
.kaart__vlak {
	position: relative;
	aspect-ratio: 3 / 1;
}

/*
 * Onder 768 stond hier een tweede vaste verhouding, 4 / 5, en dat gaf de hardste
 * sprong van de hele site: op 767 was het kader 890px hoog en op 768 nog 238px,
 * 652px verschil op een pixel vensterbreedte. Gemeten op /route/ en /contact/ op
 * 8 september 2026, en op allebei was het de grootste sprong van de pagina.
 *
 * Een verhouding kan niet vloeien, een hoogte wel. Daarom stuurt onder 768 de
 * hoogte en niet de verhouding: 27rem (432px) op 390, aflopend tot 15rem (240px)
 * op 767, en dat is precies wat 3 / 1 op 768 oplevert. De sprong is daarmee 2px.
 *
 * De twee grenzen komen uit dezelfde eis als de oude 4 / 5: op 390 moet het paneel
 * met het adres en de twee knoppen in het kader passen. Dat is 433px, en dat is de
 * bovengrens. `object-fit: cover` op .frame img vangt de wisselende uitsnede op.
 */
@media (max-width: 767px) {
	.kaart__vlak {
		aspect-ratio: auto;
		height: clamp(15rem, 39.6rem - 51.7vw, 27rem);
	}
}

/* Het paneel met het adres en de twee uitgangen, op dezelfde plaat als het
   videolabel zodat het op elke foto leesbaar blijft. */
.kaart__paneel {
	position: absolute;
	left: var(--container-px);
	bottom: var(--container-px);
	z-index: var(--z-base);
	max-width: 26rem;
	padding: var(--gap-xs) 0.75rem 0.75rem;
	background-color: var(--overlay-cta);
}

.kaart__adres {
	margin: 0 0 var(--gap-xs);
	font-family: var(--font-serif);
	font-size: var(--text-body-lg);
	line-height: var(--leading-snug);
	color: var(--color-white);
}

.kaart__acties {
	display: flex;
	flex-wrap: wrap;
	gap: var(--gap-xs);
	margin: 0;
}

/*
 * De AVG-regel staat BUITEN het kader, anders dan bij de video. Daar moest hij
 * naar binnen omdat die sectie precies één schermhoogte is; deze sectie heeft
 * gewone sectie-padding en dan is eronder de rustiger plek.
 */
.kaart__avg {
	margin-top: var(--gap-xs);
	font-size: var(--text-body-sm);
	line-height: var(--leading-normal);
	color: var(--text-on-dark-muted);
}

.section-light .kaart__avg,
.section-brick-light .kaart__avg {
	color: var(--text-on-light-muted);
}

/* De kaart die kaart.js op de plek van de facade zet. */
.kaart__vlak--live iframe {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	border: 0;
}

@media (max-width: 767px) {

	.kaart__paneel {
		left: var(--gap-xs);
		right: var(--gap-xs);
		bottom: var(--gap-xs);
		max-width: none;
	}

	/* Twee knoppen naast elkaar passen niet op 342px. */
	.kaart__acties .btn {
		width: 100%;
		justify-content: space-between;
	}
}

/* =======================================================================
 * De reistijden op de routepagina
 *
 * Deze sectie rendert vandaag niets, want de rijen zijn leeg en dat is met opzet:
 * een reistijd zonder bron is een verzonnen feit. Zie de docblock van
 * template-parts/sections/section-reizen.php. De opmaak staat er wel, zodat hij
 * klopt op het moment dat de getallen er zijn.
 *
 * Vorm overgenomen van .praktisch__lijst: een feit per regel op een haarlijn.
 * Dat is de vorm die op Bezoekers al is gekozen en gemeten, en twee lijsten met
 * praktische gegevens op één pagina horen er hetzelfde uit te zien.
 * ======================================================================= */

.reizen__lijst {
	margin: 0;
	padding: 0;
	list-style: none;
}

/*
 * --border-light en niet --border-dark: deze sectie staat op section-shadow, dus
 * op donkere grond. .praktisch__rij gebruikt de andere omdat hij op lichte
 * baksteen staat. De twee zijn niet uitwisselbaar en er is geen sectie-scoped
 * alias die ze omklapt, dus dit hoort per component gekozen te worden.
 */
.reizen__rij {
	display: grid;
	gap: 0.5rem var(--gap-lg);
	padding-block: var(--gap-md);
	border-bottom: 1px solid var(--border-light);
}

.reizen__wijze {
	margin: 0;
	font-family: var(--font-sans);
	font-size: var(--text-label);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-widest);
	text-transform: uppercase;
}

.reizen__tijd {
	margin: 0;
	font-family: var(--font-serif);
	font-size: var(--text-body-lg);
	line-height: var(--leading-snug);
}

.reizen__toelichting {
	margin: 0;
	font-size: var(--text-body-sm);
}

@media (min-width: 768px) {

	.reizen__rij {
		grid-template-columns: 14rem 10rem minmax(0, 1fr);
		align-items: baseline;
	}
}

/* ==========================================================================
   Etalage: het terrein nu, in wisselende maten onder elkaar
   Sinds 28 augustus 2026 als horizontale galerij, herbouwd op 1 september 2026.
   ========================================================================== */

/*
 * DIT WAS EEN HORIZONTALE BAND EN HET IS NU EEN VERTICAAL RASTER.
 *
 * Tot 1 september 2026 stond hier de generieke `.band` met zes tegels van gelijke
 * hoogte, hetzelfde script als de bedrijvenrij erboven. Sepp: "ik heb liever dat we
 * een soort van grote etalages sectie maken met allemaal foto's die in verschillende
 * groottes allemaal zo mooi in elkaar vallen met een gaaf scroll effect", en gevraagd
 * naar de richting van dat effect: naar beneden.
 *
 * De oude opzet had een probleem dat de vorige ronde alleen kosmetisch had opgelost.
 * Bezoekers draagt de rondgang, en dat is al een horizontale band met pijlen. Direct
 * daaronder een tweede horizontale band betekent dezelfde beweging twee keer. Een
 * eigen kop, meer lucht en andere tegelbreedtes veranderen daar niets aan, want het
 * bezwaar zat in de vorm. Verticaal is dus niet de smaakkeuze maar het structurele
 * verschil met de sectie erboven.
 *
 * Het mechanisme komt van koto.studio/work, live gelezen op 1 september 2026:
 * twee kolommen van gelijke breedte, gap 8,89px op een raster van 1495px, en per
 * tegel een EXPLICIETE `grid-column-start` plus `grid-row-start` via een custom
 * property. De gemeten posities daar (kolom 1 op 18 met hoogte 932, kolom 2 op 18
 * met 446, kolom 2 op 473 met 930, kolom 1 op 958 met 558) bewijzen dat het een
 * geschreven compositie is en geen masonry: de tweede tegel in kolom 2 begint exact
 * onder de eerste, niet waar een pakker hem zou leggen.
 *
 * Wat we van Koto NIET overnemen: de radius van 16px (hier geldt de radius-schaal van
 * het brandbook, en ingelijst beeld is 4px), de witte grond, en de hover waarbij de
 * tegel een titel over de foto legt. Onze bijschriften staan eronder.
 *
 * DE REKENEENHEID. Twee kolommen, en de rijhoogte is een tweeënzeventigste van de
 * kolombreedte. Dat is het kleinste getal waarbij alle vier de vormen op een heel
 * aantal rijen uitkomen: panorama 2:1 is 36 rijen, liggend 3:2 is 48, vierkant 1:1
 * is 72 en staand 4:5 is 90. Eén rij extra tussen twee tegels in dezelfde kolom is
 * de voeg, en die is per constructie precies even breed als de kolomvoeg:
 *
 *   voeg V, rasterbreedte W, kolombreedte K = (W - V) / 2, rijhoogte R = K / 72.
 *   Wil je R gelijk aan V, dan is 144V = W - V, dus V = W / 145.
 *
 * Vandaar de 145 hieronder. Op een raster van 1232px is dat 8,5px, en dat ligt in
 * dezelfde orde als de 8,89 van de referentie.
 *
 * WAAROM CONTAINER QUERY UNITS EN NIET VW. De voeg moet aan de RASTERbreedte hangen,
 * niet aan de vensterbreedte: `100vw` telt op Windows de scrollbalk mee, en dan klopt
 * de rijhoogte een fractie niet. Over de 293 rijen die de langste kolom hier telt
 * loopt zo'n fractie op tot een zichtbaar gat. `100cqw` op een houder binnen de
 * container is exact.
 *
 * DE TEGEL IS DE FOTO EN VERDER NIETS, en dat is een meting geweest. De eerste versie
 * had een bijschrift onder elke foto, zoals de galerij die hier stond. Omdat de span
 * vastligt gaat die regel van de FOTO af, en dan klopt precies datgene niet meer waar
 * deze sectie om draait: gemeten op 1 september 2026 werd een panorama 2,22:1 op 1440,
 * 2,29 op 1024 en 2,75 op 768, in plaats van 2:1. Elf tot zevenendertig procent
 * hoogte weggesneden. De onderbouwing van die keuze staat in section-etalage.php; wat
 * beschreven moet worden staat nu in de alt-tekst.
 */

/*
 * De houder draagt de containment. Een element kan zijn eigen container niet
 * bevragen, dus dit kan niet op het raster zelf staan, en `.container` is site-breed.
 */
.etalage__houder {
	container-type: inline-size;
}

/*
 * Mobiel eerst: één kolom, gewone lucht ertussen, en de vorm van de tegel bepaalt
 * zijn eigen hoogte. De drie custom properties uit het style-attribuut doen hier
 * niets, en dat is de bedoeling.
 */
.etalage__raster {
	display: grid;
	gap: var(--gap-sm);
}

.etalage__tegel {
	margin: 0;
}

/*
 * De vier vormen. Ze staan alle vier in het brandbook (paragraaf 7.3), op panorama
 * na, en die verhouding gebruikt de site al voor de muurschildering. Er is dus geen
 * verhouding verzonnen. De rij-aantallen die erbij horen staan in section-etalage.php.
 */
.etalage__tegel--panorama { --tegel-ratio: 2 / 1; }
.etalage__tegel--liggend  { --tegel-ratio: 3 / 2; }
.etalage__tegel--vierkant { --tegel-ratio: 1 / 1; }
.etalage__tegel--staand   { --tegel-ratio: 4 / 5; }

/*
 * De 4:3 van .frame moet hier weg, anders snijdt de tegel elk beeld een tweede keer
 * bij, boven op de uitsnede die het al heeft.
 */
.etalage__vlak {
	aspect-ratio: var(--tegel-ratio, 3 / 2);
}

/*
 * Geen onderverloop. Dat verloop van .frame::after bestaat om een bijschrift ÓP een
 * foto leesbaar te houden, en hier staat het bijschrift eronder. Het dempte dus
 * precies de foto's die deze sectie moet laten zien, over de onderste 40 procent.
 */
.etalage__vlak::after {
	content: none;
}

/*
 * Het enige hover-effect, en met opzet geen transform. De parallax hieronder zit op
 * de img zelf, en `transition` en `animation` op dezelfde eigenschap van hetzelfde
 * element vechten om de transform. Helderheid raakt daar niets van, en de tegel gaat
 * niet uitzetten over de voeg van acht pixels heen.
 */
.etalage__vlak img {
	transition: filter var(--duration-image) var(--ease-out);
}

@media (hover: hover) {

	.etalage__tegel:hover .etalage__vlak img {
		filter: brightness(1.08);
	}
}

/* Vanaf tablet het echte raster. Zie de bestandskop voor de rekeneenheid. */
@media (min-width: 768px) {

	.etalage__raster {
		--etalage-voeg: calc(100cqw / 145);

		grid-template-columns: repeat(2, minmax(0, 1fr));
		grid-auto-rows: var(--etalage-voeg);
		column-gap: var(--etalage-voeg);

		/*
		 * Nul, want de voeg tussen twee tegels in dezelfde kolom is een lege RIJ en
		 * geen gap. Met een row-gap erbij zou elke gereserveerde rij die gap er nog
		 * eens bij optellen en zouden de twee kolommen uit de pas lopen: kolom 1
		 * telt hier 293 rijen en kolom 2 telt er 307.
		 */
		row-gap: 0;
	}

	.etalage__tegel {
		grid-column: var(--tegel-kolom);
		grid-row: var(--tegel-rij) / span var(--tegel-hoog);
	}

	/*
	 * De span bepaalt de hoogte en niet de verhouding, want de span IS de verhouding:
	 * 36 rijen op een kolom van 72 is 2:1, 48 is 3:2, 72 is 1:1 en 90 is 4:5. Twee
	 * keer dezelfde vorm opleggen levert alleen een subpixelverschil op.
	 */
	.etalage__vlak {
		aspect-ratio: auto;
		height: 100%;
	}
}

/*
 * HET SCROLL-EFFECT, EN WAAROM HET UIT TWEE DELEN BESTAAT.
 *
 * De onthulling per tegel doet de bestaande waarnemer in scroll-animations.js: elke
 * tegel draagt `.reveal` en komt met de stagger van 80ms omhoog. Die werkt overal,
 * heeft een failsafe, en laat het element daarna los.
 *
 * Daar bovenop ligt een doorlopende parallax op de foto zelf. Dat is het effect dat
 * Sepp bedoelde met "naar beneden": het beeld schuift trager dan de pagina, dus je
 * kijkt tijdens het scrollen over de foto heen. Het staat op de img en niet op de
 * tegel, zodat het de transform van .reveal niet overschrijft.
 *
 * `animation-timeline: view()` is de enige scroll-gedreven vorm die zonder JavaScript
 * naar niets degradeert: valt de ondersteuning weg, dan staat de foto stil en is er
 * verder niets kapot. Het thema gebruikt `:has()` en `color-mix()` al zonder vangnet,
 * dus de browservloer is er.
 *
 * Let op de volgorde van de drie regels: de shorthand `animation` reset zowel
 * `animation-timeline` als `animation-range`, dus die twee moeten erna staan.
 *
 * Achter `no-preference` en niet achter een reduce-uitzondering, want de globale
 * regel in base.css zet `animation-duration` op 0,01ms en wat dat doet met een
 * voortgangs-tijdlijn is niet gedefinieerd. Niet aanzetten is hier het enige
 * antwoord dat zeker klopt.
 */
@supports (animation-timeline: view()) {

	@media (prefers-reduced-motion: no-preference) {

		/*
		 * DE TIJDLIJN HANGT AAN DE TEGEL EN NIET AAN DE FOTO, EN DAT MOET OOK.
		 *
		 * Met een kaal `animation-timeline: view()` op de img stond de parallax stil.
		 * Gemeten op 1 september 2026 met getAnimations(): de ViewTimeline bestond, de
		 * animatie stond op `running`, en de voortgang bleef op 0,4717 staan op elke
		 * scrollpositie.
		 *
		 * De oorzaak is `overflow: hidden` op .frame. Dat maakt van het beeldvlak een
		 * scroll-container in de zin van de specificatie, ook al scrollt er nooit iets
		 * in, en `view()` pakt de dichtstbijzijnde scroll-voorouder. De foto werd dus
		 * afgezet tegen een doos die zelf niet beweegt.
		 *
		 * Een benoemde tijdlijn op de tegel lost dat op: die staat buiten de
		 * overflow, dus zijn scroll-voorouder is de pagina. Een benoemde tijdlijn is
		 * zichtbaar voor het element zelf en zijn nakomelingen, dus de img eronder
		 * vindt hem. Elke tegel krijgt zo zijn eigen timeline; de naam mag hetzelfde
		 * zijn omdat de img altijd de dichtstbijzijnde pakt.
		 */
		.etalage__tegel {
			view-timeline: --etalage-zicht block;
		}

		.etalage__vlak img {
			/*
			 * Twaalf procent hoger dan zijn vak. Dat overschot is precies de afstand
			 * die de foto kan afleggen; groter maakt het een effect in plaats van
			 * een detail, en het kost dan ook zichtbaar meer van de foto.
			 */
			height: 112%;

			animation: etalage-zak linear both;
			animation-timeline: --etalage-zicht;
			animation-range: cover 0% cover 100%;
		}
	}

	/*
	 * Van onderkant-uitgelijnd naar bovenkant-uitgelijnd. Scroll je naar beneden, dan
	 * gaat de tegel omhoog en de foto binnen die tegel omlaag, en dat verschil is de
	 * parallax. 10,71 procent van de foto is 12 procent van het vak.
	 */
	@keyframes etalage-zak {

		from {
			transform: translateY(-10.71%);
		}

		to {
			transform: translateY(0);
		}
	}
}

/* ==========================================================================
   Onderweg: de drie dingen die je tegenkomt, als genummerde stops op de lijn
   Sinds 28 augustus 2026 op de wandelroute-pagina, herzien op 1 september 2026.
   ========================================================================== */

/*
 * DIT WAS EEN GESTIPPELDE LIJST EN HET IS NU HET TIJDLIJN-IDIOOM VAN HISTORIE.
 *
 * Greg, 1 september 2026: "bij de wandelroute-pagina vind ik die teaser nog erg
 * slecht, ik wil daar iets meer foto's of wat dan ook. Misschien kunnen we wel
 * hetzelfde design gebruiken als op de historie pagina, dat we op die manier met een
 * scroll effect zo het wandelpad uitleggen en zo kunnen teasen met foto's ook."
 *
 * De sectie draagt daarom .tijdlijn en .halte, precies zoals section-tijdlijn.php,
 * en erft daarmee de lijn die zich tekent, de bol die rood kleurt bij .is-actief en
 * de stencil van het jaartal. Onderbouwing en gemeten waarden van dat patroon staan
 * in ux-onderzoek/steal-sheet-tijdlijn.md, met de afwijkingen van deze variant in de
 * addendum-sectie daaronder.
 *
 * ALLES WAT DEZE VARIANT ANDERS DOET STAAT ONDER .pad, EN DAT IS GEEN NETHEID.
 * .tijdlijn, .halte, .halte__jaar, .halte__bol en .halte__merk staan KAAL in dit
 * bestand, niet genest onder een pagina- of sectieklasse. Eén regel hier zonder
 * scope en de tuning voor "01" verandert "1934" op Historie, waar de haltes de
 * archieffoto's en de familiegeschiedenis dragen. Vandaar de eigen klasse op de
 * container, en nul wijzigingen aan de basisregels hierboven.
 *
 * De variant gaat uit van een DONKERE grond, net als de tijdlijn zelf: het spoor
 * staat op rgba(245,242,237,0.28) en de stencil op een lichte stroke. Op de
 * wandelroute-pagina is dat section-shadow. Wie hem ooit op licht zet, moet die twee
 * kleuren per grond regelen; dat is niet gebouwd omdat niets erom vraagt.
 */

/*
 * Een stop is een regel plus eventueel een foto, en geen halte met twee alinea's.
 * De verticale maat zakt daarom een stap ten opzichte van Historie. Eerste en
 * laatste expliciet erbij: .halte:first-of-type is even specifiek als .pad .halte en
 * staat eerder in het bestand, dus zonder deze twee regels zou de eerste stop zijn
 * bovenmarge terugkrijgen terwijl zijn bol op nul blijft staan.
 */
.pad .halte { padding-block: var(--gap-md); }
.pad .halte:first-of-type { padding-top: 0; }
.pad .halte:last-of-type { padding-bottom: 0; }

.pad .halte__merk { top: var(--gap-md); }
.pad .halte:first-of-type .halte__merk { top: 0; }

/*
 * Het volgnummer draagt .halte__jaar, dus het IS dezelfde stencil, inclusief de
 * overgang naar vol wit bij .is-actief. Deze regel voegt alleen toe wat twee glyphs
 * anders nodig hebben dan vier: de stencil is afgestemd op 1934 en trekt "01" tot
 * een samengeklonken paar.
 */
.pad .halte__nummer { letter-spacing: var(--tracking-wide); }

/*
 * De kop is hier een zin van Julia en geen titel van ons. De langste telt 23 woorden
 * ("Plekken die een belangrijke rol speelden in het verleden van Leon Kalfus & Zoon
 * en de Tilburgse textielrecyclingindustrie"), en die op --text-h2-large met een
 * maat van 24ch zetten levert een blok van zes regels display-serif dat de foto
 * eronder van de pagina duwt. Een stap kleiner en een stap breder.
 */
.pad .halte__titel {
	font-size: var(--text-h3);
	max-width: var(--container-narrow);
}

/* Zonder foto sluit de stop direct af; er hoort geen lucht te staan waar niets is. */
.pad .halte--zonder-beeld .halte__titel { margin-bottom: 0; }

/*
 * De uitnodiging onder de stops. Gestapeld op mobiel, naast elkaar vanaf 768px: de
 * vraag en het antwoord horen bij elkaar en lezen dan als één regel.
 */
.onderweg__slot {
	display: grid;
	justify-items: start;
	gap: var(--gap-xs);
	margin-top: var(--gap-lg);
}

.onderweg__vraag {
	margin: 0;
	font-size: var(--text-body-lg);
}

@media (min-width: 768px) {

	.onderweg__slot {
		display: flex;
		align-items: center;
		gap: var(--gap-sm);
	}
}


/* ==========================================================================
   De wandelroute in cijfers

   Vier feiten naast elkaar, elk op een haarlijn met het rode streepje ervoor.
   Dat is bewust dezelfde taal als .praktisch__rij en .eyebrow: op deze pagina
   staan drie secties met feiten (deze, wat je onderweg tegenkomt, en het
   praktische blok) en die horen als één familie te lezen.

   Rood draagt hier geen tekst en ook geen betekenis, het is het streepje.
   #b22222 haalt op de lichte grond 5,8:1, maar dat doet er niet toe zolang
   het decoratie blijft; zie de contrastnoot in website/CLAUDE.md.
   ========================================================================== */

.routefeiten__kop {
	font-family: var(--font-serif);
	font-size: var(--text-h3);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-normal);
	line-height: var(--leading-normal);
	margin: 0 0 var(--gap-md);
}

.routefeiten__lijst {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--gap-sm) var(--gap-md);
	grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* Vanaf 768px passen de vier op één regel en leest de strip als één zin. */
@media (min-width: 768px) {
	.routefeiten__lijst { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.routefeiten__feit {
	border-top: 1px solid var(--border-dark);
	padding-top: var(--gap-xs);
}

/*
 * Het cijfer op --text-h2 en niet op --text-h2-large. "Gratis" is het langste
 * woord dat hier staat en moet op één regel passen in een kolom van een kwart
 * container; op de grote maat breekt dat af op 768px, precies waar de vier
 * naast elkaar komen te staan.
 */
.routefeiten__waarde {
	font-family: var(--font-serif);
	font-size: var(--text-h2);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-tighter);
	line-height: var(--leading-none);
	margin: 0;
}

.routefeiten__label {
	font-family: var(--font-sans);
	font-size: var(--text-body-sm);
	line-height: var(--leading-normal);
	color: var(--text-on-light-muted);
	margin: 0.5rem 0 0;
	display: flex;
	align-items: baseline;
	gap: 0.5rem;
}

.routefeiten__label::before {
	content: "";
	width: 1rem;
	height: 2px;
	background: var(--color-red);
	flex: none;
	transform: translateY(-0.3em);
}

/*
 * De voetnoot draagt het voorbehoud dat Greg zelf bij de dertig minuten zette,
 * plus het aanmelden en het startpunt. Kleiner dan de labels zou hem
 * wegstoppen, want dit is het antwoord op "kan ik zomaar komen".
 */
.routefeiten__noot {
	font-size: var(--text-body);
	line-height: var(--leading-loose);
	color: var(--text-on-light-muted);
	margin: var(--gap-md) 0 0;
}

/* ==========================================================================
   Agenda en nieuws: twee rasters van zes, en de knop eronder
   Agenda sinds 28 augustus 2026, samen met het post type `evenement`.
   Op 9 september 2026 samengevoegd, zie hieronder.
   ========================================================================== */

/*
 * DE TWEE RASTERS ZIJN OP 9 SEPTEMBER 2026 ÉÉN REGEL GEWORDEN.
 *
 * Sepp: "ik vind de cards van nieuws goed. Ik wil eigenlijk dat de cards van agenda
 * er exact hetzelfde uitzien, maar dan met wit." Dat "maar dan met wit" kost geen
 * regel: de agendasectie staat op section-light en `.section-light .card` is daar al
 * wit met --shadow-card. Het enige wat hier gebeurt is dat de agenda ophoudt een
 * eigen raster te hebben.
 *
 * HIER STONDEN TWEE BLOKKEN MET VERSCHILLENDE BREEKPUNTEN, en die reden is met de
 * kaart zelf vervallen: "Drie kolommen pas vanaf 1024 en niet vanaf 768. Een
 * agendakaart draagt vier tot zes regels tekst zonder afkapping, en op 768 is een
 * derde kolom 224px breed: dan breekt 'Open dag op het terrein' over drie regels en
 * staat de kaart hoger dan hij breed is." De agendakaart kapt sinds 9 september af
 * op twintig woorden, precies als de nieuwskaart, dus die extra trede meet niets
 * meer af en zou de twee rasters op tablet juist uit de pas laten lopen.
 *
 * En hier stond nog een blok ouder besluit dat om dezelfde reden vervalt: "Vorm
 * overgenomen van .praktisch__lijst: een item per regel op een haarlijn, geen
 * kaarten. Reden: een evenement is een datum plus twee zinnen, en kaarten om zo
 * weinig inhoud lezen als lege dozen." Dat gold toen er nul evenementen waren en
 * niemand wist hoeveel tekst Greg zou aanleveren. De agenda is inmiddels gevuld.
 */
.agenda__raster,
.nieuws__raster {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--gap-sm);
}

@media (min-width: 768px) {

	.agenda__raster,
	.nieuws__raster { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/*
 * De agenda is een ul en het nieuws een reeks losse links. Dat verschil blijft: een
 * agenda IS een lijst en een schermlezer hoort te horen hoeveel items erin staan.
 * De li is dus alleen een doorgeefluik, en flex zorgt dat de kaart erbinnen de volle
 * celhoogte pakt in plaats van de hoogte van zijn eigen inhoud.
 */
.agenda__raster {
	list-style: none;
	margin: 0;
	padding: 0;
}

.agenda__item { display: flex; }

/*
 * `hidden` moet van display: flex winnen, en dat doet het uit zichzelf niet.
 *
 * `[hidden] { display: none }` staat in de stylesheet van de BROWSER, en elke
 * auteursregel wint daarvan, ook een die minder specifiek lijkt. Zonder deze twee
 * regels staan de items voorbij het plafond er gewoon en doet de knop niets
 * zichtbaars. Precies dezelfde val als bij .band__nav[hidden] hierboven, waar hij
 * op 28 augustus 2026 al een keer is ingelopen.
 */
.agenda__item[hidden],
.card[hidden] { display: none; }

/* ==========================================================================
   DE MEER-KNOP
   Sinds 8 september 2026, zie de kop van template-parts/content/meer.php.
   ========================================================================== */

/*
 * De knop staat gecentreerd onder het raster en niet links eronder. Links leest hij
 * als het volgende item in de eerste kolom; gecentreerd leest hij als de afsluiting
 * van het hele blok, en dat is wat hij is.
 */
.meer {
	display: flex;
	justify-content: center;
	margin-top: var(--gap-md);
}

/*
 * Het opschrift en de pijl zitten sinds 9 september 2026 elk in een eigen span,
 * want meer.js wisselt ze los van elkaar: de tekst verandert, de pijl verdwijnt.
 * Zonder wikkel zou het script in de tekstknopen van de knop moeten graven en
 * daarmee het SVG-element weggooien.
 *
 * De pijl krijgt inline-flex zodat de svg op de basislijn van de tekst blijft staan
 * in plaats van op de regelhoogte van een inline-element te gaan zitten.
 */
.meer__pijl {
	display: inline-flex;
	align-items: center;
}

.meer__pijl[hidden] { display: none; }


/* ==========================================================================
   Goede doelen: de lijst die de klant zelf vult
   Sinds 28 augustus 2026. Leeg tot Greg hem invult, zie de sectie.
   ========================================================================== */

/*
 * Flex en geen grid, en dat is een bewuste ruil.
 *
 * Het aantal logo's is data: Greg vult de lijst zelf en er staan er nu vijf. Met
 * een raster van twee kolommen laat vijf er een alleen achter in de laatste rij,
 * linksuitgelijnd, en dat leest als een fout. Gezien op het contactvel van 8
 * september 2026: op 390 en 600 stond Warandeloop alleen linksonder.
 *
 * Met flex plus justify-content: center centreert elke onvolledige laatste rij
 * zichzelf, bij elk aantal en op elke breedte. De kolombreedtes blijven precies
 * die van het raster hiervoor, want de flex-basis rekent de gaps eruit.
 *
 * De prijs van deze ruil: bij een oneven aantal is de laatste rij niet meer op
 * dezelfde x-as uitgelijnd als de rijen erboven. Dat is de bedoeling, want een
 * gecentreerde rest leest als opmaak en een linkse rest als een gat.
 */
.doelen {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	align-items: flex-start;
	gap: var(--gap-md);
}

.doelen__item {
	flex: 0 1 calc( ( 100% - var(--gap-md) ) / 2 );
}

@media (min-width: 640px) {
	.doelen__item { flex-basis: calc( ( 100% - var(--gap-md) * 2 ) / 3 ); }
}

@media (min-width: 1024px) {
	.doelen__item { flex-basis: calc( ( 100% - var(--gap-md) * 4 ) / 5 ); }
}

.doelen__item {
	display: grid;
	gap: 0.5rem;
	justify-items: center;
	text-align: center;
}

.doelen__link {
	display: grid;
	gap: 0.5rem;
	justify-items: center;
	text-decoration: none;
	color: inherit;
}

/*
 * Een vast vlak van 4:3 waarbinnen het logo past, met contain en niet cover. Logo's
 * komen in alle verhoudingen binnen en de klant kiest ze zelf; met cover zou een
 * liggend logo bijgesneden worden en dat is bij een merk niet toegestaan.
 */
.doelen__logo {
	display: grid;
	place-items: center;
	width: 100%;
	aspect-ratio: 4 / 3;
	/* Zie de min-0-regel hieronder: dit vlak is zelf ook een grid-item. */
	min-width: 0;
	min-height: 0;
}

/*
 * DE min-0 HIERONDER IS GEEN OPSMUK, ZONDER HEM KLOPT HET VLAK ERBOVEN NIET.
 *
 * Een grid-item mag standaard niet kleiner worden dan zijn eigen inhoud, en voor een
 * afbeelding is dat zijn natuurlijke maat. Deze img is een grid-item (het vlak
 * hierboven is display: grid), dus `max-width: 100%` kon hem niet inperken: hij duwde
 * het vlak open en nam de aspect-ratio mee.
 *
 * Nagemeten op 1 september 2026, met de echte logo's erin en een kolom van 214px:
 * Trees for All (398x502) kreeg een vlak van 361x455 en liep zijn buurman in, en
 * CliniClowns (101x82) werd opgeblazen naar 232x188. De drie logo's die breder dan
 * hoog zijn vielen niet op, dus dit bleef staan tot de sectie voor het eerst gevuld
 * werd. Met min-width en min-height op 0 winnen de max-regels wel.
 */
.doelen__logo img {
	max-width: 100%;
	max-height: 100%;
	width: auto;
	height: auto;
	min-width: 0;
	min-height: 0;
	object-fit: contain;
}

.doelen__naam {
	font-family: var(--font-sans);
	font-size: var(--text-body-sm);
	line-height: var(--leading-normal);
}

.doelen__link:focus-visible .doelen__naam {
	text-decoration: underline;
}

@media (hover: hover) {

	.doelen__link:hover .doelen__naam {
		text-decoration: underline;
	}
}
