/*
 * Basis: reset, element-standaarden, de kleuromkering en de toegankelijkheids-
 * primitieven.
 *
 * Wat hier hoort: alles wat voor de hele site geldt en waar geen ontwerpkeuze
 * per sectie aan te pas komt.
 *
 * Wat hier niet hoort: componenten (knop, kaart, tijdlijn, accordeon) en
 * layout-composities. Die komen in components.css en layout.css, en die worden
 * gebouwd in fase B, per pagina, met een geïnspecteerde referentie erbij. De
 * homepage legt dat systeem vast.
 */

/* =======================================================================
 * Reset
 * ======================================================================= */

*,
*::before,
*::after {
	box-sizing: border-box;
}

html {
	-webkit-text-size-adjust: 100%;
	scroll-behavior: smooth;

	/*
	 * De header staat vast bovenaan, dus een sprong naar een anker legt de
	 * bovenkant van het doel eronder. Gemeten op 26 augustus 2026: een sprong
	 * naar #formulier zette de sectiekop op 110px terwijl de header tot 112px
	 * loopt. Met deze regel staat hij vrij.
	 *
	 * Het raakt vooral het foutpad van de formulieren, want dat is precies het
	 * moment waarop de bezoeker naar een anker wordt gestuurd en de melding
	 * moet kunnen lezen.
	 */
	scroll-padding-top: calc( var(--header-hoogte) + var(--gap-sm) );
}

body,
h1, h2, h3, h4, h5, h6,
p, figure, blockquote, dl, dd,
ul, ol {
	margin: 0;
}

ul[class],
ol[class] {
	padding: 0;
	list-style: none;
}

/*
 * Beeld is blok-niveau en schaalt nooit buiten zijn container. Zonder deze
 * drie regels loopt elke sectie met een foto op mobiel over de rand.
 */
img,
picture,
video,
canvas,
svg,
iframe {
	display: block;
	max-width: 100%;
}

img,
video {
	height: auto;
}

input,
button,
textarea,
select {
	font: inherit;
	color: inherit;
}

button {
	background: none;
	border: 0;
	padding: 0;
	cursor: pointer;
}

/* =======================================================================
 * Document
 * ======================================================================= */

body {
	background-color: var(--color-black);
	color: var(--text-on-dark);
	font-family: var(--font-sans);
	font-size: var(--text-body);
	font-weight: var(--weight-regular);
	line-height: var(--leading-loosest);
	font-optical-sizing: auto;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;

	/*
	 * Een lang woord mag het venster nooit oprekken. Gemeten op 320px:
	 * "textielrecyclingindustrie" in de derde halte-kop op /wandelroute/ is
	 * 270px breed in een kolom van 238, en dat gaf 11px horizontale scroll op
	 * het hele document. Er staat bewust geen overflow-x: hidden op de body
	 * (zie het blok hieronder), dus dit is de plek waar zoiets hoort te worden
	 * opgelost in plaats van verstopt.
	 *
	 * Hier staat `anywhere` en niet `break-word`, en dat verschil is het hele
	 * punt. Allebei laten ze een te lang woord breken, maar alleen `anywhere`
	 * telt mee in de min-content-breedte van een vak. Dat is waar het scheef
	 * ging: een rasterkolom van `1fr` of een flex-item wordt minstens zo breed
	 * als zijn langste woord, dus met `break-word` groeide de KOLOM mee met het
	 * woord in plaats van dat het woord brak. Gemeten op 390px bij 200 procent
	 * tekstvergroting, over tien pagina's: 581px horizontale scroll in totaal
	 * met `break-word`, 72px met `anywhere`.
	 *
	 * overflow-wrap erft, dus deze ene regel dekt elke tekst op de site: ook
	 * een e-mailadres in een kanaalblok of een URL in een alinea.
	 */
	overflow-wrap: anywhere;
}

/*
 * Hier staat met opzet GEEN overflow-x: hidden op de body, terwijl het vorige
 * thema dat wel had.
 *
 * Die regel verbergt horizontaal overloop in plaats van het te voorkomen, en
 * daarmee sloopt hij de controle erop: de toets "de pagina scrollt niet zijwaarts
 * op 390px" kan dan niet meer rood worden, ook niet als een sectie werkelijk
 * buiten het scherm loopt. Een controle die altijd groen is, is geen controle.
 *
 * Een element dat over de rand hoort te gaan, zoals een hero-beeld met de
 * overscan van scale(1.05), krijgt zijn eigen overflow: hidden op de container
 * waar die overscan zit. Clip waar het probleem zit, niet op het document.
 */

::selection {
	background-color: var(--color-red);
	color: #ffffff;
}

/* =======================================================================
 * De korrel
 *
 * Geeft elk vlak het vuil van drukwerk. Zonder deze laag blijft een donkere
 * sectie een gladde kleur, en dat is precies wat er "te zwart" aan voelde.
 *
 * Hij zit als achtergrondbeeld OP de grond en niet als losse laag erboven. Dat
 * is gemeten en niet gekozen: als vaste laag over de pagina kostte hij 0,8
 * contrast op elk hero-label, en op Contact zakte dat van 4,74 naar 3,95 bij een
 * eis van 4,5. Vijf varianten getoetst; alleen "onder de inhoud" kost niets.
 *
 * Het achtergrondbeeld ligt boven background-color en onder de inhoud, dus er is
 * geen pseudo-element en geen stapeling nodig. Dat is ook waarom het hier staat
 * en niet als extra ::before op .section: de hero deelt deze grondklassen en
 * gebruikt zijn eigen pseudo-elementen al.
 * ======================================================================= */

.section-dark,
.section-shadow,
.section-deep,
.section-light {
	background-image: var(--grain);
	background-blend-mode: soft-light;
}

/* =======================================================================
 * Typografie-standaarden
 *
 * De koppen staan op de serif, in de tightere letterafstand. De uppercase en
 * de italic-varianten zijn een componentkeuze en staan dus niet hier: een h2
 * die als sectielabel dient krijgt straks een klasse, niet een globale regel.
 * ======================================================================= */

h1, h2, h3, h4, h5, h6 {
	font-family: var(--font-serif);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-tighter);
	text-wrap: balance;

	/*
	 * Koppen breken met een streepje, de rest van de site zonder. Een kop staat
	 * op 24 tot 128px, dus daar is een woord dat midden afbreekt meteen een
	 * leesfout: "textielrecyclingindus / trie" leest als een bug, met streepje
	 * als een afbreking. hyphenate-limit-chars houdt het bij woorden vanaf
	 * twaalf tekens met minstens zes ervoor en vier erna, zodat gewone koppen
	 * ongemoeid blijven en alleen de samenstellingen breken.
	 *
	 * De browser gebruikt hiervoor het Nederlandse woordenboek, want de site
	 * staat op lang="nl-NL" via language_attributes() in header.php. Zonder dat
	 * attribuut doet hyphens: auto niets.
	 */
	hyphens: auto;
	hyphenate-limit-chars: 12 6 4;
}

h1 {
	font-size: var(--text-h1);
	line-height: var(--leading-tight);
}

h2 {
	font-size: var(--text-h2);
	line-height: var(--leading-snug);
}

h3 {
	font-size: var(--text-h3);
	line-height: var(--leading-normal);
	letter-spacing: var(--tracking-normal);
}

h4, h5, h6 {
	font-size: var(--text-body-lg);
	line-height: var(--leading-normal);
	letter-spacing: var(--tracking-normal);
}

p {
	text-wrap: pretty;
}

/*
 * Een tabelcel neemt de `anywhere` van de body NIET over.
 *
 * De kolombreedte van een tabel wordt door de browser uit de min-content van de
 * cellen berekend, en `anywhere` zet die min-content op een enkel teken. Gemeten
 * op /bedrijfsruimte-huren/ bij 600px: de kop "Oppervlakte" ging van één regel
 * naar twee, met een breuk midden in het woord, terwijl de kolom maar 5px smaller
 * werd. Dat is de enige plek op de site waar `anywhere` iets kapotmaakte in
 * plaats van repareert, en het is precies te verklaren.
 *
 * `break-word` blijft wel staan: een cel met een woord dat echt niet past breekt
 * nog steeds, alleen telt dat woord weer mee in de kolombreedte.
 */
th,
td {
	overflow-wrap: break-word;
}

strong, b {
	font-weight: var(--weight-semibold);
}

/*
 * De italic serif is een merksignaal. Standaard erft cursieve tekst dus de
 * serif, ook binnen een alinea in de sans.
 */
em, i, cite, blockquote {
	font-family: var(--font-serif);
	font-style: italic;
}

/*
 * Een adres is geen citaat. De browser zet <address> standaard cursief, en omdat
 * Inter geen italic-bestand heeft trekt de browser de letter dan zelf schuin.
 * Dat ziet er slecht uit en het zegt ook niets: de italic hoort hier bij de
 * serif en bij een verhalende toon, niet bij contactgegevens.
 */
address {
	font-style: normal;
}

a {
	color: inherit;
	text-decoration-color: var(--color-red);
	text-decoration-thickness: 1px;
	text-underline-offset: 0.2em;
	transition: color var(--duration-base) var(--ease-in-out);
}

hr {
	border: 0;
	border-top: 1px solid var(--border-light);
	margin: 0;
}

/* =======================================================================
 * De kleuromkering
 *
 * Vier klassen die achtergrond en tekstkleur samen zetten, zodat de omkering
 * altijd klopt en een sectie nooit half donker kan staan.
 *
 * De vier-traps donkerschaal is het eigenlijke ontwerp: drie donkere secties
 * kunnen achter elkaar staan en worden onderscheiden door de nuance, niet door
 * een lijn. Wie hier netjes donker en licht gaat afwisselen, bouwt een andere
 * site.
 * ======================================================================= */

.section-dark {
	background-color: var(--color-black);
	color: var(--text-on-dark);
}

.section-shadow {
	background-color: var(--color-shadow);
	color: var(--text-on-dark);
}

.section-deep {
	background-color: var(--color-deep);
	color: var(--text-on-dark);
}

.section-light {
	background-color: var(--color-white);
	color: var(--text-on-light);
}

/*
 * Op de donkere gronden kantelt de focus-kleur naar licht, want rood haalt daar
 * 2,9:1 en dat is te weinig voor een focus-indicator. Dit staat als token-
 * herdefinitie en niet als aparte outline-regel, zodat elke component die
 * --focus-color gebruikt automatisch meekantelt.
 */
.section-dark,
.section-shadow,
.section-deep,
/*
 * De chrome-onderdelen liggen buiten elke sectie en kregen daardoor de rode
 * focusring op de donkere grond: 2,84:1 bij een eis van 3,0 (WCAG 1.4.11).
 * Gemeten op 20 augustus, en het raakte de logo-link, alle zes menu-items en de
 * primaire CTA op elke pagina. Ze horen in dezelfde lijst, want ze staan altijd
 * op donker.
 */
.site-header,
.skip-link,
.menu-toggle,
.nav-mobile,
.visit-cta {
	--focus-color: var(--color-white);
}

/* =======================================================================
 * Container
 * ======================================================================= */

.container {
	width: 100%;
	max-width: var(--container);
	margin-inline: auto;
	padding-inline: var(--container-px);
}

.container-narrow {
	max-width: var(--container-narrow);
}

.container-text {
	max-width: var(--container-text);
}

/* =======================================================================
 * Toegankelijkheid
 * ======================================================================= */

/*
 * Focus alleen tonen bij toetsenbordgebruik, maar dan onmiskenbaar. Nooit
 * outline: none zonder vervanging.
 */
:focus-visible {
	outline: var(--focus-width) solid var(--focus-color);
	outline-offset: var(--focus-offset);
}

.skip-link {
	position: absolute;
	top: -100%;
	left: var(--container-px);
	z-index: var(--z-skiplink);
	background-color: var(--color-red);
	color: #ffffff;
	font-size: var(--text-button);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-widest);
	text-transform: uppercase;
	text-decoration: none;
	padding: 1rem 1.5rem;
	transition: top var(--duration-base) var(--ease-out);
}

.skip-link:focus {
	top: 1rem;
}

/* Buiten beeld, wel voorgelezen. */
.screen-reader-text {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.screen-reader-text:focus {
	position: static;
	width: auto;
	height: auto;
	margin: 0;
	overflow: visible;
	clip-path: none;
	white-space: normal;
}

/* =======================================================================
 * De scroll-onthulling
 *
 * Eén waarnemer met een drempel van 20 procent zet .is-revealed en laat het
 * element daarna los, zodat de animatie precies één keer speelt. Zie
 * assets/js/scroll-animations.js.
 *
 * De verborgen begintoestand staat achter (scripting: enabled), en dat is de
 * hele veiligheid van dit patroon. Staat JavaScript uit, dan matcht de query
 * niet en is de inhoud gewoon zichtbaar. Kent de browser de media-feature niet,
 * dan matcht hij ook niet, en dan is er geen animatie maar wel inhoud. Er is
 * geen enkel pad waarin een bezoeker naar een leeg vlak kijkt, en er is geen
 * inline script in de head nodig om dat te regelen.
 * ======================================================================= */

@media (scripting: enabled) {

	.reveal {
		opacity: 0;
		transform: translateY(30px);
		transition:
			opacity var(--duration-reveal) var(--ease-out),
			transform var(--duration-reveal) var(--ease-out);
	}

	.reveal.is-revealed {
		opacity: 1;
		transform: none;
	}

	/*
	 * De faciliteiten die vanuit het midden uit elkaar vliegen.
	 *
	 * De beginpositie staat in --spat-x en --spat-y, en die zet assets/js/spat.js
	 * per plaatje op de afstand tot het midden van de set. Draait dat script niet,
	 * dan blijven ze op hun standaard van 0px en vervaagt het plaatje gewoon in
	 * vanaf zijn eigen plek. Zonder JavaScript matcht deze hele query niet en
	 * staat de set er meteen.
	 *
	 * De KANTELING zit hier met opzet niet in: die hoort bij de plaat (.spat__tekst)
	 * en niet bij de vlucht, zodat de hover er zijn eigen duur op kan zetten.
	 */
	.spat {
		opacity: 0;
		transform:
			translate( var(--spat-x, 0px), var(--spat-y, 0px) )
			scale(0.86);
		transition:
			opacity var(--duration-reveal) var(--ease-out),
			transform var(--duration-reveal) var(--ease-out);
	}

	.spatlijst.is-revealed .spat {
		opacity: 1;
		transform: translate(0, 0) scale(1);
	}

	/*
	 * Het luik: een paneel dat opzij schuift in plaats van tekst die invervaagt.
	 *
	 * Twee dingen die bij het prototype misgingen en hier meteen goed staan.
	 * Ten eerste heeft het paneel een EIGEN tint, lichter dan de sectie eronder.
	 * Gelijk aan de achtergrond leest als laden en niet als opbouwen: je kijkt
	 * dan naar een leeg vlak tot het opengaat. Ten tweede staat er een rode rand
	 * op de kant die wegschuift, zodat de beweging een richting heeft.
	 *
	 * Alleen transform, dus geen layout-werk. De rand schaalt mee en wordt daarmee
	 * vanzelf een streep die naar rechts wegloopt.
	 *
	 * --luik-grond stelt de tint per sectie bij; de standaard past op de donkere
	 * gronden. Op een lichte sectie zet je hem op var(--color-cream).
	 */
	.luik {
		position: relative;
	}

	.luik::after {
		content: '';
		position: absolute;
		inset: 0;
		z-index: var(--z-base);
		background-color: var(--luik-grond, var(--color-luik));
		border-left: 2px solid var(--color-red);
		transform: scaleX(1);
		transform-origin: right;
		transition: transform var(--duration-reveal) var(--ease-out);
		pointer-events: none;
	}

	.luik.is-revealed::after {
		transform: scaleX(0);
	}
}

/*
 * Printen en PDF: alles zichtbaar.
 *
 * (scripting: enabled) dekt het geval "geen JavaScript", maar niet het geval
 * "JavaScript draait en er wordt niet gescrold". Een print, een PDF-export en een
 * crawler die de pagina in één keer rendert scrollen niet, en dan staat alles
 * onder de vouw op opacity 0. Dat is precies gebeurd bij de eerste eigen
 * screenshot van de historie-pagina: die was op de kop en de footer na leeg.
 */
@media print {

	.reveal,
	.spat {
		opacity: 1 !important;
		transform: none !important;
	}

	.luik::after {
		display: none !important;
	}
}

/* =======================================================================
 * Wie beweging vermijdt, krijgt geen beweging
 *
 * Inclusief de gladde scroll op html, want die is ook beweging.
 * ======================================================================= */

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

	html {
		scroll-behavior: auto;
	}

	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;

		/*
		 * De vertraging moet ook weg, niet alleen de duur.
		 *
		 * Zonder deze regel bleef de hero-intro 0,5s en de primaire CTA 1s
		 * onzichtbaar en plofte daarna zonder overgang in beeld, terwijl diezelfde
		 * knop zónder reduced motion juist netjes invervaagde. Wie om minder
		 * beweging vraagt kreeg dus een hardere sprong dan wie er niet om vraagt.
		 * Gemeten op de echte klok op 20 augustus 2026.
		 */
		animation-delay: 0s !important;
		transition-delay: 0s !important;
	}

	/*
	 * Het luik vervalt helemaal. Met de duur op nul zou het paneel niet
	 * wegschuiven maar wegknipperen, en dat is een hardere sprong dan wie er niet
	 * om vraagt. Wie minder beweging wil, ziet de sectie gewoon staan.
	 */
	.luik::after {
		display: none !important;
	}

	.reveal,
	.spat {
		opacity: 1;
		transform: none;
	}

	/*
	 * De begintoestand van de intro-choreografie staat op opacity 0 en wordt
	 * alleen door de animatie teruggezet. Met een duur van 0,01ms is dat een
	 * flikkering; expliciet zichtbaar zetten is hier het eerlijke antwoord.
	 */
	.hero__wordmark,
	.hero__tagline,
	.hero__intro,
	.hero__actions {
		opacity: 1 !important;
		transform: none !important;
	}
}
