/* ===================================================================
   RINSE&GO: BASE & COMPONENTS
   =================================================================== */

*, *::before, *::after { box-sizing: border-box; }
/* Zacht scrollen geldt bewust pas na het laden, via de klasse die main.js op
   window.load zet. Staat het meteen aan, dan animeert de browser ook de sprong
   die hoort bij een ankerlink vanaf een andere pagina (bijvoorbeeld
   /#contact vanuit de header). Die animatie loopt over duizenden pixels
   terwijl de pagina nog opbouwt, wordt door de eerste de beste verschuiving
   afgebroken en laat de bezoeker dan boven aan de homepage achter in plaats van
   bij het formulier. */
html { scroll-behavior: auto; }
html.zacht-scrollen { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html.zacht-scrollen { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--step-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img { max-width: 100%; height: auto; display: block; }
svg { display: block; }

a { color: inherit; text-decoration: none; }

/* Ankerdoelen mogen niet achter de vaste header vallen bij een sprong.
   Let op: deze ruimte is alleen zinvol zolang de balk er ook echt staat. Zie
   ankerSprongBezig in main.js, dat houdt hem tijdens een sprong op zijn plek.
   Zonder dat schoof de balk weg en keek de bezoeker door dit gat naar de
   onderkant van de vorige sectie. */
/* Een sectie heeft zelf een flinke bovenmarge. Die telde hier eerder bovenop
   de ruimte voor de balk, en dan landde de eerste tekst van de sectie ruim
   honderd pixels te laag: je klikte op Contact en keek tegen een leeg vlak aan
   met de vorige sectie er nog half boven.

   Daarom wordt die eigen marge er hier weer af getrokken. Het anker landt dus
   met de bovenrand van de sectie onder de balk, en de eerste tekst een klein
   stukje eronder.

   --header-h wordt in main.js op de gemeten hoogte gezet en gaat mee bij het
   wijzigen van de vensterbreedte. De terugvalwaarde voor het geval dat niet
   gebeurt is de hoogte op een breed scherm, 5,7rem, en dat is met opzet de
   grootste van de twee: te veel lucht ziet er rommelig uit, te weinig schuift
   de tekst onder de balk en dan leest niemand hem. */
:root { --anker-lucht: 1.5rem; }
section[id] {
  scroll-margin-top: calc(var(--header-h, 5.7rem) + var(--anker-lucht) - var(--section-pad));
}
section[id].section--tight {
  scroll-margin-top: calc(var(--header-h, 5.7rem) + var(--anker-lucht) - var(--section-pad) * 0.6);
}
/* #main is het doel van de skiplink en heeft geen eigen bovenmarge. */
main[id] { scroll-margin-top: calc(var(--header-h, 5.7rem) + var(--anker-lucht)); }

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: -0.01em;
  margin: 0;
  color: var(--ink);
}
h1 { font-size: var(--step-h1); font-weight: 600; }
h2 { font-size: var(--step-h2); }
h3 { font-size: var(--step-h3); }
h4 { font-size: var(--step-h4); }

p { margin: 0; }

em { font-style: italic; color: var(--primary); }

:focus-visible {
  outline: 2.5px solid var(--primary);
  outline-offset: 3px;
  border-radius: 2px;
}

/* ---- Layout helpers ---- */
.container {
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: clamp(1.25rem, 3vw, 3rem);
}
.container--narrow { max-width: var(--container-narrow); }

.section { padding-block: var(--section-pad); }
.section--tight { padding-block: calc(var(--section-pad) * 0.6); }
.section--sky { background: var(--sky-tint); }
.section--dark { background: var(--dark-bg); color: var(--ink-invert); }
.section--dark h1, .section--dark h2, .section--dark h3, .section--dark h4,
.blueprint h1, .blueprint h2, .blueprint h3, .blueprint h4 { color: var(--ink-invert); }
.section--dark .eyebrow, .blueprint .eyebrow { color: var(--sky); }
.blueprint { color: var(--ink-invert); }
.section--bordered { border-top: var(--border); }

/* Sectiekop als apart blok, zodat het label en de kop samen als één geheel
   uitgelijnd en begrensd worden.
   Vaste breedte in px en niet in ch: ch rekent met de tekstgrootte van dit
   blok zelf en niet met die van de kop, waardoor een grote kop veel te
   vroeg afbreekt. */
.section-head { max-width: 640px; margin-bottom: var(--space-xl); }
.section-head > :last-child { margin-bottom: 0; }

.grid { display: grid; gap: var(--space-lg); }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }

.stack { display: flex; flex-direction: column; }
.cluster { display: flex; align-items: center; flex-wrap: wrap; }

@media (max-width: 900px) {
  .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
}
@media (min-width: 901px) {
  .grid-sm-2 { grid-template-columns: repeat(2, 1fr); }
}

/* ---- Eyebrow / labels ---- */
.eyebrow {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--step-eyebrow);
  letter-spacing: 0.01em;
  color: var(--primary);
  display: block;
  margin-bottom: var(--space-sm);
}

.lede {
  font-size: var(--step-body-lg);
  color: var(--ink-soft);
  max-width: 46ch;
  line-height: 1.6;
}

/* ---- Buttons ---- */
.btn {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.98rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55em;
  padding: 0.95em 1.7em;
  border-radius: var(--radius-pill);
  border: 1.5px solid transparent;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
  white-space: nowrap;
}
.btn:active { transform: translateY(1px); }
.btn-primary { background: var(--primary); color: #fff; border-color: var(--primary); }
.btn-primary:hover { background: var(--primary-dark); border-color: var(--primary-dark); }
.btn-ghost { background: transparent; color: var(--ink); border-color: var(--line); }
.btn-ghost:hover { border-color: var(--ink); }
.btn-invert { background: #fff; color: var(--primary); border-color: #fff; }
.btn-invert:hover { background: var(--sky-tint); }
.btn-on-dark { background: transparent; color: #fff; border-color: var(--dark-line); }
.btn-on-dark:hover { border-color: #fff; }
.btn-lg { padding: 1.1em 2.1em; font-size: 1.05rem; }
.btn-arrow { transition: transform var(--dur-fast) var(--ease); }
.btn:hover .btn-arrow { transform: translateX(3px); }

/* Een pijl die naar beneden wijst hoort bij hover ook naar beneden te bewegen
   en niet opzij. Gebruikt op Over ons, waar de hero anders leest als het einde
   van de pagina: die is als enige zonder knop gebouwd, terwijl de hero op de
   homepage en op beide productpagina's er twee heeft. */
.btn:hover .btn-arrow--omlaag { transform: translateY(3px); }

/* ---- Header ---- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(250,249,246,0.97);
  border-bottom: 1px solid var(--line);
  transition: top var(--dur-base) var(--ease);
}
/* Let op: geen backdrop-filter op .site-header: dat maakt de header een
   containing block voor position:fixed kinderen (zoals het mobiele menu),
   waardoor inset:0 t.o.v. de header i.p.v. de viewport zou resolven. */

/* Wegschuiven bij naar beneden scrollen. Bewust via top en niet via een
   transform, want een transform heeft precies hetzelfde gevolg als de
   backdrop-filter hierboven: het maakt de header een containing block en
   dan valt het mobiele menu met inset:0 binnen de header.
   --header-h wordt in main.js op de gemeten hoogte gezet; de waarde
   hieronder is alleen een vangnet als dat script niet draait.
   Bij prefers-reduced-motion staan alle --dur-tokens al op 0ms, dus dan
   schuift er niets maar verdwijnt de balk direct. */
.site-header.is-hidden { top: calc(-1 * var(--header-h, 5rem)); }
.site-header__inner {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  padding-block: 1rem;
  gap: var(--space-lg);
}
.brand { grid-column: 1; display: flex; align-items: center; }
.brand img { height: 24px; width: auto; }

.nav-toggle { grid-column: 3; }

.nav-primary { display: flex; align-items: center; gap: var(--space-lg); }
@media (min-width: 981px) {
  .nav-primary { display: contents; }
  .nav-links { grid-column: 2; justify-content: center; }
  .header-cta { grid-column: 3; }
}
.nav-links { display: flex; align-items: center; gap: var(--space-md); list-style: none; margin: 0; padding: 0; }
.nav-links a {
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--ink-soft);
  padding: 0.4em 0;
  position: relative;
}
.nav-links a:hover, .nav-links a[aria-current], .nav-links a.is-hier { color: var(--ink); }
.nav-links a[aria-current]::after,
.nav-links a.is-hier::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -3px;
  height: 2px;
  background: var(--primary);
}
/* Zodra de scrollspy in main.js draait, bepaalt alleen `.is-hier` waar de
   streep staat. Zonder die regel staan er twee: de streep uit de build onder
   "Home" en de meelopende streep. `aria-current` blijft wél in de HTML staan,
   want dat is voor een schermlezer de juiste mededeling: dit ís de huidige
   pagina, ook al kijk je naar een sectie verderop. De streep is een visuele
   wegwijzer, geen uitspraak over welke pagina open staat. */
.nav-links.spy-actief a[aria-current]:not(.is-hier)::after { content: none; }

.nav-item-dropdown { position: relative; }
/* Links uitlijnen op de navigatietitel, niet centreren: een paneel van 240px
   centreren onder een titel van ~70px loopt buiten beeld zodra die titel
   dicht bij de linkerrand staat. */
.nav-dropdown {
  position: absolute;
  top: calc(100% + 14px);
  left: 0;
  background: var(--white);
  border: var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  padding: var(--space-2xs);
  min-width: 240px;
  opacity: 0;
  visibility: hidden;
  transform: translateY(6px);
  transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease), visibility var(--dur-fast);
}
.nav-item-dropdown:hover .nav-dropdown,
.nav-item-dropdown:focus-within .nav-dropdown {
  opacity: 1; visibility: visible; transform: translateY(0);
}
.nav-dropdown a {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 0.7em 0.9em;
  border-radius: var(--radius-sm);
  color: var(--ink);
}
.nav-dropdown a:hover { background: var(--sky-tint); }
.nav-dropdown a span.dd-desc { font-size: 0.82rem; color: var(--ink-faint); font-weight: 400; }

.header-cta { display: flex; align-items: center; gap: var(--space-sm); }
.nav-toggle { display: none; background: none; border: none; cursor: pointer; padding: 0.4rem; }
.nav-toggle svg { width: 24px; height: 24px; }

/* ---- Taalswitcher ---- */
.lang-switch {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  flex-shrink: 0;
}
.lang-switch__item {
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: .04em;
  line-height: 1;
  padding: 0.5em 0.75em;
  border-radius: var(--radius-pill);
  color: var(--ink-faint);
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
a.lang-switch__item:hover { color: var(--ink); background: var(--sky-tint); }
.lang-switch__item.is-active { color: #fff; background: var(--primary); }

@media (max-width: 980px) {
  .nav-primary { position: fixed; inset: 64px 0 0 0; background: var(--paper); flex-direction: column; align-items: stretch; padding: var(--space-lg) var(--space-md); gap: var(--space-lg); transform: translateY(-8px); opacity: 0; visibility: hidden; transition: opacity var(--dur-base) var(--ease), transform var(--dur-base) var(--ease), visibility var(--dur-base); overflow-y: auto; }
  .nav-primary.is-open { opacity: 1; visibility: visible; transform: translateY(0); }
  .nav-links { flex-direction: column; align-items: flex-start; gap: var(--space-md); width: 100%; }
  .nav-links a { font-size: 1.15rem; }
  /* In het mobiele menu klapt "Product" open op de eerste tik; de tweede tik
     navigeert naar het assortiment. Zie de afhandeling in main.js. */
  /* Hetzelfde paneel als op desktop: wit vlak met rand, afronding en schaduw.
     Achtergrond, rand, radius, schaduw en binnenmarge worden hier dus bewust
     niet overschreven, die komen uit de regel bovenaan.

     Eén verschil met desktop, en dat is noodzakelijk: het paneel zweeft niet
     maar staat in de lijst. In een schermvullend menu zou een absoluut paneel
     over Contact, FAQ en Over ons heen vallen.

     Hiervoor stond hier een ingesprongen lijstje met een lijn aan de
     linkerkant. Die is er op verzoek uit: de lijn begon ter hoogte van
     "Product" en leek daar dwars doorheen te lopen. */
  .nav-dropdown {
    position: static;
    display: none;
    flex-direction: column;
    opacity: 1;
    visibility: visible;
    transform: none;
    min-width: 0;
    margin-top: var(--space-2xs);
  }
  .nav-item-dropdown.is-open .nav-dropdown { display: flex; }
  /* De productnaam een maat kleiner dan de hoofditems. Zonder dit erft hij de
     1.15rem van .nav-links a hierboven en wegen hoofdmenu en submenu even
     zwaar. Op desktop ontstaat dat verschil vanzelf, want daar staan de
     hoofditems al op 0.95rem. */
  .nav-dropdown a span:first-child { font-size: 1rem; font-weight: 500; }
  .header-cta { flex-direction: column; align-items: stretch; width: 100%; }
  .nav-toggle { display: block; }
  .header-cta .btn-ghost { display: none; }
  .lang-switch { align-self: flex-start; }
}

/* ---- Hero ---- */
.hero {
  padding-top: clamp(2.5rem, 2rem + 2vw, 4.5rem);
  padding-bottom: var(--section-pad);
  overflow: hidden;
}
.hero__grid {
  display: grid;
  grid-template-columns: 7fr 5fr;
  gap: var(--space-2xl);
  align-items: center;
}
/* De hero van Over ons heeft weinig tekst naast een liggende foto, waardoor de
   band erg ondiep uitviel: 409px, waarvan het beeld maar 242px. Hier krijgt het
   beeld daarom een gelijke helft in plaats van 5 van de 12 delen. Samen met de
   4:3-uitsnede van de teamfoto, die eerder 1200x630 was, geeft dat een beeld
   dat de tekst ernaast in hoogte aankan.

   Deze regel moet binnen een min-width staan. Hij is met twee klassen zwaarder
   dan de regel verderop die het raster op smalle schermen naar één kolom zet,
   en een mediaquery voegt geen gewicht toe. Zonder die grens bleef de hero op
   een telefoon dus twee kolommen houden, met een foto van 59 px breed. */
@media (min-width: 981px) {
  .hero--intro .hero__grid { grid-template-columns: 1fr 1fr; }
}

.hero__title { margin-block: var(--space-md) var(--space-md); }
.hero__meta { display: flex; gap: var(--space-lg); margin-top: var(--space-lg); padding-top: var(--space-lg); border-top: var(--border); flex-wrap: wrap; }
.hero__stat b { display: block; font-family: var(--font-display); font-size: 1.6rem; color: var(--primary); }
.hero__stat span { font-size: 0.85rem; color: var(--ink-faint); }
.hero__actions { display: flex; gap: var(--space-md); flex-wrap: wrap; margin-top: var(--space-lg); }
.hero__visual { position: relative; }
.hero__visual img { width: 100%; height: auto; }

/* Podium voor een productrender. Zonder vlak eronder hangt zo'n uitgeknipte
   render los in de witruimte naast de tekst. Dezelfde aanpak als bij de
   productkaarten op de homepage: een eigen achtergrond, en het product staat
   op de onderrand in plaats van te zweven. */
.product-stage {
  /* relatief, want de kleurschakelaar hangt er absoluut in. */
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  /* Vaste hoogte, geen min-height: anders bepaalt het beeld zelf de hoogte van
     het vlak en heeft max-height op dat beeld niets om zich tegen af te zetten.
     Bij de staande render liep het vlak daardoor op tot ruim 1000px. */
  height: 420px;
  padding: var(--space-lg) var(--space-lg) 0;
  background: var(--sky-tint);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
/* Voor een staande render, die bij dezelfde hoogte veel te smal zou uitvallen. */
.product-stage--tall { height: 520px; }

/* Voor een render die veel smaller is dan hij hoog is, zoals de kast bij de
   PantryRinser (400 bij 984). Het beeld schaalt op de hoogte, dus op de volle
   kolombreedte bleef er links en rechts zoveel vlak over dat het product erin
   verdween: het vulde 22% van de breedte, tegen 59% bij de render ernaast.
   Het vlak krijgt daarom een eigen maximumbreedte. Alleen een maximum, geen
   vaste breedte, zodat het op smalle schermen nog gewoon meekrimpt.

   Gestapeld staat het vlak midden in de kolom. */
.product-stage--slim { max-width: 400px; margin-inline: auto; }

/* Naast een tekstkolom moet het tegen de buitenrand van de kolom liggen en niet
   in het midden ervan. Gecentreerd hield het vlak ruim 70px over aan de
   rechterkant, waardoor de rechterrand niet meer samenviel met die van de
   container en het beeld als enige blok op de pagina uit de rooilijn liep.
   Dit geldt dus voor een render in de rechterkolom; komt er ooit een in de
   linkerkolom, dan hoort daar `margin-left: 0` bij. */
@media (min-width: 981px) {
  .product-stage--slim { margin-right: 0; }
}

/* Het vlak even hoog maken als de tekstkolom ernaast, zodat de boven- en
   onderranden van de twee kolommen samenvallen. Met de vaste hoogte hierboven
   en `align-items: center` hield het vlak aan beide kanten lucht over, en dan
   leest het als een afgesneden blok in plaats van als de tegenhanger van de
   tekst.

   Waarom absoluut en niet gewoon `height: 100%`: dat laatste is geprobeerd en
   het werkt niet. Een percentagehoogte die afhangt van een rijhoogte die zelf
   nog niet vaststaat, valt terug op de inhoud, en dan bepaalt het beeld weer de
   hoogte. Het vlak werd zo 765px terwijl de tekst 582px was, dus het probleem
   sloeg om: het stak eronder uit in plaats van erboven op te houden. Dezelfde
   valkuil als bij de vaste hoogte helemaal bovenaan.

   Absoluut positioneren haalt het beeld uit de flow. De rijhoogte komt dan
   alleen van de tekstkolom, en het vlak legt zich daar exact overheen.

   Alleen boven de stapelgrens: gestapeld staat er geen kolom naast om je aan
   te meten en heeft de houder geen hoogte om tegen af te zetten. Daaronder
   geldt gewoon de vaste hoogte. */
@media (min-width: 981px) {
  .stage-houder { position: relative; }
  .stage-houder .product-stage--vul { position: absolute; inset: 0; height: auto; }
}

/* Voor een render die nergens op staat maar zweeft, zoals de twee losse
   onderdelen in de spuitgietsectie op Over ons.

   Het podium zet een product standaard op de onderrand: geen bodemmarge en
   `align-items: flex-end`. Dat klopt voor een spoelstation, dat staat op een
   blad of op de vloer, en het voorkomt dat een uitgeknipte render los in de
   ruimte hangt. Maar bij een uiteengelegde doorsnede leest datzelfde als
   afgesneden: het beeld plakt tegen de onderrand terwijl er bovenin lucht
   overblijft. Vandaar rondom dezelfde marge en verticaal gecentreerd.

   Op smalle schermen blijft de zijmarge de krappere `--space-md` uit de
   mediaquery hieronder, want die staat verderop in dit bestand en wint dus van
   de shorthand hier. Dat is de bedoeling: verticaal gelijke lucht, horizontaal
   niet meer opofferen dan nodig. Verplaats deze regel dus niet naar onder die
   mediaquery zonder daar rekening mee te houden. */
.product-stage--zwevend {
  align-items: center;
  padding: var(--space-lg);
}

.product-stage img { width: auto; max-width: 100%; max-height: 100%; }

@media (max-width: 980px) {
  /* Smallere binnenmarge en een lagere hoogte, zodat het product het vlak vult
     in plaats van er onderin te liggen met een lege bovenhelft. */
  .product-stage { height: 250px; padding-inline: var(--space-md); }
  .product-stage--tall { height: 380px; }
  /* Het vlak is hier lager, dus het beeld erin is ook smaller. In dezelfde
     mediaquery als de hoogte hierboven, want die twee horen bij elkaar. */
  .product-stage--slim { max-width: 280px; }
}

/* Sommige renders lopen in het bronbestand aan de rechterkant het kader uit.
   Door het beeld tegen die rand te leggen valt de snijrand samen met de rand
   van het vlak, in plaats van halverwege zichtbaar te zijn als een afgesneden
   product. Deze regel staat bewust na de mediaquery hierboven, anders zet die
   de rechtermarge er weer overheen. */
.product-stage--bleed-right {
  justify-content: flex-end;
  padding-right: 0;
}

@media (max-width: 980px) {
  .hero__grid { grid-template-columns: 1fr; }
  /* Gestapeld hoort het beeld even breed te zijn als de tekst eronder, zodat
     alles op dezelfde rooilijn staat.

     Hier stond `max-width: 320px; margin-inline: auto`. Dat pakte verkeerd uit,
     en op een manier die je niet ziet aankomen: een rasteritem met
     automatische zijmarges wordt niet uitgerekt maar krimpt naar zijn inhoud.
     Hoe smal het beeld werd hing dus af van de render erin. Op de PillarRinser
     bleef er 184px over van de 335px, waardoor het 75px binnen de rooilijn
     stond. Op de andere pagina's viel het minder op omdat de render breed
     genoeg was om tegen die 320px aan te lopen, maar ook daar stond het 8px
     naar binnen. */
  .hero__visual { order: -1; }
}

/* ---- Hero met achtergrondvideo ---- */
.hero--video {
  position: relative;
  padding-top: 0;
  padding-bottom: 0;
  min-height: min(86vh, 780px);
  display: flex;
  align-items: flex-end;
  overflow: hidden;
}
.hero__media { position: absolute; inset: 0; z-index: 0; background: var(--dark-bg); }
.hero__bg-video, .hero__media img { width: 100%; height: 100%; object-fit: cover; object-position: center 32%; }
.hero__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(11,10,32,.12) 0%, rgba(11,10,32,.38) 45%, rgba(11,10,32,.88) 100%);
}
.hero__content { position: relative; z-index: 1; width: 100%; padding-block: var(--space-2xl) var(--space-xl); }
/* Lichter dan --sky, en alleen hier. Op een vaste donkere sectie haalt --sky
   ruim 11:1, maar boven de herovideo zakt hij naar 3,79 op de lichtste plek in
   het beeld, terwijl 4,5 nodig is: 15px met gewicht 600 telt niet als grote
   tekst. Doorgerekend over het posterbeeld met het verloop erbovenop, per pixel
   in de strook waar deze regel staat. Deze waarde haalt daar 4,58.

   Er staat bewust geen token voor in tokens.css. Dit is geen kleur uit de
   huisstijl maar een correctie voor een bewegende achtergrond, en die hoort
   niet elders opnieuw gebruikt te worden. */
.hero--video .eyebrow { color: #CBDEF0; }
.hero--video .hero__title { color: #fff; }
.hero--video .lede { color: rgba(255,255,255,.86); max-width: 54ch; }
.hero--video .hero__meta { border-top-color: rgba(255,255,255,.22); }

.hero--video .hero__stat b { color: #fff; }
.hero--video .hero__stat span { color: rgba(255,255,255,.68); }

@media (max-width: 640px) {
  .hero--video { min-height: 92vh; align-items: flex-end; }
  .hero__bg-video, .hero__media img { object-position: center 26%; }
  .hero--video .hero__meta { gap: var(--space-md); }
}

/* Rond icoonvlak boven een kaarttitel. De vulling is --sky-tint, conform de
   afspraak dat lichte vlakken die kleur gebruiken; het lavendel uit de
   oorspronkelijke schets is hier bewust niet teruggehaald. */
.card__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--sky-tint);
  color: var(--primary);
  margin-bottom: var(--space-md);
}
.card__icon svg { width: 22px; height: 22px; }

/* ---- Cards ---- */
.card {
  background: var(--white);
  border: var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-lg);
}
.card--flush { padding: 0; overflow: hidden; }

/* ---- Wisselknoppen tussen twee panelen ----
   Zelfde vormentaal als de taalwisselaar in de header: een pil met het
   actieve onderdeel in het merkpaars. */
.tab-switch {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 4px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--white);
}
.tab-switch__btn {
  font-family: var(--font-body);
  font-size: 0.92rem;
  font-weight: 600;
  line-height: 1;
  padding: 0.75em 1.4em;
  border: none;
  border-radius: var(--radius-pill);
  background: none;
  color: var(--ink-faint);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.tab-switch__btn:hover { color: var(--ink); }
.tab-switch__btn[aria-selected="true"],
.tab-switch__btn[aria-selected="true"]:hover { color: var(--ink-invert); background: var(--primary); }

/* Beide panelen liggen op dezelfde rasterplek. Daardoor houdt de sectie de
   hoogte van het langste paneel aan en verspringt er niets bij het wisselen.
   De klasse wordt door main.js gezet: zonder JavaScript staan de panelen
   gewoon onder elkaar en zijn ze allebei zichtbaar. */
.tab-panels.is-enhanced { display: grid; }
.tab-panels.is-enhanced > .tab-panel { grid-area: 1 / 1; }
/* Het raster meerekken, zodat ook de kaarten in het kortere paneel dezelfde
   hoogte krijgen als die in het langere. */
.tab-panels.is-enhanced > .tab-panel > .grid { height: 100%; }
/* visibility:hidden houdt de ruimte bezet en haalt het paneel tegelijk uit de
   tabvolgorde en uit wat een schermlezer voorleest. */
.tab-panels.is-enhanced > .tab-panel:not(.is-active) { visibility: hidden; }

/* ---- Cijferkaarten ----
   Zelfde vlak, rand, radius en binnenmarge als .card, zodat ze naadloos bij
   de andere kaarten op de site passen. Bewust een eigen klasse en niet .card
   erbij: de tekstbox achter het info-icoon heeft hier een eigen plaatsing en
   die zou anders botsen met de regels voor de gewone kaarten. */
.impact-card {
  position: relative;
  background: var(--white);
  border: var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-lg);
}
.impact-card .claim-number { font-size: clamp(2.4rem, 1.9rem + 1.6vw, 3.2rem); }
.impact-card .claim-sub { margin-top: 0.6em; }

/* Het info-knopje staat rechtsboven in de kaart. De tekstbox hangt aan de
   kaart en niet aan het knopje, zodat hij nooit in de buurkaart overloopt:
   elke kaart heeft door data-reveal een eigen stapelcontext. */
.impact-card .claim-info { position: static; }
.impact-card .claim-info__btn {
  position: absolute;
  top: var(--space-md);
  right: var(--space-md);
  color: var(--ink-soft);
}
.impact-card .claim-info__panel {
  top: calc(var(--space-md) + 30px);
  left: var(--space-md);
  right: var(--space-md);
  width: auto;
  max-width: none;
}
.impact-card:hover,
.impact-card:focus-within,
.impact-card:has(.claim-info.is-open) { z-index: 30; }

/* ---- Cijferkaart met bronvermelding ---- */
.claim-head { display: flex; align-items: center; gap: 0.45em; margin-bottom: 0.3em; }
.claim-head .eyebrow { margin-bottom: 0; }
.claim-number { font-family: var(--font-display); font-size: 2.4rem; color: var(--primary); margin: 0; }
.claim-sub { color: var(--ink-soft); margin-top: 0.5em; }

.claim-info { position: relative; display: inline-flex; }
/* 24 bij 24 is de ondergrens uit WCAG 2.2 voor een aanraakdoel. Stond op 22,
   en dat is precies zo'n maat die op een beeldscherm prima oogt en op een
   telefoon net te vaak misgaat. Het icoontje erin blijft even groot; alleen het
   aanraakgebied is groter. */
.claim-info__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: none;
  color: var(--ink-faint);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease);
}
.claim-info__btn:hover,
.claim-info__btn[aria-expanded="true"] { color: var(--primary); }

/* De bron onder de onderbouwing. Iets rustiger dan de rekensom erboven, want
   het is de verantwoording en niet het argument. */
.claim-info__bron {
  display: block;
  margin-top: 0.6em;
  padding-top: 0.6em;
  border-top: 1px solid rgba(255,255,255,.18);
  color: rgba(255,255,255,.72);
  font-size: 0.94em;
}

.claim-info__panel {
  position: absolute;
  top: calc(100% + 8px);
  left: -8px;
  z-index: 20;
  width: max-content;
  max-width: min(260px, 72vw);
  /* Een onderbouwing kan lang worden, en op een telefoon is een tekstballon
     van een halve schermhoogte onleesbaar. Hij mag dus scrollen in plaats van
     doorgroeien. Nagemeten op 20 augustus 2026: zonder deze grens werd hij
     468px hoog op een scherm van 812. */
  max-height: min(340px, 50vh);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-sm) var(--space-md);
  background: var(--dark-bg);
  color: rgba(255,255,255,.9);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg);
  font-size: 0.85rem;
  line-height: 1.5;
  letter-spacing: 0;
  text-transform: none;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease), visibility var(--dur-fast);
}
/* Tonen bij hover (muis) en bij toetsenbordfocus. Klikken met de muis laat de
   tekstbox bewust NIET vaststaan; op aanraakschermen schakelt .is-open hem via
   JavaScript, omdat daar geen hover bestaat. */
.claim-info.is-open .claim-info__panel,
.claim-info__btn:focus-visible + .claim-info__panel {
  opacity: 1; visibility: visible; transform: translateY(0);
}
@media (hover: hover) {
  .claim-info:hover .claim-info__panel { opacity: 1; visibility: visible; transform: translateY(0); }
}

/* De onderdelen krijgen door de scroll-reveal een transform en daarmee een
   eigen stapelcontext. Zonder deze regel valt de tekstbox achter de buur. */
.grid-4 > .card { position: relative; }
/* :has() dekt ook het openen via een tik op een aanraakscherm, waar
   JavaScript .is-open zet en er dus geen hover en soms geen focus is. */
.grid-4 > .card:hover,
.grid-4 > .card:focus-within,
.grid-4 > .card:has(.claim-info.is-open) { z-index: 30; }
/* Bij de laatste twee rechts uitlijnen, zodat de tekstbox niet buiten beeld valt.
   Geldt alleen voor de gewone kaarten; in de impactkaarten vult de box de
   hele kaart, zie de regels daar. */
.grid-4 > .card:nth-child(n+3) .claim-info__panel { left: auto; right: -8px; }
/* Gestapeld: anker de tekstbox aan de labelregel in plaats van aan de knop,
   zodat hij altijd binnen het onderdeel en dus binnen het scherm blijft. */
@media (max-width: 900px) {
  .claim-head { position: relative; }
  .claim-info { position: static; }
  .grid-4 > .card:nth-child(n+3) .claim-info__panel { left: 0; right: 0; }
  .claim-info__panel { left: 0; right: 0; width: auto; max-width: none; }
}

/* ---- Kleurswitch (product swatches) ---- */
.product-swatches {
  position: absolute;
  bottom: var(--space-sm);
  right: var(--space-sm);
  display: flex;
  gap: 6px;
  background: var(--white);
  padding: 5px;
  border-radius: var(--radius-pill);
  border: var(--border);
  box-shadow: var(--shadow-sm);
}
/* De bol blijft 20px: groter maken haalt de kleurwisselaar visueel uit balans
   naast de render. Het aanraakdoel moet wel 24 bij 24 zijn volgens WCAG 2.2, en
   dat lost ::after op met een onzichtbaar vlak eromheen. Zo blijft de rand van
   de zwarte variant hieronder gewoon om de bol staan en niet om het raakgebied. */
.swatch {
  position: relative;
  width: 20px;
  height: 20px;
  padding: 0;
  border-radius: 50%;
  border: 1.5px solid var(--line);
  background: #fff;
  cursor: pointer;
  transition: box-shadow var(--dur-fast) var(--ease);
}
.swatch::after { content: ""; position: absolute; inset: -2px; border-radius: 50%; }
.swatch[data-color="zwart"] { background: #111; border-color: #111; }
.swatch.is-active { box-shadow: 0 0 0 2px var(--white), 0 0 0 4px var(--primary); }
.swatch:hover { box-shadow: 0 0 0 2px var(--white), 0 0 0 4px var(--line); }
.swatch.is-active:hover { box-shadow: 0 0 0 2px var(--white), 0 0 0 4px var(--primary); }

.audience-card { display: flex; flex-direction: column; gap: var(--space-sm); }
.audience-card .eyebrow { margin-bottom: 0; }

/* ---- Numbered steps (real sequence) ---- */
.steps { display: grid; gap: 0; counter-reset: step; }
.step {
  display: grid;
  grid-template-columns: 88px 1fr;
  gap: var(--space-lg);
  padding-block: var(--space-lg);
  border-top: var(--border);
}
.steps .step:last-child { border-bottom: var(--border); }
.step__num { font-family: var(--font-display); font-weight: 600; font-size: 0.95rem; color: var(--primary); padding-top: 0.2em; }
.step__body h3 { font-size: var(--step-h5); font-weight: 600; margin-bottom: 0.4em; }
.step__body p { color: var(--ink-soft); max-width: 60ch; }

@media (max-width: 640px) {
  .step { grid-template-columns: 1fr; gap: var(--space-2xs); }
}

/* Stappen met bewegend beeld: drie kaarten naast elkaar, zodat de hele
   volgorde in één oogopslag zichtbaar is zonder te scrollen. */
.steps--media {
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-lg);
}
.steps--media .step {
  display: flex;
  flex-direction: column;
  gap: 0;
  padding-block: 0;
  background: var(--white);
  border: var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.steps--media .step:last-child { border-bottom: var(--border); }
.steps--media .step__num { padding: var(--space-md) var(--space-lg) var(--space-3xs); }
.steps--media .step__body { padding: 0 var(--space-lg) var(--space-lg); }
.steps--media .step__body p { max-width: none; }

/* Beeld bovenaan de kaart; vierkant, gelijk aan de bronverhouding zodat er
   niets wordt afgesneden. */
.step__media {
  order: -1;
  width: 100%;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  background: var(--sky-tint);
}
.step__media video,
.step__media img { width: 100%; height: 100%; object-fit: cover; display: block; }

@media (max-width: 900px) {
  .steps--media { grid-template-columns: 1fr; gap: var(--space-md); }
  .step__media { aspect-ratio: 16 / 10; }
}

/* ---- Spec sheet ---- */
/* De specificaties zitten achter een uitklapper. Zelfde vormentaal als de FAQ,
   maar op een lichte achtergrond en met een tabel als inhoud. Bewust met
   <details> en niet met eigen JavaScript: het werkt zo ook zonder scripts, en
   toetsenbord en schermlezer krijgen het gedrag van de browser mee. */
.spec-toggle {
  background: var(--white);
  border: var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.spec-toggle > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  padding: var(--space-md) var(--space-lg);
  font-family: var(--font-display);
  /* Zelfde gewicht als de vragen in de FAQ; die twee horen bij elkaar. */
  font-weight: 400;
  font-size: var(--step-h6);
  color: var(--ink);
  cursor: pointer;
  /* Het standaard driehoekje weg; we tekenen zelf een pijl. */
  list-style: none;
}
.spec-toggle > summary::-webkit-details-marker { display: none; }
.spec-toggle > summary:hover { color: var(--primary); }
.spec-toggle__chevron {
  flex: none;
  width: 20px;
  height: 20px;
  color: var(--primary);
  transition: transform var(--dur-fast) var(--ease);
}
.spec-toggle[open] .spec-toggle__chevron { transform: rotate(180deg); }

.spec-sheet {
  background: var(--white);
  border: var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
}
/* Binnen de uitklapper zitten de rand en de radius al op de details eromheen.
   De eerste rij krijgt wel een lijn, als scheiding met de knopregel erboven. */
.spec-toggle .spec-sheet { border: none; border-radius: 0; }
.spec-toggle .spec-sheet__row:first-child { border-top: var(--border); }
.spec-sheet__row {
  display: grid;
  grid-template-columns: 1fr 1.4fr;
  border-top: var(--border);
}
.spec-sheet__row:first-child { border-top: none; }
.spec-sheet__row dt {
  font-family: var(--font-body);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--ink-faint);
  padding: 0.9em 1.2em;
  border-right: var(--border);
}
.spec-sheet__row dd { margin: 0; padding: 0.9em 1.2em; color: var(--ink); font-weight: 500; }

/* ---- Logo strip ---- */
.logo-strip { display: flex; align-items: center; flex-wrap: wrap; gap: clamp(1.5rem, 4vw, 3.5rem); }
.logo-strip img { height: clamp(22px, 3vw, 32px); width: auto; filter: grayscale(1) contrast(0.9); opacity: .72; transition: opacity var(--dur-fast) var(--ease), filter var(--dur-fast) var(--ease); }
.logo-strip img:hover { filter: none; opacity: 1; }

/* ---- Langzaam scrollende logostrook (marquee), volle kleur ---- */
.logo-marquee {
  width: 100%;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
}
/* De tussenruimte zit op de logo's zelf en niet als `gap` op de strook. Dat is
   geen stijlkwestie maar de reden dat de lus rond loopt.

   De strook bevat twee identieke sets van vijf logo's en schuift per ronde
   -50% op. Met `gap` telt de strook negen tussenruimtes, dus is die helft vijf
   logo's plus vier-en-een-halve tussenruimte, terwijl één set vijf logo's plus
   vijf tussenruimtes breed is. Elke ronde kwam de strook dus een halve
   tussenruimte tekort, en dat zag je als een sprong van 20 tot 36 pixels.

   Met een marge achter elk logo, ook achter het laatste, telt de strook tien
   gelijke tussenruimtes. De helft daarvan is exact één set, en dan valt het
   zesde logo precies op de plek waar het eerste stond. */
.logo-marquee__track {
  display: flex;
  align-items: center;
  width: max-content;
  animation: logo-marquee-scroll 34s linear infinite;
}
/* Een logo dat alleen uit een beeldmerk bestaat heeft meer hoogte nodig dan
   een woordmerk om even zwaar te wegen. Een woordmerk vult zijn regel over de
   volle breedte; een vierkant of rond merk staat op dezelfde hoogte als een
   postzegel ernaast. Vandaar deze uitzondering, en niet meer dan dat: hoger
   maken dan dit laat de hele strook meegroeien. */
.logo-marquee__track img.is-beeldmerk { height: clamp(44px, 5.4vw, 62px); }

.logo-marquee__track img {
  height: clamp(32px, 4vw, 46px);
  width: auto;
  flex-shrink: 0;
  margin-inline-end: clamp(2.5rem, 5vw, 4.5rem);
}
@keyframes logo-marquee-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .logo-marquee__track { animation: none; overflow-x: auto; }
  .logo-marquee { -webkit-mask-image: none; mask-image: none; }
}

/* ---- Feature/benefit list ---- */
.check-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-sm); }
.check-list li { display: flex; gap: 0.75em; align-items: flex-start; color: var(--ink-soft); }
.check-list svg { flex-shrink: 0; margin-top: 0.2em; color: var(--primary); }

/* ---- Testimonial cards ---- */
.testimonial-card {
  margin: 0;
  background: var(--sky-tint);
  border-radius: var(--radius-md);
  padding: var(--space-lg);
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}
/* Het aanhalingsteken is een sierteken en staat daarom niet in de tekst zelf.
   De blockquote draagt de betekenis, het teken alleen het beeld. */
.testimonial-card .quote-mark { color: var(--sky-dark); flex: none; }
/* Een stap onder de bodytekst. Op body-formaat oogt een citaat in een smalle
   kaart te zwaar nu het rechtop staat en niet meer cursief is. */
.testimonial-card blockquote { margin: 0; font-size: 0.98rem; color: var(--ink); line-height: 1.65; }
/* margin-top:auto duwt de naamregel naar de onderkant, zodat de scheidslijn
   in alle drie de kaarten op dezelfde hoogte ligt ook al verschillen de
   citaten in lengte. */
.testimonial-card cite {
  font-style: normal;
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: auto;
  padding-top: var(--space-md);
  border-top: 1px solid var(--sky);
}
.testimonial-card cite strong { font-size: 0.92rem; font-weight: 700; color: var(--primary); }
.testimonial-card cite span { font-size: 0.82rem; color: var(--ink-soft); }

/* ---- Productshot ----
   Sfeerbeeld dat gedempt in een lus speelt, zonder bediening. Wordt dus als
   beeld behandeld en niet als speler: geen knoppen, geen randen, alleen de
   radius die de rest van de site ook gebruikt. */
.productshot video {
  display: block;
  width: 100%;
  /* Zoals overal: het height-attribuut in de HTML telt als opgegeven hoogte en
     zou aspect-ratio anders buitenspel zetten. */
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: var(--radius-md);
  background: var(--sky-tint);
}

/* ---- Promovideo in een overlay ----
   De video staat niet meer als sectie op de pagina maar achter de knop in de
   hero. Dat scheelt de bezoeker die hem niet wil zien alles: met preload="none"
   gaat er geen byte video over de lijn tot er geklikt wordt.

   De maat is zo groot als past. width rekent uit hoe breed het venster mag zijn
   om binnen 86vh te blijven bij een verhouding van 16 op 9, en neemt daarvan of
   van 94vw de kleinste. Zo vult hij het scherm zonder ooit af te snijden of te
   letterboxen, op elk schermformaat. */
.video-dialoog {
  border: 0;
  padding: 0;
  background: transparent;
  overflow: visible;
  width: min(94vw, calc(86vh * 16 / 9));
  max-width: none;
}
.video-dialoog::backdrop { background: rgba(11, 11, 26, .84); }
.video-dialoog__video {
  display: block;
  width: 100%;
  /* Net als elders: het height-attribuut in de HTML telt als opgegeven hoogte
     en zou aspect-ratio buitenspel zetten. */
  height: auto;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-md);
  background: #000;
}
.video-dialoog__sluiten {
  position: absolute;
  top: -3rem;
  right: 0;
  width: 2.5rem;
  height: 2.5rem;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, .12);
  color: #fff;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease);
}
.video-dialoog__sluiten:hover,
.video-dialoog__sluiten:focus-visible { background: rgba(255, 255, 255, .26); }
.video-dialoog__sluiten svg { width: 20px; height: 20px; }
/* Op een laag scherm past de knop er niet boven; dan naar binnen. */
@media (max-height: 560px), (max-width: 560px) {
  .video-dialoog__sluiten { top: 0.6rem; right: 0.6rem; background: rgba(11, 11, 26, .6); }
}

/* ---- <picture> om afbeeldingen ----
   build.py verpakt elke afbeelding in een <picture> met een AVIF- en een
   WebP-bron. Zonder deze regel verandert dat de opmaak: waar de ouder een flex-
   of grid-container is, wordt niet meer het beeld maar die <picture> het item,
   en dan hebben regels als `.product-stage img { max-height: 100% }` niets meer
   om op te werken. `display: contents` laat het element zelf uit de opmaak
   verdwijnen en zet het beeld weer op zijn oude plek in de boom.

   Haal deze regel dus niet weg omdat hij er overbodig uitziet. */
picture { display: contents; }

/* En deze er direct achteraan, want `display: contents` haalt niet alleen de
   <picture> uit de opmaak maar zet ook zijn kinderen erin. De regel op regel 28
   maakt van elke <img> een blok, en de browser trekt dat hier door naar de
   <source>-elementen. In een grid werden dat dus twee extra rasteritems.

   Zichtbaar geworden op Over ons: de bekersectie kreeg vier rijen in plaats van
   twee (`503px 0px 0px 620px`) en werd door de tussenruimte 192px langer. De
   rijen waren leeg, dus er was niets te zien behalve gaten. */
picture > source { display: none; }

/* ---- Bekers bij de missie op Over ons ----
   De render is uitgeknipt, dus de bekers zweven direct op de donkere band. Zet
   er geen vlak of radius omheen, dat maakt er weer een kaartje van.

   De hoogte is begrensd omdat de verhouding bijna 1 staat tot 3 is: op de volle
   kolombreedte zou de sectie ruim duizend pixels hoog worden. */
.missie-bekers {
  display: block;
  max-height: 620px;
  width: auto;
  max-width: 100%;
  margin-inline: auto;
}

/* ---- Beeld bij de pilotsectie ----
   Vierkant bijgesneden, zodat het naast de tekstkolom net zo oogt als de
   andere secties met tekst en beeld naast elkaar. Het uitsnedepunt ligt naar
   rechts, want daar staat het demomodel op de foto. */
.pilot-foto {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  object-position: 60% 50%;
  border-radius: var(--radius-md);
  display: block;
}

/* ---- Onderscheidingen ----
   Een vaste hoogte op het logo zelf werkt hier niet. Een compact schild weegt
   op dezelfde hoogte optisch veel zwaarder dan een breed woordmerk, en de drie
   merken brengen ook nog eens drie vreemde kleurpaletten mee die met elkaar en
   met het indigo van de site vechten. Daar komt bij dat elk logo de awardnaam
   al in beeld draagt, terwijl die er in de kop eronder nog een keer staat.

   Vandaar dit blok: klein gehouden en op een vaste hoogte, zodat de tekst in
   alle drie de kaarten op dezelfde hoogte begint ook als een logo later een
   andere verhouding heeft. Het beeld bevestigt, de tekst vertelt. Bewust geen
   achtergrondvlak eromheen; dat is geprobeerd en het werd te veel kader. */
.award-card { display: flex; flex-direction: column; }
.award-card__mark {
  display: grid;
  place-items: center;
  height: 56px;
  margin-bottom: var(--space-md);
}
.award-card__logo {
  max-height: 56px;
  max-width: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}
/* De koppen verschillen in lengte: die van Vebego loopt over twee regels, de
   andere twee over één. Zonder dit eindigt de ene kaart met tekst tot onderaan
   en houden de andere twee ruimte over. margin-top:auto duwt het tekstblok
   omlaag zodat alle drie onderaan gelijk eindigen, net als de naamregel in de
   klantcitaten. */
.award-card .eyebrow { margin-top: auto; }

/* ---- Contactblok met stappenlijst ---- */
.contact-block {
  display: grid;
  grid-template-columns: 6fr 5fr;
  gap: var(--space-2xl);
  align-items: start;
}
@media (max-width: 980px) {
  .contact-block { grid-template-columns: 1fr; gap: var(--space-xl); }
  /* Gestapeld eerst de uitleg en dan pas het formulier. Stond andersom, met
     als redenering dat het formulier de hoofdactie is. Op 18 augustus 2026
     teruggedraaid: op een telefoon zag je vier lege invoervelden voordat er
     iets stond over waaróm je ze zou invullen, en dat is precies de volgorde
     waarin niemand een formulier invult. */
}

/* Ons verhaal op Over ons: aanhef links, de stappen rechts. Zelfde verdeling
   als de FAQ. Eerder stond alles in één kolom van 760px tegen de linkerrand,
   waardoor er in een container van 1280px ruim 40% leeg bleef. */
.verhaal-layout {
  display: grid;
  grid-template-columns: 5fr 7fr;
  gap: var(--space-2xl);
  align-items: start;
}
.verhaal-layout .section-head { margin-bottom: 0; }
@media (max-width: 900px) {
  .verhaal-layout { grid-template-columns: 1fr; gap: var(--space-lg); }
}

.process-list { display: flex; flex-direction: column; gap: var(--space-lg); }
.process-step { display: grid; grid-template-columns: 40px 1fr; gap: var(--space-md); align-items: start; }

/* Als tijdlijn: een lijn van de ene bol naar de volgende, zodat de vier stappen
   als één verhaal lezen in plaats van als vier losse punten. Alleen met deze
   modifier, want de stappenlijst bij het contactformulier is geen chronologie.

   De lijn moet absoluut staan. Een pseudo-element in een grid wordt anders zelf
   een rastervak, en dan schuift de tekst een kolom op. */
.process-list--tijdlijn .process-step { position: relative; }
.process-list--tijdlijn .process-step:not(:last-child)::before {
  content: "";
  position: absolute;
  left: 19px;
  top: 44px;
  bottom: calc(-1 * var(--space-lg));
  width: 2px;
  background: var(--line);
}
.process-step__num {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--primary);
  color: var(--ink-invert);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.95rem;
}
.process-step h3 { font-size: var(--step-h6); margin-bottom: 0.35em; }
.process-step p { color: var(--ink-soft); }

/* ---- Veelgestelde vragen ----
   Gebouwd op <details>, dus het open- en dichtklappen werkt zonder
   JavaScript en een schermlezer kondigt de toestand vanzelf aan. */
/* Twee kolommen: de aanhef links, de vragen rechts. */
.faq-layout {
  display: grid;
  grid-template-columns: 5fr 7fr;
  gap: var(--space-2xl);
  align-items: start;
}
@media (max-width: 980px) {
  .faq-layout { grid-template-columns: 1fr; gap: var(--space-xl); }
}
.faq-layout .section-head { margin-bottom: 0; }

.faq { max-width: var(--container-narrow); border-top: var(--border); }
.faq-layout .faq { max-width: none; }
.faq__item { border-bottom: var(--border); }
.faq__item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  padding-block: var(--space-md);
  font-family: var(--font-display);
  /* Bewust licht. De vragen staan op een donkere band, en daar oogt tekst
     optisch zwaarder dan op licht: op 600 werden het koppen die met de
     sectiekop concurreerden. De kopfunctie komt hier van de grootte en de
     witte kleur, niet van het gewicht. */
  font-weight: 400;
  font-size: var(--step-h6);
  color: var(--ink);
  cursor: pointer;
  /* Het standaard driehoekje weg; we tekenen zelf een pijl. */
  list-style: none;
}
.faq__item summary::-webkit-details-marker { display: none; }
.faq__item summary:hover { color: var(--primary); }
.faq__chevron {
  flex: none;
  width: 20px;
  height: 20px;
  color: var(--primary);
  transition: transform var(--dur-fast) var(--ease);
}
.faq__item[open] .faq__chevron { transform: rotate(180deg); }
.faq__answer { padding-bottom: var(--space-md); color: var(--ink-soft); max-width: 62ch; }
.faq__answer p + p { margin-top: var(--space-sm); }
.faq__answer a { color: var(--primary); text-decoration: underline; }

/* Op de donkere band: lijnen, tekst en links omdraaien. Het merkpaars is op
   deze achtergrond onleesbaar, daarvoor in de plaats komt het zachtblauw dat
   op donkere secties ook de labels kleurt. */
.section--dark .faq { border-top-color: var(--dark-line); }
.section--dark .faq__item { border-bottom-color: var(--dark-line); }
.section--dark .faq__item summary { color: var(--ink-invert); }
.section--dark .faq__item summary:hover { color: var(--sky); }
.section--dark .faq__chevron { color: var(--sky); }
.section--dark .faq__answer { color: var(--dark-text-soft); }
.section--dark .faq__answer a { color: var(--sky); }

/* ---- Blueprint texture (technical sections) ---- */
.blueprint {
  position: relative;
  background-color: var(--dark-bg);
  background-image:
    linear-gradient(rgba(255,255,255,.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.05) 1px, transparent 1px);
  background-size: 40px 40px;
}

/* ---- CTA band ---- */
.cta-band { display: flex; align-items: center; justify-content: space-between; gap: var(--space-lg); flex-wrap: wrap; }

/* ---- Breadcrumb ---- */
/* Geen hoofdletters. Het meest gebruikte kleine label op de site is .eyebrow,
   93 keer, en die staat in gewone schrijfwijze. Op de brochurepagina stonden ze
   pal boven elkaar: "BROCHURE" in het kruimelpad en "Brochure" als eyebrow
   eronder. Hetzelfde woord twee keer, één keer geschreeuwd.

   De letterafstand kan daarmee ook terug naar normaal: die 0,04em zat er omdat
   hoofdletters optisch dichter op elkaar kruipen dan onderkast. In gewone
   schrijfwijze maakt het de regel juist los. */
.breadcrumb { display: flex; gap: 0.5em; font-family: var(--font-body); font-size: 0.82rem; color: var(--ink-faint); flex-wrap: wrap; }
.breadcrumb a:hover { color: var(--primary); }
.breadcrumb .sep { color: var(--line); }

/* ---- Form ---- */
/* min-width: 0 op de hele keten van het formulier. Een raster- of flexonderdeel
   krijgt standaard `min-width: auto`, en dat betekent: word nooit smaller dan je
   inhoud nodig heeft. Een invoerveld brengt daar zijn eigen voorkeursbreedte in
   mee, en die telde hier op tot 265px. Plus de binnenmarge van de kaart kwam de
   contactkaart daarmee op 347px, terwijl er op een telefoon 335px is. De kaart
   stak dus 12px buiten de rooilijn.
   Met deze regel krimpt de keten netjes mee en past alles binnen de kolom. */
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-md); min-width: 0; }
.form-grid > *, .field input, .field select, .field textarea { min-width: 0; }
.field { display: flex; flex-direction: column; gap: 0.45em; min-width: 0; }
.field--full { grid-column: 1 / -1; }
.field label { font-size: 0.85rem; font-weight: 600; color: var(--ink); }
.field .hint { font-size: 0.78rem; color: var(--ink-faint); }
.field input, .field select, .field textarea {
  font-family: var(--font-body);
  font-size: 1rem;
  padding: 0.85em 1em;
  border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--white);
  color: var(--ink);
  transition: border-color var(--dur-fast) var(--ease);
}
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--primary); }
.field input:invalid[data-touched="true"], .field textarea:invalid[data-touched="true"] { border-color: var(--error); }
.field textarea { resize: vertical; min-height: 110px; }
.field-error { font-size: 0.8rem; color: var(--error); display: none; }
.field.has-error .field-error { display: block; }
.field.has-error input, .field.has-error textarea, .field.has-error select { border-color: var(--error); }

/* De marge naar boven hoort hier en niet als hulpklasse in de opmaak: dit blok
   staat er standaard op display:none en verschijnt pas na het verzenden. Zonder
   die marge plakt de melding tegen de verzendknop zodra hij opduikt, en dat
   zie je niet bij het bouwen van de pagina maar alleen na een echte inzending.

   Een marge op een element met display:none doet niets, dus hij kan gewoon in
   de basisregel staan. */
.form-status { margin-top: var(--space-md); padding: var(--space-md); border-radius: var(--radius-sm); font-size: 0.95rem; display: none; }
.form-status.is-success { display: block; background: #E9F5EE; color: var(--success); border: 1px solid #BFE3CC; }
.form-status.is-error { display: block; background: #FBEAE5; color: var(--error); border: 1px solid #F1C3B5; }
.form-status.is-busy { display: block; background: var(--sky-tint); color: var(--ink-faint); border: 1px solid var(--line); }

/* Honeypot. Bewust geen display:none of visibility:hidden, want een deel van
   de bots slaat velden met die eigenschappen over. Uit de tabvolgorde en uit
   de toegankelijkheidsboom gehaald, zodat een mens het veld nooit tegenkomt. */
.hp-veld { position: absolute; left: -9999px; top: auto; width: 1px; height: 1px; overflow: hidden; }

.btn[aria-busy="true"] { opacity: 0.7; cursor: progress; }

@media (max-width: 640px) { .form-grid { grid-template-columns: 1fr; } }

/* ---- Footer ---- */
.site-footer { background: var(--dark-bg); color: var(--dark-text-soft); }
.site-footer a:hover { color: #fff; }
.footer-top { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr; gap: var(--space-xl); padding-block: var(--space-2xl); border-bottom: 1px solid var(--dark-line); }
/* De ondermarge was weg toen de tagline eronder verdween. Nu staan de sociale
   iconen daar, dus hij is terug, wel kleiner: onder het logo hoeft er minder
   lucht dan onder een alinea tekst. */
.footer-brand img { height: 22px; width: auto; margin-bottom: var(--space-sm); }
/* Geen hoofdletters meer, net als bij het kruimelpad en de eyebrow. Het
   verschil met de links eronder komt nu van het gewicht en de kleur: 600 in
   wit tegenover 400 in gedempt wit. Dat is genoeg om als kop te lezen zonder
   dat er een tweede signaal bij hoeft.

   Dezelfde grootte als de links eronder. Kleiner maken zou de kop optisch
   ondergeschikt maken aan wat eronder staat, en dat is precies verkeerd om.
   De letterafstand kon weg: die zat er alleen voor de hoofdletters. */
.footer-col__titel { font-family: var(--font-body); font-size: 0.92rem; font-weight: 600; color: #fff; margin-bottom: var(--space-sm); }
.footer-col ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.6em; font-size: 0.92rem; }
/* ---- Sociale kanalen onderin de voettekst ----
   Het raakgebied is 40 bij 40, ruim boven de 24 die WCAG 2.2 vraagt, want
   onderin een voettekst op een telefoon is dat het verschil tussen raak en
   mis. Het icoon zelf blijft 20px.

   Bewust geen target="_blank": de rest van de site doet dat ook niet, en een
   nieuw tabblad opdringen aan iemand die er zelf een had kunnen openen is een
   keuze die je voor hem maakt. */
/* Onder het logo in de merkkolom, niet in de onderste balk. Daar stonden ze
   eerst, en die balk trekt met space-between drie blokken uit elkaar; de iconen
   kwamen daardoor los midden tussen de KvK-gegevens en de privacylink te
   hangen. Boven bij het logo hoort het bij het merk, en die kolom stond sinds
   het weghalen van de tagline half leeg.

   De negatieve marge links zet het eerste icoon optisch op de rooilijn van het
   logo: het raakgebied is breder dan het icoon zelf. */
.sociaal-groep { display: flex; gap: var(--space-xs); margin-left: -10px; }
.sociaal {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  color: var(--dark-text-soft);
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.sociaal:hover { color: #fff; background: rgba(255,255,255,.08); }

.footer-bottom { display: flex; justify-content: space-between; align-items: center; padding-block: var(--space-md); font-size: 0.82rem; flex-wrap: wrap; gap: var(--space-sm); }
/* De bedrijfsgegevens links bij elkaar, zodat de privacylink rechts blijft
   staan hoeveel er ook bij komt. Zonder dit groepje zou space-between elk
   gegeven apart uit elkaar trekken. */
.footer-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-sm) var(--space-md); }

@media (max-width: 900px) {
  .footer-top { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 560px) {
  .footer-top { grid-template-columns: 1fr; }
}

/* ---- Reveal on scroll ----
   De trapsgewijze vertraging loopt via een eigen variabele en niet via
   transition-delay. Kaarten met .hover-lift schrijven hun eigen transition
   voor de muisreactie, en een losse transition-delay zou daar ook op vallen:
   de vierde kaart in een rij kwam dan pas een vijfde seconde na de muis
   omhoog. */
[data-reveal] {
  --reveal-delay: 0ms;
  opacity: 0;
  transform: translateY(18px);
  transition: opacity var(--dur-slow) var(--ease) var(--reveal-delay),
              transform var(--dur-slow) var(--ease) var(--reveal-delay);
}
[data-reveal].is-visible { opacity: 1; transform: translateY(0); }
[data-reveal="1"] { --reveal-delay: 60ms; }
[data-reveal="2"] { --reveal-delay: 140ms; }
[data-reveal="3"] { --reveal-delay: 220ms; }

/* ---- Kaarten die op de muis reageren ----
   Zit op kaarten met een eigen vlak: de productkaarten, de onderscheidingen,
   de klantcitaten en de kaarten met een icoon. Bewust niet op de cijferkaarten
   met een info-icoon: daar mikt de bezoeker op een knopje van nog geen 20 px en
   dan is een kaart die wegschuift alleen maar lastig.

   Deze regel moet ná het blok hierboven staan. Beide selectors wegen even zwaar
   en de laatste wint, en de transition hieronder is de enige die ook de vier
   eigenschappen van de muisreactie dekt. */
.hover-lift {
  transition:
    translate var(--dur-fast) var(--ease),
    scale var(--dur-fast) var(--ease),
    box-shadow var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease),
    opacity var(--dur-slow) var(--ease) var(--reveal-delay, 0ms),
    transform var(--dur-slow) var(--ease) var(--reveal-delay, 0ms);
}
/* translate en scale, niet transform. Dat is hier geen smaakkwestie: de
   scroll-reveal hierboven gebruikt transform al, en een transform op hover zou
   die overschrijven. De losse eigenschappen stapelen er juist bovenop. */
@media (hover: hover) {
  .hover-lift:hover {
    translate: 0 -4px;
    scale: 1.008;
    box-shadow: var(--shadow-md);
    border-color: var(--sky);
  }
}
/* Ook bij toetsenbordgebruik, zodra iets in de kaart focus krijgt. Hier
   :has(:focus-visible) en niet :focus-within: een kleurstaal in de
   productkaart houdt na een muisklik de focus vast, en met :focus-within bleef
   de kaart daarna omhoog staan terwijl de muis er allang weg was.
   Kaarten zonder link of knop erin bereiken dit nooit en blijven dus stil. */
.hover-lift:has(:focus-visible) {
  translate: 0 -4px;
  scale: 1.008;
  box-shadow: var(--shadow-md);
  border-color: var(--sky);
}
/* Bij voorkeur voor minder beweging blijft de kaart staan. De schaduw en de
   lijn doen dan het werk, zodat de aanwijzing niet verdwijnt. */
@media (prefers-reduced-motion: reduce) {
  .hover-lift:hover,
  .hover-lift:has(:focus-visible) { translate: none; scale: none; }
}

/* ---- Utility ---- */
.text-center { text-align: center; }
.mx-auto { margin-inline: auto; }
.mt-sm { margin-top: var(--space-sm); }
.mt-md { margin-top: var(--space-md); }
.mt-lg { margin-top: var(--space-lg); }
.mt-xl { margin-top: var(--space-xl); }
.mb-sm { margin-bottom: var(--space-sm); }
.mb-md { margin-bottom: var(--space-md); }
.mb-lg { margin-bottom: var(--space-lg); }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; }
.skip-link { position: absolute; left: -999px; top: 0; background: var(--primary); color: #fff; padding: 0.8em 1.2em; z-index: 200; border-radius: 0 0 6px 0; }
.skip-link:focus { left: 0; }
