/* ==========================================================================
   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 */
  --sticker:    #ffd43b;       /* actiesticker; donkergroen erop 9:1 */
  --sticker-ink:var(--green-900);
  --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); }

/* Het tweede deel van de homepagekop: de handeling, kleiner onder plaats en
   dienst. Nog steeds deel van de `h1`, dus dezelfde letter en dezelfde
   `text-wrap: balance`; alleen de maat is die van een `h2` klein. */
.kop-sub {
  display: block;
  margin-top: .2em;
  font-size: 1.25rem;
  line-height: 1.25;
  color: var(--ink-2);
}
/* Onder 700px 1,25rem en niet de `--g-2` van breder: op 390×844 kostte de
   grotere maat zoveel hoogte dat de verzendknop van de adrescheck nog maar 3px
   boven de cookiebanner uitkwam. */
@media (min-width: 700px) { .kop-sub { margin-top: .3em; font-size: var(--g-2); } }

/* De regel direct onder de homepagekop (2026-10-03): waar, en wat de prijs omvat.
   Compact, want op 390×844 telt elke regel boven de adrescheck. */
.kop-plaats {
  margin: 10px 0 0;
  color: var(--green-800);
  font-size: .9375rem;
  font-weight: 600;
  line-height: 1.45;
}
@media (max-width: 699px) {
  .kop-plaats { margin-top: 6px; font-size: .875rem; line-height: 1.4; }
  /* Op 390×844 moet de verzendknop van de adrescheck boven de cookiebanner
     blijven; de kop met subregel kost een regel meer dan voorheen. */
  .split-kop h1 { margin-bottom: 0; }
  /* De toelichting in de aanvraagkaart in twee regels in plaats van drie. */
  .paneel-kaart .postcheck-sub { font-size: .875rem; line-height: 1.45; padding-bottom: 12px; }
  .paneel-kaart .postcheck-title-los { padding-bottom: 12px; margin-bottom: 14px; }
  .ochtend > .split { row-gap: 14px; }
}
@media (min-width: 700px) { .kop-plaats { font-size: 1.0625rem; } }
.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; }
/* De levertermijn leest als één zin ("Label binnen 1–5 werkdagen"):
   daar staat het onderschrift vóór het getal, in bron én beeld. */
.feitenbalk-chips .feit-uitleg-eerst dt { order: 0; }

/* Vier badges (2026-10-04, Floor: "liefst naast elkaar"). Op een telefoon een
   raster van 2×2 met het getal boven de uitleg, zodat elke badge even groot is;
   vanaf 620px vier pillen op één rij (bij 768 en 1440 passen ze; tussen 1000 en
   1200px, waar de leeskolom het smalst is, mogen ze afbreken). */
@media (max-width: 619px) {
  .feitenbalk-chips { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .feitenbalk-chips .feit {
    flex-direction: column; align-items: flex-start; gap: 0;
    border-radius: 12px; padding: 8px 12px;
  }
  .feitenbalk-chips .feit dt { margin-top: 1px; }
}
@media (min-width: 620px) {
  .feitenbalk-chips { gap: 6px; }
  .feitenbalk-chips .feit { padding: 6px 10px; gap: 4px; }
  .feitenbalk-chips .feit dd { font-size: .875rem; }
  .feitenbalk-chips .feit dt { font-size: .75rem; }
}

/* ── 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); }

/* `background: transparent` hoorde hier altijd al bij en stond er niet. `.btn-ghost`
   is een wit vlak met groene tekst; op een donkere band zette deze regel alleen de
   tekst op wit en liet het vlak wit staan — witte letters op een witte pil.

   Dat was tot de werkwijzenronde onzichtbaar omdat er op geen enkele
   `.on-dark`-context een spookknop stond; de partnerband op `/samenwerken/` was de
   eerste. Die band is er in de partnerronde uit — zie blok 24 — en daarmee heeft
   `.on-dark` vandaag weer geen enkele gebruiker in de sjablonen. De regel blijft
   staan: `.on-dark` is een hulpklasse en geen paginaonderdeel, en dit is precies
   het gat dat er de vorige keer ook al was. */
.on-dark .btn-ghost { background: transparent; 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 */

/* Hier stond de opmaak van `.crumbs`. `layout.php` rendert het kruimelpad niet
   meer, dus de component is dood; het kruimelpad leeft door als `BreadcrumbList`
   in de structured data. Nummer 6 blijft leeg staan zodat de nummering van de
   secties hieronder klopt met de inhoudsopgave bovenaan dit bestand. */

/* ------------------------------------------------- 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 bovenaan de leeskolom, want daar staat het paneel
     ernaast en kost het niets.

     De vier vlakken (`kop`, `paneel`, `bewijs`, `lees`) staan hier weer alle
     vier. Eén ronde lang droeg een fotoheld de kop boven deze band; die is er op
     verzoek van Floor uit, omdat een beeld van 520px de adrescheck van het
     eerste scherm drukte. */
  grid-template-areas: "kop" "paneel" "bewijs" "lees";
  padding-block: 8px var(--ruimte);
}
@media (min-width: 1000px) {
  .split {
    /* De bon staat rechts en de kop met de leeskolom links. Andersom was het tot
       deze ronde: het formulier stond vóór de kop in de leesrichting, zodat het
       eerste wat je tegenkwam een invoerveld was en pas daarna waar je terecht
       was gekomen. Nu leest de pagina van linksboven — kop, belofte, dan de
       inhoud — met het formulier ernaast in beeld. Het staat op mobiel nog
       steeds direct ná de belofte; dat is de bronvolgorde, en die verandert
       niet. */
    grid-template-columns: minmax(0, 1fr) 360px;
    grid-template-areas:
      "kop    paneel"
      "bewijs paneel"
      "lees   paneel";
    /* 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: minmax(0, 1fr) 380px; } }

.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); }

/* Een duidelijke scheiding tussen de secties van de homepage (2026-10-04, Floor):
   een lichtgroene lijn over de hele leeskolom met een kort donkergroen accent
   links, zodat het leest als een hoofdstukgrens en niet als een losse haarlijn.
   De vervolglink van elke sectie ("De volledige werkwijze", "Alle tarieven", …)
   is het laatste element en staat daardoor vlak boven de lijn. De laatste sectie
   krijgt geen lijn: daaronder begint de donkere slotband al. */
.split-lees > section:not(:last-of-type) {
  position: relative;
  padding-bottom: clamp(16px, .8rem + .6vw, 24px);
  border-bottom: 1px solid var(--green-200);
}
.split-lees > section:not(:last-of-type)::after {
  content: "";
  position: absolute; left: 0; bottom: -2px;
  width: 56px; height: 3px; border-radius: 2px;
  background: var(--green-700);
}
/* De vervolglink sluit de sectie af; geen extra marge eronder vóór de lijn. */
.split-lees > section > p:last-child { margin-bottom: 0; }

/* ── De vertrouwensstrook ───────────────────────────────────────────────────

   Eén smalle regel direct onder de navigatie, op de homepage (2026-10-04). Geen
   banner: de hoogte is één regel klein schrift (op mobiel twee), de achtergrond
   de lichtste tint van de ochtendband eronder, zodat strook en band als één vlak
   lezen.

   Geen score en geen aantal; zie het commentaar in `home.php`. De punten tussen
   de onderdelen zijn opmaak (`::before`) en geen tekst, zodat een schermlezer
   een gewone lijst hoort. Elk onderdeel breekt als geheel af (`nowrap`); de
   punt staat vóór elk onderdeel behalve het eerste van een regel. */
.vertrouwen {
  background: var(--green-50);
  border-bottom: 1px solid var(--green-100);
}
.vertrouwen-lijst {
  list-style: none; margin: 0; padding: 5px 0;
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 1px 0;
  font-size: .75rem; line-height: 1.4; color: var(--green-800);
  font-weight: 600;
}
.vertrouwen-lijst li { white-space: nowrap; }
.vertrouwen-lijst li + li::before {
  content: "·"; margin-inline: .5em; color: var(--green-700);
}
.vertrouwen-lijst a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.vertrouwen-lijst a:hover { color: var(--green-700); }
/* Op een telefoon twee vaste regels van twee: een breuk na het tweede onderdeel
   (een lege flexregel van volle breedte, via `order`), zodat geen regel met een
   los punt begint. De volgorde voor oog en schermlezer blijft die van de bron. */
@media (max-width: 699px) {
  .vertrouwen-lijst::after { content: ""; flex-basis: 100%; height: 0; order: 1; }
  .vertrouwen-lijst li:nth-child(n + 3) { order: 2; }
  .vertrouwen-lijst li:nth-child(3)::before { content: none; }
}
@media (min-width: 700px) {
  .vertrouwen-lijst { padding-block: 7px; font-size: .8125rem; line-height: 1.45; justify-content: flex-start; }
  .vertrouwen-lijst li + li::before { margin-inline: .65em; }
}

/* ── 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 tien 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 tien blaadjes netjes naast elkaar boven de vouw.

   Tien en niet de twaalf van V1: op 2026-10-04 op verzoek van Floor 20% minder
   (de twee op 58% en 74% vielen weg; de rest blijft gelijkmatig verdeeld). */
.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; }

/* 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. */
/* ── De bon ───────────────────────────────────────────────────────────────

   Het paneel was een donkergroen blok. Sinds de Meetlat-ronde is het een lichte
   kaart met een geperforeerde kop, zoals een afspraakbon: de kop zegt wát je
   krijgt, de perforatie scheidt dat van wat je invult.

   **Waarom het niet meer donkergroen is.** Op wit is de gevulde groene knop weer
   de sterkste kleur van het blok; op het donkergroene paneel moest die knop wit
   worden om nog knop te zijn, en dan draagt de belangrijkste actie van de site
   als enige niet de merkkleur. De kaart staat bovendien op de lichtgroene
   ochtendband, en een donker blok daarop las als een uitgesneden vlak in plaats
   van als een formulier dat bij de pagina hoort.

   Het levert ook contrast terug in plaats van in te leveren: de adrescheck staat
   hier nu op precies dezelfde vlakken als op de vijf andere routes, dus het
   verplicht-sterretje draagt weer `--danger` (6,6:1 op wit) in plaats van de
   lichte tint die voor donkergroen nodig was. */
.paneel-kaart {
  background: var(--paper);
  color: var(--ink-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 22px;
  box-shadow: var(--shadow-lg);
  /* De perforatie is een halve cirkel links en rechts op de scheidslijn; zonder
     dit knipt de kaart ze niet bij en steken ze buiten de rand uit. */
  position: relative;
  overflow: hidden;
}
@media (min-width: 560px) { .paneel-kaart { padding: 26px; } }

/* De adrescheck is binnen het paneel geen eigen kaart: het paneel ís de kaart.
   Zonder deze regel staat er een witte kaart met rand en schaduw binnen een
   witte 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 { font-size: 1.15rem; }

/* De scheidslijn onder de kop, met de twee perforatiegaten. Een gestreepte rand
   en geen doorgetrokken lijn: dit is de plek waar de bon "afgescheurd" wordt, en
   dat is precies de scheiding tussen wat je krijgt en wat je invult.

   De gaten dragen de paginakleur en niet wit: ze horen gaten te zijn, dus ze
   tonen wat er achter de kaart ligt. Boven 1000px ligt daar de ochtendband, en
   die is op deze hoogte al vrijwel `--green-50`. */
/* Zonder toelichting (homepage, sinds 2026-10-04) draagt de kop de scheiding;
   `.postcheck-title-los` zet de partial alleen bij een lege `$sub`. */
.paneel-kaart .postcheck-sub,
.paneel-kaart .postcheck-title-los {
  padding-bottom: 16px;
  border-bottom: 1px dashed var(--line-2);
  position: relative;
}
.paneel-kaart .postcheck-title-los { margin-bottom: 16px; }
.paneel-kaart .postcheck-sub::before,
.paneel-kaart .postcheck-sub::after,
.paneel-kaart .postcheck-title-los::before,
.paneel-kaart .postcheck-title-los::after {
  content: "";
  position: absolute; bottom: -9px;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--green-50);
}
.paneel-kaart .postcheck-sub::before,
.paneel-kaart .postcheck-title-los::before { left: -31px; }
.paneel-kaart .postcheck-sub::after,
.paneel-kaart .postcheck-title-los::after { right: -31px; }
@media (min-width: 560px) {
  .paneel-kaart .postcheck-sub::before,
  .paneel-kaart .postcheck-title-los::before { left: -35px; }
  .paneel-kaart .postcheck-sub::after,
  .paneel-kaart .postcheck-title-los::after { right: -35px; }
}

/* Hier stond een `@media (max-width: 559px)`-blok dat de kaartrand naar 18 px en
   de ruimte onder de toelichting naar 12 px bracht. Het bestond om één reden: de
   toelichting was drie zinnen lang en duwde de verzendknop tegen de cookiebanner
   aan, en die 12 px waren het enige wat er nog te halen viel.

   De toelichting is sindsdien één regel, en het paneel heeft op 390×844 weer
   91 px lucht onder de knop — ruimer dan het ooit had. De kaart houdt daarom
   gewoon zijn ontworpen maat. Een krapte-ingreep die zijn krapte niet meer
   heeft, hoort weg: hij is onzichtbaar totdat iemand zich afvraagt waarom dit
   paneel als enige een andere rand heeft dan de rest van de site. */
/* Hier stonden vier kleuroverschrijvingen voor het donkergroene paneel — witte
   labels, lichtgroene toelichtingen en een witte knop. Ze zijn eruit en niet
   vervangen: op de lichte bon is de gewone stand van elke component al de
   juiste, en een overschrijving die hetzelfde zegt als de component eronder is
   een tweede plek waar je moet zoeken zodra iemand de component wijzigt.

   De primaire knop is daarmee weer gewoon `--green-800` op wit, de sterkste
   kleur van het blok in plaats van de omgekeerde stand die op donkergroen nodig
   was. */

/* 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 var(--line);
  padding-top: 18px;
  font-size: .9375rem;
}
.paneel-usp li { display: flex; gap: 10px; color: var(--ink-2); }
.paneel-usp li::before { content: "✓"; color: var(--green-700); 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;
}

/* ── Het portret onder het paneel ───────────────────────────────────────────

   Klein en rond, naast "Floor komt zelf langs" en het telefoonnummer. Dezelfde
   vierkante uitsnede en dezelfde maat als `.balie-portret` op `/contact/`. De
   regel staat links uitgelijnd naast de foto in plaats van gecentreerd: een
   gecentreerde tekst naast een foto leest als twee losse dingen. */
.paneel-persoon {
  display: flex; align-items: center; gap: 12px;
  text-align: left;
}
.paneel-persoon p { margin: 0; line-height: 1.45; }
.paneel-persoon strong { color: var(--ink); font-weight: 600; }
.paneel-portret {
  width: 48px; height: 48px; flex: none;
  border-radius: 50%;
  object-fit: cover;
  background: var(--paper);
  box-shadow: 0 0 0 1px var(--green-200);
}

/* ── 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 "(optioneel)" in een label draagt `.muted`, en die klasse brengt zijn eigen
   maat mee: .9375rem, dus grótér dan het label van .875rem waar hij in staat. Dat
   ene punt verschil maakt de regelhoogte van zo'n label 1,7px hoger dan die van
   het label ernaast — en in een rij velden naast elkaar staat het invoerveld
   eronder dan zichtbaar scheef.

   Alleen de maat wordt teruggezet; de kleur is wél de bedoeling. */
.field-label .muted { font-size: inherit; }

/* 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; }

/* ── Het sterretje op het paneel ───────────────────────────────────────────

   Hier stond een lichtroze variant (`#ffd5d0`) voor het donkergroene paneel:
   `--danger` (#b42318) op `--green-800` (#166534) haalt **1,08:1**, dus daar was
   het sterretje er wel en zag je het niet.

   Sinds de Meetlat-ronde is de kaart licht (zie `.paneel-kaart`) en is die
   uitzondering weg. Het sterretje draagt weer gewoon `--danger` op wit: 6,6:1,
   en het is daarmee dezelfde kleur als op elk ander formulier van de site.

   Wat niet verandert is dat de kleur een **aanvulling** op de betekenis is en
   niet de drager ervan: de verplichting staat in de verborgen tekst
   "(verplicht)" naast het sterretje in `adrescheck.php`. */

.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 tijdbalk op /werkwijze/ ────────────────────────────────────────────

   Hier stond `.timeline` met `.tl-item`, `.tl-nr`, `.tl-head` en `.tl-duur`: een
   verticale lijn met acht even zware blokken eronder. De pagina las daardoor als
   veertig blokken op één scrollpad, en het getal waar iemand voor komt — hoe lang
   duurt het — stond acht keer klein in een groene pil.

   De acht stappen staan nu als balken op een as van 24 kolommen; `--van` en
   `--tot` komen per stap uit `Process::stappen()`, de kolomkoppen uit
   `Process::tijdvakken()`. `.tl-split` en `.tl-box` bleven: dat paar "Jij"/"Ik"
   is ongewijzigd en zit nu in het uitklapdeel.

   Mobile-first, zoals de rest van dit bestand: de basis hieronder is de
   telefoonstand (een regel per stap met een dunne positiestrook), en de
   tijdbalk zelf komt er vanaf 1120px bij — het desktopbreekpunt van deze site.
   Niet vanaf 900: daar is een kolom 35px en past "Opname op locatie" niet in de
   vijf kolommen van zijn balk, en een grafiek waarin de langste stap halverwege
   een woord afknipt is geen overzicht. Zijwaarts scrollen was het alternatief,
   en dat is op een telefoon geen navigatie.

   Kleur codeert wie er aan zet is en is geen tweede merkkleur: groen is van mij,
   donkere inkt is van jou, het verloop is samen. Beide dragen witte tekst met
   ruim voldoende contrast (#fff op --green-700 ≈ 5,0:1, op --ink-2 ≈ 10,3:1). */

.tb-sectie { padding-block: 0 var(--ruimte); }

/* De drie kengetallen boven de balk */
.tb-kengetallen {
  list-style: none; margin: 0 0 var(--ruimte-klein); padding: 0;
  display: grid; gap: 10px;
}
@media (min-width: 640px) { .tb-kengetallen { grid-template-columns: repeat(3, 1fr); gap: 14px; } }
.tb-kengetallen li {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--paper); padding: 14px 16px;
}
.tb-kg-label {
  display: block; font-size: .6875rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .09em; color: var(--ink-3);
}
.tb-kg-waarde {
  display: block; font-family: var(--display); font-size: var(--g-1);
  color: var(--green-800); line-height: 1.2; margin: 2px 0 3px;
}
.tb-kg-bij { display: block; font-size: .875rem; color: var(--ink-2); }

/* De kaart waarin de as en de acht stappen staan */
.tb-kaart {
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  background: var(--paper); box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.tb-kaartkop {
  display: flex; flex-wrap: wrap; gap: 8px 20px; align-items: center;
  justify-content: space-between;
  padding: 14px 16px; border-bottom: 1px solid var(--line);
}
.tb-titel { margin: 0; font-size: var(--g-1); }
.tb-legenda {
  list-style: none; display: flex; flex-wrap: wrap; gap: 6px 16px;
  margin: 0; padding: 0; font-size: .8125rem; color: var(--ink-2);
}
.tb-legenda li { display: flex; align-items: center; gap: 7px; }
.tb-vlag { width: 12px; height: 12px; border-radius: 4px; flex: none; }

/* De kleuren van "wie is aan zet", gedeeld door de balk, de strook en de vlag */
.tb-jij   { background: var(--ink-2); }
.tb-ik    { background: var(--green-700); }
.tb-samen { background: linear-gradient(100deg, var(--ink-2) 0 46%, var(--green-700) 54% 100%); }
/* In een balk telt de overgang in pixels en niet in procenten: op mobiel is die
   balk de volle schermbreedte, en dan staat een verloop op 50% als een tweekleurig
   vlak in plaats van als één stap waar we allebei aan werken. */
.tb-balk.tb-samen { background: linear-gradient(100deg, var(--ink-2) 0 92px, var(--green-700) 140px); }

/* De kolomkoppen: alleen zinvol náást de balken, dus pas vanaf 900px */
.tb-tijdvakken { display: none; }

/* ── De acht standen op de as ───────────────────────────────────────────────

   `--van` en `--tot` zijn kolomnummers op het raster van 24 hierboven; `--tot`
   is exclusief, zoals `grid-column` hem leest, en 25 is dus de rechterrand.

   Ze staan hier en niet als `style`-attribuut in de template, om dezelfde reden
   als de twaalf blaadjes: de publieke CSP voert `style-src 'self'` zonder
   `'unsafe-inline'`. Een `style` op een balk wordt door de browser niet
   toegepast — zonder foutmelding — en dan staan alle acht de balken op elkaar in
   de eerste kolom. `PublicSiteRoutesTest` houdt het attribuut tegen vóór het
   zover komt.

   De volgorde is die van `Process::stappen()`; een negende stap zonder eigen
   regel erft de laatste stand en komt boven op zijn buurman.

   De balken overlappen elkaar met opzet één kolom: registratie begint niet pas
   als de uitwerking helemaal klaar is. En het zijn verhoudingen en geen
   kalender — de pagina zegt dat er zelf bij, onder de balk.

   Waar de duur staat hangt af van hoeveel ruimte er rechts van de balk over is.
   Vanaf stap 7 is dat niets, en dan gaat hij naar links: rechts uitlijnen aan de
   rand van de kaart — de eerste opzet — legde het bijschrift over de balken van
   de laatste drie stappen heen.

   De homepage voerde tot 2026-09-30 dezelfde acht standen in het klein
   (`.tb-mini`). Die is vervangen door drie stappen (`.stappen-drie`), dus deze
   standen horen alleen nog bij `/werkwijze/`. */
.tb-lijst > li:nth-child(1) { --van:  1; --tot:  5; }
.tb-lijst > li:nth-child(2) { --van:  3; --tot:  9; }
.tb-lijst > li:nth-child(3) { --van:  5; --tot: 10; }
.tb-lijst > li:nth-child(4) { --van: 10; --tot: 15; }
.tb-lijst > li:nth-child(5) { --van: 14; --tot: 19; }
.tb-lijst > li:nth-child(6) { --van: 16; --tot: 21; }
.tb-lijst > li:nth-child(7) { --van: 19; --tot: 24; }
.tb-lijst > li:nth-child(8) { --van: 21; --tot: 25; }

.tb-lijst { list-style: none; margin: 0; padding: 8px 12px 14px; display: grid; gap: 6px; }

/* Eén stap. `<details>` levert het open/dicht-gedrag; er is geen script. */
.tb-stap { border-radius: var(--radius); }
.tb-rij {
  display: block; cursor: pointer; list-style: none;
  padding: 6px; border-radius: var(--radius);
  min-height: var(--tap);
}
.tb-rij::-webkit-details-marker { display: none; }
/* Het aanwijzen pakt de hele regel en niet alleen de balk. `--sand` stond hier
   eerder alleen, en dat vlak scheelt maar drie procent van wit: op de as, waar
   de balk zelf al donker is en de rest van de regel leeg, was er onder de muis
   nauwelijks iets te zien. Nu reageert de volle regelbreedte: een groen vlak,
   een haarlijn eromheen, en de duurtekst en de positiestrook kleuren mee. Samen
   met de balk die optilt (de regel hieronder) is dat vier signalen op één
   beweging — dat is wat een regel van 24 kolommen nodig heeft om als één
   aanklikbaar geheel te lezen.

   `background-color` en niet `background`: op de tijdbalk draagt `.tb-rij` een
   verloop met de kolomlijnen van de as, en de shorthand zou dat bij het aanwijzen
   wegvegen — de lijnen knipperden dan onder de muis vandaan. De haarlijn is een
   `inset`-schaduw en geen `border`, want een rand van 1px zou de regel 2px hoger
   maken en de hele as onder de muis laten verspringen. */
.tb-rij:hover,
.tb-rij:focus-visible {
  background-color: var(--green-50);
  box-shadow: inset 0 0 0 1px var(--green-200);
}
.tb-rij:hover .tb-duur,
.tb-rij:focus-visible .tb-duur { color: var(--ink-2); }
.tb-rij:hover .tb-strook,
.tb-rij:focus-visible .tb-strook { background: var(--green-100); }

.tb-stap[open] > .tb-rij { background-color: var(--sand); }

/* Aanwijzen moest duidelijker: `--sand` achter een balk die zelf al gekleurd is,
   is nauwelijks te zien, en dan leest de balk als een plaatje in plaats van als
   een knop. De balk zelf reageert nu: lichter, iets opgetild en met een schaduw
   eronder. Dat werkt op alle drie de kleuren, ook op het verloop van "samen",
   waar een tweede achtergrondkleur niet kan. */
.tb-balk { transition: filter .12s ease, box-shadow .12s ease, transform .12s ease; }
.tb-rij:hover .tb-balk,
.tb-rij:focus-visible .tb-balk {
  filter: brightness(1.14);
  box-shadow: 0 2px 8px rgb(0 0 0 / .22);
  transform: translateY(-1px);
}
.tb-rij:active .tb-balk { transform: none; box-shadow: none; }

/* En een vast teken dat er iets open kan: het chevron staat er altijd, ook zonder
   muis, en draait mee met `<details>`. Vanaf 1120px valt hij weg — daar is een
   balk vier kolommen breed en zou hij de kop afknijpen tot een beletselteken. */
.tb-balk::after {
  content: ""; flex: none; margin-left: auto; align-self: center;
  width: 7px; height: 7px; margin-right: 2px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
  transition: transform .15s ease;
}
.tb-stap[open] .tb-balk::after { transform: rotate(-135deg); }

/* De balk. Op mobiel een volle regel, vanaf 900px een blok op de tijdas. */
.tb-balk {
  display: flex; align-items: center; gap: 10px;
  min-height: 34px; padding: 4px 12px; border-radius: 10px;
  color: #fff; font-weight: 600; font-size: .9375rem;
}
.tb-nr {
  font-weight: 800; font-variant-numeric: tabular-nums; opacity: .72; flex: none;
}
.tb-kop { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.tb-duur { display: block; font-size: .8125rem; color: var(--ink-3); padding: 4px 12px 0; }

/* De positiestrook onder de regel: dezelfde 24 kolommen als de tijdbalk, zodat
   ook op een telefoon te zien is wáár in het traject een stap valt. */
.tb-strook {
  display: grid; grid-template-columns: repeat(24, minmax(0, 1fr));
  height: 6px; margin: 8px 12px 2px; border-radius: 3px; background: var(--sand-2);
}
.tb-strook-vak { grid-column: var(--van) / var(--tot); border-radius: 3px; }

/* Het uitklapdeel — de tekst en het paar Jij/Ik — draagt het ochtendlicht van de
   homepage, maar een trap lichter: dezelfde 160 graden en dezelfde richting, en
   dan `--green-50 → --paper` in plaats van `--green-100 → --green-50`. Het blok
   moet laten zien dat het bij zijn balk hoort, niet de aandacht wegtrekken van de
   balken zelf; met de homepagestops werd dit het zwaarste vlak van de kaart.

   Net als `.balie` eindigt het verloop op `--paper` en niet op transparant: een
   masker zou ook de tekst laten vervagen. */
.tb-detail {
  margin: 2px 6px 8px; padding: 12px 14px 14px;
  background: linear-gradient(160deg, var(--green-50) 0%, var(--green-50) 55%, var(--paper) 100%);
  border: 1px solid var(--green-100);
  border-radius: var(--radius);
}
.tb-tekst { margin: 0; max-width: var(--maat-tekst); font-size: .9375rem; }

@media (min-width: 1120px) {
  .tb-tijdvakken {
    display: grid; grid-template-columns: repeat(24, minmax(0, 1fr));
    padding: 0 20px; margin-top: 12px;
  }
  .tb-tijdvak {
    /* minmax(0, 1fr) hierboven is geen detail: met een kale `1fr` krijgt elke
       kolom de min-content van wat erin staat als ondergrens, en dan bepaalt de
       breedste kop de kolombreedte in plaats van de as. Daarom knipt het kopje
       ook af in plaats van zijn kolom op te rekken. */
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font-size: .6875rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: .07em; color: var(--ink-3);
    padding: 6px 0 6px 10px; border-left: 1px solid var(--line);
  }
  .tb-tijdvak:last-child { border-right: 1px solid var(--line); }
  /* Vijf vakken, samen de 24 kolommen van de as. Zelfde reden als de acht
     standen hierboven: een breedte kan niet uit de template komen. */
  .tb-tijdvak:nth-child(1) { grid-column: span 4; }
  .tb-tijdvak:nth-child(2) { grid-column: span 5; }
  .tb-tijdvak:nth-child(3) { grid-column: span 5; }
  .tb-tijdvak:nth-child(4) { grid-column: span 6; }
  .tb-tijdvak:nth-child(5) { grid-column: span 4; }

  .tb-lijst { padding: 0 20px 18px; gap: 0; }
  .tb-rij {
    display: grid; grid-template-columns: repeat(24, minmax(0, 1fr)); align-items: center;
    padding: 4px 0; border-radius: 0;
    /* De kolomlijnen van de tijdvakken lopen door achter de balken heen. Eén
       verloop en geen achttal losse elementen: de lijnen horen bij de as. */
    background:
      linear-gradient(to right,
        var(--line) 0 1px, transparent 1px 16.666%,
        var(--line) 16.666% calc(16.666% + 1px), transparent calc(16.666% + 1px) 37.5%,
        var(--line) 37.5% calc(37.5% + 1px), transparent calc(37.5% + 1px) 58.333%,
        var(--line) 58.333% calc(58.333% + 1px), transparent calc(58.333% + 1px) 83.333%,
        var(--line) 83.333% calc(83.333% + 1px), transparent calc(83.333% + 1px) calc(100% - 1px),
        var(--line) calc(100% - 1px) 100%);
  }
  /* De open stap houdt zijn balk lichter; het aanwijzen zelf staat in de
     basisregels hierboven en geldt hier net zo goed. */
  .tb-stap[open] > .tb-rij .tb-balk { filter: brightness(1.08); }
  .tb-stap[open] > .tb-rij { background-color: transparent; }
  /* Geen chevron op de as: de smalste balk is vier van de 24 kolommen. */
  .tb-balk::after { display: none; }

  .tb-balk {
    grid-row: 1; grid-column: var(--van) / var(--tot);
    overflow: hidden; white-space: nowrap;
  }
  .tb-duur {
    grid-row: 1; align-self: center; padding: 0 12px; white-space: nowrap;
  }
  .tb-duur { grid-column: var(--tot) / 25; }
  /* Vanaf stap 6 past het bijschrift rechts niet meer — "streven: binnen 1 tot 5
     werkdagen" heeft meer dan drie kolommen nodig — en gaat het naar links. Daar
     is de rij leeg, want er staat per rij maar één balk. */
  .tb-lijst > li:nth-child(n+6) .tb-duur { grid-column: 1 / var(--van); text-align: right; }
  .tb-strook { display: none; }

  .tb-detail {
    /* Het uitklapdeel hoort bij de balk erboven en niet bij de as: het loopt over
       de volle breedte. Het groene vlak dat het aan zijn stap bindt staat in de
       basisregel hierboven; hier staat alleen de ruimere maat van de kaart. */
    margin: 2px 0 10px; padding: 16px 18px;
  }
}

.tb-voetnoot {
  margin: 14px 0 0; font-size: .8125rem; color: var(--ink-3);
  max-width: var(--maat-tekst);
}

.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; }
/* De "Ik"-helft stond op `--green-50`; nu het uitklapdeel eromheen zelf groen is,
   is dat dezelfde tint op dezelfde tint en valt het kaartje weg. Zelfde afweging
   als de chips op de ochtendband: wit met een groenere rand houdt het los van
   zijn ondergrond én blijft het verschil met "Jij" dragen. */
.tl-box.mine { background: #fff; border-color: var(--green-200); }

/* ── Zo werkt het: de drie stappen op de homepage ────────────────────────

   Tot 2026-09-30 stond hier de tijdbalk van `/werkwijze/` in het klein, met
   alle acht stappen. Nu drie, uit `Process::homeStappen()`: een cijfer, een kop,
   de duur en een regel uitleg. Op smalle schermen onder elkaar, vanaf 700px
   naast elkaar. */
.stappen-drie {
  list-style: none; margin: 0 0 4px; padding: 0;
  display: grid; gap: 18px;
}
.stappen-drie > li { display: flex; gap: 14px; align-items: flex-start; }
.stappen-drie-nr {
  flex: none;
  width: 34px; height: 34px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--green-50); color: var(--green-800);
  box-shadow: 0 0 0 1px var(--green-200);
  font-family: var(--data); font-weight: 700; font-size: .9375rem;
}
.stappen-drie h3 { margin: 4px 0 2px; font-size: 1.0625rem; }
.stappen-drie p { margin: 0; }
.stappen-drie-duur {
  font-size: .8125rem; color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  margin-bottom: 4px;
}
@media (min-width: 700px) {
  .stappen-drie { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; }
  .stappen-drie > li { flex-direction: column; gap: 10px; }
  .stappen-drie h3 { margin-top: 0; }
}

/* ------------------------------------------------------------ 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; }
}


/* ── De meetlat: de staffels als maat ─────────────────────────────────────

   Alleen op de homepage. `/tarieven/` houdt de tabel: daar komt iemand om de
   bedragen naast elkaar te lezen, en dan is een tabel de juiste vorm. Hier is de
   vraag een andere — *waar hangt die prijs eigenlijk vanaf?* — en dat is precies
   wat een balk die zo lang is als zijn bovengrens laat zien.

   De breedte komt uit `PriceListView::tierSpan()`, dat per staffel één van de
   tien klassen hieronder kiest. Tien vaste standen en geen `:nth-child`-reeks:
   het aantal staffels komt uit de database en kan morgen anders zijn, en een
   stand per kind zou dan stilzwijgend de laatste erven. Zie de toelichting bij
   die methode voor waarom het geen `style`-attribuut kan zijn.

   `dl`/`dt`/`dd` en geen lijst: elke regel is een maat met een bedrag, en dat is
   letterlijk wat een definitielijst beschrijft. */
.lat {
  margin: 0 0 var(--ruimte-klein);
  display: grid;
  /* Ook op een telefoon staat het bedrag naast de balk en niet eronder: twee
     regels per staffel maakt van vijf staffels tien regels, en dan is de lijst
     langer dan het scherm zonder dat er iets bij gezegd wordt. De balken zijn
     daar allemaal even lang — een verhouding heeft op 390px geen ruimte — en
     dragen dus alleen nog de maat. */
  grid-template-columns: minmax(0, 1fr) fit-content(132px);
  gap: 6px 12px;
  align-items: center;
}

/* De rij is `display: contents`, en dat is hier geen truc maar de kern: alle
   staffels horen op één rooster te staan. Kreeg elke rij zijn eigen rooster —
   de eerste opzet — dan bepaalde de breedte van het bedrag hoe lang de balk
   ernaast werd, en dus tekende de rij met de toeslag ("+ € 1,25 per m² boven
   225 m²") een kórtere balk voor een gróter oppervlak. Precies de verhouding
   die de lat moet laten zien, omgedraaid door een tekstlengte. */
.lat-rij { display: contents; }

@media (min-width: 560px) {
  /* Tien kolommen om in te groeien, plus één kolom voor het bedrag. Het bedrag
     schuift niet met de balk mee: de bedragen horen onder elkaar te staan,
     anders zijn ze niet meer te vergelijken. */
  .lat {
    /* `fit-content(148px)`: de kolom is zo breed als het bedrag nodig heeft,
       maar nooit breder dan 148px. Met `max-content` bepaalde de toeslag van de
       open eindstaffel ("+ € 1,25 per m² boven 225 m²") de kolombreedte, en dan
       verliezen álle balken ruim 300px aan een regel die bij één staffel hoort.
       De toeslag wikkelt daarom onder het bedrag; zie hieronder. */
    grid-template-columns: repeat(10, minmax(0, 1fr)) fit-content(148px);
    gap: 6px 14px;
    align-items: center;
  }
  .lat-prijs { grid-column: 11; }

}

/* De balk zelf. Op smalle schermen is hij de volle breedte met de maat erin —
   daar zegt een verhouding niets meer, want alle balken zijn dan even lang — en
   de maat blijft gewoon leesbaar. */
.lat-maat {
  display: flex; align-items: center;
  min-height: 38px; padding: 4px 14px;
  border-radius: 9px;
  background: var(--green-700);
  color: #fff;
  font-size: .9375rem; font-weight: 600;
}
.lat-maat-tekst { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* De tien standen. Vanaf 560px, want daaronder is de balk de volle regel. */
@media (min-width: 560px) {
  .lat-w1  { grid-column: 1 / 2;  }
  .lat-w2  { grid-column: 1 / 3;  }
  .lat-w3  { grid-column: 1 / 4;  }
  .lat-w4  { grid-column: 1 / 5;  }
  .lat-w5  { grid-column: 1 / 6;  }
  .lat-w6  { grid-column: 1 / 7;  }
  .lat-w7  { grid-column: 1 / 8;  }
  .lat-w8  { grid-column: 1 / 9;  }
  .lat-w9  { grid-column: 1 / 10; }
  .lat-w10 { grid-column: 1 / 11; }

  /* Een balk van één of twee kolommen is te smal voor zijn eigen tekst. Dan
     staat de maat ernaast in plaats van erin, en blijft de balk de maat.

     `flex: none` en `overflow: visible` op de tekst zijn hier geen versiering:
     als flexitem krijgt de regel anders de resterende breedte toegewezen — en
     die is na een marge van 100% nul — waarna `text-overflow` hem tot niets
     afknipt. Dat is de stand waarin de maat stil verdwijnt. */
  .lat-w1 .lat-maat-tekst,
  .lat-w2 .lat-maat-tekst {
    flex: none; overflow: visible;
    margin-left: calc(100% + 10px);
    color: var(--ink-2); font-weight: 500; white-space: nowrap;
  }
}

/* De toeslag van de open eindstaffel wikkelt onder het bedrag en staat nooit op
   één regel. Zou hij dat wel doen, dan bepaalt zijn lengte de breedte van de
   bedragkolom — en op een rooster dat de rijen delen, kost dat álle balken hun
   ruimte. Vandaar ook `fit-content()` op die kolom in plaats van `max-content`:
   een bovengrens die een lange regel niet kan passeren. */
.lat .tier-toeslag {
  display: block; margin-top: 2px; white-space: normal;
  font-size: .75rem; line-height: 1.35;
}

/* Oplopend donkerder: de balk wordt niet alleen langer maar ook zwaarder, zodat
   de reeks ook zonder de lengte te meten als een oplopende schaal leest. De
   lichtste draagt donkere tekst; `--green-400` haalt met wit geen 4,5:1. */
.lat-rij:first-child .lat-maat { background: var(--green-400); color: var(--ink); }
.lat-rij:nth-child(2) .lat-maat { background: var(--green-600); }
.lat-rij:last-child .lat-maat { background: var(--green-800); }

.lat-prijs {
  margin: 0;
  font-family: var(--data);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  color: var(--ink);
  padding-left: 2px;
}
@media (max-width: 559px) {
  .lat-prijs { grid-column: 2; font-size: .9375rem; }
}

.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); }


/* ── de staffelkiezer van /tarieven/ ──────────────────────────────────────

   De tarievenpagina stelt de vraag die de bezoeker komt stellen — *hoe groot is
   je woning?* — en antwoordt met één bedrag. De knoppen zijn radiobuttons, de
   panelen liggen op elkaar in één rasterhok, en welk paneel zichtbaar is bepaalt
   `:has()` hieronder. Geen JavaScript: `site.js` laadt met `defer` en een prijs
   hoort niet op een scriptbestand te wachten. Zie de kop van
   `templates/site/pages/tarieven.php`.

   Acht standen, want zoveel staffels kan de kiezer tonen; de sjabloon valt bij
   meer terug op de volledige tabel. Handgeschreven `:nth-child`-regels en geen
   `style`-attribuut, om dezelfde reden als bij de tijdbalk van /werkwijze/:
   `style-src 'self'` laat het attribuut niet toe.
   ---------------------------------------------------------------------- */

.tk {
  display: grid;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  overflow: hidden;
}
@media (min-width: 900px) {
  .tk { grid-template-columns: 1.12fr .88fr; }
}

.tk-keuze      { padding: clamp(20px, 3vw, 34px); }
.tk-inbegrepen {
  padding: clamp(20px, 3vw, 34px);
  background: var(--green-50);
  border-top: 1px solid var(--line);
}
@media (min-width: 900px) {
  .tk-inbegrepen { border-top: 0; border-left: 1px solid var(--line); }
}
.tk-inbegrepen h2 { font-size: 1.0625rem; margin-bottom: 14px; }

/* De vraag is een `<legend>`: de knoppenrij is één keuze en hoort een groep te
   zijn met een naam. `min-width: 0` omdat een `<fieldset>` van zichzelf een
   `min-content`-breedte heeft en de rij daarmee op smalle schermen niet wil
   afbreken. */
.tk-vraag { border: 0; margin: 0; padding: 0; min-width: 0; }
.tk-vraag legend {
  font-family: var(--display);
  font-size: var(--g-1);
  font-weight: 700;
  color: var(--ink);
  padding: 0;
  margin-bottom: 12px;
}

.tk-maten { display: flex; flex-wrap: wrap; gap: 8px; }

/* De radio zelf staat uit beeld maar niet uit de boom: hij houdt het
   toetsenbordgedrag (pijltjes tussen de standen) en de schermlezer hoort een
   keuzerondje. `position: absolute` en niet `display: none`, want een verborgen
   veld is niet focusbaar. Hij zit ín zijn label — de vorm die de rest van de
   site voert en die de visuele contracttest verlangt. */
.tk-radio {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  opacity: 0;
  pointer-events: none;
}

.tk-maat {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  padding: 9px 16px;
  border: 1px solid var(--line-2);
  border-radius: 999px;
  background: #fff;
  color: var(--ink-2);
  font-size: .9375rem;
  cursor: pointer;
  transition: background .15s, border-color .15s, color .15s;
}
.tk-maat:hover { border-color: var(--green-600); color: var(--ink); }

.tk-maat:has(.tk-radio:checked) {
  background: var(--green-800);
  border-color: var(--green-800);
  color: #fff;
  font-weight: 600;
}
/* De focusring hoort om het zichtbare element en niet om het verborgen veld. */
.tk-maat:has(.tk-radio:focus-visible) {
  outline: 3px solid var(--green-700);
  outline-offset: 2px;
}

/* De panelen liggen op elkaar in één rasterhok. Daardoor is het blok altijd zo
   hoog als het hoogste paneel en springt de pagina niet bij het wisselen — de
   staffel met een toeslagregel is één regel hoger dan de rest. */
.tk-panelen { display: grid; margin-top: clamp(18px, 2.4vw, 26px); }
.tk-paneel {
  grid-area: 1 / 1;
  visibility: hidden;
}

.tk-bedrag { display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px 12px; margin: 0; }
.tk-euro {
  font-family: var(--data);
  font-variant-numeric: tabular-nums;
  font-size: clamp(2.5rem, 1.8rem + 3.2vw, 3.9rem);
  line-height: 1;
  font-weight: 700;
  letter-spacing: -.03em;
  color: var(--ink);
}
.tk-allin {
  font-size: .9375rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--green-700);
}
.tk-grenzen { margin: 10px 0 0; font-weight: 600; color: var(--ink-2); }
.tk-toeslag { margin: 2px 0 0; font-size: .9375rem; color: var(--ink-3); }

/* De ladder toont de plaats in de reeks en niet de oppervlakte: even brede
   vakken, omdat een staffel geen breedte heeft die de prijs verklaart. */
.tk-ladder {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 4px;
  list-style: none;
  margin: clamp(18px, 2.4vw, 24px) 0 0;
  padding: 0;
}
.tk-vak { height: 8px; border-radius: 999px; background: var(--sand-2); }

/* De acht standen. Per stand: het bijbehorende paneel zichtbaar, en de ladder
   gevuld tot en met dat vak. */
.tk:has(#tk-s1:checked) .tk-paneel:nth-child(1),
.tk:has(#tk-s2:checked) .tk-paneel:nth-child(2),
.tk:has(#tk-s3:checked) .tk-paneel:nth-child(3),
.tk:has(#tk-s4:checked) .tk-paneel:nth-child(4),
.tk:has(#tk-s5:checked) .tk-paneel:nth-child(5),
.tk:has(#tk-s6:checked) .tk-paneel:nth-child(6),
.tk:has(#tk-s7:checked) .tk-paneel:nth-child(7),
.tk:has(#tk-s8:checked) .tk-paneel:nth-child(8) { visibility: visible; }

.tk:has(#tk-s1:checked) .tk-vak:nth-child(-n + 1),
.tk:has(#tk-s2:checked) .tk-vak:nth-child(-n + 2),
.tk:has(#tk-s3:checked) .tk-vak:nth-child(-n + 3),
.tk:has(#tk-s4:checked) .tk-vak:nth-child(-n + 4),
.tk:has(#tk-s5:checked) .tk-vak:nth-child(-n + 5),
.tk:has(#tk-s6:checked) .tk-vak:nth-child(-n + 6),
.tk:has(#tk-s7:checked) .tk-vak:nth-child(-n + 7),
.tk:has(#tk-s8:checked) .tk-vak:nth-child(-n + 8) { background: var(--green-600); }

.tk-knoppen { margin-top: clamp(20px, 2.6vw, 28px); }
.tk-belofte {
  margin: clamp(18px, 2.4vw, 24px) 0 0;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  max-width: var(--maat-tekst);
  font-size: .875rem;
  color: var(--ink-3);
}

/* De kop hoort alleen bij de terugvalstand hieronder. */
.tk-lijstkop { display: none; }

/* Zonder `:has()` — Firefox tot 121, Safari tot 15.4 — kan geen enkele regel
   hierboven een stand aanwijzen, en zou er precies nul bedragen op de
   prijspagina staan. Dan gaat de keuze eruit en staan alle staffels onder
   elkaar: dezelfde bedragen uit dezelfde bron, als lijst. */
@supports not (selector(:has(*))) {
  .tk-vraag,
  .tk-ladder { display: none; }

  .tk-lijstkop {
    display: block;
    margin: 0 0 4px;
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .02em;
    text-transform: uppercase;
    color: var(--ink-3);
  }

  .tk-panelen { display: block; margin-top: 0; }
  .tk-paneel {
    visibility: visible;
    padding: 14px 0;
    border-bottom: 1px solid var(--line);
  }
  .tk-paneel:last-child { border-bottom: 0; }
  .tk-euro { font-size: 1.625rem; }
  .tk-grenzen { margin-top: 4px; }
}

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

/* ------------------------------------------------------------ 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; }

/* --- de carrousel ----------------------------------------------------------

   Het spoor is een gewone lijst die horizontaal schuift met `scroll-snap`.
   Zonder JavaScript is dat de hele carrousel: veeg of sleep en je hebt ze alle
   zes gezien. `site.js` voegt er het automatisch doorschuiven en de bediening
   aan toe.

   ## Containerquery's, en nadrukkelijk geen `@media`

   Hoeveel reviews er naast elkaar passen hangt af van de **kolom** waarin de
   carrousel staat en niet van het scherm, en dat is op de homepage niet
   hetzelfde: naast de leeskolom staat het adrescheckpaneel, dus op een scherm
   van 1440px is die kolom ruim 700px. Met `@media (min-width: 1120px)` kwamen er
   dan drie kaarten van 230px naast elkaar te staan — drie woorden per regel, en
   een review die zo smal is leest niemand.

   De drempels hieronder gaan daarom over de containerbreedte: één kaart onder de
   520px, twee tot 840px, drie daarboven. Een kaart houdt zo altijd ruwweg 250px
   of meer.

   `container-type: inline-size` maakt van de carrousel tegelijk een
   containingblock voor `position: fixed`-nakomelingen. Er staat er hier geen —
   wie er ooit een toevoegt, moet dat weten.

   `overflow-x` op het spoor en niet op de sectie: de pagina zelf hoort nooit
   zijwaarts te bewegen. Zelfde regel als bij `.table-scroll`.

   Het spoor en zijn bediening zitten in één rasterblok, zodat de afstand
   ertussen hier vastligt en niet als losse marge op de bediening. Verdwijnt die
   bediening — bij één pagina, of zonder JavaScript — dan verdwijnt de ruimte
   mee. */
.reviews-carrousel {
  display: grid;
  gap: 16px;
  container-type: inline-size;
  container-name: reviews;
}

.reviews-spoor {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 100%;
  gap: 16px;
  margin: 0;
  padding: 0 0 4px;
  list-style: none;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  /* De scrollbalk hoort niet bij het ontwerp maar mag niet verdwijnen voor wie
     hem nodig heeft; `thin` is het compromis dat beide honoreert. */
  scrollbar-width: thin;
}
.reviews-spoor > li {
  scroll-snap-align: start;
  /* Rasterkinderen krijgen `min-width: auto`; zonder deze regel rekt een lange
     review zijn kolom op en klopt de paginabreedte niet meer. */
  min-width: 0;
  display: flex;
}
.reviews-spoor > li > .review { width: 100%; }

@container reviews (min-width: 520px) {
  .reviews-spoor { grid-auto-columns: calc((100% - 20px) / 2); gap: 20px; }
  /* De snapstap is één **pagina** en niet één kaart: het spoor schuift met twee
     tegelijk, dus alleen de eerste kaart van elk paar is een snappunt. Dat
     regelt `site.js` niet — het volgt uit de breedte die het spoor scrollt. */
  .reviews-spoor > li:nth-child(odd) { scroll-snap-align: start; }
  .reviews-spoor > li:nth-child(even) { scroll-snap-align: none; }
}
@container reviews (min-width: 840px) {
  .reviews-spoor { grid-auto-columns: calc((100% - 40px) / 3); }
  .reviews-spoor > li:nth-child(n) { scroll-snap-align: none; }
  .reviews-spoor > li:nth-child(3n + 1) { scroll-snap-align: start; }
}

/* De bediening staat `hidden` in de markup en wordt door `site.js` getoond —
   en alleen wanneer er werkelijk meer dan één pagina is. Een stippenrij onder
   twee reviews op een breed scherm wijst naar niets. */
.reviews-bediening {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
}
/* `display: flex` wint van het `hidden`-attribuut; zonder deze regel staat de
   bediening er zichtbaar bij zolang `site.js` niet draait. */
.reviews-bediening[hidden] { display: none; }

.reviews-stippen { display: flex; align-items: center; gap: 8px; }

/* De raakvlakregel van WCAG 2.2 (SC 2.5.8) vraagt 24×24. De stip zelf is 10px;
   de knop eromheen is 24px met doorzichtige rand, zodat het doel groot is en de
   stip klein blijft. */
.reviews-stip {
  width: 24px;
  height: 24px;
  padding: 7px;
  border: 0;
  background: none;
  cursor: pointer;
  display: grid;
  place-items: center;
}
.reviews-stip::before {
  content: "";
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--line-2);
  transition: background .2s;
}
.reviews-stip:hover::before { background: var(--ink-3); }
.reviews-stip.is-hier::before { background: var(--green-700); }
.reviews-stip:focus-visible { outline: 2px solid var(--green-700); outline-offset: 2px; border-radius: 50%; }

/* -------------------------------------------------------- 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; }

/* Dezelfde reden voor de werkschil van het portaal, met één verschil: daar staat
   naast het logo helemáál niets. Zonder deze regel houdt de balk de verticale
   ruimte van een kop met knoppen erin, en dat is boven een formulier van zeven
   velden de duurste lege ruimte van het scherm. Zie
   `App\Web\Content\PageRegistry::SHELL_PORTAAL`. */
.site-header.is-portaal .header-inner { gap: 12px; padding-block: 8px; }

/* 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,
/* Zelfde maat voor de werkschil: met de gewone voetruimte staat er onder een
   portaalscherm een halve schermhoogte donkergroen met drie links erin. */
.site-footer.is-portaal { 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; }

/* ══════════════════════════════════════════════════════════════════════════
   De over-pagina — richting "Portret"

   Hier stonden `.foto-figuur`, `.werk-foto` en `.tekst-foto`: de passe-partout
   en het tekst-naast-fotorooster van de vorige stand van `/over-label-logisch/`.
   Die pagina is herbouwd volgens de gekozen ontwerprichting en voert ze geen
   van alle nog — nagelopen met `grep` op `class="…"` over `templates/`, ze
   stonden alleen daar. Wat hieronder staat is nieuw en wordt ook alleen door
   die pagina gevoerd.

   ── De held ───────────────────────────────────────────────────────────────

   Eén beeld over de volle breedte met de naam eroverheen. De sectie draagt
   `padding: 0`, want de basisregel `section { padding-block: var(--ruimte) }`
   zou een witte band boven en onder de foto zetten en de held daarmee juist
   geen held maken.

   De verhouding kantelt mee met het scherm: staand 4:5 op een telefoon, liggend
   16:9 vanaf 700px. Dezelfde bron (1600 × 1049) voor allebei — een tweede
   bestand voor de smalle stand is hier niet nodig, want de uitsnede die ertoe
   doet (de handeling en het gezicht) zit in het midden-rechterdeel van het
   beeld en blijft bij beide verhoudingen in kader. `object-position` schuift
   alleen mee: 60% op smal, want daar valt links de gordijnhelft weg. */
.over-held { position: relative; padding: 0; background: var(--green-900); }
.over-held-foto {
  display: block; width: 100%;
  aspect-ratio: 4 / 5; object-fit: cover; object-position: 62% 40%;
  /* Iets doorschijnend, zodat de foto het groen eronder oppakt en het beeld
     zwart-wit-mét-merkkleur wordt in plaats van neutraal grijs. */
  opacity: .84;
  /* De hoogtegrens is het verschil tussen een held en een scherm vol foto: hij
     houdt op elk scherm een aanzet van de tekst eronder zichtbaar.
     `object-fit: cover` vangt het verschil op. */
  max-height: min(78vh, 800px);
}
/* 3:2 en niet 16:9. De bron is staand bijgesneden (1800 × 1366) en de handeling
   staat verticaal in het midden: de laser tegen het plafond, het gezicht, de
   tablet in de hand. Een 16:9-band knipt daar de bovenste en onderste derde
   vanaf en houdt een strook over waarin alleen het gezicht past — half, want de
   onderrand valt dan samen met de kin. Op 3:2 staat de hele handeling in beeld
   en blijft het gezicht boven de donkerste helft van het verloop. */
@media (min-width: 700px) {
  .over-held-foto { aspect-ratio: 3 / 2; object-position: 56% 34%; }
}

/* Het verloop doet het leeswerk. Onderaan is het vrijwel dicht, dus de kop
   staat feitelijk op een groen vlak en niet op een foto: de leesbaarheid hangt
   daardoor niet af van hoe licht de uitsnede daar toevallig uitvalt. Wit op
   `rgba(14,31,20,.94)` boven dit beeld haalt ruim 12:1. */
.over-held::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg,
    rgba(14, 31, 20, .06) 0%,
    rgba(14, 31, 20, .32) 50%,
    rgba(14, 31, 20, .70) 78%,
    rgba(14, 31, 20, .94) 100%);
}
.over-held-tekst {
  position: absolute; inset: auto 0 0 0; z-index: 2;
  padding-bottom: clamp(20px, 3.4vw, 44px);
}
.over-naam {
  margin: 0; color: #fff;
  font-size: clamp(2.25rem, 7.4vw, 4.25rem); line-height: 1.02; letter-spacing: -.015em;
}
/* De rolregel deelt de vorm van `.eyebrow` maar niet de kleur: op dit donkere
   vlak haalt `--green-700` geen contrast. `--green-300` (#86efac) haalt 9,8:1. */
.over-rol {
  margin: 12px 0 0; color: var(--green-300);
  font-size: .8125rem; font-weight: 700; letter-spacing: .11em; text-transform: uppercase;
}

/* ── De feitenband ─────────────────────────────────────────────────────────

   Vier feiten in dezelfde kleur als de onderkant van de held, zodat het één
   blok is en geen losse balk eronder. Geen opsommingstekens, wél een `<ul>`:
   het zíjn vier gelijkwaardige feiten.

   Op smal wordt het een tweekolomsraster in plaats van een rij die afbreekt:
   vier regels van wisselende lengte onder elkaar lezen als een lijstje dat
   niemand leest, twee kolommen als een keurmerkenrij. */
.over-strip {
  padding-block: 14px;
  background: var(--green-900); color: var(--green-200);
  border-top: 1px solid rgba(255, 255, 255, .10);
}
.over-strip ul {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 24px;
  font-size: .8125rem; letter-spacing: .04em;
}
@media (min-width: 760px) {
  .over-strip ul { display: flex; flex-wrap: wrap; gap: 10px 36px; }
}

/* ── Het verhaal in twee kolommen ──────────────────────────────────────────

   Links de belofte, rechts de onderbouwing. De tweede kolom is breder dan de
   eerste: daar staan drie alinea's tegenover een kop met één zin. Gelijke
   kolommen zouden links een halve kolom wit opleveren.

   `align-items: start`, anders zweeft de korte linkerkolom halverwege de
   rechter. */
.over-verhaal { display: grid; gap: var(--ruimte-klein); align-items: start; }
@media (min-width: 760px) {
  .over-verhaal { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: 56px; }
}
.over-verhaal h2 { margin-bottom: .4em; }
.over-verhaal p { max-width: var(--maat-tekst); }
.over-verhaal p + p { margin-top: 14px; }
.over-intro { font-size: 1.0625rem; color: var(--ink); }

/* ── Het citaat ────────────────────────────────────────────────────────────

   Eén zin in de schreefletter, in de maat van een `h2` maar zonder kopgewicht:
   dit is een rustpunt tussen twee tekstblokken en geen nieuwe sectiekop. Daarom
   ook geen aanhalingstekens in het beeld — de zin staat er alleen, dat is de
   aanhaling al — en geen citaatstreep aan de zijkant.

   Max. 24 tekens per regel: bij deze maat breekt de zin in drie korte regels en
   dát maakt hem tot een rustpunt. Over de volle leesbreedte zou het gewoon een
   grote alinea zijn. */
/* De groene band komt van de homepage: `.ochtend::before` voert hetzelfde
   verloop (`--green-100 → --green-50`, 160deg) met een verticaal masker eroverheen.
   Vandaar dezelfde opzet hier — een pseudo-element met `z-index: -1` in een eigen
   stapelcontext, en niet een `background` op de sectie zelf. Twee redenen: een
   masker op de sectie zou ook de tekst laten vervagen, en met een kale
   achtergrond krijgt het blok twee harde randen tussen twee witte secties, wat
   het tot een doos maakt in plaats van tot een rustpunt.

   Het masker vervaagt aan beide kanten: het citaat staat tussen twee witte
   blokken, dus de kleur moet ook aan de bovenkant uit het wit komen. */
.over-citaat { position: relative; isolation: isolate; }
.over-citaat::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(160deg, var(--green-100) 0%, var(--green-50) 65%, var(--green-50) 100%);
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 20%, #000 74%, transparent 100%);
          mask-image: linear-gradient(180deg, transparent 0%, #000 20%, #000 74%, transparent 100%);
}
.over-citaat blockquote {
  margin: 0; font-family: var(--display); font-weight: 400;
  font-size: clamp(1.375rem, 3.4vw, 2rem); line-height: 1.3;
  letter-spacing: -.01em; max-width: 24ch;
}
/* `--ink-2` en niet het grijs van een gewoon onderschrift: op #dcfce7 haalt
   `--ink-3` maar 4,0:1 en dit is kleine, vette tekst. */
.over-citaat-bron {
  margin: 16px 0 0; color: var(--ink-2);
  font-size: .8125rem; font-weight: 700; letter-spacing: .11em; text-transform: uppercase;
}

/* ── De werkfoto naast de kenmerken ────────────────────────────────────────

   Beeld links, tekst rechts, en onder 760px stapelt het met het beeld bovenaan.
   In de gestapelde stand is de foto begrensd op 420px: zonder die grens vult
   hij op een tablet de hele leeskolom en wordt hij 728 × 910 — een scherm vol
   foto tussen twee blokken tekst.

   `align-items: center`: naast de vier kenmerken staat een staand beeld dat
   hoger is dan de lijst, en bovenaan uitlijnen laat het er onderuit steken. */
.over-duo { display: grid; gap: var(--ruimte-klein); align-items: center; }
.over-duo-foto { margin: 0; max-width: 420px; }
.over-duo-foto img {
  display: block; width: 100%; height: auto;
  border-radius: var(--radius); background: var(--sand-2);
}
@media (min-width: 760px) {
  .over-duo { grid-template-columns: minmax(0, 320px) minmax(0, 1fr); gap: 48px; }
  .over-duo-foto { max-width: none; }
}
@media (min-width: 1100px) {
  .over-duo { grid-template-columns: minmax(0, 380px) minmax(0, 1fr); gap: 64px; }
}
.over-duo h2 { margin-bottom: .55em; }
/* De check-list heeft `margin: 0`, dus zonder deze regel plakt de slotregel met
   de bedrijfsgegevens tegen het laatste kenmerk aan. */
.over-duo-slot { margin-top: 24px; color: var(--ink-3); font-size: .9375rem; }

/* 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 onder de dagen: vorige links, volgende rechts. Op een
   smalle telefoon breken ze om; de lege `<span>` houdt "Volgende" dan rechts. */
.venster-nav {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 10px 12px;
  margin-bottom: 18px;
}
.venster-bereik { margin: 0 0 10px; font-size: .875rem; }

/* ──────────────────────────────────────────────────────────────────────────
   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);
}

/* De kaart is een `<figure>`, en die krijgt van de browser 40px marge links en
   rechts. Daardoor sprongen de kaarten in ten opzichte van de kop erboven en
   stond er tussen twee kaarten ruim 100px lucht. */
.review { margin: 0; }

/* Een groot aanhalingsteken boven het citaat: zo leest de kaart als iets wat
   iemand anders zei, en niet als tekst van de site zelf. Versiering, dus in
   CSS en niet in de tekst: een schermlezer leest het niet voor. */
.review blockquote::before {
  content: "\201C";
  display: block;
  height: .5em;
  margin-bottom: .15em;
  font-family: var(--display);
  font-size: 3rem;
  line-height: 1;
  color: var(--green-700);
}
.review blockquote p { margin: 0; }

/* --- 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 spoedkeuze op de bevestiging, in de afspraakkaart boven het kenmerk. */
.bev-spoed { margin: 14px 0 0; padding-top: 14px; border-top: 1px solid var(--line); }
.bev-spoed strong { color: var(--ink); }

/* --- 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; }

/* De bron van de oppervlakte, direct onder "110 m² gebruiksoppervlakte". Klein
   en rustig: hij onderbouwt het getal erboven en is geen tweede boodschap. */
/* ── De gegevensstap, compact (2026-10-04) ───────────────────────────────

   Floor: "erg erg groot opgezet". Minder lucht tussen de velden, voor- en
   achternaam ook op een telefoon naast elkaar, "Handig om te weten?" als
   uitklaplinkje en een kleinere blok "na het versturen". De velden zelf houden
   hun 44px-tikmaat en 16px-letter. */
.gegevens-intro { margin: 0 0 14px; color: var(--ink-2); font-size: .9375rem; }
.gegevens-compact .fieldset-bare { margin-bottom: 12px; }
.gegevens-compact .grid { gap: 12px; }
.gegevens-naam { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 10px; }
.gegevens-opmerking { margin: 0 0 12px; }
.gegevens-opmerking > summary {
  display: inline-flex; align-items: center; gap: 4px; min-height: 32px;
  cursor: pointer; list-style: none;
  color: var(--green-800); font-size: .875rem; font-weight: 600;
  text-decoration: underline; text-underline-offset: 2px;
}
.gegevens-opmerking > summary::-webkit-details-marker { display: none; }
.gegevens-opmerking > summary::before { content: "+"; font-weight: 700; text-decoration: none; }
.gegevens-opmerking[open] > summary::before { content: "−"; }
.gegevens-opmerking > summary .muted { font-weight: 400; text-decoration: none; }
.gegevens-opmerking .field { margin-top: 6px; }
.gegevens-opmerking .field-label {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.gegevens-compact .check { padding-block: 10px; }
.gegevens-compact .na-versturen { margin: 14px 0 2px; padding: 12px 14px; font-size: .875rem; }
.gegevens-compact .na-versturen-kop { margin-bottom: 6px; }
.gegevens-compact .na-versturen .check-list { gap: 4px; }

/* "Wat gebeurt er na het versturen?" op de gegevensstap, direct boven de knop. */
.na-versturen {
  margin: 20px 0 4px;
  padding: 16px 18px;
  border: 1px solid var(--green-200);
  border-radius: var(--radius);
  background: var(--green-50);
  color: var(--ink-2);
}
.na-versturen-kop {
  margin: 0 0 10px;
  color: var(--green-900);
  font-weight: 700;
}
.na-versturen strong { color: var(--green-900); }

/* De herkomst van de oppervlakte als label, zodat meteen te zien is of het getal
   uit de BAG (Kadaster) komt of zelf is ingevuld. */
.pk-bron {
  display: inline-block;
  margin: 6px 0 0;
  padding: 3px 10px;
  border-radius: 999px;
  border: 1px solid var(--green-200);
  background: var(--green-50);
  color: var(--green-900);
  font-size: .875rem;
  font-weight: 600;
  line-height: 1.4;
}
.pk-bron--klant {
  border-color: var(--amber-200);
  background: var(--amber-50);
  color: var(--amber-700);
}

/* De oppervlakte als invoerveld in de prijskaart (sinds 2026-10-04): een klein
   getal in de zin "118 m² gebruiksoppervlakte", met alleen een gestippelde
   onderlijn — geen groot wit invoervak (Floor: "iets subtieler"). Bij hover en
   focus wordt het vlak wit, zodat zichtbaar is dat je erin kunt typen. Zonder
   JavaScript staat er een kleine "Herbereken"-knop naast; met JavaScript rekent
   het veld vanzelf mee (`site.js`) en is die knop `hidden`. De letter blijft de
   16px van `.input`, zodat iOS niet inzoomt. */
.pk-woning {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 6px;
  margin: 6px 0 0; color: var(--ink-2); font-size: .9375rem;
}
.prijskaart .pk-m2 {
  width: 3.2em; min-height: 0; height: auto;
  padding: 1px 4px;
  background: transparent;
  border: 0; border-bottom: 1.5px dashed var(--green-700); border-radius: 4px 4px 0 0;
  box-shadow: none;
  font-weight: 700; color: var(--ink); text-align: center;
}
.prijskaart .pk-m2:hover,
.prijskaart .pk-m2:focus { background: #fff; }
.pk-m2-label { margin: 0; font-weight: 400; color: var(--ink-2); }
.pk-m2-knop {
  min-height: 24px; padding: 0 2px;
  background: none; border: 0; cursor: pointer;
  color: var(--green-800); font: inherit; font-size: .875rem; font-weight: 600;
  text-decoration: underline; text-underline-offset: 2px;
}
.pk-m2-knop[hidden] { display: none; }
.pk-woning.has-error .pk-m2 { border-bottom-color: var(--danger); }
.prijskaart .field-error { margin: 6px 0 0; }
.pk-m2-hint { margin: 6px 0 0; color: var(--ink-3); font-size: .8125rem; line-height: 1.4; }
/* Tijdens de herberekening: het oude bedrag vervaagt, zodat niemand het voor
   de nieuwe prijs aanziet. */
.prijskaart.is-bezig .pk-bedrag,
.prijskaart.is-bezig .pk-normaal,
.prijskaart.is-bezig .pk-korting { opacity: .35; transition: opacity .15s; }

/* Een bedrag breekt niet tussen "€" en het getal. */
.nowrap { white-space: nowrap; }

/* De actiecode op de prijskaart: de normale prijs klein en doorgestreept, de
   korting in de merkkleur, en daaronder "Jouw prijs" als het ene grote bedrag. */
.pk-normaal { margin: 18px 0 0; color: var(--ink-3); font-size: .9375rem; }
.pk-normaal s { color: var(--ink-3); }
.pk-korting { margin: 2px 0 0; color: var(--green-900); font-weight: 700; font-size: .9375rem; }
.pk-normaal + .pk-korting + .pk-label { margin-top: 10px; }

/* Het actiecodeformulier onder de prijskaart. Dezelfde opbouw als de eigen
   oppervlakte: label over de volle breedte, veld en knop naast elkaar zodra er
   ruimte is, onder elkaar op een telefoon. */
.actiecode { margin: 0 0 22px; }
.actiecode-veld { display: grid; gap: 10px; margin: 0; }
.actiecode-veld .field-label { margin: 0; }
.actiecode-veld .input { text-transform: uppercase; }
.actiecode-veld .field-error { margin: 0; }
@media (min-width: 560px) {
  .actiecode-veld { grid-template-columns: minmax(0, 240px) auto; justify-content: start; column-gap: 12px; row-gap: 6px; }
  .actiecode-veld .field-label { grid-column: 1 / -1; grid-row: 1; }
  .actiecode-veld .input { grid-column: 1; grid-row: 2; }
  .actiecode-veld > .btn { grid-column: 2; grid-row: 2; width: auto; justify-self: start; }
  .actiecode-veld .field-error { grid-column: 1 / -1; grid-row: 3; }
}
.actiecode-toegepast { margin: 0 0 10px; color: var(--ink-2); }
.actiecode-toegepast strong { color: var(--green-900); }
.actiecode-weg { width: auto; }

/* De normale prijs op de controlestap: klein, en niet het bedrag dat geldt. */
.kv-normaal dt,
.kv-normaal dd { color: var(--ink-3); font-size: .9375rem; }

/* De spoedkeuze: een gewone `.check`, met ruimte tussen de kop en de uitleg. */
.spoedkeuze .check strong { color: var(--ink); }
.spoedkeuze .field-hint { margin-top: 8px; }

/* De drie acties onder de prijs. Op een telefoon onder elkaar, met de primaire
   knop bovenaan (dat doet `.booking-nav` al); vanaf 480px op één rij. */
.prijs-acties .btn { white-space: normal; }

/* "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.
   170px zodat "wo 14 oktober" op één regel past: dan zijn alle veertien kaarten
   even hoog, met of zonder tijden. */
.dagen {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(170px, 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 dag zonder tijden is geen knop en hoort er ook niet als een uit te zien,
   maar staat wel even hoog in het raster als de knoppen ernaast. */
.dag.is-leeg .dag-blok {
  display: flex; flex-direction: column; justify-content: center; gap: 3px;
  min-height: var(--tap); margin-bottom: 0;
  border: 1px dashed var(--line); border-radius: var(--radius);
  padding: 12px 14px; color: var(--ink-3);
}
.dag.is-leeg .dag-kop { font-family: var(--font); font-size: 1rem; line-height: inherit; margin: 0; color: var(--ink-2); }
.dag.is-leeg .muted { margin: 0; font-size: .8125rem; }
.dag-knop, .dag.is-leeg .dag-blok { height: 100%; }

/* 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; } }

/* ------------------------------------------- 24. de samenwerkpagina

   Twee blokken die alleen op `/samenwerken/` staan: de drie werkwijzen en de
   band die het partnerportaal aankondigt. Ze staan hier onderaan en niet bij de
   kaarten (blok 11), omdat een werkwijze géén kaart is: hij heeft een vaste
   inhoudelijke opbouw — rol, naam, één zin, vier regels, één knop — en die
   opbouw is wat de drie kolommen vergelijkbaar maakt. Wie er `.card` van maakt,
   verliest precies dat.
   -------------------------------------------------------------------------- */

/* De sectie staat buiten `.lees` en dus in de volle `.wrap`; de eigen leesmaat
   hangt daarom aan de tekst en niet aan de kolom. */
.werkwijzen-lead, .beloften-lead { max-width: var(--maat-lead); font-size: var(--g-1); color: var(--ink-2); }
/* `.werkwijzen-voet` stond hier voor de slotalinea onder de drie werkwijzen
   ("Je legt je keuze niet vast…"). Die alinea is er op verzoek uit; de klasse
   is daarmee vervallen. */

/* ── De toegangsregel in de paginakop ──────────────────────────────────────
   Drie routes, in rangorde. Twee knoppen voor wie nog geen account heeft (een
   eerste opdracht bespreken, of een korte kennismaking), een rustige noot dat een
   account daarna volgt, en een kleine tekstlink "Inloggen" voor wie al
   samenwerkt. "Account aanmaken" staat hier niet meer: een account is geen eerste
   drempel.

   De verticale ruimte komt van `.paginakop-onder` (`margin-top: 24px`); deze
   regels voegen daar niets aan toe. */
.samenwerken-toegang { display: grid; gap: 12px; justify-items: start; }
.samenwerken-toegang-knoppen { display: flex; flex-wrap: wrap; gap: 12px; }
.samenwerken-toegang-noot,
.samenwerken-toegang-inlog { margin: 0; font-size: .9375rem; color: var(--ink-2); }
/* Klein, maar een volwaardig tikdoel: 24 px hoog haalt WCAG 2.2 SC 2.5.8. */
.samenwerken-toegang-inlog a {
  display: inline-flex; align-items: center; min-height: 24px; padding: 2px 0;
  font-weight: 600;
}
@media (max-width: 639px) {
  /* Onder elkaar en over de volle breedte: twee knoppen die halverwege afbreken
     lezen slechter dan twee die op elkaar staan. */
  .samenwerken-toegang { justify-items: stretch; }
  .samenwerken-toegang-knoppen { display: grid; gap: 10px; }
  .samenwerken-toegang-knoppen .btn { width: 100%; }
}

/* "Zo beginnen we": drie korte zinnen, geen kaarten en geen knoppen. */
.samenwerken-stappen { display: grid; gap: 12px; margin: 16px 0 0; padding-left: 1.25rem; max-width: 46rem; }
.samenwerken-stappen li { padding-left: 4px; }
.samenwerken-stappen strong { display: block; color: var(--ink); }

/* ── Het samenwerkingsverzoek ──────────────────────────────────────────────
   De keuze woning/kennismaken hergebruikt de `.choice`-kaarten van de
   boekingsflow. Het woningblok staat alleen open bij "Ik heb al een concrete
   woning". Zonder `:has()` blijft het altijd zichtbaar: dan kan het adres nog
   steeds ingevuld worden, en de server bewaart het alleen bij die keuze. */
.verzoek-keuze { border: 0; margin: 0; padding: 0; min-width: 0; }
.verzoek-keuze legend { padding: 0; margin-bottom: 8px; }
.verzoek-keuze .choice-grid { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.verzoek-keuze.has-error .choice { border-color: var(--danger); }
@supports selector(:has(a)) {
  .verzoek-form .verzoek-woning { display: none; }
  .verzoek-form:has(#vz-keuze-woning:checked) .verzoek-woning { display: grid; }
}
.verzoek-ander { margin-top: 24px; }

/* De vakgebieden. Geen filter en geen keuze: het is een opsomming die in één
   oogopslag zegt dat deze pagina breder is dan makelaars. Daarom ook geen
   knopvorm — iets wat eruitziet als een knop en niet klikt, is een fout. */
.vakgebieden {
  display: flex; flex-wrap: wrap; gap: 8px;
  list-style: none; padding-left: 0; margin: 18px 0 0; max-width: none;
}
.vakgebied {
  border: 1px solid var(--line-2); border-radius: 999px;
  padding: 5px 13px; font-size: .875rem; color: var(--ink-2); background: var(--paper);
}

/* Drie gelijkwaardige kolommen. Op 640px worden het er twee en blijft de derde
   alleen achter; dat is hier aanvaardbaar omdat de derde werkwijze ("op jouw
   manier") ook inhoudelijk de uitzondering is. Onder 640px staan ze onder
   elkaar in de volgorde 1, 2, 3 — en niet met de uitgelichte bovenaan, want dan
   klopt de nummering in de koppen niet meer met wat er staat. */
.werkwijzen {
  display: grid; gap: 16px; margin: 26px 0 0;
  list-style: none; padding-left: 0; max-width: none;
}
@media (min-width: 640px) { .werkwijzen { grid-template-columns: repeat(2, 1fr); gap: 20px; } }
@media (min-width: 1000px) { .werkwijzen { grid-template-columns: repeat(3, 1fr); } }

/* `display: flex` met `min-width: 0`: een lange `dd` zonder spaties mag de kolom
   niet oprekken, en de voet moet met `margin-top: auto` onderaan kunnen staan
   zodat de drie knoppen op één lijn eindigen. */
/* De vulling is hetzelfde ochtendlicht als het uitklapdeel op `/werkwijze/`:
   dezelfde 160 graden als `.ochtend::before` op de homepage, een trap lichter
   (`--green-50 → --paper` in plaats van `--green-100 → --green-50`) en eindigend
   op papier in plaats van op transparant, want een masker zou ook de tekst en de
   knop laten vervagen — zie `.balie` en `.tb-detail`.

   De kaart is hoog en de knop staat onderaan: de 62%-stop zorgt dat het groen op
   is vóór de voet, zodat de knop op papier staat en de vier regels van de `<dl>`
   over een egale ondergrond lopen. */
.werkwijze {
  display: flex; flex-direction: column; min-width: 0;
  background: linear-gradient(160deg, var(--green-50) 0%, var(--green-50) 32%, var(--paper) 62%);
  border: 1px solid var(--line);
  border-radius: var(--radius); overflow: hidden;
}

/* De uitgelichte kolom draagt een groene rand en een groene kop, en géén
   schaduw of vergroting: hij mag opvallen zonder de andere twee tot alternatief
   te degraderen. De `box-shadow` is de tweede randlijn — een 2px-rand zou de
   kolom 1px smaller maken dan zijn buren en de drie koppen uit lijn duwen. */
.werkwijze-uitgelicht { border-color: var(--green-700); box-shadow: inset 0 0 0 1px var(--green-700); }

/* De kop had een eigen zandvlak (en groen op de uitgelichte kolom). Dat kan nu
   niet meer: een tweede vulling bovenop de kaart knipt het verloop juist af op de
   plek waar het het lichtst hoort te beginnen. De scheidingslijn blijft staan —
   die deed het werk, niet de kleur. */
.werkwijze-kop { padding: 18px 20px 14px; background: transparent; border-bottom: 1px solid var(--line); }
.werkwijze-uitgelicht .werkwijze-kop { border-bottom-color: var(--green-200); }

.werkwijze-rol {
  display: block; font-size: .75rem; font-weight: 700; letter-spacing: .11em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 6px;
}
.werkwijze-uitgelicht .werkwijze-rol { color: var(--green-800); }

.werkwijze-kop h3 { font-size: var(--g-1); margin: 0; }
.werkwijze-lead-klein { margin: 6px 0 0; font-size: .9375rem; color: var(--ink-3); }

/* De vier regels. Een `<dl>` en geen lijst met vetgedrukte aanhef: "Jij doet"
   is werkelijk de term en de zin erachter de beschrijving, en een schermlezer
   leest dat verband dan ook voor.

   Twee kolommen vanaf 400px: de termen zijn kort en vast, dus een vaste kolom
   van 84px houdt de vier zinnen onder elkaar uitgelijnd. Daaronder stapelen ze,
   want 84px van 320px is een kwart van de regel. */
.werkwijze-rollen { margin: 0; padding: 16px 20px; display: grid; gap: 10px; font-size: .9375rem; }
.werkwijze-rollen dt {
  font-size: .75rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-3);
}
.werkwijze-rollen dd { margin: 2px 0 0; color: var(--ink-2); }
@media (min-width: 400px) {
  .werkwijze-rollen { grid-template-columns: 84px 1fr; gap: 12px 14px; align-items: start; }
  .werkwijze-rollen dt { padding-top: 2px; }
  .werkwijze-rollen dd { margin-top: 0; }
}

.werkwijze-voet { margin: auto 0 0; padding: 0 20px 20px; }

/* ── de doelgroepen ─────────────────────────────────────────────────────────

   Vier kaarten in `ul.grid.grid-2`, dezelfde vorm als de drie contactkaarten.
   Er is hier daarom bijna niets eigens nodig: alleen de afstand tot de
   opsomming erboven, en de slotregel eronder.

   Géén `.grid-4`. De kaarten dragen drie tot vier regels tekst, en vier kolommen
   van 270px maken daar acht regels van — dan is de rij hoger dan twee rijen van
   twee. */
.doelgroepen { margin: 22px 0 0; }
.doelgroepen-rest {
  margin-top: 22px; max-width: var(--maat-tekst);
  font-size: .9375rem; color: var(--ink-2);
}

/* ══ De contactpagina: het formulier met de balie ernaast ═══════════════

   Ontwerprichting A ("Balie"), gekozen op 2026-09-13. Het formulier links, en
   rechts een blok dat de hele tijd zichtbaar houdt wie er antwoordt, op welk
   nummer, en of dat nú kan. Zie `templates/site/pages/contact.php` en
   {@see App\Web\Contact\OfficeHours}.

   Eén markup, twee verschijningen: op desktop is de balie een kolom naast het
   formulier, op mobiel een actiebalk erboven. Dat schakelt hier en niet in PHP,
   zodat het telefoonnummer één keer in de HTML staat. */

/* De tweedeling. Mobiel één kolom met de balie **eerst** — daar is hij een
   actiebalk en hoort hij bovenaan; op desktop staat hij rechts en keert de
   volgorde om. `order` en geen tweede HTML-blok, om dezelfde reden als boven.

   De grens ligt op 1000px en niet op 900: de leeskolom is daaronder te smal om
   een formulier én een kaart naast elkaar te dragen zonder dat het tekstvak
   onder de veertig tekens per regel duikt. Dat is dezelfde grens waarop
   `.mobiele-cta` verdwijnt, zodat er niet twee verschillende "nu is het
   desktop"-momenten op één pagina bestaan. */
.contact-split { display: grid; grid-template-columns: 1fr; gap: 24px; }
.contact-split > .balie        { order: -1; }
.contact-split > .contact-form { min-width: 0; }

@media (min-width: 1000px) {
  .contact-split {
    grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr);
    gap: 32px;
    align-items: start;
  }
  .contact-split > .balie { order: 0; }
}

/* Zonder formulier (geen mailconfiguratie) draagt de balie de volle breedte in
   plaats van een lege kolom naast zich te laten staan. */
.contact-split-leeg { grid-template-columns: 1fr; }
@media (min-width: 1000px) { .contact-split-leeg { grid-template-columns: 1fr; } }

/* ── De balie zelf ──────────────────────────────────────────────────── */

/* De balie draagt het ochtendlicht van de homepage.

   Dezelfde hoek en dezelfde drie tokens als `.ochtend::before`: 160 graden, van
   `--green-100` linksboven naar `--green-50`. Dat is niet "ook een groen
   verloopje" maar letterlijk de band die uit LabelLogisch 1.0 komt, zodat de
   contactpagina en de homepage hetzelfde licht voeren.

   Waar het afwijkt, en waarom het moet afwijken: de homepageband vervaagt met
   een **masker** naar transparant. Een masker op dit blok zou ook de tekst en de
   knop erin laten vervagen — een masker werkt op het hele element en niet alleen
   op zijn vulling. En hem op een `::before` zetten zoals `.ochtend` doet, levert
   een kaart op waarvan de vulling onderaan oplost terwijl de rand er nog
   omheen staat: een kader om niets.

   Daarom eindigt het verloop hier op `--paper` in plaats van op transparant. Dat
   geeft hetzelfde beeld — groen bovenin, wit onderin, de knop op papier — met een
   rand die overal iets omsluit. De 55% is de stop waarop het homepagemasker
   begint te vervagen. */
.balie {
  border: 1px solid var(--green-200);
  border-radius: var(--radius);
  background: linear-gradient(160deg,
              var(--green-100) 0%,
              var(--green-50) 55%,
              var(--paper) 100%);
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* Meescrollen, maar alleen waar dat kan. `sticky` heeft een hoogtegrens nodig:
   op een kort venster zou een plakkende kaart de onderkant van zichzelf
   afsnijden en is er geen manier meer om bij de knop onderin te komen. 640px is
   ruim de hoogte van de kaart zelf.

   `--header-h` plus ademruimte, want de paginakop is vast en zou er anders
   overheen komen te staan. */
@media (min-width: 1000px) and (min-height: 640px) {
  .balie { position: sticky; top: calc(var(--header-h) + 16px); }
}

.balie-kop { display: flex; align-items: center; gap: 12px; }

/* `<picture>` is een gewone inline-container en wordt hier een flexitem. Zonder
   `flex: none` rekt hij mee met de vrije ruimte en staat de foto niet meer tegen
   de naam aan; `display: flex` haalt de regelafstand onder de `<img>` weg die
   een inline-element anders meebrengt. */
.balie-kop > picture { flex: none; display: flex; }

/* Het portret. De bronafbeelding is 160×160, dus hij wordt fors verkleind —
   `object-fit: cover` staat er voor de dag dat er een niet-vierkante foto voor
   in de plaats komt; zonder die regel wordt die dan uitgerekt in plaats van
   bijgesneden.

   De haarlijn eromheen is er omdat de balie een groene ondergrond heeft: zonder
   rand loopt een lichte achtergrond in de foto over in het vlak eromheen en
   lijkt het rondje ingedeukt. */
.balie-portret {
  width: 46px; height: 46px; flex: none;
  border-radius: 50%;
  object-fit: cover;
  background: var(--paper);
  box-shadow: 0 0 0 1px var(--green-200);
}

.balie-naam { font-weight: 700; color: var(--ink); margin: 0; }
.balie-rol  { font-size: .8125rem; color: var(--ink-3); margin: 0; }

/* De drie kanalen. Op desktop regels met een naam links en de waarde rechts; op
   mobiel drie tikdoelen naast elkaar waarin alleen de naam past — het
   telefoonnummer zelf staat dan in de `href`, waar een telefoon het toch al
   vandaan haalt. */
.balie-kanalen { list-style: none; margin: 0; padding: 0; }
.balie-kanalen a {
  display: grid;
  grid-template-columns: 74px 1fr;
  align-items: baseline;
  gap: 10px;
  padding: 11px 0;
  border-top: 1px solid var(--green-200);
  min-height: var(--tap);
  text-decoration: none;
}
.balie-kanalen li:first-child a { border-top: 0; padding-top: 0; }
.balie-kanalen a:hover .bk-waarde { text-decoration: underline; }

.bk-naam {
  font-size: .75rem; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-3);
}
.bk-waarde { font-weight: 650; color: var(--green-800); }

@media (max-width: 999px) {
  .balie-kanalen {
    display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;
  }
  .balie-kanalen a {
    display: flex; align-items: center; justify-content: center;
    padding: 10px 6px;
    border-top: 0;
    border: 1px solid var(--green-200);
    border-radius: var(--radius-sm);
    background: var(--paper);
  }
  .balie-kanalen li:first-child a { padding-top: 10px; }
  /* De waarde verdwijnt, niet de betekenis: de naam blijft staan en het
     `href` draagt het nummer. Daarom `display: none` en geen `.sr-only` —
     een schermlezer leest hier anders "Bellen 06 44382787 link" met het
     nummer cijfer voor cijfer. */
  .bk-waarde { display: none; }
  .bk-naam {
    font-size: .8125rem; letter-spacing: 0; text-transform: none;
    font-weight: 650; color: var(--green-800);
  }
}

/* ── De bereikbaarheidsstand ────────────────────────────────────────── */

.balie-status { display: flex; flex-direction: column; gap: 4px; }

.balie-nu {
  display: flex; align-items: center; gap: 8px;
  font-size: .875rem; font-weight: 650; color: var(--ink-2); margin: 0;
}

/* Het stipje is decoratie; de toestand staat in de tekst ernaast. Kleur alleen
   is geen informatie — dat is WCAG 1.4.1 en hier is het bovendien het verschil
   tussen "bel gerust" en "je krijgt de voicemail". Grijs is de dichte stand, en
   die is de standaard: staat `is-open` er om wat voor reden dan ook niet op,
   dan belooft de pagina niets wat ze niet waar kan maken. */
.balie-stip {
  width: 8px; height: 8px; flex: none;
  border-radius: 50%;
  background: var(--ink-3);
}
.balie-nu.is-open .balie-stip { background: var(--green-600); }

.balie-venster { font-size: .8125rem; color: var(--ink-3); margin: 0; }
.balie-noot    { font-size: .8125rem; color: var(--ink-3); margin: 0; line-height: 1.45; }

/* De knop vult de balie; hij is de enige actie in dit blok en een halve knop
   naast lege ruimte leest als een detail in plaats van als een uitweg.

   De rand is een tint sterker dan die van `.btn-ghost` elders, en dat is een
   gevolg van het verloop hierboven: onderin de balie is de vulling `--paper`, en
   een witte spookknop op wit papier hangt daar aan een rand van `--green-200`
   alleen. Alleen hier opgehoogd, want alleen hier staat hij op het lichte eind
   van een verloop. */
.balie-knop {
  display: flex; justify-content: center; width: 100%;
  border-color: var(--green-300);
}

/* ── De voet: klachten, zakelijk, toegankelijkheid ──────────────────── */

.contact-voet {
  display: grid; grid-template-columns: 1fr; gap: 26px;
  border-top: 1px solid var(--line);
  padding-top: 26px;
}
@media (min-width: 760px) { .contact-voet { grid-template-columns: 1fr 1fr; gap: 32px; } }

.contact-voet-stapel { display: flex; flex-direction: column; gap: 22px; }

/* Kleiner dan de koppen erboven: dit is wat je moet kúnnen vinden, niet wat je
   moet lezen. `.lees h2` zet de marge eronder; die blijft gelden. */
.contact-voet h2 { font-size: 1rem; }
.contact-voet p  { font-size: .875rem; }

/* Het uitklapbare deel van de klachtenprocedure. Geen driehoekje van de
   browser: `list-style: none` plus het WebKit-pseudo-element, want Safari
   negeert de eerste. De eigen chevron draait mee met de stand. */
.contact-details { margin-top: 12px; }
.contact-details > summary {
  display: flex; align-items: center; gap: 8px;
  list-style: none;
  cursor: pointer;
  font-size: .875rem; font-weight: 650; color: var(--green-700);
  min-height: var(--tap);
}
.contact-details > summary::-webkit-details-marker { display: none; }
.contact-details > summary::before {
  content: ""; width: 7px; height: 7px; flex: none;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(-45deg); margin-left: 2px;
  transition: transform .15s ease;
}
.contact-details[open] > summary::before { transform: rotate(45deg); margin-top: -3px; }
@media (prefers-reduced-motion: reduce) {
  .contact-details > summary::before { transition: none; }
}
.contact-details > summary:hover { color: var(--green-800); }

.contact-details-body { display: flex; flex-direction: column; gap: 10px; padding-top: 10px; }
.contact-details-body ol { margin: 0; padding-left: 1.25em; display: flex; flex-direction: column; gap: 8px; }
.contact-details-body li { font-size: .875rem; }

/* ── de beloften ──────────────────────────────────────────────────────────

   Zes regels die voor alle drie de werkwijzen gelden. Geen `.card` en geen
   `.check-list`: een kaart is hier de vorm van een wérkwijze en een vinkjeslijst
   is de vorm van kleine lettertjes. Wat overblijft is een haarlijn met een groen
   kopstuk — hetzelfde ritme als de kolommen erboven, zonder ze na te doen. */
.beloften {
  display: grid; gap: 22px 28px; margin: 26px 0 0;
  list-style: none; padding-left: 0; max-width: none;
}
@media (min-width: 640px) { .beloften { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .beloften { grid-template-columns: repeat(3, 1fr); } }

/* De lijn is een `border-top` op het item zelf en geen `::before`: hij hoort bij
   de regel en niet bij de kop, en moet dus de volle kolombreedte houden ook als
   de kop over twee regels loopt. Het groene kopstuk is wél een `::before`, want
   dat is decoratie bovenop diezelfde lijn. */
.belofte { position: relative; padding-top: 16px; border-top: 1px solid var(--line); min-width: 0; }
.belofte::before {
  content: ""; position: absolute; top: -1px; left: 0;
  width: 34px; height: 2px; background: var(--green-700);
}
.belofte h3 { font-size: 1.0625rem; margin: 0 0 6px; }
.belofte p { margin: 0; color: var(--ink-2); font-size: .9375rem; max-width: none; }

/* Een gekleurde band direct onder de paginakop plakte tegen de leadzin aan. Dat
   is het gevolg van twee regels die apart allebei kloppen: `.paginakop` draagt
   `padding-block: var(--ruimte) 0` en `.paginakop .lead` draagt
   `margin-bottom: 0`, dus tussen de laatste regel van de intro en de kleurwissel
   staat nul ruimte. Op een witte vervolgsectie valt dat niet op, op `/samenwerken/`
   wel: daar begint het zandkleurige werkwijzenblok precies onder de zin.

   De ruimte hangt aan de kop en niet aan de band. De band heeft zijn eigen
   binnenruimte al, en die groter maken zou lucht ín het vlak zetten in plaats van
   erboven. `--ruimte-klein` en niet `--ruimte`: de kop en het blok eronder horen
   bij elkaar, precies zoals de regel hierboven over `.paginakop + section` zegt. */
.paginakop:has(+ .bg-sand),
.paginakop:has(+ .bg-green),
.paginakop:has(+ .bg-ink) { padding-bottom: var(--ruimte-klein); }


/* ------------------------------------- 25. de energielabelhub
   -------------------------------------------------------------------------

   `/energielabel-aanvragen/` is de langste pagina van de site: acht
   hoofdstukken met samen een kleine tweeduizend woorden. Wat deze ronde
   toevoegt is geen opmaak maar oriëntatie — drie ingangen boven, genummerde
   hoofdstukken, en een rail die dezelfde nummers draagt.

   Alles hieronder hangt aan klassen die alleen dit sjabloon voert (`hub-`,
   `hst-`). De gedeelde bouwstenen die de pagina gebruikt — `.check-list`,
   `.notice`, `.steps`, `.tiers`, `.postcheck`, `.arrow-link` — blijven wat ze
   overal zijn; er staat hieronder geen enkele regel die er iets aan verandert.
   -------------------------------------------------------------------------- */

/* ── de adrescheck naast de kop ─────────────────────────────────────────────

   Op de hub staat de adrescheck rechts van de titel in plaats van eronder. Dat
   is een zaak van deze pagina, en de gedeelde `paginakop` hoort er dus geen
   vierde variant voor te krijgen. De haak is `:has()` op het omhulsel dat het
   sjabloon meegeeft: alleen een paginakop die een `.hub-adres` draagt, wordt
   tweekolommig. Op elke andere pagina raakt deze regel niets.

   Onder 1000px blijft het gewoon de stapeling: een adrescheck naast een `<h1>`
   in een kolom van 40 tekens is geen tweedeling maar twee smalle stroken. */
.hub-adres { scroll-margin-top: calc(var(--header-h) + 20px); }
.hub-adres:focus:not(:focus-visible) { outline: none; }

@media (min-width: 1000px) {
  .paginakop:has(.hub-adres) > .wrap {
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
    column-gap: clamp(28px, 3.4vw, 52px);
    align-items: start;
  }

  /* De drie kopelementen in de eerste kolom, in hun eigen volgorde; het paneel
     ernaast over de volle hoogte. Expliciete rijen en niet `grid-auto-flow`:
     met automatische plaatsing zou het paneel in rij 4 belanden en dus ónder de
     intro, precies wat deze regel opheft. */
  .paginakop:has(.hub-adres) > .wrap > .eyebrow { grid-column: 1; grid-row: 1; }
  .paginakop:has(.hub-adres) > .wrap > h1       { grid-column: 1; grid-row: 2; }
  .paginakop:has(.hub-adres) > .wrap > .lead    { grid-column: 1; grid-row: 3; }

  .paginakop:has(.hub-adres) > .wrap > .paginakop-onder {
    grid-column: 2;
    grid-row: 1 / 5;
    margin-top: 0;
  }
}

/* ── de drie ingangen ─────────────────────────────────────────────────────── */

.hub-ingangen-sectie { padding-block: var(--ruimte-klein) 0; }

.hub-ingangen {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 14px;
}
@media (min-width: 760px) {
  .hub-ingangen { grid-template-columns: repeat(3, 1fr); }
}

/* Een kaart die één link is en niet een kaart met een link erin: de hele tegel
   is het tikdoel, en er staat maar één bestemming in. Daarom een `<a>` met
   blokinhoud en geen tweede `<a>` op de pijlregel — die zou een tweede
   tabstop zijn naar dezelfde plek. */
.hub-ingang {
  display: flex;
  flex-direction: column;
  gap: 6px;
  height: 100%;
  padding: 20px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  text-decoration: none;
  color: var(--ink-2);
  transition: border-color .15s, transform .15s;
}
.hub-ingang:hover { border-color: var(--green-600); transform: translateY(-2px); }
.hub-ingang:focus-visible { outline: 3px solid var(--green-700); outline-offset: 2px; }

.hub-ingang b {
  font-family: var(--display);
  font-size: 1.1875rem;
  font-weight: 700;
  color: var(--ink);
  line-height: 1.2;
}
.hub-ingang span { font-size: .9375rem; line-height: 1.55; }

/* De pijlregel onderaan, ook als de teksten ongelijk lang zijn: `margin-top:
   auto` duwt hem naar de voet van de tegel, zodat de drie pijlen op één lijn
   staan. `.arrow-link` levert de pijl en de beweging; hij staat hier op een
   `<em>` en niet op een link, want de tegel is de link. */
.hub-ingang .arrow-link {
  margin-top: auto;
  padding-top: 10px;
  font-style: normal;
  font-weight: 600;
  font-size: .9375rem;
  color: var(--green-700);
}

@media (prefers-reduced-motion: reduce) {
  .hub-ingang { transition: none; }
  .hub-ingang:hover { transform: none; }
}

/* ── de hoofdstukken en de rail ───────────────────────────────────────────── */

.hub { display: grid; gap: clamp(24px, 3vw, 44px); }
@media (min-width: 1000px) {
  .hub { grid-template-columns: 210px minmax(0, 1fr); align-items: start; }
}

/* De rail is er alleen waar hij past. Onder 1000px zou hij een tweede
   inhoudsopgave boven de inhoud zijn — dat is precies wat de drie ingangen al
   doen, korter en met meer uitleg. `display: none` en niet visueel verbergen:
   de koppen eronder staan gewoon in de leesvolgorde, dus er gaat geen
   navigatie verloren. */
.hub-rail { display: none; }

@media (min-width: 1000px) {
  .hub-rail {
    display: block;
    position: sticky;
    top: calc(var(--header-h) + 16px);
    align-self: start;
  }

  .hub-rail-kop {
    margin: 0 0 10px;
    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--ink-3);
  }

  .hub-rail ol {
    list-style: none;
    margin: 0;
    padding: 0;
    counter-reset: hub;
    display: grid;
    gap: 2px;
  }
  .hub-rail li { counter-increment: hub; }

  /* Het nummer komt uit dezelfde teller als de kop ernaast; de sjabloonlijst
     bepaalt de volgorde, de stylesheet telt. Zo kan een hoofdstuk erbij zonder
     dat hier iets bijgeteld hoeft te worden. */
  .hub-rail a {
    display: grid;
    grid-template-columns: 22px 1fr;
    gap: 6px;
    padding: 7px 0 7px 12px;
    border-left: 2px solid var(--line);
    color: var(--ink-2);
    text-decoration: none;
    font-size: .875rem;
    line-height: 1.4;
  }
  .hub-rail a::before {
    content: counter(hub, decimal-leading-zero);
    font-family: var(--data);
    font-size: .75rem;
    color: var(--ink-3);
  }
  .hub-rail a:hover { border-left-color: var(--green-600); color: var(--ink); }
  .hub-rail a:hover::before { color: var(--green-700); }
  .hub-rail a:focus-visible { outline: 3px solid var(--green-700); outline-offset: 2px; }
}

.hub-inhoud { display: grid; gap: clamp(28px, 4vw, 52px); min-width: 0; }

.hst { scroll-margin-top: calc(var(--header-h) + 20px); }

.hst-kop { display: flex; align-items: baseline; gap: 12px; margin-bottom: 4px; }
.hst-kop h2 { margin: 0; font-size: var(--g-2); }

.hst-nr {
  flex: none;
  font-family: var(--data);
  font-size: .75rem;
  font-weight: 700;
  color: var(--green-700);
  border: 1px solid var(--green-200);
  border-radius: 999px;
  padding: 2px 9px;
}

/* Twee blokken binnen één hoofdstuk — de opname en wat je klaarlegt, de
   geldigheid en het nieuwe label na verduurzaming — krijgen een haarlijn en
   niet een tweede kop-met-nummer: het zijn twee alinea's van hetzelfde
   onderwerp en geen twee hoofdstukken. */
.hst-blok { padding-top: clamp(16px, 2.2vw, 24px); }
.hst-blok + .hst-blok {
  margin-top: clamp(16px, 2.2vw, 24px);
  border-top: 1px solid var(--line);
}
.hst-blok > h3 { margin-bottom: .35em; }
.hst-blok > p,
.hst-blok > ul,
.hst-blok > ol { max-width: var(--maat-tekst); }
/* De stappen en de vinklijst met twee kolommen mogen wél de volle kolom
   gebruiken: die staan naast elkaar en niet als lopende regel. */
.hst-blok > .steps,
.hst-blok > .check-list-2 { max-width: none; }

/* De bronvermelding onder de verplichtingenlijst. Een streep en niet cursief:
   dit is de herkomst van de lijst erboven, en die hoort zichtbaar bij dat blok
   te horen zonder de toon van een voetnoot in kleine letters te krijgen. */
.hub-bron {
  border-left: 2px solid var(--line);
  padding-left: 12px;
  color: var(--ink-3);
  font-size: .875rem;
}

/* ═══════════════════════════════════════════════════════════════════════════
   MAKELAARSPORTAAL
   ═══════════════════════════════════════════════════════════════════════════

   De schermen achter `/makelaar/`. Ze delen alles met de rest van de site —
   `.wrap`, `.lees`, `.grid`, `.field`, `.notice`, `.btn` — en voegen precies
   drie dingen toe die elders niet voorkomen: een balk met wie er is ingelogd,
   een tabel met gelijksoortige regels, en een prijsblok.

   Er staat hier geen enkele kleur- of maatwaarde die niet uit de tokens komt.
   Een portaal dat zijn eigen groen meebrengt, is een portaal dat bij de
   volgende huisstijlronde achterblijft. */

/* ── De balk met wie er is ingelogd ──────────────────────────────────────── */

/* Boven de paginakop en binnen dezelfde `.wrap`-breedte. Op een telefoon
   stapelt hij: de naam is belangrijker dan de knoppen, en twee regels is beter
   dan een uitlogknop die van het scherm valt. */
/* Het vlak loopt van rand tot rand, de **inhoud** lijnt uit met `.wrap`. Met een
   `max-width` op het vlak zelf eindigde de zandkleurige strook op een breed scherm
   halverwege de pagina, met wit ernaast — dan leest hij als een zwevend blok in
   plaats van als een balk onder de kop. De `max()` houdt de linkerkant gelijk aan
   de containerrand zolang die er is, en valt daaronder terug op de gewone
   schermmarge. */
.partner-bar {
  padding-block: 12px;
  padding-inline: max(clamp(16px, 4vw, 32px), calc((100% - var(--container)) / 2 + 32px));
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 16px;
  border-bottom: 1px solid var(--line);
  background: var(--sand);
}
.partner-bar-wie {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  font-size: .9375rem;
}
.partner-bar-naam { font-weight: 600; }
.partner-bar-kantoor { color: var(--ink-3); }

/* De navigatie draagt een link én een formulier (uitloggen is een POST; zie
   `templates/site/partner/kop.php`). Het formulier krijgt `margin: 0` omdat het
   anders de verticale ritmeregel van de layout meeneemt en de balk scheef
   trekt. */
.partner-bar-nav {
  display: flex;
  align-items: center;
  gap: 16px;
  font-size: .9375rem;
}
.partner-bar-nav form { margin: 0; }

/* ── De aanvragentabel ───────────────────────────────────────────────────── */

/* De scroller zit om de tabel heen en niet om de pagina: een tabel met vijf
   kolommen past niet op een telefoon, en de oplossing daarvoor is nooit dat de
   pagina zelf zijwaarts beweegt. `overflow-x: auto` op een eigen omhulsel houdt
   de beweging binnen het kader.

   `-webkit-overflow-scrolling` staat er niet: die is sinds iOS 13 de standaard
   en het weglaten scheelt een regel die niemand meer kan uitleggen. */
.table-scroll {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--paper);
}
.table {
  width: 100%;
  min-width: 640px;
  border-collapse: collapse;
  font-size: .9375rem;
}
.table th,
.table td {
  padding: 10px 14px;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--line);
}
.table thead th {
  font-size: .8125rem;
  font-weight: 600;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: .04em;
  white-space: nowrap;
}
/* Geen streep onder de laatste rij: die valt anders samen met de rand van het
   omhulsel en leest als een dubbele lijn. */
.table tbody tr:last-child td { border-bottom: 0; }

/* De tweede regel in een cel: postcode en plaats onder het adres, de prijsbron
   onder het bedrag. Een `<span>` en geen `<small>`, want dit is geen
   kleingedrukte tekst maar een tweede gegeven van dezelfde soort. */
.muted-block {
  display: block;
  margin-top: 2px;
  color: var(--ink-3);
  font-size: .875rem;
}

/* Een code of een bedrag dat overgetypt of vergeleken wordt. Dezelfde familie
   als de rest van de site gebruikt voor cijferwerk. */
.mono {
  font-family: var(--data);
  letter-spacing: .04em;
}

/* ═══ Het aanvraagblad ═══════════════════════════════════════════════════════

   De schermen van de aanvraagronde dragen het voorvoegsel `ma-` (makelaar). Ze
   vervangen `.partner-prijs`, `.partner-woning` en het gebruik van `.lees` op
   deze pagina's.

   ## Waarom deze schermen `.lees` niet gebruiken

   `.lees` is de **leeskolom**: zijn ritmiek is `--ruimte-klein`, tussen de 22 en
   36 px, en zijn tekstmaat is 66ch. Dat klopt voor een pagina die gelezen wordt
   en niet voor een formulier dat ingevuld wordt. Op 390px kostte die ritmiek
   tussen de vier blokken van het aanvraagscherm meer dan honderd pixels aan
   witruimte — een half toestelscherm dat niets zegt.

   `.ma-blad` zet daarom zijn eigen kolombreedte en zijn eigen sprong, en die
   sprong is een vaste 18px. Vast en niet `clamp()`: de afstand tussen twee
   velden hoort op een telefoon en op een desktop hetzelfde te zijn, want het is
   dezelfde handeling. */

.ma-sectie { padding-block: clamp(20px, 4vw, 40px); }

.ma-blad { max-width: 620px; }
/* Het overzicht draagt een tabel en heeft de volle breedte nodig; het formulier
   niet. Eén klasse erbij is goedkoper dan een tweede blad. */
.ma-blad-breed { max-width: var(--container); }
.ma-blad > * + * { margin-top: 18px; }

/* De paginakop van deze schermen. Kleiner dan `h1` van de site: dit is geen
   inhoudspagina met een boodschap maar een werkscherm, en een kop van 2,25rem
   duwt op 390px het eerste veld onder de vouw. */
.ma-titel {
  margin: 0;
  font-size: clamp(1.375rem, 1.2rem + 1vw, 1.75rem);
  line-height: 1.2;
}

/* Kop en knop op één regel zodra er ruimte is. Op een telefoon onder elkaar, met
   de knop op volle breedte — dat is daar het grootste tapdoel dat er te maken
   valt. */
.ma-titelrij {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.ma-titelrij .btn { flex: 1 1 100%; justify-content: center; }
@media (min-width: 560px) {
  .ma-titelrij .btn { flex: 0 0 auto; }
}

/* Een blok velden met zijn kop. `<form>` is het element; deze klasse geeft hem
   alleen de ritmiek, zodat de twee formulieren van het aanvraagscherm als één
   doorlopend blad lezen en niet als twee kaarten. */
.ma-groep > * + * { margin-top: 14px; }

/* De kop van zo'n blok. Nadrukkelijk klein: hij verdeelt het scherm en trekt er
   geen aandacht naartoe. `.lees h2` geldt hier niet — dat is de leeskolom. */
.ma-kop {
  margin: 0;
  font-family: inherit;
  font-size: .8125rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* ── De adresrij ─────────────────────────────────────────────────────────── */

/* Postcode, huisnummer en toevoeging. Op een telefoon staan de twee **verplichte**
   velden naast elkaar en krijgt de toevoeging de regel eronder; vanaf 560px passen
   ze met z'n drieën op één regel.

   Die verdeling volgt niet de inhoud van de vélden maar de breedte van hun
   **labels**. "2712 AB" en "A" zijn allebei kort, maar "Toevoeging (optioneel)" is
   ruim twee keer zo breed als "Postcode": in een halve kolom breekt hij over twee
   regels, en dan staat zijn invoerveld twintig pixels lager dan het veld ernaast.
   Met de toevoeging op een eigen volle regel kan dat bij geen enkele breedte meer
   gebeuren — en het groepeert bovendien wat bij elkaar hoort, want postcode en
   huisnummer zijn samen de zoekopdracht.

   De kolomverdeling vanaf 560px is om dezelfde reden 1,1 : 1 : 1,5 en niet het
   voor de hand liggende 2 : 1 : 1. */
.ma-adresrij {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}
.ma-adresrij > *:last-child { grid-column: 1 / -1; }
@media (min-width: 560px) {
  .ma-adresrij { grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr) minmax(0, 1.5fr); }
  .ma-adresrij > *:last-child { grid-column: auto; }
}

/* ── De adrescontrole ────────────────────────────────────────────────────── */

/* Het terugkoppelblok onder de adresvelden: gevonden woning of herstelmelding,
   altijd op dezelfde plek. Klein, met een streep aan de zijkant in plaats van
   een volledig kader — het is een bevestiging bij een veld en geen mededeling
   van de site.

   Geen `.notice`: die draagt 16px padding rondom, een eigen rand en een vetgedrukte
   eerste regel, en is daarmee zwaarder dan het blok waar hij onder hangt. */
.ma-bag {
  padding: 10px 14px;
  border-left: 3px solid var(--line-2);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: var(--sand);
  font-size: .9375rem;
}
.ma-bag p { margin: 0; }
.ma-bag p + p { margin-top: 3px; }
.ma-bag-adres { font-weight: 600; color: var(--ink); }
.ma-bag-feiten { color: var(--ink-2); }

.ma-bag-ok   { border-left-color: var(--green-700); background: var(--green-50); }
/* De foutstand draagt zijn betekenis in de tekst en niet alleen in de kleur; de
   melding zegt zelf wat er mis is en wat de uitweg is. De kleur bevestigt dat
   alleen. */
.ma-bag-fout { border-left-color: var(--danger); background: var(--danger-bg); color: var(--danger); }
.ma-bag-fout a { color: inherit; }

/* ── De tariefregel ──────────────────────────────────────────────────────── */

/* Eén regel, nooit een blok met bedragen. Zie `App\Web\Partner\PartnerTariffLine`
   voor waarom een makelaar geen kaal publiek websitetarief te zien krijgt.

   Het bedrag staat rechts en in de cijferfamilie, zodat het te lezen is zonder
   de zin ernaast te lezen. Op een telefoon valt het onder de tekst in plaats van
   ernaast te blijven persen. */
.ma-tarief {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 16px;
  margin: 0;
  padding: 12px 14px;
  border: 1px solid var(--green-200);
  border-radius: var(--radius-sm);
  background: var(--green-50);
  font-size: .9375rem;
}
.ma-tarief-tekst  { font-weight: 600; color: var(--green-900); }
.ma-tarief-bedrag { font-family: var(--data); font-weight: 700; color: var(--green-900); }
.ma-tarief-bron   { color: var(--ink-2); }

/* Zonder afspraak is er niets om uit te lichten: dan is het een gewone
   mededeling en geen groen vlak. */
.ma-tarief-open {
  border-color: var(--line);
  background: var(--sand);
}
.ma-tarief-open .ma-tarief-tekst { color: var(--ink-2); font-weight: 600; }

/* ── De rest van het blad ────────────────────────────────────────────────── */

.ma-velden > * + * { margin-top: 14px; }

/* E-mailadres en telefoonnummer naast elkaar zodra het past. Onder de 560px
   nooit: een telefoonnummerveld van 150px breed is geen tijdwinst. */
.ma-duo { display: grid; grid-template-columns: 1fr; gap: 14px; }
@media (min-width: 560px) { .ma-duo { grid-template-columns: 1fr 1fr; } }

.ma-knoprij { display: flex; flex-wrap: wrap; gap: 12px; margin: 0; }
/* Op een telefoon vult de knop de breedte; vanaf 560px krimpt hij tot zijn
   inhoud. Een knop van 350px breed op een desktop leest als een banner. */
.ma-knoprij .btn { flex: 1 1 100%; justify-content: center; }
@media (min-width: 560px) {
  .ma-knoprij .btn { flex: 0 0 auto; }
}
/* Behalve de kleine. "Ander adres" is een terugweg en geen actie: hem op een
   telefoon net zo breed maken als "Aanvraag versturen" geeft twee knoppen die
   even hard roepen, en de opdracht vraagt om één duidelijke primaire knop. */
.ma-knoprij .btn-sm { flex: 0 0 auto; }

.ma-voet { margin: 0; color: var(--ink-3); font-size: .8125rem; }

/* De gegevens van één ingediende aanvraag. Onder elkaar op een telefoon, vanaf
   560px twee kolommen met het label rechts uitgelijnd tegen zijn waarde. */
.ma-lijst {
  margin: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: 4px 20px;
  font-size: .9375rem;
}
.ma-lijst dt { color: var(--ink-3); }
.ma-lijst dd { margin: 0 0 10px; }
@media (min-width: 560px) {
  .ma-lijst { grid-template-columns: max-content 1fr; align-items: baseline; }
  .ma-lijst dt { text-align: right; }
  .ma-lijst dd { margin-bottom: 4px; }
}

/* De labelknop: klein genoeg voor een tabelcel, groot genoeg om aan te tikken.

   `.btn` staat op `min-height: var(--tap)` (44px) en dat is de juiste maat voor een
   knop die alleen op een scherm staat. In een tabelrij naast vijf andere kolommen maakt
   hij de regel anderhalf keer zo hoog, en dan leest de lijst als een reeks knoppen met
   wat tekst ertussen in plaats van andersom.

   32px is de ondergrens die hier verantwoord is: WCAG 2.2 SC 2.5.8 vraagt 24x24 CSS-px
   voor een doel dat niet uitgezonderd is, en dat halen we met ruimte over. De breedte
   volgt vanzelf uit de tekst en is altijd ruimer dan de hoogte.

   `white-space: nowrap` omdat "Energielabel downloaden" anders midden in een smalle
   kolom afbreekt; de tabel scrollt al horizontaal binnen `.table-scroll`, dus er is
   ruimte om niet af te breken. */
.btn-klein {
  min-height: 32px;
  padding: 6px 14px;
  font-size: .875rem;
  white-space: nowrap;
}

/* De actiebalk van de homepage. Alleen aanwezig wanneer de beheerder een geldige
   homepageactie heeft; anders staat er geen element en dus ook geen ruimte. De
   tekst is van de beheerder en kan een lange code bevatten: `overflow-wrap`
   breekt die af in plaats van de pagina op 390px breder te maken dan het scherm. */
.actiebalk {
  background: var(--green-800);
  color: var(--ink-on-dark);
}
.actiebalk-tekst {
  margin: 0;
  padding-block: 8px;
  font-size: .875rem;
  font-weight: 600;
  line-height: 1.4;
  text-align: center;
  overflow-wrap: anywhere;
}
@media (min-width: 640px) { .actiebalk-tekst { font-size: 1.0625rem; padding-block: 14px; } }
@media (max-width: 639px) {
  .actiebalk-tekst { padding-block: 6px; }
  .actiebalk-label { font-size: .8125rem; padding: 2px 8px; }
}

/* Het label is de ingestelde korting ("20% korting") in de stickerkleur, zodat
   het getal het eerste is wat je leest. */
.actiebalk-label {
  display: inline-block;
  margin-right: 8px;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--sticker);
  color: var(--sticker-ink);
  font-size: .875rem;
  font-weight: 800;
  letter-spacing: .02em;
  white-space: nowrap;
  vertical-align: 1px;
}

/* De kortingssticker rechtsboven op het aanvraagpaneel. Hij hangt aan `.paneel`
   (de kaart knipt af met `overflow: hidden`) en steekt over de rand van de kaart,
   licht gedraaid. Binnen de breedte van het paneel, dus geen horizontale scroll
   op 390px. `pointer-events: none`: hij mag het formulier eronder nooit
   blokkeren.
   `relative` alleen onder 1000px: daarboven is het paneel `sticky` (zie
   `.paneel` hoger in dit bestand), en dat is al een bevattend blok voor de
   sticker. Een kale `.paneel { position: relative; }` hier overschreef die
   sticky en liet het paneel op desktop niet meer meelopen. */
@media (max-width: 999px) { .paneel { position: relative; } }
.actiesticker {
  position: absolute;
  z-index: 2;
  /* Mobiel klein en grotendeels bóven de kaart: zo blijft de toelichting
     eronder leesbaar. */
  top: -36px;
  right: 8px;
  margin: 0;
  display: grid;
  place-items: center;
  align-content: center;
  width: 78px;
  height: 78px;
  border-radius: 50%;
  background: var(--sticker);
  color: var(--sticker-ink);
  box-shadow: 0 6px 16px rgba(17, 33, 26, .22);
  transform: rotate(10deg);
  font-size: .75rem;
  font-weight: 700;
  line-height: 1.05;
  text-align: center;
  pointer-events: none;
}
.actiesticker-getal {
  font-size: 1.3rem;
  font-weight: 900;
  letter-spacing: -.02em;
}
@media (min-width: 560px) {
  .actiesticker { top: -26px; right: 10px; width: 104px; height: 104px; font-size: .8125rem; }
  .actiesticker-getal { font-size: 1.75rem; }
}
/* Pas naast de kop steekt hij over de rand: daaronder is het paneel schermbreed
   en zou een negatieve `right` horizontale scroll geven (768px: 2px). */
@media (min-width: 1000px) { .actiesticker { right: -14px; } }
/* Onder 1000px staat het paneel onder de intro en steekt de sticker boven de
   kaart uit (`top` hierboven). Zonder extra ruimte viel hij over de laatste
   regel van de intro (390px, 2026-10-04). Alleen met sticker; zonder actie
   blijft de afstand zoals hij was. */
@media (max-width: 999px) {
  .paneel-met-sticker { margin-top: 32px; }
}
@media (min-width: 560px) and (max-width: 999px) {
  .paneel-met-sticker { margin-top: 28px; }
}

/* ── Aanvraag eerst: "Plan direct je afspraak" (2026-10) ─────────────────────

   De sectie op de ontvangstpagina. Sinds 2026-10-04 staat de bestaande momentkiezer
   er direct in (`.dagen`, `.tijdrooster`, de dialoog), met dezelfde regels als toen
   hij nog een eigen stap was; er is geen ingeklapte stand meer.

   `min-width: 0` op de kaart: de kaart staat in een leeskolom, en een raster van
   170px-kolommen mag die kolom niet breder maken dan het scherm. Geen
   `overflow: hidden` — dat zou de focusringen van de tijden afknippen. */
/* De ontvangstpagina (2026-10-03): één kaart met wat er binnen is, dan direct de
   agenda, dan de andere route. */
.ontvangst .lees > * + * { margin-top: 20px; }
.ontvangst-kaart {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 18px 20px;
  box-shadow: var(--shadow-sm);
}
.ontvangst-status {
  display: inline-flex; align-items: center; gap: 8px;
  margin: 0 0 6px;
  padding: 3px 12px 3px 10px;
  border-radius: 999px;
  background: var(--green-50);
  border: 1px solid var(--green-200);
  color: var(--green-900);
  font-size: .875rem; font-weight: 700;
}
.ontvangst-status::before { content: "✓"; color: var(--green-700); }
.ontvangst-email { overflow-wrap: anywhere; }
.ontvangst-noot {
  max-width: none;
  margin: 12px 0 0;
  padding: 12px 14px;
  border-radius: var(--radius);
  background: var(--sand-2);
  color: var(--ink-2);
  font-size: .9375rem;
  line-height: 1.5;
}
.ontvangst-noot strong { display: block; color: var(--ink); }
.agenda-uitleg { margin: 4px 0 0; color: var(--ink-2); }
.ontvangst .agenda-sectie { padding: 22px 22px 20px; }
@media (max-width: 420px) { .ontvangst .agenda-sectie { padding: 18px 14px 16px; } }
.ontvangst-anders h2 { font-size: var(--g-1); }

.agenda-sectie {
  min-width: 0;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 20px;
  border-color: var(--green-200);
  box-shadow: var(--shadow);
}
.agenda-sectie > h2 { margin-top: 0; }
.agenda-sectie .btn-row { margin-bottom: 0; }
.agenda-blok { min-width: 0; margin-top: 12px; }
.agenda-blok .booking-nav { margin-top: 8px; }
@media (max-width: 420px) {
  .agenda-sectie { padding: 16px 14px; }
  .agenda-sectie .dagen { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
}
