/* ==========================================================================
   ARTIFEX DIGITAL — basisstijlen
   Taak 3: design-tokens, typografie, sectie-flow-basis, preloader.
   Taak 4: definitief merk — goud-accent (#B8912B), Playfair Display-koppen,
   merkteken/vonk-verwerking, sectie-kleuromslag (licht-gedomineerd).
   ========================================================================== */

/* ------------------------- @font-face (self-hosted) ---------------------- */

@font-face {
  font-family: 'Archivo';
  src: url('/assets/fonts/archivo-v25-latin-regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Archivo';
  src: url('/assets/fonts/archivo-v25-latin-700.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Archivo';
  src: url('/assets/fonts/archivo-v25-latin-900.woff2') format('woff2');
  font-weight: 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Space Mono';
  src: url('/assets/fonts/space-mono-v17-latin-regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Space Mono';
  src: url('/assets/fonts/space-mono-v17-latin-700.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Playfair Display';
  src: url('/assets/fonts/playfair-display-v40-latin-700.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* --------------------------------- Tokens --------------------------------- */

:root {
  /* Kleur */
  --kleur-inkt: #0d0d0b;
  --kleur-papier: #f4f1e8;
  --kleur-accent: #B8912B; /* definitief — goedgekeurd merk Taak 4; vonk/graphics + alles op donker */
  --kleur-accent-tekst: #836128; /* donkerder goud (portrettenpalet) — tekst/focus op licht, FIX 07-08, T15-contrastfix:
     #8d6b2e mat 4.35:1 op --kleur-papier (net onder WCAG AA 4.5:1 voor kleine 12px mono-labels) —
     #836128 haalt 5.02:1, zelfde tint, nauwelijks zichtbaar donkerder. */
  --kleur-inkt-vervaagd: rgba(13, 13, 11, 0.62);
  --kleur-papier-vervaagd: rgba(244, 241, 232, 0.66);
  --kleur-neon: #3BE8FF; /* taak-v4: elektrisch blauw voor de #personeel-circuitbanen/pulsen/
     knooppunten (gallery.js "tekenLijnen") — bewust op ÉÉN token gezet: wissel de hele
     netwerk-kleur (bv. naar groen) door alleen deze regel te wijzigen. Chips/scanner/tekst
     in #personeel blijven de bestaande inkt/goud-taal, alleen de verbindingen zijn neon. */

  /* Typografie */
  --font-display: 'Archivo', 'Helvetica Neue', Arial, sans-serif;
  --font-mono: 'Space Mono', 'SFMono-Regular', Consolas, monospace;
  --font-serif: 'Playfair Display', serif;
  --type-hero: clamp(3rem, 12vw, 11rem);
  --type-kop: clamp(2rem, 6vw, 5rem);
  --type-body: clamp(1rem, 0.85rem + 0.6vw, 1.25rem);
  --type-label: 0.75rem;

  /* Ruimte & beweging */
  --ruimte-sectie: clamp(4rem, 12vw, 9rem);
  --ruimte-container: clamp(1.25rem, 6vw, 5rem);
  --ruimte-overlap: clamp(1.5rem, 5vw, 4rem);
  --duur-kort: 0.25s;
  --duur-lang: 0.6s;
  --easing: cubic-bezier(0.16, 1, 0.3, 1);
}

/* ---------------------------------- Reset ---------------------------------- */

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

html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
html, body { height: 100%; }
body { overflow-x: hidden; }

body {
  font-family: var(--font-display);
  font-size: var(--type-body);
  line-height: 1.5;
  background: var(--kleur-papier);
  color: var(--kleur-inkt);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img, svg, video { display: block; max-width: 100%; }
ul, ol { list-style: none; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }

h1, h2, h3, h4 {
  line-height: 1.05;
  overflow-wrap: break-word;
  word-break: break-word;
}
h1, h2 {
  font-family: var(--font-serif);
  font-weight: 700;
}
h3, h4 {
  font-family: var(--font-display);
  font-weight: 900;
}

p { max-width: 60ch; }

/* Focus & selectie */
:focus { outline: none; }
:focus-visible {
  outline: 3px solid var(--kleur-accent-tekst);
  outline-offset: 2px;
}
/* Op permanent donkere vlakken (nav, .sectie--donker, footer) is donkergoud te
   weinig te onderscheiden van de achtergrond — daar blijft de heldere accent. */
header[data-nav] :focus-visible,
.sectie--donker :focus-visible,
footer#contact :focus-visible {
  outline-color: var(--kleur-accent);
}
::selection {
  background: var(--kleur-accent);
  color: var(--kleur-inkt);
}

/* ------------------------------- Preloader -------------------------------- */

#preloader {
  position: fixed;
  inset: 0;
  z-index: 999;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.5rem;
  background: var(--kleur-papier);
  color: var(--kleur-inkt);
}

#preloader .mono-label { color: var(--kleur-inkt); }

/* CSS-vangnet, onafhankelijk van JS (eindreview, punt 1): als main.js om wat voor reden dan
   ook niet draait (404, syntaxfout, geblokkeerde module-scripts), blijft #preloader anders
   permanent op scherm staan — position:fixed; inset:0 dekt de hele pagina af: geen nav, geen
   content, geen scroll. Deze animatie verbergt 'm na 4,4s (ruim voorbij de ~1,4s die de
   JS-fade-out normaal duurt) ook zónder JS. Als JS wél draait, wint hij sowieso eerder:
   preloader.remove() haalt het element allang eerder uit de DOM. */
@keyframes preloader-vangnet { to { visibility: hidden; pointer-events: none; } }
#preloader { animation: preloader-vangnet 0.01s 4.4s forwards; }

.preloader__mark {
  position: relative;
  width: clamp(84px, 16vw, 132px);
}
.preloader__merkteken {
  width: 100%;
  height: auto;
  opacity: 0; /* JS fadet in (0→1); voorkomt een flits vóór het script draait */
}
.preloader__vonk {
  position: absolute;
  /* Gecentreerd op de apex-chip van het merkteken: chip-centrum ligt op
     x=50%/y≈20,74% en chip-breedte ≈20,8% binnen de merkteken-viewBox
     (30 6 500 434) — zie merkteken.svg. JS zet xPercent/yPercent -50 zodat
     dit punt het echte centrum van de vonk wordt, niet de linkerbovenhoek. */
  left: 50%;
  top: 20.74%;
  width: 20.8%;
  opacity: 0;
  pointer-events: none;
}

/* --------------------------------- Navigatie ------------------------------- */

header[data-nav] {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--kleur-inkt);
  color: var(--kleur-papier);
  border-bottom: 2px solid var(--kleur-accent);
}

.nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1.25rem;
  padding: 1rem clamp(1rem, 4vw, 2.5rem);
}

.nav__logo-link {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
}
.nav__logo-mark {
  height: 34px;
  width: auto;
  flex-shrink: 0;
}
.nav__logo-word {
  font-family: var(--font-serif);
  font-weight: 700;
  font-size: clamp(1rem, 2vw, 1.35rem);
  letter-spacing: 0.04em;
  white-space: nowrap;
}
.nav__logo-i {
  position: relative;
  display: inline-block;
}
.nav__logo-vonk {
  position: absolute;
  top: -0.20em;
  left: 50%;
  width: 0.30em;
  height: auto;
  transform: translateX(-50%);
  pointer-events: none;
}

.nav__links {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(0.6rem, 2vw, 2rem);
  font-family: var(--font-mono);
  font-size: clamp(0.68rem, 1.4vw, 0.8rem);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.nav__links a {
  position: relative;
  display: inline-block;
  padding-bottom: 0.2rem;
  transition: color var(--duur-kort) ease;
}
.nav__links a::after {
  content: '';
  position: absolute;
  left: 0;
  right: 100%;
  bottom: 0;
  height: 2px;
  background: var(--kleur-accent);
  transition: right var(--duur-kort) var(--easing);
}
.nav__links a:hover,
.nav__links a:focus-visible { color: var(--kleur-accent); }
.nav__links a:hover::after,
.nav__links a:focus-visible::after { right: 0; }

.nav__sound {
  width: 2.25rem;
  height: 2.25rem;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid currentColor;
  border-radius: 999px;
  font-size: 1rem;
  transition: background var(--duur-kort) ease, color var(--duur-kort) ease;
}

/* Taalknop (11-08). Ryan: "als de site 2talig is waarom is er geen omschakel knop van taal" --
   hij stond alleen in de footer. Zelfde vorm en randen als .nav__sound ernaast, zodat de balk
   één geheel blijft; alleen de inhoud is tekst (NL/EN) in plaats van een pictogram. */
.nav__taal {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.4rem;
  padding: 0 0.5rem;
  height: 2.4rem;
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 999px;
  color: inherit;
  text-decoration: none;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  transition: border-color 0.2s ease, background-color 0.2s ease;
}

.nav__taal:hover,
.nav__taal:focus-visible {
  border-color: var(--goud, #B8912B);
  background: rgba(184, 145, 43, 0.12);
}
.nav__sound:hover,
.nav__sound:focus-visible {
  background: var(--kleur-accent);
  color: var(--kleur-inkt);
}
.nav__sound[aria-pressed="true"] { background: var(--kleur-accent); color: var(--kleur-inkt); }

.nav__acties {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-shrink: 0;
}

/* Eindreview, punt 11: zakelijke mailto-contactknop, altijd bereikbaar in de sticky nav
   (i.p.v. pas ná doorscrollen naar de footer). Zelfde border/hover-taal als .nav__sound
   hiernaast, zodat de twee als één actie-cluster ogen. */
.nav__contact {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.5rem 1rem;
  border: 1px solid currentColor;
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: clamp(0.68rem, 1.4vw, 0.8rem);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: background var(--duur-kort) ease, color var(--duur-kort) ease;
}
.nav__contact:hover,
.nav__contact:focus-visible {
  background: var(--kleur-accent);
  color: var(--kleur-inkt);
}
/* Op smalle schermen alleen het icoon — anders valt de nav om (spec-eis, punt 11). De
   volledige tekst blijft beschikbaar voor screenreaders via aria-label op .nav__contact. */
@media (max-width: 700px) {
  .nav__contact-label { display: none; }
  .nav__contact { padding: 0.5rem; }
}

/* ---------------------------- Sectie-flow-basis ---------------------------- */

main > section,
footer#contact {
  padding: var(--ruimte-sectie) var(--ruimte-container);
  position: relative;
}

.sectie--donker { background: var(--kleur-inkt); color: var(--kleur-papier); }
.sectie--licht { background: var(--kleur-papier); color: var(--kleur-inkt); }

main > section h2 {
  font-size: var(--type-kop);
  margin-bottom: 1.5rem;
}

#hero {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1.5rem;
  padding-inline: clamp(1rem, 4vw, 2.5rem);
}
#hero h1 {
  font-size: var(--type-hero);
  letter-spacing: -0.03em;
  max-width: 100%;
}
#hero p {
  font-family: var(--font-mono);
  font-size: clamp(1rem, 2vw, 1.4rem);
  max-width: 42ch;
  opacity: 0.85;
}

.hero__frame {
  position: absolute;
  left: clamp(2rem, 6vw, 4rem);
  bottom: clamp(4rem, 10vw, 6rem);
  opacity: 0.4;
  pointer-events: none;
  -webkit-user-select: none;
  user-select: none;
}

/* ---------------------------- Overvloeiende overgangen ---------------------- */
/* Elke sectie snijdt diagonaal over de vorige i.p.v. een harde blokgrens —
   aansluitend bij het drukwerk/doka-motief van .hoekmarkering. */
main > section + section {
  margin-top: calc(-1 * var(--ruimte-overlap));
  padding-top: calc(var(--ruimte-sectie) + var(--ruimte-overlap));
  clip-path: polygon(0 var(--ruimte-overlap), 100% 0, 100% 100%, 0 100%);
}
/* #hero behoudt zijn volledige hoekmarkering-kader: geen overlap eroverheen */
/* #verhaal is een full-width beeldvlak (Taak 8) — geen zijdelingse container-marge */
#verhaal {
  margin-top: 0;
  padding: var(--ruimte-sectie) 0;
  clip-path: none;
}

/* -------------------------------- Utilities -------------------------------- */

/* RONDE 6 (Ryan, over Producten: "de uitlijningen hier staan super scheef en ongelijk"):
   de inspringing die hier stond zette de looptekst 43px naar binnen terwijl de kop en de
   mono-regel eronder wél op de sectierand begonnen — drie verschillende linkerkanten onder
   elkaar. Dat las als slordigheid, niet als compositie. De links/rechts-afwisseling blijft
   (max-width + auto-marge doet dat werk); alleen de rafelrand is weg, zodat elk tekstblok
   dezelfde kantlijn deelt als zijn kop. */
.offset-links {
  max-width: 42rem;
  margin-right: auto;
}

.offset-rechts {
  max-width: 34rem;
  margin-left: auto;
}
@media (min-width: 768px) {
  .offset-rechts { text-align: right; }
}

.mono-label {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: var(--type-label);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* Registratie-markering (drukwerk/doka-motief), zuiver CSS, geen extra DOM */
.hoekmarkering { position: relative; }
.hoekmarkering::before {
  content: '';
  position: absolute;
  inset: clamp(1rem, 4vw, 2.5rem);
  pointer-events: none;
  opacity: 0.5;
  background-repeat: no-repeat;
  background-image:
    linear-gradient(currentColor, currentColor), linear-gradient(currentColor, currentColor),
    linear-gradient(currentColor, currentColor), linear-gradient(currentColor, currentColor),
    linear-gradient(currentColor, currentColor), linear-gradient(currentColor, currentColor),
    linear-gradient(currentColor, currentColor), linear-gradient(currentColor, currentColor);
  background-size:
    1.5rem 1px, 1px 1.5rem,
    1.5rem 1px, 1px 1.5rem,
    1.5rem 1px, 1px 1.5rem,
    1.5rem 1px, 1px 1.5rem;
  background-position:
    top left, top left,
    top right, top right,
    bottom left, bottom left,
    bottom right, bottom right;
}

/* --------------------------- Machinekamerdeur (#verhaal) --------------------------- */
/* Fotografische scène (geen aparte parallax-lagen): open scène onderin met trage
   schaal-parallax, twee dichte deurbladen erboven (barn-door, echte bg-image-helften),
   verhaal-laag (Atlas/Machinekamer/team) die pas na `deur:open` in-animeert, en 2-3
   trage gouden gloed-flikkers op "schermposities" in de scène. */

.deur-scene {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--kleur-inkt);
  /* Voorkomt dat een langgerekte sleepbeweging als native tekst-/elementselectie wordt
     opgepikt (die zou de pagina laten auto-scrollen zodra de cursor de viewport-rand nadert). */
  -webkit-user-select: none;
  user-select: none;
}
@media (max-width: 700px) {
  .deur-scene { aspect-ratio: 3 / 4; } /* mobiel: hoger uitgesneden i.p.v. brede reep */
}

/* Gedeelde zoom-laag (data-parallax-zoom): beeld + gloed + agent-ogen zitten hierbinnen en
   schalen dus altijd SAMEN mee — percentage-posities van de overlays blijven zo kloppend,
   ongeacht de scroll-gedreven scale(1 → 1.06) op deze laag. */
.deur-scene__laag {
  position: absolute;
  inset: 0;
  z-index: 0;
  will-change: transform;
}
.deur-scene__open {
  position: absolute;
  inset: 0;
}
.deur-scene__open picture,
.deur-scene__open img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Trage gouden gloed-flikker op schermposities — coördinaten afgestemd op de echte
   beeldcompositie (bureaus/monitoren links en rechts, lichtjes achterin). JS (door.js)
   start de opacity-loop en slaat dit volledig over bij reduced-motion. */
.deur-scene__gloed {
  position: absolute;
  z-index: 1;
  border-radius: 40%;
  background: radial-gradient(circle, rgba(184, 145, 43, 0.9) 0%, rgba(184, 145, 43, 0) 72%);
  mix-blend-mode: screen;
  opacity: 0.2;
  filter: blur(2px);
  pointer-events: none;
}
.deur-scene__gloed--1 { left: 20%; top: 50%; width: 15%; height: 16%; }
.deur-scene__gloed--2 { left: 42%; top: 25%; width: 19%; height: 23%; }
.deur-scene__gloed--3 { left: 61%; top: 48%; width: 15%; height: 18%; }

/* Agent-ogen — 3 agents (links-voor / midden / rechts-voor), elk 2 ogen, overlay op de
   reeds in S2-warm-donker gebakken ogen. `.agent-oog` is het donkere "masker" (kleur
   gesampled uit de kop naast de ogen van elke agent) dat het gebakken oog afdekt;
   `.agent-oog__gloei` is het nagemaakte gloei-oog erbovenop (standaard AAN — geen
   zichtbaar verschil in rust). Posities zijn gemeten in native beeldpixels (2000×1131) en
   omgerekend naar exacte object-fit:cover-percentages per breakpoint (16:9 vs 3:4 croppen
   het beeld anders, dus zowel positie ALS maskergrootte verschillen per breakpoint — een
   vaste %-maat zou op mobiel een verkeerd fysiek formaat geven). door.js stuurt het
   knipperen aan; bij reduced-motion blijft dit blok volledig statisch (altijd "aan"). */
.agent-oog {
  position: absolute;
  z-index: 1;
  width: 0.900%;
  height: 2.311%;
  border-radius: 50%;
  pointer-events: none;
}
.agent-oog__gloei {
  position: absolute;
  inset: 14%;
  border-radius: 50%;
  background: radial-gradient(circle, #ffe9b8 0%, #f0b23c 55%, rgba(240, 178, 60, 0) 100%);
  box-shadow: 0 0 3px 0 rgba(240, 178, 60, 0.85);
  transform-origin: center;
}
.agent-oog--links-l  { left: 35.700%; top: 53.680%; background: #04060a; }
.agent-oog--links-r  { left: 36.750%; top: 53.740%; background: #04060a; }
.agent-oog--rechts-l { left: 61.170%; top: 53.871%; background: #04060a; }
.agent-oog--rechts-r { left: 62.050%; top: 53.952%; background: #04060a; }
/* Agent "midden" heeft de twee ogen véél dichter bij elkaar (~5px) dan links/rechts —
   eigen (smaller) maskerbreedte zodat ze niet tot één glans versmelten. */
.agent-oog--midden-l,
.agent-oog--midden-r { width: 0.550%; background: #241708; }
.agent-oog--midden-l { left: 48.145%; top: 54.183%; }
.agent-oog--midden-r { left: 48.395%; top: 54.173%; }
@media (max-width: 700px) {
  /* Zelfde breekpunt als de scène-aspect-ratio hierboven — 3:4 snijdt het beeld smaller
     bij, dus zowel de positie als de fysieke maskergrootte verschuiven mee. */
  .agent-oog { width: 2.122%; height: 2.299%; }
  .agent-oog--links-l  { left: 16.284%; top: 53.661%; }
  .agent-oog--links-r  { left: 18.759%; top: 53.721%; }
  .agent-oog--rechts-l { left: 76.337%; top: 53.851%; }
  .agent-oog--rechts-r { left: 78.411%; top: 53.931%; }
  .agent-oog--midden-l,
  .agent-oog--midden-r { width: 1.297%; }
  .agent-oog--midden-l { left: 45.626%; top: 54.161%; }
  .agent-oog--midden-r { left: 46.216%; top: 54.151%; }
}

/* Verhaal-laag: kop + 3 blokken, overlay met scrim voor leesbaarheid op de foto.
   Zit onder de deurbladen (z-index 2 < 3): fysiek verborgen tot de deur opengaat. */
.deur-verhaal {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: clamp(1rem, 3vw, 1.75rem);
  padding: clamp(1.25rem, 4vw, 3rem);
  background: linear-gradient(to top, rgba(13, 13, 11, 0.88) 0%, rgba(13, 13, 11, 0.55) 45%, rgba(13, 13, 11, 0) 100%);
}
.deur-verhaal h2 {
  margin-bottom: 0;
  max-width: 34ch;
  font-size: clamp(1.75rem, 4vw, 3rem);
}
.deur-verhaal__blokken {
  display: grid;
  gap: clamp(1rem, 3vw, 2rem);
}
@media (min-width: 760px) {
  .deur-verhaal__blokken { grid-template-columns: repeat(3, 1fr); }
}
.deur-verhaal__blok h3 {
  margin-bottom: 0.4rem;
  font-family: var(--font-mono);
  font-size: var(--type-label);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--kleur-accent);
}
.deur-verhaal__blok p {
  max-width: 32ch;
  font-size: clamp(0.9rem, 1.6vw, 1.05rem);
  color: var(--kleur-papier-vervaagd);
}

/* Dichte deur — twee bladen, elk 50% breed, elk de eigen helft van S2-deur-dicht via
   background-position; background-size 200% (relatief aan het blad, dus 100% van de
   containerbreedte) zorgt dat de twee helften naadloos aansluiten tot één deurbeeld. */
/* Beide bladen zijn onafhankelijk sleepbaar (elk een eigen Draggable-instantie, zie door.js) —
   cursor/touch-action gelden dus voor allebei, niet alleen voor het rechterblad. */
/* z-index-hiërarchie is BEWUST vast: .deur__blad (3) moet ALTIJD onder .deur-instructie en
   .deur-open-knop (beide 4) blijven liggen — ook tijdens het slepen zelf en na een
   elastische terugveer. GSAP Draggable heeft standaard zIndexBoost:true, wat bij press een
   inline style.zIndex (1000+) op het blad zet die na loslaten blijft staan en deze
   CSS-volgorde zou overschrijven (bug, live-test Ryan: knop/instructie verdwenen achter de
   dichte deur). Beide Draggable-instanties in door.js hebben daarom zIndexBoost:false —
   verander dat niet zonder deze hiërarchie opnieuw te verifiëren. */
.deur__blad {
  position: absolute;
  top: 0;
  bottom: 0;
  z-index: 3;
  width: 50%;
  background-repeat: no-repeat;
  background-size: 200% 100%;
  cursor: grab;
}
.deur__blad:active { cursor: grabbing; }
/* Fix-ronde 2 (Ryan iPhone-test 07-08): touch-action:none uitsluitend op fijne pointers
   (muis/trackpad) — daar stuurt Draggable zelf de horizontale sleep aan (zie door.js). Op
   touch is er sinds deze fix GEEN Draggable meer op de deurbladen (tikken i.p.v. slepen,
   zie door.js) — touch-action moet daar dus op de normale `auto` blijven staan, anders
   onderdrukt de browser zelf nog altijd de standaard-touchscroll zodra een gebaar op de
   deurbladen begint, zonder dat er nog een Draggable is die 'm overneemt. (De hoofdoorzaak
   van "kan ik niet meer scrollen" was het mid-gesture disable()-patroon hieronder bij de
   fijne-pointer-tak — zie de toelichting bij `pointerFijn()` in door.js — maar de scène blijft
   ook zónder die specifieke bug een groot deel van het scherm, dus deze CSS-regel hoort
   sowieso bij "touch = geen sleepgedrag meer op dit element".) */
@media (pointer: fine) {
  .deur__blad { touch-action: none; }
}
.deur__blad--links {
  left: 0;
  background-position: left top;
  background-image: url('/assets/img/machinekamer/S2-deur-dicht.webp');
  background-image: -webkit-image-set(url('/assets/img/machinekamer/S2-deur-dicht.avif') type('image/avif'), url('/assets/img/machinekamer/S2-deur-dicht.webp') type('image/webp'));
  background-image: image-set(url('/assets/img/machinekamer/S2-deur-dicht.avif') type('image/avif'), url('/assets/img/machinekamer/S2-deur-dicht.webp') type('image/webp'));
}
.deur__blad--rechts {
  left: 50%;
  background-position: right top;
  background-image: url('/assets/img/machinekamer/S2-deur-dicht.webp');
  background-image: -webkit-image-set(url('/assets/img/machinekamer/S2-deur-dicht.avif') type('image/avif'), url('/assets/img/machinekamer/S2-deur-dicht.webp') type('image/webp'));
  background-image: image-set(url('/assets/img/machinekamer/S2-deur-dicht.avif') type('image/avif'), url('/assets/img/machinekamer/S2-deur-dicht.webp') type('image/webp'));
}
.is-open .deur__blad { pointer-events: none; }

.deur-instructie {
  position: absolute;
  z-index: 4;
  left: 50%;
  bottom: clamp(1.5rem, 6vw, 3rem);
  transform: translateX(-50%);
  /* Fix-ronde 2, bijvangst: zonder expliciete breedte valt een absoluut gepositioneerd
     element met alleen `left` (geen `right`) terug op CSS' shrink-to-fit-algoritme, dat de
     "beschikbare breedte" hier gelijkstelt aan containerbreedte MINUS de 50% left-offset —
     op mobiel dus de HELFT van het scherm, ongeacht hoe lang de tekst is. De iets langere
     tik-copy ("Tik om de deur te openen — …") week daardoor naar 2 regels uit en overlapte
     de knop erboven (gemeten: 22px overlap in de touch-emulatie, tegen 4px met de kortere
     sleep-copy). `width: max-content` + een veilige max-breedte laat 'm zich naar zijn
     werkelijke tekstbreedte vormen — translateX(-50%) blijft 'm correct centreren, ongeacht
     die breedte.
  */
  width: max-content;
  max-width: min(90vw, 26rem);
  color: var(--kleur-papier);
  text-align: center;
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.6);
  transition: opacity var(--duur-lang) ease;
  pointer-events: none;
}
/* Fix-ronde 2 (Ryan-beslissing 07-08): twee copy-varianten (strings-keys, geen JS-tekst-
   manipulatie) — welke zichtbaar is, volgt zuiver CSS `(pointer: fine)`, exact dezelfde
   media-feature als de matchMedia-check in door.js die daar Draggable vs. tik bepaalt, zodat
   copy en gedrag nooit uit de pas kunnen lopen. Mobile-first default = de tik-copy (touch is
   de veruit grootste doelgroep); op een fijne pointer (muis/trackpad) wisselt dat naar de
   sleep-copy. */
.deur-instructie__tikken { display: inline; }
.deur-instructie__slepen { display: none; }
@media (pointer: fine) {
  .deur-instructie__tikken { display: none; }
  .deur-instructie__slepen { display: inline; }
}
/* Volledig weg (niet slechts gedimd): op smalle/korte scènes overlapt de instructieregel
   anders met de onderste regel van de verhaal-laag zodra die in-animeert. */
.is-open .deur-instructie { opacity: 0; }

.deur-open-knop {
  position: absolute;
  z-index: 4;
  left: 50%;
  bottom: clamp(3.5rem, 10vw, 5.5rem);
  transform: translateX(-50%);
  padding: 0.6rem 1.5rem;
  border: 1px solid var(--kleur-accent);
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: var(--type-label);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--kleur-papier);
  background: rgba(13, 13, 11, 0.55);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  transition: background var(--duur-kort) ease, color var(--duur-kort) ease, opacity var(--duur-lang) ease;
}
.deur-open-knop:hover,
.deur-open-knop:focus-visible {
  background: var(--kleur-accent);
  color: var(--kleur-inkt);
}
.is-open .deur-open-knop { opacity: 0; pointer-events: none; }

/* ------------------------ Personeelsgalerij — identificatie-scan ---------------------- */
/* HERONTWERP 07-08 (Ryan, referentie trionn.com/about) + VISUELE CORRECTIERONDE 07-08
   (galerij-fix-v2, projectleiding afgekeurd op de eerste uitvoering — zie
   .superpowers/sdd/2026-08-07-onepager-implementatie/galerij-fix-v2-report.md) +
   COMPOSITIE-RONDE taak-v4 (Ryan: "silhouetten en de overgang zijn mooi" — die blijven — maar
   de elektra viel weg en de scanner moest los van het netwerk):
     1) Sectie is bewust DONKER — de 2e "achter de schermen"-sectie naast #verhaal.
     2) Nooit meer tekst OVER een portret: alle identiteitsgegevens staan in het bijschrift
        naast de scanner, buiten de foto. Op de chips zelf staat alleen een klein naam-label
        onder de foto (.doka-kaart-item__naam).
     3) Geen procent-posities: de negen chips staan in drie CSS-flex-rijen (flank/midden/
        onder, de merkteken-hiërarchie) met een gegarandeerde min-gap — overlap wordt door de
        layout zelf uitgesloten, niet op het oog geschat.
     4) taak-v4: de SCANNER (.doka__scanner) doet niet langer mee aan de netwerk-hiërarchie —
        hij blijft het drag/tik-doel (mechaniek ONGEWIJZIGD) maar staat nu LOS, prominent en
        centraal (zie .doka__stage). In zijn plaats komt een bedrijfskaart (.doka__bedrijf,
        "[Jouw bedrijfsnaam]") bovenaan het netwerk: DIE is nu de apex waar in ons merkteken de
        vonk zit, en alle circuitbanen (gallery.js, tekenLijnen) lopen van daar naar de negen
        agent-chips — "het netwerk werkt zichtbaar vóór de bezoeker". De verbindingen zelf
        (banen/pulsen/knooppunten + het lichtspoor rond de bedrijfskaart) zijn NEON
        (--kleur-neon, elektrisch blauw) i.p.v. goud — echte elektra, geen decoratief goud
        meer. Chips, scanner en tekst blijven bewust in de bestaande inkt/goud-taal.
   Interactie ongewijzigd: slepen (of tikken op touch) een chip naar de scanner → chip schaalt
   op tot scanner-formaat → scanlijn-sweep → silhouet dooft uit naar portret. GATE Ryan 07-08:
   geen tellers op de kaart. */

.doka {
  position: relative; /* containing block voor .doka__achtergrond (position:absolute, inset:0) */
  margin-top: clamp(2.5rem, 6vw, 4rem);
}

/* Zwevende achtergrondchips (taak-v7, 2e commit — coördinator: "onbeperkt uitbreidbaar", elke
   taak kan een eigen agent worden). Puur CSS/HTML, geen JS: 12 vaste posities (procenten op
   `.doka`'s eigen box, GEEN Math.random — projecteis).

   STERRENHEMEL-HERONTWERP (taak-v8, twee ronden):
   Ronde 1 (bugfix): de oorspronkelijke twee-kolommen-opzet (x≤11%/≥90%) plaatste chip-ICOON
   en chip-LABEL los van elkaar — het label is BREDER dan het icoon en staat gecentreerd
   eronder (.doka__achtergrond-chip__label, transform:translateX(-50%)), dus een icoon vlak
   bij de rand duwde zijn eigen label alsnog over de rand van `.doka__achtergrond`
   (overflow:hidden) of de viewport. Elke positie hieronder is nu MET het label-half-breedte
   erbij doorgerekend (Playwright-gemeten px-breedte per rolnaam, NL+EN, worst-case) i.p.v. op
   het icoon alleen.
   Ronde 2 (Ryan, na screenshot): "ik wou ze juist óm de rest heen laten zweven als een
   sterrenhemel" — geen twee rechte kolommen meer. De 9 netwerk-chips + bedrading + scanner
   groeien/krimpen zelf sterk per breedte (bewuste flex-grow op .doka__constellatie, zie
   .doka__stage hieronder) — bij 1024-1280px raken scanner/bijschrift zelfs letterlijk de
   rand (0% marge, gemeten), bij 1440px+ is er weer ~5%+ ruimte. Vier layout-lagen, elk met
   een EIGEN veilige-zone-analyse (gemeten met Playwright, niet geschat):
     • BASIS (geen media query = ≥1440px "wijd"): korte rolnamen in de smalle zijmarge +
       één chip in de echte kier tussen netwerk en scanner (de opdracht noemt die kier
       expliciet), langere rolnamen in de top-/onderstrook boven/onder de compositie.
     • 860-1439,98px ("krap-rij"): scanner/netwerk kunnen tot 0% zijmarge krimpen → GEEN
       enkele chip op de zijkant. `.doka` krijgt hier (net als mobiel) een eigen
       padding-top/-bottom-strook die altijd leeg is, ongeacht breedte — alle 12 chips staan
       daarin, klein formaat.
     • 700-859,98px ("compact-kolom"): de stage staat in kolomvorm (scanner boven
       constellatie), dat laat juist een royale kolom-marge over (15-20%+, gemeten) → de
       meeste chips terug op de zijkant, alleen de 3 langste rolnamen in dezelfde
       padding-strook-truc.
     • ≤699,98px (mobiel): bestaande padding-strook-aanpak (taak-v7b), nu met drie
       groottetrappen + variërende opaciteit in plaats van één uniforme rij.
   Elke laag is met Playwright geverifieerd: label-rect volledig binnen [0, innerWidth] EN
   binnen de sectiegrenzen, op de rustpositie én op het uiterste driftpunt (zie v8-report.md).
   Eerste kind in de DOM (vóór .doka__instructie/.doka__stage) → paint-volgorde alleen al zet
   'm onderaan; .doka__lijnen/de chips/de scanner komen allemaal LATER in de DOM en
   overschilderen 'm dus vanzelf, geen negatieve z-index nodig (die zou buiten .doka kunnen
   "lekken" als een voorouder toevallig geen eigen stacking-context heeft). */
.doka__achtergrond {
  position: absolute;
  inset: 0;
  overflow: hidden; /* voorkomt dat een chip vlak bij de rand de sectie breder maakt */
  pointer-events: none;
}
.doka__achtergrond-chip {
  position: absolute;
  left: var(--x);
  top: var(--y);
  /* STERRENHEMEL-RONDE (taak-v8, Ryan: "ik wou ze juist óm de rest heen laten zweven als een
     sterrenhemel", niet meer twee strakke kolommen): --maat/--opaciteit zijn nu PER CHIP
     ingesteld (inline + per breakpoint-laag hieronder) i.p.v. één vaste waarde voor alle 12 —
     drie groottetrappen (~1,4/2,1/2,9rem) met bijpassende opaciteit (verder-ogend = zwakker,
     dichterbij-ogend = sterker) geven de laag echt diepte. Fallbacks hier zijn de OUDE
     eenvormige waarden, puur als vangnet mocht een chip ooit zonder inline custom property
     renderen. */
  width: var(--maat, clamp(1.8rem, 2.6vw, 3.2rem)); /* ~⅓–½ van --kaart-basis (6-8,5rem): bewust klein */
  aspect-ratio: 1;
  opacity: var(--opaciteit, 0.28); /* richtlijn 0,22-0,40 (taak-v8 ronde 2, Ryan: eerdere
    0,10-0,22 was te transparant — "moeten duidelijk leesbaar en herkenbaar zijn", met behoud
    van de dichterbij=sterker/verder=zwakker-hiërarchie; zie v8-report.md voor de gemeten
    contrastratio's tegen --kleur-inkt op de nieuwe uitersten) */
  animation-name: doka-achtergrond-drift;
  animation-duration: var(--duur, 14s);
  animation-delay: var(--vertraging, 0s);
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}
.doka__achtergrond-chip__lichaam {
  position: absolute;
  inset: 0;
  border: 1px solid var(--kleur-accent); /* dekking komt van de opacity op de OUDER (.doka__achtergrond-chip), consistent met hoe de opacity ook het label meeneemt */
  border-radius: 22%; /* zelfde chip-afronding als de agent-chips/apex (correctie 4: goud i.p.v. neon, "in lijn met de kleurkeuze" — zie v7-report.md voor de motivatie */
}
.doka__achtergrond-chip__pins {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  fill: var(--kleur-accent);
}
.doka__achtergrond-chip__label {
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  margin-top: 0.35rem;
  font-size: 0.56rem;
  letter-spacing: 0.08em;
  white-space: nowrap;
  color: var(--kleur-accent);
}
@keyframes doka-achtergrond-drift {
  0%, 100% { transform: translate(0, 0); }
  50% { transform: translate(var(--dx, 3px), var(--dy, -6px)); }
}

/* USP-regel boven het netwerk en de bijbehorende uitleg eronder (ronde 6). Allebei BUITEN
   `.doka`: die box is de referentie voor de negen zwevende chips, dus alles wat je erin hangt
   verschuift het sterrenveld. De globale leesbreedte (`p { max-width: 60ch }`) wordt hier
   losgelaten en door de wrapper overgenomen, anders krijgt elke alinea zijn eigen breedte en
   oogt het blok scheef. */
.doka-claim {
  max-width: 44rem;
  margin: clamp(2rem, 5vw, 3rem) auto 0;
  text-align: center;
  font-family: var(--font-serif);
  font-size: clamp(1.5rem, 3.2vw, 2.25rem);
  line-height: 1.15;
  /* De regel bestaat uit twee zinnen die tegen elkaar afzetten ("leger" ↔ "loonlijst van een
     leger"); balance legt de regelovergang op het scharnier tussen die twee in plaats van
     midden in de tweede zin. Waar de browser het niet kent (Safari) valt het terug op normale
     terugloop — de regel blijft dan gewoon leesbaar, alleen minder mooi gebroken. */
  text-wrap: balance;
}

.doka-droom {
  max-width: 44rem;
  margin: clamp(2.5rem, 5vw, 3.5rem) auto 0;
  text-align: center;
}
.doka-droom__tekst {
  max-width: none;
  margin: 0 0 1rem;
  opacity: 0.72;
  text-wrap: pretty; /* geen losse slotwoorden op een eigen regel */
}
.doka-droom__tekst:last-child { margin-bottom: 0; }

.doka__instructie {
  /* RONDE 6 (Ryan: "sleep een chip in de scanner moet gecentreerd boven de chips ipv links"):
     `.mono-label` zet display:inline-block, dus `text-align:center` centreerde alleen de tekst
     BINNEN het krimpende regelvakje — het vakje zelf bleef links in `.doka` staan. Blok maken
     laat het vakje de volle breedte pakken; `margin: 0 auto` is daarbij geen luxe maar nodig,
     want een globale leesbreedte-regel geeft tekstblokken een max-width (gemeten 440,6px).
     De padding compenseert de letter-spacing van .mono-label: die zet ook spatie achter de
     laatste letter, waardoor een gecentreerde regel optisch een fractie naar links schuift. */
  display: block;
  padding-inline-start: 0.14em;
  text-align: center;
  margin: 0 auto clamp(1.25rem, 4vw, 2rem);
  opacity: 0.6;
}

/* Stage (taak-v4): scanner + constellatie naast elkaar. DOM-volgorde is bewust
   scanner-EERST, constellatie-TWEEDE: op mobiel (kolom, zie hieronder) is dat meteen de
   gevraagde volgorde "eerst de scanner, daaronder de constellatie" zonder CSS-order-truc —
   de scanner is het prominente/centrale element waar de blik als eerste op valt, de
   constellatie erna nodigt uit tot scrollen/verkennen. Desktop (≥860px, zelfde omslagpunt
   als #gesprekken) draait de VISUELE volgorde om (constellatie links, scanner rechts) via
   `order`, maar de DOM/tab-volgorde (screenreader, toetsenbord) blijft scanner-dan-chips —
   onschadelijk, want de scanner zelf bevat geen focusbare elementen (alleen de 9
   chip-knoppen in de constellatie zijn dat), dus de facto tab-volgorde over de chips
   verandert niet. */
.doka__stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(2.5rem, 6vw, 4rem);
}
@media (min-width: 860px) {
  .doka__stage {
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: clamp(3rem, 6vw, 6rem);
  }
  .doka__constellatie { order: -1; flex: 1 1 34rem; max-width: 42rem; }
  .doka__scanner { flex: 0 1 24rem; }

  /* RONDE 6 (Ryan: "de scanner moet iets lager komen zodat hij in het midden hoogte is van de
     chips links"). De rij centreerde al netjes — maar op de GROEP scan-vak + bijschrift, en
     het bijschrift reserveert ~144px hoogte terwijl het leeg (onzichtbaar) is tot er een chip
     geïdentificeerd is. Daardoor werd het zichtbare vak ~87px boven het midden geduwd.
     Het bijschrift uit de flow halen laat de kolomhoogte gelijk worden aan die van het vak,
     zodat `align-items: center` het VAK centreert — en dat klopt automatisch op elke breedte,
     ook waar netwerk en vak anders meeschalen. De gereserveerde hoogte blijft staan zodat er
     nog steeds niets springt zodra de tekst verschijnt; hij telt alleen niet meer mee voor de
     centrering. */
  .doka__scanner { position: relative; }
  .doka__bijschrift {
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
  }
}

.doka__constellatie {
  position: relative; /* enige containing block voor .doka__lijnen (SVG, inset:0) — GEEN transform/z-index hier */
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  /* BLADSPIEGEL-FIX v5 (07-08): was clamp(1.75rem,5vw,3.5rem) — op ≥860px liep dit tot 56px op en
     samen met de grid-gaps hieronder maakte dat de constellatie zoveel hoger dan de scanner-kolom
     dat .doka__stage (align-items:center) een groot leeg vlak onder de scanner overliet. Vast op
     de vloer van de bestaande overlap-eis (24px, geen vw-groei meer nodig voor zo'n compact
     chip-netwerk) — de merkteken-hiërarchie (apex → schouders → dwarsbalk → onder) blijft net zo
     herkenbaar, alleen minder uitgerekt. Mobiel (≤699,98px) heeft zijn EIGEN media-query-override
     hieronder en is dus ongemoeid. */
  gap: 1.5rem;
  --kaart-basis: clamp(6rem, 7.5vw, 8.5rem); /* pure chip-maat: draagt geen tekst meer (correctie 3), mag compact */
}

/* Verbindingslijnen-laag (SVG, volledig door gallery.js getekend): onderste laag, achter
   zowel de kaarten als de bedrijfskaart. PRECISIE-CORRECTIE taak-v7 (Ryan, na visuele
   inspectie — zie v7-report.md voor de letterlijke feedback en gallery.js tekenLijnen() voor
   de volledige toelichting): twee losgekoppelde lagen i.p.v. één ondifferentieerd geheel —
   Laag A = .doka__lijn-basis, de "bedrading" (dun, laag opaak, GEEN animatie, altijd
   zichtbaar; 13 vaste verbindingen: apex→flank×2, flank-bus, 2×trunk, midden-bus, onder-bus +
   6 organigram-takken/ORG_TAKKEN). Laag B = .doka__lijn-puls, de "stroom" (fel, glowend,
   animeert via GSAP stroke-dashoffset met darkroom.js' pulsDashOffsets() — reist de VOLLEDIGE
   padlengte, stopt nooit halverwege). stroke-linejoin:round geeft elke knik een zachte hoek
   i.p.v. een scherpe punt.
   KLEURCORRECTIE (4e ronde, Ryan: "een gouden printplaat die er altijd is, waar blauwe stroom
   doorheen schiet"): Laag A is nu GOUD (--kleur-accent, dezelfde tint als de chip-pinnen/
   hoekmarkeringen) i.p.v. neon — "rustend" hoort bij de bestaande merktaal. Laag B (de
   pulsen) + .doka__rand-lichtspoor (het BEWEGENDE lichtspoor om de apex, dus zelf ook "stroom"
   i.p.v. rustende bedrading) blijven --kleur-neon (elektrisch blauw). Dekking hieronder
   GEMETEN (WCAG-formule, achtergrond --kleur-inkt #0d0d0b): basis 38% → 1,90:1 t.o.v. de
   achtergrond (zacht maar duidelijk zichtbaar); dwarsbalk/knooppunt 50-55% → 2,46–2,75:1 (iets
   nadrukkelijker voor de rij2-bus/trunk-knopen). De blauwe puls blijft er ruim bovenuit
   steken: 6,9:1 (tegen de basis-bedrading) tot 4,8:1 (tegen de felste dwarsbalk-lijn) contrast
   — nooit "verdwijnt" de puls in het goud. */
.doka__lijnen {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
  overflow: visible;
}
.doka__lijn-basis,
.doka__lijn-puls { stroke-linejoin: round; stroke-linecap: round; }
.doka__lijn-basis { stroke: color-mix(in srgb, var(--kleur-accent) 38%, transparent); stroke-width: 1.15; }
.doka__lijn-basis--dwarsbalk { stroke: color-mix(in srgb, var(--kleur-accent) 55%, transparent); stroke-width: 1.7; } /* de flank-bus (rij 2 onderling) — het dwarsbalk-paar uit het merkteken, iets dikker */
/* Meerlaagse gloed (opdracht-eis): een brede zachte halo (buitenste drop-shadow, lage
   dekking) + een smalle felle kern (binnenste drop-shadow, volle dekking) — gestapelde
   filter-lagen i.p.v. één vage vlek, zodat de puls ook op een donkere sectie "echt" gloeit.
   Uniforme stijl voor alle 9 pulsen (geen hoofd/zij-hiërarchie meer, taak-v7): elke chip
   krijgt hetzelfde soort stroompuls vanaf de apex. Blijft --kleur-neon (kleurcorrectie
   hierboven raakt alleen Laag A). */
.doka__lijn-puls {
  stroke: var(--kleur-neon);
  stroke-width: 1.6;
  filter:
    drop-shadow(0 0 1.5px var(--kleur-neon))
    drop-shadow(0 0 5px color-mix(in srgb, var(--kleur-neon) 85%, transparent))
    drop-shadow(0 0 13px color-mix(in srgb, var(--kleur-neon) 55%, transparent));
}
.doka__lijn-puls.is-scan-actief {
  stroke-width: 2.4;
  filter:
    drop-shadow(0 0 2px var(--kleur-neon))
    drop-shadow(0 0 8px var(--kleur-neon))
    drop-shadow(0 0 20px color-mix(in srgb, var(--kleur-neon) 65%, transparent));
}
.doka__knooppunt { fill: var(--kleur-accent); opacity: 0.5; filter: drop-shadow(0 0 3px color-mix(in srgb, var(--kleur-accent) 70%, transparent)); } /* de 3 trunk-knooppunten (flank/midden/onder-bus-midden) — goud, zelfde kleurcorrectie */
.doka__rand-lichtspoor {
  stroke: var(--kleur-neon);
  stroke-width: 1.5;
  filter: drop-shadow(0 0 2px var(--kleur-neon)) drop-shadow(0 0 7px color-mix(in srgb, var(--kleur-neon) 75%, transparent));
  opacity: 0.9;
}
.doka__rand-lichtspoor.is-statisch { stroke-dasharray: none; opacity: 0.4; filter: none; } /* reduced-motion: geen loop, gewoon een rustige rand */

/* Bedrijfskaart (taak-v4, chipvorm-fix taak-v7) — de apex van het netwerk: "dit bent u".
   FIX 1 (Ryan: "geef hem exact dezelfde chipvorm als de agent-chips... hij hoort visueel bij
   de familie"): zelfde border-radius/chipvorm ALS de agent-chips (vergelijk
   .doka-kaart__foto-wrap) én dezelfde 12-pinnetjes-SVG (.doka-kaart__pins, door gallery.js op
   dit element gezet — zie initGallery) — geen aparte nabouw, letterlijk dezelfde class/CSS dus
   pixel-identieke pin-constructie/verhoudingen als op de negen agent-chips en als in
   merkteken.svg. Leeg/omlijnd (geen foto) markeert 'm nog steeds als "iets anders dan een
   bemande agent-chip". Alle apex-lijnen vertrekken hiervandaan (gallery.js tekenLijnen) en het
   lichtspoor hierboven loopt om DEZE kaart — waar in het merkteken de vonk zit.
   "Continu op stroom" (taak-v7): een permanente, rustige ademende gloed op de kaart zelf —
   los van de traveling pulsen, het is de "energiebron" waar ze vandaan komen. Reduced-motion:
   de globale *-regel verkort animation-duration al tot 0,01ms/1 iteratie, dus het bevriest op
   een stabiel, nog altijd zichtbaar glow-frame — nooit onzichtbaar. */
.doka__bedrijf {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: calc(var(--kaart-basis) * 1.05);
  aspect-ratio: 1;
  padding: 0.75rem;
  border-radius: 22%;
  border: 1.5px solid color-mix(in srgb, var(--kleur-neon) 55%, transparent);
  background: color-mix(in srgb, var(--kleur-neon) 6%, transparent);
  text-align: center;
  animation: doka-bedrijf-stroom 3.4s ease-in-out infinite;
}
@keyframes doka-bedrijf-stroom {
  0%, 100% {
    border-color: color-mix(in srgb, var(--kleur-neon) 50%, transparent);
    box-shadow: 0 0 9px 1px color-mix(in srgb, var(--kleur-neon) 30%, transparent);
  }
  50% {
    border-color: color-mix(in srgb, var(--kleur-neon) 90%, transparent);
    box-shadow: 0 0 22px 5px color-mix(in srgb, var(--kleur-neon) 60%, transparent);
  }
}
.doka__bedrijf-tekst {
  font-size: 0.66rem;
  line-height: 1.35;
  letter-spacing: 0.06em;
  color: var(--kleur-papier);
  opacity: 0.85;
}

/* Scanner (taak-v4): het scan-venster + het bijschrift ernaast, LOS van de netwerk-
   hiërarchie hierboven — prominent en centraal in de sectie (zie .doka__stage). Puur een
   flow-wrapper: GEEN position/z-index hier, anders trekt hij een eigen stacking-context open
   en verstoort dat exact dezelfde kaart-boven-scanner-onder-scanlijn-volgorde die het vak
   hieronder bewust vermijdt. */
.doka__scanner {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
}

/* Het scan-vak zelf — blijft de bestaande inkt/goud-taal (taak-v4, punt 1: alleen de
   verbindingen worden neon, de scanner niet). BEWUST GEEN eigen z-index op dit element: dat
   zou een eigen stacking-context aanmaken en zijn kinderen (scanlijn/hoekmarkeringen) daarin
   opsluiten — dan kan de actieve kaart (elders in de DOM, .doka__grid) er nooit meer precies
   tussenin komen te liggen. Centreren gebeurt nu gewoon door de flex-ouder (.doka__scanner);
   JS (schaalVakMee) zet alleen nog width/height, geen margin-trucs meer nodig.
   border-radius:14% draagt dezelfde chip-taal als de kaarten mee. */
.doka__vak {
  position: relative;
  width: clamp(13rem, 24vw, 17rem); /* pre-JS/no-ResizeObserver-vangnet; JS overschrijft dit vrijwel meteen */
  height: clamp(13rem, 24vw, 17rem);
  border-radius: 14%;
  border: 1px solid rgba(184, 145, 43, 0.18); /* subtiele omlijning: de sectie is nu zelf ook donker, het vak heeft een eigen randje nodig om niet in de achtergrond weg te vallen */
  background: radial-gradient(circle at 50% 40%, rgba(13, 13, 11, 0.94), rgba(13, 13, 11, 0.98));
}

/* BLADSPIEGEL-FIX v5 (07-08): hoekmarkeringen groter/dikker + een zachte gouden gloed, en een
   trage "ademende" opacity-puls per hoek (kort na elkaar, ietsje uit fase) zolang het vak niet
   .is-actief is — Ryan: het vak oogde in ruststand te zwak/leeg. Zodra een chip het vak raakt
   (gallery.js identificeer(), ruim vóór de echte scan-sweep) staan de hoeken vol/stabiel "op
   scherp" (animatie uit, volle dekking) i.p.v. door te blijven ademen — dat zou tijdens de
   dramatische scan-sweep juist afleiden. Reduced-motion: de globale *-regel hieronder in dit
   bestand verkort animation-duration al tot 0,01ms/1 iteratie, en zonder eigen opacity in de
   basisregel hier valt het element na die ene frame terug op zijn ongeanimeerde staat (opacity
   1, dus gewoon vol zichtbaar en stil) — zelfde bewezen patroon als elders in dit bestand. */
.doka__vak-hoek {
  position: absolute;
  width: 2rem;
  height: 2rem;
  z-index: 3; /* boven rustende kaarten (z-index 1), buiten de kaart-inhoud zelf door de negatieve offset hieronder */
  border-color: var(--kleur-accent);
  border-style: solid;
  border-width: 0;
  filter: drop-shadow(0 0 4px rgba(184, 145, 43, 0.5));
  animation: doka-hoek-ademen 3.6s ease-in-out infinite;
}
.doka__vak-hoek--tl { top: -0.6rem; left: -0.6rem; border-top-width: 2.5px; border-left-width: 2.5px; animation-delay: 0s; }
.doka__vak-hoek--tr { top: -0.6rem; right: -0.6rem; border-top-width: 2.5px; border-right-width: 2.5px; animation-delay: 0.5s; }
.doka__vak-hoek--bl { bottom: -0.6rem; left: -0.6rem; border-bottom-width: 2.5px; border-left-width: 2.5px; animation-delay: 1s; }
.doka__vak-hoek--br { bottom: -0.6rem; right: -0.6rem; border-bottom-width: 2.5px; border-right-width: 2.5px; animation-delay: 1.5s; }
.doka__vak.is-actief .doka__vak-hoek { animation: none; opacity: 1; }
@keyframes doka-hoek-ademen {
  0%, 100% { opacity: 0.68; }
  50% { opacity: 1; }
}

/* Binnenkant: overflow:hidden zodat de scanlijn/meetlijnen netjes binnen het vak-kader
   blijven — de hoekmarkeringen hierboven zitten BUITEN deze wrapper zodat ze nooit worden
   afgesneden. */
.doka__vak-binnenkant {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: inherit;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  text-align: center;
  padding: 1rem;
}
.doka__vak-meetlijnen {
  position: absolute;
  inset: 0;
  z-index: 1;
  opacity: 0.35;
  background-image: repeating-linear-gradient(
    to bottom, rgba(184, 145, 43, 0.5) 0, rgba(184, 145, 43, 0.5) 1px,
    transparent 1px, transparent calc(100% / 9)
  );
}
/* Idle-scanlijn (v5, "BLADSPIEGEL-FIX"): een zachte, trage streep die op-en-neer door het vak
   drijft zolang er nog niets geïdentificeerd is — Ryan: een verder helemaal stil vak oogt al
   snel als een leeg/kapot kader, dit is de "uitnodiging tot interactie". Puur CSS/decoratief,
   raakt de ECHTE scan-sweep hieronder (.doka__vak-scanlijn, GSAP-gedreven) niet aan: eigen
   element, eigen z-index (onder de tekst, z-index 2), en verdwijnt voorgoed zodra gallery.js
   .is-actief op het vak zet — exact op het moment dat een chip begint te vliegen, ruim vóór de
   echte sweep start, dus nooit twee lichtstrepen tegelijk. */
.doka__vak-idlespoor {
  position: absolute;
  left: 14%;
  right: 14%;
  top: 0;
  height: 1.5px;
  z-index: 1;
  background: linear-gradient(to right, transparent, rgba(184, 145, 43, 0.8) 50%, transparent);
  filter: drop-shadow(0 0 3px rgba(184, 145, 43, 0.55));
  opacity: 0;
  animation: doka-idlespoor-drift 5.5s ease-in-out infinite;
}
.doka__vak.is-actief .doka__vak-idlespoor { animation: none; opacity: 0; }
@keyframes doka-idlespoor-drift {
  0%, 100% { top: 16%; opacity: 0.18; }
  50% { top: 78%; opacity: 0.5; }
}
.doka__vak-scanlijn {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 4px;
  z-index: 10; /* boven een actieve kaart (z-index 6) — bubbelt door .doka__vak-binnenkant/.doka__vak heen, die zelf geen context aanmaken */
  background: linear-gradient(to bottom, transparent, #B8912B 45%, #B8912B 55%, transparent);
  box-shadow: 0 0 16px 4px rgba(184, 145, 43, 0.65), 0 0 40px 8px rgba(184, 145, 43, 0.25);
  opacity: 0;
}
.doka__vak-naam {
  position: relative;
  z-index: 2;
  font-size: 0.95rem;
  letter-spacing: 0.08em;
  opacity: 0.45;
  color: var(--kleur-papier);
}
.doka__vak-label {
  position: relative;
  z-index: 2;
  opacity: 0.5;
  max-width: 15ch;
  color: var(--kleur-papier-vervaagd);
}
/* Content-review eindfix-ronde (Important #5): team.vak_label ("Sleep een chip hierheen") stond
   ongesplitst in het lege vak — op touch las een bezoeker daardoor tegelijk "TIK EEN CHIP..."
   (.doka__instructie, boven het vak) én "SLEEP EEN CHIP HIERHEEN" (hierbinnen), een tegenstrijdig
   commando op een scherm zonder slepen. Zelfde bewezen patroon als .deur-instructie__tikken/
   __slepen: twee kant-en-klare strings (geen JS-tekstmanipulatie), CSS `(pointer: fine)` bepaalt
   welke zichtbaar is — exact dezelfde media-feature als de matchMedia-check in gallery.js
   (fijneAanwijzer) die daar Draggable vs. tik bepaalt, dus copy en gedrag lopen nooit uit de pas.
   Mobile-first default = de tik-copy. */
.doka__vak-label--tikken { display: block; }
.doka__vak-label--slepen { display: none; }
@media (pointer: fine) {
  .doka__vak-label--tikken { display: none; }
  .doka__vak-label--slepen { display: block; }
}
.doka__vak.is-actief .doka__vak-naam,
.doka__vak.is-actief .doka__vak-label { opacity: 0; }

/* Bijschrift-balk — ALTIJD onder het venster, buiten de foto (correctie 2: nooit meer tekst
   over een portret). Reserveert zijn eigen hoogte (getoetst op de langste rol/kracht-tekst in
   data/agents.json) zodat de rijen eronder nooit springen zodra de tekst verschijnt of wisselt
   van agent. Start onzichtbaar (CSS-vangnet vóór JS-load); gallery.js dooft 'm in met autoAlpha
   bij de eerste onthulling en werkt de tekst bij zonder ooit de zichtbare foto te raken. */
.doka__bijschrift {
  width: 100%;
  max-width: 26rem;
  margin-top: clamp(1.6rem, 3vw, 1.85rem);
  min-height: clamp(7rem, 15vw, 9rem);
  padding: 0 0.5rem;
  text-align: center;
  opacity: 0;
  visibility: hidden;
}
.doka__bijschrift-naam {
  display: block;
  font-family: var(--font-serif);
  font-weight: 700;
  font-size: clamp(1.4rem, 3vw, 1.9rem);
  line-height: 1.1;
}
.doka__bijschrift-rol {
  display: block;
  margin-top: 0.3rem;
  font-size: clamp(0.85rem, 1.6vw, 1rem);
  color: var(--kleur-papier-vervaagd);
}
.doka__bijschrift-sinds {
  display: block;
  margin-top: 0.7rem;
  font-size: 0.72rem;
  opacity: 0.75;
}
.doka__bijschrift-zaak {
  display: block;
  margin-top: 0.3rem;
  font-size: 0.72rem;
  color: var(--kleur-accent);
}
.doka__bijschrift-kracht {
  display: block;
  margin-top: 0.5rem;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  opacity: 0.9;
}

/* Noscript-fallback (T15): eenvoudige leesbare lijst, geen kaart-styling nodig — komt
   alleen in beeld zonder JavaScript, dus geen animaties/hover-states om over na te denken. */
.noscript-team-lijst {
  display: grid;
  gap: 0.5rem 2rem;
  max-width: 42rem;
  margin: 1rem 0 0;
  padding: 0;
  list-style: none;
}
@media (min-width: 560px) {
  .noscript-team-lijst { grid-template-columns: repeat(2, 1fr); }
}

/* Rijen volgen de merkteken-hiërarchie: flank (2) → midden-dwarsbalk (3) → onder (4). Een
   CSS-flex-kolom van drie flex-rijen i.p.v. hand-getunede procent-posities (correctie 4) —
   overlap wordt door de layout zelf structureel uitgesloten (gegarandeerde min-gap), niet op
   het oog geschat. .doka__grid-rij is de enige plek die op mobiel via display:contents platvalt
   tot één simpel raster (zie media query onderaan). */
.doka__grid {
  position: relative;
  width: 100%;
  display: flex;
  flex-direction: column;
  /* BLADSPIEGEL-FIX v5: was clamp(1.75rem,4vw,2.5rem) — zie .doka__constellatie hierboven voor de
     volledige toelichting; vast op dezelfde 24px-vloer, geen vw-groei meer. */
  gap: 1.5rem;
}
.doka__grid-rij {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: flex-start;
  row-gap: 1.5rem; /* BLADSPIEGEL-FIX v5: was clamp(1.75rem,4vw,2.5rem) */
  /* BLADSPIEGEL-FIX v5: was clamp(2.25rem,6vw,4rem) — op 1024px liet dat de vier chips van de
     "onder"-rij niet meer naast elkaar passen (492px kolom), waardoor die rij naar TWEE regels
     omklapte en de constellatie daar juist WEER veel hoger werd dan de scanner-kolom (gemeten:
     717px i.p.v. de bedoelde ~640px). Lager plafond houdt die rij op elke breedte ≥860px op één
     regel (getoetst op 1024px en 1440px, zie v5-report.md). */
  column-gap: clamp(1.75rem, 4vw, 3.5rem);
}
.doka__grid-rij--flank { column-gap: clamp(3rem, 9vw, 6rem); } /* de twee "schouders" mogen het venster breed flankeren */

.doka-kaart-item {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: calc(var(--kaart-basis) * var(--doka-schaal, 1));
  z-index: 1;
}
.doka-kaart-item.is-actief { z-index: 6; } /* boven het vak (dat zelf geen z-index heeft) én boven rustende kaarten */

.doka-kaart {
  position: relative;
  display: block;
  width: 100%;
  text-align: left;
  -webkit-user-select: none;
  user-select: none;
}
/* SPOEDFIX 07-08 (Ryan, echte iPhone): touch-action:none is nodig zodat GSAP Draggable op
   een fijne aanwijzer (muis/trackpad/pen) kan slepen, maar blokkeert op een touchscreen
   TEGELIJK verticaal swipen — Ryan kon de sectie niet meer scrollen. gallery.js maakt op
   touch sowieso geen Draggable aan (zie fijneAanwijzer daar); deze regel geldt daarom nu
   ALLEEN op apparaten met een fijne aanwijzer, zodat touch nooit een lock zet. */
@media (pointer: fine) {
  .doka-kaart { touch-action: none; cursor: grab; }
  .doka-kaart:active { cursor: grabbing; }
}

.doka-kaart__foto-wrap {
  position: relative;
  display: block;
  aspect-ratio: 1;
  overflow: hidden;
  background: var(--kleur-inkt);
  border: 1px solid rgba(184, 145, 43, 0.28); /* goud-vervaagd i.p.v. inkt-vervaagd: op de nu-donkere sectie moet de chip-rand zichtbaar blijven i.p.v. bijna onzichtbaar te worden */
  border-radius: 22%; /* chip-vorm (Ryan): zelfde afrondingsverhouding als de chips in merkteken.svg (rx/zijde ≈ 23%) */
  transition: border-color var(--duur-kort) ease;
}
.doka-kaart-item.is-actief .doka-kaart__foto-wrap {
  border-color: var(--kleur-accent);
  box-shadow: 0 0 0 1px rgba(184, 145, 43, 0.4), 0 12px 34px rgba(0, 0, 0, 0.55);
}
.doka-kaart:hover .doka-kaart__foto-wrap,
.doka-kaart:focus-visible .doka-kaart__foto-wrap {
  border-color: var(--kleur-accent);
}

/* Chip-pootjes (Ryan): 12 kleine gouden pinnetjes (3 per zijde) rond elke kaart, exact zoals de
   <rect>-pootjes in merkteken.svg. overflow:visible laat ze over foto-wrap's afgeronde rand heen
   steken i.p.v. eronder verdwijnen — foto-wrap zelf blijft overflow:hidden voor de foto. */
.doka-kaart__pins {
  position: absolute;
  inset: 0;
  z-index: 2; /* altijd zichtbaar boven de foto (silhouet of portret), ongeacht identificatie-status */
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
  fill: var(--kleur-accent);
  opacity: 0.85;
}

/* Twee-lagen "doka"-structuur: het silhouet ligt bovenop en dooft bij de onthulling uit
   (gallery.js, developCurve-tempo), het portret ligt er al onder op volle helderheid.
   Terugval (.doka-kaart--geen-silhouet, gezet zodra de silhouet-<img> 404't): silhouetlaag
   weg, portret krijgt het oorspronkelijke onbelicht-filter terug — zodat de kaart nooit een
   kapot-plaatje-icoon toont en de site nooit stuk staat zolang de silhouet-assets ontbreken. */
.doka-kaart__silhouet-laag,
.doka-kaart__portret-laag {
  position: absolute;
  inset: 0;
}
.doka-kaart__silhouet-laag { z-index: 1; }
.doka-kaart__portret-laag { z-index: 0; }
.doka-kaart.is-geidentificeerd .doka-kaart__silhouet-laag { opacity: 0; } /* CSS-eindstand als vangnet; JS drijft de tween zelf */

.doka-kaart__silhouet,
.doka-kaart__foto {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.doka-kaart__foto { filter: none; } /* portret zelf is altijd "belicht" — het silhouet erboven verbeeldt het onontwikkelde */

.doka-kaart--geen-silhouet .doka-kaart__silhouet-laag { display: none; }
.doka-kaart--geen-silhouet .doka-kaart__foto {
  filter: brightness(0.12) sepia(0.55); /* onbelicht — startwaarde, zelfde als gallery.js' ONONTWIKKELD_FILTER */
}
.doka-kaart--geen-silhouet.is-geidentificeerd .doka-kaart__foto { filter: brightness(1) sepia(0); }

/* Correctie 3: de chip zelf draagt GEEN tekst meer — alleen de naam, klein en goud, ONDER de
   chip (buiten de foto). Alle overige gegevens (rol/sinds/zaak/kracht) verschijnen uitsluitend
   in het bijschrift bij identificatie, wat de scan ook een tikkeltje spannender maakt. */
.doka-kaart-item__naam {
  display: block;
  margin-top: 0.45rem;
  font-size: 0.625rem;
  letter-spacing: 0.1em;
  color: var(--kleur-accent);
  text-align: center;
}

/* SPOEDFIX 07-08 (Ryan, echte iPhone): "de kaarten staan onder elkaar waardoor het slepen
   niet te doen is" — smalle schermen (≤699px) krijgen bewust GEEN constellatie (te weinig
   ruimte om leesbaar te blijven) maar een nette compacte weergave: vak vol-breedte bovenaan
   met het bijschrift eronder, chips in een 2/3-koloms raster daaronder. De rij-wrappers
   (.doka__grid-rij) vallen hier CSS-only plat (display:contents) zodat alle negen chips gewoon
   directe kinderen van het grid worden — geen aparte JS-tak nodig voor mobiel. Zelfde vlieg→
   scan→onthul-mechaniek (gallery.js), alleen normale document-flow i.p.v. absolute posities.
   BEWUST HELEMAAL ONDERAAN dit CSS-blok: een media-query wint een gelijke-specificiteit-
   botsing alleen als hij LATER in de broncode staat — stond dit blok eerder, dan won de
   onvoorwaardelijke basisregel altijd, ook op smalle schermen. Met Playwright aangetoond
   (vorige ronde): getBoundingClientRect() van twee "naast elkaar" kaarten week >30px af en een
   tik op kaart 1 raakte kaart 5's foto. */
@media (max-width: 699.98px) {
  .doka__lijnen { display: none; } /* decoratieve constellatie-lijnen: desktop-only flourish */
  .doka__constellatie { gap: clamp(1.75rem, 6vw, 2.5rem); }
  .doka__scanner { align-items: stretch; }
  .doka__vak {
    width: 100%;
    height: auto;
    /* MOBIELE UITLIJNFIX 07-08 (taak A-1, bijschrift overlapte het vak): was aspect-ratio 4/3.
       De kaart-foto's zelf zijn ALTIJD vierkant (1:1, zie .doka-kaart__foto-wrap). Bij
       identificatie schaalt gallery.js de actieve kaart naar de BREEDTE van het vak
       (kSchaal = vakRect.width / kaart.offsetWidth, identificeer()) — met een 4:3-vak werd die
       vierkante foto daardoor ~33% hoger dan het vak zelf en stak ze tot 58-73px onder de
       vak-rand uit (Playwright-meting op 390px/360px, vóór deze fix), tot ver over de pinnen
       én het bijschrift heen. Vierkant vak = vierkante kaart die er exact in past: geen
       hoogte-overloop meer, alleen nog de bewust ontworpen ~3%-pin-oversteek (zie hieronder). */
    aspect-ratio: 1 / 1;
    /* LET OP (gemeten 11-08): de MAAT van dit vak komt hier NIET vandaan. gallery.js
       (schaalVakMee) zet een inline width/height van 2,7x de gerenderde chip -- Ryans eis dat
       het vak ruim groter is dan een kaart -- en een inline style wint van elke regel hier.
       Wil je het vak kleiner op mobiel, verklein dan de chip: zie .doka__grid hieronder. */
  }
  .doka__bijschrift {
    max-width: none;
    /* MOBIELE UITLIJNFIX 07-08 (taak A-1): de 12 chip-pootjes (.doka-kaart__pins, bouwPinsSvg
       in gallery.js) steken BEWUST ~3% van de kaarthoogte over de kaartrand heen — bij een vak
       dat de volle sectiebreedte beslaat is dat tot ~19px op de breedste mobiele viewport
       (699.98px). Daar bovenop komt een tweede, empirisch gemeten effect (Playwright): het
       bijschrift zelf reserveert alleen een MIN-HEIGHT (hieronder) — zodra gallery.js de echte
       rol/kracht-tekst van de langste agents (bv. Lars) erin zet, groeit het bijschrift daar
       voorbij, en omdat het vák vóór het bijschrift in dezelfde flex-kolom staat, duwt die groei
       de kaarten-rij eronder (met de net vergrote/vliegende kaart erin) verder omlaag t.o.v. het
       vak. De vloer hier (3.5rem/56px) is met beide effecten samen getoetst — met
       getBoundingClientRect gemeten op 390px én 360px, voor alle 9 agents — en houdt in elk
       geval ≥16px vrije ruimte over (zie galerij-v3-report). */
    /* Vloer verlaagd van 3.5rem naar 2.25rem bij de iPhone-check van 11-08: de oude waarde was
       gemeten bij een vak van VOLLE breedte. De pin-oversteek is ~3% van de kaarthoogte, dus met
       het begrensde vak hierboven krimpt die mee (bij 34vh op 700px is de kaart ~238px en steekt
       ~7px over in plaats van ~19px). De bovengrens blijft 3.5rem en vangt het tweede effect op:
       een bijschrift dat groeit bij de langste rolteksten. */
    margin-top: clamp(2.25rem, 7vw, 3.5rem);
  }
  .doka__grid {
    display: grid;
    /* MOBIELE UITLIJNFIX 07-08 (taak A-2): was repeat(2,1fr) met daaronder een aparte
       ≥480px-regel die naar repeat(3,1fr) omschakelde. Negen chips over 2 kolommen laat altijd
       een rest-chip op de laatste rij vallen (4 paren + 1 alleenstaande) — en zodra die
       rest-chip's rij-buur wordt geïdentificeerd (zijn zichtbare foto vliegt dan naar het vak,
       zijn eigen grid-cel blijft wél gereserveerd maar oogt leeg) hangt de overblijvende chip
       zichtbaar alleen aan één kant, exact het gerapporteerde defect. Negen chips delen wél
       exact op in drie volle rijen van drie (3-3-3, geen rest) — dat geldt nu voor ALLE mobiele
       breedtes (geen aparte 480px-knik meer nodig), dus nooit meer een lone chip, ook niet
       wanneer één van de drie in een rij tijdelijk "leegtrekt" tijdens identificatie (de andere
       twee blijven dan gewoon zichtbaar staan). */
    grid-template-columns: repeat(3, 1fr);
    gap: clamp(1.6rem, 6vw, 2rem); /* vloer 25,6px — boven de 24px-eis op elke breedte, incl. 390px */
    /* IPHONE-CHECK 11-08 (Ryan: "de scanner neemt het hele scherm in en de chips zijn niet te
       zien, terwijl het aanklikken en de reveal in 1 scherm zouden moeten passen").
       Het vak meet zichzelf op als 2,7x de chip (gallery.js, schaalVakMee) — dus het vak
       verkleinen kan ALLEEN via de chip, anders sneuvelt die verhoudingseis. Chips van ~97px
       gaven een vak van 370px: samen met bijschrift, bedrijfskaart en de kop paste er geen chip
       meer in beeld. Dit grid is daarom begrensd, wat de chip naar ~84px brengt en het vak naar
       ~300px. 84px blijft ruim boven de 44px-richtlijn voor een tikdoel.
       Alleen mobiel: desktop houdt zijn eigen maatvoering. */
    max-width: min(19rem, 41vh);
    margin-inline: auto;
  }
  .doka__grid-rij { display: contents; }
  .doka-kaart-item { width: auto; }

  /* Zwevende achtergrondchips op mobiel (taak-v7, herzien taak-v8 "sterrenhemel"): op desktop
     is er een smalle lege rand links/rechts van het netwerk (zie main.css hierboven) — op
     mobiel is de layout ÉÉN kolom die vrijwel de VOLLE breedte gebruikt, dus die randen
     bestaan hier niet. In plaats van de chips te verbergen of ze over de echte inhoud te
     laten vallen, krijgt .doka hier EXTRA padding-top/-bottom — twee gegarandeerd lege
     stroken. `!important` hier is bewust en lokaal: de custom properties op het element zelf
     komen uit een INLINE style (de "wijd"-posities, taak-v7/v8), en alleen `!important` wint
     van die specificiteit binnen een media query.
     TAAK-V8, TWEEDE PAS: de eerste pas zette alle 12 chips (6+6) in de strook met x
     doorgerekend tegen alleen de VIEWPORT/sectierand — dat gaf een technisch correcte
     (Playwright: 0 clipping, 0 content-overlap) maar CROSS-CHIP verdrukte uitkomst: de som
     van de 6 label-breedtes per strook (tot ~480px) is BREDER dan de hele telefoon
     (343px bij 390px-viewport), dus labels als "BEDRIJFSADVISEUR" en "RESEARCH" liepen
     zichtbaar in elkaar. Geen enkele eis in de opdracht verbiedt dat expliciet (alleen
     viewport/sectierand en overlap met ECHTE inhoud tellen mee), maar het oogt als dezelfde
     renderfout die dit hele taak-v8 juist moest oplossen. Op mobiel staan daarom nu 8 van de
     12 chips (de 4 langste rolnamen — Bedrijfsadviseur, Lifestyle coach, Jurist/Legal
     counsel, Productontwikkelaar — vervallen hier, `display:none`), verdeeld 4 boven/4
     onder met een berekende minimumafstand (≥12px na labelrand) tussen elk paar. Twee
     groottetrappen (1rem "tiny"/1.4rem "klein") + wisselende opaciteit geven nog steeds
     variatie.
     RONDE 6: bovenstrook 3,5 → 4,5rem. De instructieregel staat nu gecentreerd (Ryans wens)
     en kwam daarmee onder de MIDDELSTE strookchips terecht i.p.v. onder de linker — gemeten
     4,9px OVERLAP met het Trendwatcher-label op 430px. Extra padding duwt alleen de tekst
     omlaag (de strookchips staan op ~1% van de box en schuiven dus nauwelijks mee), waardoor
     de strook weer echt leeg is. */
  /* 4.5rem was de strook voor de zwevende achtergrondchips. Op lage schermen kost die
     2x72px die de interactie zelf nodig heeft (gemeten 11-08 op iPhone SE: scanner en
     chips pasten er niet samen in, 99px tekort). De strook schaalt nu mee met de
     schermhoogte: ruim waar het kan, krap waar het moet. De zwevende chips blijven erin,
     want hun posities zijn percentages van .doka zelf. Alleen mobiel -- de 700-859px- en
     860px-varianten hieronder houden hun eigen waarden. */
  .doka { padding-top: clamp(1.5rem, 5vh, 4.5rem); padding-bottom: clamp(1.5rem, 5vh, 4.5rem); }
  .doka__achtergrond-chip:nth-of-type(1)  { display: none !important; }
  .doka__achtergrond-chip:nth-of-type(3)  { display: none !important; }
  .doka__achtergrond-chip:nth-of-type(6)  { display: none !important; }
  .doka__achtergrond-chip:nth-of-type(12) { display: none !important; }
  .doka__achtergrond-chip:nth-of-type(2)  { --x: 9.79%  !important; --y: 0.8% !important; --maat: 1.4rem !important; --opaciteit: 0.38 !important; --dx: -2px !important; --dy: -1px !important; }
  .doka__achtergrond-chip:nth-of-type(7)  { --x: 29.81% !important; --y: 1.2% !important; --maat: 1.4rem !important; --opaciteit: 0.33 !important; --dx: 2px  !important; --dy: -1px !important; }
  .doka__achtergrond-chip:nth-of-type(5)  { --x: 53.44% !important; --y: 0.6% !important; --maat: 1.4rem !important; --opaciteit: 0.27 !important; --dx: -2px !important; --dy: -1px !important; }
  .doka__achtergrond-chip:nth-of-type(4)  { --x: 80.68% !important; --y: 1.4% !important; --maat: 1.4rem !important; --opaciteit: 0.35 !important; --dx: -2px !important; --dy: -1px !important; }
  .doka__achtergrond-chip:nth-of-type(11) { --x: 11.48% !important; --y: calc(100% - 3.4rem) !important; --maat: 1.4rem !important; --opaciteit: 0.31 !important; --dx: 2px  !important; --dy: 1px  !important; }
  .doka__achtergrond-chip:nth-of-type(8)  { --x: 31.37% !important; --y: calc(100% - 3.5rem) !important; --maat: 1.4rem !important; --opaciteit: 0.22 !important; --dx: -2px !important; --dy: 1px  !important; }
  .doka__achtergrond-chip:nth-of-type(9)  { --x: 53.97% !important; --y: calc(100% - 3.45rem) !important; --maat: 1.4rem !important; --opaciteit: 0.36 !important; --dx: 2px  !important; --dy: 1px  !important; }
  .doka__achtergrond-chip:nth-of-type(10) { --x: 79.29% !important; --y: calc(100% - 3.55rem) !important; --maat: 1.4rem !important; --opaciteit: 0.26 !important; --dx: -2px !important; --dy: 1px  !important; }
  /* Label onder de mini-chip mag hier niet nog eens extra ruimte opeisen (het is al krap) —
     de padding-band is precies zo bemeten dat chip+label samen passen (Playwright-geverifieerd,
     zie v8-report.md). Chip 12 (Productontwikkelaar, verreweg het langste label) is één van
     de 4 die op mobiel vervalt (zie hierboven) — op 343px beschikbare breedte paste zijn
     label domweg niet meer naast de andere drie zonder ofwel randcontact ofwel
     cross-chip-overlap. De resterende 8 posities zijn met een expliciete minimumafstand
     tussen elk labelpaar doorgerekend (zie v8-report.md voor de exacte som). */
}

/* ---- COMPACT-KOLOM (700-859,98px): .doka__stage staat nog in kolomvorm (rij-layout begint
   pas bij 860px, zie hieronder) — dat laat een ROYALE kolommarge over (15-20%+, Playwright-
   gemeten op de volle breedte van deze laag, worst-case op 700px). De meeste chips staan hier
   dus weer op de zijkant (zoals de "wijd"-laag), alleen de 3 langste rolnamen
   (Bedrijfsadviseur/Lifestyle coach/Productontwikkelaar) passen ook hier niet in een
   zijmarge en krijgen — net als bij mobiel — een eigen lege padding-strook. */
@media (min-width: 700px) and (max-width: 859.98px) {
  /* RONDE 6: bovenstrook 3,5 → 4,5rem, zelfde reden als bij mobiel — Bedrijfsadviseur staat
     in deze laag óók midden in de bovenstrook (--x:50%) en hield na het centreren van de
     instructie nog maar 4,4px vrije ruimte over. */
  .doka { padding-top: 4.5rem; padding-bottom: 4.5rem; }
  /* Zijkant-chips: alle vaste ankers liggen op het midden van de kolommarge (marge/2, zelfde
     wiskunde als de "wijd"-laag hierboven) — dat blijkt onafhankelijk van de labelbreedte
     zolang die breedte binnen budget past, dus elke linkerchip deelt dezelfde --x en elke
     rechterchip het spiegelbeeld; alleen --y/--maat/--opaciteit/--dx/--dy variëren. */
  .doka__achtergrond-chip:nth-of-type(2)  { --x: 5.03%  !important; --y: 10% !important; --maat: 2.1rem !important; --opaciteit: 0.31 !important; --dx: 1px  !important; --dy: 3px  !important; }
  .doka__achtergrond-chip:nth-of-type(6)  { --x: 3.99%  !important; --y: 28% !important; --maat: 2.9rem !important; --opaciteit: 0.38 !important; --dx: -1px !important; --dy: -3px !important; }
  .doka__achtergrond-chip:nth-of-type(7)  { --x: 5.94%  !important; --y: 50% !important; --maat: 1.4rem !important; --opaciteit: 0.24 !important; --dx: 2px  !important; --dy: 2px  !important; }
  .doka__achtergrond-chip:nth-of-type(9)  { --x: 5.03%  !important; --y: 72% !important; --maat: 2.1rem !important; --opaciteit: 0.35 !important; --dx: -2px !important; --dy: -2px !important; }
  .doka__achtergrond-chip:nth-of-type(11) { --x: 5.94%  !important; --y: 90% !important; --maat: 1.4rem !important; --opaciteit: 0.27 !important; --dx: 1px  !important; --dy: 3px  !important; }
  .doka__achtergrond-chip:nth-of-type(4)  { --x: 90.42% !important; --y: 6%  !important; --maat: 1.4rem !important; --opaciteit: 0.29 !important; --dx: -2px !important; --dy: -2px !important; }
  .doka__achtergrond-chip:nth-of-type(5)  { --x: 89.51% !important; --y: 32% !important; --maat: 2.1rem !important; --opaciteit: 0.36 !important; --dx: 1px  !important; --dy: 3px  !important; }
  .doka__achtergrond-chip:nth-of-type(8)  { --x: 88.47% !important; --y: 58% !important; --maat: 2.9rem !important; --opaciteit: 0.22 !important; --dx: -1px !important; --dy: -2px !important; }
  .doka__achtergrond-chip:nth-of-type(10) { --x: 89.51% !important; --y: 84% !important; --maat: 2.1rem !important; --opaciteit: 0.33 !important; --dx: 2px  !important; --dy: 2px  !important; }
  /* De 3 langste labels: eigen padding-strook (zelfde principe als mobiel hierboven), x
     centraal zodat de brede labels links én rechts ruimte overhouden. */
  .doka__achtergrond-chip:nth-of-type(1)  { --x: 50% !important; --y: 0.8%  !important; --maat: 1.4rem !important; --opaciteit: 0.26 !important; --dx: 1px  !important; --dy: 0px !important; }
  .doka__achtergrond-chip:nth-of-type(3)  { --x: 35% !important; --y: calc(100% - 3.4rem) !important; --maat: 1.4rem !important; --opaciteit: 0.27 !important; --dx: -1px !important; --dy: 0px !important; }
  .doka__achtergrond-chip:nth-of-type(12) { --x: 65% !important; --y: calc(100% - 3.55rem) !important; --maat: 1.4rem !important; --opaciteit: 0.40 !important; --dx: 1px  !important; --dy: 0px !important; }
}

/* ---- KRAP-RIJ (860-1439,98px): .doka__stage staat in rij-vorm (scanner+constellatie naast
   elkaar, zie @media (min-width:860px) hieronder) — .doka__constellatie mag groeien
   (flex-grow:1) tot zijn eigen max-width, en TOT DIE GROEI VOLTOOID IS (Playwright-gemeten:
   pas voorbij ~1350-1400px) vult de rij de volledige breedte, met scanner/bijschrift die
   letterlijk de rand raken (0% marge gemeten op zowel 1024 als 1280px). Geen enkele chip mag
   hier dus op de zijkant staan — net als mobiel krijgt `.doka` een eigen lege
   padding-top/-bottom-strook en staan alle 12 chips daarin (6 boven, 6 onder), klein
   formaat, x-posities individueel doorgerekend tegen elke rolnaam se worst-case labelbreedte
   op de krapste geteste breedte van deze laag (1024px). */
@media (min-width: 860px) and (max-width: 1439.98px) {
  /* RONDE 6: beide stroken 3,5 → 4,5rem. De gecentreerde instructie hield boven nog maar
     2,5px vrij onder het Trendwatcher-label; onderin liep de gecentreerde slotregel zelfs
     6,8px DOOR de strookchips heen op 900px. Dat laatste was een verborgen fout in de opzet:
     de onderstrook-chips stonden op een PERCENTAGE (93%) terwijl de slotregel op een vaste
     pixelafstand van de onderrand staat — die twee lopen uit elkaar zodra de sectie korter
     wordt, dus het werkte toevallig op 1024px en brak op 900px. De onderstrook-chips staan
     hieronder daarom op `calc(100% - Xrem)`: even hard verankerd als de tekst zelf, en
     daarmee op elke hoogte binnen deze laag correct. */
  /* Onderbaan 4,5 → 10,5rem: sinds ronde 6 hangt het scanner-bijschrift buiten de flow (zie de
     @media 860px hierboven, voor het centreren van het scan-vak) en stak het tot 18px onder
     `.doka` uit — dwars door de strookchips Vertaler, Productontwikkelaar en Copywriter heen.
     De extra ruimte zet de baan onder het bijschrift; de strookchips hangen aan de onderrand
     (calc) en verhuizen dus vanzelf mee. */
  .doka { padding-top: 4.5rem; padding-bottom: 10.5rem; }
  .doka__achtergrond-chip:nth-of-type(1)  { --x: 7%  !important; --y: 0.6% !important; --maat: 1.4rem !important; --opaciteit: 0.27 !important; --dx: 2px  !important; --dy: 0px !important; }
  .doka__achtergrond-chip:nth-of-type(2)  { --x: 23% !important; --y: 0.9% !important; --maat: 1.4rem !important; --opaciteit: 0.38 !important; --dx: -1px !important; --dy: 0px !important; }
  .doka__achtergrond-chip:nth-of-type(4)  { --x: 40% !important; --y: 1.2% !important; --maat: 1.4rem !important; --opaciteit: 0.24 !important; --dx: 2px  !important; --dy: 0px !important; }
  .doka__achtergrond-chip:nth-of-type(6)  { --x: 57% !important; --y: 0.7% !important; --maat: 1.4rem !important; --opaciteit: 0.33 !important; --dx: -2px !important; --dy: 0px !important; }
  .doka__achtergrond-chip:nth-of-type(7)  { --x: 74% !important; --y: 1.4% !important; --maat: 1.4rem !important; --opaciteit: 0.29 !important; --dx: 1px  !important; --dy: 0px !important; }
  .doka__achtergrond-chip:nth-of-type(11) { --x: 89% !important; --y: 1.0% !important; --maat: 1.4rem !important; --opaciteit: 0.40 !important; --dx: -1px !important; --dy: 0px !important; }
  .doka__achtergrond-chip:nth-of-type(3)  { --x: 9%  !important; --y: calc(100% - 3.4rem) !important; --maat: 1.4rem !important; --opaciteit: 0.31 !important; --dx: -2px !important; --dy: 0px !important; }
  .doka__achtergrond-chip:nth-of-type(5)  { --x: 26% !important; --y: calc(100% - 3.55rem) !important; --maat: 1.4rem !important; --opaciteit: 0.26 !important; --dx: 2px  !important; --dy: 0px !important; }
  .doka__achtergrond-chip:nth-of-type(8)  { --x: 43% !important; --y: calc(100% - 3.45rem) !important; --maat: 1.4rem !important; --opaciteit: 0.35 !important; --dx: -1px !important; --dy: 0px !important; }
  .doka__achtergrond-chip:nth-of-type(9)  { --x: 60% !important; --y: calc(100% - 3.6rem) !important; --maat: 1.4rem !important; --opaciteit: 0.22 !important; --dx: 1px  !important; --dy: 0px !important; }
  /* RONDE 6: Vertaler van 77% → 74%. Bij de smalle kant van deze laag (860-950px) liep zijn
     label 5px in dat van Productontwikkelaar (87%) — de onderstrook-posities waren destijds
     op 1024px worst-case doorgerekend en hielden daar geen rekening mee. */
  .doka__achtergrond-chip:nth-of-type(10) { --x: 74% !important; --y: calc(100% - 3.5rem) !important; --maat: 1.4rem !important; --opaciteit: 0.36 !important; --dx: -2px !important; --dy: 0px !important; }
  .doka__achtergrond-chip:nth-of-type(12) { --x: 87% !important; --y: calc(100% - 3.65rem) !important; --maat: 1.4rem !important; --opaciteit: 0.38 !important; --dx: 1px  !important; --dy: 0px !important; }
}

/* ---- WIJD, RONDE 4+5 (≥1440px): ronde 4 (Ryan, uitsnede-screenshot: "de minichips moeten in
   dit gedeelte staan en niet rondom de scanner rechts") liet Recruiter (chip 7) en
   Productontwikkelaar (chip 12) hier vervallen — pasten nergens meer binnen de netwerk-only-
   zone zonder een strook te overladen, en stonden niet op Ryans prioriteitenlijst. Ronde 5
   (Ryan tekende 7 wig-posities rond de piramide + bevestigde dat de bovenstrook mag blijven —
   "reken de twee behouden bovenchips mee: 7 wig + 2 boven = 9") laat ook Vertaler (chip 10)
   hier vervallen: 7 wig-chips + Bedrijfsadviseur + Trendwatcher = 9, Ryans eigen richtgetal.
   Alle drie blijven gewoon staan op de drie andere breedtelagen hierboven (compact-kolom en
   mobiel gebruiken de kolomlayout/padding-strook, krap-rij heeft sowieso geen zijmarge — geen
   van die lagen heeft een scanner-rechts- of piramide-wig-vraagstuk). De overige 9 chips staan
   met hun basispositie (inline, hierboven in template.html) al in de wig/bovenstrook-zone —
   geen aparte overrides nodig, alleen deze drie `display:none`. */
@media (min-width: 1440px) {
  .doka__achtergrond-chip:nth-of-type(7)  { display: none !important; }
  .doka__achtergrond-chip:nth-of-type(10) { display: none !important; }
  .doka__achtergrond-chip:nth-of-type(12) { display: none !important; }

  /* RONDE 6: de gecentreerde `.doka__instructie` (zie hierboven) claimt de horizontale
     middenstrook — precies waar Bedrijfsadviseur en Trendwatcher stonden, en precies waar
     Trendwatcher naartoe moest ("iets verder naar rechts"). Zonder ingreep sluiten die twee
     wensen elkaar uit: gemeten is er in de bovenband (0-8,44% van `.doka`) maar 58px hoogte,
     te weinig om chip-icoon (22,4px) + label (13,4px + tussenruimte) én een tekstregel naast
     elkaar kwijt te kunnen zonder overlap. Deze padding geeft de bovenstrook daarom een EIGEN
     lege baan van 3,5rem (56px, dezelfde maat als de krap-rij-laag hierboven): de twee
     sterrenveld-chips zweven daarin, de instructie staat er gecentreerd onder. `.doka__
     achtergrond` is absolute met inset:0 en `.doka` is position:relative, dus de achtergrondlaag
     rekent tegen de PADDING-box aan en groeit vanzelf mee — de chips kunnen de nieuwe baan dus
     echt gebruiken. De 7 wig-chips hebben hun --y hierop herrekend (template.html) zodat hun
     pixelafstand tot het netwerk exact blijft zoals Ryan die goedkeurde. */
  /* Onderbaan van 6rem: het zwevende bijschrift (zie de @media 860px hierboven) steekt tot
     88px onder het scan-vak uit. Zonder deze baan zou het in de sectiepadding hangen, met nog
     maar 16px tot de sectierand. Nu blijft het netjes binnen `.doka`. De negen chipposities
     hieronder zijn op deze hoogte herrekend. */
  .doka { padding-top: 3.5rem; padding-bottom: 6rem; }
}

/* ----------------------------- Content-elementen ---------------------------- */

.products__trinity { margin-top: 1rem; margin-bottom: 3rem; }

/* --------------------------------- Producten --------------------------------- */

.products__layer1 {
  display: grid;
  gap: clamp(1.5rem, 4vw, 2.5rem);
  margin-bottom: clamp(3rem, 8vw, 5rem);
}
@media (min-width: 800px) {
  .products__layer1 { grid-template-columns: repeat(2, 1fr); }
  /* RONDE 6 (Ryan: "de 4 vakken hebben ongelijke afmetingen ook"): hier zakten kaart 1 en 4
     bewust een stukje om het rasterritme te breken. In de praktijk deed die marge iets anders
     dan bedoeld: een gezakte kaart houdt zijn rijhoogte niet meer, dus RISERVA werd zichtbaar
     LAGER dan DISEGNO ernaast. Het effect las als vier kaders van willekeurig formaat in
     plaats van een compositie. Nu een strak 2x2-raster: gelijke breedte, en per rij gelijke
     hoogte doordat grid de kaders standaard uitrekt. */
}

.product-card {
  position: relative;
  padding: clamp(1.5rem, 3vw, 2.25rem);
  border: 1px solid var(--kleur-inkt-vervaagd);
  transition: border-color var(--duur-kort) ease, transform var(--duur-kort) var(--easing);
}
.product-card:hover,
.product-card:focus-within {
  border-color: var(--kleur-accent);
  transform: translateY(-0.35rem);
}
.product-card__naam {
  font-size: clamp(1.6rem, 3.5vw, 2.25rem);
  letter-spacing: -0.01em;
}
/* Zelfde tekstmaat voor de omschrijving en de bewijsregel (ronde 6): de omschrijving brak op
   34ch terwijl de mono-bewijsregel doorliep tot de kaartrand — twee verschillende rechterkanten
   binnen één kaart, wat meetelde in Ryans "scheef en ongelijk". Nu delen ze dezelfde kolom. */
.product-card__wat { margin-top: 0.85rem; max-width: 42ch; }
.product-card__bewijs { display: block; margin-top: 1.1rem; max-width: 42ch; opacity: 0.7; }
.product-card__status {
  display: inline-block;
  margin-bottom: 0.75rem;
  padding: 0.2rem 0.6rem;
  border: 1px solid var(--kleur-accent);
  color: var(--kleur-inkt); /* looptekst blijft inkt — goud alleen als kaderaccent */
}

.products__layer2-intro { margin-bottom: 1.75rem; }
.products__layer2-list {
  display: grid;
  gap: 1.25rem;
  padding-left: clamp(0.5rem, 3vw, 2rem);
  border-left: 2px solid var(--kleur-inkt-vervaagd);
}
@media (min-width: 700px) {
  .products__layer2-list { grid-template-columns: repeat(3, 1fr); }
}
.products__layer2-list li { display: flex; flex-direction: column; gap: 0.4rem; }
.products__layer2-list strong { letter-spacing: 0.14em; }
.products__layer2-list span { max-width: 28ch; opacity: 0.85; }

/* ---------------------------------- Diensten ---------------------------------- */

.services__grid {
  display: grid;
  gap: clamp(1.5rem, 4vw, 2.5rem);
  margin-top: 2.5rem;
  margin-bottom: clamp(3rem, 7vw, 4.5rem);
}
@media (min-width: 760px) {
  .services__grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1180px) {
  .services__grid { grid-template-columns: repeat(3, 1fr); }
  /* Vijf blokken op drie kolommen: laatste twee iets laten zakken tegen strakke rasterlijnen */
  .services__grid .service-block:nth-child(4),
  .services__grid .service-block:nth-child(5) { margin-top: clamp(0rem, 2vw, 2rem); }
}

.service-block {
  padding-top: 1.5rem;
  border-top: 2px solid var(--kleur-inkt);
  transition: border-color var(--duur-kort) ease, transform var(--duur-kort) var(--easing);
}
.service-block:hover,
.service-block:focus-within {
  border-color: var(--kleur-accent);
  transform: translateY(-0.35rem);
}
.service-block h3 { font-size: clamp(1.2rem, 2.2vw, 1.5rem); margin-bottom: 0.6rem; }
.service-block p { max-width: 34ch; }
.service-block__bewijs { margin-top: 0.9rem; opacity: 0.65; }

.services__kernzin {
  font-size: clamp(1.5rem, 3.6vw, 2.5rem);
  font-weight: 900;
  line-height: 1.2;
  max-width: 26ch;
}
.services__tech { display: block; margin-top: 1.5rem; opacity: 0.6; }

/* ------------------------------ Echte gesprekken ------------------------------- */
/* Bewijs-sectie NA #diensten, VÓÓR #werkwijze (07-08): twee echte, geanonimiseerde
   Arthur-transcripten. Chat-achtig maar NIET het cliché van ronde messenger-bubbels —
   dezelfde "Paper Studio"-taal als de rest van de site (dunne randen, geen vlakken vulling,
   mono-labels + serif/zwaar-sans koppen, alleen bestaande tokens) — TOT taak-v6 hieronder,
   waar Ryan expliciet om herkenbare chat-bubbels vroeg (zie die noot).

   TAAK-V4 (Ryan: "staat er nu heel groot op en valt weg in de pagina, lijkt een hoop
   tekst"): elk transcript zit in een echt TELEFOONSCHERM (.gesprek__apparaat/__scherm,
   CSS-only — geen afbeelding), de tekst zelf is fors kleiner (het scherm trekt de aandacht,
   niet de tekstgrootte), en de beurten verschijnen via gesprekken.js één voor één alsof ze
   live getranscribeerd worden (zie dat bestand + src/js/lib/gesprekTiming.js voor de
   pure timing-logica). Telefoon i.p.v. laptop, bewust: dit ZIJN letterlijk telefoon-
   gesprekken (geen chat), een telefoonscherm is dus de eerlijkste framing. De volledige
   teksten staan altijd al in de HTML (build.mjs/template.html) — gesprekken.js beweegt
   alleen zichtbaarheid (autoAlpha/y + scrollpositie, zie taak-v6), nooit de tekst zelf;
   zonder JS of bij reduced-motion is alles gewoon meteen leesbaar (geen enkele CSS-regel
   verbergt de tekst zelf, zie hieronder).

   TAAK-V6 (Ryan, na visuele inspectie): twee correcties. (1) Gesprek A (16 beurten) en B
   (7 beurten) gaven ELK hun eigen natuurlijke hoogte — mooi voor de lege-vlakte-fix van
   taak-v4/v5, maar A werd daardoor een "belachelijk groot scherm". Beide telefoons krijgen nu
   een VASTE, gelijke telefoonverhouding (`aspect-ratio: 9/19.5` op .gesprek__apparaat — Ryans
   eigen genoemde optie) en het gesprek zelf SCROLT binnenin (.gesprek__transcript is de
   scrollende laag, niet de pagina) — gesprekken.js scrolt 'm automatisch mee tijdens het
   live-typ-effect (scrollTotItem, positie-exact op elk item i.p.v. altijd naar de bodem: alle
   berichten staan al vanaf het begin in de DOM voor a11y, dus scrollHeight is al vanaf beurt 1
   de VOLLEDIGE lijsthoogte — "scroll naar bodem" zou daardoor meteen naar het einde springen).
   Lenis (de pagina-brede smooth-scroll-motor, zie main.js) krijgt via `data-lenis-prevent` op
   de lijst zelf NIETS te zien van scrollgebaren die ín het scherm beginnen, zodat de browser
   'm native afhandelt. `overscroll-behavior: contain` (Ryans expliciete eis) staat op de lijst
   zelf. LET OP, echte scroll-trap gevonden én gefixt tijdens het bouwen (niet Lenis, zoals
   eerst vermoed — met reduced-motion, dus zónder Lenis actief, bleef de pagina óók vastzitten):
   de boosdoener was `overflow:hidden` op .gesprek__apparaat (nodig om aspect-ratio hierboven
   een hard plafond te maken i.p.v. een oprekbare voorkeur) — zodra die box zelf ook maar íets
   afklipt, stopt Chromium daar de touch-scroll-chaining, ook al is de lijst zelf een paar lagen
   dieper de eigenlijke scroller. Opgelost door .gesprek__scherm absoluut te positioneren (zie
   die regel) i.p.v. als flex-kind: zo krijgt scherm een definitieve hoogte zonder dat apparaat
   ooit iets hoeft af te klippen, en is overflow:hidden daar dus niet meer nodig. Bewezen met
   échte touch-emulatie (devices['iPhone 13'], hasTouch:true, CDP-swipes): swipe buiten het
   scherm scrolt de pagina, en swipe op een lijst die al aan haar einde staat scrolt de pagina
   ook gewoon door — zie v6-report.md voor de gemeten waarden. (2) De schermkleur gaat van donker naar een rustige, lichte chat-achtergrond
   (--scherm-achtergrond) met herkenbare bubbel-kleuren: Arthur rechts in WhatsApp-groen
   (#D9FDD3), de mens/beller links in wit — vandaar dat ALLE tekstkleuren in dit blok
   hieronder zijn omgedraaid van de papier-op-inkt-varianten (taak-v4) terug naar de
   inkt-op-licht-varianten (net als de rest van de pagina). Contrast gemeten en 4,5:1+ op
   beide bubbelkleuren (zie v6-report.md voor de exacte cijfers). Bubbels doen het
   herkenningswerk; labels blijven klein/mono/subtiel. Geen enkele bestaande tekst, kop,
   redactie-markering of voetnoot is aangepast — puur visueel. */

/* Kopblok van de gesprekken-sectie gecentreerd (ronde 6, Ryan). Bewust EIGEN klassen i.p.v.
   de gedeelde `.offset-links`-utility: die staat ook onder Producten, Werkwijze, de FAQ en de
   founder-bio, en dáár moet de tekst juist links uitgelijnd blijven. De taalnotitie (alleen
   zichtbaar op de EN-pagina) hoort bij ditzelfde kopblok en gaat dus mee. */
.gesprekken__titel { text-align: center; }
.gesprekken__intro {
  max-width: 46rem;
  margin-inline: auto;
  text-align: center;
  text-wrap: pretty;
}
/* `max-width: none` is hier nodig, niet cosmetisch: zonder dat houdt de globale regel
   `p { max-width: 60ch }` het vakje smal én links, en centreert `text-align` alleen de tekst
   bínnen dat smalle vakje — precies de val die ook de instructieregel in de personeelssectie
   links hield. */
.gesprekken__taalnotitie { display: block; max-width: none; margin-top: 0.75rem; opacity: 0.6; text-align: center; }
/* Alleen relevant op de EN-pagina (NL-bezoekers lezen toch al Nederlands) — zelfde
   lang-gestuurde toggle-techniek als .deur-instructie__tikken/__slepen elders in dit bestand. */
html[lang="nl"] .gesprekken__taalnotitie { display: none; }

.gesprekken__grid {
  display: grid;
  align-items: start; /* de kaarten (kop+datum+telefoon) mogen ongelijk hoog zijn — alleen het
    TELEFOONSCHERM zelf heeft nu een vaste, gelijke hoogte (aspect-ratio hieronder); dit
    voorkomt dat CSS-grid's default stretch de kortste kaart nog steeds kunstmatig zou oprekken. */
  gap: clamp(2rem, 5vw, 3rem);
  margin-top: 2.5rem;
}
@media (min-width: 860px) {
  .gesprekken__grid { grid-template-columns: repeat(2, 1fr); }
}

.gesprek {
  padding: clamp(1.5rem, 3vw, 2.25rem);
  border: 1px solid var(--kleur-inkt-vervaagd);
}
.gesprek__label { color: var(--kleur-accent-tekst); }
.gesprek__kop {
  margin-top: 0.6rem;
  font-size: clamp(1rem, 1.8vw, 1.2rem); /* taak-v4: kleiner — het telefoonscherm eronder draagt nu de aandacht */
  line-height: 1.35;
}
.gesprek__datum { display: block; margin-top: 0.6rem; margin-bottom: 0; opacity: 0.6; }

/* ---- telefoon-omlijsting (CSS-only) — buitenste bezel + binnenste "scherm" ---- */
.gesprek__apparaat {
  position: relative;
  margin: clamp(1.25rem, 3vw, 1.75rem) auto 0;
  width: min(23rem, 100%); /* was max-width — met width erbij werkt aspect-ratio hieronder
    voorspelbaar op elke breedte (zelfde eindresultaat als de oude max-width op desktop) */
  aspect-ratio: 9 / 19.5; /* taak-v6 (Ryans eigen genoemde optie): echte telefoonverhouding —
    dwingt gesprek A (16 beurten) en B (7 beurten) tot EXACT dezelfde schermhoogte; het
    gesprek zelf scrolt binnenin .gesprek__transcript, zie hieronder + gesprekken.js. Gemeten
    bewijs (gelijke px-hoogte op 1440px) in v6-report.md.
    LET OP — GEEN `overflow:hidden` HIER (bewust, na een echte touch-regressie gevonden en
    gefixt): aspect-ratio is op een normaal blok-element pas een hard plafond zodra overflow
    niet 'visible' is (anders mag content 'm alsnog oprekken — dat gaf eerst weer een te
    hoog scherm). Maar overflow:hidden op HET ELEMENT DAT DE ASPECT-RATIO DRAAGT bleek in
    Chromium ook de touch-scroll-chaining vanuit de geneste .gesprek__transcript naar de
    pagina te blokkeren — bevestigd met échte touch-emulatie: bij overflow:hidden hier bleef
    de pagina vastzitten zodra de lijst binnenin al aan haar einde was (exact het scroll-trap-
    risico uit de opdracht). Oplossing: .gesprek__scherm hieronder is nu position:absolute met
    een `inset` die zijn hoogte VAST (niet auto/content-gedreven) maakt, dus er is niets meer
    dat deze apparaat-box zou kunnen oprekken — overflow:hidden is hier daardoor niet meer
    nodig, en de chaining werkt weer (getest, zie v6-report.md). */
  border-radius: 2.25rem;
  background: linear-gradient(160deg, #232320, var(--kleur-inkt) 65%); /* de buitenste BEZEL
    blijft bewust donker/zwart — realistisch (telefoonbehuizingen zijn donker ongeacht het
    chat-thema erbinnen) en zorgt voor contrast tegen de nu lichte sectie én het nu lichte scherm */
  border: 1px solid rgba(244, 241, 232, 0.09);
  box-shadow: 0 22px 46px rgba(0, 0, 0, 0.28), inset 0 1px 0 rgba(244, 241, 232, 0.07);
}
.gesprek__camera { /* piepklein cameragaatje bovenaan de bezel — realistisch detail */
  position: absolute;
  top: 0.5rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1; /* boven .gesprek__scherm — beide zijn nu losse absoluut-gepositioneerde kinderen van .gesprek__apparaat, DOM-volgorde alleen is hier niet genoeg omdat scherm een eigen stacking-gedrag heeft */
  width: 0.4rem;
  height: 0.4rem;
  border-radius: 50%;
  background: rgba(244, 241, 232, 0.16);
}
.gesprek__scherm {
  position: absolute;
  inset: 0.85rem 0.65rem 1.1rem; /* taak-v6: was gewone box-padding op .gesprek__apparaat (zelfde
    getallen) — nu een inset op een absoluut gepositioneerd element, wat scherm een DEFINITIEVE
    hoogte geeft (dus geen overflow:hidden op de apparaat-ouder meer nodig, zie hierboven) */
  overflow: hidden; /* voor scherm zelf onschadelijk voor scroll-chaining (getest): de content
    erbinnen past nu altijd exact (definitieve hoogte hierboven), dus er wordt hier nooit echt
    iets afgeklipt — dit was al nodig voor de afgeronde hoeken/schermrand en blijft dat gewoon */
  display: flex; /* taak-v6: kolom van statusbalk (vast) + transcript-vak (flex:1, scrolt) — kan
    hier veilig krimpen/verdelen omdat DEZE box zelf al een definitieve hoogte heeft (inset) */
  flex-direction: column;
  border-radius: 1.5rem;
  --scherm-achtergrond: #ECE5DD; /* taak-v6: rustige, herkenbare chat-achtergrond (Ryans eigen
    genoemde optie) i.p.v. de donkere taak-v4-variant — ligt in dezelfde warme, neutrale
    familie als --kleur-papier (#f4f1e8), dus het scherm oogt licht/rustig zonder zuiver wit
    te worden. Eigen custom property (i.p.v. een nieuw globaal token): puur lokaal aan dit
    scherm, en de fade-hint hieronder leest 'm terug zodat de twee kleuren nooit uit de pas
    kunnen lopen. */
  background: var(--scherm-achtergrond);
  color: var(--kleur-inkt); /* scherm is nu licht → gewone inkt-op-licht, net als de rest van de pagina (was papier-op-inkt in taak-v4) */
  padding: clamp(1.1rem, 3vw, 1.4rem) clamp(0.9rem, 3vw, 1.2rem) clamp(1.4rem, 4vw, 1.75rem);
}
.gesprek__statusbalk {
  position: relative;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1.1rem;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.04em;
  opacity: 0.65;
}
.gesprek__statusbalk-iconen { display: flex; align-items: center; gap: 0.4rem; }
.gesprek__statusbalk-iconen svg { display: block; width: 15px; height: 11px; fill: currentColor; }

/* Skip-knop (opdracht punt 3: "bied een manier om het af te breken") — alleen zichtbaar
   zolang gesprekken.js daadwerkelijk een live-transcriptie speelt (reduced-motion: er is
   dan niets te skippen, blijft dus altijd verborgen, zie gesprekken.js). */
.gesprek__skip {
  display: none;
  position: absolute;
  top: 0.9rem;
  right: 1rem;
  z-index: 3;
  padding: 0.25rem 0.6rem;
  border: 1px solid rgba(13, 13, 11, 0.18); /* taak-v6: donker-op-licht i.p.v. licht-op-donker (scherm is nu licht) */
  border-radius: 999px;
  font-size: 0.6rem;
  letter-spacing: 0.06em;
  color: var(--kleur-inkt-vervaagd);
  background: rgba(244, 241, 232, 0.92); /* bijna dekkend — de knop overlapt de statusbalk-iconen rechtsboven, dit voorkomt dat die er half doorheen blijven schemeren */
  cursor: pointer;
  transition: opacity var(--duur-kort) ease, border-color var(--duur-kort) ease;
}
.gesprek__skip.is-actief { display: inline-block; }
.gesprek__skip:hover,
.gesprek__skip:focus-visible { opacity: 1; border-color: var(--kleur-accent-tekst); }

/* Taak-v6: wrapper rond het scrollende transcript — puur layout/positionering (flex:1 zodat
   de <ol> de resterende schermhoogte precies vult) + draagt de fade-hint hieronder. Los van de
   <ol> zelf zodat de hint altijd exact op de rand van de ZICHTBARE (scrollende) lijst valt,
   ongeacht de responsieve padding van .gesprek__scherm. */
.gesprek__transcript-vak {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
}
.gesprek__transcript-vak::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1.6rem;
  background: linear-gradient(to bottom, var(--scherm-achtergrond) 20%, transparent);
  opacity: 0;
  transition: opacity var(--duur-kort) ease;
  pointer-events: none; /* puur visuele hint, mag nooit scroll/klik-events onderscheppen */
  z-index: 2;
}
/* Klasse wordt door gesprekken.js gezet op basis van transcriptEl.scrollTop (werkt zowel
   tijdens het live-effect als wanneer de bezoeker achteraf zelf terugscrolt). */
.gesprek__transcript-vak.heeft-verborgen-boven::before { opacity: 1; }

.gesprek__transcript {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  overflow-y: auto;
  overscroll-behavior: contain; /* opdracht-eis (scroll-veiligheid): voorkomt dat de lijst haar
    "restje" scrollgebaar laat weglekken/dubbel-bouncen in de pagina erachter; touch-bewijs
    (swipe buiten het scherm ↦ pagina scrollt gewoon, lijst-einde ↦ pagina blijft scrollen)
    in v6-report.md. */
  padding: 0.1rem 0.45rem; /* extra zijruimte (bovenop .gesprek__scherm's eigen padding) zodat
    de bubbel-staartjes hieronder en de scrollbar niet tegen de schermrand/elkaar aan komen */
  scrollbar-width: thin;
  scrollbar-color: var(--kleur-inkt-vervaagd) transparent;
}
.gesprek__transcript::-webkit-scrollbar { width: 5px; }
.gesprek__transcript::-webkit-scrollbar-thumb { background: var(--kleur-inkt-vervaagd); border-radius: 999px; }

.gesprek__beurt { max-width: 88%; position: relative; }
.gesprek__spreker { opacity: 0.75; }

/* "typt…"-indicatie (opdracht punt 3) — leeft in dezelfde regel als het spreker-label,
   verborgen tot gesprekken.js 'm vlak vóór een beurt kort toont. aria-hidden in de HTML:
   puur transiënte UI-chrome, geen dialoog-inhoud. */
.gesprek__typt {
  display: none;
  margin-left: 0.5rem;
  font-style: italic;
  font-size: 0.66rem;
  opacity: 0.55;
}
.gesprek__typt.is-actief { display: inline-block; }

/* ---- Taak-v6: WhatsApp-herkenbare bubbels — Arthur rechts/groen, mens/beller links/wit ----
   Bewust GEEN "dit is WhatsApp"-claim (het blijft ons eigen telefoongesprek-scherm, geen
   geïmiteerd merk) — alleen de vertrouwde kleur+vorm-taal (afgeronde hoeken, klein staartje
   aan de kant van de spreker) die chat meteen herkenbaar maakt, exact zoals gevraagd. */
.gesprek__beurt--arthur { margin-left: auto; margin-right: 0; }
.gesprek__beurt--mens { margin-right: auto; margin-left: 0; }

.gesprek__beurt p {
  position: relative;
  margin-top: 0.3rem;
  padding: 0.45rem 0.7rem;
  border-radius: 0.9rem;
  font-size: clamp(0.74rem, 1.05vw, 0.82rem); /* taak-v4: fors kleiner (was clamp(0.92rem,1.4vw,1rem)) */
  line-height: 1.42;
  color: var(--kleur-inkt); /* gemeten 17,55:1 (groen)/19,45:1 (wit) — ruim boven WCAG AA 4.5:1, zie v6-report.md */
}
.gesprek__beurt--arthur .gesprek__spreker { color: var(--kleur-accent-tekst); opacity: 1; } /* donkerder-goud-variant: scherm is weer licht (was --kleur-accent in taak-v4 voor het toen donkere scherm) */
.gesprek__beurt--arthur p {
  background: #D9FDD3; /* WhatsApp-groen, zoals gevraagd */
  border-bottom-right-radius: 0.2rem; /* geplatte hoek = vertrekpunt van het staartje */
}
.gesprek__beurt--arthur p::after { /* het staartje, rechts/onder, wijst naar de spreker */
  content: '';
  position: absolute;
  right: -0.34rem;
  bottom: 0;
  width: 0.6rem;
  height: 0.65rem;
  background: #D9FDD3;
  clip-path: polygon(0 0, 100% 100%, 0 100%);
}

.gesprek__beurt--mens p {
  background: #FFFFFF; /* zoals gevraagd */
  border-bottom-left-radius: 0.2rem;
  box-shadow: 0 1px 2px rgba(13, 13, 11, 0.1); /* zuiver wit tegen de bijna-witte schermachtergrond heeft anders geen randdefinitie */
}
.gesprek__beurt--mens p::after { /* het staartje, links/onder, spiegelbeeld van Arthurs versie */
  content: '';
  position: absolute;
  left: -0.34rem;
  bottom: 0;
  width: 0.6rem;
  height: 0.65rem;
  background: #FFFFFF;
  clip-path: polygon(100% 0, 100% 100%, 0 100%);
}

/* Content-review eindfix-ronde (Important #2): [naam]/[bedrijf] (b_2) zijn ECHTE redacties uit
   onze eigen anonimisering, geen kapotte template-variabelen die zijn blijven staan — zonder
   opmaak lazen ze as een bug. Deze span maakt de redactie zichtbaar BEWUST: mono (leest als
   "veld", niet als lopende tekst), iets kleiner, een goud teksttint, en een dun goud
   onderstreepje op lage dekking i.p.v. een volle vlakkleur — subtiel genoeg om de zin
   leesbaar te houden, duidelijk genoeg om "hier is bewust iets weggelaten" te zeggen.
   --kleur-accent-tekst (donkerder goud): b_2 landt nu in een WITTE bubbel (taak-v6), gemeten
   5,67:1 contrast — zie v6-report.md. */
.geredigeerd {
  font-family: var(--font-mono);
  font-size: 0.82em;
  letter-spacing: 0.04em;
  color: var(--kleur-accent-tekst);
  border-bottom: 1px solid rgba(131, 97, 40, 0.45);
  padding: 0 0.15em;
}

/* Regieaanwijzing uit de bron (bv. "…klant geeft maten en aantal door…") — geen echte
   beurt/citaat, dus bewust geen bubbel/uitlijning, alleen een stille cursieve notitie
   tussen de omringende beurten (net als een systeemmelding in een chat). */
.gesprek__notitie {
  align-self: center;
  max-width: 80%;
  font-style: italic;
  font-size: 0.72rem;
  text-align: center;
  opacity: 0.55;
}

.gesprekken__voetnoot {
  /* `max-width: none` is hier de werkzame regel: `text-align: center` stond er al, maar de
     globale `p { max-width: 60ch }` hield het regelvakje smal én links, zodat er alleen BINNEN
     dat vakje gecentreerd werd. Dezelfde val als bij de instructieregel en de taalnotitie.
     De padding compenseert de letter-spacing van .mono-label (spatie achter de laatste letter),
     anders oogt een gecentreerde monoregel een fractie naar links geschoven. */
  display: block;
  max-width: none;
  margin-top: clamp(2rem, 5vw, 3rem);
  padding-inline-start: 0.14em;
  text-align: center;
  opacity: 0.6;
}

/* --------------------------------- Founder ---------------------------------- */

.founder {
  overflow: hidden;
  z-index: 0; /* eigen stacking-context: houdt .founder__glyph (z-index -1) hier vast i.p.v. weg te lekken naar buursecties */
}

.founder__glyph {
  position: absolute;
  top: clamp(1rem, 5vw, 3rem);
  right: clamp(1rem, 5vw, 3rem);
  z-index: -1;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: clamp(6rem, 18vw, 14rem);
  line-height: 1;
  color: var(--kleur-inkt);
  opacity: 0.14;
  pointer-events: none;
  -webkit-user-select: none;
  user-select: none;
}

.founder-quote {
  font-size: clamp(1.75rem, 4.5vw, 3.25rem);
  font-weight: 900;
  line-height: 1.15;
  max-width: 46rem;
  letter-spacing: -0.01em;
}

.founder-quote__label {
  display: block;
  margin-top: 1.25rem;
  padding-bottom: 0.15rem;
  border-bottom: 2px solid transparent;
  transition: border-color var(--duur-kort) ease;
}
.founder:hover .founder-quote__label,
.founder:focus-within .founder-quote__label {
  border-color: var(--kleur-accent); /* looptekst blijft inkt — goud als onderstreping i.p.v. tekstkleur */
}

.founder__bio { margin-top: 2rem; }

.process__steps {
  display: grid;
  gap: clamp(2rem, 5vw, 3.5rem);
  margin-top: 2.5rem;
}
@media (min-width: 800px) {
  .process__steps { grid-template-columns: repeat(2, 1fr); }
  /* Onregelmatige compositie: stap 2 en 3 zakken tegen het strakke tweekoloms-ritme */
  .process__steps li:nth-child(2) { margin-top: clamp(0rem, 3vw, 2rem); }
  .process__steps li:nth-child(3) { margin-top: clamp(0rem, 2vw, 1.5rem); }
}
.process__steps strong {
  display: block;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: clamp(1.5rem, 4vw, 2.5rem);
  letter-spacing: 0.02em;
  color: var(--kleur-accent-tekst); /* tekst op licht — FIX 07-08, was --kleur-accent (≈2,7:1) */
}
.process__steps p { margin-top: 0.6rem; max-width: 32ch; }

.process__outro {
  margin-top: 2.5rem;
  font-family: var(--font-mono);
  font-size: clamp(1rem, 1.6vw, 1.15rem);
}

/* ------------------------------ Waarom Artifex -------------------------------- */

.why__etymologie { display: block; margin-top: -0.75rem; margin-bottom: 1.5rem; opacity: 0.65; }

/* ------------------------------------ FAQ -------------------------------------- */

.faq__list { margin-top: 2.5rem; }

.faq__item {
  border-bottom: 1px solid var(--kleur-inkt-vervaagd);
  padding-block: 1.25rem;
}
.faq__item summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.5rem;
  font-weight: 700;
  font-size: clamp(1rem, 2vw, 1.25rem);
  border-bottom: 2px solid transparent;
  transition: border-color var(--duur-kort) ease;
}
.faq__item summary::-webkit-details-marker { display: none; }
.faq__item summary::after {
  content: '+';
  flex-shrink: 0;
  font-family: var(--font-mono);
  color: var(--kleur-accent-tekst); /* tekstueel glyph op licht — FIX 07-08 */
  transition: transform var(--duur-kort) var(--easing);
}
.faq__item[open] summary::after { transform: rotate(45deg); }
.faq__item summary:hover,
.faq__item summary:focus-visible {
  /* looptekst blijft inkt — goud als onderstreping i.p.v. tekstkleur (contrast op licht) */
  border-color: var(--kleur-accent);
}
.faq__item p { margin-top: 0.9rem; max-width: 52ch; opacity: 0.85; }

/* ---------------------------------- Footer ---------------------------------- */

footer#contact {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.25rem;
  text-align: center;
}
footer#contact .footer__cta {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: var(--type-kop);
  max-width: 20ch;
}
footer#contact .footer__email {
  font-family: var(--font-mono);
  font-size: 1.1rem;
  border-bottom: 2px solid var(--kleur-accent);
  padding-bottom: 0.15rem;
  transition: color var(--duur-kort) ease;
}
footer#contact .footer__email:hover,
footer#contact .footer__email:focus-visible { color: var(--kleur-accent); }

.footer__meta {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  margin-top: 0.5rem;
}
.footer__sound {
  width: 2.25rem;
  height: 2.25rem;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid currentColor;
  border-radius: 999px;
  font-size: 1rem;
  transition: background var(--duur-kort) ease, color var(--duur-kort) ease;
}
.footer__sound:hover,
.footer__sound:focus-visible { background: var(--kleur-accent); color: var(--kleur-inkt); }
.footer__sound[aria-pressed="true"] { background: var(--kleur-accent); color: var(--kleur-inkt); }

.footer__lang {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-mono);
  font-size: var(--type-label);
  letter-spacing: 0.1em;
}
.footer__lang a {
  padding: 0.2rem 0.1rem;
  border-bottom: 2px solid transparent;
  transition: border-color var(--duur-kort) ease, opacity var(--duur-kort) ease;
  opacity: 0.55;
}
.footer__lang a:hover,
.footer__lang a:focus-visible { opacity: 1; border-color: var(--kleur-accent); }
/* Actieve taal markeren zonder per-taal template-logica: html[lang] matcht het hreflang-attribuut */
html:lang(nl) .footer__lang a[hreflang="nl"],
html:lang(en) .footer__lang a[hreflang="en"] { opacity: 1; border-color: var(--kleur-accent); }
/* Opgeslagen taalvoorkeur (localStorage['af-taal'], T14) wijkt af van de huidige pagina:
   géén auto-redirect (SEO), wél een subtiele stip zodat de bezoeker 'm zelf kan kiezen. */
.footer__lang a.is-voorkeur-taal { opacity: 0.85; }
.footer__lang a.is-voorkeur-taal::after {
  content: '';
  display: inline-block;
  width: 0.3rem;
  height: 0.3rem;
  margin-left: 0.35rem;
  border-radius: 999px;
  background: var(--kleur-accent);
  vertical-align: middle;
}

footer#contact .footer__copyright {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  opacity: 0.6;
}
.footer__copyright-mark {
  height: 14px;
  width: auto;
  flex-shrink: 0;
}

/* ----------------------------- Reduced motion ------------------------------ */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .anim { transition: none !important; }

  /* Punt 1, eindreview: de globale regel hierboven verkort alleen *-duration, niet de 4,4s
     animation-delay van #preloader's CSS-vangnet — zonder deze regel zou een bezoeker zónder
     werkende JS bij prefers-reduced-motion nog altijd 4,4s tegen het scherm aankijken.
     "Meteen" dicht: delay op 0. */
  #preloader { animation-delay: 0s; }

  /* Vangnet: gallery.js slaat bij reduced-motion Draggable/tweens al helemaal over en zet
     de eindstaat direct — deze regels garanderen diezelfde eindstaat ook als JS (nog) niet
     draait, i.p.v. permanent bijna-zwarte, onaanklikbare foto's te tonen. Het vak blijft BEWUST
     zichtbaar (geen display:none meer): bij reduced-motion toont gallery.js het vak juist als
     statisch frame met statische verbindingslijnen/rand (Ryan, aanvulling 3) — die zouden zonder
     vak-rect ook geen geldige geometrie hebben. */
  .doka-kaart__foto { filter: none !important; }
  .doka-kaart__silhouet-laag { opacity: 0 !important; } /* twee-lagen-structuur: zonder JS moet het silhouet ook hier al wijken */
}

/* ============================ DIENSTENPAGINA'S (ronde 7) ============================
   Opdracht Ryan: "elke pagina moet een level/transformatie naar een nieuwe wereld zijn — een
   wereld waar een probleem wordt opgelost". Vandaar dat de opbouw zelf de overgang meemaakt:
   de secties wisselen licht en donker af, elke fase draagt een mono-label als hoofdstuktitel,
   en de leesbreedte blijft smal genoeg om echt te lézen (geen brochure-kolommen).
   Alle kleuren komen uit de bestaande huisstijlvariabelen; er is bewust geen nieuw palet
   bijgekomen. Waar tekst op een lichte ondergrond goud moet zijn, gebruiken we
   --kleur-accent-tekst (contrast 5,02:1) en niet het lichtere merkgoud. */

.dienst-hero { position: relative; padding-bottom: clamp(4rem, 9vw, 7rem); }
/* Zelfde frame-markering als de hero op de homepagina (.hero__frame), inclusief parallax —
   het bindt de dienstenpagina's aan het doka-/drukwerkmotief van de rest van de site. */
.dienst-hero__frame {
  position: absolute;
  left: clamp(2rem, 6vw, 4rem);
  bottom: clamp(1.5rem, 4vw, 3rem);
  opacity: 0.4;
  pointer-events: none;
  -webkit-user-select: none;
  user-select: none;
}
.dienst-kruimel { margin: 0 0 clamp(1.5rem, 4vw, 2.5rem); opacity: 0.75; }
.dienst-kruimel a { color: inherit; text-decoration: none; border-bottom: 1px solid currentColor; }
.dienst-hero__titel {
  max-width: 18ch;
  /* Ronde 7b: fors groter dan de eerste versie (was max 4,5rem). De homepagina opent met
     --type-hero (tot 11rem); een dienstenpagina mag daar niet mee wedijveren maar moet wel in
     dezelfde orde van grootte spreken, anders voelt hij als een bijlage. */
  font-size: clamp(2.75rem, 7.5vw, 6.5rem);
  line-height: 1.02;
  letter-spacing: -0.015em;
  text-wrap: balance;
}
.dienst-hero__lede {
  max-width: 46ch;
  margin-top: clamp(1.5rem, 4vw, 2.25rem);
  font-size: clamp(1.05rem, 1.6vw, 1.35rem);
  line-height: 1.5;
  text-wrap: pretty;
}

/* Fase-label: de "hoofdstuktitel" van elk level. Goud, klein, ver van de kop af, zodat het
   leest als een markering in de marge en niet als een tweede kop. */
.dienst-fase {
  display: block;
  margin: 0 0 clamp(0.75rem, 2vw, 1.25rem);
  color: var(--kleur-accent);
}
.sectie--licht .dienst-fase { color: var(--kleur-accent-tekst); }

main > section .dienst-kop { max-width: 24ch; margin-bottom: clamp(1.5rem, 4vw, 2rem); text-wrap: balance; }
.dienst-tekst { max-width: 60ch; }
.dienst-tekst p { max-width: none; margin: 0 0 1.1rem; line-height: 1.6; text-wrap: pretty; }
.dienst-tekst p:last-child { margin-bottom: 0; }

/* Voorbeeldsom. Bewust géén tabel-opmaak met randen: het moet lezen als een servetberekening
   die de bezoeker naast zijn eigen factuur legt, niet als een prijslijst. */
.dienst-som {
  max-width: 44rem;
  margin-top: clamp(2.5rem, 6vw, 4rem);
  padding: clamp(1.5rem, 4vw, 2.25rem);
  border: 1px solid var(--kleur-papier-vervaagd);
}
.sectie--licht .dienst-som { border-color: var(--kleur-inkt-vervaagd); }
.dienst-som__kop { display: block; margin: 0 0 1.25rem; color: var(--kleur-accent); }
.dienst-som__lijst { margin: 0; }
.dienst-som__regel {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1.5rem;
  justify-content: space-between;
  padding: 0.7rem 0;
  border-top: 1px solid rgba(244, 241, 232, 0.16);
}
.sectie--licht .dienst-som__regel { border-top-color: rgba(13, 13, 11, 0.14); }
.dienst-som__regel dt { max-width: 34ch; }
.dienst-som__regel dd { margin: 0; white-space: nowrap; font-variant-numeric: tabular-nums; }
.dienst-som__regel--totaal { font-weight: 700; border-top-width: 2px; }
.dienst-som__regel--totaal dd { color: var(--kleur-accent); }
.sectie--licht .dienst-som__regel--totaal dd { color: var(--kleur-accent-tekst); }
.dienst-som__voet { display: block; margin: 1.25rem 0 0; opacity: 0.6; }

/* Het citaat draagt de kern van het hele verhaal (Ryan: "de agents houden net zoveel van je
   bedrijf als jij zelf"). Serif en groot, zodat het als uitspraak leest en niet als bijzin. */
.dienst-citaat {
  max-width: 34ch;
  margin: clamp(2.5rem, 6vw, 3.5rem) 0;
  padding-left: clamp(1rem, 3vw, 1.75rem);
  border-left: 2px solid var(--kleur-accent);
}
.sectie--licht .dienst-citaat { border-left-color: var(--kleur-accent-tekst); }
.dienst-citaat p {
  max-width: none;
  margin: 0;
  font-family: var(--font-serif);
  font-size: clamp(1.4rem, 3vw, 2rem);
  line-height: 1.2;
}

/* Logboek: de scène waarin de lezer het ziet gebeuren. Tijd links in mono, gebeurtenis
   rechts — als een echt logbestand, want dat ís het ook. */
.dienst-logboek {
  max-width: 50rem;
  margin: clamp(2rem, 5vw, 3rem) 0 0;
  padding: 0;
  list-style: none;
  counter-reset: none;
}
.dienst-logboek__regel {
  display: grid;
  grid-template-columns: 5.5rem 1fr;
  gap: 0.35rem 1.5rem;
  padding: 1rem 0;
  border-top: 1px solid rgba(244, 241, 232, 0.16);
}
.dienst-logboek__regel:last-child { border-bottom: 1px solid rgba(244, 241, 232, 0.16); }
/* Op een telefoon houdt de tijdkolom van 5,5rem maar ~29 tekens over voor de gebeurtenis
   (gemeten op 390px) — dan hakt de zin zich aan flarden. Daar zet de tijd zich boven de
   regel in plaats van ernaast. */
@media (max-width: 559.98px) {
  .dienst-logboek__regel { grid-template-columns: 1fr; gap: 0.3rem; }
}
.dienst-logboek__tijd { color: var(--kleur-accent); }
.dienst-logboek__wat { line-height: 1.55; text-wrap: pretty; }
.dienst-logboek__slot {
  max-width: 44ch;
  margin: clamp(1.75rem, 4vw, 2.5rem) 0 0;
  font-family: var(--font-serif);
  font-size: clamp(1.2rem, 2.4vw, 1.6rem);
  line-height: 1.25;
}

.dienst-lijst {
  max-width: 52rem;
  margin: clamp(2rem, 5vw, 3rem) 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 1.5rem;
}
.dienst-lijst li { display: grid; gap: 0.35rem; }
.dienst-lijst strong { font-size: 1.05rem; }
.dienst-lijst span { max-width: 58ch; opacity: 0.85; line-height: 1.55; text-wrap: pretty; }

.dienst-claim {
  max-width: 30ch;
  margin: clamp(2.5rem, 6vw, 3.5rem) 0 0;
  font-family: var(--font-serif);
  font-size: clamp(1.6rem, 3.6vw, 2.6rem);
  line-height: 1.12;
  text-wrap: balance;
}

.dienst-cta { margin: clamp(2rem, 5vw, 3rem) 0 0; }
.dienst-cta__knop {
  display: inline-block;
  padding: 0.9rem 1.6rem;
  border: 1px solid currentColor;
  color: inherit;
  text-decoration: none;
  transition: background-color var(--duur-kort) ease, color var(--duur-kort) ease;
}
.dienst-cta__knop:hover,
.dienst-cta__knop:focus-visible { background: var(--kleur-inkt); color: var(--kleur-papier); }
.sectie--donker .dienst-cta__knop:hover,
.sectie--donker .dienst-cta__knop:focus-visible { background: var(--kleur-papier); color: var(--kleur-inkt); }

/* FAQ met <details>: werkt zonder JavaScript en is toetsenbord-toegankelijk uit zichzelf —
   past bij een site die ook zonder JS leesbaar moet blijven. */
.dienst-faq { max-width: 52rem; margin-top: clamp(1.5rem, 4vw, 2.25rem); }
.dienst-faq__item { border-top: 1px solid rgba(13, 13, 11, 0.14); }
.dienst-faq__item:last-child { border-bottom: 1px solid rgba(13, 13, 11, 0.14); }
.dienst-faq__item summary {
  padding: 1.1rem 2rem 1.1rem 0;
  font-weight: 700;
  cursor: pointer;
  position: relative;
  list-style: none;
}
.dienst-faq__item summary::-webkit-details-marker { display: none; }
.dienst-faq__item summary::after {
  content: '+';
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--font-mono);
  color: var(--kleur-accent-tekst);
}
.dienst-faq__item[open] summary::after { content: '–'; }
.dienst-faq__item p { max-width: 62ch; margin: 0 0 1.25rem; line-height: 1.6; text-wrap: pretty; }

.dienst-terug { margin-top: clamp(2.5rem, 6vw, 3.5rem); }
.dienst-terug a { color: inherit; }

@media (prefers-reduced-motion: reduce) {
  .dienst-cta__knop { transition: none; }
}

/* Doorverwijzing vanaf het dienstenblok op de homepagina naar de bijbehorende dienstenpagina
   (ronde 7). Gouden onderstreping in plaats van een knop: het blok is al een kaart, een knop
   erin zou een tweede handeling suggereren naast de mail-CTA in de footer. */
.service-block__meer { margin-top: 1rem; }
.service-block__meer a {
  color: var(--kleur-accent-tekst);
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-bottom: 1px;
}
.service-block__meer a::after { content: ' →'; }

/* ---- Ronde 7b: de drie momenten die je ziet gebeuren ---- */

/* 1. Voorbeeldsom die optelt. De totaalregel krijgt een gouden gloed zodra hij compleet is,
   zodat het oog eindigt bij het getal waar de hele pagina om draait. */
.dienst-som__regel dd { transition: color var(--duur-kort) ease; }
.dienst-som__regel--totaal dd { font-size: 1.1em; }

/* 2. Logboekvenster. Bewust géén nagebouwde terminal met venstertjes: het is een strook met
   een kop-balk, zoals de weekrapporten die Lars daadwerkelijk verstuurt. De regels schuiven
   binnen zodra ze in beeld komen; zonder JS staat .is-zichtbaar er niet en zijn ze gewoon
   zichtbaar (zie de :not-regel hieronder) — de tekst mag nooit van JavaScript afhangen. */
.dienst-logboek__venster {
  max-width: 52rem;
  margin: clamp(2rem, 5vw, 3rem) 0 0;
  border: 1px solid rgba(244, 241, 232, 0.18);
}
.dienst-logboek__balk {
  display: block;
  margin: 0;
  padding: 0.7rem clamp(1rem, 3vw, 1.5rem);
  border-bottom: 1px solid rgba(244, 241, 232, 0.18);
  color: var(--kleur-accent);
  opacity: 0.85;
}
.dienst-logboek { margin: 0; padding: 0 clamp(1rem, 3vw, 1.5rem); list-style: none; }
.dienst-logboek__regel:first-child { border-top: none; }
.dienst-logboek__regel:last-child { border-bottom: none; }

/* De klasse wordt door dienst.js gezet. Alleen wanneer JS daadwerkelijk draait (html.js-actief)
   beginnen de regels onzichtbaar — anders zou een bezoeker zonder JavaScript een leeg venster
   zien, en dat is precies het soort stille storing dat de eindreview eerder ving. */
.js-actief .dienst-logboek__regel {
  opacity: 0;
  transform: translateY(0.6rem);
  transition: opacity 0.5s ease, transform 0.5s var(--easing);
}
.js-actief .dienst-logboek__regel.is-zichtbaar { opacity: 1; transform: none; }
/* Cursor op de laatst ingevulde regel: het logboek schrijft nog. */
.js-actief .dienst-logboek__regel.is-zichtbaar:last-child .dienst-logboek__wat::after {
  content: '';
  display: inline-block;
  width: 0.5em;
  height: 1em;
  margin-left: 0.35em;
  vertical-align: -0.15em;
  background: var(--kleur-accent);
  animation: dienst-cursor 1.1s steps(1) infinite;
}
@keyframes dienst-cursor { 0%, 55% { opacity: 1; } 56%, 100% { opacity: 0; } }

/* 3. Samensmelting: vier pakketten worden één server. Op breed scherm links de vier bronnen,
   rechts het doel, met de gouden circuitlijnen ertussen; op smal scherm vervalt de tekening
   en staat het onder elkaar met een pijl (schuine lijnen werken daar niet). */
.smelt {
  position: relative;
  max-width: 52rem;
  margin: clamp(2.5rem, 6vw, 4rem) 0;
  padding: 0;
}
.smelt__draden { display: none; }
.smelt__bronnen { display: grid; gap: 0.75rem; }
.smelt__bron,
.smelt__doel {
  border: 1px solid var(--kleur-inkt-vervaagd);
  border-radius: 0.35rem;
  padding: 0.85rem 1.1rem;
}
.sectie--donker .smelt__bron,
.sectie--donker .smelt__doel { border-color: rgba(244, 241, 232, 0.28); }
.smelt__doel {
  display: grid;
  gap: 0.25rem;
  border-color: var(--kleur-accent-tekst);
  border-width: 2px;
}
.smelt__doel-naam { font-weight: 700; font-size: 1.1rem; }
.smelt__doel-bij { color: var(--kleur-accent-tekst); }
.smelt__pijl {
  display: block;
  margin: 0.9rem 0;
  text-align: center;
  color: var(--kleur-accent-tekst);
  font-size: 1.2rem;
}
.smelt__voet { display: block; margin-top: 1.25rem; opacity: 0.7; }

@media (min-width: 860px) {
  .smelt { display: grid; grid-template-columns: 1fr 1fr; column-gap: clamp(6rem, 14vw, 12rem); align-items: center; }
  .smelt__draden {
    display: block;
    position: absolute;
    inset: 0 0 2.5rem;
    width: 100%;
    height: calc(100% - 2.5rem);
    pointer-events: none;
  }
  .smelt__lijn {
    stroke: var(--kleur-accent-tekst);
    stroke-width: 1.5;
    vector-effect: non-scaling-stroke;
    opacity: 0.55;
  }
  .sectie--donker .smelt__lijn { stroke: var(--kleur-accent); }
  /* Zodra de lijnen getekend zijn licht het doel op — het moment waarop vier één wordt. */
  .smelt.is-klaar .smelt__doel { box-shadow: 0 0 0 1px var(--kleur-accent-tekst), 0 0 2rem rgba(184, 145, 43, 0.22); }
  .smelt__pijl { display: none; }
  .smelt__bronnen { grid-column: 1; }
  .smelt__doel { grid-column: 2; justify-self: start; min-width: 15rem; }
  .smelt__voet { grid-column: 1 / -1; }
}

@media (prefers-reduced-motion: reduce) {
  .js-actief .dienst-logboek__regel { opacity: 1; transform: none; transition: none; }
  .js-actief .dienst-logboek__regel.is-zichtbaar:last-child .dienst-logboek__wat::after { animation: none; }
}

/* Waaier-variant van het samensmelt-diagram: één ding links dat uitwaaiert naar vier rechts
   (de telefonistpagina). Alleen de kolomvolgorde en de lijnen verschillen — de rest van de
   component blijft gelijk, zodat beide diagrammen herkenbaar familie zijn. */
@media (min-width: 860px) {
  .smelt--waaier .smelt__doel { grid-column: 1; justify-self: stretch; }
  .smelt--waaier .smelt__bronnen { grid-column: 2; }
  .smelt--waaier.is-klaar .smelt__bron { border-color: var(--kleur-accent-tekst); }
  .sectie--donker .smelt--waaier.is-klaar .smelt__bron { border-color: var(--kleur-accent); }
}

/* Tijdlijn — voor diensten waarbij het MOMENT de boodschap is (opvolging, dagindeling).
   Op breed scherm een horizontaal spoor met gouden knopen, op smal scherm een verticale
   lijst; de lijn zelf is een pseudo-element zodat er geen extra DOM voor nodig is. */
.tijdlijn { max-width: 52rem; margin: clamp(2.5rem, 6vw, 4rem) 0; }
.tijdlijn__spoor { position: relative; margin: 0; padding: 0; list-style: none; display: grid; gap: 1.75rem; }
.tijdlijn__punt { position: relative; padding-left: 2rem; display: grid; gap: 0.3rem; }
.tijdlijn__punt::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.45em;
  width: 0.7rem;
  height: 0.7rem;
  border-radius: 50%;
  background: var(--kleur-accent-tekst);
}
.sectie--donker .tijdlijn__punt::before { background: var(--kleur-accent); }
.tijdlijn__punt:not(:last-child)::after {
  content: '';
  position: absolute;
  left: 0.3rem;
  top: 1.35em;
  bottom: -1.75rem;
  width: 1px;
  background: currentColor;
  opacity: 0.3;
}
.tijdlijn__wanneer { color: var(--kleur-accent-tekst); }
.sectie--donker .tijdlijn__wanneer { color: var(--kleur-accent); }
.tijdlijn__wat { max-width: 52ch; line-height: 1.55; text-wrap: pretty; }
.tijdlijn__voet { display: block; margin-top: 1.5rem; opacity: 0.7; }

@media (min-width: 860px) {
  .tijdlijn__spoor { grid-template-columns: repeat(4, 1fr); gap: 0 1.5rem; }
  .tijdlijn__punt { padding: 1.75rem 0 0; }
  .tijdlijn__punt::before { top: 0; }
  .tijdlijn__punt:not(:last-child)::after {
    left: 0.7rem;
    top: 0.35rem;
    bottom: auto;
    right: -1.5rem;
    width: auto;
    height: 1px;
  }
  .tijdlijn__wat { max-width: none; }
}

/* ---- Uitklapmenu in de navigatie (ronde 7) ----
   Zes dienstenpagina's onder één item. De knop verschijnt alleen als JavaScript draait
   (.js-actief): zonder JS zou een uitklapknop die niets doet erger zijn dan geen knop, en de
   link ernaast brengt de bezoeker dan gewoon naar de dienstensectie. */
.nav__item--sub { position: relative; display: inline-flex; align-items: center; gap: 0.3rem; }
.nav__sub-knop {
  display: none;
  padding: 0 0.15rem;
  font-family: var(--font-mono);
  font-size: 0.7em;
  line-height: 1;
  color: inherit;
  background: none;
  border: 0;
  cursor: pointer;
  transition: transform var(--duur-kort) var(--easing), color var(--duur-kort) ease;
}
.js-actief .nav__sub-knop { display: inline-block; }
.nav__sub-knop:hover, .nav__sub-knop:focus-visible { color: var(--kleur-accent); }
.nav__item--sub.is-open .nav__sub-knop { transform: rotate(180deg); }

.nav__sub {
  position: absolute;
  top: calc(100% + 0.75rem);
  left: -0.75rem;
  z-index: 20;
  min-width: 15rem;
  margin: 0;
  padding: 0.5rem 0;
  list-style: none;
  background: var(--kleur-inkt);
  border: 1px solid rgba(244, 241, 232, 0.18);
  /* Dicht: onzichtbaar én onbereikbaar voor toetsenbord en screenreader. Alleen opacity zou
     een onzichtbaar menu laten meedoen in de tabvolgorde — een klassieke val. */
  opacity: 0;
  visibility: hidden;
  transform: translateY(-0.4rem);
  transition: opacity var(--duur-kort) ease, transform var(--duur-kort) var(--easing), visibility var(--duur-kort);
}
.nav__item--sub.is-open .nav__sub { opacity: 1; visibility: visible; transform: none; }
.nav__sub li { display: block; }
.nav__sub a {
  display: block;
  padding: 0.55rem 1.1rem;
  color: var(--kleur-papier);
  text-decoration: none;
  text-transform: none;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.nav__sub a::after { content: none; } /* geen onderstreep-animatie van .nav__links a */
.nav__sub a:hover, .nav__sub a:focus-visible { background: rgba(184, 145, 43, 0.16); color: var(--kleur-accent); }

/* Op smalle schermen wordt de balk al een wrappende rij; een zwevend menu zou daar half buiten
   beeld vallen. Daar klapt het gewoon in de stroom open, over de volle breedte. */
@media (max-width: 699.98px) {
  .nav__item--sub { position: static; }
  .nav__sub {
    position: absolute;
    left: clamp(1rem, 4vw, 2.5rem);
    right: clamp(1rem, 4vw, 2.5rem);
    min-width: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .nav__sub, .nav__sub-knop { transition: none; }
}

/* Kopje binnen het uitklapmenu, om diensten en software van elkaar te scheiden zodra er
   meer dan tien items onder staan. Geen link, dus aria-hidden en niet focusbaar. */
.nav__sub-kop {
  padding: 0.9rem 1.1rem 0.35rem;
  color: var(--kleur-accent);
  opacity: 0.75;
  border-top: 1px solid rgba(244, 241, 232, 0.14);
  margin-top: 0.4rem;
}
