/* generated by build.mjs, edit src/ and run: node mockups/stroom-v4/build.mjs */

/* ---------- src/core/tokens.css ---------- */

/* Stroom, rebuilt (D-084). One fluid ground under the page that changes world per chapter; every section is transparent and takes its
   text colours from its world. `.beweeg` (set by stroming.js when GSAP runs and motion is allowed) turns the pinned scenes on; without it
   the page reads as a plain column. */

:root {
  --rood: #ED1D24;
  --rood-tekst: #BD1119;
  --grafiet: #181A1D;
  --houtskool: #25282D;
  --leisteen: #393E45;
  --inkt: #141414;
  --kalk: #F5F3EE;
  --f: 'Schibsted Grotesk', ui-sans-serif, system-ui, sans-serif;
  --mono: 'Geist Mono', ui-monospace, 'SFMono-Regular', Consolas, monospace;
  --rand: clamp(16px, 3.2vw, 56px);
  /* the layout rules (specs/011-page-system/layout.md, D-193): the rhythm, the type steps, the radii. A section's stylesheet uses these
     and declares no value of its own; the phone's values are under 760 px at the foot of this file */
  --sec-y: clamp(96px, 10vw, 170px);      /* a section's edge: two sections stand 2 x --sec-y apart (288 px at 1440) */
  --kop-y: clamp(40px, 4.5vw, 72px);      /* head to body, body to hand-off, block to block */
  --label-y: clamp(20px, 3vh, 32px);      /* the section label to the heading */
  --sub-y: 24px;                          /* the heading to the standfirst */
  --pagina-top: clamp(130px, 20vh, 220px); /* the top of a page without a film hero */
  --kolom-gap: clamp(40px, 6vw, 120px);   /* the text column to the demo column */
  --t-film: clamp(56px, 10.4vw, 168px);   /* the H1 on a film hero */
  --t-pagina: clamp(46px, 7.4vw, 132px);  /* the H1 of a page without a film */
  --t-mega: clamp(38px, 5.8vw, 92px);     /* a closing sentence */
  --t-kop2: clamp(34px, 4.4vw, 68px);     /* a section's H2 */
  --t-kop3: clamp(28px, 3.4vw, 54px);     /* an H3 that carries a demo */
  --t-kaart: clamp(24px, 2.2vw, 36px);    /* an H3 inside a plate or card */
  --t-zin: clamp(20px, 1.7vw, 28px);      /* a statement line */
  --t-sub: clamp(17px, 1.2vw, 20px);      /* the standfirst */
  --t-meta: 15px;                         /* captions, meta, the phone button label; the phone's floor for any text */
  --t-label: 12px;                        /* uppercase and tracked: the section label and the small labels styled as it */
  --t-tag: 10px;                          /* review tags and [tbc], off on a showing */
  --r-plaat: clamp(22px, 2.4vw, 32px);    /* a plate */
  --r-kaart: 14px;                        /* a card inside a plate */
  --r-veld: 10px;                         /* inputs, drawer buttons */
  --r-knop: 999px;                        /* pills */
  --plaat-p: clamp(24px, 3vw, 48px);      /* a plate's inner padding */
  --vel-p: clamp(24px, 4vw, 72px);        /* the form sheet's inner padding (D-138) */
  --uit: cubic-bezier(.16, 1, .3, 1);
  --inuit: cubic-bezier(.65, 0, .35, 1);
  /* the motion system (spec §3), mirrored as M in src/core/motion.js: entrances, scene changes, exits, small pops; scroll-linked is linear */
  --e-uit: cubic-bezier(.16, 1, .3, 1);
  --e-scene: cubic-bezier(.87, 0, .13, 1);
  --e-in: cubic-bezier(.55, 0, 1, .45);
  --e-pop: cubic-bezier(.34, 1.56, .64, 1);
  --t-druk: 150ms; --t-klein: 300ms; --t-deel: 700ms; --t-scene: 1000ms;
  --rood-knop: #D0141B;  /* the button red: white text at 5,5:1 (--rood gives 4,4:1) */
  --rood-diep: #A31115;
  --w0: #181A1D; --w1: #25282D; --w2: #393E45; --w3: #565C64;
  --pijl: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14M13 6l6 6-6 6'/%3E%3C/svg%3E");
  --haak: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12.5l5 5L20 6.5'/%3E%3C/svg%3E");
}

/* the phone's rhythm (D-192, D-193): 160 px between sections, 40 px inside them */
@media (max-width: 760px) { :root { --sec-y: 80px; --kop-y: 40px; --label-y: 20px; --pagina-top: 130px; } }

/* ---------- src/core/basis.css ---------- */

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
html { scrollbar-gutter: stable; }
html.laadt, html.menu-vast { overflow: hidden; }
body {
  margin: 0; min-height: 100vh; overflow-x: clip;
  font-family: var(--f); font-size: clamp(17px, .2vw + 14.5px, 19px); line-height: 1.5;
  color: #fff; background: var(--grafiet);
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
}
img, video, svg { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; }
button { font: inherit; color: inherit; }
::selection { background: var(--rood); color: #fff; }
:focus-visible { outline: 2px solid currentColor; outline-offset: 4px; border-radius: 4px; }
.sr { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.mono { font-family: var(--mono); }
.skip { position: fixed; left: 12px; top: -60px; z-index: 200; background: #fff; color: var(--inkt); padding: 10px 14px; border-radius: 8px; }
.skip:focus { top: 12px; }

/* ---------- the sticky hold (src/core/houd.js): the height is set only by the script, so without it the section is its content ---------- */
.houd { height: calc(100svh + var(--houd, 1) * 100vh); }
.houd > .houd-podium { position: sticky; top: 0; height: 100vh; height: 100svh; overflow: hidden; }
/* without the script, and on the quiet tier, .houd is never set, so the stage must not keep the height a section gave it (wave C close) */
html:not(.beweeg) .houd-podium { position: static; height: auto; min-height: 0; overflow: visible; }
/* a section that declares .houd in the markup (slice D) must still collapse to its content without the script, and on a tier that does
   not hold it: .houd-lite-uit marks a hold the phone tier replaces with a list, a bar or a swiped carousel (spec §7, Q1) */
html:not(.beweeg) .houd { height: auto; }
[data-tier=lite] .houd-lite-uit { height: auto; }
[data-tier=lite] .houd-lite-uit > .houd-podium { position: static; height: auto; min-height: 0; overflow: visible; }

/* ---------- the worlds: each section's colours ---------- */
[data-world=grafiet], [data-world=nacht] { --fg: #fff; --fg2: rgba(255, 255, 255, .78); --lijn: rgba(255, 255, 255, .22); --punt: var(--rood); color: var(--fg); }
[data-world=kalk], [data-world=dag], [data-world=wit] { --fg: var(--inkt); --fg2: #4f4b46; --lijn: rgba(20, 20, 20, .15); --punt: var(--rood); color: var(--fg); }
[data-world=dag] { --fg2: #3f4a52; }
main, .voet { position: relative; z-index: 1; }
em { font-style: normal; }
h1 em, h2 em, h3 em, .slot-quote em, .voet-zin em { color: var(--punt); }

/* ---------- src/core/grond.css ---------- */

/* ---------- the ground (slice A2): Campaign layers C2 on the canvas; grond.js sizes its buffer, the browser scales it up ---------- */
.grond { position: fixed; left: 0; top: 0; width: 100vw; height: 100vh; height: 100lvh; z-index: 0; pointer-events: none; }
/* grain is off in C2 and never a blend layer over the page (spec §7.1) */
.korrel { display: none; }
/* without WebGL: two still planes in the world's own tones over its base, no blur and no animation (spec §7.7).
   .vlekken is the fallback's layer; its old blurred blobs are not used */
.vlekken, .vlekken i { display: none; }
.geen-gl .grond { display: none; }
.geen-gl body { background: var(--w1); transition: background-color 1.2s var(--inuit); }
.geen-gl .vlekken {
  display: block; position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background:
    linear-gradient(104deg, transparent 64%, color-mix(in srgb, var(--w2) 22%, transparent) 64.15%, transparent 96%),
    linear-gradient(116deg, transparent 38%, color-mix(in srgb, var(--w3) 14%, transparent) 38.15%, transparent 78%);
}

/* ---------- src/core/type.css ---------- */

/* ---------- common type ---------- */
.rand { width: 100%; max-width: 1760px; margin-inline: auto; padding-inline: var(--rand); }
.sec-label { display: flex; align-items: center; gap: 12px; margin: 0 0 var(--label-y); font-size: 12px; font-weight: 500; line-height: 1; letter-spacing: .08em; text-transform: uppercase; color: var(--fg2); }
/* the rule above each section label, drawn on entry (motion.js); without JavaScript it simply stands. A lone 68 px bar of solid red read
   as a default divider (Alex, 18-09), so it is now an index rule: a short red mark that runs on into a hairline fading to nothing. The
   hairline draws a beat after the mark. */
.sec-label { position: relative; padding-top: 20px; }
.sec-label::before, .sec-label::after { content: ''; position: absolute; left: 0; top: 0; transform-origin: 0 50%; transition: transform var(--t-deel) var(--e-uit); }
.sec-label::before { z-index: 1; width: 38px; height: 2px; background: var(--rood); }
.sec-label::after { left: 38px; top: .5px; width: clamp(110px, 15vw, 230px); height: 1px; background: linear-gradient(90deg, var(--lijn), transparent); transition-delay: .14s; }
.sec-label.wacht::before, .sec-label.wacht::after { transform: scaleX(0); }
.sec-label.wacht::after { transition-delay: 0s; }
/* the red full stop can scale: it pops in last (spec §3) */
:is(.kop2, .kop-mega, .slot-zin, .vel-titel, .held-titel) em { display: inline-block; }
.sec-label b { font-weight: 500; color: var(--fg); border: 1px solid var(--lijn); border-radius: 99px; padding: 5px 9px; }
.kop2 { margin: 0; font-size: var(--t-kop2); font-weight: 640; line-height: 1.05; letter-spacing: -.02em; text-wrap: balance; }
.kop-mega { margin: 0; font-size: var(--t-mega); font-weight: 650; line-height: 1.02; letter-spacing: -.02em; text-wrap: balance; }
.sub { margin: var(--sub-y) 0 0; max-width: 34em; font-size: var(--t-sub); line-height: 1.5; color: var(--fg2); }
.rood-tekst { color: var(--rood); }
/* SplitText's line masks. The room under a line comes from the font: Schibsted Grotesk's g and y reach .207em under the baseline, and the
   line box ends .5lh - .3575em under it (ascent .975em, descent .26em), so the mask needs .5645em - .5lh, plus .025em for the antialiasing:
   .11em at line-height .96, .06em from 1.06 up. One rule for every heading: a local override is how /formules/ was fixed once and the
   sector pages broke again. look.mjs reports any glyph a clip cuts. */
.regel-mask { --onder: max(.06em, calc(.59em - .5lh)); padding: .1em .02em var(--onder); margin: -.1em -.02em calc(-1 * var(--onder)); }
.tbc, .ptag {
  display: inline-block; vertical-align: middle; font: 500 10px/1 var(--mono); letter-spacing: .04em; text-transform: uppercase; font-style: normal;
  white-space: nowrap; padding: 3px 6px; border: 1px dashed currentColor; border-radius: 4px; opacity: .62;
}
.ptag { margin-left: 8px; }
[data-tags=uit] .tbc, [data-tags=uit] .ptag { display: none !important; }

/* ---------- src/core/knoppen.css ---------- */

/* ---------- buttons and links ---------- */
.knop {
  --kb: #fff; --kf: var(--inkt);
  position: relative; display: inline-flex; align-items: center; gap: 16px; height: 62px; padding: 0 10px 0 26px; border: 0; border-radius: 999px;
  background: var(--kb); color: var(--kf); font-weight: 600; font-size: 17px; letter-spacing: -.01em; text-decoration: none; white-space: nowrap; cursor: pointer;
  transition: transform .5s var(--uit), background-color .4s;
}
.knop:active { transform: scale(.97); }
.knop > span { display: block; position: relative; line-height: 1.3; }
.knop > span[data-t] { overflow: hidden; color: transparent; }
.knop > span[data-t]::before, .knop > span[data-t]::after { content: attr(data-t); position: absolute; left: 0; top: 0; width: 100%; color: var(--kf); transition: transform .65s var(--uit); }
.knop > span[data-t]::after { transform: translateY(115%); }
.knop:hover > span[data-t]::before { transform: translateY(-115%); }
.knop:hover > span[data-t]::after { transform: none; }
.pijl { position: relative; display: block; flex: none; width: 42px; height: 42px; border-radius: 50%; overflow: hidden; background: var(--kf); }
.pijl::before, .pijl::after {
  content: ''; position: absolute; inset: 0; background: var(--kb, #fff); transition: transform .65s var(--uit);
  -webkit-mask: var(--pijl) center / 18px no-repeat; mask: var(--pijl) center / 18px no-repeat;
}
.pijl::after { transform: translateX(-110%); }
.knop:hover .pijl::before { transform: translateX(110%); }
.knop:hover .pijl::after { transform: none; }
.knop-wit { --kb: #fff; --kf: var(--inkt); }
.knop-inkt { --kb: var(--inkt); --kf: #fff; }
.knop-rood { --kb: var(--rood); --kf: #fff; }
.knop-klein { height: 46px; padding: 0 22px; font-size: 15px; }
/* het vaste paar (spec §6): the red button, then the quiet link, always in that order */
.paar { display: flex; flex-wrap: wrap; align-items: center; gap: 14px 28px; }
.knop-ghost {--kb: transparent; --kf: var(--fg, #fff); box-shadow: inset 0 0 0 1.5px currentColor; color: var(--kf); }
.knop-ghost .pijl { background: transparent; --kb: currentColor; }
.knop-ghost:hover { box-shadow: inset 0 0 0 2.5px currentColor; }

/* a link (kit 3): the underline rests at its full width like v1's (Alex, 18-09), and on hover it wipes out to the right and draws in again
   from the left; the arrow leaves right while a clone enters from the left in 180 ms (two layers of one mask). On a phone it plays once on press */
.link {
  display: inline-flex; align-items: center; gap: .35em; font-weight: 600; text-decoration: none; padding-bottom: 4px;
  background: linear-gradient(currentColor, currentColor) 0 100% / 100% 1.5px no-repeat;
}
.link::after {
  content: ''; flex: none; width: 1em; height: 1em; background: currentColor;
  -webkit-mask: var(--pijl) 0 50% / .9em no-repeat, var(--pijl) -1.2em 50% / .9em no-repeat; mask: var(--pijl) 0 50% / .9em no-repeat, var(--pijl) -1.2em 50% / .9em no-repeat;
  transition: -webkit-mask-position .18s var(--e-uit), mask-position .18s var(--e-uit);
}
.link:is(:hover, :focus-visible, :active)::after { -webkit-mask-position: 1.2em 50%, 0 50%; mask-position: 1.2em 50%, 0 50%; }

/* the tally light (kit 2): one red light runs once around the button the first time it enters view; never loops (src/core/knoppen.js) */
@property --tally { syntax: '<angle>'; inherits: false; initial-value: 0deg; }
.knop[data-tally]::before {
  content: ''; position: absolute; inset: -6px; border-radius: inherit; padding: 2px; pointer-events: none; opacity: 0;
  background: conic-gradient(from var(--tally), transparent 0 78%, rgba(237, 29, 36, .2) 86%, var(--rood) 96%, #fff 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
}
.knop.is-tally::before { animation: tally 1.6s var(--e-scene) both; }
@keyframes tally { 0% { --tally: -30deg; opacity: 0; } 12% { opacity: 1; } 85% { opacity: 1; } 100% { --tally: 330deg; opacity: 0; } }
[data-tier=stil] .knop.is-tally::before { animation: none; }

/* ---------- src/core/gesprek.css ---------- */

/* ---------- the callback (spec §6): printed at the foot of the form section, opened as a sheet by every "Plan een gesprek" ---------- */
.terugbel-voet { margin-top: clamp(64px, 10vh, 120px); }
.terugbel-vraag { margin: 0 0 28px; font-size: clamp(20px, 1.6vw, 26px); font-weight: 560; letter-spacing: -.01em; }
.terugbel-vraag .link { margin-left: 10px; }
.terugbel { --fg: var(--inkt); --fg2: #57534e; --lijn: rgba(20, 20, 20, .12); max-width: 620px; padding: clamp(24px, 3vw, 44px); border-radius: var(--r-plaat); background: #fff; color: var(--inkt); }
.terugbel-titel { margin: 0 0 10px; font-size: clamp(30px, 2.8vw, 44px); font-weight: 640; line-height: 1.05; letter-spacing: -.02em; }
.terugbel-titel em { color: var(--rood); display: inline-block; }
.terugbel-stand { margin: 0 0 26px; font-size: 17px; line-height: 1.45; color: var(--fg2); }
.terugbel-form { position: relative; display: grid; gap: 14px; }
.chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0; padding: 0; border: 0; }
.chips legend { width: 100%; margin: 0 0 10px; padding: 0; font-size: 15px; font-weight: 560; color: var(--inkt); }
.chip { position: relative; cursor: pointer; }
.chip input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.chip span { display: inline-flex; align-items: center; gap: 6px; min-height: 48px; padding: 0 18px; border: 1px solid #dedad4; border-radius: 99px; background: #f6f4f1; font-size: 16px; font-weight: 520; transition: background-color var(--t-druk), border-color var(--t-druk), color var(--t-druk); }
.chip:hover span { border-color: #b9b4ac; }
.chip input:checked + span { background: var(--inkt); border-color: var(--inkt); color: #fff; }
.chip input:focus-visible + span { outline: 2px solid var(--inkt); outline-offset: 3px; }
.terugbel-knop { justify-content: space-between; height: 66px; padding-left: 26px; }
.terugbel-knop[aria-busy=true] { pointer-events: none; }
.terugbel-klaar { padding: 20px 0 6px; outline: none; }
.terugbel-klaar p:last-child { margin: 0; font-size: 19px; color: var(--fg2); }

/* the sheet: a right-hand panel on the desktop, a bottom sheet on the phone */
.gesprek {
  position: fixed; inset: 0 0 0 auto; width: min(560px, 100vw); max-width: none; height: 100%; max-height: none; margin: 0; padding: 0; border: 0;
  background: #fff; color: var(--inkt); overflow-y: auto; overscroll-behavior: contain;
  transform: translateX(100%); transition: transform .5s var(--e-uit), overlay .5s allow-discrete, display .5s allow-discrete;
}
.gesprek[open] { transform: none; }
@starting-style { .gesprek[open] { transform: translateX(100%); } }
.gesprek::backdrop { background: rgba(10, 11, 13, .55); opacity: 0; transition: opacity .4s, overlay .4s allow-discrete, display .4s allow-discrete; }
.gesprek[open]::backdrop { opacity: 1; }
@starting-style { .gesprek[open]::backdrop { opacity: 0; } }
.gesprek .terugbel { display: block; max-width: none; padding: clamp(72px, 10vh, 96px) clamp(24px, 3vw, 44px) calc(32px + env(safe-area-inset-bottom)); border-radius: 0; background: none; }
.gesprek-dicht {
  position: absolute; right: 18px; top: 18px; z-index: 1; width: 48px; height: 48px; border: 1px solid rgba(20, 20, 20, .18); border-radius: 50%; background: #fff; cursor: pointer;
  transition: border-color var(--t-druk), transform var(--t-druk);
}
.gesprek-dicht:hover { border-color: var(--inkt); }
.gesprek-dicht:active { transform: scale(.94); }
.gesprek-dicht::before, .gesprek-dicht::after { content: ''; position: absolute; left: 14px; right: 14px; top: 23px; height: 1.5px; background: var(--inkt); transform: rotate(45deg); }
.gesprek-dicht::after { transform: rotate(-45deg); }
html.gesprek-open { overflow: hidden; }
@media (max-width: 760px) {
  .gesprek { inset: auto 0 0 0; width: 100%; height: auto; max-height: 92svh; border-radius: 24px 24px 0 0; transform: translateY(100%); }
  @starting-style { .gesprek[open] { transform: translateY(100%); } }
  .gesprek .terugbel { padding-top: 64px; }
}
[data-tier=stil] .gesprek, [data-tier=stil] .gesprek::backdrop { transition: none; }

/* ---------- src/sections/00-lader.css ---------- */

/* ---------- loader ---------- */
/* the logo is drawn left to right behind a thin red edge, then the graphite lifts into the hero (stroming.js). The inline script in the head
   removes .laadt after 5 s whatever happens, so a failed script never leaves it standing */
.lader { position: fixed; inset: 0; z-index: 150; background: var(--grafiet); display: none; place-items: center; clip-path: inset(0 0 0 0); }
.laadt .lader { display: grid; }
.lader-merk { position: relative; width: min(56vw, 400px); }
.lader-merk img { width: 100%; height: auto; animation: lader-teken .45s .06s var(--inuit) both; }
.lader-rand { position: absolute; left: 0; right: 0; top: -45%; bottom: -45%; animation: lader-rand .45s .06s var(--inuit) both; }
.lader-rand::after { content: ''; position: absolute; right: -1px; top: 0; bottom: 0; width: 2px; background: var(--rood); }
@keyframes lader-teken { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes lader-rand { 0% { transform: translateX(-100%); opacity: 1; } 80% { opacity: 1; } 100% { transform: none; opacity: 0; } }

/* ---------- src/sections/00-kop.css ---------- */

/* ---------- header ---------- */
body[data-fg=licht], body.menu-open { --kop-fg: #fff; }
body[data-fg=donker] { --kop-fg: var(--inkt); }
.kop {
  position: fixed; left: 0; right: 0; top: 0; z-index: 80; display: flex; align-items: center; justify-content: space-between; gap: 24px;
  padding: 18px var(--rand); color: var(--kop-fg); transition: transform .7s var(--uit), color .6s;
}
.kop.is-weg { transform: translateY(-120%); }
/* over a light plate inside a dark world (the form panel): the header turns dark on its own, without touching body[data-fg], which
   grond.js rewrites every frame (§11). It carries all three things the body attribute carries: the colour, the logo and the button.
   The open menu always wins, so the class defers to body.menu-open */
body:not(.menu-open) .kop.is-donker { --kop-fg: var(--inkt); }
body:not(.menu-open) .kop.is-donker .merk-rood { opacity: 1; }
body:not(.menu-open) .kop.is-donker .merk-wit { opacity: 0; }
body:not(.menu-open) .kop.is-donker .knop-klein { --kb: var(--inkt); --kf: #fff; }
html:not([data-tier=rich]) body:not(.menu-open) .kop.is-donker::before { background: rgba(245, 243, 238, .92); }
.kop::before { content: ''; position: absolute; z-index: -1; inset: 0 0 -24px; opacity: 0; -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px); -webkit-mask: linear-gradient(#000 55%, transparent); mask: linear-gradient(#000 55%, transparent); transition: opacity .6s; pointer-events: none; }
.kop.is-vast::before { opacity: 1; }
body.menu-open .kop::before { opacity: 0; }
/* the blur is for the rich tier only; the others get the world colour at 92 % (spec §7.5) */
html:not([data-tier=rich]) .kop::before { -webkit-backdrop-filter: none; backdrop-filter: none; background: rgba(24, 26, 29, .92); -webkit-mask: none; mask: none; inset: 0; }
html:not([data-tier=rich]) body[data-fg=donker] .kop::before { background: rgba(245, 243, 238, .92); }
/* the header's button waits until the hero's own button has left the screen (kit 14); on a phone the phone bar does its job */
.kop .kop-cta { transition: opacity var(--t-klein) var(--e-uit), transform var(--t-klein) var(--e-uit), visibility 0s; }
html.kop-wacht .kop:not(.cta-aan) .kop-cta { opacity: 0; transform: translateY(-8px); visibility: hidden; transition: opacity .2s var(--e-in), transform .2s var(--e-in), visibility 0s .2s; }
@media (max-width: 760px) { html.js .kop .kop-cta { display: none; } }
.merk { position: relative; display: block; flex: none; width: clamp(132px, 10.5vw, 172px); aspect-ratio: 483 / 42; }
.merk img { position: absolute; inset: 0; width: 100%; height: 100%; transition: opacity .6s; }
body[data-fg=licht] .merk-rood, body.menu-open .merk-rood { opacity: 0; }
body[data-fg=donker]:not(.menu-open) .merk-wit { opacity: 0; }
.kop-nav { display: flex; align-items: center; gap: clamp(14px, 1.7vw, 30px); font-size: 15px; font-weight: 500; }
.kop-nav > a, .kop-sec-knop { position: relative; text-decoration: none; padding: 6px 0; }
.kop-nav > a::after, .kop-sec-knop::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1.5px; background: currentColor; transform: scaleX(0); transform-origin: right; transition: transform .6s var(--uit); }
.kop-nav > a:hover::after, .kop-sec:hover .kop-sec-knop::after, .kop-sec-knop[aria-expanded=true]::after { transform: scaleX(1); transform-origin: left; }
/* the page he is standing on keeps its line (the sample pages set it; paginas.mjs kop()) */
.kop-nav > a[aria-current]::after, .kop-sec-knop.is-hier::after { transform: scaleX(1); transform-origin: left; }
.menu-links a[aria-current] small, .menu-meer a[aria-current] { color: var(--rood); opacity: 1; }
.kop-paneel a[aria-current] { color: var(--rood); }

/* Sectoren: the eight trade pages carry the organic traffic, so they get a panel of their own instead of the footer.
   It is graphite whatever the ground does, like the phone's menu, so its contrast never depends on the world behind it. */
.kop-sec { position: relative; }
.kop-sec-knop { display: inline-flex; align-items: center; gap: 7px; border: 0; background: none; color: inherit; font: inherit; cursor: pointer; }
.kop-punt { width: 7px; height: 7px; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: translateY(-2px) rotate(45deg); transition: transform .4s var(--uit); }
.kop-sec-knop[aria-expanded=true] .kop-punt { transform: translateY(1px) rotate(225deg); }
.kop-paneel {
  position: absolute; top: calc(100% + 16px); left: -22px; z-index: 5; width: 316px; padding: 18px 22px 12px;
  background: var(--grafiet); color: #fff; border-radius: 14px; box-shadow: 0 24px 60px rgba(0, 0, 0, .34);
  transform-origin: 28% 0; opacity: 0; transform: translateY(-8px) scale(.97); pointer-events: none;
  transition: opacity .4s var(--uit), transform .5s var(--uit);
}
/* it opens like the phone's menu: the attribute goes first, the class one frame later, so it is out of the tree while shut */
.kop-paneel.is-open { opacity: 1; transform: none; pointer-events: auto; }
/* the pointer has to cross the 16 px between the button and the panel; without a bridge it is over neither, .kop-sec gets
   pointerleave and the panel shuts before he reaches it. The bridge is a child of the panel, so it counts as inside .kop-sec. */
.kop-paneel::before { content: ''; position: absolute; left: 0; right: 0; bottom: 100%; height: 20px; }
.kop-paneel-kop { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding-bottom: 13px; margin-bottom: 9px; border-bottom: 1px solid rgba(255, 255, 255, .16); color: #fff; text-decoration: none; font-weight: 560; }
.kop-paneel-kop .pijl { transition: transform .5s var(--uit); }
.kop-paneel-kop:hover .pijl { transform: translateX(4px); }
/* down the first column, then the second: a list of eight trades is scanned vertically, not across */
.kop-paneel-lijst { display: grid; grid-template-rows: repeat(4, auto); grid-auto-flow: column; gap: 0 18px; }
.kop-paneel-lijst a { display: block; padding: 7px 0; color: rgba(255, 255, 255, .72); text-decoration: none; font-size: 14px; font-weight: 450; line-height: 1.25; transition: color .3s; }
.kop-paneel-lijst a:hover { color: #fff; }
.kop-rechts { display: flex; align-items: center; gap: 20px; }
.kop-tel { font-size: 14px; text-decoration: none; }
body[data-fg=licht] .kop .knop-klein { --kb: #fff; --kf: var(--inkt); }
body[data-fg=donker] .kop .knop-klein { --kb: var(--inkt); --kf: #fff; }
.burger { display: none; position: relative; width: 46px; height: 46px; border: 1px solid currentColor; border-radius: 50%; background: transparent; cursor: pointer; }
.burger i { position: absolute; left: 14px; right: 14px; height: 1.5px; background: currentColor; transition: transform .6s var(--uit); }
.burger i:first-child { top: 19px; } .burger i:nth-child(2) { top: 25px; }
.burger[aria-expanded=true] i:first-child { transform: translateY(3px) rotate(45deg); }
.burger[aria-expanded=true] i:nth-child(2) { transform: translateY(-3px) rotate(-45deg); }
.menu {
  position: fixed; inset: 0; z-index: 70; background: var(--grafiet); color: #fff; padding: 110px var(--rand) 32px; overscroll-behavior: contain;
  display: flex; flex-direction: column; justify-content: space-between; clip-path: inset(0 0 100% 0); transition: clip-path .9s var(--inuit);
}
.menu.is-open { clip-path: inset(0 0 0 0); }
.menu-links { list-style: none; margin: 0; padding: 0; }
.menu-links a { display: flex; align-items: baseline; gap: 14px; font-size: clamp(36px, 8vw, 68px); font-weight: 640; line-height: 1.12; letter-spacing: -.02em; text-decoration: none; }
.menu-links small { font-size: 12px; opacity: .6; letter-spacing: 0; }
/* the pages that do not fit the six: small, two columns, under the line (sitemap §3) */
.menu-meer { display: grid; grid-template-rows: repeat(4, auto); grid-auto-flow: column; gap: 2px 20px; margin-top: 26px; padding-top: 22px; border-top: 1px solid rgba(255, 255, 255, .16); max-width: 460px; }
.menu-meer a { padding: 6px 0; color: rgba(255, 255, 255, .66); text-decoration: none; font-size: 15px; transition: color .3s; }
.menu-meer a:hover { color: #fff; }
.menu-voet { display: flex; flex-direction: column; align-items: flex-start; gap: 18px; }
.menu-tel { font-size: 30px; font-weight: 600; letter-spacing: -.02em; text-decoration: none; }
/* a laptop keeps the whole row (D-237). Measured with the scrollbar, the home page's row needs 1 112 px and a subpage's, with its
   Home link (D-149), 1 185 px: the phone number leaves first, under 1180 and 1240 px, the subpage's gaps tighten under 1180 px,
   and the burger takes over only under 1024 px, on tablets upright and phones */
@media (max-width: 1240px) {
  .kop-thuis .kop-tel { display: none; }
}
@media (max-width: 1180px) {
  .kop-tel { display: none; }
  .kop-thuis { gap: 16px; }
  .kop-thuis .kop-nav { gap: 14px; }
}
@media (max-width: 1023px) {
  .kop-nav { display: none; }
  .burger { display: block; }
}
@media (max-width: 760px) {
  .kop { padding-block: 12px; }
  .kop .knop-klein { height: 40px; padding: 0 16px; font-size: 14px; }
  .kop .knop-klein > span[data-t]::before { content: 'Doorlichting'; }
  .kop .knop-klein > span[data-t]::after { content: 'Doorlichting'; }
  .kop .knop-klein > span[data-t] { width: 6.6em; }
  .burger { width: 44px; height: 44px; }
  .burger i { left: 13px; right: 13px; }
  .burger i:first-child { top: 18px; } .burger i:nth-child(2) { top: 24px; }
  /* the wordmark is 11 px tall at this width: the link keeps its size and grows its hit area (slice D, phone tier) */
  .merk::before { content: ''; position: absolute; inset: -17px -8px; }
}

/* ---------- src/sections/01-held.css ---------- */

/* ============ 1 · hero (slice B: a 2,2-screen sticky hold, the lead line as whole lines, a REC readout that never lies) ============ */
/* the hold's height stands here, not in the script, so the page is its final height at the first paint (slice D, CLS) */
.held { position: relative; z-index: 1; --houd: 2.2; }
[data-tier=lite] .held { --houd: 1.6; }
.held > .houd-podium { min-height: 600px; }
.held-binnen { position: relative; z-index: 2; height: 100%; display: flex; flex-direction: column; justify-content: flex-end; padding: 110px var(--rand) clamp(24px, 4.5vh, 52px); }
.held-kicker { position: absolute; left: var(--rand); right: var(--rand); top: clamp(92px, 13vh, 132px); margin: 0; display: flex; justify-content: space-between; font-size: 12px; letter-spacing: .08em; text-transform: uppercase; }
.held-titel { margin: 0 0 clamp(26px, 5vh, 56px); font-size: clamp(64px, 11vw, 172px); font-weight: 650; line-height: 1; letter-spacing: -.02em; }
.held-titel .r1, .held-titel .r2 { display: block; white-space: nowrap; }
.held-titel .r2 { padding-left: 1.15em; }
.pil { display: inline-block; width: 2.1em; height: .66em; margin-left: .04em; border-radius: 999px; vertical-align: .04em; }
.held-onder { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 40px; align-items: end; }
.held-stand { margin: 0; max-width: 24em; font-size: clamp(19px, 1.5vw, 24px); font-weight: 500; line-height: 1.35; letter-spacing: -.01em; }
.held-stand .tbc { margin-left: 6px; }
.held-cta { display: flex; flex-direction: column; align-items: flex-start; gap: 14px; max-width: 540px; }
.held-klein { max-width: 360px; }
.held-klein { margin: 0; font-size: 14px; line-height: 1.4; color: var(--fg2); }
.held-scroll { position: absolute; right: var(--rand); top: 50%; margin: 0; display: flex; flex-direction: column; align-items: center; gap: 12px; font-size: 11px; letter-spacing: .1em; text-transform: uppercase; writing-mode: vertical-rl; }
.held-scroll i { width: 1px; height: 56px; background: currentColor; transform-origin: top; animation: scrolllijn 2.2s var(--inuit) infinite; }
@keyframes scrolllijn { 0% { transform: scaleY(0); transform-origin: top; } 45% { transform: scaleY(1); transform-origin: top; } 55% { transform: scaleY(1); transform-origin: bottom; } 100% { transform: scaleY(0); transform-origin: bottom; } }

/* the film. rich and standaard clip the window out of a full-screen layer; lite scales the layer itself and counter-scales the video
   inside it, so the phone never repaints a clip-path per frame (spec §7, fix 3) */
.doek { position: absolute; inset: 0; z-index: 3; overflow: hidden; pointer-events: none; clip-path: inset(50% 50% 50% 50%); will-change: clip-path; background: #111; }
.doek video { position: absolute; left: 0; top: 0; width: 100%; height: 100%; object-fit: cover; transform-origin: 0 0; }
[data-tier=lite] .doek { clip-path: none; will-change: transform; transform-origin: 0 0; }
.doek-waas { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(0, 0, 0, .25), rgba(0, 0, 0, .1) 40%, rgba(0, 0, 0, .55)); opacity: 0; }

/* the camera readout, in its own layer so the lite scale never stretches it (kit 10): REC with a blinking dot only while the clip
   really plays, STBY otherwise */
.doek-ui { position: absolute; inset: 0; z-index: 4; pointer-events: none; opacity: 0; }
.rec { position: absolute; left: var(--rand); top: clamp(92px, 13vh, 132px); margin: 0; display: flex; align-items: center; gap: 8px; font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: #fff; text-shadow: 0 1px 6px rgba(0, 0, 0, .55); }
.doek-krediet { position: absolute; right: var(--rand); bottom: clamp(20px, 3vh, 32px); margin: 0; display: flex; align-items: center; gap: 8px; font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: #fff; text-shadow: 0 1px 6px rgba(0, 0, 0, .55); }
.rec i { width: 8px; height: 8px; border-radius: 50%; background: rgba(255, 255, 255, .45); }
.doek-ui.is-rec .rec i { background: var(--rood); animation: recknip 1.1s steps(1, end) infinite; }
@keyframes recknip { 0%, 55% { opacity: 1; } 56%, 100% { opacity: .15; } }

.doek-tekst { position: absolute; inset: 0; z-index: 5; display: flex; flex-direction: column; justify-content: center; padding: 0 var(--rand); color: #fff; pointer-events: none; visibility: hidden; opacity: 0; }
/* the lead line has to be read once, over a moving frame: a sweep from the left darkens the half the words stand on and dies out before
   the right edge, so the take is still a take. ?lees=plaat swaps it for a plate behind each line (gate question, slice R1) */
.doek-tekst::before { content: ''; position: absolute; inset: 0; background: linear-gradient(100deg, rgba(0, 0, 0, .86), rgba(0, 0, 0, .72) 30%, rgba(0, 0, 0, .34) 58%, rgba(0, 0, 0, 0) 84%); }
[data-lees=plaat] .doek-tekst::before { display: none; }
.groot-zin { position: relative; margin: 0; max-width: 15em; font-size: clamp(34px, 5vw, 84px); font-weight: 640; line-height: 1.06; letter-spacing: -.02em; text-shadow: 0 2px 24px rgba(0, 0, 0, .5); }
.groot-zin em { color: var(--rood); display: inline-block; }
[data-lees=plaat] .groot-zin { text-shadow: none; }
[data-lees=plaat] .groot-zin .regel { width: max-content; max-width: 100%; padding: .1em .3em .16em; margin-left: -.3em; background: rgba(0, 0, 0, .74); }

/* without JavaScript, on the quiet tier and with ?rust=1: no hold, so the stage is not sticky and the parts stack (spec §3).
   The same three lines belong in src/core/basis.css for every held section; noted for the session that closes the wave */
html:not(.beweeg) .held-binnen { height: 100svh; min-height: 600px; }
html:not(.beweeg) .pil { background: rgba(255, 255, 255, .22); }
html:not(.beweeg) .doek { position: relative; height: 90svh; clip-path: none !important; transform: none !important; }
html:not(.beweeg) .doek-waas { opacity: 1; }
html:not(.beweeg) .doek-ui { top: 100svh; bottom: auto; height: 90svh; opacity: 1; }
html:not(.beweeg) .rec { display: none; }
html:not(.beweeg) .doek-tekst { position: absolute; top: 100svh; bottom: auto; height: 90svh; visibility: visible; opacity: 1; }
html:not(.beweeg) .doek video { transform: none !important; }
/* a narrow desktop window: the line above the buttons, not squeezed into a column beside them (responsive pass, 21-09) */
@media (min-width: 761px) and (max-width: 1000px) {
  .held-onder { grid-template-columns: 1fr; gap: 28px; }
}
@media (max-width: 760px) {
  .held-kicker { top: 84px; }
  .held-plaats { display: none; }
  .held-titel { font-size: 15vw; margin-bottom: 26px; }
  .held-titel .r2 { padding-left: 0; }
  .pil { width: 1.5em; height: .62em; }
  .held-onder { grid-template-columns: 1fr; gap: 22px; }
  .held-stand { font-size: 19px; }
  .held-cta { max-width: none; }
  .held-scroll { display: none; }
  .rec { top: 84px; }
}
@media (prefers-reduced-motion: reduce) {
  .held-scroll i { animation: none !important; }
  .doek-ui.is-rec .rec i { animation: none !important; }
}

/* ---------- src/sections/03-klant.css ---------- */

/* ============ 3 · his customer (slice C1: a native intro, a 3,6-screen sticky hold over six steps, the flip's beat, a native outro) ============ */
.klant { position: relative; }
/* the hold's height stands here, not in the script, so the page is its final height at the first paint (slice D, CLS) */
.klant-houd { --houd: 3.6; }
[data-tier=lite] .klant-houd { --houd: 3; }
/* the intro stands in the middle: the heading is short and the sub is one line, so a left-set block left a hole on the right (slice R1) */
.klant-intro { padding-top: var(--sec-y); padding-bottom: var(--kop-y); text-align: center; }
.klant-intro .kop2 { max-width: 15em; margin-inline: auto; }
.klant-intro .sub { margin-inline: auto; }
.klant-intro .sec-label { justify-content: center; }
/* the index rule, centred: the red mark on the middle of a hairline that fades to nothing at both ends */
.klant-intro .sec-label::before { left: 50%; margin-left: -19px; transform-origin: 50% 50%; }
.klant-intro .sec-label::after { left: 50%; width: clamp(150px, 19vw, 280px); margin-left: calc(clamp(150px, 19vw, 280px) / -2); transform-origin: 50% 50%; background: linear-gradient(90deg, transparent, var(--lijn) 26%, var(--lijn) 74%, transparent); }
.klant-intro .sec-label.wacht::before, .klant-intro .sec-label.wacht::after { transform: scaleX(0); }
/* the hold: the wrapper is the tall element houd() measures, so the intro and the outro stay outside it (spec §1: no hold starts where
   another releases). The podium is its sticky stage */
.klant-houd > .houd-podium { min-height: 600px; }
/* the text and the card are read together, so on a wide screen they move towards each other instead of to the two edges: the grid keeps
   its own narrower width, the card is bigger and the copy column sets to its right edge (slice R1) */
.klant-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(440px, 620px); gap: clamp(28px, 3vw, 72px); align-items: center; height: 100%; max-width: 1380px; padding-top: 90px; padding-bottom: 40px; }
.klant-links { justify-self: end; width: 100%; max-width: 33em; }
.gaten { list-style: none; margin: 0; padding: 0; }
.gat { margin-bottom: 56px; }
.gat h3 { margin: 0 0 20px; font-size: clamp(30px, 3.8vw, 58px); font-weight: 640; line-height: 1.05; letter-spacing: -.02em; text-wrap: balance; }
.gat p { margin: 0 0 10px; max-width: 30em; font-size: clamp(17px, 1.2vw, 20px); line-height: 1.5; color: var(--fg2); }
.gat .gevolg { color: var(--fg); font-weight: 600; }
.gat-n { display: inline-block; margin-bottom: 20px; padding: 5px 10px; border: 1px solid var(--rood); border-radius: 99px; font-size: 12px; line-height: 1; color: var(--fg); }
/* step 5, the turn: the concession is set back in grey at reading scale and the red verdict lands after it, twice its size (slice R1) */
.gat-slot h3 { max-width: 15em; margin-bottom: 14px; font-size: clamp(26px, 2.6vw, 40px); font-weight: 500; line-height: 1.15; letter-spacing: -.015em; color: var(--fg2); }
.gat-slot .gevolg { font-size: clamp(34px, 4.2vw, 68px); font-weight: 740; line-height: 1.02; letter-spacing: -.03em; color: var(--rood); max-width: 11em; }
.beweeg .gat-slot .gevolg { opacity: 0; transform: translateY(26px); transition: opacity .5s var(--e-in), transform .5s var(--e-in); }
.beweeg .gat-slot.is-nu .gevolg { opacity: 1; transform: none; transition: opacity var(--t-deel) var(--e-uit) .44s, transform var(--t-deel) var(--e-uit) .44s; }
/* step 6, the payoff: the same weight as the verdict it answers, with the promise in red. The term is in the sentence, not on a pill above
   it (Alex, 18-09): it used to sit over an 88 px headline and arrive 180 ms after it, so the eye took the headline first */
.gat-brug h3 { max-width: 13em; margin-bottom: 18px; font-size: clamp(36px, 4.9vw, 82px); font-weight: 760; line-height: .99; letter-spacing: -.035em; }
.gat-brug h3 em { display: inline-block; font-style: normal; color: var(--rood); }
.gat-brug p { max-width: 26em; font-size: clamp(18px, 1.35vw, 22px); color: var(--fg); }
.beweeg .gat-brug h3 em { opacity: 0; transform: translateY(.2em); transition: opacity .5s var(--e-in), transform .5s var(--e-in); }
.beweeg .gat-brug.is-nu h3 em { opacity: 1; transform: none; transition: opacity var(--t-deel) var(--e-uit) .4s, transform var(--t-deel) var(--e-uit) .4s; }
/* the steps swap on time, not on the scroll: the outgoing text leaves in 60 % of the entrance (spec §3) */
.beweeg .klant-links { position: relative; }
.beweeg .gaten { position: relative; min-height: clamp(440px, 48vh, 560px); }
.beweeg .gat { position: absolute; left: 0; right: 0; top: 0; margin: 0; opacity: 0; visibility: hidden; transform: translateY(56px); transition: opacity .42s var(--e-in), transform .42s var(--e-in), visibility 0s .42s; }
.beweeg .gat.is-voorbij { transform: translateY(-56px); }
.beweeg .gat.is-nu { opacity: 1; visibility: visible; transform: none; transition: opacity var(--t-deel) var(--e-uit) .12s, transform var(--t-deel) var(--e-uit) .12s, visibility 0s; }
/* the outro: the closing line and the CTA, at least half a screen after the hold releases (spec §1) */
.klant-uit { display: flex; flex-direction: column; justify-content: flex-start; align-items: center; text-align: center; padding-top: 0; padding-bottom: var(--sec-y); }
.klant-uit-zin { margin: 0 auto; max-width: 18em; font-size: clamp(26px, 2.8vw, 46px); font-weight: 640; line-height: 1.1; letter-spacing: -.02em; color: var(--fg); text-wrap: balance; }
.klant-uit-zin em { display: inline-block; color: var(--rood); }
.klant-uit-cta { margin-top: clamp(24px, 3.5vh, 36px); max-width: none; justify-content: center; }

/* without JavaScript, on the quiet tier and with ?rust=1: no hold, the stage is not sticky, the steps stack beside a card that sticks
   (the same three lines as 01-held.css; they belong in src/core/basis.css for every held section, noted for the wave close) */
html:not(.beweeg) .klant-grid { align-items: start; height: auto; }
html:not(.beweeg) .gkaart { position: sticky; top: 100px; align-self: start; }

.gkaart { position: relative; margin: 0; padding: 22px 22px 16px; border-radius: 24px; background: #fff; color: var(--inkt); font-size: 15px; line-height: 1.35; box-shadow: 0 50px 120px -30px rgba(0, 0, 0, .7), 0 0 0 1px rgba(255, 255, 255, .08); }
.gk-kop { display: flex; flex-wrap: wrap; gap: 12px; justify-content: space-between; align-items: center; margin-bottom: 8px; }
.gk-zoek { flex: 1 1 260px; margin: 0; display: flex; align-items: center; gap: 12px; padding: 12px 18px; border: 1px solid #e2e2e2; border-radius: 99px; font-size: 15px; }
.gk-schakel { margin: 0; display: flex; gap: 2px; padding: 4px; border-radius: 99px; background: #f0efed; font-size: 12px; }
.gk-schakel button { border: 0; background: transparent; padding: 8px 12px; border-radius: 99px; cursor: pointer; color: #666; text-transform: uppercase; letter-spacing: .04em; transition: background-color .4s, color .4s; }
.gk-schakel button.is-aan { background: var(--inkt); color: #fff; }
.gk-lijst { list-style: none; margin: 0; padding: 0; }
.gk-rij { position: relative; display: flex; justify-content: space-between; align-items: center; gap: 16px; padding: 14px 0; border-top: 1px solid #ececec; transition: opacity .6s; }
.gk-naam { margin: 0; display: flex; align-items: center; gap: 10px; font-size: 18px; font-weight: 650; letter-spacing: -.015em; transition: color .25s; }
.gk-meta { margin: 2px 0 0; font-size: 13.5px; color: #6b6b6b; }
.ster { font-style: normal; font-size: 11px; letter-spacing: 1px; color: var(--inkt); }
.ster-deel { background: linear-gradient(90deg, var(--inkt) 84%, #cfcfcf 84%); -webkit-background-clip: text; background-clip: text; color: transparent; }
.gk-duim { position: relative; flex: none; width: 92px; height: 66px; border-radius: 10px; background: linear-gradient(135deg, #d6d6d6, #a9a9a9); }
.gk-duim.d2 { background: linear-gradient(135deg, #c9c9c9, #8f8f8f); }
.gk-duim::after, .speel { content: ''; position: absolute; left: 50%; top: 50%; width: 24px; height: 24px; margin: -12px 0 0 -12px; border-radius: 50%; background: rgba(255, 255, 255, .9); }
.gk-duim::before { content: ''; position: absolute; z-index: 1; left: 50%; top: 50%; margin: -5px 0 0 -3px; border-left: 8px solid var(--inkt); border-top: 5px solid transparent; border-bottom: 5px solid transparent; }
.gk-vouw { justify-content: center; gap: 10px; padding: 9px 0; font-size: 12px; color: #8a8a8a; text-transform: uppercase; letter-spacing: .06em; }
/* his row: the wash (background and rim) takes 250 ms, the same beat as the name and the tab */
.gk-uw { margin: 0 -12px; padding: 14px 12px; border-radius: 14px; border-top-color: transparent; background: #f5f4f2; transition: background-color .25s, box-shadow .25s, opacity .6s; }
.gk-spons { position: absolute; left: 12px; top: -9px; margin: 0; padding: 3px 7px; border-radius: 4px; background: #fff; box-shadow: inset 0 0 0 1.5px var(--rood); font-size: 9.5px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--rood-tekst); opacity: 0; transform: translateY(4px); transition: opacity .25s, transform .25s var(--e-uit); }
.gk-dit { padding: 4px 8px; border-radius: 99px; background: var(--inkt); color: #fff; font-size: 9.5px; font-weight: 500; letter-spacing: .06em; text-transform: uppercase; transition: background-color .25s; }
.gk-gaten { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 10px 14px; }
.gk-gaten li { position: relative; display: inline-flex; align-items: center; gap: 6px; padding: 5px 16px 5px 10px; border: 1px solid #dcdcdc; border-radius: 99px; font-size: 12.5px; color: #777; transition: border-color .5s, color .5s, box-shadow .5s, background-color .5s; }
.gk-n, .gk-haak { display: none; }
.gk-m { position: absolute; top: -10px; right: -10px; width: 22px; height: 22px; display: grid; place-items: center; border-radius: 50%; background: var(--rood-knop); color: #fff; font-size: 9.5px; font-weight: 500; transform: scale(0); transition: transform .6s var(--uit); }
.gk-vouw .gk-m { position: static; }
.gk-beeld { position: relative; flex: none; width: 112px; height: 80px; border-radius: 10px; overflow: hidden; background: #e4e3e0; }
.gk-beeld img { width: 100%; height: 100%; object-fit: cover; opacity: 0; transform: scale(1.25); transition: opacity .9s var(--uit), transform 1.2s var(--uit); }
.gk-beeld .speel { opacity: 0; transition: opacity .6s .4s; }
.speel::before { content: ''; position: absolute; left: 50%; top: 50%; margin: -5px 0 0 -3px; border-left: 8px solid var(--inkt); border-top: 5px solid transparent; border-bottom: 5px solid transparent; }
/* the steps on the card: 0 outlines his row (the sub says it), 1 to 4 light one gap each, 5 lights all four at once */
.gkaart[data-stap="0"] .gk-uw { box-shadow: inset 0 0 0 1.5px var(--inkt); }
.gkaart[data-stap="1"] [data-m="1"], .gkaart[data-stap="2"] [data-m="2"], .gkaart[data-stap="3"] [data-m="3"],
.gkaart[data-stap="5"] .gk-gaten li { border-color: var(--rood); color: var(--rood); background: #fff; box-shadow: 0 0 0 5px rgba(237, 29, 36, .14); }
.gkaart[data-stap="4"] .gk-vouw, .gkaart[data-stap="5"] .gk-vouw { color: var(--rood); }
.gkaart[data-stap="1"] [data-m="1"] .gk-m, .gkaart[data-stap="2"] [data-m="2"] .gk-m, .gkaart[data-stap="3"] [data-m="3"] .gk-m, .gkaart[data-stap="4"] [data-m="4"] .gk-m,
.gkaart[data-stap="5"] .gk-m { transform: scale(1); }
.gkaart[data-stap="1"] .gk-rij:not(.gk-uw), .gkaart[data-stap="2"] .gk-rij:not(.gk-uw), .gkaart[data-stap="3"] .gk-rij:not(.gk-uw), .gkaart[data-stap="4"] .gk-rij:not(.gk-vouw),
.gkaart[data-stap="5"] .gk-rij:not(.gk-uw):not(.gk-vouw) { opacity: .42; }
/* after 12 weeks: the row is at the top (Flip, 1,1 s, in 03-klant.js), then the wash, the name and the tab in 250 ms, then the checks */
.gkaart.is-na .gk-uw { background: #fff0ef; box-shadow: inset 0 0 0 1.5px var(--rood); opacity: 1; }
.gkaart.is-na .gk-spons { opacity: 1; transform: none; }
.gkaart.is-na .gk-naam { color: var(--rood-tekst); }
.gkaart.is-na .gk-dit { background: var(--rood); }
.gkaart.is-na .gk-v { display: none; }
.gkaart.is-na .gk-n { display: inline; }
.gkaart.is-na .gk-haak { display: inline-block; width: 13px; height: 13px; background: var(--rood); -webkit-mask: var(--haak) center / contain no-repeat; mask: var(--haak) center / contain no-repeat; animation: haak-teken .25s var(--e-uit) both; animation-delay: calc(.25s + var(--i, 0) * 80ms); }
@keyframes haak-teken { from { clip-path: inset(0 100% 0 0); transform: scale(.6); } to { clip-path: inset(0 -20% 0 0); transform: none; } }
.gkaart.is-na .gk-gaten li { border-color: rgba(237, 29, 36, .35); color: var(--inkt); background: #fff; box-shadow: none; }
.gkaart.is-na .gk-gaten .gk-m { transform: scale(0); }
.gkaart.is-na .gk-beeld img, .gkaart.is-na .gk-beeld .speel { opacity: 1; transform: none; }
.gkaart.is-na .gk-rij:not(.gk-uw) { opacity: .5; }
/* the player bar (D-166): a video player's controls across the foot of the card, so the hold shows how far he is and how much is left.
   The chapters are the six steps, each as wide as its band; the played part is red and the head follows every pixel (03-klant.js) */
.klant .sp { margin: 14px -22px -16px; padding: 12px 20px 10px; border-radius: 0 0 24px 24px; background: var(--inkt); color: #fff; }
html:not(.beweeg) .klant .sp { display: none; }
.klant .sp-balk { position: relative; height: 22px; cursor: pointer; }
.klant .sp-hfst { position: absolute; top: 50%; left: calc(var(--a) * 100% + 2px); width: calc((var(--b) - var(--a)) * 100% - 4px); height: 6px; margin-top: -3px; border-radius: 3px; background: rgba(255, 255, 255, .24); transition: height .2s, margin .2s, background-color .2s; }
.klant .sp-hfst.is-nu { height: 10px; margin-top: -5px; }
.klant .sp-vul { position: absolute; inset: 0; border-radius: inherit; background: var(--rood); transform-origin: 0 50%; transform: scaleX(var(--f, 0)); }
.klant .sp-kop { position: absolute; z-index: 2; top: 50%; left: calc(var(--p, 0) * 100%); width: 18px; height: 18px; margin: -9px 0 0 -9px; border-radius: 50%; background: var(--rood); pointer-events: none; transition: transform .25s var(--e-uit), box-shadow .3s; }
.klant .sp.is-loopt .sp-kop { transform: scale(1.25); box-shadow: 0 0 0 6px rgba(237, 29, 36, .28); }
.klant .sp-ctrl { display: flex; align-items: center; gap: 14px; margin-top: 6px; font-size: 13.5px; }
/* play while he stands still, pause while he scrolls: the film runs only while he moves it */
.klant .sp-speel { position: relative; flex: none; width: 30px; height: 30px; margin-left: -6px; padding: 0; border: 0; border-radius: 50%; background: transparent; color: #fff; cursor: pointer; transition: background-color .2s; }
.klant .sp-speel::before { content: ''; position: absolute; left: 11px; top: 8px; width: 0; height: 0; border-left: 12px solid currentColor; border-top: 7px solid transparent; border-bottom: 7px solid transparent; }
.klant .sp.is-loopt .sp-speel::before { left: 9px; width: 4px; height: 14px; border: 0; background: currentColor; box-shadow: 8px 0 0 currentColor; }
.klant .sp-tijd { flex: none; font-size: 12px; color: rgba(255, 255, 255, .6); }
.klant .sp-tijd b { font-weight: 500; color: #fff; }
.klant .sp-titel { display: flex; align-items: center; gap: 8px; min-width: 0; overflow: hidden; font-weight: 600; }
.klant .sp-bol { flex: none; width: 4px; height: 4px; border-radius: 50%; background: rgba(255, 255, 255, .5); }
.klant .sp-titel span { display: inline-block; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.klant .sp-titel span.is-in { animation: sp-in .4s var(--e-uit); }
.klant .sp-titel span.is-terug { animation: sp-terug .4s var(--e-uit); }
@keyframes sp-in { from { opacity: 0; transform: translateY(12px); } }
@keyframes sp-terug { from { opacity: 0; transform: translateY(-12px); } }
.klant .sp-pijl { flex: none; font-style: normal; }
.klant .sp-pijl::before { content: '\203A'; font-size: 17px; line-height: 1; color: rgba(255, 255, 255, .6); }
.klant .sp-n { flex: none; margin-left: auto; font-size: 11px; color: rgba(255, 255, 255, .55); }
.klant .sp-n b { font-weight: 500; color: #fff; }
/* with a mouse: the bar thickens under the pointer and names the chapter, as a player does. Not on touch, where a hover would stick */
@media (hover: hover) {
  .klant .sp-balk:hover .sp-hfst { height: 10px; margin-top: -5px; }
  .klant .sp-hfst:hover { background: rgba(255, 255, 255, .4); }
  .klant .sp-speel:hover { background: rgba(255, 255, 255, .12); }
  .klant .sp-hfst::after { content: attr(data-titel); position: absolute; bottom: 16px; left: 50%; padding: 6px 10px; border-radius: 7px; background: var(--inkt); box-shadow: 0 8px 24px rgba(0, 0, 0, .25); color: #fff; font-size: 12px; font-weight: 600; white-space: nowrap; opacity: 0; transform: translate(-50%, 4px); pointer-events: none; transition: opacity .2s, transform .2s; }
  .klant .sp-hfst:hover::after { opacity: 1; transform: translate(-50%, 0); }
}
/* on touch the bar and play are a thumb's height to hit, though they draw as before */
@media (pointer: coarse) {
  .gk-schakel button { position: relative; }
  .gk-schakel button::before { content: ''; position: absolute; inset: -4px 0; }
  .klant .sp-balk { height: 30px; }
  .klant .sp-speel { width: 36px; height: 36px; margin-left: -8px; }
  .klant .sp-speel::before { left: 14px; top: 11px; }
  .klant .sp.is-loopt .sp-speel::before { left: 12px; top: 11px; }
}
/* lite (spec §7): the card above the text, no tilt (03-klant.js) */
[data-tier=lite] .klant-grid { grid-template-columns: 1fr; gap: 18px; align-items: start; padding-top: 84px; }
[data-tier=lite] .gkaart { order: -1; }
[data-tier=lite].beweeg .gaten { min-height: 250px; }
@media (max-width: 1100px) {
  .klant-grid { grid-template-columns: minmax(0, 1fr) minmax(340px, 440px); }
}
@media (max-width: 760px) {
  .klant-grid { grid-template-columns: 1fr; gap: 18px; padding-top: 70px; padding-bottom: 20px; }
  .gkaart { order: -1; padding: 14px 14px 10px; font-size: 13px; border-radius: 18px; }
  .gk-zoek { flex-basis: 100%; padding: 9px 14px; font-size: 13px; }
  .gk-kop { gap: 8px; }
  /* the phone tier (slice D): the card's own switch is tapped, so it gets a thumb's height inside the Google chrome */
  .gk-schakel button { min-height: 36px; padding: 8px 14px; }
  .gk-rij { padding: 9px 0; gap: 10px; }
  .gk-uw { margin: 0 -8px; padding: 10px 8px; }
  .gk-spons { left: 8px; }
  .gk-naam { font-size: 15px; }
  .gk-meta { font-size: 12px; }
  .gk-duim { width: 58px; height: 42px; }
  .gk-beeld { width: 72px; height: 54px; }
  .gk-gaten li { font-size: 11px; padding: 4px 13px 4px 8px; }
  .gk-m { width: 18px; height: 18px; top: -8px; right: -8px; font-size: 8.5px; }
  /* the bar is one row here, play, chapters, count: the step's own heading stands right under the card, so the title and the time go,
     and the card stays short enough for the text under it on a 780 px screen */
  .klant .sp { display: flex; align-items: center; gap: 8px; margin: 10px -14px -10px; padding: 5px 14px 5px 6px; border-radius: 0 0 18px 18px; }
  .klant .sp-ctrl { display: contents; }
  .klant .sp-speel { order: -1; margin-left: 0; }
  .klant .sp-balk { flex: 1 1 auto; }
  .klant .sp-tijd, .klant .sp-titel { display: none; }
  .klant .sp-n { margin-left: 2px; }
  .beweeg .gaten { min-height: 270px; }
  .gat h3 { font-size: 30px; margin-bottom: 12px; }
  .gat p { font-size: 15.5px; }
  .gat-n { margin-bottom: 10px; }
  .gat-slot h3 { font-size: 21px; margin-bottom: 8px; }
  .gat-slot .gevolg { font-size: 31px; margin-bottom: 0; }
  .gat-brug h3 { font-size: 32px; margin-bottom: 12px; }
  .gat-brug p { font-size: 16px; }
  .klant-uit-zin { font-size: 26px; }
}
@media (prefers-reduced-motion: reduce) {
  .gkaart.is-na .gk-haak { animation: none; }
}

/* ---------- the trades band (Alex, 18-09): the section's own bottom edge ----------
   Full width, not in .rand, and the last thing in the night section, so it stays black while the ground turns white under "Wat wij
   doen". A fixed label cell on the left, then two copies of the trades running past for ever. Scoped under .klant so the names cannot
   collide with another section's rules. Lifted from De werf v2's vakband (D-061). */
.klant .vakband { position: relative; display: flex; align-items: stretch; overflow: hidden; border-top: 1px solid var(--lijn); border-bottom: 1px solid var(--lijn); }
/* the names run under the label, so it carries the ground's own colour and covers them */
.klant .vakband-label { position: relative; z-index: 2; flex: none; display: flex; align-items: center; margin: 0; padding: 0 18px 0 var(--rand); background: #0E0F11; border-right: 1px solid var(--lijn); font-size: 11px; letter-spacing: .09em; text-transform: uppercase; color: var(--fg2); }
.klant .vakken { display: flex; flex: none; width: max-content; margin: 0; padding: 16px 0 15px; white-space: nowrap; font-size: clamp(13px, 1.1vw, 15px); font-weight: 500; letter-spacing: .1em; text-transform: uppercase; color: var(--fg); }
/* the element is empty: its two pseudo-elements are the two copies, so the loop closes on itself at -50% */
.klant .vakken::before, .klant .vakken::after { content: attr(data-v); padding-left: 1.1em; }
html.beweeg .klant .vakken { animation: vakken 60s linear infinite; }
/* It does not stop under the pointer (Alex, 18-09, as on the proof strip). The band fills the width, so a pointer left anywhere near the
   middle of the screen is on it, and a scroll drags the band across that pointer: the loop froze while it passed under it and ran on
   after, which is the stutter that looked like the band catching up with the section. Only the button and the fold stop it now. */
.klant .vakband:is(.is-stil, .is-buiten) .vakken { animation-play-state: paused; }
@keyframes vakken { to { transform: translateX(-50%); } }
/* the pause control, under a fade so the names do not run into it */
.klant .vakband-knop { position: absolute; z-index: 2; top: 0; right: 0; bottom: 0; display: grid; place-items: center; width: calc(var(--rand) + 92px); padding-left: 48px; border: 0; background: linear-gradient(90deg, rgba(14, 15, 17, 0), #0E0F11 52%); color: var(--fg); cursor: pointer; }
.klant .vakband-knop::after { content: ''; width: 10px; height: 12px; background: linear-gradient(90deg, currentColor 0 3.5px, transparent 3.5px 6.5px, currentColor 6.5px); }
.klant .vakband-knop[aria-pressed="true"]::after { background: currentColor; clip-path: polygon(0 0, 100% 50%, 0 100%); }
@media (max-width: 760px) {
  /* the label would eat the screen, so it goes and the band is the names alone */
  .klant .vakband-label, .klant .vakband-knop { display: none; }
  .klant .vakken { padding: 13px 0 12px; }
}
@media (prefers-reduced-motion: reduce) {
  .klant .vakken { animation: none; }
}

/* ---------- src/sections/04-wij.css ---------- */

/* ============ 3 · Wat wij doen: intro, proof strip, then the wheel's sticky hold (slice C2) ============ */
.wij { position: relative; }
.wij-intro { padding-top: var(--sec-y); padding-bottom: var(--kop-y); }
.wij-intro .kop2 { max-width: 16em; }
.wij-intro .sub { max-width: 40em; }
/* the hold's height stands here, not in the script (slice D, CLS); on lite the wheel is a list, so nothing is held */
.wiel-houd { --houd: 2.8; }

/* ---------- the proof strip (kit 9): the calm passage between two holds; the figures count up once. Capped at the heading's own measure
     so the block ends where the title ends instead of running to the page's edge — the cap sits on the track, not on its .rand, so the
     left edge stays flush with the intro above ----------
   Reworked 18-09 (Alex: the block looks messy), then settled on the band (Alex, 18-09): one row of seven identical cells, three and a
   half of them in the measure, drifting on for ever. It does not stop under the pointer — the reader who wants to steer it drags it or
   presses one of the two arrows under it.
   The cell is always figure · unit · two lines of caption · the tag on its own bottom line. The tag used to sit inside the caption and
   broke its lines, which is what made every cell end at a different height. */
/* 13,4 em, not the heading's own 16 em: text-wrap balance breaks the title well before its max-width, so this is where the title
   really ends on the screen and where the rule and the cells now end with it */
.strook-rand { --meet: calc(13.4 * clamp(34px, 4.4vw, 68px)); --cel: clamp(200px, 25.6%, 280px); padding-bottom: var(--kop-y); }
/* the rule that opens the strip, with the arrows sitting on its right end: the control costs the block no height of its own, and the
   rule running into it is what ties the two together (Alex, 18-09) */
.strook-kop { display: flex; align-items: center; gap: clamp(14px, 1.6vw, 22px); max-width: var(--meet); }
.strook-lijn { flex: 1; height: 1px; background: var(--lijn); }
/* the track's box: the clip that the band runs behind */
.strook-baan { max-width: var(--meet); }
/* padding-inline: 0 kills the browser's 40 px list indent, which pushed every figure right of the heading above it (Alex, 18-09) */
.strook { list-style: none; margin: 0; padding-inline: 0; padding-top: clamp(24px, 4vh, 44px); padding-bottom: clamp(28px, 4vh, 44px); }
.strook-i { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; }
.strook-n { display: flex; align-items: baseline; gap: 10px; min-height: 1em; font-size: clamp(40px, 3.8vw, 58px); font-weight: 640; line-height: 1; letter-spacing: -.035em; }
.strook-n small { font-size: .3em; font-weight: 600; letter-spacing: 0; color: var(--fg2); }
/* the badge has no figure of its own, so the mark stands where the digits stand and Partner where the unit stands — the word Google is
   gone, the mark says it (Alex, 18-09) */
.strook-g { align-items: center; }
.strook-g svg { flex: none; width: clamp(34px, 3vw, 44px); height: auto; }
.strook-g small { font-size: .32em; }
/* two lines, always: the box is reserved so the tags below line up across the row even where the caption runs short */
.strook-t { min-height: 2.9em; font-size: 14.5px; line-height: 1.45; color: var(--fg2); }
.strook-i .tbc { margin-top: auto; }

/* --- the band: one row, seven cells and their clone, pulled left for ever. The hairline between cells is what makes the seven read as
       one set; the cell that is cut by the right edge is the invitation to wait for the rest --- */
.strook-baan { overflow: hidden; }
.strook { display: flex; flex-wrap: nowrap; }
/* The drift is the browser's own animation, so the compositor keeps its pace while the main thread is busy with the scroll below it: a
   drift written per frame from JavaScript moved in whatever step the last frame happened to be long, and against a page that scrolls on
   the compositor that reads as the band stuttering and catching up (Alex, 18-09). --set is one set of seven cells, measured; the row is
   that set twice, so at the end of every turn the row stands exactly where it started. The push from a drag or an arrow rides on the
   wrapper and only moves while that push lives. */
.band-aan .strook { animation: strook-drift var(--duur, 40s) linear infinite; will-change: transform; }
.band-aan.sleept .strook { animation-play-state: paused; }
@keyframes strook-drift { from { transform: translate3d(0, 0, 0); } to { transform: translate3d(calc(var(--set, 0px) * -1), 0, 0); } }
.strook-i { flex: 0 0 var(--cel); padding-right: clamp(18px, 2vw, 30px); padding-left: clamp(18px, 2vw, 30px); border-left: 1px solid var(--lijn); }
.strook-i:first-child { padding-left: 0; border-left: 0; }
.strook-t { min-height: 4.35em; }
/* the whole row is draggable while it drifts, so it says so with the cursor and gives no text selection away under the drag */
.band-aan { cursor: grab; touch-action: pan-y; }
.band-aan.sleept { cursor: grabbing; user-select: none; }
/* without the script, under reduced motion and on the phone the band is a plain row the reader pushes along */
.strook-baan:not(.band-aan) { overflow-x: auto; scrollbar-width: none; scroll-snap-type: x proximity; }
.strook-baan:not(.band-aan)::-webkit-scrollbar { display: none; }
.strook-baan:not(.band-aan) .strook-i { scroll-snap-align: start; }

/* the two arrows: one compact pill on the rule, quiet until the pointer is on a half. The pill carries the ring, the halves only the
   hairline between them, so the whole control is 64 px wide and reads as one thing */
.strook-stuur { flex: none; display: flex; overflow: hidden; border: 1px solid var(--lijn); border-radius: 99px; background: none; }
.strook-p { display: grid; place-items: center; width: 32px; height: 30px; padding: 0; border: 0; background: none; color: var(--fg2); cursor: pointer; transition: background var(--t-druk) linear, color var(--t-druk) linear; }
.strook-p + .strook-p { box-shadow: inset 1px 0 0 var(--lijn); }
.strook-p:hover { color: var(--fg); background: color-mix(in srgb, var(--fg) 6%, transparent); }
.strook-p:active { background: color-mix(in srgb, var(--fg) 12%, transparent); }
.strook-p svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* ---------- the drawing in the right column (Alex, 24-09; the team photo of 18-09 before it) ----------
   The strip stops at the heading's measure, which leaves about 430 px of empty page beside it at 1440. The figure stands there,
   absolutely, so neither the intro nor the strip has to change its own box. It is /online-marketing/'s five places (core/koppen.css and
   core/koppen.js), each with another client's frame, drawn in ink on the white ground where that head draws in white on graphite */
.wij-boven { position: relative; }
.wij-foto { position: absolute; z-index: 1; right: var(--rand); top: clamp(150px, 21vh, 250px); width: clamp(280px, calc(100vw - var(--rand) * 2 - 13.4 * clamp(34px, 4.4vw, 68px) - clamp(64px, 6vw, 120px)), 600px); margin: 0; }
.wij-tek { --kp-a: .62; --kp-tx: 15px; color: rgb(20 20 20 / var(--kp-a)); }
.wij-tek svg .f { color: rgb(20 20 20 / calc(var(--kp-a) * .6)); }
.wij-tek svg .foto { opacity: .95; }
.wij-tek svg .foto image { filter: saturate(.85); }

/* ---------- the hold: 2,8 screens, nothing pinned (spec §7, fix 2). It starts under the strip, so the section's own height is not used ---------- */
.wiel-houd > .houd-podium { min-height: 620px; }
.wiel-podium { position: relative; height: 100%; display: grid; grid-template-columns: 27vw minmax(0, 1fr) minmax(0, 36vw); align-items: center; gap: 0 clamp(24px, 3vw, 56px); padding: 92px var(--rand) 96px 0; }

/* the dial names all five services, all five stay on screen, each one is a button that jumps to its step (spec §2, wheel 1) */
.wiel { --R: min(46vh, 26vw); --step: 16deg; --base: 0deg; --dir: 1; position: relative; align-self: stretch; }
.wiel-draai { position: absolute; left: calc(var(--R) * -.6); top: 50%; width: 0; height: 0; transform: rotate(calc(var(--p, 0) * var(--step) * var(--dir) * -1)); }
.wiel-ring { position: absolute; left: calc(var(--R) * -1); top: calc(var(--R) * -1); width: calc(var(--R) * 2); height: calc(var(--R) * 2); max-width: none; overflow: visible; }
.wr-lijn { fill: none; stroke: var(--lijn); stroke-width: .35; }
/* the dash pattern closes at the circle's own start point, 3 o'clock, which is exactly the arc that stands beside the names: Chrome's
   rounding there put two ticks a hair apart (Alex, 18-09). The circle carries rotate(180), so that seam sits at 9 o'clock, far off screen */
.wr-tik { fill: none; stroke: var(--fg); stroke-opacity: .3; stroke-width: 3; stroke-dasharray: .35 2.65; }
.wiel-num { list-style: none; margin: 0; padding: 0; position: absolute; left: 0; top: 0; }
.wiel-num li { position: absolute; left: 0; top: 0; width: 0; height: 0; transform: rotate(calc(var(--base) + var(--i) * var(--step) * var(--dir))) translateX(var(--R)); }
/* the arc tilts the anchors; every name turns back so all five read level, whatever the dial's angle (spec §2, wheel 1) */
.wiel-num button {
  position: absolute; left: 26px; top: 0; display: flex; align-items: baseline; gap: 9px; padding: 7px 10px 7px 0; border: 0; background: none; cursor: pointer;
  white-space: nowrap; text-align: left; color: var(--fg2); opacity: .55; transform-origin: 0 50%;
  transform: translateY(-50%) rotate(calc((var(--p, 0) - var(--i)) * var(--step) * var(--dir) - var(--base))); transition: opacity .4s, color .4s;
}
.wiel-num button b { font-size: 11px; font-weight: 500; letter-spacing: .06em; }
.wiel-num button span { font-size: clamp(17px, 1.45vw, 21px); font-weight: 620; letter-spacing: -.02em; }
.wiel-num button:hover { opacity: .85; }
.wiel-num li.is-nu button { color: var(--fg); opacity: 1; }
.wiel-num li.is-nu button b { color: var(--rood-tekst); }
.wiel-wijzer { position: absolute; top: 50%; left: calc(var(--R) * .4); width: 11px; height: 11px; margin: -5.5px 0 0 -5.5px; border-radius: 50%; background: var(--rood); box-shadow: 0 0 0 6px rgba(237, 29, 36, .16); }

.diensten { list-style: none; margin: 0; padding: 0; position: relative; }
.dienst { padding: 40px 0; }
.dienst-n { margin: 0 0 22px; font-size: 12px; letter-spacing: .08em; color: var(--rood-tekst); }
.dienst h3 { margin: 0 0 22px; font-size: clamp(30px, 3.6vw, 56px); font-weight: 640; line-height: 1.05; letter-spacing: -.02em; }
.dienst-tekst { margin: 0 0 28px; max-width: 26em; font-size: clamp(17px, 1.2vw, 20px); line-height: 1.5; color: var(--fg2); }
.pillen { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.pillen li { padding: 10px 16px; border-radius: 99px; background: #fff; color: var(--inkt); font-size: 14px; line-height: 1; box-shadow: 0 1px 0 rgba(0, 0, 0, .04); }
/* on the stage the five services share one place; in the list they stand one under the other */
html.beweeg .wij:not(.wiel-lijst) .diensten { height: min(62vh, 580px); }
html.beweeg .wij:not(.wiel-lijst) .dienst { position: absolute; left: 0; right: 0; top: 50%; transform: translateY(-50%); padding: 0; pointer-events: none; }
html.beweeg .wij:not(.wiel-lijst) .dienst.is-nu { pointer-events: auto; }

/* the scenes: under ?wiel=stap they cross-fade as one, so nothing is ever half-cut over a playing clip (spec §2, wheel 3) */
.podium { position: relative; height: min(72vh, 680px); }
.scene { position: absolute; inset: 0; }
.scene-in { position: absolute; inset: 0; overflow: hidden; border-radius: 28px; background: var(--inkt); }
.scene-film video { width: 100%; height: 100%; object-fit: cover; }
.scene-tag { position: absolute; left: 16px; bottom: 16px; z-index: 3; margin: 0; display: flex; align-items: center; gap: 8px; padding: 8px 11px; border-radius: 99px; background: rgba(20, 20, 20, .58); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); color: #fff; font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; }
[data-tier=lite] .scene-tag, [data-tier=standaard] .scene-tag { -webkit-backdrop-filter: none; backdrop-filter: none; background: rgba(20, 20, 20, .82); }
.scene-tag .tbc { border-color: rgba(255, 255, 255, .6); }
/* the readout never lies (kit 10): REC with a blinking dot only while the clip really plays, STBY otherwise */
.s-dot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: rgba(255, 255, 255, .45); }
.scene.is-rec .s-dot { background: var(--rood); animation: sknip 1.1s steps(1, end) infinite; }
@keyframes sknip { 0%, 55% { opacity: 1; } 56%, 100% { opacity: .15; } }

.scene-web .scene-in { background: var(--leisteen); }
.browser { position: absolute; left: 8%; right: 8%; top: 9%; bottom: 9%; display: flex; flex-direction: column; overflow: hidden; border-radius: 14px; background: #fff; color: var(--inkt); font-size: 12px; box-shadow: 0 40px 90px -30px rgba(0, 0, 0, .55); }
.br-balk { margin: 0; display: flex; align-items: center; gap: 6px; padding: 10px 12px; background: #efeeec; }
.br-balk i { width: 9px; height: 9px; border-radius: 50%; background: #d2d0cc; }
.br-balk span { flex: 1; margin-left: 10px; padding: 5px 12px; border-radius: 99px; background: #fff; font-size: 10px; color: #777; }
.br-pagina { position: relative; flex: 1; overflow: hidden; }
.br-nav { margin: 0; display: flex; align-items: center; gap: 14px; padding: 12px 16px; font-size: 11px; color: #555; }
.br-nav b { margin-right: auto; font-size: 14px; color: var(--inkt); letter-spacing: -.02em; }
.br-knop { padding: 6px 11px; border-radius: 99px; background: var(--rood); color: #fff; }
/* the browser's own scroll is a self-running loop too, so it runs only while this scene is the one the scheduler picked (kit 11, 15) */
.br-held, .br-rij { animation: brscroll 9s var(--inuit) infinite; animation-play-state: paused; }
.scene.is-loop .br-held, .scene.is-loop .br-rij { animation-play-state: running; }
.br-held { position: relative; height: 62%; margin: 0 16px; overflow: hidden; border-radius: 10px; }
.br-held img { width: 100%; height: 100%; object-fit: cover; }
/* the dark fade under the words, as /online-marketing/'s website use has it (Alex, 24-09: the white words got lost in the photo) */
.br-held::after { content: ''; position: absolute; inset: 0; background: linear-gradient(to top, rgba(12, 12, 12, .78) 0%, rgba(12, 12, 12, .42) 34%, rgba(12, 12, 12, 0) 68%), linear-gradient(to right, rgba(12, 12, 12, .32), rgba(12, 12, 12, 0) 60%); pointer-events: none; }
.br-held p { position: absolute; z-index: 1; left: 18px; bottom: 16px; margin: 0; color: #fff; font-size: clamp(20px, 2vw, 34px); font-weight: 650; line-height: 1; letter-spacing: -.02em; text-shadow: 0 2px 30px rgba(0, 0, 0, .35); }
.br-rij { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin: 8px 16px; }
.br-rij img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 8px; }
@keyframes brscroll { 0%, 18% { transform: none; } 45%, 70% { transform: translateY(-34%); } 92%, 100% { transform: none; } }

/* the post scene swipes its four tiles by itself, 2,2 s apart, under the scheduler (kit 11) */
.scene-post .scene-in { background: #1c1b1a; }
.telefoon { position: absolute; left: 50%; top: 50%; width: min(56%, 300px); aspect-ratio: 9 / 18.5; display: flex; flex-direction: column; padding: 12px; border-radius: 36px; background: #fff; color: var(--inkt); font-size: 12px; transform: translate(-50%, -50%) rotate(-5deg); box-shadow: 0 50px 100px -30px rgba(0, 0, 0, .8); }
.tf-account { margin: 4px 4px 10px; display: flex; align-items: center; gap: 8px; font-weight: 600; }
.tf-account i { width: 24px; height: 24px; border-radius: 50%; background: conic-gradient(var(--rood), #ff9a3c, var(--rood)); }
.tf-beeld { position: relative; flex: 1; overflow: hidden; border-radius: 14px; background: #ddd; }
.tf-rol { position: absolute; inset: 0; display: flex; width: 400%; }
.tf-rol img { width: 25%; height: 100%; object-fit: cover; }
.tf-acties { margin: 10px 4px 6px; display: flex; align-items: center; gap: 12px; }
.tf-acties svg { width: 20px; height: 20px; fill: none; stroke: var(--inkt); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.tf-acties svg:first-child { fill: var(--rood); stroke: var(--rood); }
.tf-stippen { margin-left: auto; display: flex; gap: 4px; }
.tf-stippen i { width: 5px; height: 5px; border-radius: 50%; background: #ccc; transition: background-color .3s; }
.tf-stippen i.aan { background: var(--inkt); }
.tf-tekst { margin: 0 4px 6px; line-height: 1.35; }

.scene-ad .scene-in { background: #e3ddd3; }
.advertentie { position: absolute; z-index: 2; left: 8%; right: 8%; top: 9%; padding: 20px; border-radius: 18px; background: #fff; color: var(--inkt); font-size: 14px; line-height: 1.35; box-shadow: 0 40px 80px -30px rgba(0, 0, 0, .35); }
.ad-spons { margin: 0 0 6px; display: flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 600; }
.ad-naam { margin: 0; font-size: 22px; font-weight: 660; letter-spacing: -.02em; }
.ad-kop { margin: 4px 0 8px; font-weight: 600; color: var(--rood-tekst); }
.ad-tekst { margin: 0 0 12px; color: #555; }
.advertentie img { width: 100%; aspect-ratio: 16 / 7; object-fit: cover; border-radius: 10px; }
.ad-kaart { position: absolute; left: 0; right: 0; bottom: 0; height: 42%; overflow: hidden; background-color: #d8d1c5; background-image: linear-gradient(rgba(20, 20, 20, .07) 1px, transparent 1px), linear-gradient(90deg, rgba(20, 20, 20, .07) 1px, transparent 1px); background-size: 32px 32px; }
.ad-kaart b { position: absolute; right: 16px; top: 14px; font-size: 10px; font-weight: 500; letter-spacing: .08em; text-transform: uppercase; color: #5a554e; }
.ad-cirkel { position: absolute; left: 50%; top: 58%; width: 180px; height: 180px; margin: -90px 0 0 -90px; border-radius: 50%; border: 1.5px solid var(--rood); background: rgba(237, 29, 36, .1); animation: puls 3s var(--uit) infinite; animation-play-state: paused; }
.scene.is-loop .ad-cirkel { animation-play-state: running; }
@keyframes puls { 0% { transform: scale(.4); opacity: 1; } 100% { transform: scale(1.5); opacity: 0; } }
.ad-stip { position: absolute; width: 10px; height: 10px; border-radius: 50%; background: var(--rood); box-shadow: 0 0 0 4px rgba(237, 29, 36, .2); }
.ad-stip.s1 { left: 50%; top: 58%; } .ad-stip.s2 { left: 38%; top: 72%; } .ad-stip.s3 { left: 62%; top: 46%; }

/* the report's bars run grey before and red at the result (D-063, kit 11) */
.scene-rapport .scene-in { background: var(--houtskool); }
.rapport { position: absolute; left: 11%; right: 11%; top: 7%; bottom: 7%; display: flex; flex-direction: column; padding: 22px; border-radius: 16px; background: #fff; color: var(--inkt); font-size: 13px; transform: rotate(2.5deg); box-shadow: 0 40px 80px -30px rgba(0, 0, 0, .45); }
.rp-strook { margin: 0 0 12px; display: flex; justify-content: space-between; font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: #888; }
.rp-strook span:first-child { color: var(--rood-tekst); }
.rp-kop { margin: 0 0 16px; font-size: clamp(18px, 1.6vw, 24px); font-weight: 660; letter-spacing: -.02em; }
.rp-maand { margin: 0 0 16px; display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.rp-maand div { padding: 12px; border-radius: 10px; background: #f4f2ef; }
.rp-maand dt { font-size: 11px; color: #5c5c5c; }
.rp-maand dd { margin: 6px 0 0; font-size: clamp(22px, 2vw, 32px); font-weight: 660; letter-spacing: -.025em; }
.rp-kopje { margin: 0 0 8px; font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: #6b6b6b; }
/* the bars take the slack the closing line left behind (Alex, 18-09): the card keeps its height, the chart grows into it */
.rp-staven { margin: 0 0 16px; display: flex; align-items: flex-end; gap: 8px; flex: 1; min-height: 50px; }
.rp-staven i { flex: 1; height: calc(var(--v) * 100%); border-radius: 5px 5px 0 0; background: #c6c2bb; transform-origin: bottom; transition: background-color .4s var(--e-uit); }
.rp-staven i.is-rood { background: var(--rood); }
.rp-deden { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.rp-deden li { padding: 5px 10px; border-radius: 99px; background: #f4f2ef; font-size: 12px; }

/* the closing line, now its own dark moment between the chalk of "Wat wij doen" and the day ground of "Ons werk" (Alex, 18-09).
   The wheel's red progress rail is gone with it: the dial and the pills already name the step, and the rail read as a line splitting
   this block off the section above. No plate and no bloom either — the type stands on the ground, which draws at full speed here. */
/* short, as Alex had it (19-09: "this cannot take up a whole section, it was good when it was short"). It was briefly a full screen
   because the ground could only paint two bands, so a world shorter than the screen ran on over the section beneath it. The ground draws
   three bands since 19-09 (`grond.js`, `grond-lagen.js`), so the night is exactly as tall as this block and the line keeps its own height. */
.wij-slot { position: relative; min-height: 38vh; min-height: 38svh; display: flex; justify-content: center; align-items: center; padding-block: calc((var(--kop-y) + var(--sec-y)) / 2); }
.slot-binnen { display: flex; flex-direction: column; align-items: center; gap: clamp(20px, 3vh, 32px); width: 100%; text-align: center; }
.wij-slot-zin { margin: 0; max-width: 17em; font-size: clamp(22px, 2.4vw, 38px); font-weight: 560; line-height: 1.3; letter-spacing: -.018em; text-wrap: balance; }

/* ---------- the list: on the phone the wheel is five services, each entering with its still (D-099, Q1 A), and the same list stands
     without JavaScript, on the quiet tier and with ?rust=1 (spec §3). The three lines below are 01-held.css's, until the wave close
     moves them into src/core/basis.css ---------- */
.wij.wiel-lijst .wiel-podium, html:not(.beweeg) .wij .wiel-podium { display: grid; grid-template-columns: minmax(0, 1fr); height: auto; padding: 0 var(--rand) clamp(40px, 8vh, 90px); gap: 0; }
.wij.wiel-lijst .wiel, html:not(.beweeg) .wij .wiel { display: none; }
.wij.wiel-lijst .diensten, html:not(.beweeg) .wij .diensten,
.wij.wiel-lijst .podium, html:not(.beweeg) .wij .podium { display: contents; }
.wij.wiel-lijst .dienst, html:not(.beweeg) .wij .dienst { order: calc(var(--i) * 2); position: static; transform: none; padding: clamp(34px, 6vh, 60px) 0 18px; pointer-events: auto; }
.wij.wiel-lijst .scene, html:not(.beweeg) .wij .scene { order: calc(var(--i) * 2 + 1); position: relative; inset: auto; aspect-ratio: 5 / 4; opacity: 1; }
.wij.wiel-lijst .scene-in, html:not(.beweeg) .wij .scene-in { border-radius: 20px; }
.wij.wiel-lijst .br-rij, html:not(.beweeg) .wij .br-rij { display: none; }
.wij.wiel-lijst .br-held, html:not(.beweeg) .wij .br-held { height: 82%; }
/* each pair rises once as it comes into view; without the scripts they simply stand */
html.beweeg .wij.wiel-lijst .dienst, html.beweeg .wij.wiel-lijst .scene { opacity: 0; transform: translateY(24px); transition: opacity .6s var(--e-uit), transform .6s var(--e-uit); }
html.beweeg .wij.wiel-lijst .dienst.is-in, html.beweeg .wij.wiel-lijst .scene.is-in { opacity: 1; transform: none; }

@media (min-width: 761px) and (max-height: 820px) {
  .wiel-podium { padding-top: 74px; padding-bottom: 96px; }
  .podium { height: calc(100svh - 196px); }
  .dienst h3 { margin-bottom: 14px; font-size: clamp(28px, 3vw, 44px); }
  .dienst-n { margin-bottom: 14px; }
  .dienst-tekst { margin-bottom: 18px; }
}
@media (max-width: 1100px) {
  .wiel-podium { grid-template-columns: 24vw minmax(0, 1fr) minmax(0, 38vw); }
  /* the strip holds down to 760: it is capped at the heading's measure, so the cells narrow with it */
}
/* under 1100 the right column is gone: the figure stands under the strip, in the page's own gutters */
@media (max-width: 1100px) {
  .strook-rand { --meet: 100%; }
  .wij-foto { position: static; width: auto; max-width: 440px; margin: 0 var(--rand) clamp(48px, 8vh, 90px); }
}
@media (max-width: 760px) {
  /* the phone: the measure is the screen and the band is swiped, not dragged or drifted, so the next cell only peeks */
  .strook-rand { --cel: 68%; }
  .strook-baan { max-width: none; }
  .strook-n { font-size: 38px; }
  /* the pill stays compact, but each half keeps the phone tier's 44 px target (D-121) */
  .strook-p { width: 46px; height: 44px; }
  .strook-p svg { width: 17px; height: 17px; }
  .wij-slot { min-height: 0; }
  /* the phone tier (slice D): the readout is wider than a 390 px card, so it spans the card and wraps instead of running off its edge */
  .scene-tag { right: 16px; flex-wrap: wrap; gap: 4px 6px; padding: 7px 10px; font-size: 9.5px; }
}
@media (prefers-reduced-motion: reduce) {
  .s-dot, .ad-cirkel, .br-held, .br-rij { animation: none !important; }
}

/* ---------- src/sections/05-werk.css ---------- */

/* ============ 5 · client frames, sideways (rebuilt 18-09 on v1's shape: the title travels on the track, five flat frames on white mounts,
   the quote at the end of the track; no turn, no skew, a wider film parallax) ============ */
.werk { position: relative; }
/* the hold's height stands here, not in the script (slice D, CLS). 3,4 screens, because the track now carries the title and the quote too:
   at 1440 × 900 that is about one pixel of travel per pixel of scroll, which is what v1's pinned track did */
.werk-houd { --houd: 3.4; }
.werk-houd > .houd-podium { min-height: 620px; }
/* the track: positioned by 05-werk.js, from its own left edge to the end of its width, so the title stands on the left when the hold
   starts and you scroll sideways into the quote at the end */
.werk-baan { position: relative; display: flex; align-items: center; gap: clamp(48px, 6vw, 120px); width: max-content; height: 100%; padding: 0 var(--rand); will-change: transform; }
/* the title, as the first thing on the track (v1's .spoor-intro) */
.spoor-intro { flex: none; width: min(64vw, 1000px); }
.spoor-intro .sub { max-width: 24em; }
.spoor-hint { margin: 44px 0 0; display: flex; align-items: center; gap: 14px; font-size: 12px; letter-spacing: .08em; text-transform: uppercase; color: var(--fg2); }
.spoor-hint .pijl { --kb: var(--inkt); --kf: #fff; width: 46px; height: 46px; }
html.beweeg .spoor-hint .pijl::before { animation: werk-duw 1.8s var(--inuit) infinite; }
@keyframes werk-duw { 0%, 100% { transform: none; } 50% { transform: translateX(26%); } }
.kaders { list-style: none; margin: 0; padding: 0; display: flex; align-items: center; gap: clamp(48px, 6vw, 120px); height: 100%; }
.kader { position: relative; flex: none; }
.kader a { display: block; text-decoration: none; color: inherit; }
/* the mount, the same treatment as the team photo in "Wat wij doen" (Orionix, D-131): 5 px of white, radius 24 outside and 20 inside,
   a hairline ring and the four-layer shadow, so the picture reads as a print laid on the day ground, not as a hole cut in it */
.kader-beeld { display: block; padding: 5px; border-radius: 24px; background: #fff; box-shadow: 0 0 0 1px rgba(0, 0, 0, .05), 0 1px 2px rgba(0, 0, 0, .08), 0 4px 6px rgba(0, 0, 0, .04), 0 44px 48px -26px rgba(30, 40, 50, .26); }
.kader-raam { --kh: 48vh; position: relative; display: block; height: var(--kh); overflow: hidden; border-radius: 20px; background: #c4ced4; isolation: isolate; }
/* the zoom (kit 5) is a CSS transform on its own layer; the parallax (05-werk.js) moves the film inside it, so the two never fight */
.kader-zoom { position: absolute; inset: 0; transition: transform .7s var(--e-uit); }
/* the film is wider than its window on both sides, and the overhang must stay larger than the travel in 05-werk.js, or the window's own
   background shows at one edge as the frame slides — which is the pale bar Alex saw coming in from the right (18-09). At -26 % the film is
   152 % of the window, the script's ±14,5 % of that is ±22 % of the window, so about 4 % of the window is spare at full travel. */
/* `will-change: transform` here is not a micro-optimisation (Alex, 18 and 19-09: "an overlay coming from the right on hover... i think it
   even happens on scroll"). The film's transform changes on every scroll frame, and without a layer of its own that change invalidates the
   paint of the track it sits in, so Chrome re-rasters the frame's tiles sixty times a second and a tile that misses its turn shows as a
   pale slab — a 256 px band sliding in from the side the film is moving towards. With the film composited, moving it only moves a layer:
   nothing is painted again. It also makes the hover zoom free, because `.kader-zoom` is then a layer with no painted content of its own. */
.kader-film { position: absolute; inset: 0 -26%; will-change: transform; }
.kader-film img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* the gate (kit 6) is gone (Alex, 20-09). It held every photo at saturate(.5) brightness(.82) until the frame reached the centre, then
   advanced an unfiltered copy over it in five clip-path steps with one inverted frame. On the way in the work looked washed out, and the
   switch to colour read as a glitch rather than as film passing a gate. The photos are now simply themselves, at full colour, always. */
/* the shade under the title: always there, deeper and taller on hover while the still zooms 5 % over 700 ms (kit 5, DW werf.css:561-571) */
.kader-raam::after { content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none; background: linear-gradient(180deg, rgba(11, 11, 11, 0) 0%, rgba(11, 11, 11, .5) 45%, rgba(11, 11, 11, .86) 100%) 0 100% / 100% 64% no-repeat; transition: background-size .7s var(--e-uit); }
.kader a:hover .kader-zoom, .kader a:focus-visible .kader-zoom { transform: scale(1.05); }
.kader a:hover .kader-raam::after, .kader a:focus-visible .kader-raam::after { background-size: 100% 96%; }
/* the big trade word over the picture is gone (Alex, 18-09): the trade already stands under the client's name, on the line below */
.kader-titel { position: absolute; z-index: 2; left: 18px; right: 18px; bottom: 16px; display: flex; flex-direction: column; gap: 3px; padding-right: 120px; color: #fff; }
.kader-titel b { font-size: clamp(18px, 1.5vw, 24px); font-weight: 640; line-height: 1.15; letter-spacing: -.015em; }
.kader-titel span { font-size: 13px; color: rgba(255, 255, 255, .82); }
/* "Bekijk" stays visible, so the frames read as links on touch too; hover and keyboard focus turn it red */
.kader-bekijk { position: absolute; right: 14px; bottom: 14px; z-index: 3; display: inline-flex; align-items: center; gap: 10px; height: 40px; padding: 0 5px 0 15px; border-radius: 99px; background: #fff; color: var(--inkt); font-size: 11px; font-weight: 500; line-height: 1; letter-spacing: .08em; text-transform: uppercase; box-shadow: 0 10px 30px -12px rgba(0, 0, 0, .45); transition: background-color .4s, color .4s; }
.kader-bekijk .pijl { --kb: #fff; --kf: var(--inkt); width: 30px; height: 30px; }
.kader-bekijk .pijl::before, .kader-bekijk .pijl::after { -webkit-mask-size: 14px; mask-size: 14px; }
.kader a:hover .kader-bekijk, .kader a:focus-visible .kader-bekijk { background: var(--rood); color: #fff; }
.kader a:hover .kader-bekijk .pijl, .kader a:focus-visible .kader-bekijk .pijl { --kb: var(--rood); --kf: #fff; }
.kader a:hover .kader-bekijk .pijl::before, .kader a:focus-visible .kader-bekijk .pijl::before { transform: translateX(110%); }
.kader a:hover .kader-bekijk .pijl::after, .kader a:focus-visible .kader-bekijk .pijl::after { transform: none; }
/* one result line under each frame, as wide as the frame */
.kader-onder { margin-top: 16px; display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 12px; width: 0; min-width: 100%; font-size: clamp(15px, 1.15vw, 18px); line-height: 1.4; color: var(--fg); }
.kader-n { font-size: 11px; color: var(--fg2); }
.kader-uitkomst { flex: 1 1 14em; font-weight: 560; }
.kader-onder .ptag { flex-basis: 100%; margin: 0; }
.k1 .kader-raam { --kh: 46vh; aspect-ratio: 16 / 10; } .k1 { align-self: flex-start; margin-top: 12vh; }
.k2 .kader-raam { --kh: 60vh; aspect-ratio: 9 / 14; }
.k3 .kader-raam { --kh: 44vh; aspect-ratio: 1; } .k3 { align-self: flex-end; margin-bottom: 8vh; }
.k4 .kader-raam { --kh: 52vh; aspect-ratio: 4 / 3; } .k4 { align-self: flex-start; margin-top: 9vh; }
.k5 .kader-raam { --kh: 56vh; aspect-ratio: 9 / 14; } .k5 { align-self: flex-end; margin-bottom: 6vh; }
.werk-balk { position: absolute; left: var(--rand); right: var(--rand); bottom: 32px; display: flex; align-items: center; gap: 20px; }
.werk-tel { font-size: 12px; }
.werk-balk > i { position: relative; flex: 1; height: 2px; background: var(--lijn); }
.werk-balk > i i { position: absolute; inset: 0; background: var(--fg); transform-origin: left; transform: scaleX(0); }
/* the quote, at the end of the track (v1's .spoor-slot): you scroll sideways into it after the last frame; its parts rise on entry
   through core (.spoor-slot > *) */
.spoor-slot { flex: none; width: min(56vw, 860px); padding-right: 6vw; }
.slot-quote { margin: 0 0 14px; max-width: 16em; font-size: clamp(30px, 3.6vw, 56px); font-weight: 630; line-height: 1.08; letter-spacing: -.02em; text-wrap: balance; }
.werk-uit-tag { margin: 0; }
.spoor-slot .paar { margin-top: 26px; }

/* the phone tier, the quiet tier and no JavaScript (spec §7 fix 4): a native scroll-snap carousel swiped by thumb, level frames, no hold.
   The title is its first slide and the quote its last, as in v1. The no-JS guard on the stage lives in src/core/basis.css since the wave C close */
html:not(.beweeg) .werk-houd > .houd-podium, [data-tier=lite] .werk-houd > .houd-podium { min-height: 0; overflow: visible; }
html:not(.beweeg) .werk-houd, [data-tier=lite] .werk-houd { padding: 0 0 24px; }
html:not(.beweeg) .werk-baan, [data-tier=lite] .werk-baan { width: auto; height: auto; align-items: flex-start; gap: clamp(20px, 4vw, 48px); overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory; scroll-padding-inline: var(--rand); scrollbar-width: none; will-change: auto; transform: none !important; -webkit-overflow-scrolling: touch; }
html:not(.beweeg) .werk-baan::-webkit-scrollbar, [data-tier=lite] .werk-baan::-webkit-scrollbar { display: none; }
html:not(.beweeg) .spoor-intro, [data-tier=lite] .spoor-intro,
html:not(.beweeg) .spoor-slot, [data-tier=lite] .spoor-slot { align-self: center; width: 84vw; padding: clamp(24px, 4vh, 48px) 0; scroll-snap-align: center; }
html:not(.beweeg) .spoor-hint, [data-tier=lite] .spoor-hint { display: none; }
html:not(.beweeg) .kaders, [data-tier=lite] .kaders { align-items: flex-start; gap: clamp(20px, 4vw, 48px); height: auto; padding: 12px 0 8px; }
html:not(.beweeg) .kader, [data-tier=lite] .kader { scroll-snap-align: center; align-self: auto; margin: 0; }
/* one height for all five, so the frames are level and every result line sits on the same rule: the desktop's staggered crops leave half a
   screen of dead space beside a short card on a phone, and its tall one runs past the screen (spec §7 "level frames", slice D) */
html:not(.beweeg) .kader-raam, [data-tier=lite] .kader-raam { --kh: auto; width: min(78vw, 440px); height: 52svh; aspect-ratio: auto; }
/* nothing moves inside a frame on the carousel, so the film needs no layer of its own there */
html:not(.beweeg) .kader-film, [data-tier=lite] .kader-film { inset: 0; transform: none !important; will-change: auto; }
html:not(.beweeg) .werk-balk, [data-tier=lite] .werk-balk { display: none; }
@media (max-width: 760px) {
  /* the phone: the title as the first slide filled the screen and left the frames off its right edge, so it looked like an empty section
     (Alex, 21-09). The title and the quote stand in the page, and only the five frames are the swiped row, the next one peeking */
  html:not(.beweeg) .werk-baan, [data-tier=lite] .werk-baan { display: block; overflow: visible; padding: 0; scroll-snap-type: none; }
  html:not(.beweeg) .spoor-intro, [data-tier=lite] .spoor-intro,
  html:not(.beweeg) .spoor-slot, [data-tier=lite] .spoor-slot { width: auto; padding: 0 var(--rand); }
  html:not(.beweeg) .spoor-intro, [data-tier=lite] .spoor-intro { padding-top: 96px; padding-bottom: 28px; }
  html:not(.beweeg) .spoor-slot, [data-tier=lite] .spoor-slot { padding-top: 40px; padding-bottom: 56px; }
  html:not(.beweeg) .kaders, [data-tier=lite] .kaders { gap: 14px; padding: 12px var(--rand) 8px; overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory; scroll-padding-inline: var(--rand); scrollbar-width: none; }
  html:not(.beweeg) .kaders::-webkit-scrollbar, [data-tier=lite] .kaders::-webkit-scrollbar { display: none; }
  html:not(.beweeg) .kader, [data-tier=lite] .kader { scroll-snap-align: start; }
  html:not(.beweeg) .kader-raam, [data-tier=lite] .kader-raam { width: 80vw; height: min(52svh, 105vw); }
  .kader-titel { left: 14px; right: 14px; bottom: 12px; padding-right: 100px; }
  .kader-titel b { font-size: 17px; }
  .kader-onder { font-size: 15px; }
  .slot-quote { font-size: 30px; }
}
@media (prefers-reduced-motion: reduce) {
  .spoor-hint .pijl::before { animation: none !important; }
}

/* the rhythm (Alex, 22-09): on the phone every section edge is --sec-y (tokens.css), so the space between two sections is the same on every page */
@media (max-width: 760px) {
  html:not(.beweeg) .spoor-intro, [data-tier=lite] .spoor-intro { padding-top: var(--sec-y); }
}

/* ---------- src/sections/08-twaalf.css ---------- */

/* ============ 5 · Twaalf weken: intro, a 2,0-screen sticky hold, outro (slice C2) ============ */
.twaalf { position: relative; }
.twaalf-kop { padding-top: var(--sec-y); padding-bottom: var(--kop-y); }
.twaalf-kop .kop2 { max-width: 16em; }
.twaalf-kop .sub { margin-top: 18px; }

/* the hold's height stands here, not in the script (slice D, CLS); on lite it is one bar, so nothing is held */
.twaalf-houd { --houd: 2; }
.twaalf-houd > .houd-podium { min-height: 600px; }
/* minmax(0, 1fr): the grid never widens past the window, whatever the track measures */
.tl-podium { height: 100%; display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: 1fr auto; align-items: center; gap: clamp(20px, 4vh, 48px); padding: clamp(30px, 6vh, 70px) var(--rand) clamp(34px, 6vh, 64px); }

/* ---------- the track stands still and the playhead moves, so all twelve weeks and both rows keep their labels (spec §2, timeline 1) ---------- */
.tijdlijn { position: relative; align-self: center; height: 300px; padding-left: 62px; }
/* no clipping: the track is exactly as wide as the window, and the playhead's label may hang into the page margin */
.tl-venster { position: relative; height: 100%; }
.tl-spoor { position: relative; width: 100%; padding-top: 36px; }
.tl-lineaal { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); height: 30px; font-size: 11px; color: var(--fg2); }
.tl-lineaal span { padding: 3px 0 0 8px; border-left: 1px solid var(--lijn); transition: color .3s, border-color .3s; }
.tl-lineaal span.is-nu { color: #fff; border-left-color: var(--rood); }
.tl-baan { position: relative; display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); grid-auto-rows: 54px; row-gap: 8px; margin-top: 14px; }
.tl-u { margin-top: 24px; padding-top: 18px; border-top: 1px dashed var(--lijn); }

/* one block, two stacked labels: the filled one is the fill, clipped by --vul, and both sit at 4,5:1 — no mix-blend-mode (spec §2) */
.tl-blok { position: relative; grid-column: var(--a) / calc(var(--b) + 1); grid-row: var(--r); margin-right: 8px; display: flex; align-items: center; padding: 0 14px; overflow: hidden; border: 1px solid rgba(255, 255, 255, .2); border-radius: 12px; background: rgba(255, 255, 255, .05); color: #fff; font-size: 15px; font-weight: 560; letter-spacing: -.01em; }
.tl-t { position: relative; z-index: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tl-vulblok { position: absolute; inset: 0; z-index: 2; display: flex; align-items: center; padding: 0 14px; background: #fff; color: var(--inkt); clip-path: inset(0 calc(100% - var(--vul, 0) * 100%) 0 0); }
.tl-uw .tl-vulblok, .tl-online .tl-vulblok { background: var(--rood-knop); color: #fff; }
/* "Niets" reads: plain text at full contrast, not 50 % grey italic (spec §2, timeline 3) */
.tl-niets { border-style: dashed; }
.tl-niets .tl-vulblok { background: rgba(255, 255, 255, .13); color: #fff; }
.tl-online.is-aan { box-shadow: 0 0 24px rgba(237, 29, 36, .3); }

.tl-kop { position: absolute; z-index: 3; left: 0; top: 4px; bottom: 4px; width: 2px; margin-left: -1px; background: var(--rood); box-shadow: 0 0 14px 1px rgba(237, 29, 36, .35); }
.tl-kop b { position: absolute; top: 0; left: 50%; transform: translate(-50%, 0); padding: 5px 9px; border-radius: 99px; background: var(--rood); color: #fff; font-size: 10px; font-weight: 500; letter-spacing: .08em; text-transform: uppercase; white-space: nowrap; }
/* the lane names sit in the 62 px gutter and centre on their own lane, whatever its height (Alex, 18-09): they used to be parked on two
   hardcoded offsets against the track, so neither lined up with the rows it named. Bigger and at full white, because they are read */
.tl-naam { position: absolute; z-index: 4; left: -62px; top: 50%; transform: translateY(-50%); width: 52px; margin: 0; font-size: 15px; letter-spacing: .08em; text-transform: uppercase; color: #fff; }


.twaalf-onder { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 16px clamp(24px, 4vw, 64px); align-items: end; }
.week-groot { margin: 0; display: flex; flex-direction: column; line-height: .86; }
.week-groot span { margin-bottom: 10px; font-size: 12px; letter-spacing: .08em; text-transform: uppercase; color: var(--fg2); }
.wk-nr { display: block; font-size: clamp(72px, 7.2vw, 120px); font-weight: 640; letter-spacing: -.035em; }
.stappen { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 16px; }
.stap { padding-top: 12px; border-top: 2px solid var(--lijn); color: var(--fg2); transition: color .5s, border-color .5s; }
.stap.is-nu { color: #fff; border-top-color: var(--rood); }
.stap span { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--fg2); }
.stap.is-nu span { color: var(--rood); }
.stap p { margin: 6px 0 0; font-size: 15px; line-height: 1.35; }

/* the phone's form (D-099, Q1 A): one twelve-week bar that fills once on view */
.tl-simpel { display: none; }
.tl-simpel-kop { margin: 0 0 10px; display: flex; justify-content: space-between; font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--fg2); }
.tl-simpel-baan { position: relative; height: 16px; overflow: hidden; border: 1px solid var(--lijn); border-radius: 99px; }
.tl-simpel-baan i { position: absolute; inset: 0; background: linear-gradient(90deg, rgba(255, 255, 255, .5), var(--rood)); transform-origin: left; }
html.beweeg .tl-simpel:not(.is-in) .tl-simpel-baan i { transform: scaleX(0); }
html.beweeg .tl-simpel.is-in .tl-simpel-baan i { transition: transform 1.6s var(--e-uit); }

.twaalf-slot { display: flex; flex-direction: column; justify-content: center; align-items: flex-start; gap: 26px; padding-top: var(--kop-y); padding-bottom: var(--sec-y); }
.twaalf-slot-zin { margin: 0; max-width: 28em; font-size: clamp(19px, 1.7vw, 26px); font-weight: 500; line-height: 1.4; letter-spacing: -.01em; }

/* ---------- without JavaScript, on the quiet tier and with ?rust=1: no hold, the timeline fully drawn (spec §3). The three lines below
     are 01-held.css's, until the wave close moves them into src/core/basis.css ---------- */
/* with no playhead running, every step reads at full contrast and only week 12 keeps the red rule */
html:not(.beweeg) .stap, .twaalf.tl-licht .stap { color: #fff; }
html:not(.beweeg) .tl-podium { height: auto; }

/* ---------- the phone: no hold, no track, the bar instead ---------- */
.twaalf.tl-licht .tijdlijn, .twaalf.tl-licht .week-groot { display: none; }
.twaalf.tl-licht .tl-simpel { display: block; }
.twaalf.tl-licht .tl-podium { height: auto; grid-template-rows: auto auto auto; gap: 28px; padding: 10px var(--rand) 40px; }
.twaalf.tl-licht .twaalf-onder { grid-template-columns: minmax(0, 1fr); }
.twaalf.tl-licht .stappen { grid-template-columns: minmax(0, 1fr); gap: 14px; }

@media (min-width: 761px) and (max-height: 820px) {
  .tijdlijn { height: 254px; }
  .tl-baan { grid-auto-rows: 44px; row-gap: 6px; margin-top: 10px; }
  .tl-u { margin-top: 16px; padding-top: 12px; }
  .tl-naam { font-size: 13px; }
  .wk-nr { font-size: clamp(56px, 6vw, 88px); }
  .stappen { gap: 12px; }
  .stap p { font-size: 14px; }
}
@media (max-width: 1100px) {
  .tl-blok { font-size: 14px; padding: 0 10px; }
  .tl-vulblok { padding: 0 10px; }
}
/* a narrow desktop window keeps the track, so a one-week block is 50 to 70 px wide: the names column and the padding give way so "Bezoek"
   and "Online" fit whole instead of ending in an ellipsis (responsive pass, 21-09) */
@media (min-width: 761px) and (max-width: 1100px) {
  .tijdlijn { padding-left: 40px; }
  .tl-naam { left: -40px; width: 36px; font-size: 12px; }
  .tl-blok { margin-right: 4px; padding: 0 6px; font-size: 12.5px; }
  .tl-vulblok { padding: 0 6px; }
  .tl-t { text-overflow: clip; }
}
@media (min-width: 761px) and (max-width: 1100px) {
  .tl-blok { padding: 0 4px; font-size: 11.5px; letter-spacing: -.02em; }
  .tl-vulblok { padding: 0 4px; }
}
@media (max-width: 760px) {
  .tijdlijn { padding-left: 0; }
  .tl-naam { display: none; }
  .twaalf-onder { grid-template-columns: minmax(0, 1fr); }
  .stappen { grid-template-columns: minmax(0, 1fr); }
  .wk-nr { font-size: 22vw; }
}

/* ---------- src/sections/06-formules.css ---------- */

/* ============ 6 · formulas ============ */
.formules { position: relative; padding: var(--sec-y) 0; }
.form-kop { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); gap: 40px; align-items: end; }
.form-kop .sub { margin: 0; }
.jaren { position: relative; display: inline-flex; margin: clamp(48px, 8vh, 80px) 0 36px; padding: 5px; border-radius: 99px; background: rgba(20, 20, 20, .07); font-size: 13px; }
.jaren button { position: relative; z-index: 1; padding: 13px 22px; border: 0; border-radius: 99px; background: transparent; cursor: pointer; letter-spacing: .02em; transition: color .5s; }
.jaren button[aria-checked=true] { color: #fff; }
.jaren-glijder { position: absolute; left: 0; top: 5px; bottom: 5px; width: 0; border-radius: 99px; background: var(--inkt); transition: transform .8s var(--uit), width .8s var(--uit); }
.plannen { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
.plan { --fg2: #5a554f; --lijn: rgba(20, 20, 20, .14); position: relative; display: flex; flex-direction: column; min-height: 600px; padding: clamp(24px, 2.4vw, 40px); border-radius: var(--r-plaat); background: #fff; color: var(--inkt); transition: transform .7s var(--uit), box-shadow .7s var(--uit); }
.plan:hover { transform: translateY(-10px); box-shadow: 0 40px 80px -40px rgba(60, 40, 20, .35); }
.plan-hi { --fg2: rgba(255, 255, 255, .78); --lijn: rgba(255, 255, 255, .22); background: var(--grafiet); color: #fff; }
.plan-hi .plan-soort { align-self: flex-start; padding: 6px 10px; border-radius: 99px; background: var(--rood-knop); color: #fff; }
.plan-soort { margin: 0 0 8px; font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--fg2); }
.plan h3 { margin: 0 0 24px; font-size: clamp(28px, 2.4vw, 40px); font-weight: 640; line-height: 1.05; letter-spacing: -.02em; }
.prijs { margin: 0 0 22px; display: flex; align-items: flex-start; gap: 6px; line-height: 1; }
.eur { margin-top: .15em; font-size: clamp(28px, 2.6vw, 44px); font-weight: 500; }
.odo { display: inline-flex; height: 1em; overflow: hidden; font-size: clamp(60px, 6vw, 100px); font-weight: 640; line-height: 1; letter-spacing: -.03em; }
/* Schibsted Grotesk has no tabular figures, so a column is as wide as its widest digit: centre the digit in it instead (wave C close) */
.odo-kol { display: inline-block; height: 1em; overflow: hidden; text-align: center; transition: width .8s var(--uit); }
.odo-band { display: block; transition: transform 1.1s var(--uit); }
.odo-band span { display: block; height: 1em; }
.pm { align-self: flex-end; margin: 0 0 .9em 4px; font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--fg2); }
/* the three year rows are the tabs as well (Alex, 18-09): on a phone the strip above the cards is off screen while he compares them */
.plan-jaren { margin: 0 0 26px; display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; font-size: 11px; }
/* a row that is not the chosen year is dimmed with colour, not with opacity, so the red on "Vanaf jaar 3" keeps its contrast */
.plan-jaren button { display: block; width: 100%; padding: 9px 0 0; border: 0; border-top: 1.5px solid var(--lijn); border-radius: 0; background: none; color: var(--fg2); font: inherit; text-align: left; cursor: pointer; transition: color .5s, border-color .5s; }
.plan-jaren button:is(:hover, [aria-pressed=true]) { color: inherit; }
.plan-jaren button[aria-pressed=true] { border-top-color: currentColor; }
.pj-j { display: block; letter-spacing: .04em; text-transform: uppercase; }
.pj-p { display: block; margin-top: 4px; font-size: 14px; }
/* "Vanaf jaar 3" is the number the section argues for, so it carries the red — the text token on white (5,7:1), the brand red on graphite (4,65:1) */
.plan-jaren button[data-j="2"] .pj-p { color: var(--rood-tekst); }
.plan-hi .plan-jaren button[data-j="2"] .pj-p { color: var(--rood); }
/* and when jaar 3 is the year on show, the big price takes that red as well (Alex, 18-09): the € and the odometer, not "per maand" */
.prijs { transition: color .6s var(--uit); }
.formules.is-jaar3 .plan .prijs { color: var(--rood-tekst); }
.formules.is-jaar3 .plan-hi .prijs { color: var(--rood); }
.plan-inhoud { list-style: none; margin: 0 0 30px; padding: 0; display: flex; flex-direction: column; gap: 10px; font-size: 17px; line-height: 1.4; }
.plan-inhoud li { display: flex; gap: 12px; align-items: baseline; }
.plan-inhoud li::before { content: ''; flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--rood); transform: translateY(-2px); }
.plan-hi .plan-inhoud li::before { background: var(--rood); }
.plan .link { margin-top: auto; align-self: flex-start; }
.regels { margin: 56px 0 0; padding: 40px 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px; border-top: 1px solid var(--lijn); border-bottom: 1px solid var(--lijn); }
.regels dt { font-size: clamp(20px, 1.7vw, 28px); font-weight: 620; letter-spacing: -.02em; }
.regels dd { margin: 6px 0 0; color: var(--fg2); }
.nul { margin: 48px 0 12px; max-width: 30em; font-size: clamp(20px, 1.8vw, 30px); line-height: 1.3; letter-spacing: -.015em; }
.nul b { font-size: 1.7em; font-weight: 680; letter-spacing: -.028em; color: var(--rood); }
.voetnoot { margin: 0; font-size: 12px; color: var(--fg2); }
/* kit 4: a red rim light follows the pointer along the card's border on rich; on the other tiers it sweeps once around each card on entry, then rests */
@property --rim { syntax: '<angle>'; inherits: false; initial-value: 0deg; }
.plan::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 2px; pointer-events: none; opacity: 0; transition: opacity .3s;
  background: radial-gradient(320px circle at var(--mx, 50%) var(--my, 50%), var(--rood) 0, rgba(237, 29, 36, .5) 40%, transparent 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
}
[data-tier=rich] .plan:hover::after { opacity: 1; }
.plan.is-veeg::after { background: conic-gradient(from var(--rim), transparent 0 72%, rgba(237, 29, 36, .25) 86%, var(--rood) 100%); animation: rimveeg 1.5s var(--e-scene) both; }
@keyframes rimveeg { 0% { --rim: 0deg; opacity: 0; } 15% { opacity: 1; } 85% { opacity: 1; } 100% { --rim: 360deg; opacity: 0; } }
/* the section's end: the question and the gesprek (spec §1, row 6) */
/* the question at the left, the button and the link together at the right (Alex, 22-09: space-between had put the button in the middle) */
.form-slot { margin-top: clamp(64px, 10vh, 120px); display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-start; gap: 24px 28px; }
.form-slot-zin { margin: 0 auto 0 0; padding-right: 12px; font-size: clamp(28px, 2.8vw, 48px); font-weight: 620; line-height: 1.1; letter-spacing: -.02em; }
/* the quiet tier: the prices and the year control jump to their value */
[data-tier=stil] :is(.odo-band, .odo-kol, .jaren-glijder, .plan-jaren button, .prijs) { transition: none; }
@media (max-width: 1100px) {
  .plan { min-height: 0; }
  .plan-jaren { grid-template-columns: 1fr 1fr 1.45fr; }
  .pj-j { white-space: nowrap; }
}
/* a narrow desktop window: three cards of 220 px broke every line, so they stack, as on the phone */
@media (min-width: 761px) and (max-width: 1100px) {
  .plannen { grid-template-columns: 1fr; max-width: 620px; }
}
@media (max-width: 760px) {
  .form-kop { grid-template-columns: 1fr; gap: 20px; }
  .jaren { font-size: 11.5px; }
  .jaren button { min-height: 44px; padding: 11px 14px; }
  .plannen { grid-template-columns: 1fr; }
  .plan-jaren button { min-height: 44px; padding-bottom: 6px; }
  .odo { font-size: 19vw; }
  .regels { grid-template-columns: 1fr; }
}

/* ---------- src/sections/07-reken.css ---------- */

/* ============ 7 · reken mee (slice C3, spec §5; rebuilt on Alex's notes, 20-09) ============ */
.reken { position: relative; padding: var(--sec-y) 0; }
.reken .kop2 { max-width: 16em; }
.reken-grid { display: grid; grid-template-columns: minmax(0, .78fr) minmax(0, 1.22fr); gap: clamp(40px, 5vw, 96px); align-items: start; margin-top: clamp(48px, 8vh, 90px); }
/* the result column sticks under the header, so the ratio at its top stays beside the sliders for the whole section (Alex, 20-09) */
.reken-uit { position: sticky; top: clamp(92px, 12vh, 140px); }

/* 1 · the sentence is put away (Alex, 20-09): a quiet line under the ratio instead of the section's biggest type. The numbers in it
   still move with the sliders */
.reken-zin { margin: 0 0 clamp(28px, 4vh, 44px); max-width: 26em; font-size: clamp(17px, 1.25vw, 21px); font-weight: 500; line-height: 1.5; color: var(--fg2); }
.reken-zin b { color: #fff; font-weight: 640; white-space: nowrap; }

/* 6 · "Zo rekenen we": the drawer under the sentence, in the engine's words */
.zo { margin: 0 0 36px; border-top: 1px solid var(--lijn); border-bottom: 1px solid var(--lijn); }
.zo summary { display: flex; justify-content: space-between; align-items: center; gap: 24px; padding: 20px 0; cursor: pointer; list-style: none; font-size: 18px; font-weight: 600; letter-spacing: -.01em; }
.zo summary::-webkit-details-marker { display: none; }
.zo-plus { position: relative; flex: none; width: 40px; height: 40px; border-radius: 50%; box-shadow: inset 0 0 0 1px var(--lijn); transition: background-color .5s, color .5s, transform .7s var(--e-uit), box-shadow .5s; }
.zo-plus::before, .zo-plus::after { content: ''; position: absolute; left: 50%; top: 50%; width: 14px; height: 1.5px; margin: -.75px 0 0 -7px; background: currentColor; transition: transform .6s var(--e-uit); }
.zo-plus::after { transform: rotate(90deg); }
.zo summary:hover .zo-plus { box-shadow: inset 0 0 0 1px var(--fg); }
.zo[open] .zo-plus { background: var(--rood); color: #fff; box-shadow: none; transform: rotate(180deg); }
.zo[open] .zo-plus::after { transform: rotate(0deg); }
.zo-in { overflow: hidden; }
.zo-lijst { list-style: none; margin: 0; padding: 0 0 24px; display: grid; gap: 14px; max-width: 34em; font-size: 15px; line-height: 1.45; color: var(--fg2); }
.zo-lijst b { color: #fff; font-weight: 600; }

/* 7 · the column ends on one red button, with "Meer rekenmachines" beside it and the fine print under it */
.reken-acties { display: flex; flex-wrap: wrap; align-items: center; gap: 16px 28px; }
.reken-acties .knop b { font-weight: 700; }
.eerlijk { margin: clamp(28px, 4vh, 44px) 0 0; max-width: 40em; font-size: 14px; line-height: 1.45; color: var(--fg2); }

/* ---- the instrument: three slider rows, the two bars and the three levers share one set of columns, so every value stands in the
   same place (Alex, 20-09: heading left of the slider, value right of it, bars beside the sliders) ---- */
.reken-in { --kol: minmax(0, 200px) minmax(110px, 1fr) minmax(0, 176px); --sp: clamp(16px, 1.6vw, 30px); }

/* 3 and 4 · one row per slider. The thumb is an index into stops; the typed twin at the right takes exact values */
.schuif { display: grid; grid-template-columns: var(--kol); align-items: center; gap: 0 var(--sp); padding: 7px 0; }
.schuif-kop { font-size: 16px; line-height: 1.25; color: var(--fg2); cursor: pointer; }
.twin { justify-self: end; display: inline-flex; align-items: baseline; gap: .2em; max-width: 100%; font-size: clamp(20px, 1.6vw, 28px); font-weight: 640; letter-spacing: -.025em; transition: scale .3s var(--e-uit); transform-origin: 100% 60%; }
/* the euro sits against its digits (Alex, 20-09): the field is as wide as what it holds, not a fixed box with the number pushed right */
.twin .getal { width: 6.4em; max-width: 100%; padding: 2px 0; border: 0; border-bottom: 1.5px solid transparent; border-radius: 0; background: transparent; color: #fff; font: inherit; text-align: right; transition: border-color .3s; }
@supports (field-sizing: content) { .twin .getal { field-sizing: content; width: auto; min-width: 2ch; } }
.twin .getal:hover { border-bottom-color: rgba(255, 255, 255, .5); }
.twin .getal:focus { outline: none; border-bottom-color: #fff; }
.twin .getal::placeholder { color: var(--fg2); font-size: .72em; font-weight: 500; letter-spacing: 0; }
/* the euro belongs to an amount, so it steps aside for the one word that stands on the last stop ("meer", not "€ meer") */
.twin:has(.getal:placeholder-shown) .twin-eur { display: none; }
/* the value at the right of the row answers the drag too, beside the bubble that rides with the thumb */
.schuif:has(input[type=range]:active) .twin { scale: 1.07; }

.spoor { --v: .5; --zwaai: 0px; --lean: 0deg; --d: 28px; position: relative; height: 44px; }
.spoor::before { content: ''; position: absolute; left: 0; right: 0; top: 19px; height: 6px; border-radius: 99px; background: rgba(255, 255, 255, .26); }
.spoor-vul { position: absolute; left: 0; top: 19px; height: 6px; border-radius: 99px; background: #fff; width: calc(var(--d) / 2 + var(--v) * (100% - var(--d)) + var(--zwaai)); }
.duim { position: absolute; top: calc(50% - var(--d) / 2); left: calc(var(--d) / 2 + var(--v) * (100% - var(--d))); width: var(--d); height: var(--d); border-radius: 50%; background: #fff; box-shadow: 0 8px 24px rgba(0, 0, 0, .35); transform: translateX(calc(-50% + var(--zwaai))); transition: scale .35s var(--e-uit); }
.spoor:active .duim { scale: 1.2; }
.spoor:focus-within .duim { outline: 2px solid #fff; outline-offset: 4px; }
/* the bubble is back (Alex, 20-09), but only while the slider is being used: it rides over the thumb on the thumb's own formula, leans
   against the direction of travel while he drags and stands up again 140 ms after he stops. At rest the row keeps the compact height,
   so nothing above it moves; the permanent value at the right of the row stays where it is */
.bel { position: absolute; bottom: calc(100% + 2px); left: calc(var(--d) / 2 + var(--v) * (100% - var(--d))); z-index: 4; padding: 7px 10px 6px; border-radius: 8px; background: #fff; color: var(--inkt); font: 640 13px/1 var(--f); letter-spacing: -.01em; white-space: nowrap; box-shadow: 0 10px 26px rgba(0, 0, 0, .34); opacity: 0; scale: .82; transform: translateX(calc(-50% + var(--zwaai))) rotate(var(--lean)); transform-origin: 50% 150%; pointer-events: none; transition: opacity .2s, scale .32s var(--e-uit), transform .35s var(--e-uit); }
.bel::after { content: ''; position: absolute; left: 50%; top: 100%; margin-left: -5px; border: 5px solid transparent; border-top-color: #fff; }
.spoor:hover .bel, .spoor:focus-within .bel, .spoor:has(input[type=range]:active) .bel { opacity: 1; scale: 1; }
.spoor input[type=range] { position: absolute; inset: 0; width: 100%; height: 44px; margin: 0; opacity: 0; cursor: grab; -webkit-appearance: none; appearance: none; }
.spoor input[type=range]:active { cursor: grabbing; }
.spoor input[type=range]::-webkit-slider-thumb { width: 28px; height: 28px; -webkit-appearance: none; appearance: none; }
.spoor input[type=range]::-moz-range-thumb { width: 28px; height: 28px; border: 0; }

/* 2a · the two bars on the sliders' own columns, a thumb's reach under the tracks. The axis is four times Groei's year (07-reken.js),
   so the top bar grows and shrinks with every drag instead of standing full at every value */
.staven { margin: clamp(20px, 2.6vh, 34px) 0 0; padding-top: clamp(18px, 2.2vh, 28px); border-top: 1px solid var(--lijn); }
.staaf { margin: 0 0 14px; display: grid; grid-template-columns: var(--kol); align-items: center; gap: 0 var(--sp); }
.staaf > span { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--fg2); }
.staaf > b { justify-self: end; font-size: clamp(18px, 1.35vw, 23px); font-weight: 640; letter-spacing: -.025em; white-space: nowrap; }
.baan { position: relative; display: block; }
.staaf-baan { position: relative; display: block; height: 18px; overflow: hidden; border-radius: 99px; background: rgba(0, 0, 0, .32); }
/* each band spans the track and is moved and sized by transform, so a slider's drag animates on the compositor, not in layout */
.staaf-baan i { position: absolute; inset: 0; transform-origin: 0 50%; transform: translateX(calc(var(--x, 0) * 100%)) scaleX(var(--w, 0)); transition: transform .7s var(--e-uit), opacity .25s; }
.staaf-baan [data-seg="0"] { background: #fff; } .staaf-baan [data-seg="1"] { background: rgba(255, 255, 255, .68); } .staaf-baan [data-seg="2"] { background: rgba(255, 255, 255, .42); } .staaf-baan [data-seg="g"] { background: #7C838C; }
/* Alex, 20-09: "the bar is white, grey and dark grey — what do they mean?" Each band names itself under the pointer, in the slider
   bubble's own white panel, over the band it belongs to. The others step back and the lever that band stands for lights up, so the
   colour and the line that explains it are read in one look */
.baan-tip { position: absolute; bottom: calc(100% + 9px); left: var(--tx, 50%); z-index: 5; display: grid; gap: 3px; padding: 9px 12px 8px; border-radius: 9px; background: #fff; color: var(--inkt); white-space: nowrap; box-shadow: 0 10px 28px rgba(0, 0, 0, .36); opacity: 0; scale: .84; transform: translateX(-50%); transform-origin: 50% 140%; pointer-events: none; transition: opacity .2s, scale .32s var(--e-uit), left .4s var(--e-uit); }
.baan-tip::after { content: ''; position: absolute; left: 50%; top: 100%; margin-left: -5px; border: 5px solid transparent; border-top-color: #fff; }
.baan-tip b { font-size: 13.5px; font-weight: 640; line-height: 1.2; letter-spacing: -.01em; }
.baan-tip span { font-size: 12px; font-weight: 500; line-height: 1; color: #6f6a62; }
.baan.is-aan .baan-tip { opacity: 1; scale: 1; }
.staaf-baan:has(i:hover) i:not(:hover) { opacity: .4; }
.reken[data-band] .hefbomen li { color: var(--fg2); }
.reken[data-band="0"] .hefbomen li:nth-child(1), .reken[data-band="1"] .hefbomen li:nth-child(2), .reken[data-band="2"] .hefbomen li:nth-child(3) { color: var(--fg); }
.reken[data-band="0"] .hefbomen li:nth-child(1) .hb-kleur, .reken[data-band="1"] .hefbomen li:nth-child(2) .hb-kleur, .reken[data-band="2"] .hefbomen li:nth-child(3) .hb-kleur { scale: 1.3; }
.hb-kleur { transition: scale .3s var(--e-uit); }
.hefbomen li { transition: color .25s; }

/* 2b · the three levers, colour-keyed to the bar's segments right above them */
.hefbomen { list-style: none; margin: clamp(18px, 2.4vh, 30px) 0 0; padding: 0; border-top: 1px solid var(--lijn); }
.hefbomen li { display: grid; grid-template-columns: 14px minmax(0, 1fr) auto; gap: 14px; align-items: center; padding: 15px 0; border-bottom: 1px solid var(--lijn); font-size: 17px; line-height: 1.4; }
.hb-kleur { width: 12px; height: 12px; border-radius: 3px; background: #fff; }
.hefbomen li:nth-child(2) .hb-kleur { background: rgba(255, 255, 255, .68); } .hefbomen li:nth-child(3) .hb-kleur { background: rgba(255, 255, 255, .42); }
.hefbomen b { font-size: 22px; font-weight: 640; letter-spacing: -.025em; white-space: nowrap; }

/* 2c · the ratio opens the sticky column, the section's largest number, with the verdict under it.
   data-stand on the section: ok · veel (above 10×) · meer (a slider on "meer") */
.ratio-blok { margin: 0 0 clamp(26px, 3.4vh, 42px); }
.ratio { margin: 0; display: flex; align-items: flex-start; font-size: clamp(96px, 11vw, 190px); font-weight: 650; line-height: .86; letter-spacing: -.035em; }
.ratio-getal number-flow { --number-flow-mask-height: .18em; }
.ratio-x { margin: .08em 0 0 .04em; font-size: .36em; font-weight: 300; letter-spacing: 0; color: var(--rood); white-space: nowrap; }
.reken[data-stand=veel] .ratio-x { align-self: flex-end; margin: 0 0 1.15em .1em; font-size: .2em; }
.oordeel { margin: 18px 0 0; font-size: clamp(22px, 1.9vw, 32px); font-weight: 620; letter-spacing: -.02em; }
.samen { display: none; margin: 16px 0 0; flex-wrap: wrap; align-items: baseline; gap: 12px 24px; font-size: clamp(19px, 1.5vw, 24px); }
.reken[data-stand=veel] .samen, .reken[data-stand=meer] .samen { display: flex; }
.reken[data-stand=meer] .samen { flex: 1 0 100%; }
.reken[data-stand=meer] .samen > span { flex: 1 0 100%; font-size: clamp(36px, 4vw, 64px); font-weight: 640; line-height: 1.02; letter-spacing: -.025em; }
.reken[data-stand=meer] :is(.ratio, .oordeel, .reken-zin, .staven) { display: none; }

/* 9 · without JavaScript the printed example is the result: the sliders and the bars they drive stay hidden */
.no-js :is(.schuif, .staven) { display: none; }
.no-js .hefbomen { margin-top: 0; border-top: 0; }

/* the quiet tier: the bars and the drawer's marker jump to their value */
[data-tier=stil] :is(.staaf-baan i, .zo-plus, .twin, .bel, .baan-tip, .hb-kleur, .hefbomen li) { transition: none; }
[data-tier=stil] .zo-plus::before, [data-tier=stil] .zo-plus::after { transition: none; }

/* one column under 1024 px: the ratio is a strip that stays under the header while the sliders and the bars pass beneath it, the
   instrument follows, and label and value share a line over their own track */
@media (max-width: 1100px) {
  .reken-grid { grid-template-columns: minmax(0, 1fr); gap: clamp(28px, 4.5vh, 44px); }
  .reken-uit { display: contents; }
  .reken-uit > * { order: 2; }
  .reken-in { order: 1; }
  /* 68 px of graphite over it is the fixed header's own height, so nothing scrolls through when both are on screen */
  .ratio-blok { order: 0; position: sticky; top: 0; z-index: 3; margin: 0 calc(-1 * var(--rand)) -8px; padding: 68px var(--rand) 10px; display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 18px; background: var(--grafiet); }
  .ratio { font-size: clamp(44px, 11.5vw, 60px); }
  .oordeel { margin: 0; font-size: clamp(16px, 4vw, 21px); }
  .samen { margin: 0; }
  .reken[data-stand=meer] .samen > span { flex-basis: auto; font-size: clamp(19px, 5vw, 26px); }
  /* the label and its value share the first line, the track takes the second: the three columns do not fit a phone */
  .schuif, .staaf { grid-template-columns: minmax(0, 1fr) auto; gap: 4px var(--sp); }
  .schuif-kop, .staaf > span { grid-area: 1 / 1; }
  .twin, .staaf > b { grid-area: 1 / 2; }
  .schuif .spoor, .staaf .baan { grid-area: 2 / 1 / 3 / -1; }
  .reken-acties .knop { height: auto; min-height: 56px; padding-block: 9px; white-space: normal; }
}
@media (max-width: 760px) {
  /* the phone tier (slice D): a number field is a thumb target, and the phone bar may not cover the last line under the sticky strip */
  .twin .getal { min-height: 44px; }
  .reken-acties { padding-bottom: 72px; }
}

@media (max-width: 760px) {
  /* the 72 px kept under the buttons for the phone bar: the section's own edge is taller than the bar */
  .reken-acties { padding-bottom: 0; }
}

/* ---------- src/sections/09-beloftes.css ---------- */

/* ============ 9 · promises ============ */
.beloftes { position: relative; padding: var(--sec-y) 0; }
.beloftes .kop2 { max-width: 14em; }
/* one grid over both columns (Alex, 18-09): the left items are one line and the right ones a bold line plus an explanation, so as two
   independent lists no row lined up and the columns ended at different heights. Two levels of subgrid — the column, then its list — put
   every pair of promises on one row, so the hairlines meet across the gutter and both columns end on the same rule */
.belof-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: auto repeat(6, auto); gap: 0 clamp(32px, 5vw, 96px); margin-top: clamp(56px, 9vh, 96px); }
.belof-uit { margin: clamp(48px, 7vh, 80px) 0 0; }
.belof-kol { display: grid; grid-row: span 7; grid-template-rows: subgrid; }
.belof-kol h3 { margin: 0 0 16px; font-size: 12px; font-weight: 500; letter-spacing: .08em; text-transform: uppercase; color: var(--fg2); }
.belof-kol ol { list-style: none; margin: 0; padding: 0; display: grid; grid-row: span 6; grid-template-rows: subgrid; }
.belof-kol li { display: grid; grid-template-columns: 36px minmax(0, 1fr); gap: 18px; align-items: start; padding: 22px 0; border-top: 1px solid var(--lijn); font-size: clamp(19px, 1.5vw, 24px); font-weight: 540; line-height: 1.32; letter-spacing: -.01em; }
.belof-nee li { font-size: 17px; font-weight: 400; line-height: 1.45; letter-spacing: 0; color: var(--fg2); }
.belof-nee li b { display: block; margin-bottom: 4px; font-size: clamp(19px, 1.5vw, 24px); font-weight: 540; line-height: 1.32; letter-spacing: -.01em; color: var(--fg); }
.vink { width: 34px; height: 34px; display: grid; place-items: center; border-radius: 50%; background: var(--rood); }
.vink svg { width: 17px; height: 17px; fill: none; stroke: #fff; stroke-width: 2.8; stroke-linecap: round; stroke-linejoin: round; }
.vink path { stroke-dasharray: 1; stroke-dashoffset: 0; }
.belof-nee .vink { background: transparent; box-shadow: inset 0 0 0 1.5px var(--fg); }
.belof-nee .vink svg { stroke: var(--fg); stroke-width: 2.2; width: 13px; height: 13px; }
@media (max-width: 760px) {
  .belof-grid { grid-template-columns: 1fr; grid-template-rows: none; gap: clamp(32px, 5vw, 96px); }
  .belof-kol, .belof-kol ol { display: block; grid-row: auto; }
}

/* ---------- src/sections/10-vragen.css ---------- */

/* ============ 10 · questions ============ */
.vragen { position: relative; padding: var(--sec-y) 0; }
.vragen-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr); gap: clamp(40px, 6vw, 120px); align-items: start; }
.vragen-kop { position: sticky; top: 120px; }
.lijst details { border-top: 1px solid var(--lijn); }
.lijst details:last-child { border-bottom: 1px solid var(--lijn); }
.lijst summary { display: flex; justify-content: space-between; align-items: center; gap: 24px; padding: 26px 0; cursor: pointer; list-style: none; font-size: clamp(19px, 1.5vw, 24px); font-weight: 580; line-height: 1.3; letter-spacing: -.012em; }
.lijst summary::-webkit-details-marker { display: none; }
.lijst summary > span { transition: transform var(--t-klein) var(--e-uit); }
/* kit 12: the question steps 6 px right under a pointer; on touch there is only the tap state */
@media (hover: hover) and (pointer: fine) {
  .lijst summary:hover > span { transform: translateX(6px); }
}
.lijst summary:active > span { transform: translateX(6px); }
.plus { position: relative; flex: none; width: 44px; height: 44px; border-radius: 50%; box-shadow: inset 0 0 0 1px var(--lijn); transition: background-color .5s, color .5s, transform .7s var(--uit), box-shadow .5s; }
.plus::before, .plus::after { content: ''; position: absolute; left: 50%; top: 50%; width: 14px; height: 1.5px; margin: -.75px 0 0 -7px; background: currentColor; transition: transform .6s var(--uit); }
.plus::after { transform: rotate(90deg); }
.lijst summary:hover .plus { box-shadow: inset 0 0 0 1px var(--fg); }
.lijst details[open] .plus { background: var(--rood); color: #fff; box-shadow: none; transform: rotate(180deg); }
.lijst details[open] .plus::after { transform: rotate(0deg); }
.antw { overflow: hidden; }
.antw p { margin: 0 0 16px; max-width: 36em; font-size: 18px; line-height: 1.5; color: var(--fg2); }
.antw p:last-child { margin-bottom: 0; padding-bottom: 28px; }
.antw a { color: var(--fg); text-underline-offset: 3px; }
/* the section's own pair (spec §1, row 9): bel ons, then the quiet gesprek */
.vragen-cta { margin-top: clamp(36px, 5vh, 56px); }
@media (max-width: 760px) {
  .vragen-grid { grid-template-columns: 1fr; }
  .vragen-kop { position: static; }
}

/* ---------- src/sections/11-slot.css ---------- */

/* ============ 10 · closer and form (slice C4, spec §6; rebuilt in pass 2 slice 3, §10) ============ */
#doorlichting { scroll-margin-top: clamp(72px, 10vh, 104px); }
.slot { position: relative; padding: var(--sec-y) 0; }
.slot-zin { margin: 0; max-width: 18em; font-size: clamp(32px, 4.2vw, 68px); font-weight: 640; line-height: 1.06; letter-spacing: -.02em; }
/* the closer arrives as two whole lines, one after the other (spec §9) */
.slot-zin span { display: block; }
.slot-zin span + span { margin-top: .18em; }
.slot-tbc { margin: 20px 0 clamp(100px, 16vh, 180px); }
.vel { --fg: var(--inkt); --fg2: #57534e; --lijn: rgba(20, 20, 20, .12); display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); gap: clamp(32px, 5vw, 96px); padding: var(--vel-p); border-radius: var(--r-plaat); background: #fff; color: var(--inkt); box-shadow: 0 60px 140px -50px rgba(0, 0, 0, .6); }
/* both columns end on the same rule (Alex, 18-09): the intro is a column with the contact block pushed to its foot */
.vel-intro { display: flex; flex-direction: column; align-items: flex-start; }
.vel-titel { margin: 0 0 20px; font-size: clamp(32px, 3.4vw, 54px); font-weight: 640; line-height: 1.05; letter-spacing: -.02em; }
.vel-titel em { color: var(--rood); }
.vel-stand { margin: 0 0 32px; font-size: clamp(17px, 1.3vw, 21px); line-height: 1.45; color: var(--fg2); }
/* no bottom margin: the contact block's own margin-top: auto sets the distance, and that is what levels the two columns */
.drie { list-style: none; margin: 0; padding: 0; width: 100%; }
.drie li { display: grid; grid-template-columns: 44px minmax(0, 1fr); padding: 11px 0; border-top: 1px solid var(--lijn); font-size: 17px; line-height: 1.45; color: var(--fg2); }
.drie li > b { padding-top: 3px; font-size: 12px; font-weight: 500; color: var(--rood-tekst); }
.drie span b { font-weight: 620; color: var(--inkt); }

/* ---------- the contact column (§10.5): a 20 px monoline icon before every line, the VAT number without a hover, then the four
     profiles as 44 px targets. Under the pointer the icon and its line take the red ---------- */
.contact { margin-top: auto; padding-top: 24px; border-top: 1px solid var(--lijn); display: grid; gap: 2px; width: 100%; font-style: normal; font-size: 15px; line-height: 1.5; color: var(--fg2); }
.contact a, .contact-rij { display: flex; align-items: center; gap: 10px; min-height: 32px; color: var(--inkt); text-decoration: none; transition: color var(--t-druk); }
.ci { flex: none; width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; color: var(--fg2); transition: color var(--t-druk); }
.contact a:hover, .contact a:hover .ci { color: var(--rood-tekst); }
/* the number is red already, so a colour change is no answer to the pointer (Alex, 20-09): the red rule of the fields draws itself under
   the digits, and the handset tips off the hook. Both on a real hover only, so a tap on a phone dials instead of animating */
.contact-tel { margin-bottom: 4px; font-size: clamp(26px, 2.2vw, 38px); font-weight: 660; letter-spacing: -.025em; color: var(--rood-tekst) !important; }
.contact-tel .ci { width: 26px; height: 26px; stroke-width: 1.5; color: inherit; transition: transform var(--t-klein) var(--e-pop); }
.contact-tel span { background: linear-gradient(var(--rood) 0 0) 0 100% / 0 2px no-repeat; padding-bottom: 3px; transition: background-size .5s var(--e-uit); }
@media (hover: hover) and (pointer: fine) {
  .contact-tel:hover span { background-size: 100% 2px; }
  .contact-tel:hover .ci { transform: rotate(-16deg) translateY(-1px); }
  /* the two addresses open Google Maps: the pin lifts, the line takes the red from .contact a:hover */
  .contact-kaart:hover .ci { transform: translateY(-2px); }
}
.contact-tel:focus-visible span { background-size: 100% 2px; }
.contact-kaart .ci { transition: transform var(--t-klein) var(--e-pop), color var(--t-druk); }
.contact-btw { margin-top: 10px; font-size: 13px; color: var(--fg2); }
/* scoped under .contact: the footer carries the same four icons on the night ground, with its own colours (12-voet.css) */
.contact .sociaal { list-style: none; display: flex; gap: 4px; margin: 6px 0 0 -12px; padding: 0; }
.contact .sociaal a { display: grid; place-items: center; width: 44px; height: 44px; min-height: 0; color: var(--inkt); }
.contact .sociaal svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.contact .sociaal a:hover { color: var(--rood-tekst); }

/* ---------- one page, eight fields (Alex, 18-09): the wizard, its counter, its chip groups and the check of the answers are gone ---------- */
.aanvraag { position: relative; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 22px 16px; align-content: start; counter-reset: veld; }
.calc-mee { grid-column: 1 / -1; margin: 0; padding: 13px 16px; border-radius: 14px; background: #f2efe9; font-size: 15px; line-height: 1.4; color: #4a463f; }
.calc-mee b { color: var(--inkt); }
/* wijzigen, and the way out for someone who only played with the sliders (Alex, 20-09): the line and the hidden values go with one click */
.calc-knoppen { display: inline-flex; flex-wrap: wrap; gap: 4px 16px; margin-left: 8px; }
.calc-wijzig { color: var(--rood-tekst); text-underline-offset: 3px; }
.calc-weg { padding: 0; border: 0; background: none; font: inherit; color: #6e6a64; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; transition: color var(--t-druk); }
.calc-weg:hover { color: var(--inkt); }

/* ---------- one field (spec §6, §10.2): the label notched into the top edge and numbered 01…08, the red line running around the whole
     box on focus, a red full stop when it is valid; the error under it, never in the label.
     The corner bracket and the straight rule under the box were de-werf v2's camera frame and never belonged here (Alex, 20-09): a
     16 px rounded box cannot carry a flat underline. The rule is the same line, and it now travels: at rest it is the 2 px stub at the
     bottom edge, on focus it opens into the box's own outline, corners and all. One interpolated clip-path, so it is one gesture. */
.veld { --h: 64px; --r: 16px; position: relative; margin-top: 9px; }
.aanvraag .veld { counter-increment: veld; }
.veld.breed { grid-column: 1 / -1; }
.veld :is(input, select) {
  width: 100%; height: var(--h); padding: 0 46px 0 18px; border: 1px solid #dedad4; border-radius: 16px; background-color: #f6f4f1; color: var(--inkt);
  font: 500 17px/1.2 var(--f); -webkit-appearance: none; appearance: none; transition: border-color var(--t-klein), background-color var(--t-klein), background-position var(--t-druk) var(--e-uit);
}
.veld :is(input, select):hover { border-color: #b9b4ac; }
.veld :is(input, select):focus { outline: none; border-color: var(--inkt); background-color: #fff; }
.veld input::placeholder { color: #8a857d; opacity: 1; }
/* the chevron is the select's own background, not a pseudo-element: ::before is the corner bracket and ::after the red rule */
.veld select {
  cursor: pointer; padding-right: 52px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%23181A1D' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 22px center; background-size: 12px 8px;
}
.veld select:focus { background-position: right 22px calc(50% + 3px); }
.veld select:invalid { color: #8a857d; }
.veld option { color: var(--inkt); }
.veld label {
  position: absolute; left: 14px; top: 0; z-index: 1; transform: translateY(-50%); padding: 2px 9px; border-radius: 99px; background: #fff; color: #5b5751;
  font-size: 13px; font-weight: 560; line-height: 1.25; pointer-events: none; transition: background-color var(--t-druk), color var(--t-druk);
}
/* the number reads as part of the label, in the mono face the rest of the page numbers with */
.aanvraag .veld label::before { content: counter(veld, decimal-leading-zero); content: counter(veld, decimal-leading-zero) / ''; margin-right: 7px; font-family: var(--mono); font-size: .92em; color: var(--rood-tekst); transition: color var(--t-druk); }
.veld:focus-within label { background: var(--inkt); color: #fff; }
.veld:focus-within label::before { color: #fff; }
/* the red line: a 2 px ring clipped to the stub under the box, opened to the whole outline on focus */
.veld::after {
  content: ''; position: absolute; left: 0; right: 0; top: 0; height: var(--h); border-radius: var(--r);
  box-shadow: inset 0 0 0 2px var(--rood); pointer-events: none;
  clip-path: inset(calc(100% - 2px) 100% 0 0 round 2px);
  transition: clip-path .5s var(--e-uit);
}
.veld:focus-within::after, .veld.is-fout::after { clip-path: inset(0 round var(--r)); }
/* under a pointer the line runs out along the bottom edge; on focus it goes on around the box */
.veld:hover::after { clip-path: inset(calc(100% - 2px) 16px 0 16px round 2px); }
.veld:focus-within:hover::after { clip-path: inset(0 round var(--r)); }
.veld-punt { position: absolute; right: 20px; top: calc(var(--h) / 2 - 5px); width: 10px; height: 10px; border-radius: 50%; background: var(--rood); opacity: 0; transform: scale(.2); transition: opacity var(--t-klein), transform var(--t-klein) var(--e-pop); }
.veld.keuze .veld-punt { right: 42px; }
.veld:has(:user-valid) .veld-punt, .veld.is-geldig .veld-punt { opacity: 1; transform: none; }
/* punish late: the error appears once the field was touched (:user-invalid, so it also works without JavaScript) or the form was sent */
.fout { display: none; margin: 7px 4px 0; font-size: 13px; line-height: 1.35; color: var(--rood-tekst); }
.veld:has(:user-invalid) .fout, .veld.is-fout .fout, .chips:has(input:user-invalid) .fout, .chips.is-fout .fout { display: block; }
.veld:has(:user-invalid) :is(input, select), .veld.is-fout :is(input, select) { border-color: var(--rood); background-color: #fff5f4; }
.veld:has(:user-invalid) label, .veld.is-fout label { background: var(--rood); color: #fff; }
.veld:has(:user-invalid) label::before, .veld.is-fout label::before { color: #fff; }
.veld:has(:user-invalid) .veld-punt, .veld.is-fout .veld-punt { opacity: 0; }
.veld:has(:user-invalid)::after { clip-path: inset(0 round var(--r)); }
/* why we ask for the number (A9) */
.waarom { grid-column: 1 / -1; margin: 0; font-size: 14px; line-height: 1.4; color: #6e6a64; }
.pot { position: absolute; left: -9999px; }
.privacy { grid-column: 1 / -1; margin: 0; font-size: 13px; color: #6e6a64; }
.privacy a { color: inherit; }

/* ---------- "Andere" asks which one (Alex, 20-09): opened by the select's own :checked option, so it works without JavaScript too ---------- */
.veld-andere { display: none; }
.aanvraag:has(#f-sector option[value=Andere]:checked) .veld-andere { display: block; }

/* ---------- the consent he ticks himself: the box takes the red and the tick draws itself in ---------- */
.akkoord-veld { grid-column: 1 / -1; }
.akkoord { position: relative; display: grid; grid-template-columns: 26px minmax(0, 1fr); gap: 12px; align-items: start; padding: 2px 0; cursor: pointer; font-size: 15px; line-height: 1.45; color: #4a463f; }
.akkoord input { position: absolute; left: 0; top: 2px; width: 26px; height: 26px; margin: 0; opacity: 0; cursor: pointer; }
.akk-vink { display: grid; place-items: center; width: 26px; height: 26px; border: 1px solid #dedad4; border-radius: 9px; background: #f6f4f1; transition: background-color var(--t-druk), border-color var(--t-druk); }
.akk-vink svg { width: 16px; height: 16px; fill: none; stroke: #fff; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 24; stroke-dashoffset: 24; transition: stroke-dashoffset .4s var(--e-uit); }
.akkoord:hover .akk-vink { border-color: #b9b4ac; }
.akkoord input:checked + .akk-vink { border-color: var(--rood); background: var(--rood); }
.akkoord input:checked + .akk-vink svg { stroke-dashoffset: 0; }
.akkoord input:focus-visible + .akk-vink { outline: 2px solid var(--inkt); outline-offset: 3px; }
.akkoord-veld:has(:user-invalid) .fout, .akkoord-veld.is-fout .fout { display: block; }
.akkoord-veld.is-fout .akk-vink { border-color: var(--rood); background: #fff5f4; }

/* ---------- the pip meter: one pip per field, filling red, and the word that says what is left (de-werf v2) ---------- */
@property --n { syntax: '<number>'; inherits: true; initial-value: 0; }
.nog { grid-column: 1 / -1; display: flex; align-items: center; gap: 12px; margin: 0; font-size: 13px; letter-spacing: .02em; color: var(--fg2); transition: --n .35s var(--e-uit), color var(--t-druk); }
.nog::before { content: ''; flex: none; width: calc(var(--tot, 8) * 11px - 3px); height: 8px; background: linear-gradient(90deg, var(--rood) calc(var(--n, 0) / var(--tot, 8) * 100%), rgba(20, 20, 20, .18) 0); -webkit-mask: repeating-linear-gradient(90deg, #000 0 8px, transparent 8px 11px); mask: repeating-linear-gradient(90deg, #000 0 8px, transparent 8px 11px); }
.nog.klaar { color: var(--rood-tekst); }

/* ---------- the submit arms when everything is valid (kit 2's tally light runs once, from src/core/knoppen.js) ---------- */
.verstuur { grid-column: 1 / -1; justify-content: space-between; height: 74px; padding-left: 30px; font-size: 19px; }
html[data-knop=rec] .aanvraag .verstuur.is-ontwapend { --kb: #6e6a64; --kf: #fff; }
.aanvraag .verstuur.is-ontwapend { --kb: #6e6a64; --kf: #fff; }
/* without JavaScript nothing arms it, so the button is simply the red button and the browser does the checking */
html.no-js .aanvraag .verstuur.is-ontwapend, html.no-js[data-knop=rec] .aanvraag .verstuur.is-ontwapend { --kb: var(--rood-knop); --kf: #fff; }
html.no-js .nog { display: none; }
.verstuur[aria-busy=true] { cursor: progress; }

/* ---------- after sending: the red fills the screen from the button, then calms into "Wat gebeurt er nu" ---------- */
.vlam { position: fixed; inset: 0; z-index: 90; background: var(--rood-knop); pointer-events: none; will-change: clip-path; }
.vlam.vlam-wit { background: #fff; }
.vel.is-gelukt { grid-template-columns: minmax(0, 1fr); background: var(--rood-knop); color: #fff; --fg: #fff; --fg2: rgba(255, 255, 255, .84); --lijn: rgba(255, 255, 255, .32); }
.vel.is-gelukt .vel-intro { display: none; }
.gelukt { grid-column: 1 / -1; padding: clamp(8px, 2vw, 24px) 0 clamp(8px, 2vw, 20px); outline: none; }
.gelukt-merk { display: grid; place-items: center; width: 62px; height: 62px; margin: 0 0 26px; border-radius: 50%; background: #fff; }
.gelukt-merk svg { width: 28px; height: 28px; fill: none; stroke: var(--rood-knop); stroke-width: 2.8; stroke-linecap: round; stroke-linejoin: round; }
.gelukt-merk path { stroke-dasharray: 1; stroke-dashoffset: 0; }
.bedankt-kop { margin: 0 0 10px; font-size: clamp(44px, 4.6vw, 72px); font-weight: 650; line-height: 1; letter-spacing: -.02em; }
.bedankt-kop em { color: var(--rood); }
.gelukt .bedankt-kop em { color: #fff; }
.gelukt-sub { margin: 0 0 24px; font-size: clamp(20px, 1.7vw, 26px); font-weight: 600; letter-spacing: -.01em; }
.nu { list-style: none; margin: 0 0 30px; padding: 0; }
.nu li { display: grid; grid-template-columns: 12em minmax(0, 1fr); gap: 4px 22px; padding: 16px 0; border-top: 1px solid var(--lijn); font-size: 18px; line-height: 1.45; }
.nu b { padding-top: 4px; font-size: 12px; font-weight: 500; letter-spacing: .08em; text-transform: uppercase; color: var(--fg2); }
.gelukt-nog { margin: 0; font-size: 17px; }
.gelukt-nog .link { margin-left: 8px; }

@media (max-width: 1100px) {
  .aanvraag { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 760px) {
  .vel { grid-template-columns: minmax(0, 1fr); }
  .vel-intro { display: block; }
  .contact { margin-top: 0; }
  .nu li { grid-template-columns: minmax(0, 1fr); }
  .verstuur { height: 66px; }
}
@media (prefers-reduced-motion: reduce) {
  .veld::after, .veld-punt, .veld label, .nog, .akk-vink svg, .contact-tel span, .contact-tel .ci { transition: none; }
}

/* ---------- src/sections/12-voet.css ---------- */

/* ============ footer (slice C4, kit 13: the curtain) ============ */
.voet { overflow: hidden; }
.voet-binnen { padding: var(--sec-y) 0 0; }
.voet-grid { display: grid; grid-template-columns: minmax(0, 1.7fr) repeat(3, minmax(0, 1fr)); gap: 40px; }
.voet-zin { margin: 0 0 28px; font-size: clamp(36px, 4.2vw, 68px); font-weight: 650; line-height: 1.02; letter-spacing: -.02em; }
.voet-contact { margin-top: 40px; display: flex; flex-direction: column; align-items: flex-start; gap: 4px; font-style: normal; font-size: 15px; color: var(--fg2); }
.voet-contact a { font-size: 19px; text-decoration: none; color: #fff; }
/* the phone number draws its red underline once, as the curtain opens (kit 13). The line was already standing by the time a pointer
   reached it, so hovering did nothing (Alex, 20-09): under the pointer it now wipes off to the right and draws itself again */
.voet-tel { position: relative; }
.voet-tel::after { content: ''; position: absolute; left: 0; right: 0; bottom: -5px; height: 2px; background: var(--rood); transform-origin: 0 50%; transition: transform var(--t-deel) var(--e-uit); }
html.beweeg .voet-tel::after { transform: scaleX(0); }
html.beweeg .voet-tel.is-in::after, html.beweeg .voet-tel:hover::after { transform: scaleX(1); }
@media (hover: hover) and (pointer: fine) {
  html.beweeg .voet-tel.is-in:hover::after { animation: tel-opnieuw .62s var(--e-uit); }
}
@keyframes tel-opnieuw {
  0% { transform: scaleX(1); transform-origin: 100% 50%; }
  46% { transform: scaleX(0); transform-origin: 100% 50%; }
  47% { transform: scaleX(0); transform-origin: 0 50%; }
  100% { transform: scaleX(1); transform-origin: 0 50%; }
}
/* both addresses open Google Maps: quiet like the lines they replace, white under the pointer */
.voet-contact .voet-kaart { font-size: 15px; color: var(--fg2); transition: color var(--t-druk); }
.voet-contact .voet-kaart:hover { color: #fff; }
/* the four profiles under the contact block (Alex, 20-09), 44 px each, out of the legal rule */
.voet-sociaal { list-style: none; display: flex; gap: 4px; margin: 8px 0 0 -10px; padding: 0; }
.voet-contact .voet-sociaal a { display: grid; place-items: center; width: 44px; height: 44px; color: var(--fg2); transition: color var(--t-druk); }
.voet-sociaal svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.voet-contact .voet-sociaal a:hover { color: #fff; }
/* "Gekopieerd" on the e-mail address; on a phone the address stays a plain mailto and the number a tel: link */
.voet-mail { display: inline-flex; align-items: baseline; gap: 12px; }
.kopieer { background: none; border: 0; padding: 2px 0; font-size: 13px; font-weight: 560; color: var(--fg2); cursor: pointer; text-decoration: underline; text-underline-offset: 4px; opacity: 0; transition: opacity var(--t-klein), color var(--t-klein); }
.voet-mail:hover .kopieer, .kopieer:focus-visible { opacity: 1; color: #fff; }
.kopie-melding { font-size: 13px; color: var(--rood); }
@media (hover: none) { .kopieer { display: none; } }
.groep { display: flex; flex-direction: column; gap: 10px; }
.groep h2 { margin: 0 0 10px; font-size: 12px; font-weight: 500; letter-spacing: .08em; text-transform: uppercase; color: var(--fg2); }
.groep a { font-size: 16px; text-decoration: none; opacity: .82; transition: opacity .3s; }
.groep a:hover { opacity: 1; }
.voet-merk { padding: clamp(80px, 14vh, 160px) var(--rand) 0; }
.voet-merk img { width: 100%; height: auto; }
.juridisch { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 12px; padding-top: 28px; padding-bottom: 28px; font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--fg2); }
.juridisch a { text-decoration: none; }
.juridisch a:hover { text-decoration: underline; }

/* the curtain (kit 13): the footer's content counter-scrolls exactly one footer height while the footer passes the bottom edge, so it
   stands still and the page lifts off it. Scroll-driven, so it never touches the main thread; src/core/houd.js is not needed here.
   Without JavaScript, on the quiet tier and with ?rust=1 the footer is simply the last block of the page. */
@supports (animation-timeline: view()) {
  html.beweeg .voet { view-timeline: --voet block; }
  html.beweeg .voet-binnen { animation: voet-gordijn linear both; animation-timeline: --voet; animation-range: entry 0% entry 100%; }
  html.beweeg .voet-merk img { animation: voet-merk linear both; animation-timeline: --voet; animation-range: entry 0% entry 100%; }
}
@keyframes voet-gordijn { from { transform: translateY(-100%); } to { transform: none; } }
@keyframes voet-merk { from { transform: translateY(22%); } to { transform: none; } }

@media (max-width: 1100px) {
  .voet-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .voet-cta { grid-column: 1 / -1; }
}
@media (max-width: 760px) {
  .voet-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .groep:last-of-type { grid-column: 1 / -1; }
  .juridisch { flex-direction: column; }
  /* the phone tier (slice D): the sitemap links stand apart already, so each one only has to claim its own 44 px */
  .groep a, .voet-contact a { display: inline-flex; align-items: center; min-height: 44px; }
}
@media (prefers-reduced-motion: reduce) {
  .voet-binnen, .voet-merk img { animation: none !important; transform: none !important; }
  .voet-tel::after { transition: none; }
  html.beweeg .voet-tel.is-in:hover::after { animation: none; }
}

/* ---------- src/sections/99-balk.css ---------- */

/* ============ the phone bar: 64 px plus the safe area, opaque graphite, sliding in over 350 ms ============ */
.balk { display: none; }
@media (max-width: 760px) {
  .balk:not([hidden]) {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 75; display: flex; align-items: center; gap: 10px;
    padding: 8px 12px calc(8px + env(safe-area-inset-bottom)); background: var(--grafiet); box-shadow: 0 -1px 0 rgba(255, 255, 255, .08);
    transform: translateY(100%); visibility: hidden; transition: transform .35s var(--e-in), visibility 0s .35s;
  }
  .balk.is-aan { transform: none; visibility: visible; transition: transform .35s var(--e-uit), visibility 0s; }
  .balk .knop { flex: 1; height: 48px; justify-content: space-between; font-size: 16px; padding-left: 20px; padding-right: 4px; }
  /* scoped under .balk: knoppen-telefoon.css's a[href^="tel:"] (inline-flex) outranked a bare .balk-bel and pushed the icon off centre */
  .balk .balk-bel { display: grid; place-items: center; flex: none; width: 48px; height: 48px; border-radius: 50%; background: #fff; color: var(--inkt); }
  .balk-bel svg { width: 20px; height: 20px; fill: currentColor; }
  .balk-bel:active { transform: scale(.94); }
}
[data-tier=stil] .balk { transition: none !important; }

/* ---------- src/core/knoppen-telefoon.css ---------- */

/* built after the sections: on a phone these win over section buttons of equal weight, such as .verstuur */
@media (max-width: 760px) {
  .knop { height: 56px; font-size: 16px; padding-left: 22px; }
  .pijl { width: 38px; height: 38px; }
  /* the phone-tier pass (slice D): every standalone control is at least 44 px under a thumb. .link is only used for a call to action on
     its own line, so it may grow downwards without moving the text; a link inside a sentence is a plain <a> and keeps its line height. */
  .link { min-height: 44px; padding-top: 7px; padding-bottom: 11px; }
  /* a phone number is the one link a phone visitor is most likely to hit, wherever it stands, the callback sheet included */
  a[href^="tel:"] { display: inline-flex; align-items: center; min-height: 44px; }
}

/* ---------- src/core/knop-rec.css ---------- */

/* ---------- the record-dot button (kit 1), the lab's rec-vast (D-112) ----------
   Built after the sections, so it wins over their button colours of equal weight. Every primary button is red with a white dot where the
   arrow was, like the red circle that starts a recording on his phone. Pointed at, focused or tapped, a circle of deeper red grows from
   where the pointer came in and leaves toward where it went out (core/knoppen.js moves it with WAAPI, so a fast in-out never jumps); a
   ring arms around the dot and the dot breathes at REC's rhythm; pressed, the ring closes on the dot. Never a square: on his phone the
   square means stop. The dot stays white, so REC keeps its meaning. Ghost buttons keep their arrow. */
html[data-knop=rec] .knop:not(.knop-ghost) { --kb: var(--rood-knop); --kf: #fff; isolation: isolate; }
html[data-knop=rec] .knop:not(.knop-ghost) > span[data-t] { color: var(--kf); }
html[data-knop=rec] .knop:not(.knop-ghost) > span[data-t]::before, html[data-knop=rec] .knop:not(.knop-ghost) > span[data-t]::after { display: none; }
/* the fill: one circle, sized once per button, moved and scaled on the compositor */
.knop > .k-bak { position: absolute; inset: 0; z-index: -1; border-radius: inherit; overflow: hidden; pointer-events: none; }
.k-vul {
  position: absolute; left: 0; top: 0; width: var(--R, 700px); height: var(--R, 700px);
  margin: calc(var(--R, 700px) / -2) 0 0 calc(var(--R, 700px) / -2); border-radius: 50%; background: var(--rood-diep); scale: 0; pointer-events: none;
}
html[data-knop=rec] .knop:not(.knop-ghost) .pijl { background: transparent; overflow: visible; }
html[data-knop=rec] .knop:not(.knop-ghost) .pijl::before {
  -webkit-mask: none; mask: none; inset: 16px; border-radius: 50%; background: #fff; transform: none; transition: none; forced-color-adjust: none;
}
html[data-knop=rec] .knop:not(.knop-ghost) .pijl::after {
  -webkit-mask: none; mask: none; inset: 10px; border-radius: 50%; background: none; border: 1.5px solid #fff;
  opacity: 0; transform: scale(1.6); transition: opacity .16s ease, transform .2s var(--e-uit);
}
html[data-knop=rec] .knop:not(.knop-ghost).is-aan .pijl::after { opacity: 1; transform: none; }
html[data-knop=rec] .knop:not(.knop-ghost).is-aan .pijl::before { animation: adem 1.4s ease-in-out .15s infinite; }
html[data-knop=rec] .knop:not(.knop-ghost):active .pijl::after { opacity: 1; transform: scale(.62); transition-duration: .13s; }
html[data-knop=rec] .knop:not(.knop-ghost).knipper .pijl::before { animation: rec .6s steps(1) 2; }
@keyframes rec { 50% { opacity: .2; } }
@keyframes adem { 50% { opacity: .3; } }
@media (max-width: 760px) {
  html[data-knop=rec] .knop:not(.knop-ghost) .pijl::before { inset: 14px; }
  html[data-knop=rec] .knop:not(.knop-ghost) .pijl::after { inset: 8px; }
}
/* the header's small button carries a dot in rec only */
html[data-knop=rec] .knop-klein { padding-right: 4px; gap: 4px; }
html[data-knop=rec] .knop-klein .pijl { width: 38px; height: 38px; }
html[data-knop=rec] .knop-klein .pijl::before { inset: 15px; }
html[data-knop=rec] .knop-klein .pijl::after { inset: 9px; }
/* the quiet tier: a colour change only, no fill and no blink */
[data-tier=stil] .knop .pijl::before { animation: none !important; }
[data-tier=stil] .knop .pijl::after { transition: none; }
[data-tier=stil] .k-vul { display: none; }
[data-tier=stil] .knop.knop.is-aan { --kb: var(--rood-diep); }

/* ---------- the link beside it (kit 3), fixed: the underline rests full, wipes out to the right and draws in again (knoppen.js) ---------- */
.link.is-vast { position: relative; padding-bottom: 5px; background: none; transition: none; }
.link.is-vast::after { content: none; }
.l-tekst { display: block; }
.l-lijn { position: absolute; left: 0; bottom: 0; width: 100%; height: 1.5px; background: currentColor; transform-origin: 0 50%; scale: 1 1; pointer-events: none; }
.l-pijl { display: block; flex: none; width: 1em; height: 1em; }
.l-pijl svg { display: block; width: 100%; height: 100%; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
/* the quiet tier keeps the full line and skips the cycle; !important because the cycle runs on WAAPI, which loses to it */
[data-tier=stil] .link.is-vast .l-lijn { scale: 1 1 !important; translate: 0px 0px !important; }

/* ---------- src/core/overgang.css ---------- */

/* ---------- page transitions (D-091, D-145; orionix's own rules copied in D-146) ----------
   orionix.framer.website runs a same-document View Transition: Framer's router calls `document.startViewTransition`
   and, for the length of the change, injects a stylesheet. D-145 read `getTiming().easing` off the two animations, which
   says `linear` for every CSS animation because the curve sits on the keyframes, and never saw that stylesheet. Read out
   of `document.styleSheets` while the transition runs (Chrome, 1440 x 900, the About and the Works link), it is:

     ::view-transition-old(*), ::view-transition-new(*)   mix-blend-mode: normal; backface-visibility: hidden
     ::view-transition-old(root)   1 s, no delay, cubic-bezier(.8, 0, .2, 1), fill both
                                   opacity 1 -> 0, transform none -> translate(0, -10%) scale(.9)
     ::view-transition-new(root)   1 s, 10 ms delay, the same curve, fill both
                                   opacity 0 -> 1, transform translate(0, 30%) -> none
                                   plus a hard-edged mask that wipes the page in from its bottom edge to its top,
                                   driven by a registered number that the same keyframes take from 0 to 1

   The curve is what he sees: both pages stand nearly still for the first fifth, change places fast through the middle
   and settle slowly, where a linear second reads as a plain cross-fade. The header is not a named element there: it
   travels with its own page, which is what makes each page read as one thing rather than as content under a frame.

   Ours is the cross-document form of the same API, so no router: Chrome and Edge 126+, Safari 18.2+, Firefox an ordinary
   load. Same origin only, so it runs over serve-gzip.cjs or deel.cjs, never from file://. */
@media (prefers-reduced-motion: no-preference) { @view-transition { navigation: auto; } }

@property --vt-veeg { syntax: "<number>"; inherits: false; initial-value: 0; }
::view-transition-old(*), ::view-transition-new(*) { mix-blend-mode: normal; backface-visibility: hidden; }
::view-transition-old(root) { animation: 1s cubic-bezier(.8, 0, .2, 1) both vt-weg; }
::view-transition-new(root) {
  animation: 1s .01s cubic-bezier(.8, 0, .2, 1) both vt-komt;
  -webkit-mask-image: linear-gradient(360deg, #000 calc(100% * var(--vt-veeg)), transparent calc(100% * var(--vt-veeg)));
  mask-image: linear-gradient(360deg, #000 calc(100% * var(--vt-veeg)), transparent calc(100% * var(--vt-veeg)));
}
@keyframes vt-weg {
  from { opacity: 1; transform: translate(0, 0) scale(1); }
  to { opacity: 0; transform: translate(0, -10%) scale(.9); }
}
@keyframes vt-komt {
  from { opacity: 0; transform: translate(0, 30%) scale(1); --vt-veeg: 0; }
  to { opacity: 1; transform: translate(0, 0) scale(1); --vt-veeg: 1; }
}

/* ?kop=vast holds the header still instead, as concept-3.md §6.2 first proposed, and ?kop=mee gives orionix's back.
   The choice is kept for the tab (begin.html and the sample pages read it), so it survives the page change it judges. */
html[data-kop=vast] .kop { view-transition-name: kop; }
html[data-kop=vast] ::view-transition-group(kop) { animation-duration: 600ms; animation-timing-function: var(--e-uit); }
