/* ==========================================================================
   LabelLogisch — publieke website V2, visueel prototype
   ==========================================================================

   Mobile-first: iedere @media-regel is in beginsel een *uitbreiding* naar boven.
   Dat is niet alleen netjes, het is de enige manier waarop de 390px-controle uit
   de opdracht betrouwbaar blijft terwijl er desktopvarianten bijkomen.

   Er staan inmiddels twee `max-width`-queries in dit bestand — `479px` en
   `639px` — en die zijn een bewuste uitzondering: ze zetten iets *uit* op een
   smal scherm dat op een breed scherm de standaard is. Andersom formuleren zou
   betekenen dat de regel op mobiel al geldt en op desktop teruggedraaid wordt,
   en dan bepaalt de desktopregel wat mobiel doet. Dit stond hier als "geen
   enkele max-width-query"; dat klopte tot 12B.9 en daarna niet meer.

   Breekpunten, en waarom precies deze:
     640px  — de eerste kolomsplitsing; twee kaarten passen naast elkaar
     900px  — tablet staand: navigatie past uitgeschreven, hero wordt tweekolommig
     1120px — desktop: drie- en vierkolomsroosters, bredere marges

   Kleur. Groen is de merkkleur én de actiekleur: primaire knoppen, actieve
   navigatie, links, geselecteerde keuzes, voortgang, succes, prijs en focus.
   Er is bewust geen tweede accentkleur meer. Tot deze ronde was warm geel de
   primaire actiekleur — de gele knop, de gele focusring, de gele voortgangsbalk
   — en dat gaf de site een tweede merkkleur die LabelLogisch 1.0 niet heeft.
   Geel is teruggebracht tot wat het hoort te zijn: een waarschuwing.

   De waarden staan hier niet meer. Ze komen uit `css/ll-brand.css`, dat de
   admin óók laadt; dit blok bindt de merkkleuren alleen aan de namen die deze
   stylesheet al gebruikte. Wie een kleur wil wijzigen, doet dat daar.

   Contrast. Elke tekst-op-vlakcombinatie hieronder haalt minstens 4,5:1; de
   berekening staat in `ll-brand.css`.
   -------------------------------------------------------------------------- */

/* -------------------------------------------------------------- 1. tokens */

:root {
  /* Inkt — de neutralen van V1 (gray-900/700/500), gedeeld met de admin. */
  --ink:        var(--ll-ink);
  --ink-2:      var(--ll-ink-2);
  --ink-3:      var(--ll-muted);
  --ink-on-dark:var(--ll-on-dark);

  /* Groen — de merkschaal. `--green-700` is #15803d, het groen dat V1 op 77
     plekken voert; `--green-800` is #166534, de canonieke merkkleur uit de
     favicon en de `theme-color`. */
  --green-900:  var(--ll-green-950);
  --green-800:  var(--ll-green-800);
  --green-700:  var(--ll-green-700);
  --green-600:  var(--ll-green-600);
  /* 500 en 400 zijn de twee blaadjesgroenen van V1 (#22c55e en #4ade80). Ze
     ontbraken hier, en `var(--green-500)` zonder waarde is geen kleur maar een
     ongeldige regel: `color` viel dan terug op de geërfde inkt, en de blaadjes
     dwarrelden grijs door een groene band. Ze staan alleen voor decoratie op een
     lichte ondergrond; voor tekst is geen van beide licht genoeg. */
  --green-500:  var(--ll-green-500);
  --green-400:  var(--ll-green-400);
  --green-300:  var(--ll-green-300);
  --green-200:  var(--ll-green-200);
  --green-100:  var(--ll-green-100);
  --green-50:   var(--ll-green-50);

  /* Amber — uitsluitend waarschuwing. Er is geen `--amber` (het gevulde vlak)
     meer: dat was de primaire knop, en een waarschuwing is nooit een primaire
     actie. Wat overblijft is een tekstkleur, een rand en een zacht vlak. */
  --amber-700:  var(--ll-warning);
  --amber-200:  var(--ll-warning-line);
  --amber-50:   var(--ll-warning-soft);

  /* Vlakken */
  --paper:      var(--ll-surface);
  --sand:       var(--ll-page);
  --sand-2:     #f1f3f2;
  --line:       var(--ll-border);
  --line-2:     var(--ll-border-strong);

  /* Signalen */
  --danger:     var(--ll-danger);
  --danger-bg:  var(--ll-danger-soft);
  --ok:         var(--ll-success);
  --ok-bg:      var(--ll-success-soft);

  /* Maatvoering */
  /* 1240px, de maat van de ontwerprichting. Hij raakt alleen de blokken die de
     volle `.wrap` gebruiken — de kop, de voet, het kruimelpad en de tweedeling
     van de homepage. De inhoudspagina's staan binnenin op `.wrap-narrow` (760px)
     en worden hier dus niet breder van; hun leesmaat is een letteraantal en geen
     percentage van het scherm. */
  --container:  1240px;
  --radius-sm:  8px;
  --radius:     14px;
  --radius-lg:  22px;
  --tap:        44px;          /* minimale aanraakmaat, opdrachtvereiste */

  /* Schaduw — laag en warm, geen zwarte SaaS-slagschaduw */
  --shadow-sm:  0 1px 2px rgba(17, 33, 26, .06), 0 2px 6px rgba(17, 33, 26, .04);
  --shadow:     0 2px 4px rgba(17, 33, 26, .05), 0 10px 24px rgba(17, 33, 26, .07);
  --shadow-lg:  0 4px 8px rgba(17, 33, 26, .06), 0 20px 44px rgba(17, 33, 26, .10);

  /* De hoogte van de vaste header; alles wat eronder plakt, rekent hiermee */
  --header-h:   64px;

  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto,
          "Helvetica Neue", Arial, sans-serif;

  /* ── Ochtendlicht: de redactionele laag ─────────────────────────────────

     De ontwerprichting vraagt om een "krachtige redactionele compositie" en om
     een "premium maar persoonlijke" uitstraling. Dat verschil zit vrijwel
     helemaal in de koppen: dezelfde tekst in een schreefloze grotesk leest als
     een SaaS-productpagina, en in een brede schreefletter als een artikel dat
     iemand geschreven heeft.

     Georgia en geen webfont. De Content-Security-Policy laat geen externe bron
     toe ({@see PublicSecurityPolicy}) en er staan geen fontbestanden in
     `public/assets/`; een `@import` naar Google Fonts zou hier dus niet alleen
     ongewenst zijn maar ook simpelweg geblokkeerd worden. Georgia staat op
     macOS, Windows, iOS en Android, is ontworpen voor schermgebruik en heeft de
     brede letterbak die deze richting nodig heeft. De stack valt daarna terug
     op Iowan (iOS) en op de generieke `serif`.

     De body blijft schreefloos. Twee schreefletters over elkaar heen maakt een
     pagina niet redactioneler, alleen drukker.

     Kleur verandert hier níét mee: de bruine noteninkt en het zachte
     rood-oranje van de ontwerprichting blijven eruit. Wat overblijft is de
     compositie, en die draagt LabelLogisch-groen. */
  --display: Georgia, "Iowan Old Style", "Times New Roman", serif;

  /* Bedragen en postcodes in een tabellarische mono: een staffeltabel waarin de
     cijfers niet onder elkaar staan, leest als een prijslijst die niet klopt. */
  --data: ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* De typografische ladder. Eén vloeiende schaal voor de hele site, zodat een
     kop op de tarievenpagina dezelfde sprong maakt als op de homepage — dat is
     de "consistente ritmiek over alle pagina's" uit de opdracht. */
  --g-0: clamp(1.0625rem, 1.03rem + .16vw, 1.125rem);   /* lopende tekst      */
  --g-1: clamp(1.1875rem, 1.11rem + .34vw, 1.375rem);   /* lead, h3           */
  --g-2: clamp(1.4rem,  1.24rem + .68vw, 1.85rem);      /* h2 klein           */
  --g-3: clamp(1.65rem, 1.38rem + 1.15vw, 2.3rem);      /* h2                 */
  /* De bovengrens is opgemeten en niet gekozen. Op 1440px is de kopkolom van de
     hero ongeveer 566px breed; bij 3,35rem paste de kop van de homepage daar in
     vier regels, waarvan de laatste één woord. Bij 2,9rem zijn het er drie, met
     een volle slotregel.
     De ondergrens is op 390px gemeten, waar hij de adrescheck binnen het eerste
     scherm moet houden. */
  --g-4: clamp(1.95rem, 1.55rem + 2.0vw, 2.9rem);       /* h1                 */

  /* Sectieritme. Twee maten in plaats van de losse `padding-block` per sectie:
     `--ruimte` is de gewone sprong tussen twee secties, `--ruimte-klein` die
     tussen twee blokken die inhoudelijk bij elkaar horen. */
  --ruimte:       clamp(32px, 2.2rem + 1.3vw, 56px);
  --ruimte-klein: clamp(22px, 1.5rem + .8vw, 36px);

  /* De leesmaten van de redactionele kolom. In `ch` en niet in pixels: een
     regellengte is een letteraantal, en dat is wat leesbaarheid bepaalt. */
  --maat-lead:  54ch;
  --maat-tekst: 66ch;
}

@media (min-width: 900px) {
  :root { --header-h: 76px; }
}

/* ------------------------------------------------------------ 2. fundament */

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

/* `hidden` is een attribuut met display:none in de UA-stylesheet, en dus verliest
   het van elke klasse die zelf display zet (.field-error, .notice, .mobile-menu).
   Zonder deze regel staat een verborgen foutmelding gewoon in beeld. */
[hidden] { display: none !important; }

html {
  /* De ankernavigatie van de FAQ mag niet onder de vaste header verdwijnen. */
  scroll-padding-top: calc(var(--header-h) + 16px);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--g-0);
  /* 1.7 en niet 1.65: de richting leest zijn lopende tekst ruimer, en dat is op
     een pagina met lange alinea's het verschil tussen "lezen" en "scannen". */
  line-height: 1.7;
  color: var(--ink-2);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  /* Vangnet tegen horizontale paginascroll: geen enkel kind mag het venster
     oprekken. `clip` en niet `hidden`, want `hidden` breekt position:sticky. */
  overflow-x: clip;
}

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

/* De koppen dragen de schreefletter; de rest van de site blijft schreefloos.
   `font-weight: 700` en niet 800: Georgia heeft geen extra-bold en valt daar
   terug op een kunstmatig verdikte letter, die op een grote kop zichtbaar
   uitloopt. 700 is het echte vette snijblad. */
h1, h2, h3, h4 {
  font-family: var(--display);
  color: var(--ink);
  line-height: 1.16;
  letter-spacing: -0.012em;
  margin: 0 0 .5em;
  font-weight: 700;
  text-wrap: balance;
}

/* Bewust géén `max-width` op de `h1`. Een maat in `ch` schaalt mee met de
   lettergrootte, dus 19ch is bij 2,9rem ongeveer 440px — smaller dan de
   leeskolom van 760px waarin de meeste koppen staan, en dat maakt elke
   paginatitel onnodig rafelig. De kolom begrenst de kop; `text-wrap: balance`
   verdeelt de regels. */
h1 { font-size: var(--g-4); }
h2 { font-size: var(--g-3); }
h3 { font-size: var(--g-1); }
h4 { font-size: var(--g-0); }

/* Bewust géén `max-width` op `p` zelf. Een leesmaat op elke alinea raakt ook de
   alinea's die geen lopende tekst zijn — een knoppenrij, een tabelcel, een
   melding, de voet — en die zouden dan allemaal hun eigen uitzondering nodig
   hebben. De leesmaat hangt daarom aan de *kolom* (`.wrap-narrow`, `.lees`) en
   niet aan het element. */
p { margin: 0 0 1em; text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

a { color: var(--green-700); text-underline-offset: 3px; }
a:hover { color: var(--green-800); }

strong, b { color: var(--ink); font-weight: 700; }

/* Zichtbare focus, overal, ook op donkere vlakken. */
:focus-visible {
  outline: var(--ll-focus-width) solid var(--ll-focus);
  outline-offset: var(--ll-focus-offset);
  border-radius: 4px;
}
.on-dark :focus-visible { outline-color: var(--ll-focus-on-dark); }

.skip {
  position: absolute; left: 8px; top: -100px; z-index: 200;
  background: var(--ink); color: #fff; padding: 12px 18px;
  border-radius: var(--radius-sm); font-weight: 700; text-decoration: none;
}
.skip:focus { top: 8px; color: #fff; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

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

/* ---------------------------------------------------------- 3. hulpklassen */

.wrap {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: 20px;
}
@media (min-width: 900px) { .wrap { padding-inline: 32px; } }

.wrap-narrow { max-width: 760px; }
.wrap-mid    { max-width: 940px; }

/* Sectieritme uit één token in plaats van twee losse maten met een breekpunt
   ertussen. `--ruimte` schaalt vloeiend van 44px op 390px naar 84px op 1440px,
   dus er is geen sprong meer op 900px waar een sectie ineens 32px groeit.

   De maat is bewust kleiner dan de 56/88px van daarvoor. De opdracht noemt
   "minder ongebruikte witruimte" met zoveel woorden, en op 1024×768 kostte de
   oude maat 176px per sectiegrens — bijna een kwart scherm aan niets. */
section { padding-block: var(--ruimte); }

.bg-sand  { background: var(--sand); }
.bg-green { background: var(--green-50); }
.bg-ink   { background: var(--green-900); color: var(--ink-on-dark); }
.bg-ink h1, .bg-ink h2, .bg-ink h3 { color: #fff; }

.lead { font-size: var(--g-1); color: var(--ink-2); max-width: var(--maat-lead); }

.muted { color: var(--ink-3); font-size: .9375rem; }

/* De bovenregel boven een kop. Uit de ontwerprichting: kort, in kapitalen, met
   een ruime letterafstand, in de merkkleur — en zónder het streepje dat er
   eerder voor stond. Dat streepje maakte er een badge van, en een badge vraagt
   meer aandacht dan de kop eronder.

   De homepage voert hem sinds deze ronde niet meer: daar herhaalde de bovenregel
   grotendeels de kop eronder. Wat overblijft zijn de inhoudspagina's, waar
   `paginakop.php` er het onderwerp of de plaats in zet. */
.eyebrow {
  display: block;
  font-size: .8125rem; font-weight: 700; letter-spacing: .11em;
  text-transform: uppercase; color: var(--green-700);
  margin: 0 0 12px;
}
.on-dark .eyebrow { color: var(--green-300); }

/* Eén woord in de kop in de merkkleur. Op de homepage is dat "logisch": daar is
   het tegelijk het woord uit de belofte en de tweede helft van de merknaam, en
   de kleur maakt dat verband zichtbaar zonder er een tweede logo van te maken.

   `--green-700` (#15803d) en niet het lichtere merkgroen: op de zandkleurige
   ochtendband haalt deze tint 5,0:1 en blijft de kop dus leesbaar. Verder
   verandert er niets: geen ander lettertype, geen ander gewicht, geen
   onderstreping. Een gekleurd woord binnen een kop mag geen tweede kop worden.

   Geen `<b>` of `<em>` in de markup maar een `<span>`: het woord is niet
   belangrijker dan de rest van de zin, het ziet er alleen anders uit. */
.kop-accent { color: var(--green-700); }
.on-dark .kop-accent { color: var(--green-300); }

/* ── De redactionele kolom ───────────────────────────────────────────────

   `.lees` is de leeskolom van de ontwerprichting: alles erin staat op één
   verticaal ritme, en de leesmaten hangen aan de kolom in plaats van aan elk
   element. Hij vervangt de losse marges die de inhoudspagina's per blok
   meebrachten. */
/* Een `<section>` in de leeskolom draagt géén eigen `padding-block`.
   Zonder deze regel telt de ruimte tussen twee secties drie keer: de onderpadding
   van de eerste, de bovenpadding van de tweede én de marge hieronder. Op 1440px
   was dat 83 + 83 + 49 = 215px tussen "Wat een energielabel kost" en "Hoe het
   gaat" — een gat waar je doorheen valt. De leeskolom bepaalt het ritme, en dat
   doet hij op één plek. */
.lees > section { padding-block: 0; }
.lees > * + * { margin-top: var(--ruimte-klein); }
.lees p, .lees ul, .lees ol { max-width: var(--maat-tekst); }
.lees h2 { margin-bottom: .45em; }
.lees h3 { margin-bottom: .25em; }

/* ── De bewijs- of cijferbalk ────────────────────────────────────────────

   Drie feiten naast elkaar, gescheiden door haarlijnen in plaats van door drie
   losse kaarten met elk een eigen rand en schaduw. Dat is letterlijk de
   "minder losse kaarten" en de "compacte cijfer-/bewijsbalk" uit de opdracht:
   één rand om het geheel, 1px raster ertussen.

   Het getal draagt de schreefletter, het onderschrift de schreefloze. Zo leest
   de balk als een tabel met drie cijfers en niet als drie zinnetjes.

   Elk feit hier komt uit een echte bron: het bedrag uit de actieve prijslijst
   in de database, de opnameduur en de levertermijn uit `SiteContent`. Er staat
   met opzet geen vierde vak met een aantal, een score of een beschikbaarheid —
   daar is geen databron voor. */
.feitenbalk {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1px;
  margin: 0;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
@media (min-width: 620px) { .feitenbalk { grid-template-columns: repeat(3, 1fr); } }

/* `order` draait de leesvolgorde om: in de HTML staat de term (`<dt>`) vóór de
   waarde (`<dd>`), zoals een `<dl>` vereist; in beeld staat het getal boven het
   onderschrift. Zie de toelichting in de partial. */
.feit { background: var(--paper); padding: 14px 16px; display: flex; flex-direction: column; }
/* 1,15rem en niet 1,3rem: "vijf werkdagen" is het langste getal in de balk en
   viel bij 1,3rem in een vak van ~180px over twee regels, terwijl de twee
   buurvakken er één gebruikten. Een cijferbalk waarvan één vak hoger is dan de
   rest leest als een fout. */
.feit dd {
  order: 1; margin: 0;
  font-family: var(--display); font-weight: 700;
  font-size: 1.15rem; line-height: 1.25; color: var(--ink);
  letter-spacing: -.01em;
}
.feit dt { order: 2; font-size: .875rem; color: var(--ink-3); margin-top: 2px; }

/* Staat de balk midden in een blok — op `/energielabel-aanvragen/` boven de
   staffeltabel — dan hoort er ruimte onder. In de hero regelt het rooster dat. */
.feitenbalk + * { margin-top: 20px; }

/* ── Dezelfde drie feiten als chips ──────────────────────────────────────

   De chipvorm van de homepage-hero. Zelfde `<dl>`, zelfde drie bronnen, andere
   opmaak — de partial schakelt hem aan met `compact`.

   **Waarom hij er is.** Op 390px waren de drie vakken samen 234px hoog en
   stonden ze als drie losse blokken tussen de adrescheck en de tarieven in. Dat
   is precies één blok te veel op het scherm waar de bezoeker beslist. Als chips
   zijn dezelfde drie feiten ongeveer de helft zo hoog, en lezen ze als een
   onderschrift bij de prijskaart in plaats van als een eigen sectie.

   Alleen hier. `/tarieven/`, `/energielabel-aanvragen/`, de plaatspagina's en
   de Ads-pagina's houden de balk met haarlijnen: daar staat hij niet in een
   verloop maar als blok op zichzelf, en daar doet die vorm zijn werk.

   Wit en niet `--green-50`: de chips staan op de ochtendband, die zelf al van
   `--green-100` naar `--green-50` verloopt. Een groene chip op een groen vlak is
   geen chip meer. Wit met een `--green-200`-rand houdt hem los van zijn
   achtergrond, op elke hoogte van het verloop.

   De grid-eigenschappen hierboven blijven staan maar doen niets: `display: flex`
   wint, en `grid-template-columns` heeft op een flexcontainer geen betekenis. */
.feitenbalk-chips {
  display: flex; flex-wrap: wrap; gap: 8px;
  background: none; border: 0; border-radius: 0; overflow: visible;
}
.feitenbalk-chips .feit {
  flex-direction: row; align-items: baseline; gap: 7px;
  background: #fff;
  border: 1px solid var(--green-200);
  border-radius: 999px;
  padding: 7px 15px;
}
/* Het getal blijft de schreefletter en blijft vóór het onderschrift staan
   (`order` op `.feit dd`); alleen de maat zakt naar die van een chip. */
.feitenbalk-chips .feit dd { font-size: .9375rem; }
.feitenbalk-chips .feit dt { margin-top: 0; font-size: .8125rem; }

/* ── Werkgebiedlinks ─────────────────────────────────────────────────────

   Plaatsnamen als rustige chips. Vervangt `.wg-plaatsen` op de plekken waar
   het om navigatie gaat; `.wg-plaatsen` zelf blijft bestaan voor de lijsten
   die géén link zijn (het werkgebied noemt ook plaatsen zonder eigen pagina). */
.plaatsen {
  display: flex; flex-wrap: wrap; gap: 8px;
  list-style: none; padding: 0; margin: 0;
}
.plaatsen a {
  display: inline-flex; align-items: center;
  min-height: var(--tap); padding: 8px 16px;
  border: 1px solid var(--line); border-radius: 999px;
  background: var(--paper); color: var(--ink-2);
  font-size: .9375rem; font-weight: 600; text-decoration: none;
}
.plaatsen a:hover, .plaatsen a:focus-visible {
  border-color: var(--green-600); color: var(--green-800); background: var(--green-50);
}

/* ── Het persoonsblok ────────────────────────────────────────────────────

   Portret naast twee alinea's, op één rand en zonder schaduw. Dit is het
   "premium maar persoonlijk" van de opdracht: één echt gezicht, geen
   teamgalerij en geen keurmerkenrij. */
.persoon {
  display: grid; gap: 20px;
  /* `start` en niet `center`: bij een tekst van twee alinea's zweeft een
     verticaal gecentreerd portret midden in een kolom wit, en dat leest als een
     fout in plaats van als een uitlijning. Boven uitlijnen zet het gezicht naast
     de kop, waar het hoort. */
  align-items: start;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--paper);
  padding: 20px;
}
@media (min-width: 620px) {
  .persoon { grid-template-columns: 176px minmax(0, 1fr); gap: 28px; padding: 24px; }
}
/* 4/5 en niet 1/1: de bron is een staand portret (800×1045). Vierkant snijden
   kost een kwart van de hoogte en zet de kin op de onderrand. */
.persoon-foto {
  width: 100%; max-width: 220px;
  aspect-ratio: 4 / 5; object-fit: cover; object-position: 50% 18%;
  border-radius: var(--radius); background: var(--sand-2);
}
/* De kop in de kaart, ongeacht of hij `h2` of `h3` is — dat hangt af van de
   pagina en niet van hoe groot hij hoort te zijn. Zie de partial. */
.persoon-kop { font-size: var(--g-2); margin-bottom: .35em; }
.persoon p { max-width: var(--maat-tekst); }

/* ── De gedeelde paginakop ───────────────────────────────────────────────

   Drie varianten, één ritme. De kop krijgt zijn eigen bovenruimte en géén
   onderruimte: de sectie eronder brengt zijn `--ruimte` al mee, en twee maten
   op elkaar was precies het gat dat `section.section-head` moest repareren.
   Die reparatie is daarmee overbodig geworden; zie de regel eronder. */
.paginakop { padding-block: var(--ruimte) 0; }
.paginakop .lead { margin-bottom: 0; }
.paginakop-onder { margin-top: 24px; }

/* De kop en de eerste sectie horen bij elkaar en krijgen daarom niet allebei de
   volle sprong: op 1440px stond er anders 84px tussen een introzin en de tabel
   die hem uitlegt. Een sectie met een eigen vlak is de uitzondering — daar
   markeert de kleurwissel de grens, en dan hoort de ruimte er wél bij. */
.paginakop + section:not([class*="bg-"]):not(.cta-band) { padding-top: var(--ruimte-klein); }

/* De redactionele kop is de standaardvariant en heeft daarom de volle leesmaat:
   deze pagina's beginnen met een intro die gelezen moet worden en niet met een
   formulier dat ingevuld moet worden.

   Hij heeft een eigen regel en niet alleen de klasse. Een klassenaam in de HTML
   zonder selector in de stylesheet is precies waar
   {@see \Tests\Http\PublicVisualContractTest} op valt — en terecht: dan is het
   niet te zien of de opmaak ontbreekt of dat de haak overbodig is. */
.paginakop-redactie .lead { max-width: var(--maat-lead); }

/* Een conversiekop staat boven een formulier en houdt het daarom kort: de
   bezoeker is hier om iets in te vullen, niet om te lezen. */
.paginakop-conversie { padding-block: var(--ruimte-klein) 0; }
.paginakop-conversie h1 { font-size: var(--g-3); }

/* Een juridische pagina is een leesdocument. De kop is kleiner dan elders,
   omdat een privacyverklaring geen aandacht hoeft te trekken maar gelezen moet
   kunnen worden. */
.paginakop-juridisch h1 { font-size: var(--g-3); max-width: none; }

/* Hier stond `.section-head`: de kopsectie die vijftien inhoudspagina's als
   `<section class="section-head">` voerden, plus twee reparatieregels
   (`section.section-head`) die de gevolgen daarvan terugdraaiden — een
   `max-width` op de sectie zelf brak namelijk de omhulling erbinnen, waardoor
   elke paginatitel links tegen de vensterrand plakte.

   Alle vijftien gebruiken sinds de Ochtendlicht-ronde `site/partials/paginakop`,
   dat de kop in een `.wrap.wrap-narrow` zet en zijn ruimte in één richting
   opbouwt in plaats van hem eerst te nemen en dan terug te geven. Daarmee
   verdwijnen de component én zijn twee reparaties tegelijk; een reparatie die
   zijn patiënt overleeft, is de volgende verwarring.

   Nagelopen met `grep` op `class="…"` over `templates/`: geen enkele template
   voert de klasse nog. */

.stack > * + * { margin-top: 16px; }
.stack-lg > * + * { margin-top: 28px; }

/* ------------------------------------------------------------- 4. knoppen */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  min-height: var(--tap);
  padding: 12px 22px;
  border: 2px solid transparent;
  border-radius: 999px;
  font: inherit; font-size: 1rem; font-weight: 700;
  text-decoration: none; cursor: pointer; white-space: nowrap;
  transition: background-color .15s, border-color .15s, color .15s, transform .15s;
}
.btn:active { transform: translateY(1px); }

/* 12A.3 — deze regel ontbrak, en dat was zichtbaar op twee manieren tegelijk.
   Zonder eigen maat valt een inline-svg terug op `img, svg { max-width: 100%;
   height: auto }` en neemt hij in een flexcontainer de ruimte die overblijft.
   In de brede knoppen van het mobiele menu werd het telefoonicoon daardoor
   ongeveer twee keer zo hoog als de tekst ernaast; in een smalle knop waarvan
   het label verborgen is, kromp hij tot niets en bleef er een lege ronde vorm
   over. Beide zijn opnames uit deze ronde, niet een vermoeden. */
.btn svg { width: 18px; height: 18px; flex: none; }
.btn-lg svg { width: 20px; height: 20px; }

/* Primair = donkergroen met witte tekst, en een iets lichtere groene hover.
   Tot deze ronde was dit een gele knop met donkere tekst. Dat maakte geel de
   actiekleur van de site terwijl LabelLogisch 1.0 die kleur niet kent, en het
   botste met de eis dat geel alleen nog een waarschuwing mag zijn.

   De hover is lichter en niet donkerder, en de twee tinten zijn zo gekozen dat
   allebei de standen AA halen met witte tekst: `--green-800` (#166534) is 7,1:1
   en `--green-700` (#15803d) is 5,0:1. De voor de hand liggende hover
   `--green-600` (#16a34a) haalt maar 3,3:1 — een knop die tijdens het aanwijzen
   onleesbaar wordt, is geen hover maar een fout. De schaduw blijft laag: een
   knop mag opvallen zonder los te komen van de pagina. */
.btn-primary {
  background: var(--green-800); color: #fff; border-color: var(--green-800);
  box-shadow: var(--shadow-sm);
}
.btn-primary:hover { background: var(--green-700); border-color: var(--green-700); color: #fff; }

/* `.btn-dark` is sinds deze ronde dezelfde knop. Twee verschillende gevulde
   groenen naast elkaar zouden de bezoeker laten raden welke de hoofdactie is;
   de klasse blijft bestaan omdat de bevestigingspagina hem voert. */
.btn-dark { background: var(--green-800); color: #fff; border-color: var(--green-800); }
.btn-dark:hover { background: var(--green-700); border-color: var(--green-700); color: #fff; }

/* Secundair: wit vlak, groene rand, groene tekst. Geen tweede gevulde kleur die
   met de primaire actie concurreert. */
.btn-ghost { background: #fff; color: var(--green-800); border-color: var(--green-200); }
.btn-ghost:hover { border-color: var(--green-700); color: var(--green-900); background: var(--green-50); }

.on-dark .btn-ghost { color: #fff; border-color: rgba(255,255,255,.35); }
.on-dark .btn-ghost:hover { border-color: #fff; background: rgba(255,255,255,.08); color: #fff; }

.btn-light { background: #fff; color: var(--green-800); border-color: #fff; }
.btn-light:hover { background: var(--green-50); color: var(--green-900); border-color: var(--green-50); }

/* Een knop over de volle breedte moet zijn tekst wél mogen afbreken. Met
   `nowrap` duwt "Bekijk prijs en vraag een datum aan" op 390px de hele kolom
   46px breder dan het venster — precies de horizontale paginascroll die de
   opdracht verbiedt. Inline-knoppen houden `nowrap`; die kunnen naast elkaar
   uitwijken, een blokknop niet. */
.btn-block { width: 100%; white-space: normal; text-align: center; }
.btn-lg { padding: 15px 30px; font-size: 1.0625rem; min-height: 52px; }
.btn-sm { padding: 8px 16px; font-size: .9375rem; min-height: 40px; }

.btn[disabled], .btn[aria-disabled="true"] {
  opacity: .5; cursor: not-allowed; pointer-events: none;
}

.btn-row { display: flex; flex-wrap: wrap; gap: 12px; }
.btn-row.center { justify-content: center; }

/* De vervolgstap onder een sectie in de leeskolom: één knop, met de tekstlink
   naar de volledige pagina ernaast.

   Geen tweede `.btn` maar een `.arrow-link`, en dat is de hele afweging: de
   knop is de actie, de link is de uitweiding. Twee gevulde knoppen naast elkaar
   maken van de vervolgstap een keuze, en een keuze kost conversie — dezelfde
   regel die het meelopende paneel op precies één primaire knop houdt.

   `align-items: center` en niet de standaard `stretch`: de link is 20px hoog en
   de knop 48px, en zonder deze regel rekt de link zich uit tot knophoogte en
   staat zijn onderstreping op de verkeerde lijn. Op een smal scherm valt de
   link onder de knop; `row-gap` houdt daar dan 12px tussen. */
.sectie-cta {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 12px 20px;
}
.sectie-cta .arrow-link { margin: 0; }

/* Tekstlink met pijl — voor "lees verder"-verwijzingen */
.arrow-link {
  display: inline-flex; align-items: center; gap: 7px;
  font-weight: 700; text-decoration: none; min-height: var(--tap);
}
.arrow-link::after { content: "→"; transition: transform .15s; }
.arrow-link:hover::after { transform: translateX(3px); }

/* -------------------------------------------------------------- 5. header */

.site-header {
  position: sticky; top: 0; z-index: 60;
  background: rgba(255,255,255,.94);
  backdrop-filter: saturate(1.4) blur(10px);
  border-bottom: 1px solid var(--line);
  transition: box-shadow .2s;
}
.site-header.is-scrolled { box-shadow: var(--shadow-sm); }

.header-inner {
  display: flex; align-items: center; gap: 16px;
  height: var(--header-h);
}

.logo {
  display: inline-flex; align-items: center; gap: 10px;
  text-decoration: none; color: var(--ink); font-weight: 800;
  font-size: 1.0625rem; letter-spacing: -.02em; flex: none;
}
.logo img {
  width: auto;
  height: 50px;
  max-width: 76px;
  object-fit: contain;
}
@media (min-width: 640px) {
  .logo img { height: 60px; max-width: 88px; }
}

/* De navigatie verschijnt vanaf 1100px.
   In 12A.1 stond dit op 1240px, omdat zeven items plus twee icoonknoppen en een
   CTA op 1120px net wél pasten maar zonder ademruimte. Sinds 12A.2 zijn het zes
   items (~140px minder), en past de balk weer ruim vanaf 1100px. Dat scheelt een
   hele breedteklasse waarin de bezoeker anders het compacte menu kreeg terwijl
   er ruimte genoeg was. Gemeten op 1024/1100/1200/1440. */
.nav { display: none; }
@media (min-width: 1100px) {
  .nav { display: flex; align-items: center; gap: 2px; margin-left: 8px; }
  /* De productieheader nest de items in een `<ul>`; het prototype zette de
     links rechtstreeks in `.nav`. Zonder deze regel is `.nav` een flexbox met
     precies één kind — de lijst — en rendert die als een gewone opsomming met
     bolletjes ónder de header. Gevonden met de browsermatrix van 12B.9; op
     1440px was het de opvallendste van de vier. */
  .nav ul {
    display: flex; align-items: center; gap: 2px;
    list-style: none; margin: 0; padding: 0;
  }
  .nav a {
    display: inline-flex; align-items: center; min-height: 40px;
    padding: 0 10px; border-radius: 8px;
    color: var(--ink-2); font-size: .9375rem; font-weight: 600;
    text-decoration: none; white-space: nowrap;
  }
  .nav a:hover { background: var(--green-50); color: var(--ink); }
  .nav a[aria-current="page"] {
    color: var(--green-800); box-shadow: inset 0 -3px 0 var(--green-700);
    border-radius: 8px 8px 0 0;
  }
}

.header-actions { margin-left: auto; display: flex; align-items: center; gap: 8px; }

.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--tap); height: var(--tap);
  border: 1px solid var(--line-2); border-radius: 12px;
  background: #fff; color: var(--ink); text-decoration: none; cursor: pointer;
}
.icon-btn:hover { border-color: var(--ink); color: var(--ink); }
.icon-btn svg { width: 20px; height: 20px; }

/* De CTA is de hoofdactie en mag nooit als eerste sneuvelen. Telefoon en
   WhatsApp blijven bereikbaar: onder 520px verdwijnen ze uit de balk, maar ze
   staan dan als volwaardige knoppen in het uitklapmenu.

   ── Twee CTA's, nooit twee tegelijk ───────────────────────────────────────

   Tot deze ronde stond hier alleen `.header-cta` ("Plan je opname"), zichtbaar
   vanaf 520px. Onder die grens had de kop dus géén actie — op 390px, het scherm
   waar de bezoeker het vaakst op zit, was de header een logo met een menuknop.
   De maatregel van toen klopte (de brede knop past daar echt niet naast het
   logo), maar het antwoord was "dan maar geen knop" in plaats van "dan een
   kortere knop".

   `.header-cta-kort` is die kortere knop: "Bekijk prijs", en hij springt naar
   het adrescheckpaneel op dezelfde pagina in plaats van naar `/boeken/`. Hij
   geldt tot 1000px en niet tot 520px, want 1000px is precies de grens waarboven
   `.paneel` meeloopt (`position: sticky`) en de adrescheck vanzelf in beeld
   blijft. Onder die grens scrollt hij weg en is een knop in de kop de enige
   actie die altijd bereikbaar is.

   Het gevolg voor de tussenmaat 520–999px is bewust: daar stond "Plan je
   opname" en staat nu "Bekijk prijs". Dat is dezelfde afweging als op 390px —
   een sprong naar het formulier dat er al staat is korter dan een paginalading
   naar hetzelfde formulier. Vanaf 1000px verandert er niets. */
.header-cta { display: none; white-space: nowrap; }
@media (min-width: 1000px) { .header-cta { display: inline-flex; } }

.header-cta-kort { white-space: nowrap; }
@media (min-width: 1000px) { .header-cta-kort { display: none; } }

/* Onder 520px is er geen ruimte voor logo + twee icoonknoppen + CTA + menu.
   De icoonknoppen gaan er dan uit, niet de CTA. */
.header-actions .icon-btn:not(.menu-toggle) { display: none; }
@media (min-width: 400px) { .header-actions .icon-btn:not(.menu-toggle) { display: inline-flex; } }

/* Het mobiele menu — een uitklap onder de header, geen overlay die de pagina
   afdekt. De opdracht verbiedt expliciet dat de header inhoud bedekt. */
.menu-toggle { display: inline-flex !important; }
@media (min-width: 1100px) { .menu-toggle { display: none !important; } }

.mobile-menu {
  display: none;
  border-top: 1px solid var(--line);
  background: #fff;
  padding: 12px 0 20px;
}
.mobile-menu.is-open { display: block; }
@media (min-width: 1100px) { .mobile-menu.is-open { display: none; } }

.mobile-menu a.m-link {
  display: flex; align-items: center; min-height: var(--tap);
  padding: 8px 4px; border-bottom: 1px solid var(--line);
  color: var(--ink); font-weight: 600; text-decoration: none;
}
.mobile-menu a.m-link[aria-current="page"] { color: var(--green-700); }
.mobile-menu .m-cta { margin-top: 18px; }
.mobile-menu .m-contact { display: flex; gap: 10px; margin-top: 10px; }
.mobile-menu .m-contact .btn { flex: 1; }

/* De boekingsschil (12A.4): kop en voet zo klein als verantwoord, zonder
   navigatie, zonder menuknop en zonder een tweede "plan een afspraak" terwijl
   je daar middenin zit. */
.site-header.is-flow .menu-toggle { display: none !important; }
.site-header.is-flow .flow-hulp {
  font-size: .875rem; color: var(--ink-3); font-weight: 600;
  margin-right: 4px;
}
/* Onder 640px is er geen ruimte voor het woord én het nummer; het nummer wint. */
.site-header.is-flow .flow-hulp { display: none; }
@media (min-width: 640px) { .site-header.is-flow .flow-hulp { display: inline; } }
/* Onder 420px verdwijnt het uitgeschreven nummer uit de belknop; het icoon en
   de aanraakmaat blijven. */
.site-header.is-flow .flow-bel span { display: none; }
@media (min-width: 420px) { .site-header.is-flow .flow-bel span { display: inline; } }

.site-footer.is-flow { padding-block: 24px; }
.site-footer.is-flow .footer-meta { border-top: 0; margin-top: 0; padding-top: 0; }

/* Hier stond de vaste mobiele actiebalk (`.mobile-bar`) uit het prototype, met
   `body { padding-bottom: 76px }` eronder zodat de balk de laatste regel van de
   footer niet zou afdekken.

   Geen enkele productietemplate rendert die balk nog, en `site.js` maakt hem
   ook niet aan — maar de bodempadding gold onverminderd. Elke pagina onder
   640px droeg daardoor **76px lege ruimte** onder de footer, voor een balk die
   er niet is. Dat is het spiegelbeeld van de fouten van 12B.9: daar bleef de
   opmaak achter bij de markup, hier bleef de opmaak achter bij markup die
   helemaal verdwenen is.

   De component en zijn bodempadding gaan samen weg. Een dode component die
   globale `body`-padding bezit, is precies het soort ding dat je pas terugvindt
   als je hem in de browser opmeet. */

/* --------------------------------------------------------- 6. breadcrumbs */

.crumbs { padding: 14px 0 0; font-size: .875rem; }
.crumbs ol {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  color: var(--ink-3);
}
.crumbs li { display: flex; align-items: center; gap: 6px; }
.crumbs li + li::before { content: "/"; color: var(--line-2); }
.crumbs a { color: var(--ink-3); text-decoration: none; }
.crumbs a:hover { color: var(--green-700); text-decoration: underline; }
.crumbs [aria-current="page"] { color: var(--ink-2); font-weight: 600; }

/* ------------------------------------------------- 7. de hero en de tweedeling */

/* De tweedeling van de homepage — het conversiemechanisme van ontwerprichting F.
 *
 * ## Wat dit anders maakt dan een hero
 *
 * Een hero is een blok bovenaan dat wegscrolt. Hier scrollt de adrescheck
 * **niet** weg: links staat een meelopend paneel met de prijscheck en het
 * telefoonnummer, rechts scrolt alle inhoud die Google moet lezen erlangs. De
 * bezoeker hoeft dus nooit terug omhoog om te boeken, en de tekst hoeft niet
 * ingekort te worden om de conversie te beschermen. Dat is het hele idee van de
 * richting, en het is de reden dat deze pagina geen afwisselende volvlakbanden
 * meer heeft: een band over de volle breedte zou dwars door de tweedeling snijden.
 *
 * ## Waarom `position: sticky` hier werkelijk plakt
 *
 * Sticky faalt stil zodra één voorouder een scrollcontainer is. In dit bestand
 * staat daarom `overflow-x: clip` op `body` en niet `hidden`: `clip` snijdt af
 * zonder een scrollcontainer te maken, `hidden` maakt er wél een en zou het
 * paneel gewoon laten meescrollen alsof er niets stond. Geen enkele voorouder
 * van `.paneel` mag `overflow: hidden`, `auto` of `scroll` krijgen.
 *
 * `top` rekent met `--header-h`, want de kop van de site is zelf ook sticky;
 * zonder die verrekening schuift het paneel eronder.
 *
 * ## De volgorde op mobiel
 *
 * Onder 1000px is er geen tweede kolom en stapelt alles. De ontwerprichting zet
 * zijn paneel daar bovenáán; hier staat de belofte ervóór, omdat de opdracht
 * merk → belofte → korte uitleg → adrescheck voorschrijft. Iemand die op een
 * advertentie klikt, hoort eerst te lezen wáár hij is voordat hij zijn postcode
 * intypt.
 *
 * Dat kan uit één stuk HTML omdat de drie vlakken benoemd zijn (`kop`, `paneel`,
 * `lees`): het rooster hangt ze op desktop anders op dan op mobiel, zonder een
 * blok te verdubbelen. Verdubbelen zou betekenen dat een schermlezer de
 * adrescheck twee keer voorleest.
 */
.split {
  display: grid;
  gap: 24px;
  /* Mobiel: belofte → adrescheck → bewijs → de rest. De bewijsbalk staat ná het
     paneel en niet ervóór, want alles tussen de intro en de adrescheck duwt de
     enige knop die telt uit het eerste scherm. Op desktop staat hij wél direct
     onder de intro, want daar staat het paneel ernaast en kost het niets. */
  grid-template-areas: "kop" "paneel" "bewijs" "lees";
  padding-block: 8px var(--ruimte);
}
@media (min-width: 1000px) {
  .split {
    grid-template-columns: 360px minmax(0, 1fr);
    grid-template-areas:
      "paneel kop"
      "paneel bewijs"
      "paneel lees";
    /* De ruimere tussenmaat van de ontwerprichting. De twee kolommen doen iets
       heel anders — links beslissen, rechts lezen — en die scheiding mag je
       zien. */
    column-gap: clamp(32px, 4.5vw, 68px);
    row-gap: 28px;
    /* `start` en niet de standaard `stretch`: een uitgerekt rasteritem is even
       hoog als zijn rij, en dan heeft `position: sticky` binnen dat item geen
       ruimte om in te bewegen. Dit is de tweede manier waarop sticky stil faalt. */
    align-items: start;
    padding-block: 28px var(--ruimte);
  }
}
@media (min-width: 1200px) { .split { grid-template-columns: 380px minmax(0, 1fr); } }

.split-kop { grid-area: kop; }
.split-bewijs { grid-area: bewijs; }
.split-lees { grid-area: lees; }

/* De sectiekoppen van de homepage staan in de merkkleur.

   Alleen hier, en niet op de hele site: de leeskolom van de homepage is één
   doorlopende reeks van zes secties zonder achtergrondbanden ertussen, en de
   kleur is wat de bezoeker bij het scrollen laat zien dat er een nieuw
   hoofdstuk begint. Op de inhoudspagina's doet de paginakop dat werk al.

   `--green-800` (#166534) en niet het lichtere merkgroen: 7,1:1 op wit, dus ook
   op een grote schreefletter ruim binnen AA. De `h3`'s eronder — de stappen, de
   FAQ-vragen, de kop in het persoonsblok — blijven inktkleur. Zou alles groen
   worden, dan onderscheidt niets zich meer. */
.split-lees h2 { color: var(--green-800); }

/* ── De ochtendband: lichtgroene tint met dwarrelende blaadjes ───────────

   Overgenomen uit LabelLogisch 1.0, waar `.hero-bg` hetzelfde verloop voert
   (`#f0fdf4 → #dcfce7 → #bbf7d0`, en dat zijn precies `--green-50`, `--green-100`
   en `--green-200` uit de merkschaal). Hij dekt alleen de bovenkant van de
   pagina en vervaagt naar wit, zodat de leeskolom eronder gewoon op papier staat.

   `isolation: isolate` maakt een eigen stapelcontext, zodat `z-index: -1`
   hieronder de band achter de inhoud zet zonder onder de paginaachtergrond te
   verdwijnen.

   Let op: hier staat bewust géén `overflow` op `.ochtend` zelf. Het meelopende
   paneel staat erbinnen, en één `overflow: hidden` op een voorouder zet
   `position: sticky` stil uit. Het afsnijden gebeurt op `.blaadjes`, dat geen
   voorouder van het paneel is. */
.ochtend { position: relative; isolation: isolate; }
.ochtend::before {
  content: "";
  /* 1100px en niet de 640px van de eerste ronde. Op 1280px eindigde de band toen
     halverwege de bewijsbalk, dus precies waar de pagina begint te lezen, en dat
     las als een afgekapte kop in plaats van als ochtendlicht. Nu loopt hij door
     tot in de tarieventabel en is hij daar al aan het vervagen. Verder omlaag
     hoort hij niet te komen: de leeskolom leest het prettigst op papier. */
  position: absolute; inset: 0 0 auto; height: 1100px; z-index: -1;
  background: linear-gradient(160deg, var(--green-100) 0%, var(--green-50) 65%, var(--green-50) 100%);
  /* De vervaging is een verticaal masker en geen kleurstop in het verloop zelf.
     Bij een diagonaal verloop van 160deg ligt het eindpunt in een hoek, dus een
     transparante laatste stop geeft een schuine grens die aan de linkerkant als
     een harde streep onder het paneel uitkomt. Gemeten op 1440px. Het masker
     staat los van de richting van de kleur en vervaagt overal even ver. */
  -webkit-mask-image: linear-gradient(180deg, #000 55%, transparent 100%);
          mask-image: linear-gradient(180deg, #000 55%, transparent 100%);
}

/* De blaadjes vallen verder dan de band. Dat is opzet: op de huidige site vallen
   ze over 110vh en houden ze niet op waar de kleur ophoudt. Het valveld is
   1800px hoog, dus ze dwarrelen nog een sectie of twee door over wit papier, en
   het masker haalt ze in de onderste 25% weg in plaats van ze af te knippen.

   De hoogte staat in `--valveld` en op twee plekken gebruikt: de hoogte van het
   vlak en het eindpunt van de val. Anders zakt een blaadje uit beeld voordat de
   animatie klaar is, of het blijft de laatste seconden onzichtbaar hangen. */
.blaadjes {
  --valveld: 1800px;
  position: absolute; inset: 0 0 auto; height: var(--valveld); z-index: -1;
  overflow: clip; pointer-events: none;
  -webkit-mask-image: linear-gradient(180deg, #000 75%, transparent 100%);
          mask-image: linear-gradient(180deg, #000 75%, transparent 100%);
}

/* Val en zwaai, letterlijk de twee animaties van de huidige site. */
@keyframes blad-val {
  0%   { transform: translateY(-60px) translateX(0) rotate(0deg); opacity: 0; }
  10%  { opacity: .7; }
  85%  { opacity: .5; }
  100% { transform: translateY(var(--valveld, 1800px)) translateX(60px) rotate(360deg); opacity: 0; }
}
@keyframes blad-zwaai {
  0%, 100% { margin-left: 0; }
  50%      { margin-left: 28px; }
}

.blad {
  position: absolute; top: -60px;
  animation: blad-val linear infinite, blad-zwaai ease-in-out infinite;
  will-change: transform;
}
.blad svg { display: block; opacity: var(--blad-dek, .5); }
.blad-nerf { color: var(--green-700); opacity: .45; }

/* De twaalf standen. In de stylesheet en niet in een `style`-attribuut: de CSP
   staat `style-src 'self'` zonder `'unsafe-inline'`, en een routetest bewaakt
   dat er nergens een `style`-attribuut in de uitvoer staat.

   Positie en tempo zijn dezelfde als in V1, en sinds deze ronde de kleur ook.
   V1 geeft elk blaadje zijn eigen tint en dekking — #4ade80, #86efac, #22c55e en
   #16a34a, tussen .35 en .6 — en dat is precies waarom die hero als een bui
   blaadjes leest en niet als twaalf keer hetzelfde stickertje. Hier stond één
   kleur voor alle twaalf, en die verwees bovendien naar een token dat niet
   bestond; zie de opmerking bij `--green-500` bovenin.

   De volgorde van de tinten is die van V1, blaadje voor blaadje overgenomen.

   De valduren zijn wél veranderd, en dat moest: het valveld is bijna drie keer
   zo diep als de 640px van hiervoor, dus met de oude 8 tot 15 seconden zouden
   dezelfde blaadjes er drie keer zo hard doorheen schieten. Dat is geen dwarrel
   meer maar regen. Ze zijn met dezelfde factor meegegroeid, zodat de valsnelheid
   blijft wat hij op de huidige site is. De zwaai staat los van de diepte en
   verandert niet.

   De negatieve vertragingen zijn over de nieuwe duren uitgesmeerd: ze zetten elk
   blaadje bij het laden op een ander punt in zijn val. Zonder dat begint de
   pagina met twaalf blaadjes netjes naast elkaar boven de vouw. */
.blad:nth-child(1)  { left: 7%;  animation-duration: 20s, 4.2s;  animation-delay: 0s, 0s;      color: var(--green-400); --blad-dek: .6; }
.blad:nth-child(2)  { left: 18%; animation-duration: 26s, 5s;    animation-delay: -8s, -1s;    color: var(--green-300); --blad-dek: .55; }
.blad:nth-child(3)  { left: 33%; animation-duration: 22s, 3.8s;  animation-delay: -14s, -2s;   color: var(--green-600); --blad-dek: .35; }
.blad:nth-child(4)  { left: 52%; animation-duration: 30s, 6s;    animation-delay: -3s, -3s;    color: var(--green-400); --blad-dek: .5; }
.blad:nth-child(5)  { left: 67%; animation-duration: 18s, 4.5s;  animation-delay: -20s, -.5s;  color: var(--green-300); --blad-dek: .6; }
.blad:nth-child(6)  { left: 80%; animation-duration: 24s, 5.5s;  animation-delay: -10s, -1.5s; color: var(--green-500); --blad-dek: .4; }
.blad:nth-child(7)  { left: 91%; animation-duration: 28s, 4s;    animation-delay: -17s, -2.5s; color: var(--green-400); --blad-dek: .5; }
.blad:nth-child(8)  { left: 12%; animation-duration: 24s, 5.2s;  animation-delay: -5s, -1.8s;  color: var(--green-600); --blad-dek: .45; }
.blad:nth-child(9)  { left: 25%; animation-duration: 21s, 3.5s;  animation-delay: -12s, -.8s;  color: var(--green-300); --blad-dek: .6; }
.blad:nth-child(10) { left: 43%; animation-duration: 32s, 6.5s;  animation-delay: -22s, -3.2s; color: var(--green-400); --blad-dek: .4; }
.blad:nth-child(11) { left: 58%; animation-duration: 23s, 4.8s;  animation-delay: -4s, -2.2s;  color: var(--green-500); --blad-dek: .55; }
.blad:nth-child(12) { left: 74%; animation-duration: 19s, 3.9s;  animation-delay: -25s, -1.2s; color: var(--green-300); --blad-dek: .5; }

/* Onder `prefers-reduced-motion` gaan ze wég en niet op pauze. Het blok
   verderop in dit bestand zet elke animatieduur op .001ms; dat zou hier twaalf
   blaadjes bevroren middenin de lucht achterlaten. */
@media (prefers-reduced-motion: reduce) {
  .blaadjes { display: none; }
}

.paneel { grid-area: paneel; }
@media (min-width: 1000px) {
  .paneel { position: sticky; top: calc(var(--header-h) + 20px); }
}

/* Het paneel is het doel van de twee mobiele CTA's (`#prijscheck`).

   `scroll-margin-top` en niet alleen de globale `scroll-padding-top` op `html`:
   die laatste houdt rekening met de vaste header, maar zet het paneel dan met
   zijn bovenrand precies tegen de onderkant daarvan aan. De extra ruimte maakt
   zichtbaar dat er iets bóven het paneel staat en dat je dus niet op een nieuwe
   pagina bent beland — de sprong hoort als "terug naar het formulier" te lezen
   en niet als een paginawissel.

   De focusring blijft staan. Het paneel draagt `tabindex="-1"` zodat een
   schermlezer de sprong ook werkelijk aankondigt, en dan hoort er een zichtbaar
   teken bij waar de focus terechtkwam. Alleen wanneer de browser zelf oordeelt
   dat de ring niet nodig is (`:focus:not(:focus-visible)` — een muisklik op de
   knop) blijft hij weg; dat is de stand waarin een groene rechthoek om een heel
   paneel als een weergavefout leest. */
.paneel { scroll-margin-top: calc(var(--header-h) + 20px); }
.paneel:focus:not(:focus-visible) { outline: none; }

/* Het paneel draagt hetzelfde groen als de primaire knop (`--green-800`,
   #166534): dat is de canonieke merkkleur en de actiekleur van de site, en dit
   is het blok waar de actie gebeurt. Eerder stond hier `--green-900`, het
   donkerste vlak; dat las als de voet en niet als een aanmeldblok.

   Wit op `--green-800` haalt 7,1:1. */
.paneel-kaart {
  background: var(--green-800);
  color: var(--ink-on-dark);
  border-radius: var(--radius-lg);
  padding: 22px;
  box-shadow: var(--shadow-lg);
}
@media (min-width: 560px) { .paneel-kaart { padding: 26px; } }

/* De invoervelden blijven wit met donkere tekst. De ontwerprichting maakt ze
   doorschijnend, en dat is op een donker vlak precies waar contrast sneuvelt:
   een placeholder op 14% wit haalt geen 4,5:1. Wit veld op donkergroen paneel
   haalt het altijd, en houdt bovendien `.input` ongewijzigd — dezelfde component
   als elk ander formulier op de site. */
/* De adrescheck is binnen het paneel geen eigen kaart meer: het paneel ís de
   kaart. Zonder deze regel staat er een witte kaart met rand en schaduw binnen
   een donkergroene kaart met rand en schaduw. De partial zelf blijft
   ongewijzigd — hij wordt op zes routes gebruikt en houdt overal dezelfde
   veldnamen, id's en `.input`-klassen. */
.paneel-kaart .postcheck {
  background: transparent; border: 0; box-shadow: none; padding: 0;
}
.paneel-kaart .postcheck-title { color: #fff; font-size: 1.15rem; }
.paneel-kaart .postcheck-sub { color: var(--green-200); }
.paneel-kaart .field-label { color: #fff; }
.paneel-kaart .field-label .muted { color: var(--green-200); }
.paneel-kaart .muted { color: var(--green-200); }

/* De knop is wit met donkergroene tekst. Op dit vlak kán de primaire knop niet
   groen zijn — groen op groen is geen knop. Hij blijft de enige dominante actie
   van de pagina; wit op donkergroen is hier de sterkste stand die er is.
   Contrast van `--green-800` op wit is 7,1:1. */
.paneel-kaart .btn-primary {
  background: #fff; color: var(--green-800); border-color: #fff;
}
.paneel-kaart .btn-primary:hover {
  background: var(--green-50); border-color: var(--green-50); color: var(--green-800);
}

/* De drie beloftes onder het formulier. In het paneel en niet in de leeskolom:
   ze horen bij de beslissing om het formulier in te vullen. */
.paneel-usp {
  list-style: none; padding: 0;
  margin: 18px 0 0;
  display: grid; gap: 8px;
  border-top: 1px solid rgba(255,255,255,.18);
  padding-top: 18px;
  font-size: .9375rem;
}
.paneel-usp li { display: flex; gap: 10px; color: var(--green-100); }
.paneel-usp li::before { content: "✓"; color: var(--green-300); font-weight: 700; flex: none; }

.paneel-onder { margin: 14px 0 0; font-size: .9375rem; color: var(--ink-3); text-align: center; }

/* ── Het tikdoel van "Liever even bellen? 06 …" ────────────────────────────

   Gemeten op 390×844: 94×18 CSS-pixels. WCAG 2.2 SC 2.5.8 (Target Size,
   Minimum, niveau AA) vraagt 24×24, en de uitzondering voor tekstlinks in een
   lopende zin geldt hier niet — dit is een losse regel onder een formulier,
   geen link in een alinea.

   18px is bovendien precies de maat waarop het in de praktijk misgaat: op een
   telefoon staat deze regel vlak boven of onder de vaste actiebalk, en dan is
   een strook van 18 px het verschil tussen bellen en iets anders raken.

   ── Waarom zó, en niet met padding ────────────────────────────────────────

   De eis luidde: geen visuele rommel. Een `padding` op een inline element
   vergroot het tikdoel niet in de hoogte (inline boxen negeren verticale
   padding voor de regelhoogte), en `display: inline-block` mét padding schuift
   de regel uit elkaar en zet een zichtbaar blok onder het paneel.

   `min-height` op een `inline-flex` doet wat er gevraagd wordt: de raakbare doos
   wordt 24px hoog, de tekst blijft in het midden staan, en er verandert niets
   aan kleur, rand, achtergrond of onderstreping. De regel eromheen blijft even
   hoog omdat de 24px binnen de bestaande regelhoogte van `.paneel-onder` valt —
   nagemeten, niet aangenomen. */
.paneel-onder a {
  display: inline-flex; align-items: center;
  min-height: 24px; min-width: 24px;
}

/* ── De hero van de advertentiepagina ────────────────────────────────────

   `.hero` is niet meer de homepage maar nog wél de compacte kop van `/lp/`:
   daar is één kolom juist goed, want elke uitgang is op betaald verkeer een
   lek en een tweede kolom is een tweede blikrichting. */
.hero {
  padding-block: 8px var(--ruimte-klein);
  background: linear-gradient(180deg, var(--green-50) 0%, var(--paper) 62%);
}
@media (min-width: 900px) { .hero { padding-block: 28px var(--ruimte); } }

.hero h1 { margin-bottom: 10px; }
/* 52ch en niet de 54ch van `--maat-lead`: bij 54ch viel het laatste woord van de
   introzin op een derde regel, en de opdracht staat er twee toe. */
.hero .lead { margin-bottom: 0; max-width: 52ch; }
@media (min-width: 900px) {
  .hero h1 { margin-bottom: 12px; }
}

/* Hier stond `.trust-list`, de drie voordelen onder de oude hero. Ze staan sinds
   de tweedeling in het meelopende paneel (`.paneel-usp`), want ze horen bij de
   beslissing om het formulier in te vullen en niet bij de leeskolom. Wat er
   inhoudelijk in élke prijs zit, staat nu in de prijssectie als `.check-list` —
   dat is een andere uitspraak en hoort op een andere plek. Nagelopen met `grep`
   op `class="…"` over `templates/`: geen enkele template voert hem nog. */

/* Hier stonden `.hero-photo` en `.hero-figure`, de brede werkfoto tussen de
   intro en de tarieven op de homepage. Die is er op verzoek van Floor uitgegaan;
   het gezicht staat een stuk lager, in het persoonsblok, waar het bij de tekst
   hoort die het toelicht. De bestanden onder `/assets/img/hero-opname-*` blijven
   staan — die horen bij de beeldbank en niet bij deze ene plaatsing.

   Nagelopen met `grep` op `class="…"` over `templates/`: geen enkele template
   voert ze nog. */

/* Hier stonden drie componenten die geen enkele template meer rendert:
   `.adviseur` (de adviseurregel boven de H1), `.hero-prijs` (het vetgezette
   vanafbedrag in de introzin) en `.labelstrook` (de A-t/m-G-schaal). Alle drie
   zijn ze met `grep` op `class="…"` over `templates/` nagelopen en geen van
   drieën komt er nog in voor; ze zijn resten van een eerdere heroversie.

   Wat ze deden, doet deze ronde een gedeeld component:
   de bovenregel is `.eyebrow`, en het vanafbedrag staat als eerste vak in
   `.feitenbalk` — mét zijn bron, in plaats van als los vetgezet getal.

   `.photo-caption` en `.photo-placeholder` zijn om dezelfde reden weg: de
   eerste plakte een naambordje over de hero-foto, de tweede was de tijdelijke
   ruit voor een foto die er inmiddels gewoon is. */

/* -------------------------------------------------- 8. de postcodecheck */

.postcheck {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: 20px;
}
@media (min-width: 560px) { .postcheck { padding: 24px; } }

.postcheck.on-green { border-color: var(--green-200); }

.postcheck-title {
  font-size: 1.0625rem; font-weight: 800; color: var(--ink);
  margin: 0 0 4px; letter-spacing: -.01em;
}
.postcheck-sub { font-size: .875rem; color: var(--ink-3); margin: 0 0 16px; }

/* De invoervelden lijnen ónderaan uit en niet bovenaan.

   Ze staan in een raster, dus standaard begint elk label op dezelfde lijn en
   rekt elk veld tot de hoogte van zijn rij. Zodra één label over twee regels
   valt — "Toev. (optioneel)" doet dat in een kolom van deze breedte — zakt dat
   ene invoerveld een regel omlaag en staan de drie velden niet meer op één
   lijn. Opgemeten op 1440px, nadat de optioneel-markering erbij kwam.

   `end` legt de onderrand van de velden vast. Dan mag een label boven het veld
   twee regels innemen zonder dat de rij scheef gaat staan, en hoeft de lengte
   van een labeltekst geen ontwerpbeperking te zijn.

   De twee velden staan vanaf 360px naast elkaar in plaats van vanaf 420px.
   Op een 390px-scherm scheelt dat ongeveer 76px, en dat is precies het verschil
   tussen een verzendknop nét onder en nét boven de vouw. "2712 AB" en "12 A"
   passen ruim in de helft van 310px binnenwerk; ze zijn op 360px gemeten. */
.postcheck-fields { display: grid; gap: 12px; grid-template-columns: 1fr; }
@media (min-width: 360px) {
  .postcheck-fields { grid-template-columns: 1.25fr 1fr; gap: 10px; align-items: end; }
}

/* "Adres controleren…" — de regel tussen de klik en het omslaan van de pagina.

   Hij staat met `hidden` in de HTML en site.js haalt die vlag weg bij verzenden;
   zonder script blijft hij dus onzichtbaar. `margin-top` en niets eronder: de
   regel eronder ("Vrijblijvend…") houdt zijn eigen ruimte, zodat het verschijnen
   van deze tekst de knop niet verplaatst terwijl de bezoeker er nog op kijkt.

   Geen animatie en geen spinner. Op een geslaagde opzoeking staat hij er ~0,15 s
   en dan is elke inloopanimatie een flits; wat er moet staan is een woord, niet
   een effect. */
.postcheck-status {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 12px 0 0;
  font-size: .875rem;
  font-weight: 600;
  color: var(--ink-2);
}
.postcheck-status[hidden] { display: none; }

/* Het bolletje ervoor is decoratief en staat daarom in CSS en niet in de tekst:
   een schermlezer leest via role="status" alleen "Adres controleren…". */
.postcheck-status::before {
  content: "";
  flex: none;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  border: 2px solid var(--green-600, currentColor);
  border-top-color: transparent;
  animation: postcheck-draai .7s linear infinite;
}
@keyframes postcheck-draai { to { transform: rotate(360deg); } }

/* Wie beweging heeft afgezet, krijgt een vol bolletje in plaats van niets:
   een statisch halfrondje leest als een weergavefout. */
@media (prefers-reduced-motion: reduce) {
  .postcheck-status::before {
    animation: none;
    border-top-color: currentColor;
  }
}

/* De knop tijdens het verzenden: zichtbaar buiten werking, maar niet weggevaagd.
   `disabled` alleen zou hem in sommige thema's grijs en onleesbaar maken, en de
   bezoeker moet kunnen blijven lezen waar hij op geklikt heeft. */
.postcheck [data-postcheck-knop][disabled] { opacity: .65; cursor: default; }

/* De hero-variant: alles wat niet meehelpt om de knop hoger te krijgen, gaat op
   een smal scherm weg. Op 560px en breder is de ruimte er wél en komt de
   toelichting gewoon terug. */
/* Onderaan iets krapper dan bovenaan: de hulptekst is in deze variant
   verborgen, dus 16px onder de knop is lucht die op 390px de kaart tot ónder de
   bovenrand van de cookiebanner duwde. Gemeten, niet geschat. */
.postcheck.is-compact { padding: 16px 16px 10px; }
.postcheck.is-compact .postcheck-sub,
.postcheck.is-compact .field-hint { display: none; }
@media (min-width: 560px) {
  .postcheck.is-compact { padding: 24px; }
  .postcheck.is-compact .postcheck-sub,
  .postcheck.is-compact .field-hint { display: block; }
}

/* De statuschip: kan ik hier direct langskomen, ja of nee. Dat is de eerste
   vraag van iemand die via een advertentie op een plaatsnaampagina landt, en hij
   stond alleen verstopt in de eyebrow-tekst. */
.status-chip {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: .8125rem; font-weight: 700;
  padding: 6px 14px 6px 10px; border-radius: 999px;
  margin-bottom: 14px;
}
.status-chip svg { width: 16px; height: 16px; flex: none; }
.status-chip.is-direct  { background: var(--green-100); color: var(--green-900); }
/* "Op aanvraag" is geen waarschuwing maar een gewone bedrijfsstand, en geel is
   sinds deze ronde voorbehouden aan echte waarschuwingen. Neutraal dus; het
   onderscheid met `is-direct` blijft in de tekst staan en niet alleen in kleur. */
.status-chip.is-aanvraag { background: var(--sand); color: var(--ink-2); border: 1px solid var(--line-2); }

/* -------------------------------------------------------- 9. formulieren */

.field { display: block; }
.field-label {
  display: block; font-size: .875rem; font-weight: 700;
  color: var(--ink); margin-bottom: 6px;
}
.field-hint { font-size: .8125rem; color: var(--ink-3); margin: 6px 0 0; }

/* Het verplicht-sterretje. Rood en niet groen: het is geen merkaccent maar een
   eis, en de admin doet met `.ll-required` precies hetzelfde.

   Het sterretje zelf staat op `aria-hidden`; de betekenis komt uit de verborgen
   tekst ernaast in de markup. Zonder die tekst zou "verplicht" alleen uit een
   kleur en een vorm blijken, en dat is de foutstand die de opdracht verbiedt. */
.field-required { color: var(--danger); margin-left: 2px; font-weight: 700; }

/* ── Hetzelfde sterretje op het groene paneel ──────────────────────────────

   `--danger` (#b42318) op `--green-800` (#166534) haalt **1,08:1**. Dat is geen
   krap contrast maar geen contrast: donkerrood op donkergroen is op een gewoon
   scherm één vlak, en de twee kleuren liggen bovendien precies op de as waar
   rood-groenblindheid ze samenvouwt. Het sterretje stond er dus wel en was er
   niet — op het enige formulier dat de homepage draagt.

   Uitgerekend en niet geschat: beide kleuren staan in `ll-brand.css`, en de
   berekening is de gewone WCAG-verhouding over de relatieve luminanties.

   ── Waarom lichtroze en niet wit ──────────────────────────────────────────

   Wit haalt 7,1:1 en zou het probleem ook oplossen, maar dan is het sterretje
   dezelfde kleur als het label ernaast en verdwijnt het onderscheid dat het moet
   maken. #ffd5d0 is de lichte tint van dezelfde rode familie: 5,3:1 op dit
   paneel, dus ruim boven de 4,5:1 voor gewone tekst, en nog altijd zichtbaar
   rood naast het witte label.

   Dit blijft een **aanvulling** op de betekenis en niet de drager ervan: de
   verplichting staat in de verborgen tekst "(verplicht)" naast het sterretje in
   `adrescheck.php`. Die markup verandert hier niet. Wat hier wordt gerepareerd
   is de zichtbare helft, voor de bezoeker die geen schermlezer gebruikt.

   `.paneel-kaart` en niet `.on-dark`: alleen ín de kaart is de achtergrond
   werkelijk donkergroen. `.on-dark` staat op het hele paneel, waarvan het
   onderste stuk (`.paneel-onder`) op de lichte ochtendband ligt. */
.paneel-kaart .field-required { color: #ffd5d0; }

.input, .select, .textarea {
  width: 100%;
  min-height: var(--tap);
  padding: 11px 14px;
  /* 16px is de ondergrens waaronder iOS bij focus inzoomt. Nooit lager. */
  font: inherit; font-size: 16px;
  color: var(--ink);
  background: #fff;
  border: 1.5px solid var(--line-2);
  border-radius: var(--radius-sm);
  transition: border-color .15s, box-shadow .15s;
}
.input::placeholder { color: var(--ink-3); }
.input:hover, .select:hover, .textarea:hover { border-color: var(--ink-3); }
.input:focus, .select:focus, .textarea:focus {
  border-color: var(--green-700);
  box-shadow: 0 0 0 3px var(--green-100);
  outline: none;
}
.textarea { min-height: 120px; resize: vertical; line-height: 1.6; }

.select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='%2367786e'%3E%3Cpath d='M5.5 7.5 10 12l4.5-4.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 20px;
  padding-right: 40px;
}

/* Foutmelding staat direct bij het veld, nooit alleen bovenaan het formulier */
.field.has-error .input,
.field.has-error .select,
.field.has-error .textarea { border-color: var(--danger); background: #fffbfb; }
.field.has-error .input:focus { box-shadow: 0 0 0 3px var(--danger-bg); }

.field-error {
  display: flex; align-items: flex-start; gap: 6px;
  margin: 6px 0 0; font-size: .875rem; font-weight: 600; color: var(--danger);
}
.field-error svg { width: 16px; height: 16px; flex: none; margin-top: 2px; }

.check {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 12px; border: 1.5px solid var(--line);
  border-radius: var(--radius-sm); cursor: pointer;
  min-height: var(--tap);
}
.check:hover { border-color: var(--line-2); background: var(--sand); }
.check input { width: 20px; height: 20px; margin: 2px 0 0; flex: none; accent-color: var(--green-700); }
.check span { font-size: .9375rem; }

/* Keuzeknoppen (woningtype, datum, tijd) — radio's die als kaart tonen */
.choice-grid { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.choice {
  position: relative; display: flex; flex-direction: column; gap: 2px;
  min-height: var(--tap); padding: 12px 14px;
  border: 1.5px solid var(--line-2); border-radius: var(--radius);
  background: #fff; cursor: pointer; text-align: left;
  font: inherit; color: var(--ink-2);
  transition: border-color .15s, background-color .15s;
}
.choice:hover { border-color: var(--green-600); background: var(--green-50); }
.choice input { position: absolute; opacity: 0; pointer-events: none; }
.choice .c-title { font-weight: 700; color: var(--ink); font-size: .9375rem; }
.choice .c-note { font-size: .8125rem; color: var(--ink-3); }
.choice:has(input:checked) {
  border-color: var(--green-700); background: var(--green-50);
  box-shadow: inset 0 0 0 1px var(--green-700);
}
.choice:has(input:checked)::after {
  content: "✓"; position: absolute; top: 10px; right: 12px;
  color: var(--green-700); font-weight: 800;
}
.choice:has(input:focus-visible) { outline: var(--ll-focus-width) solid var(--ll-focus); outline-offset: var(--ll-focus-offset); }
.choice[disabled], .choice.is-disabled {
  opacity: .45; cursor: not-allowed; background: var(--sand);
}

/* --------------------------------------------------------- 10. meldingen */

.notice {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 14px 16px; border-radius: var(--radius);
  border: 1px solid var(--line); background: var(--sand);
  font-size: .9375rem;
}
.notice svg { width: 20px; height: 20px; flex: none; margin-top: 2px; }
.notice p { margin: 0; }
.notice p + p { margin-top: 6px; }
.notice strong { display: block; margin-bottom: 2px; }

.notice-ok      { background: var(--ok-bg);     border-color: var(--green-200); color: var(--green-900); }
.notice-ok svg  { color: var(--green-700); }
/* De enige plek op de publieke site waar geel de hoofdrol speelt, en precies
   waarvoor het is bedoeld. */
.notice-warn    { background: var(--amber-50);  border-color: var(--amber-200); color: var(--amber-700); }
.notice-warn svg{ color: var(--amber-700); }
.notice-error   { background: var(--danger-bg); border-color: var(--ll-danger-line); color: var(--danger); }
.notice-error svg { color: var(--danger); }

/* Het label waarmee het prototype eerlijk blijft over wat er nog niet echt is */
.placeholder-tag {
  display: inline-flex; align-items: center; gap: 6px;
  background: repeating-linear-gradient(45deg, var(--amber-50) 0 8px, #fff 8px 16px);
  border: 1px dashed var(--amber-700);
  color: var(--amber-700); font-size: .75rem; font-weight: 700;
  padding: 4px 10px; border-radius: 999px;
  text-transform: uppercase; letter-spacing: .04em;
}

/* ------------------------------------------------------------ 11. kaarten */

/* Rasterkinderen krijgen standaard `min-width: auto`, waardoor één breed kind
   (een lange knop, een tabel) de hele kolom oprekt in plaats van te krimpen.
   Dit zet dat terug voor alle roosters van de site. */
.grid > *, .hero-grid > *, .booking-grid > *, .area-cols > *, .cta-grid > * { min-width: 0; }

/* Een raster is soms een `<ul>` — de contactpagina zet er drie `<li class="card">`
   in, en dat is de juiste markup voor drie gelijkwaardige contactmanieren. Zonder
   deze reset houdt de lijst zijn opsommingstekens en zijn 40px inspringing: op
   1440px stonden er drie bolletjes náást de kaarten in de lege ruimte links.

   Dezelfde reset als `.steps`, `.included`, `.check-list` en `.footer-links ul`
   al hebben. `.grid` was de enige rasterklasse zonder. */
.grid { display: grid; gap: 16px; list-style: none; padding-left: 0; }
.grid-2 { grid-template-columns: 1fr; }
.grid-3 { grid-template-columns: 1fr; }
.grid-4 { grid-template-columns: 1fr; }
@media (min-width: 640px) {
  .grid { gap: 20px; }
  .grid-2, .grid-3, .grid-4 { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1120px) {
  .grid-3 { grid-template-columns: repeat(3, 1fr); }
  .grid-4 { grid-template-columns: repeat(4, 1fr); }
}

.card {
  background: #fff; border: 1px solid var(--line);
  border-radius: var(--radius-lg); padding: 22px;
}
.card-pad-lg { padding: 26px; }
@media (min-width: 900px) { .card-pad-lg { padding: 34px; } }
/* De kop van een kaart, welk niveau hij ook heeft. Een `<h2>` in een kaart is
   geen ontwerpkeuze maar een koppenstructuur: op de contactpagina staan de drie
   kaarten direct onder de `<h1>`, dus `h2` is het juiste niveau. Zonder maat
   erbij droeg die kop de paginaschaal uit blok 3 — `clamp(1.5rem … 2.25rem)` —
   en was "Bellen" in een kaart van 200px breed groter dan de sectiekop eronder.

   De kop van een kaart hoort bij de kaart en niet bij de pagina; het niveau is
   voor de schermlezer, de maat voor het oog. */
.card h2, .card h3 { font-size: 1.0625rem; margin-bottom: 8px; }
.card p:last-child { margin-bottom: 0; }
.card-raised { box-shadow: var(--shadow); border-color: transparent; }

.card-icon {
  width: 44px; height: 44px; border-radius: 12px;
  background: var(--green-50); color: var(--green-700);
  display: grid; place-items: center; margin-bottom: 14px;
}
.card-icon svg { width: 22px; height: 22px; }
/* Het waarschuwende kaarticoon. Heette `.amber` naar zijn kleur; een klasse die
   naar een kleur is genoemd, staat het wisselen van die kleur juist in de weg. */
.card-icon.card-icon-warn { background: var(--amber-50); color: var(--amber-700); }

/* -------------------------------------------------------------- 12. stappen */

/* De stappen zijn een verticale genummerde lijst en geen kolommenrooster.
 *
 * ## Waarom dit in de Ochtendlicht-ronde is omgezet
 *
 * Twee redenen, en de tweede is een gemeten fout.
 *
 * **De ontwerprichting.** Vier stappen als vier omrande kaarten naast elkaar is
 * precies wat de opdracht met "minder losse kaarten" bedoelt. Een genummerde
 * lijst leest als een uitleg; vier kaarten lezen als een productvergelijking.
 *
 * **De kolombreedte.** De oude regel zette vier kolommen aan vanaf een
 * **venster** van 1120px, terwijl deze lijst sinds deze ronde in de leeskolom
 * van 760px staat. Op 1440px werd elke stap daardoor ongeveer 170px breed — een
 * kolom van drie woorden per regel, waarin "Registratie, factuur en levering"
 * over vier regels viel. Een media query kijkt naar het venster en niet naar de
 * ruimte die het element werkelijk heeft; dat verschil was hier onzichtbaar
 * zolang de lijst nog over de volle breedte stond.
 *
 * Verticaal heeft dat probleem niet: de tekst krijgt de volle leeskolom, en de
 * lijst wordt niet hoger dan de vier alinea's die er toch al stonden.
 */
.steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 20px; }

.step {
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr);
  gap: 4px 14px;
  align-items: start;
}
.step-nr {
  display: inline-grid; place-items: center;
  width: 32px; height: 32px; border-radius: 50%;
  background: var(--green-100); color: var(--green-800);
  font-family: var(--display); font-weight: 700; font-size: .9375rem;
}
/* De kop en de tekst staan in de tweede kolom. Een `<h3>` is een blokelement en
   zou zonder deze regel een eigen rasterrij pakken.

   `align-self: center` op de kop en niet `start`: het bolletje is 32px hoog en
   een kopregel ongeveer 26px, dus met beide bovenaan hangt de tekst zichtbaar
   boven het midden van het bolletje. Gecentreerd staan ze op één lijn. */
.step h3 {
  grid-column: 2; align-self: center;
  font-size: var(--g-0); margin: 0;
}
.step p  { grid-column: 2; font-size: .9375rem; margin: 0; }

/* Staat er geen nummer in de HTML — de advertentiepagina laat het weg, want daar
   is het "in het kort" en geen stappenplan — dan valt de nummerkolom weg. */
.step:not(:has(.step-nr)) { grid-template-columns: minmax(0, 1fr); }
.step:not(:has(.step-nr)) h3,
.step:not(:has(.step-nr)) p { grid-column: 1; }

/* Hier stond `.steps-kaal`: de homepage toonde van elke processtap alleen de
   kop, en 12px tussenruimte hield die zes losse regels bij elkaar.

   Sinds deze ronde staat onder elke stap weer de korte regel uit `route()` — zes
   koppen vertellen wélke stappen er zijn maar niet wat er van je verwacht wordt,
   en dat is juist het geruststellende deel. Daarmee is een stap weer twee regels
   hoog en is de gewone 20px van `.steps` de maat waarvoor dat raster gemaakt is.

   Nagelopen met `grep` op `steps-kaal` over `templates/`: geen enkele template
   voert hem nog. */

/* De lange tijdlijn op /werkwijze/ */
.timeline { list-style: none; margin: 0; padding: 0; position: relative; }
.timeline::before {
  content: ""; position: absolute; left: 19px; top: 8px; bottom: 8px;
  width: 2px; background: var(--line); border-radius: 2px;
}
.tl-item { position: relative; padding: 0 0 28px 56px; }
.tl-item:last-child { padding-bottom: 0; }
.tl-nr {
  position: absolute; left: 0; top: 0;
  width: 40px; height: 40px; border-radius: 12px;
  background: var(--green-700); color: #fff;
  display: grid; place-items: center; font-weight: 800; font-size: 1rem;
  border: 4px solid #fff;
}
.tl-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px 12px; margin-bottom: 6px; }
/* h2 én h3: /werkwijze/ zet de stapkop op h2 (de paginakop levert de h1), de
   plaatspagina's gebruiken h3 onder een eigen sectiekop. */
.tl-head :is(h2, h3) { margin: 0; }
.tl-duur {
  font-size: .8125rem; font-weight: 700; color: var(--green-800);
  background: var(--green-100); padding: 3px 10px; border-radius: 999px;
}
.tl-split { display: grid; gap: 10px; margin-top: 14px; }
@media (min-width: 640px) { .tl-split { grid-template-columns: 1fr 1fr; gap: 14px; } }
.tl-box {
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 12px 14px; background: #fff; font-size: .9375rem;
}
.tl-box b { display: block; font-size: .75rem; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-3); margin-bottom: 3px; }
.tl-box.mine { background: var(--green-50); border-color: var(--green-100); }

/* ------------------------------------------------------------ 13. prijzen */

.price-card {
  background: var(--green-900); color: var(--ink-on-dark);
  border-radius: var(--radius-lg); padding: 26px;
  box-shadow: var(--shadow-lg);
}
@media (min-width: 900px) { .price-card { padding: 40px; } }
.price-card h2, .price-card h3 { color: #fff; }

.price-headline { display: flex; flex-wrap: wrap; align-items: baseline; gap: 10px; margin-bottom: 4px; }
.price-headline .p-big { font-size: clamp(2.25rem, 1.6rem + 2.6vw, 3.25rem); font-weight: 800; color: #fff; letter-spacing: -.03em; line-height: 1; }
.price-headline .p-from { font-size: 1rem; font-weight: 700; color: var(--green-300); }

/* De staffeltabel.

   Dit blok was geschreven voor een rijencomponent van `<div>`s (`.tier`,
   `.tier-name`, `.tier-price`) op de dónkere `.price-card` — met een rand van
   `rgba(255,255,255,.16)`. Wat `templates/site/partials/prijstabel.php` rendert
   is een gewone `<table class="tiers">` met `<thead>`, `<th scope="row">` en
   `<td>`, en die staat op alle vijf de plekken waar hij voorkomt op een lichte
   achtergrond: home, /tarieven/, de plaatspagina's, de Ads-pagina's en — binnen
   een `<details>`, dus buiten de kaart — stap 5 van de boekingsflow.

   Geen enkele selector hieronder raakte die markup. De tabel viel daardoor
   terug op de UA-standaard: 1px celpadding, een gecentreerde `<th>` en een rand
   die op wit onzichtbaar is. Dezelfde soort fout als de header en het menu van
   12B.9 — de markup is vernieuwd, de opmaak bleef op de oude haak zitten.

   Hij is daarom herschreven als de tabelcomponent die er werkelijk staat. De
   dode `.tier*`-klassen zijn eruit: een tweede naam voor hetzelfde ding die
   niemand rendert, is precies wat de volgende lezer op het verkeerde been zet. */
.tiers {
  width: 100%;
  /* `separate` en niet `collapse`: een samengevouwen rand negeert de ronding van
     de tabel zelf, en dan zou de hoek van een omhullende scroller moeten komen —
     die kan hem alleen met `overflow: hidden` afsnijden, en dat zet juist het
     scrollen uit. Met `border-spacing: 0` ziet hij er verder hetzelfde uit.
     Dezelfde afweging als bij `.ll-table` in admin.css. */
  border-collapse: separate;
  border-spacing: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: #fff;
  font-size: .9375rem;
}

.tiers thead th {
  padding: 11px 16px;
  text-align: left;
  font-size: .8125rem;
  font-weight: 700;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--ink-3);
  background: var(--sand);
  border-bottom: 1px solid var(--line);
}

.tiers tbody th,
.tiers tbody td {
  padding: 13px 16px;
  border-bottom: 1px solid var(--line);
  vertical-align: baseline;
}

.tiers tbody tr:last-child th,
.tiers tbody tr:last-child td { border-bottom: 0; }

/* De staffelnaam is de rijkop en hoort links uitgelijnd; `<th>` staat in de
   UA-stylesheet op `center`. */
.tiers tbody th {
  text-align: left;
  font-weight: 600;
  color: var(--ink-2);
}

/* Het bedrag in tabellarische cijfers. Zonder `tabular-nums` hebben de cijfers
   in de meeste proportionele letters een eigen breedte — een "1" is smaller dan
   een "4" — en dan staan de komma's van € 249,00 en € 429,00 niet onder elkaar.
   Op een prijslijst leest dat als een tabel die niet klopt.

   `--data` erbij, want een mono-letter maakt de uitlijning zichtbaar in plaats
   van alleen correct; het is dezelfde keuze als in de ontwerprichting. */
.tiers tbody td {
  font-family: var(--data);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  font-size: .9375rem;
  color: var(--ink);
  white-space: nowrap;
}

/* De toeslag boven de laatste staffel: hoort bij het bedrag, maar niet met
   hetzelfde gewicht. Op een smal scherm onder het bedrag in plaats van ernaast —
   "€ 429,00 + € 1,25 per m² boven 225 m²" past niet op één regel van 390px. */
.tier-toeslag {
  display: block;
  margin-top: 2px;
  font-size: .8125rem;
  font-weight: 600;
  color: var(--ink-3);
  white-space: normal;
}
@media (min-width: 560px) {
  .tier-toeslag { display: inline; margin-top: 0; }
}


.included { list-style: none; margin: 0; padding: 0; display: grid; gap: 11px; }
.included li { display: flex; gap: 11px; align-items: flex-start; font-size: .9375rem; }
.included svg { width: 20px; height: 20px; flex: none; color: var(--green-300); margin-top: 1px; }
.included.on-light svg { color: var(--green-600); }

/* ------------------------------------------------------------ 14. reviews */

/* Goud is de conventie voor sterren, maar het is op deze site geel zonder
   waarschuwing en dat is precies wat er weg moest. De sterren dragen hun
   waardering al in een `aria-label`, dus de kleur is versiering. */
.stars { display: inline-flex; gap: 2px; color: var(--green-700); }
.stars svg { width: 17px; height: 17px; }

.review {
  background: #fff; border: 1px solid var(--line);
  border-radius: var(--radius-lg); padding: 22px;
  display: flex; flex-direction: column; gap: 14px;
}
.review-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.review blockquote { margin: 0; font-size: .9375rem; color: var(--ink-2); line-height: 1.6; }
.review-who { display: flex; align-items: center; gap: 11px; margin-top: auto; }
.review-avatar {
  width: 38px; height: 38px; border-radius: 50%; flex: none;
  background: var(--green-100); color: var(--green-800);
  display: grid; place-items: center; font-weight: 800; font-size: .9375rem;
}
.review-name { font-weight: 700; color: var(--ink); font-size: .9375rem; line-height: 1.3; }
.review-meta { font-size: .8125rem; color: var(--ink-3); line-height: 1.3; }

.google-mark { font-weight: 800; font-size: .875rem; letter-spacing: -.02em; }
.google-mark .b { color: #4285f4; } .google-mark .r { color: #ea4335; }
.google-mark .y { color: #fbbc05; } .google-mark .g { color: #34a853; }

/* -------------------------------------------------------- 15. werkgebied */

.area-cols { display: grid; gap: 16px; }
@media (min-width: 760px) { .area-cols { grid-template-columns: 1.1fr .9fr; gap: 24px; } }

.area-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.area-list li {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 9px 0; border-bottom: 1px solid var(--line); font-size: .9375rem;
}
.area-list li:last-child { border-bottom: 0; }
.area-list .a-name { font-weight: 600; color: var(--ink); }
.area-list .a-note { font-size: .8125rem; color: var(--ink-3); white-space: nowrap; }

.area-badge {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: .8125rem; font-weight: 700; padding: 5px 12px;
  border-radius: 999px; margin-bottom: 12px;
}
/* Zonder deze regel valt het icoon terug op `img, svg { max-width: 100%;
   height: auto }` en rekt het zich uit tot wat er in de chip aan breedte over
   is. Op 1440px leek dat nog een groot vinkje; op 390px brak de chip in drie
   regels met een vierkant blok ernaast. Elk ander icoongebruik in deze
   stylesheet heeft zo'n maatregel — deze was de enige zonder. */
.area-badge svg { width: 15px; height: 15px; flex: none; }
.area-badge.direct  { background: var(--green-100); color: var(--green-900); }
.area-badge.aanvraag{ background: var(--sand); color: var(--ink-2); border: 1px solid var(--line-2); }

/* Rustige schematische kaart — geen ingesloten Google Map, geen extern verzoek */
/* Het compacte werkgebiedblok op de homepage (12A.4). Eén kolom, geen kaart,
   geen postcodecatalogus: vijf herkenbare namen en een link. */
.werkgebied-kort { max-width: 640px; }
.wg-plaatsen {
  margin: 16px 0 0; font-size: .9375rem; color: var(--ink-2); font-weight: 600;
}

.map-schematic {
  aspect-ratio: 4 / 3; width: 100%;
  background: var(--green-50); border: 1px solid var(--green-100);
  border-radius: var(--radius-lg); overflow: hidden;
}

/* ---------------------------------------------------------------- 16. FAQ */

.faq-list { border-top: 1px solid var(--line); }
.faq-item { border-bottom: 1px solid var(--line); }
.faq-item summary {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
  padding: 18px 0; min-height: var(--tap);
  cursor: pointer; list-style: none;
  font-weight: 700; color: var(--ink); font-size: 1.0625rem;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
  content: "+"; flex: none; font-size: 1.5rem; font-weight: 400;
  color: var(--green-700); line-height: 1; margin-top: -2px;
  transition: transform .15s;
}
.faq-item[open] summary::after { content: "−"; }
.faq-item summary:hover { color: var(--green-700); }
.faq-answer { padding: 0 0 20px; max-width: 68ch; }
.faq-answer p { font-size: .9375rem; margin-bottom: .75em; }
.faq-answer p:last-child { margin-bottom: 0; }

.faq-group + .faq-group { margin-top: 36px; }
.faq-group h2 { font-size: 1.25rem; margin-bottom: 4px; }

/* ------------------------------------------------------- 17. eind-CTA */

.cta-band { background: var(--green-900); color: var(--ink-on-dark); }
.cta-grid { display: grid; gap: 28px; }
@media (min-width: 900px) { .cta-grid { grid-template-columns: 1fr 420px; gap: 48px; align-items: center; } }
.cta-band h2 { color: #fff; }
.cta-band .lead { color: var(--green-100); }

/* De rustige afsluiting (12A.4): kop, één zin, één knop, één tekstlink. Staat op
   de homepage, waar de adrescheck al boven de vouw in de hero staat en een
   tweede formulier met dezelfde velden alleen maar verwarring toevoegt. */
.cta-rustig { text-align: center; }
.cta-rustig .wrap { max-width: 640px; }
.cta-rustig h2 { margin-bottom: 10px; }
.cta-rustig .lead { margin-bottom: 26px; }
.cta-rustig .cta-alt { margin: 18px 0 0; font-size: .9375rem; color: var(--green-100); }
.cta-rustig .cta-alt a { color: #fff; text-decoration: underline; text-underline-offset: 3px; }

.alt-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 20px; }
.alt-actions a {
  display: inline-flex; align-items: center; gap: 8px; min-height: var(--tap);
  padding: 8px 16px; border-radius: 999px;
  border: 1px solid rgba(255,255,255,.28); color: #fff;
  text-decoration: none; font-size: .9375rem; font-weight: 600;
}
.alt-actions a:hover { border-color: #fff; background: rgba(255,255,255,.08); color: #fff; }
.alt-actions svg { width: 18px; height: 18px; }

/* ------------------------------------------------------------- 18. footer */

.site-footer { background: var(--green-900); color: var(--green-100); padding-block: 48px 32px; }
/* De kolomkoppen van de voet. Zij zijn de bovenste koppen binnen het
   footer-landmark en dragen sinds 12A.4 `h2` in plaats van `h4`: onder een
   `h2` uit de inhoud was dat op elke pagina een overgeslagen niveau. De
   opmaak verandert niet; die hing al aan deze regel. */
/* De klasse `.f-kop` komt in de uitvoer niet voor. `templates/site/footer.php` en
   `footer-lp.php` renderen kale `<h2>`'s, en die vielen dus terug op de
   elementregel uit blok 2: `h1, h2, h3, h4 { color: var(--ink) }`.

   Dat is `--ink` (#111827) op `--green-900` (#0e1f14) — een contrast van
   ongeveer 1,2:1. De vier kolomkoppen van de voet waren op elke pagina van de
   site letterlijk onleesbaar, en op de screenshot van 1440px zag je precies
   niets waar "Energielabel", "Werkgebied", "LabelLogisch" en "Contact" horen te
   staan.

   Exact dezelfde fout als bij de nadruk op een donker vlak, die onderaan dit
   bestand met naam en toenaam staat, en dezelfde soort als de zes van 12B.9: de
   markup is vernieuwd en de opmaak bleef op de oude haak zitten. Alleen ging het
   hier niet om een maat maar om leesbaarheid.

   Het element staat er nu naast in plaats van dat de template een klasse krijgt:
   elke kop in dit donkere vlak hoort licht te zijn, ook de volgende die iemand
   erbij zet. `.f-kop` blijft staan voor het geval de klasse ooit alsnog komt. */
.site-footer .f-kop,
.site-footer h2,
.site-footer h3 { color: #fff; font-size: .8125rem; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; margin: 0 0 14px; line-height: 1.3; }
.site-footer a { color: var(--green-100); text-decoration: none; }
.site-footer a:hover { color: #fff; text-decoration: underline; }

.footer-grid { display: grid; gap: 32px; }
@media (min-width: 640px) { .footer-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1120px) { .footer-grid { grid-template-columns: 1.5fr 1fr 1fr 1fr; gap: 40px; } }

/* `align-content: start` is hier geen smaakje maar de reparatie van de voet.
   De vier kolommen zijn grid-items van `.footer-grid` en worden dus even hoog
   als de langste (Werkgebied, met alle plaatsen erin). Elke kolom is zelf óók
   een grid, en een grid met auto-rijen rekt zijn rijen uit wanneer de container
   hoger is dan de inhoud. Bij "Contact" en "LabelLogisch" — drie links — werd de
   ruimte die de langste kolom overhoudt netjes verdeeld over de kop en de
   regels: tientallen pixels lucht onder "Contact" en tussen elke link, terwijl
   de lange kolommen ernaast strak op 4px stonden. Met `start` pakken de rijen
   naar boven en houdt alleen de kolom onderaan ruimte over, zoals het hoort. */
.footer-links { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px;
  align-content: start; }
.footer-links a { display: inline-flex; align-items: center; min-height: 34px; font-size: .9375rem; }

/* `.footer-brand` is in de voettemplate een `<p>` met de bedrijfsregel erin en
   geen omhulsel met een `.logo` erbinnen; de twee regels die dat veronderstelden
   raakten niets. Wat overblijft is de regel die er wél toe doet. */
.footer-brand { font-size: .9375rem; color: var(--green-100); max-width: 42ch; }

.footer-meta {
  margin-top: 36px; padding-top: 22px;
  border-top: 1px solid rgba(255,255,255,.14);
  display: flex; flex-wrap: wrap; gap: 8px 20px;
  font-size: .8125rem; color: var(--green-200);
}
/* De juridische links in de slotregel staan náást elkaar, niet onder elkaar.
   `.footer-links` is een kolomgrid — terecht in de vier kolommen erboven, maar
   hier gaat het om drie korte links achter de bedrijfsregel. Flex met wrap in
   plaats van het grid: op een smal scherm breken ze alsnog netjes af. */
.footer-meta .footer-links { display: flex; flex-wrap: wrap; gap: 0 20px; }

.footer-meta .admin-link { margin-left: auto; opacity: .55; font-size: .75rem; }

/* ------------------------------------------------- 19. de boekingsflow */

.booking-shell { padding-block: 24px 40px; }
@media (min-width: 900px) { .booking-shell { padding-block: 32px 64px; } }

.booking-step { background: #fff; border: 1px solid var(--line); border-radius: var(--radius-lg); padding: 22px; }
@media (min-width: 900px) { .booking-step { padding: 32px; } }
.booking-step h2 { font-size: clamp(1.25rem, 1.1rem + .6vw, 1.6rem); margin-bottom: 6px; }
.booking-step > .lead { font-size: 1rem; margin-bottom: 24px; }

.booking-nav {
  display: flex; flex-wrap: wrap; gap: 12px; align-items: center;
  margin-top: 28px; padding-top: 22px; border-top: 1px solid var(--line);
}
.booking-nav .btn-primary { margin-left: auto; }
@media (max-width: 479px) {
  .booking-nav { flex-direction: column-reverse; align-items: stretch; }
  .booking-nav .btn { width: 100%; margin-left: 0; }
}

/* Laadtoestand */
.is-loading { position: relative; pointer-events: none; }
.spinner {
  width: 18px; height: 18px; border-radius: 50%; flex: none;
  border: 2.5px solid rgba(17,33,26,.2); border-top-color: var(--ink);
  animation: spin .7s linear infinite;
}
.btn-light .spinner, .btn-primary .spinner { border-color: rgba(17,33,26,.25); border-top-color: var(--ink); }
@keyframes spin { to { transform: rotate(360deg); } }

.skeleton {
  background: linear-gradient(90deg, var(--line) 25%, var(--sand) 50%, var(--line) 75%);
  background-size: 200% 100%; animation: shimmer 1.4s infinite;
  border-radius: var(--radius-sm);
}
@keyframes shimmer { to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .skeleton { animation: none; background: var(--line); } }

/* Succesbevestiging */
.success-mark {
  width: 64px; height: 64px; border-radius: 50%;
  background: var(--green-100); color: var(--green-700);
  display: grid; place-items: center; margin-bottom: 20px;
}
.success-mark svg { width: 32px; height: 32px; }

.detail-card {
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  background: #fff; overflow: hidden;
}
.detail-card .dc-head {
  background: var(--green-50); padding: 14px 20px;
  border-bottom: 1px solid var(--line); font-weight: 700; color: var(--ink);
  font-size: .9375rem;
}
.detail-card dl { margin: 0; padding: 6px 20px 16px; }

/* -------------------------------------------------- 20. energielabelschaal */

/* Subtiel technisch element: de labelletters als rustige, correcte schaal.
   Geen sierpaneel — het is het product waar de bezoeker voor komt. */
.label-scale { display: grid; gap: 3px; }
.label-row {
  display: grid; grid-template-columns: 52px 1fr; align-items: center; gap: 10px;
}
.label-chip {
  height: 26px; border-radius: 4px 12px 12px 4px;
  display: grid; place-items: center;
  font-size: .8125rem; font-weight: 800; color: #fff;
}
.label-bar { height: 8px; border-radius: 4px; background: var(--line); }
.label-note { font-size: .8125rem; color: var(--ink-3); }

/* ------------------------------------------------------- 21. diversen */

.divider { height: 1px; background: var(--line); border: 0; margin: 0; }

.tag-row { display: flex; flex-wrap: wrap; gap: 8px; }
.tag {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px; border-radius: 999px;
  background: #fff; border: 1px solid var(--line);
  font-size: .8125rem; font-weight: 600; color: var(--ink-2);
}
.tag svg { width: 15px; height: 15px; color: var(--green-600); }

.kv-list { margin: 0; display: grid; gap: 0; }
.kv-list > div {
  display: flex; flex-wrap: wrap; gap: 4px 16px; justify-content: space-between;
  padding: 11px 0; border-bottom: 1px solid var(--line); font-size: .9375rem;
}
.kv-list > div:last-child { border-bottom: 0; }
.kv-list dt { color: var(--ink-3); }
.kv-list dd { margin: 0; font-weight: 600; color: var(--ink); text-align: right; }

/* Brede inhoud mag nooit de pagina laten schuiven — hij schuift in zichzelf */
.scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; }

.prose { max-width: 68ch; }
.prose h2 { margin-top: 2em; }
.prose h2:first-child { margin-top: 0; }
.prose h3 { margin-top: 1.6em; }
.prose ul, .prose ol { padding-left: 1.25em; margin: 0 0 1em; }
.prose li { margin-bottom: .4em; }
.prose li::marker { color: var(--green-600); }

/* De cookiebanner — geen wall, wegklikbaar, twee even zware keuzes.
   Mobiel plakt hij ónderaan (niet 88px erboven: de actiebalk is dan verborgen)
   en is hij zo laag mogelijk.

   12A.4 — hij was op 390px ongeveer 250px hoog: drie regels tekst plus een
   knoppenrij, boven op een scherm waar de adrescheck en de vaste actiebalk al om
   ruimte vechten. Twee ingrepen: de tekst is teruggebracht tot twee regels op
   normale mobiele breedte (zie `render_cookiebar()`), en de knoppen staan op één
   rij mét de tekst zodra daar ruimte voor is. Op 390px blijft hij eronder — daar
   is een knop van halve breedte al krap. */
.cookiebar {
  position: fixed; z-index: 70; left: 0; right: 0;
  bottom: 0; padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
  background: #fff; border-top: 1px solid var(--line-2);
  box-shadow: 0 -6px 24px rgba(17, 33, 26, .14);
  display: grid; gap: 10px;
}
@media (min-width: 480px) {
  .cookiebar { grid-template-columns: 1fr auto; align-items: center; gap: 16px; }
}
@media (min-width: 640px) {
  .cookiebar {
    left: auto; right: 16px; bottom: 16px; max-width: 420px;
    grid-template-columns: 1fr;
    border: 1px solid var(--line-2); border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg); padding: 18px;
  }
}
.cookiebar-text { font-size: .8125rem; line-height: 1.45; color: var(--ink-2); margin: 0; }
@media (min-width: 640px) { .cookiebar-text { font-size: .875rem; } }
/* De link naar het cookiebeleid moet als link te herkennen zijn, ook binnen een
   alinea van 13px: onderstreept en in de merkkleur, niet alleen in kleur. */
.cookiebar-text a { font-weight: 600; text-decoration: underline; }
.cookiebar-acties { display: flex; gap: 10px; }
/* Accepteren en weigeren zijn even breed en even goed leesbaar. Sinds 12A.4
   is "Accepteren" groen en niet meer geel: geel is op deze site de kleur van dé
   primaire actie, en op elk scherm waar de banner staat is dat de adrescheck.
   Twee gele knoppen naast elkaar maakten van de cookiekeuze de hoofdhandeling.
   Het verschil tussen de twee knoppen blijft even groot — alleen niet meer in
   de kleur die de conversie draagt. */
.cookiebar-acties .btn { flex: 1 1 0; min-width: 0; white-space: nowrap; }
@media (min-width: 480px) { .cookiebar-acties .btn { flex: 0 0 auto; } }
@media (min-width: 640px) { .cookiebar-acties .btn { flex: 1 1 0; } }

/* Prototypebalk — maakt op elk scherm zichtbaar dat dit geen productie is.

   12A.4 — hij was op 390px twee regels hoog (circa 56px) en stond met dezelfde
   volle breedte en hetzelfde gewicht boven de echte header, waardoor hij in elke
   beoordeling van "de eerste viewport" meetelde terwijl hij niet bij de site
   hoort. Nu: één regel, kleiner, gedempt, met een duidelijke scheiding eronder.
   Verwijderen blijft één keuze — de `<div class="proto-bar">` in
   `render_head()` weghalen. */
.proto-bar {
  background: var(--ink); color: rgba(255,255,255,.72);
  font-size: .6875rem; letter-spacing: .01em;
  padding: 5px 0; text-align: center;
  border-bottom: 2px solid var(--amber-700);
}
.proto-bar .wrap {
  display: flex; align-items: center; justify-content: center;
  gap: 8px; flex-wrap: wrap; line-height: 1.35;
}
.proto-bar strong { color: #fff; font-weight: 700; }
.proto-bar a { color: var(--green-300); font-weight: 700; }
/* Onder 560px is de toelichting weg: de balk zegt dan alleen nog wát dit is en
   waar de toestanden staan. */
.proto-bar span { display: none; }
@media (min-width: 560px) { .proto-bar span { display: inline; } }

/* ==========================================================================
   21. De boekingsflow, correctieronde 12A.1
   ========================================================================== */

.booking-title { font-size: clamp(1.35rem, 1.15rem + 0.8vw, 1.75rem); margin-bottom: 18px; }

.fieldset-bare { border: 0; padding: 0; margin: 0 0 24px; min-width: 0; }
.fieldset-bare > legend { padding: 0; }

.choice-grid-narrow { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }

.notice-tight { margin-top: 20px; }
/* Een tweede alinea binnen een melding: `strong` is al block, dus een losse
   regel eronder heeft een eigen blokvorm nodig. */
.notice .n-body { display: block; margin-top: 6px; }

.details-summary {
  cursor: pointer; font-weight: 700; color: var(--green-700);
  min-height: var(--tap); display: flex; align-items: center;
  /* Net als bij `.faq-item summary` en `.menu-toggle > summary`: zonder deze
     regel zet de browser er zijn eigen driehoek voor. De pseudo-elementen die
     oudere WebKit nodig heeft, staan onderaan bij de herstelronde. */
  list-style: none;
}

/* ------------------------------------------------------- het BAG-paneel */

.bag-panel {
  border: 1px solid var(--line); border-left: 4px solid var(--green-600);
  border-radius: var(--radius); background: var(--sand);
  padding: 16px 18px; margin-bottom: 20px;
}
.bag-panel.bag-not_found,
.bag-panel.bag-unavailable,
.bag-panel.bag-ambiguous {
  border-left-color: var(--amber-700); background: var(--amber-50);
}
.bag-lead { font-size: 1.0625rem; line-height: 1.45; margin: 0 0 6px; color: var(--ink); }
.bag-meta { font-size: .875rem; color: var(--ink-3); margin: 0 0 10px; }
.bag-panel .muted { margin: 0 0 10px; }
.bag-bron { font-size: .75rem; color: var(--ink-3); margin: 10px 0 0; }

.bag-kandidaten { list-style: none; padding: 0; margin: 12px 0 0; }
.bag-kandidaten li {
  display: flex; flex-wrap: wrap; gap: 4px 14px; justify-content: space-between;
  padding: 8px 0; border-bottom: 1px solid var(--line); font-size: .875rem;
}
.bag-kandidaten li:last-child { border-bottom: 0; }
.bag-kandidaten .k-naam { font-weight: 600; }
.bag-kandidaten .k-opp { color: var(--ink-3); }

/* "Klopt dit niet? Oppervlakte corrigeren" — rustig, en nooit de hoofdactie. */
.bag-correct { margin-bottom: 20px; }
.bag-correct > summary {
  cursor: pointer; font-weight: 700; color: var(--green-700);
  min-height: var(--tap); display: flex; align-items: center;
}
.bag-correct-body { padding-top: 12px; }
.bag-correct-body .muted { margin-bottom: 12px; }
.field-m2 { max-width: 320px; }

/* ------------------------------------- velden die alleen soms relevant zijn */

/*
   Particulier/zakelijk, afwijkende contactpersoon en afwijkend factuuradres.

   Zonder JavaScript, dus zonder de CSP te verruimen: `:has()` op de omhullende
   fieldset leest welke radio aanstaat. Het `@supports`-blok is de reden dat dit
   veilig is — een browser zonder `:has()` past de `display: none` nooit toe en
   toont dus gewoon alle velden. Degraderen naar "alles zichtbaar" is precies de
   goede kant op: niemand raakt een veld kwijt dat hij moet invullen.
*/
.reveal { padding-top: 4px; }
.reveal-kop {
  font-size: .875rem; font-weight: 700; color: var(--ink);
  margin: 20px 0 10px; padding-top: 16px; border-top: 1px solid var(--line);
}
.reveal > .reveal-kop:first-child { margin-top: 4px; }

@supports selector(:has(*)) {
  .reveal-host .reveal { display: none; }
  .reveal-host:has(input[value="zakelijk"]:checked) .reveal[data-reveal="zakelijk"],
  .reveal-host:has(input[name="toegang_zelfde"][value="nee"]:checked) .reveal[data-reveal="nee"],
  .reveal-host:has(input[name="factuur_afwijkend"][value="ja"]:checked) .reveal[data-reveal="ja"] {
    display: block;
  }
}

/* -------------------------------------------------- akkoord en juridisch */

.akkoord-kop { font-size: 1.0625rem; margin: 28px 0 4px; }
.akkoord-kop + .muted { margin-bottom: 14px; }
.check + .check { margin-top: 10px; }
/* De privacytekst onderin de boekingskaart. Lopende tekst achter een
   scheidslijn: het hoort bij de pagina, niet bij de knop. Kleiner dan de stap
   erboven, zodat de kop niet leest als een negende stap. */
.gegevensnoot {
  margin-top: 24px; padding-top: 20px; border-top: 1px solid var(--line);
  color: var(--ink-2); font-size: .875rem; line-height: 1.6;
}
.gegevensnoot h3 { font-size: .9375rem; margin: 0 0 6px; color: var(--ink); }
.gegevensnoot p { margin: 0; max-width: 68ch; }

.check.is-locked { opacity: .75; cursor: not-allowed; background: var(--sand); }
.check.is-locked input { cursor: not-allowed; }

/* Het juridische blok op stap 7.

   Hier stond een tweede `.legal-block` — een gele stippellijn op een geel vlak —
   die volledig werd overschreven door de definitie verderop in dit bestand (het
   rustige zandvlak bij "de akkoordblokken op stap 7"). Twee regels met dezelfde
   naam en dezelfde specificiteit: de laatste won, en dat was al jaren de zandkaart.

   Alleen `color` en `display` van `.legal-kop` overleefden die botsing, en dat is
   waarom de kop van het akkoordblok geelbruin was terwijl niets eromheen dat is.
   De dode regel is weg; de kop staat nu in gewone inkt. Instemming vragen is geen
   waarschuwing — een afgekeurd vinkje is dat wel, en dat is `.check.has-error`. */
.legal-kop {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  font-weight: 800; color: var(--ink); margin: 0 0 8px;
}
.legal-kop svg { width: 20px; height: 20px; flex: none; color: var(--green-700); }
.legal-block .muted { margin-bottom: 12px; }

/* ------------------------------------------------------- prijs op stap 3 */

.price-card-step { padding: 24px; }
.price-card-step .eyebrow { color: var(--green-300); }
.price-basis { color: var(--green-100); font-size: .9375rem; margin: 10px 0 0; }

/* De terugknop is een submit ín het formulier; hij mag nooit de plek van de
   hoofdactie innemen. */
.booking-nav [name="terug"] { margin-right: auto; }
@media (max-width: 479px) { .booking-nav [name="terug"] { margin-right: 0; } }

/* De regio-uitslag hoort visueel bij stap 1 en niet bij het formulier erboven. */
.region-result {
  margin-top: 24px; padding-top: 22px; border-top: 1px solid var(--line);
}
.region-result:focus { outline: var(--ll-focus-width) solid var(--ll-focus); outline-offset: 4px; }
.region-next { margin-top: 18px; }

.success-mark-warn { background: var(--amber-50); color: var(--amber-700); }
.success-mark-error { background: var(--danger-bg); color: var(--danger); }

/* Een fieldset-legenda in de boekingsflow is een sectiekop, net als
   `.reveal-kop`. Zonder deze scheiding plakt "Wie verleent toegang tot de
   woning?" tegen het veld erboven en lijkt het een bijschrift daarvan. */
.booking-step .fieldset-bare:not(:first-of-type) > legend.field-label {
  margin-top: 20px; padding-top: 16px;
  border-top: 1px solid var(--line); width: 100%;
}

/* ------------------------------------- 22. de advertentielandingspagina */

/* De landingsschil is geen tweede designsysteem. Alles hieronder is een
   uitzondering op de gewone schil, en er zijn er precies vijf: een balk zonder
   navigatie, een vanafprijs die op licht moet werken, drie punten onder elkaar,
   en een voet van twee kolommen in plaats van vier. */

/* Zonder navigatie duwt `justify-content` het logo en de acties uit elkaar; dat
   gebeurt al door `.header-inner`. Wat hier moet, is dat de balk niet
   onbedoeld hoger wordt dan de gewone. */
.site-header.is-lp .header-inner { gap: 12px; }

/* Het telefoonnummer voluit is op een landingspagina een tweede conversie en
   geen decoratie. Onder 420px is er geen ruimte voor de cijfers naast het logo;
   het icoon blijft dan staan en de knop houdt zijn aanraakmaat. */
.lp-bel span { display: none; }
@media (min-width: 420px) { .lp-bel span { display: inline; } }

.lp-hero { padding-bottom: 32px; }

/* Dezelfde opbouw als `.price-headline`, maar op een lichte ondergrond: daar is
   wit onleesbaar en amber te zwak voor een bedrag van deze grootte. */
.lp-vanaf {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 10px;
  margin: 18px 0 0;
}
.lp-vanaf .p-big {
  font-size: clamp(2rem, 1.5rem + 2.2vw, 2.75rem); font-weight: 800;
  color: var(--ink); letter-spacing: -.03em; line-height: 1;
}
.lp-vanaf .p-from { font-size: .9375rem; font-weight: 700; color: var(--green-700); }

/* Drie punten, niet vier: in één kolom lezen ze als een opsomming, in twee
   kolommen als een raster waarin er één ontbreekt. */
.lp-punten { margin-top: 20px; }
@media (min-width: 560px) { .lp-punten { grid-template-columns: 1fr; } }

.site-footer.is-lp { padding-block: 40px 28px; }
.lp-foot { display: grid; gap: 28px; }
@media (min-width: 640px) { .lp-foot { grid-template-columns: 1.4fr 1fr; gap: 40px; } }
.lp-foot p { font-size: .9375rem; color: var(--green-100); max-width: 46ch; }
.lp-foot .logo { color: #fff; }
.lp-foot .logo span b { color: var(--green-300); }

/* De alternatieve acties onder de adrescheck in de hero. Een regel en geen
   knoppenrij: zie de toelichting in `pages/home.php`. */
.hero-alt { margin-top: 20px; max-width: 46ch; }
.hero-alt a { color: var(--green-700); font-weight: 600; }

/* Het kader om elke foto. Een `<figure>` krijgt van de browser `margin: 1em 40px`,
   en die 40px maakt in een rooster van de foto stilletjes de smalste kolom. */
.foto-figuur { margin: 0; }

/* De drie praktijkfoto's op `/over-label-logisch/`. De bronnen zijn drie
   verschillende verhoudingen (800×1965, 1400×1965 en 900×993); zonder één vaste
   verhouding worden het drie ongelijke kolommen. Uitsnede iets boven het midden:
   op alle drie staat de handeling in de bovenhelft. */
.werk-foto {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover; object-position: 50% 35%;
  border-radius: var(--radius-lg); background: var(--sand-2);
}

/* ── Tekst met een beeld ernaast ───────────────────────────────────────────

   De werkfoto op `/over-label-logisch/` stond in een eigen sectie over de volle
   breedte van de leeskolom. Gemeten op 1440×900: **1176 × 882 px, oftewel 98 %
   van de schermhoogte**. Je scrolde van een blok tekst een volledig scherm foto
   in en daarna weer een blok tekst uit — één beeld dat de pagina in tweeën
   knipt. Op 768 was het 728 × 546.

   Hij staat nu naast de tekst die hij illustreert. In een zijkolom van 360 px is
   "kleiner" geen aparte maatregel meer maar een gevolg van waar hij staat.

   ── De uitsnede kantelt mee, en alleen hier ───────────────────────────────

   De bron is staand (1400 × 1965) en `.werk-foto` snijdt hem liggend af op 4:3.
   Dat klopt over de volle breedte, maar in een smalle kolom naast tekst levert
   het een streepje van 360 × 270 op naast een tekstblok dat drie keer zo hoog
   is. Daarom kantelt de verhouding hier mee naar 3:4 — dezelfde richting als de
   bron, dus de uitsnede gooit ook minder weg: 360 × 480, en dat staat naast een
   lijst van vier punten met een alinea eronder.

   `object-position` blijft op 35 %: de handeling — de tablet, de handen, de
   gevel erachter — zit in de bovenhelft van het beeld, en dat is bij beide
   verhoudingen zo.

   ── Onder 900 px gebeurt er niets ─────────────────────────────────────────

   Daar is er geen tweede kolom, stapelt het beeld onder de tekst en houdt het de
   liggende 4:3. Dat is met opzet: op 390 px is dat 350 × 263 px, en een staande
   uitsnede zou de foto daar juist gróter maken — het omgekeerde van wat deze
   regel moet doen.

   Wél begrensd is de breedte in de gestapelde stand. Zonder die grens werd het
   beeld op 768 px nog steeds 728 × 546, want daar is er nog geen tweede kolom
   en vult hij de hele leeskolom. 480 px is de maat waarop hij als beeld bij een
   tekst leest en niet als band dwars door de pagina; op 390 px raakt de grens
   niets, want daar is de kolom zelf al smaller. */
.tekst-foto { display: grid; gap: var(--ruimte-klein); align-items: start; }

@media (max-width: 899px) {
  .tekst-foto .foto-figuur { max-width: 480px; }
}

@media (min-width: 900px) {
  .tekst-foto { grid-template-columns: minmax(0, 1fr) minmax(0, 360px); gap: 40px; }
  .tekst-foto .werk-foto { aspect-ratio: 3 / 4; }
}

/* Hier stonden `.grid-foto` en `.floor-foto`: het tekst-naast-fotorooster dat de
   homepage en `/over-label-logisch/` elk apart opbouwden. Beide pagina's
   gebruiken sinds de Ochtendlicht-ronde `site/partials/persoon`, dat dat rooster
   één keer definieert (`.persoon`). Nagelopen met `grep` op `class="…"` over
   `templates/`: geen enkele template voert ze nog. */

/* ══════════════════════════════════════════════════════════════════════════
   Fase 12B.2 — de echte boekingsflow

   Het prototype loste drie dingen met een `style`-attribuut op: de breedte van
   de voortgangsbalk, de marges rond de regio-uitslag en het verbergen van het
   lokaasveld. Dat kan hier niet: de publieke CSP staat `style-src 'self'`
   zonder `'unsafe-inline'`, en een routetest bewaakt dat er geen enkel
   `style`-attribuut in de uitvoer staat. Vandaar deze acht klassen.
   ══════════════════════════════════════════════════════════════════════════ */

/* Het honeypot-veld. Buiten beeld gehaald met absolute positionering en niet
   met `display:none`: een deel van de formulierbots slaat verborgen velden
   over, en juist die wil je laten invullen. `aria-hidden` en `tabindex="-1"`
   in de markup houden hem weg bij een schermlezer en het toetsenbord. */
.hp-veld {
  position: absolute; left: -9999px; width: 1px; height: 1px;
  overflow: hidden;
}

/* De regio-uitslag onder stap 1, en de losse blokken binnen een stap. */
.region-result { margin-top: 24px; }
.blok-ruimte { margin-top: 20px; }
.blok-ruimte-klein { margin-top: 12px; }

/* De akkoordblokken op stap 7. */
.akkoord-kop { margin-top: 28px; margin-bottom: 6px; font-size: 1.0625rem; }
.check + .check { margin-top: 10px; }
.legal-block {
  margin-top: 20px; padding: 16px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--sand);
}
.legal-kop { font-weight: 700; margin: 0 0 8px; }

/* De dagkolommen op stap 5: per dag een kop met daaronder zijn tijden. */
.dag-blok + .dag-blok { margin-top: 20px; }
.dag-kop { font-size: .9375rem; font-weight: 700; margin: 0 0 8px; color: var(--ink); }
.dag-leeg { font-size: .875rem; color: var(--ink-3); margin: 0; }

/* De vensternavigatie boven de dagen. */
.venster-nav { display: flex; justify-content: space-between; gap: 12px; margin-bottom: 18px; }

/* ──────────────────────────────────────────────────────────────────────────
   Fase 12B.9 — de mobiele header liep 86 px over

   Gevonden met de eerste echte browsermatrix; 12B.1 is uitsluitend met `curl`
   gecontroleerd en een `scrollWidth` meet je niet met `curl`.

   De regel bij `.header-actions .icon-btn:not(.menu-toggle)` hierboven mikt op
   een klasse die de **productie**header niet rendert: die zet een tekstknop met
   het telefoonnummer (`.btn-sm`) naast de CTA, waar het prototype een icoonknop
   had. De mobiele uitzondering greep daardoor nergens op aan, en onder 640 px
   pasten logo + telefoonnummer + CTA + Menu niet naast elkaar.

   De telefoonknop gaat eruit en niet de CTA — dezelfde afweging als in de regel
   hierboven. Het nummer blijft bereikbaar in het mobiele menu, in de voet en op
   elke contactsectie.

   ── `.btn-ghost.btn-sm` en niet elke `.btn-sm` ────────────────────────────

   De selector mikte op `.btn-sm`, en dat was zolang de telefoonknop de enige
   kleine knop in de balk was hetzelfde. Sinds de compacte CTA erbij staat is dat
   niet meer zo: die draagt `.btn-primary.btn-sm` en zou door de oude selector
   precies onder 640px verdwijnen — het bereik waarvoor hij gemaakt is. De regel
   benoemt daarom nu wát er weg moet, en niet welke maat het toevallig heeft.
   ────────────────────────────────────────────────────────────────────────── */
@media (max-width: 639px) {
  .site-header .header-actions .btn-ghost.btn-sm { display: none; }
}

/* De verzendknop van het adrescheckblok stond in kolom 2 van een raster van
   twee, en `.btn` staat op `white-space: nowrap`. "Bekijk prijs en
   beschikbaarheid" heeft daardoor een min-content-breedte van 289 px, en die
   duwde de hele pagina op 390 px 103 px breed — óók op de vier plaatspagina's
   en de vier Ads-pagina's.

   Hij loopt nu over de volle breedte en mag afbreken. Dat is bovendien de
   betere vorm: de primaire actie van de hele site hoort niet in een halve
   kolom te staan. Gemeten met de browsermatrix van 12B.9, niet geschat.

   ── De vorm en de hover ──────────────────────────────────────────────────

   Deze knop is het enige rechthoekige element in een site vol pilvormen, en
   dat is opzet. Hij staat in hetzelfde raster als de drie invoervelden en
   direct eronder; `.input` draagt `--radius-sm`, en een pil onder drie
   rechthoeken las als iets wat toevallig in het kader beland was in plaats van
   als de sluitregel van het formulier. Dezelfde straal maakt er één blok van.
   De rest van de site houdt de pil — dit is geen nieuwe knopvorm voor overal.

   De hoverstand doet er twee dingen bij boven op de kleursprong die
   `.btn-primary:hover` al maakt: de knop komt een pixel omhoog en zijn schaduw
   wordt dieper. Op het donkergroene paneel is een tintverschil tussen wit en
   `--green-50` namelijk nauwelijks te zien; daar draagt een lichte ring de
   boodschap. Bij `:active` valt hij terug op zijn plek, zodat de klik voelbaar
   is. Wie beweging heeft uitgezet, houdt de schaduw en de kleur — die zeggen
   hetzelfde zonder de sprong. */
.postcheck-fields > button {
  grid-column: 1 / -1;
  white-space: normal;
  border-radius: var(--radius-sm);
  transition: background-color .15s, border-color .15s, color .15s,
              transform .15s, box-shadow .15s;
}
.postcheck-fields > button:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow);
}
.postcheck-fields > button:active {
  transform: translateY(1px);
  box-shadow: var(--shadow-sm);
}
.paneel-kaart .postcheck-fields > button:hover {
  box-shadow: 0 0 0 3px rgba(255, 255, 255, .28), var(--shadow);
}
@media (prefers-reduced-motion: reduce) {
  .postcheck-fields > button:hover,
  .postcheck-fields > button:active { transform: none; }
}

/* Het mobiele menu opende niet — gevonden met de browsermatrix van 12B.9.

   `.mobile-menu.is-open` hierboven komt uit het prototype, waar JavaScript die
   klasse zette. De productieheader gebruikt een `<details>` (progressieve
   verbetering: hij klapt zonder JavaScript open) en er is niets dat `is-open`
   toevoegt — `site.js` raakt de klasse niet aan. Het menu klapte dus wél open
   als element, maar bleef `display: none`.

   Dit is dezelfde soort fout als de telefoonknop hierboven: 12B.1 heeft de
   templates op het bestaande klassevocabulaire afgebeeld, en twee regels bleven
   op de oude haak zitten. Met `curl` is geen van beide te zien.

   De `.is-open`-regel blijft staan voor het geval er ooit alsnog een
   JavaScript-variant komt. */
.menu-toggle[open] .mobile-menu {
  display: block;
  /* Een uitklap ONDER de header en over de volle breedte — precies wat de
     toelichting bij `.mobile-menu` hierboven beschrijft. Zonder deze regel
     rendert het menu binnen de flexrij van `.header-inner`, want de productie-
     header nest het in een `<details>` die zelf een flexitem is. Het duwde de
     pagina dan 114px breed op een scherm van 390. `.site-header` is `sticky` en
     is daarmee al het containing block. */
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  padding-inline: 20px;
  box-shadow: var(--shadow-sm);
  max-height: calc(100vh - var(--header-h));
  overflow-y: auto;
}
@media (min-width: 900px) { .menu-toggle[open] .mobile-menu { padding-inline: 32px; } }
@media (min-width: 1100px) { .menu-toggle[open] .mobile-menu { display: none; } }

/* De lijst zelf: geen opsommingstekens en geen UA-inspringing van 40px. */
.mobile-menu ul { list-style: none; margin: 0; padding: 0; }

/* Twee lijsten die op de UA-standaard terugvielen — bolletjes en 40px
   inspringing — omdat de klasse waar de opmaak aan hangt niet is wat de
   productietemplates renderen. Vierde en vijfde vondst van de browsermatrix van
   12B.9, en dezelfde soort als de header en het menu.

   `.footer-links` is in de stylesheet een `<ul>`; de templates gebruiken het als
   `<div>`-omhulsel met een `<h2>` en een `<ul>` erin. De reset gold daardoor
   voor het omhulsel en niet voor de lijst.

   `.check-list` had helemaal geen regel: de templates van 12B.1 voerden die
   klassenaam in, de stylesheet kende hem niet. Hij krijgt hier dezelfde vorm als
   zijn buren (`.included`, `.trust-list`, `.area-list`). */
.footer-links ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px;
  align-content: start; }
.check-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }

/* Twee kolommen waar de lijst kort en opsommend is — "wat er in elke prijs zit"
   op de homepage. Alleen vanaf 620px: daaronder wordt een kolom smaller dan de
   langste regel en breekt elk item alsnog. */
@media (min-width: 620px) {
  .check-list-2 { grid-template-columns: 1fr 1fr; gap: 8px 24px; }
}

/* Nog drie lijstklassen die de UA-standaard kregen. `.wg-plaatsen` en
   `.lp-punten` bestáán in deze stylesheet maar zijn geschreven voor de
   prototypemarkup (een alinea, respectievelijk een raster met `<div>`s); de
   productietemplates gebruiken ze op een `<ul>` en `<ol>`, en dan ontbreekt de
   reset. `.steps-lijst` kende de stylesheet helemaal niet.

   `.lp-punten` had zelfs al een `grid-template-columns` in zijn media query —
   een raster dat nooit een raster wérd. Vandaar `display: grid` erbij.

   Zesde tot achtste vondst van de browsermatrix van 12B.9. */
.wg-plaatsen,
.lp-punten,
.steps-lijst { list-style: none; padding-left: 0; }

.lp-punten { display: grid; gap: 10px; }
.steps-lijst { display: grid; gap: 10px; margin: 16px 0 0; }

/* ==========================================================================
   Visuele herstelronde — markup die van zijn component was weggelopen
   ==========================================================================

   Dezelfde soort vondsten als de appendix hierboven van 12B.9, en met dezelfde
   methode gevonden: in de browser opgemeten, niet in de stylesheet gelezen. Wat
   ze delen is dat de templates een klassenaam voeren die deze stylesheet niet
   kent, of markup renderen waar de bestaande selector niet op past. Met `curl`
   is er geen van te zien: elke pagina geeft 200 en de stylesheet laadt.
   -------------------------------------------------------------------------- */

/* --- de menuknop -----------------------------------------------------------

   `.menu-toggle` is in de productieheader een `<details>` en niet de
   `<button class="icon-btn menu-toggle">` uit het prototype. Er stond dus geen
   enkele regel op de `<summary>`, en die viel terug op de UA-standaard: een
   `list-item` met een `disclosure-closed`-driehoekje ervoor, 28px hoog.

   Op de primaire navigatie van elk scherm onder 1100px. De regels hieronder
   maken er weer de knop van die `.icon-btn` beschrijft — inclusief de
   aanraakmaat van 44px die de opdracht als ondergrens stelt. */
.menu-toggle > summary {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: var(--tap);
  padding: 0 14px;
  border: 1px solid var(--line-2);
  border-radius: 12px;
  background: #fff;
  color: var(--ink);
  font-weight: 600;
  cursor: pointer;
  /* Twee regels voor hetzelfde: `list-style` dekt Firefox en de moderne
     Chromium's, de pseudo-elementen dekken oudere WebKit. */
  list-style: none;
}
.menu-toggle > summary::-webkit-details-marker { display: none; }
.menu-toggle > summary::marker { content: ""; }
.menu-toggle > summary:hover { border-color: var(--ink); }

/* Onder 420px is de balk 6px te smal voor logo + knop mét het woord erin —
   opgemeten op 390px, waar `.logo` 244px breed is en niet krimpt. Het woord
   gaat dan weg en de knop wordt een vierkant van 44px; `aria-label` op de
   `<summary>` houdt de toegankelijke naam overeind. Dezelfde ingreep als bij
   `.flow-bel span` hierboven, op dezelfde breedte. */
.menu-woord { display: none; }
@media (min-width: 420px) { .menu-woord { display: inline; } }
.menu-toggle > summary { padding: 0; width: var(--tap); justify-content: center; }
@media (min-width: 420px) {
  .menu-toggle > summary { padding: 0 14px; width: auto; }
}

/* Het hamburgerstreepje. `.menu-streep` is een lege `<span>` in de template en
   had geen enkele regel; hij rendeerde als een inline span van 0px. Drie
   strepen uit één element, met `currentColor` zodat hij de knop volgt. */
.menu-streep {
  display: block;
  width: 18px;
  height: 2px;
  background: currentColor;
  border-radius: 2px;
  box-shadow: 0 -6px 0 currentColor, 0 6px 0 currentColor;
}

/* --- het adrescheckblok ----------------------------------------------------

   `.field-kort` bestond alleen in de template. De twee korte velden kregen
   daardoor de volle kolombreedte van het raster, en op 360px en breder stond
   "Toev." als derde veld alleen op een eigen rij.

   Drie kolommen zodra ze passen: postcode heeft ruimte nodig voor "2711 AB",
   huisnummer en toevoeging niet. Onder 480px blijven het er twee — daar past
   een derde kolom niet zonder dat het huisnummerveld smaller wordt dan zijn
   eigen inhoud. */
.field-kort { min-width: 0; }

@media (min-width: 480px) {
  .postcheck-fields { grid-template-columns: 1.6fr 1fr .8fr; }
}

/* --- de akkoordvinkjes -----------------------------------------------------

   `.check` had wel een `:hover` maar geen foutstand, terwijl de template
   `.check.has-error` zet. Een afgekeurd vinkje was daardoor op geen enkele
   manier van een goedgekeurd vinkje te onderscheiden — de melding eronder was
   het enige signaal, en die stond los.

   Rand én achtergrond, niet alleen kleur: betekenis mag nooit uitsluitend uit
   kleur komen. De rand is bovendien 1,5px zoals bij `.field.has-error`. */
.check.has-error {
  border-color: var(--danger);
  background: #fffbfb;
}
.check.has-error:hover { border-color: var(--danger); background: #fffbfb; }

/* --- de reviewkaart --------------------------------------------------------

   `.review` verwacht `.review-who`, `.review-name` en `.review-meta`; de
   template rendert een `<figure>` met een `<blockquote>` en een `<figcaption>`.
   De naamregel liep daardoor mee in de lopende tekstmaat in plaats van als
   ondertekening te lezen. */
.review figcaption {
  margin-top: auto;
  padding-top: 12px;
  font-size: .875rem;
  font-weight: 600;
  color: var(--ink-3);
}

/* --- het woordmerk ---------------------------------------------------------

   Hier stonden `.logo-naam` en `.logo-plaats`: het merk als twee spans, met
   "Zoetermeer e.o." als bijstelling eronder. Beide partials renderen sinds het
   logo-beeldmerk een `<img>` en geen spans meer, dus die regels hingen aan
   markup die niet meer bestaat. Wat overblijft is `.logo img` in blok 5 — de
   enige plek waar de maat van het merk staat, voor beide schillen tegelijk.

   Er is met opzet geen tweede woordmerkvariant: één partial, één beeld. */

/* Het merk van de Ads-schil is geen link — daar staat geen navigatie op de
   pagina. Verder is het hetzelfde merk. */
.logo-stil { cursor: default; }

/* --- de FAQ-vraag ----------------------------------------------------------

   De vraag staat als `<h3>` binnen de `<summary>`, zodat de koppenstructuur van
   de pagina klopt. Maar een `<h3>` draagt de kopregels uit blok 3: een grotere
   letter dan `.faq-item summary` voorschrijft, plus marges boven en onder. In de
   flexrij van de summary duwde dat de vraag uit het midden en zette het een
   halve regel ruimte onder elke gesloten vraag.

   `.faq-vraag` haalt die twee dingen weg. De kop blijft een kop voor de
   toegankelijkheidsboom; alleen zijn opmaak komt van de component eromheen. */
.faq-vraag {
  margin: 0;
  font-size: inherit;
  font-weight: inherit;
  line-height: inherit;
  letter-spacing: inherit;
  color: inherit;
}

/* --- de voorbereidingschecklist --------------------------------------------

   `Process::voorbereiding()` schrijft in zijn eigen docblock waar het om gaat:
   de zwaarte "zegt of een item de uitkomst beïnvloedt of alleen het bezoek
   soepeler maakt. Zonder dat onderscheid leest de lijst als twintig even
   belangrijke huiswerkopdrachten en doet niemand er iets mee."

   Precies dat gebeurde er ook: `.tag` had één neutrale vorm en de vijf
   `tag-*`-varianten hadden geen enkele regel, dus alle twintig items droegen
   hetzelfde grijze label. De onderscheidende regel stond in de PHP en niet in de
   opmaak.

   De kleur is een versterking en niet de drager: in het label staat het woord
   zelf ("nodig", "handig"), dus wie geen kleurverschil ziet, leest hetzelfde
   onderscheid gewoon in de tekst. */
.check-tekst { flex: 1 1 auto; min-width: 0; }
.check-list li { display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: baseline; }

/* Zakelijke landingspagina: minder losse tekst, duidelijkere overdracht tussen
   makelaar en adviseur. De componenten blijven binnen het bestaande palet. */
.business-callout {
  margin-bottom: clamp(36px, 6vw, 64px);
  padding: clamp(24px, 4vw, 38px);
  border-left: 4px solid var(--green-600);
  border-radius: 0 var(--radius-lg) var(--radius-lg) 0;
  background: var(--green-50);
}
.business-callout > :last-child { margin-bottom: 0; }
.business-steps { margin-bottom: clamp(36px, 6vw, 64px); }
.business-steps strong { color: var(--ink); }
.business-grid {
  display: grid;
  gap: 18px;
}
.business-grid .card { margin: 0; }
.business-grid h2 { font-size: clamp(1.25rem, 2vw, 1.55rem); }
@media (min-width: 760px) {
  .business-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Een lijst die `check-list` heet, hoorde vinkjes te hebben en had ze niet: de
   klasse zette alleen `list-style: none`, dus de opsomming verloor zijn bolletje
   zonder er iets voor terug te krijgen. Op `/tarieven/` en
   `/voorbereiden-opname/` waren "wat er in elke prijs zit" en de checklist
   daardoor niet van gewone alinea's te onderscheiden.

   Hetzelfde vinkje als `.trust-list`, en met opzet: het is dezelfde uitspraak
   ("dit zit erbij") en hoort er dus hetzelfde uit te zien. Het teken is
   decoratief — de betekenis staat in de tekst ernaast — en komt daarom uit de
   stylesheet en niet uit de HTML. */
/* Het vinkje staat absoluut en niet als flexitem in de rij.
 *
 * Als flexitem is de tekst ernaast een *anonieme* flexbox, en die kan bij
 * `flex-wrap: wrap` naar de volgende regel springen zodra de kolom smal wordt —
 * dan staat het vinkje alleen op regel één en de tekst eronder. Precies wat er
 * gebeurde in de tweekolomsvariant op de homepage.
 *
 * Absoluut gepositioneerd valt het vinkje buiten de flexstroom, en houdt de rij
 * zijn eigen indeling (op `/voorbereiden-opname/` staat er naast de tekst nog
 * een `.tag`, en die moet wél kunnen afbreken). */
.check-list > li,
.lp-punten > li { position: relative; padding-left: 26px; }

.check-list > li::before,
.lp-punten > li::before {
  content: "✓";
  position: absolute; left: 0; top: 0;
  color: var(--green-700); font-weight: 700;
}

/* Vier zwaarten, één kleurladder. Dit was geel — het zwaarste item van een
   checklist is geen waarschuwing maar een nadruk, en nadruk hoort in de
   merkkleur. Het woord staat in het label zelf, dus wie geen kleurverschil ziet
   leest hetzelfde onderscheid gewoon. */
.tag-bepaalt-het-label {
  background: var(--green-700);
  border-color: var(--green-700);
  color: #fff;
}

.tag-nodig {
  background: var(--green-100);
  border-color: var(--green-200);
  color: var(--green-900);
}

.tag-helpt-veel {
  background: var(--green-50);
  border-color: var(--green-200);
  color: var(--green-800);
}

.tag-handig,
.tag-goed-om-te-weten {
  background: var(--sand);
  border-color: var(--line);
  color: var(--ink-3);
}

/* --- nadruk op een donker vlak ---------------------------------------------

   `strong, b { color: var(--ink) }` in blok 2 is een elementregel en wint
   daarmee van de overgeërfde `color` van elk vlak eromheen. Op wit klopt dat;
   op de donkere vlakken van deze site is `--ink` (#111827) op `--green-900`
   (#0e1f14) een contrast van ongeveer 1,2:1 — de tekst is er letterlijk niet
   te lezen.

   Dat trof precies het verkeerde woord: op stap 3 van de boeking staat
   "Gebaseerd op <strong>120 m²</strong>", en dat getal is het enige op die kaart
   dat de bezoeker moet controleren.

   `inherit` en geen vaste kleur: elk donker vlak zet zijn eigen tekstkleur, en
   nadruk hoort die te volgen. Het gewicht van 700 blijft staan — dát is wat de
   nadruk draagt, en het is ook de reden dat dit geen betekenis-via-kleur is. */
.price-card strong, .price-card b,
.cta-band strong, .cta-band b,
.bg-ink strong, .bg-ink b { color: inherit; }

/* --- de uitklapper op de prijsstap -----------------------------------------

   Dezelfde vondst als bij de menuknop, op de derde `<summary>` van de site:
   `.details-summary` zette wel `display: flex` maar haalde de driehoek van de
   browser niet weg. `list-style: none` staat bij de component zelf hierboven;
   deze twee pseudo-elementen staan hier omdat ze bij de andere twee summaries
   ook hier staan. */
.details-summary::-webkit-details-marker { display: none; }
.details-summary::marker { content: ""; }

/* --------------------------------------- 23. de boekingsbevestiging

   Alleen `/boeken/bevestigd/`. De pagina hergebruikt waar het kan — `.success-mark`,
   `.tag`, `.btn`, `.arrow-link`, `.lead` — en zet hier alleen neer wat er nog niet was:
   de afspraakkaart, de tijdlijn en de twee zachte blokken eronder.

   Bewust géén `section.prose`: die zet `max-width: 68ch` op de sectie zelf, waardoor
   een `.wrap` erbinnen niet meer centreert. Op de andere pagina's valt dat niet op
   omdat de inhoud daar toch smal is; hier zou de kaart links tegen de rand plakken. */

/* Eén vlak en geen verloop met een percentagestop: dat percentage rekent over de
   hoogte van de sectie, en die hangt af van hoe lang de naam en het adres zijn.
   Op 1440px sneed de rand daardoor dwars door de afspraakkaart. */
.bev-top  {
  background: var(--green-50); padding-block: 44px 32px;
  /* `clip` en niet `hidden`: `hidden` maakt van de sectie een scrollcontainer,
     en dat breekt `position: sticky` van alles wat er ooit in belandt. */
  position: relative; overflow: clip;
}
.bev-top > .wrap { position: relative; z-index: 1; }
.bev-body { padding-block: 40px 64px; }
@media (min-width: 900px) {
  .bev-top  { padding-block: 64px 40px; }
  .bev-body { padding-block: 56px 88px; }
}

/* --- de dwarreling ---------------------------------------------------------

   Duurzaamheid als een klein gebaar, en nadrukkelijk geen confetti: acht
   blaadjes vallen één keer door de groene kop en zijn na ongeveer negen seconden
   weg. `forwards` houdt ze daarna op `opacity: 0` — ze komen niet terug bij het
   scrollen en ze draaien niet eeuwig door achter de tekst die iemand leest.

   De slinger zit in dezelfde keyframes als de val, en niet in een tweede
   animatie op een omhullend element. Twee animaties die allebei `transform`
   zetten, overschrijven elkaar; de laatste wint en de val zou verdwijnen.

   Alle afstanden in `px` via `--bev-val`, want een percentage in `translateY`
   rekent over de eigen hoogte van het blaadje (12px) en niet over de sectie. */

.bev-dwarrel {
  position: absolute; inset: 0; z-index: 0;
  pointer-events: none;
  --bev-val: 760px;
}
@media (min-width: 900px) { .bev-dwarrel { --bev-val: 880px; } }

.bev-dwarrel span {
  position: absolute; inset-block-start: 0;
  width: 12px; height: 12px;
  border-radius: 0 100% 0 100%;      /* blad, en van opzij een bloemblaadje */
  background: var(--green-200);
  opacity: 0;
  animation: bev-dwarrel 8s linear forwards;
}

/* De variatie: acht keer een eigen kolom, tempo, vertraging, maat en tint, zodat
   het geen regen van gelijke stipjes wordt.

   Kleur en maat staan hier per blaadje en niet in een `:nth-child(3n)`-regel.
   Dat was de eerste opzet, en op 1440px viel die modulo precies samen met de
   kolommen die de afspraakkaart afdekt (die loopt van ~26% tot ~74%): alle
   donkere blaadjes zaten achter de kaart en alleen de bleke waren te zien.
   Wie hieronder een kolom verschuift, moet de tinten dus opnieuw verdelen.

   `--green-100` is er helemaal uit. Op een vlak van `--green-50` is dat geen
   blaadje meer; op de screenshot las het als een stofje op het scherm. */
.bev-dwarrel span:nth-child(1) { inset-inline-start:  6%; animation-duration: 8.5s; animation-delay: .10s; width: 15px; height: 15px; background: var(--green-600); }
.bev-dwarrel span:nth-child(2) { inset-inline-start: 19%; animation-duration: 7.2s; animation-delay: 1.4s; width: 12px; height: 12px; }
.bev-dwarrel span:nth-child(3) { inset-inline-start: 31%; animation-duration: 9.4s; animation-delay: .60s; width: 10px; height: 10px; background: var(--green-700); }
.bev-dwarrel span:nth-child(4) { inset-inline-start: 45%; animation-duration: 7.8s; animation-delay: 2.3s; width: 14px; height: 14px; }
.bev-dwarrel span:nth-child(5) { inset-inline-start: 58%; animation-duration: 8.8s; animation-delay: .90s; width: 11px; height: 11px; background: var(--green-600); }
.bev-dwarrel span:nth-child(6) { inset-inline-start: 71%; animation-duration: 7.5s; animation-delay: 1.9s; width: 13px; height: 13px; }
.bev-dwarrel span:nth-child(7) { inset-inline-start: 84%; animation-duration: 9.1s; animation-delay: .35s; width: 12px; height: 12px; background: var(--green-700); }
.bev-dwarrel span:nth-child(8) { inset-inline-start: 93%; animation-duration: 8.1s; animation-delay: 2.8s; width: 15px; height: 15px; background: var(--green-600); }

@keyframes bev-dwarrel {
  0%   { opacity: 0;   transform: translate3d(0, -30px, 0) rotate(0deg); }
  9%   { opacity: .55; }
  25%  { transform: translate3d(20px, calc(var(--bev-val) * .25), 0) rotate(85deg); }
  50%  { transform: translate3d(-14px, calc(var(--bev-val) * .5), 0) rotate(185deg); }
  75%  { transform: translate3d(17px, calc(var(--bev-val) * .75), 0) rotate(280deg); }
  86%  { opacity: .3; }
  100% { opacity: 0;   transform: translate3d(-4px, var(--bev-val), 0) rotate(375deg); }
}

/* Wie beweging heeft uitgezet, krijgt hem niet alsnog stil in beeld te staan. */
@media (prefers-reduced-motion: reduce) {
  .bev-dwarrel { display: none; }
}

/* --- de succesheader --- */

.bev-header { margin-bottom: 28px; }
.bev-header .success-mark { margin-bottom: 18px; box-shadow: 0 0 0 8px rgba(22, 101, 52, .06); }
.bev-header h1 { margin: 0 0 12px; }
.bev-header .lead { margin: 0; }
.bev-header .lead strong { white-space: nowrap; }

.bev-eyebrow {
  margin: 0 0 6px;
  font-size: .875rem; font-weight: 700; letter-spacing: .02em;
  color: var(--green-700);
}

/* --- de agendaknop ---

   Staat in de kop en niet in de kaart eronder, zodat hij op een telefoon boven de
   vouw blijft; het waarom staat in de template.

   Eén kolom en geen flexrij: `.btn` draagt `white-space: nowrap`, dus zou de knop
   naast de bijzin staan, dan liep hij op 320px de kolom uit in plaats van af te
   breken. */

.bev-agenda {
  margin: 20px 0 0;
  display: grid; gap: 10px; justify-items: start;
}

/* Op de smalste schermen de volle kolombreedte: een knop die de duimzone raakt is
   daar de enige die betrouwbaar geraakt wordt. Vanaf 400px krimpt hij terug naar
   zijn eigen breedte, want een knop van 500px breed leest niet meer als een knop.

   De witte vulling van `.btn-ghost` is hier geen toeval maar de reden dat hij op
   het groene kopvlak als knop leest; een doorzichtige variant zou op `--green-50`
   in de achtergrond verdwijnen. */
.bev-agenda-knop { width: 100%; }
@media (min-width: 400px) { .bev-agenda-knop { width: auto; } }

.bev-agenda-sub {
  font-size: .8125rem; line-height: 1.5; color: var(--ink-3);
  text-wrap: pretty;
}
.bev-agenda-sub code {
  font-size: .9em; padding: 1px 5px; border-radius: 5px;
  background: #fff; color: var(--green-800);
}

/* --- de afspraakkaart ---

   Staat in de DOM direct onder de header en blijft daar op elke breedte; er is
   geen `order` nodig en dus ook geen leesvolgorde die van de bronvolgorde afwijkt. */

.bev-card {
  background: #fff;
  border: 1px solid var(--green-200);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: 20px;
  position: relative; overflow: hidden;
}
@media (min-width: 640px) { .bev-card { padding: 26px 28px; } }

/* Het decoratieve element: een liggende labelbalk in de merkkleur, half
   doorzichtig en achter de inhoud. Geen afbeelding en geen animatie. */
.bev-card::before {
  content: "";
  position: absolute; inset-block-start: -46px; inset-inline-end: -34px;
  width: 132px; height: 132px; border-radius: 6px 40px 40px 6px;
  background: var(--green-50);
  transform: rotate(-18deg);
  pointer-events: none;
}
.bev-card > * { position: relative; }

.bev-card-head {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px;
  justify-content: space-between;
  margin-bottom: 4px;
}
.bev-card-head h2 { margin: 0; font-size: 1.125rem; }

.bev-chip {
  background: var(--ok-bg); border-color: var(--green-200); color: var(--green-800);
  font-weight: 700;
}
.bev-chip svg { width: 14px; height: 14px; color: var(--green-700); }

/* Mobiel staat de waarde onder zijn label en links uitgelijnd, en niet
   half-links-half-rechts. Met één flexregel die mag afbreken hing dat af van de
   lengte van de waarde: "14:00 uur" bleef naast het label staan en dus rechts,
   "dinsdag 18 augustus 2026" viel naar de volgende regel en dus links. Twee
   uitlijningen in één kaart, bepaald door de kalender. */
.bev-rows { margin: 0; display: grid; }
.bev-rows > div {
  padding: 13px 0; border-bottom: 1px solid var(--line);
}
.bev-rows > div:last-child { border-bottom: 0; padding-bottom: 4px; }
.bev-rows dt {
  display: flex; align-items: center; gap: 9px;
  color: var(--ink-3); font-size: .9375rem;
}
.bev-rows dd {
  margin: 6px 0 0; padding-inline-start: 39px;  /* uitgelijnd op de labeltekst */
  font-weight: 700; color: var(--ink);
  min-width: 0; overflow-wrap: anywhere;
}

/* Vanaf 640px past label en waarde wél naast elkaar, en dan is rechts uitlijnen
   de rustigste kolom: alle waarden eindigen op dezelfde streep. */
@media (min-width: 640px) {
  .bev-rows > div {
    display: flex; flex-wrap: wrap; gap: 2px 20px;
    align-items: baseline; justify-content: space-between;
  }
  .bev-rows dd { margin: 0; padding-inline-start: 0; text-align: right; }
}

.bev-ico {
  width: 30px; height: 30px; border-radius: 9px; flex: none;
  background: var(--green-50); color: var(--green-700);
  display: grid; place-items: center;
}
.bev-ico svg { width: 17px; height: 17px; }

/* De duur hangt onder de starttijd en is nadrukkelijk secundair: hij is een
   verwachting, geen afspraak. Op smalle schermen mag hij niet naast de tijd
   gaan staan, want dan leest "14:30 uur circa 60 minuten" als één waarde. */
.bev-sub { display: block; font-weight: 500; color: var(--ink-3); font-size: .875rem; }

.bev-ref {
  margin: 14px 0 0; padding-top: 14px; border-top: 1px solid var(--line);
  font-size: .875rem; color: var(--ink-3);
}
.bev-ref strong { color: var(--ink-2); }

/* --- de tijdlijn --- */

.bev-body h2 { font-size: 1.25rem; margin: 0 0 18px; }

.bev-tijdlijn {
  list-style: none; margin: 0 0 36px; padding: 0;
  counter-reset: bev;
  display: grid; gap: 0;
}
.bev-tijdlijn li {
  counter-increment: bev;
  position: relative;
  padding: 0 0 22px 46px;
}
.bev-tijdlijn li::before {
  content: counter(bev);
  position: absolute; inset-inline-start: 0; inset-block-start: 0;
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--green-700); color: #fff;
  display: grid; place-items: center;
  font-size: .875rem; font-weight: 700;
}
/* De verbindingslijn, en niet onder de laatste stap. */
.bev-tijdlijn li::after {
  content: ""; position: absolute;
  inset-inline-start: 14px; inset-block: 34px 4px;
  width: 2px; background: var(--green-100);
}
.bev-tijdlijn li:last-child { padding-bottom: 0; }
.bev-tijdlijn li:last-child::after { display: none; }
.bev-tijdlijn h3 { margin: 4px 0 4px; font-size: 1rem; }
.bev-tijdlijn p { margin: 0; color: var(--ink-2); font-size: .9375rem; }

/* --- voorbereiding en contact --- */

.bev-voorbereiding, .bev-contact {
  border-radius: var(--radius-lg);
  padding: 22px;
  margin-bottom: 28px;
}
@media (min-width: 640px) { .bev-voorbereiding, .bev-contact { padding: 26px 28px; } }

.bev-voorbereiding { background: var(--sand); border: 1px solid var(--line); }
.bev-contact       { background: var(--green-50); border: 1px solid var(--green-200); }

.bev-voorbereiding ul { list-style: none; margin: 0 0 16px; padding: 0; display: grid; gap: 10px; }
.bev-voorbereiding li {
  position: relative; padding-inline-start: 26px;
  color: var(--ink-2); font-size: .9375rem;
}
.bev-voorbereiding li::before {
  content: ""; position: absolute; inset-inline-start: 2px; inset-block-start: .45em;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--green-600);
}
.bev-voorbereiding p:last-child { margin: 0; }

.bev-contact p { color: var(--ink-2); }
.bev-contact .btn-row { margin: 16px 0 0; }
.bev-contact .btn-ghost { background: #fff; border-color: var(--green-200); }
.bev-contact .btn-ghost:hover { border-color: var(--green-700); color: var(--green-800); }
.bev-contact .btn svg { color: var(--green-700); }

.bev-terug { margin: 0; }
.bev-terug .btn { width: 100%; white-space: normal; }
@media (min-width: 640px) { .bev-terug .btn { width: auto; } }

/* ══════════════════════════════════════════════════════════════════════════
   24. Boekingsflow — één kolom, één prijs, één moment

   Deze ronde haalde de samenvattingskolom weg (de bezoeker las alles twee
   keer) en voegde datum en tijd samen tot één stap. Wat hier staat vervangt de
   `.booking-grid`-, `.progress-`- en `.summary-`-blokken van ronde 12A; die
   selectors komen in de uitvoer niet meer voor en zijn hierboven verwijderd.

   Alles is mobiel-eerst en niets rekent met een vaste breedte, zodat 390px en
   1440px allebei zonder horizontale schuifbalk passen.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── De navigatiebalk onder de titel ────────────────────────────────────── */

/* Drie kolommen met de titel in het midden, zodat "terug" en "verder" op elke
   stap op exact dezelfde plek staan — ook wanneer een van de twee ontbreekt.
   Vandaar de lege <span> in de markup in plaats van een weggelaten element. */
.stapnav {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 10px;
  margin-bottom: 18px;
  padding: 6px 0;
  border-block: 1px solid var(--line);
  font-size: .875rem;
}
.stapnav a {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: var(--tap); padding: 6px 4px;
  font-weight: 700; color: var(--green-700); text-decoration: none;
}
.stapnav a:hover { text-decoration: underline; }
.stapnav-hier {
  text-align: center; font-weight: 700; color: var(--ink);
  overflow-wrap: anywhere;
}
.stapnav-verder { justify-self: end; }
.stapnav-verder.is-leeg { min-width: 1px; }

/* ── De voortgangsregel ─────────────────────────────────────────────────── */

/* Vijf stappen, horizontaal, en op een smal scherm gewoon smaller in plaats
   van verborgen: de bezoeker mag altijd zien hoeveel er nog komt. De nummers
   zijn er voor wie de labels niet ziet staan — bij 390px vallen die weg. */
.stapregel {
  display: flex; gap: 4px; list-style: none; padding: 0;
  margin: 0 0 24px; font-size: .75rem;
}
.stapregel li {
  flex: 1 1 0; min-width: 0;
  display: flex; align-items: center; justify-content: center; gap: 5px;
  padding: 7px 4px; border-radius: 999px;
  background: var(--sand); color: var(--ink-3);
  text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.stapregel li.is-done { background: var(--green-100); color: var(--green-900); font-weight: 600; }
.stapregel li.is-current { background: var(--green-800); color: #fff; font-weight: 700; }
.sr-nummer { font-weight: 700; }

/* Onder 480px past alleen de huidige stap als tekst; de rest wordt een bolletje
   met zijn nummer. Weglaten zou de regel laten overlopen, en dat is precies de
   horizontale schuifbalk die er niet mag komen. */
@media (max-width: 479px) {
  .stapregel li { flex: 0 0 auto; padding: 7px 9px; }
  .stapregel li.is-current { flex: 1 1 auto; }
  .stapregel li:not(.is-current) { font-size: 0; }
  .stapregel li:not(.is-current) .sr-nummer { font-size: .75rem; }
}

/* ── De prijskaart ──────────────────────────────────────────────────────── */

/* Eén groene kaart, en het bedrag staat op deze pagina nergens anders meer. */
.prijskaart {
  border: 1px solid var(--green-700);
  border-radius: var(--radius-lg);
  background: var(--green-100);
  padding: 20px;
  margin-bottom: 22px;
}
@media (min-width: 640px) { .prijskaart { padding: 26px 28px; } }

.pk-adres { font-weight: 700; color: var(--green-900); margin: 0; overflow-wrap: anywhere; }
.pk-woning { margin: 2px 0 0; color: var(--ink-2); font-size: .9375rem; }
.pk-label {
  margin: 18px 0 0; font-size: .8125rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em; color: var(--green-900);
}
.pk-bedrag {
  margin: 2px 0 0;
  font-size: clamp(2rem, 1.5rem + 2.4vw, 2.75rem);
  font-weight: 800; line-height: 1.05; letter-spacing: -.02em;
  color: var(--green-900);
}
.pk-inclusief { margin: 8px 0 0; color: var(--ink-2); font-size: .9375rem; }

/* "incl. btw" achter een bedrag.

   Stond op `.muted` en dus in hetzelfde grijs als een terzijde, terwijl het geen
   terzijde is: het is de belofte dat het genoemde bedrag het eindbedrag is. In
   de merkkleur hoort het bij het bedrag ervoor.

   `--green-700` en niet `--green-600`: dit is tekst, en dan geldt de ondergrens
   van 4,5:1. Op wit haalt de eerste 5,0:1 en de tweede 3,3:1.

   De spatie ervoor staat in de markup en niet hier. Een `margin-left` zou bij een
   regelafbreking meeschuiven naar het begin van de volgende regel; een echte
   spatie breekt netjes af. Zonder die spatie stond er "€ 299,00incl. btw". */
.btw-noot, .kv-noot { color: var(--green-700); font-weight: 600; }

/* Een zijnoot: iets tussen een grijze slotzin en een melding in.

   Geen achtergrond en geen kader — dat is `.notice`, en die trekt terecht de
   aandacht naar zich toe. Wat de regel hier overeind houdt is één klein icoon en
   een lijn ernaast, zodat het oog ziet dát er iets staat zonder dat het schreeuwt.

   De tekst blijft op `--ink-2` en niet op `--ink-3`: dit is een mededeling die
   gelezen hoort te worden, en de zwakste grijstint van de site is precies wat
   mensen overslaan. */
.zijnoot {
  display: flex; gap: 10px; align-items: flex-start;
  border-left: 2px solid var(--line); padding: 2px 0 2px 12px;
  color: var(--ink-2); font-size: .875rem; line-height: 1.5;
}
.zijnoot svg { width: 16px; height: 16px; flex: none; margin-top: 3px; color: var(--ink-3); }

/* ── De momentkiezer ────────────────────────────────────────────────────── */

/* De dagen. `auto-fill` met een minimum in plaats van een vast aantal kolommen:
   zeven dagen naast elkaar past op 1440px en nergens anders. */
.dagen {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 10px;
  margin-bottom: 20px;
}

.dag-knop {
  display: flex; flex-direction: column; gap: 3px;
  width: 100%; min-height: var(--tap); padding: 12px 14px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: #fff; color: var(--ink); text-align: left; cursor: pointer;
  font: inherit;
}
.dag-knop:hover { border-color: var(--green-700); background: var(--green-100); }
.dag-knop:focus-visible { outline: 2px solid var(--green-700); outline-offset: 2px; }
.dag-titel { font-weight: 700; }
.dag-aantal { font-size: .8125rem; color: var(--ink-3); }

/* Een volle dag is geen knop en hoort er ook niet als een uit te zien. */
.dag.is-leeg .dag-blok {
  border: 1px dashed var(--line); border-radius: var(--radius);
  padding: 12px 14px; color: var(--ink-3);
}
.dag.is-leeg .dag-kop { font-size: .9375rem; margin: 0 0 2px; }
.dag.is-leeg .muted { margin: 0; font-size: .8125rem; }

/* Zonder JavaScript staat dit blok gewoon in de pagina: de dagkop met daaronder
   de tijden. `site.js` verhuist het naar een <dialog> en maakt de knop zichtbaar. */
.dag-blok { margin-bottom: 6px; }
.dag-kop { font-size: 1.0625rem; margin: 0 0 10px; }
.dag-kop:focus-visible { outline: 2px solid var(--green-700); outline-offset: 3px; }

.tijdrooster {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(88px, 1fr));
  gap: 8px;
}
.tijd { position: relative; display: block; }
.tijd input {
  position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer;
}
.tijd span {
  display: flex; align-items: center; justify-content: center;
  min-height: var(--tap); padding: 8px 6px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: #fff; font-weight: 700; font-variant-numeric: tabular-nums;
}
.tijd input:hover + span { border-color: var(--green-700); }
.tijd input:checked + span {
  border-color: var(--green-800); background: var(--green-800); color: #fff;
}
/* De focusring hangt aan het label en niet aan de onzichtbare radio: die is
   opacity 0 en zijn outline zou nergens te zien zijn. */
.tijd input:focus-visible + span { outline: 2px solid var(--green-700); outline-offset: 2px; }

.dag-sluit {
  margin-top: 16px; min-height: var(--tap); padding: 8px 16px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: #fff; font: inherit; font-weight: 700; cursor: pointer;
}

/* De dialoog. `max-height` met `overflow` zodat een dag met twintig tijdvakken
   op een telefoon scrollt in plaats van buiten het scherm te vallen. */
.dag-dialoog {
  width: min(440px, calc(100vw - 32px));
  max-height: min(560px, calc(100vh - 48px));
  overflow-y: auto;
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: 20px; background: #fff; color: var(--ink);
}
.dag-dialoog::backdrop { background: rgba(17, 33, 26, .45); }
.dag-dialoog .dag-blok { margin: 0; }

.gekozen-moment { min-height: 1.5em; margin: 0 0 4px; color: var(--ink-2); }
.gekozen-moment strong { color: var(--green-900); }

/* --- een lijst met tekst eronder ------------------------------------------

   `.lees > * + *` zet de verticale ritmiek tussen de blokken van een leeskolom,
   maar `.check-list` zelf draagt `margin: 0` — de reset die hem zijn bolletje
   afnam. Zolang een lijst het laatste element in zijn blok was, viel dat niet
   op: op `/tarieven/` en `/voorbereiden-opname/` staat er niets meer onder.

   Op de hubpagina staat er wél iets onder. Daar loopt de opsomming van
   verplichtingen door in de alinea over de advertentieplicht, zonder een enkele
   pixel ertussen — twee verschillende uitspraken die als één blok lezen.

   Vandaar deze regel, en niet een `margin-bottom` op de lijst zelf: die zou ook
   werken waar de lijst het blok afsluit en het ritme van `.lees` dubbel tellen.
   Het aangrenzende-broer-teken zegt precies wat de bedoeling is — alleen wanneer
   er werkelijk iets volgt. */
.check-list + p,
.check-list + h3,
.steps-lijst + p {
  margin-top: var(--ruimte-klein);
}

/* ══════════════════════════════════════════════════════════════════════════
   25. Juridische tekst — de algemene voorwaarden en het modelformulier

   De tekst komt uit `App\Legal\LegalHtmlRenderer` en niet uit een template; dit
   zijn de vier klassen die die renderer meegeeft. Bewust weinig: het document
   leest verder als gewone `prose`, en een voorwaardenpagina met een eigen
   typografie zou een tweede leesstijl op de site zijn.
   ══════════════════════════════════════════════════════════════════════════ */

/* Het lednummer hangt links van zijn tekst en niet ervoor in de zin: zo is
   "artikel 9.2" te vinden door de kolom af te lezen in plaats van door elke
   alinea te beginnen te lezen. Op een smal scherm valt het nummer terug naar
   een gewone vetgedrukte aanhef — inspringen kost daar de halve regelbreedte. */
.legal-clause { position: relative; margin: 0 0 .9em; }
.legal-nr { font-weight: 700; color: var(--ink-2); }

@media (min-width: 640px) {
  .legal-clause { padding-left: 3.4em; }
  .legal-nr { position: absolute; left: 0; top: 0; }
}

/* De kopgegevens en de invulregels: label boven, waarde eronder, en op een
   breder scherm naast elkaar. Geen `.kv-list`, want die lijnt zijn waarde
   rechts uit — passend voor een prijsregel, misleidend voor een KvK-nummer. */
.legal-facts, .legal-fields { margin: 0 0 1.4em; }
.legal-facts dt, .legal-fields dt { color: var(--ink-3); font-size: .92em; }
.legal-facts dd, .legal-fields dd { margin: 0 0 .6em; }

@media (min-width: 640px) {
  .legal-facts { display: grid; grid-template-columns: 12em 1fr; gap: .25em 1em; }
  .legal-facts dt, .legal-facts dd { margin: 0; }
}

/* De schrijflijn van het modelformulier. Een rand en geen reeks liggende
   streepjes: die worden voorgelezen. */
.legal-rule { display: block; height: 1.6em; border-bottom: 1px solid var(--line); }

/* De inhoudsopgave: één kolom op mobiel, twee zodra het past. */
.legal-toc { list-style: none; padding: 0; margin: 0 0 1.5em; columns: 1; }
.legal-toc li { margin-bottom: .35em; }

@media (min-width: 720px) {
  .legal-toc { columns: 2; column-gap: 2em; }
}

/* ══════════════════════════════════════════════════════════════════════════
   De mobiele conversieronde — de vaste actieknop en de herbalans van de kop
   --------------------------------------------------------------------------

   Drie gemeten feiten van 390×844 met een verse cookietoestand, en niet drie
   vermoedens:

     1. de verzendknop van de adrescheck liep van 662 tot 717px, en de
        cookiebanner begon op 698px. De primaire actie van de hele site stond bij
        het eerste bezoek dus 19px achter de banner;
     2. onder 1000px loopt `.paneel` niet mee. Ná de onderkant van die knop volgde
        er 4078px lang geen enkele zichtbare boekingsactie, tot de CTA-band
        onderaan;
     3. onder 520px verdween ook de CTA uit de kop, dus er was op dat stuk
        helemaal niets.

   Punt 1 is hieronder opgelost door de kop rustiger te zetten, punt 2 door de
   vaste knop, punt 3 door `.header-cta-kort` (zie blok 5). Alle drie gelden ze
   uitsluitend onder 1000px: dáárboven lost het meelopende paneel hetzelfde
   probleem al op, en er verandert op desktop dus niets.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── De kop van de homepage, alleen op mobiel ─────────────────────────────

   De H1 draagt de lokale zoekintentie ("Energielabel aanvragen in Zoetermeer en
   omgeving?") en die blijft woordelijk staan — hij voedt ook de `<title>` en de
   metabeschrijving. Wat hier verandert is uitsluitend de maat waarop hij op een
   smal scherm gezet wordt: `--g-4` levert op 390px 32,6px en vier regels van
   samen 189px, en dat is op een scherm van 844px met een cookiebanner van 146px
   eronder ruim een kwart van alles wat er te zien is.

   De sprong is één trede en geen halvering: op 390px komt hij op 28,4px uit. De
   kop blijft daarmee veruit het grootste element op het scherm.

   Alleen `.split-kop h1`, dus alleen de homepage. De paginakop van de
   inhoudspagina's en de hero van de Ads-pagina's houden hun eigen maat. */
@media (max-width: 999px) {
  .split-kop h1 { font-size: clamp(1.65rem, 1.3rem + 1.75vw, 2.1rem); }

  /* Twee maten die op een smal scherm alleen maar wit tussen de kop en het
     formulier zijn: de rasterspleet en de bovenmarge van het paneel. Samen goed
     voor de laatste tientallen pixels die de knop boven de banner tillen. */
  .split { gap: 18px; }
}

/* ── De vaste mobiele actieknop ───────────────────────────────────────────

   Hij verschijnt pas als `site.js` de `hidden`-vlag weghaalt, en dat gebeurt
   alleen wanneer de adrescheck buiten beeld is én de cookiebanner weg is. Zie
   `templates/site/partials/mobiele-cta.php` voor de redenen en `site.js` voor
   de twee voorwaarden.

   `z-index: 60` ligt onder de 70 van `.cookiebar`. Dat is een vangnet en geen
   oplossing: de twee horen nooit tegelijk in beeld te staan, en het script zorgt
   daarvoor. Maar mocht die voorwaarde ooit sneuvelen, dan legt de banner zich
   erover in plaats van eronder — de cookiekeuze is dan het scherm dat wint, en
   dat is de juiste volgorde.

   Boven 1000px bestaat hij niet. Daar loopt het adrescheckpaneel mee en zou een
   tweede vaste knop een tweede primaire actie op hetzelfde scherm zijn. */
.mobiele-cta {
  position: fixed; z-index: 60; left: 0; right: 0; bottom: 0;
  padding: 10px 16px calc(10px + env(safe-area-inset-bottom));
  background: rgba(255, 255, 255, .97);
  border-top: 1px solid var(--line-2);
  box-shadow: 0 -6px 24px rgba(17, 33, 26, .14);
}
@media (min-width: 1000px) { .mobiele-cta { display: none; } }

/* De knop vult de balk en is minstens een vol tikdoel hoog. `white-space:
   normal` omdat "Bekijk prijs en beschikbaarheid" op 320px over twee regels
   moet kunnen: `.btn` staat standaard op `nowrap`, en dat zou de balk — en
   daarmee de pagina — breder maken dan het scherm. Dezelfde afweging als bij
   `.postcheck-fields > button`. */
.mobiele-cta-knop {
  display: flex; width: 100%;
  min-height: var(--tap);
  white-space: normal;
  border-radius: var(--radius-sm);
}

/* De ruimte onder de voet, zodat de balk de laatste regel niet afdekt.

   Deze padding hangt aan een klasse die `site.js` zet en weghaalt tegelijk met
   de balk zelf, en niet kaal aan `body`. Dat is de les van `.mobile-bar`: die
   component was verdwenen en zijn `body { padding-bottom: 76px }` stond er nog,
   waardoor elke pagina onder 640px lege ruimte onder de voet droeg voor een balk
   die niet bestond. Verdwijnt deze balk ooit, dan verdwijnt met de klasse ook de
   padding, want zonder script wordt hij nooit gezet.
   {@see Tests\Unit\View\PublicStylesheetTest} bewaakt die regel. */
.site-body.heeft-mobiele-cta { padding-bottom: 84px; }
@media (min-width: 1000px) { .site-body.heeft-mobiele-cta { padding-bottom: 0; } }
