/* Sennasearch V2 — base: reset, typografie, container, gedeelde componenten.
   Sectie-specifieke opmaak hoort in css/sections/sX.css. */

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

/* [hidden] MOET WINNEN (Timo 2026-08-21).
   `display:none` voor [hidden] komt uit de browser zelf, en een regel uit de
   browser verliest van ELKE regel van ons — ook van een enkele klasse. Elk
   element met een eigen display-regel is daarmee onverbergbaar via het
   hidden-attribuut, zonder dat er iets stukgaat of iets meldt.

   Dit heeft dit project inmiddels drie keer geraakt:
     - de "Kies een moment"-knop bleef staan op stap 3 (.btn), en een klik erop
       toonde een NEP-bevestiging zonder boeking — 20 augustus, toen opgelost met
       een inline style.display op die ene knop;
     - het datumveld op de afzegpagina (.field{display:flex}) stond er altijd,
       bij elke afzegreden, in plaats van alleen bij "komt nu niet uit";
     - het hele afzegformulier (.af-form{display:grid}) stond er al voordat de
       afspraak geladen was, en bleef staan als de link niet klopte.
   De laatste twee zijn op 21 augustus gemeten in een echte browser; ze zaten er
   sinds 19 augustus in en waren nooit in een browser bekeken.

   Eén regel met !important zet dat voor de hele site recht. Wie hierna een
   element wél zichtbaar wil houden terwijl het hidden draagt, heeft geen
   hidden-attribuut nodig maar een klasse. */
[hidden] { display: none !important; }

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-body-size);
  line-height: 1.6;
  color: var(--text-body);
  background: var(--surface-cream);
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

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

::selection { background: var(--orange-500); color: #fff; }

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

/* ---------- Typografie ---------- */

h1, h2, h3, .display {
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: .005em;
  line-height: .95;
  margin: 0;
  color: var(--text-strong);
}
h1 { font-size: var(--text-h1); }
h2 { font-size: var(--text-h2); }
h3 { font-size: var(--text-h3); }

.on-dark h1, .on-dark h2, .on-dark h3,
h1.inv, h2.inv, h3.inv { color: var(--text-strong-inv); }

/* Kop-punt: canon = RONDE oranje punt op de baseline (vormsysteem-recept:
   inline-block cirkel .14em, Anton's eigen punt is vierkantig) */
h1 .dot, h2 .dot, h3 .dot {
  display: inline-block;
  width: .14em;
  height: .14em;
  margin-left: .06em;
  border-radius: 50%;
  background: var(--orange-500);
  color: transparent;
  overflow: hidden;
  vertical-align: baseline;
}

/* Kop-staart: bindt het LAATSTE woord van een kop aan de kop-punt.
   Toegevoegd 2026-08-11 na de visuele controle van de Engelse site. Bestond
   hiervoor niet; er stond alleen de .dot-regel hierboven.

   Waarom: .dot is display:inline-block en telt bij het regelafbreken dus als
   een atomair inline-vak. Chromium mag daar voor afbreken, ook al staat er
   geen spatie in de bron. Op en/about-us.html viel de punt daardoor als los
   bolletje op een eigen regel (gemeten @320 en @1024). s1.css regel 245 en 267
   zeggen expliciet dat de kop-punt nooit hoort te wrappen; daar werd dat per
   pagina met de font-maat opgelost, wat bij andere tekstlengtes weer breekt.

   text-wrap:pretty lost het in Chromium ook op, maar Firefox kent dat niet,
   dus dan blijft de punt daar alsnog los staan. white-space:nowrap werkt
   overal. Gemeten effect op de kopafmetingen: geen (272x167 en 707x134 voor
   en na). */
.kop-staart { white-space: nowrap; }

p { margin: 0; }
.lead { font-size: var(--text-lead); line-height: 1.55; }

/* Eyebrow met oranje ticks (canon, vormsysteem §04) */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: .5em;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.eyebrow::before { content: '\231C'; } /* ⌜ */
.eyebrow::after  { content: '\231D'; } /* ⌝ */
.eyebrow::before, .eyebrow::after {
  color: var(--orange-500);
  font-weight: 700;
  transform: translateY(-.1em);
}
.on-dark .eyebrow, .eyebrow.inv { color: var(--orange-500); }

/* Korte oranje kicker-lijn */
.kicker-line {
  width: 52px;
  border: 0;
  border-top: var(--kicker);
  border-radius: 2px;
  margin: 0;
}

/* Pill / tag / badge */
.pill {
  display: inline-flex;
  align-items: center;
  gap: .5em;
  border: 1px solid var(--text-strong);
  border-radius: var(--r-pill);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  padding: 7px 16px;
  color: var(--text-strong);
}
.pill--inv { border-color: rgba(255, 255, 255, .35); color: #fff; }
.pill--blue { background: var(--blue-100); border-color: var(--blue-100); color: var(--navy-950); }

/* ---------- Knoppen ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  padding: 14px 24px;
  border-radius: var(--r-sm);
  transition: background-color .18s ease, color .18s ease, border-color .18s ease, transform .18s ease, box-shadow .18s ease;
}
/* De pijl was een tekstglyph (&rarr;). Die hangt aan het lettertype en rendeerde
   haarfijn naast de zware knoplabels, terwijl de knop zelf 700 tot 800 weegt.
   Sinds 2026-08-24 is het een inline SVG met een eigen lijndikte, zodat de vorm
   niet meer afhangt van welk font er laadt of van welk gewicht de knop erft.
   1em maakt hem meeschalen met het label, dus een kleine link krijgt vanzelf een
   kleine pijl. De vertical-align corrigeert dat een SVG op de onderkant van de
   regel gaat staan in plaats van optisch in het midden. */
.arr { display: inline-flex; align-items: center; vertical-align: -0.14em; }
.arr svg { width: 1em; height: 1em; display: block; }

.btn .arr { transition: transform .18s ease; }
.btn:hover .arr { transform: translateX(3px); }

/* Hover-lift (V1-recept, P25): knop komt subtiel omhoog en groeit iets.
   V1 deed scale(1.05) + oranje CTA-schaduw op de orange-knop en scale(1.04)
   op de outline; hier vertaald naar translateY+scale zodat "omhoog/groter"
   allebei zichtbaar zijn. Kleurgedrag blijft ongewijzigd. */
.btn--primary { background: var(--orange-500); color: #fff; }
.btn--primary:hover {
  background: var(--orange-600);
  transform: translateY(-2px) scale(1.03);
  box-shadow: 0 10px 26px color-mix(in srgb, var(--orange-500) 32%, transparent);
}

.btn--ghost { border: 1px solid var(--text-strong); color: var(--text-strong); padding: 13px 23px; }
.btn--ghost:hover {
  border-color: var(--orange-500);
  color: var(--orange-600);
  /* Geen schaduw: transparante achtergrond (conform V1-outline) */
  transform: translateY(-2px) scale(1.02);
}
.on-dark .btn--ghost, .btn--ghost.inv { border-color: rgba(255, 255, 255, .55); color: #fff; }
.on-dark .btn--ghost:hover, .btn--ghost.inv:hover { border-color: var(--orange-500); color: #fff; }

/* Indruk bij :active NA de :hover-regels, zodat de press bij gelijke
   specificiteit via bronvolgorde wint tijdens hover+press (V1-recept). */
.btn:active { transform: scale(.97); }

@media (prefers-reduced-motion: reduce) {
  /* Geen lift/schaduwstap bij reduced motion; kleur-hover blijft. */
  .btn--primary:hover, .btn--ghost:hover { transform: none; box-shadow: none; }
}

.btn--link {
  padding: 0 0 4px;
  border-radius: 0;
  border-bottom: 2px solid var(--orange-500);
  color: var(--text-strong);
}
.btn--link:hover { color: var(--orange-600); }
.btn--link .arr { color: var(--orange-500); }
.on-dark .btn--link { color: #fff; }

/* Play-knop: altijd gevulde oranje cirkel + witte driehoek */
.play-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--orange-500);
  transition: transform .18s ease, background-color .18s ease;
  flex: none;
}
.play-btn::after {
  content: '';
  width: 0; height: 0;
  border-left: 16px solid #fff;
  border-top: 10px solid transparent;
  border-bottom: 10px solid transparent;
  margin-left: 4px;
}
.play-btn:hover { background: var(--orange-600); transform: scale(1.06); }

/* Ronde pijl-knoppen (carrousel) */
.circle-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, .45);
  color: #fff;
  transition: background-color .18s ease, border-color .18s ease;
  flex: none;
}
.circle-btn:hover { background: var(--orange-500); border-color: var(--orange-500); }

/* Nummer-badge (vormsysteem canon) */
.num-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--navy-950);
  color: #fff;
  font-family: var(--font-display);
  font-size: 18px;
  flex: none;
}

/* ---------- Secties ---------- */

.section { padding-block: var(--space-section); }
.section--dark { background: var(--surface-deep); }
.section--dark, .section--dark .lead { color: var(--text-body-inv); }

/* Kaarten op licht: 1px rand + zachte schaduw. Op donker: rand ÓF liftkleur. */
.card {
  background: var(--surface-card);
  border: 1px solid var(--line-paper);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-card);
}

/* Formuliervelden */
.field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.field label { font-size: 13px; font-weight: 700; color: var(--navy-950); }
.field label .req { color: var(--orange-600); }
.field input, .field select, .field textarea {
  width: 100%;
  border: 1px solid var(--blue-200);
  border-radius: var(--r-sm);
  background: #fff;
  color: var(--navy-950);
  padding: 12px 14px;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.field input::placeholder, .field textarea::placeholder { color: var(--navy-300); }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none;
  border-color: var(--orange-500);
  box-shadow: 0 0 0 3px rgba(246, 116, 12, .18);
}

/* ---------- 2-staps-contactformulier (Timo 2026-07-21) ----------
   js/main.js splitst elk .contact-form in twee stappen: stap 1 = kwalificatie
   (rol, aantal, hulpvraag, context), stap 2 = gegevens (naam, telefoon, e-mail,
   bedrijf); stap 3 = de bestaande .form-success. De twee stappen liggen als
   grid-stack over elkaar (grid-area 1/1) zodat de blauwe kaart NOOIT springt:
   de inactieve stap reserveert zijn hoogte maar is onzichtbaar. Erft de gap van
   het formulier (18px s9 / 20px oa-slot) via gap:inherit. */
.form-stepind {
  display: flex;
  align-items: center;
  justify-content: space-between; /* stap-label links, "Terug" rechts */
  gap: 10px;
  min-height: 20px;               /* constante regelhoogte, met of zonder Terug */
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.form-stepind-num b { color: var(--text-strong); }

/* De stack volgt de ZICHTBARE stap, niet de hoogste (Timo 2026-08-21).
   Stond dit op grid-stacking zonder meer, dan reserveert de cel altijd
   max(stap1, stap2, stap3). Stap 3 is de kalender en die is met afstand de
   hoogste, dus stap 1 werd op de kalenderhoogte getoond: een kaart van 854px
   met 255px inhoud erin. Erger nog, de kalender komt ASYNCHROON binnen
   (voorladen() bij het openen), dus die reservering groeide een frame ná het
   openen van 737 naar 854 px: precies de sprong die als bug is gemeld.
   De verborgen stappen staan nu absoluut, zodat alleen de zichtbare stap de
   hoogte bepaalt, en js/main.js zet die hoogte expliciet zodat de overgang
   tussen de stappen een animatie is in plaats van een sprong. */
.form-stack {
  display: grid;
  gap: inherit;
  position: relative;
  /* min-height:0 is hier GEEN opsmuk. .form-stack is zelf een grid-item van het
     formulier, en grid-items krijgen automatisch min-height:auto: ze kunnen niet
     kleiner worden dan hun inhoud. De hoogte die js/main.js zet werd daardoor
     genegeerd zodra hij kleiner was dan de zichtbare stap, en de stack bleef op de
     hoogte van stap 1 staan. Gemeten: inline height ging netjes naar 175px terwijl
     offsetHeight 292 bleef. overflow:hidden hoort erbij, anders puilt de inhoud
     tijdens de 0,3s-overgang buiten de kaart. */
  min-height: 0;
  /* CLIP, NIET HIDDEN (Timo 2026-08-21). overflow:hidden knipt de inhoud af én
     maakt van deze doos een SCROLLBAAR vlak. De verborgen stappen hiernaast
     staan op position:absolute met translateX(14px), dus ze steken 14px voorbij
     de rechterrand: scrollWidth 336 tegen clientWidth 322. Zodra de browser dan
     iets in beeld wil brengen (focus die naar stap 3 verspringt) scrolt hij die
     doos een paar pixels mee, gemeten scrollLeft 7, en schuift de ZICHTBARE stap
     dus naar links weg. Gevolg op stap 3: de eerste letter van "Kies een moment"
     viel achter de kaartrand. Zichtbaar op alle zeven boekingsformulieren, niet
     alleen op de nieuwe pagina.
     overflow:clip knipt hetzelfde af maar maakt geen scroll-container, dus er
     valt niets te verschuiven. De hidden-regel blijft eronder staan als
     terugval voor browsers die clip niet kennen (Safari < 16); die krijgen het
     oude gedrag, niet een kapotte kaart.
     Oude waarde verbatim: overflow: hidden; */
  overflow: hidden;
  overflow: clip;
  transition: height .3s cubic-bezier(.4, 0, .2, 1);
}

.form-step {
  grid-area: 1 / 1;
  display: grid;
  gap: inherit;
  align-content: start;
  /* align-SELF, niet align-content (Timo 2026-08-21). Zonder deze regel rekt de
     stap zich als grid-item uit tot de hoogte van .form-stack. Die hoogte zet
     js/main.js op de hoogte van de stap zelf, dus de stap mat daarna zijn eigen
     uitgerekte hoogte en bleef hangen op de waarde van de eerste meting. */
  align-self: start;
  transition: opacity .3s ease, transform .3s ease;
}
.form-step[aria-hidden="true"] {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translateX(14px);
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
}
.form-step[aria-hidden="false"] { opacity: 1; transform: none; }

.form-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-body);
  transition: color .15s ease;
}
.form-back[hidden] { display: none; }
.form-back:hover { color: var(--orange-600); }

@media (prefers-reduced-motion: reduce) {
  .form-step { transition: none; }
  .form-step[aria-hidden="true"] { transform: none; }
  /* Ook de hoogte-overgang van de stack: die is er om een sprong te verzachten,
     en wie beweging uit heeft staan wil die verzachting niet, alleen het
     resultaat. De hoogte zelf blijft gewoon gezet, dus er springt niets kapot. */
  .form-stack { transition: none; }
}

/* Stap 3 (succes): kaart-kop verbergen + bedankje verticaal centreren; de kaart
   houdt zijn vastgezette hoogte (js/main.js) dus er springt niets. */
.s9-card.is-done,
.oa-slot-card.is-done {
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.s9-card.is-done .s9-card-title,
.s9-card.is-done .s9-card-sub,
.oa-slot-card.is-done .ct-kaartkop,
.oa-slot-card.is-done .ct-kaartsub,
.oa-slot-card.is-done .oa-slot-kaartkop,
.oa-slot-card.is-done .oa-slot-kaartsub { display: none; }

/* Toegankelijke focus */
a:focus-visible, button:focus-visible {
  outline: 2px solid var(--orange-500);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ---------- Scroll-reveals (fail-open: zonder html.motion is alles zichtbaar) ---------- */

html.motion [data-reveal] {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .6s cubic-bezier(.22, .61, .36, 1), transform .6s cubic-bezier(.22, .61, .36, 1);
}
html.motion [data-reveal].is-in { opacity: 1; transform: none; }
html.motion [data-reveal][data-reveal-delay="1"] { transition-delay: .08s; }
html.motion [data-reveal][data-reveal-delay="2"] { transition-delay: .16s; }
html.motion [data-reveal][data-reveal-delay="3"] { transition-delay: .24s; }

@media (prefers-reduced-motion: reduce) {
  html.motion [data-reveal] { opacity: 1 !important; transform: none !important; transition: none !important; }
}

/* ---------- Terugkerend thema: dot-grid decor ---------- */

.decor-dots {
  position: absolute;
  width: 130px;
  height: 180px;
  background-image: radial-gradient(currentColor 1.5px, transparent 1.6px);
  background-size: 18px 18px;
  color: color-mix(in srgb, var(--navy-950) 13%, transparent);
  pointer-events: none;
  z-index: 0;
}
.on-dark .decor-dots,
.decor-dots--inv { color: color-mix(in srgb, #fff 16%, transparent); }

/* ---------- Pulserende play-knop (hero) ---------- */

@keyframes play-pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--orange-500) 45%, transparent); }
  70%  { box-shadow: 0 0 0 20px color-mix(in srgb, var(--orange-500) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--orange-500) 0%, transparent); }
}
html.motion .play-btn--pulse { animation: play-pulse 2.8s ease-out infinite; }
@media (prefers-reduced-motion: reduce) { html.motion .play-btn--pulse { animation: none; } }

/* ---------- Kruimelpad (sitebreed contract, HERO-SYSTEEM §9) ----------
   Op ELKE pagina behalve de homepage, altijd als eerste kind van de
   hero-container. Vaste plek: de hero zet padding-top tot het kruimelpad
   (clamp(102px, 13vh, 128px) desktop) en .crumbs draagt de marge naar de
   eyebrow. Huidige pagina = oranje, geen link. */

.crumbs {
  position: relative;
  z-index: 2;
  font-size: 13px;
}

.crumbs ol {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 10px;
}

.crumbs li {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--text-muted);
}

.crumbs li + li::before {
  content: '\203A'; /* › */
  color: var(--text-muted);
  font-weight: 600;
}

.crumbs a { transition: color .15s ease; }
.crumbs a:hover { color: var(--orange-600); }

/* Huidige pagina: oranje; lange artikeltitels afkappen met ellipsis. */
.crumbs li[aria-current="page"] {
  color: var(--orange-500);
  font-weight: 600;
}

.crumbs li[aria-current="page"] > span {
  display: inline-block;
  max-width: min(48vw, 34ch);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.on-dark .crumbs li { color: var(--text-muted-inv); }
.on-dark .crumbs li + li::before { color: var(--text-muted-inv); }
.on-dark .crumbs a:hover { color: #fff; }
.on-dark .crumbs li[aria-current="page"] { color: var(--orange-500); }

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

/* ===== Exit-intent (T9, sitebreed) =====
   Markup injecteert js/main.js; simpele opacity-transitie (geen
   motion.js-afhankelijkheid). z-index boven de site-header (s1.css: 40). */

.exit-intent {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--gutter);
  opacity: 0;
  transition: opacity .25s ease;
}
.exit-intent.is-open { opacity: 1; }
.exit-intent[hidden] { display: none; }

.exit-intent-backdrop {
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--navy-950) 62%, transparent);
}

.exit-intent-card {
  position: relative;
  width: 100%;
  max-width: 420px;
  background: var(--surface-card);
  border-radius: var(--r-md);
  padding: clamp(28px, 5vw, 32px);
  box-shadow: var(--shadow-panel);
}

.exit-intent-close {
  position: absolute;
  top: 6px;
  right: 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  font-size: 22px;
  line-height: 1;
  color: var(--text-muted);
  border-radius: var(--r-sm);
}
.exit-intent-close:hover { color: var(--text-strong); }

.exit-intent-title {
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: .005em;
  line-height: .95;
  font-size: 1.9rem;
  color: var(--text-strong);
}
/* Kop-punt-recept (base.css .dot is gescoped op h1/h2/h3) */
.exit-intent-title .dot {
  display: inline-block;
  width: .14em;
  height: .14em;
  margin-left: .06em;
  border-radius: 50%;
  background: var(--orange-500);
  color: transparent;
  overflow: hidden;
  vertical-align: baseline;
}

.exit-intent-body {
  margin-top: 12px;
  font-size: 15px;
  line-height: 1.6;
  color: var(--text-body);
}

.exit-intent-cta { margin-top: 20px; }

@media (max-width: 560px) {
  .exit-intent-cta { width: 100%; }
}

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

/* ===== Plan-modaal (sitebreed, Timo 2026-08-19) =====
   Het boekingsformulier is uit de contactpagina getild en zit nu achter elke
   primaire CTA. Markup: sections/site/plan.html, door _qa/build.py op elke
   pagina gezet; gedrag in js/main.js.

   Zelfde recept als .exit-intent hierboven (opacity-overgang, backdrop,
   z-index 60 boven de header), met drie verschillen die uit de inhoud volgen:
   de kaart is breder want er staat een formulier in, hij mag zelf scrollen op
   een laag scherm, en de pagina eronder wordt vastgezet. */

.planmodaal {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: var(--gutter);
  overflow-y: auto;           /* lange kaart op een laag scherm: het modaal scrollt, niet de pagina */
  overscroll-behavior: contain;
  opacity: 0;
  transition: opacity .25s ease;
}
.planmodaal.is-open { opacity: 1; }
.planmodaal[hidden] { display: none; }

/* De pagina eronder staat stil zolang het modaal open is. overflow:hidden en
   geen position:fixed op body: dat laatste springt terug naar boven en je bent
   je scrollpositie kwijt zodra je sluit. */
.plan-open, .plan-open body { overflow: hidden; }

.planmodaal-achtergrond {
  position: fixed;
  inset: 0;
  background: color-mix(in srgb, var(--navy-950) 62%, transparent);
}

.planmodaal-kaart {
  position: relative;
  width: 100%;
  max-width: 560px;
  margin: auto;               /* verticaal midden zolang hij past, daarna gewoon bovenaan */
  background: var(--surface-card);
  border-radius: var(--r-md);
  padding: clamp(26px, 4.5vw, 40px);
  box-shadow: var(--shadow-panel);
  /* VERWIJDERD 2026-08-21: hier stond min-height: 620px, de vierde poging om de
     sprong tussen stap 2 en 3 te stoppen. Twee redenen dat hij weg kan. Hij was
     gemikt op het OMGEKEERDE probleem (stap 1 had toen vier vragen en was hoger
     dan stap 3, dus de kaart kromp); sinds de wanneer-vraag eruit is, is stap 3
     juist de hoogste. En hij deed sowieso niets: lock() in js/main.js draaide bij
     init terwijl het modaal nog verborgen was, mat 0 en zette er inline
     min-height: 0px overheen. De hoogte wordt nu op de stack geregeld, één laag
     lager, waar hij hoort. */
}

.planmodaal-sluit {
  position: absolute;
  top: 8px;
  right: 8px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  font-size: 22px;
  line-height: 1;
  color: var(--text-muted);
  border-radius: var(--r-sm);
}
.planmodaal-sluit:hover { color: var(--text-strong); }

.planmodaal-eyebrow { margin-bottom: 14px; }

.planmodaal-titel {
  font-size: clamp(1.6rem, 3.2vw, 2.1rem);
  line-height: 1.02;
  color: var(--text-strong);
}

.planmodaal-sub {
  margin-top: 12px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--text-body);
}

.planmodaal-form {
  display: grid;
  gap: 18px;
  margin-top: 24px;
}

.planmodaal-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
}

/* Zelfde pijl-op-select-behandeling als de kaarten in de pagina (s9/oa-slot),
   zodat het modaal niet als een ander formulier voelt. */
.planmodaal-select { position: relative; display: block; }
.planmodaal-select::after {
  content: "";
  position: absolute;
  top: 50%;
  right: 16px;
  width: 8px;
  height: 8px;
  border-right: 2px solid var(--navy-950);
  border-bottom: 2px solid var(--navy-950);
  transform: translateY(-70%) rotate(45deg);
  pointer-events: none;
}
/* FIX (Timo 2026-08-19, gemeld via screenshot): deze regel ontbrak hier, in
   tegenstelling tot .s9-select/.oa-slot-select. Zonder appearance:none blijft
   de NATIVE pijl van de browser staan naast de eigen chevron hierboven — twee
   pijltjes over elkaar op elke select in het modaal. Bestond al vóór de
   boekingsflow (rol/hires/hulpvraag hadden 'm ook), alleen nu pas gezien. */
.planmodaal-select select {
  padding-right: 40px;
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
}

.planmodaal-submit { width: 100%; justify-content: center; }

.planmodaal-vraag {
  margin-top: -4px;
  font-size: 14px;
  color: var(--text-body);
  text-align: center;
}
.planmodaal-vraag a {
  font-weight: 700;
  color: var(--navy-950);
  text-decoration: underline;
  text-decoration-color: var(--orange-500);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}
.planmodaal-vraag a:hover { color: var(--orange-600); }

.planmodaal-privacy {
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--text-muted);
}
.planmodaal-privacy a { text-decoration: underline; }

.planmodaal-kaart .form-stepind { margin-bottom: 0; }

@media (max-width: 560px) {
  .planmodaal { padding: 12px; align-items: flex-start; }
  .planmodaal-kaart { padding: 24px 20px 26px; }
  .planmodaal-row { grid-template-columns: 1fr; }
}

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

/* ===== Plan-modaal stap 3: moment kiezen (Timo 2026-08-19) =====
   Specificatie "Prompt voor Timo, boekingspagina". Markup is volledig
   JS-gebouwd (js/main.js, setupTwoStep → renderKalender), want de inhoud
   hangt af van wat GHL teruggeeft. Dag-kalender + tijdenlijst i.p.v. een
   platte lijst (Timo 2026-08-19, referentiebeeld van een vergelijkbare
   boekingsflow) — altijd GESTAPELD, niet naast elkaar: de kaart is max 560px
   breed en dat is te smal voor twee kolommen die allebei iets voorstellen.
   Hergebruikt bestaande tokens, geen nieuwe kleuren. */

/* GEEN SPRONG BIJ STAP 2 -> 3, VIERDE EN LAATSTE POGING (Timo 2026-08-20).
   Voorgaande pogingen mikten steeds op een LAAG in het systeem dat bij nader
   inzien niet de kaart zelf was:
     1e — min-height op .form-step--3: loste de sprong op maar te ruim
          gegokt, dus zichtbare witruimte.
     2e — geen CSS-minimum, kalender voorladen bij modaal-open: lost de
          async-race niet volledig op (fetch nog niet klaar op het moment
          van doorklikken), en verklaart de sprong sowieso niet in de kern.
     3e — min-height terug op .form-step--3, plus een aparte mobiele variant
          op .form-stack (want position:absolute op verborgen stappen telt
          op mobiel niet mee voor de ouderhoogte). Timo: "nee het gaat echt
          over desktop" — dus DIT was niet de oorzaak, en de mobiele regel
          (die op zich klopt, maar loste hier niets op) is weer verwijderd.
   Het echte probleem: .form-step--3's min-height werkt op de STAP, maar de
   kaart (.planmodaal-kaart) zelf heeft nergens een minimum. Zodra de active
   stap wisselt van step1 (natuurlijk hoger, 4 velden) naar step3, kan de
   kaart alsnog krimpen als er ook maar ÉÉN laag tussen stap en kaart de
   hoogte niet volledig doorgeeft. In plaats van dat verder na te jagen: de
   reservering hier direct op de kaart zelf, die nooit verborgen of absoluut
   gepositioneerd is en dus altijd meetelt, op elke viewport, ongeacht wat de
   stappen daarbinnen doen. Zie .planmodaal-kaart hierboven. */

.planmodaal-slots-titel {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--navy-950);
  margin: 0 0 4px;
}

.planmodaal-slots-status {
  font-size: 14px;
  color: var(--text-muted);
  padding: 6px 0 2px;
}
.planmodaal-slots-status--fout { color: var(--orange-600); }

.planmodaal-slots-conflict {
  margin: 0 0 4px;
  padding: 10px 12px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--orange-600);
  background: color-mix(in srgb, var(--orange-500) 10%, transparent);
  border-radius: var(--r-sm);
}

.planmodaal-cal-maand {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}
.planmodaal-cal-maandlabel {
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: .04em;
  font-size: 14px;
  color: var(--text-strong);
}
.planmodaal-cal-nav {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  font-size: 20px;
  line-height: 1;
  color: var(--navy-950);
  border-radius: 50%;
  transition: background-color .15s ease, color .15s ease, opacity .15s ease;
}
.planmodaal-cal-nav:hover:not(:disabled) {
  background: color-mix(in srgb, var(--orange-500) 12%, transparent);
  color: var(--orange-600);
}
.planmodaal-cal-nav:disabled { opacity: .25; cursor: default; }

.planmodaal-cal-weekdagen {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  margin-bottom: 6px;
}
.planmodaal-cal-weekdagen span {
  text-align: center;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--text-muted);
}

/* Vaste 6 rijen (Timo 2026-08-20, "de popup blijft steeds even groot"): een
   kalendermaand beslaat 5 of 6 weken, en met aspect-ratio:1 per cel werd de
   kalender dus per maand een rij hoger of lager. grid-template-rows met een
   vaste celhoogte reserveert altijd zes rijen, ook bij een maand van vijf —
   dan blijft de laatste rij leeg in plaats van dat de kalender inkrimpt. */
.planmodaal-cal-dagen {
  /* Rijhoogte/gap ruimer gezet (Timo 2026-08-20, screenshot: "verticaal
     samengeperst"): de 34px/4px van de vorige commit hield rekening met de
     inmiddels verwijderde min-height-budgetten. Zonder dat plafond mag de
     kalender gewoon lucht hebben. */
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  grid-template-rows: repeat(6, 42px);
  row-gap: 10px;
}

.planmodaal-cal-dag,
.planmodaal-cal-leeg {
  display: flex;
  align-items: center;
  justify-content: center;
}

button.planmodaal-cal-dag {
  /* Vaste vierkante afmeting (Timo 2026-08-20, screenshot: "platgeslagen
     ovaal"). Zonder dit rekt een gridkind zich standaard uit tot de volle
     cel (68x34px bij 7 kolommen), en wordt border-radius:50% een ovaal in
     plaats van een cirkel. justify/align-self centreert 'm in de cel. */
  width: 34px;
  height: 34px;
  justify-self: center;
  align-self: center;
  font-size: 13px;
  font-weight: 600;
  color: var(--navy-950);
  border-radius: 50%;
  border: 1px solid transparent;
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
button.planmodaal-cal-dag:hover { border-color: var(--orange-500); }
button.planmodaal-cal-dag.is-actief {
  background: var(--orange-500);
  color: #fff;
}
span.planmodaal-cal-dag--leeg {
  font-size: 13px;
  color: var(--navy-300);
}

/* De tijdenfase als flexkolom met een EIGEN, kleine gap — niet de 18px
   form-gap die .form-step van de kaart erft, want dat maakte deze fase een
   heel eind hoger dan de kalenderfase (Timo 2026-08-20, "blijft dezelfde
   grootte op alle stappen"). max-height op de lijst hieronder houdt de
   tijdenfase in dezelfde orde van grootte als de kalenderfase (vaste 6
   rijen), zodat het wisselen tussen de twee binnen stap 3 ook niet springt. */
.planmodaal-cal-tijden {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* Terug-naar-kalender (Timo 2026-08-20): eigen knop, want de gedeelde
   .form-back gaat stap 3 -> stap 2 (gegevens); deze gaat binnen stap 3 van
   de tijden terug naar de dagkeuze. Zelfde vormtaal als .form-back. */
.planmodaal-cal-terugdag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-body);
  transition: color .15s ease;
}
.planmodaal-cal-terugdag:hover { color: var(--orange-600); }

.planmodaal-cal-tijdenlabel {
  font-size: 13px;
  font-weight: 700;
  color: var(--navy-950);
  margin: 0;
  text-transform: capitalize;
}
.planmodaal-cal-tijdenlijst {
  display: flex;
  flex-direction: column;
  gap: 8px;
  /* 190px = 4 zichtbare tijden i.p.v. 3 (Timo 2026-08-20, screenshot). Kon
     omhoog nu de kaarthoogte op .planmodaal-kaart zelf gereserveerd is: de
     tijdenfase hoeft niet meer precies in het budget van de kalenderfase te
     passen (zie "Plan-modaal stap 3" verderop). */
  max-height: 190px;
  overflow-y: auto;
  /* Kadertje om de lijst zelf (Timo 2026-08-20, screenshot: "wordt boven en
     onder afgesneden door niks"). Zonder rand liep de bovenste/onderste knop
     kaal tegen de scroll-grens aan; nu heeft de lijst een zichtbare grens die
     laat zien dat er hierbinnen gescrold wordt, met wat lucht erin zodat de
     knoppen niet tegen de rand zelf plakken. */
  padding: 10px;
  border: 1px solid var(--blue-200);
  border-radius: var(--r-sm);
}

.planmodaal-slot-btn {
  padding: 10px 14px;
  font-size: 14px;
  font-weight: 600;
  text-align: left;
  color: var(--navy-950);
  background: #fff;
  border: 1px solid var(--blue-200);
  border-radius: var(--r-sm);
  transition: border-color .15s ease, background-color .15s ease, color .15s ease;
}
.planmodaal-slot-btn:hover:not(:disabled) { border-color: var(--orange-500); color: var(--orange-600); }
.planmodaal-slot-btn.is-actief {
  background: var(--orange-500);
  border-color: var(--orange-500);
  color: #fff;
}
.planmodaal-slot-btn:disabled { opacity: .45; cursor: default; }

.planmodaal-cal-tijdzone {
  margin: 0;
  font-size: 12.5px;
  color: var(--text-muted);
  text-align: center;
}

.planmodaal-cal-bevestig { width: 100%; justify-content: center; }
.planmodaal-cal-bevestig:disabled { opacity: .45; cursor: default; }

/* ===== "Eerst een vraag stellen?" onder de boekingsformulieren =====
   Timo 2026-08-19, hoort bij de splitsing van de twee formulieren. Staat in
   base.css en niet zes keer per sectie-CSS, want het is één regel met één
   gedrag op zes plekken (s9 op de homepage, o10, os6, ws8, rpo8, nf3).

   De kleur erft van de kaart eronder: op de homepage staat het formulier in een
   donkere kaart (s9), op de andere pagina's in een lichte (oa-slot). currentColor
   pakt daarom vanzelf de goede kant; alleen de link krijgt de oranje onderstreping
   die de site sitebreed voor tekstlinks gebruikt. */

.form-vraaglink {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid color-mix(in srgb, currentColor 18%, transparent);
  font-size: 13.5px;
  line-height: 1.5;
  text-align: center;
}
.form-vraaglink a {
  font-weight: 700;
  color: inherit;
  text-decoration: underline;
  text-decoration-color: var(--orange-500);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
  white-space: nowrap;
}
.form-vraaglink a:hover { color: var(--orange-500); }
.form-vraaglink .arr { display: inline-block; }

/* De spiegel op de contactpagina: daar staat het VRAAGformulier en wijst de regel
   terug naar het plan-modaal in plaats van naar een pagina. */
.ct-vraag-plan { margin-top: 10px; }
.ct-vraag-plan a {
  font-weight: 700;
  color: var(--navy-950);
  text-decoration: underline;
  text-decoration-color: var(--orange-500);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}
.ct-vraag-plan a:hover { color: var(--orange-600); }
