:root {
  /* Fluted-glass ground. The canvas is a cool near-white because the ribs and
     the frosted cards are what carry the warmth; his photographs are full of
     timber and bring the warm half on their own. */
  --sc-canvas:     #F3F4F7;
  --sc-surface:    #FAFBFC;
  --sc-ink:        #0B0D10;   /* 17.7:1 */
  --sc-ink-soft:   #5A6472;   /* 5.5:1  */

  /* The intake's primary is #FF55FF. At 2.4:1 it cannot carry text or a filled
     button, so it splits by job: the hot value lights the ground and the
     progress bar, where it is atmosphere and never has to be read, and the same
     hue taken down does every pill, rule and accent word at 4.9:1 or better.
     One colour, two jobs, no second accent. */
  --sc-accent:     #C600A1;   /* the mark's own magenta, taken down until it
                                 reads: 4.88:1 on canvas, white on it 5.36:1 */
  --sc-accent-hot: #FB23D3;   /* the magenta straight off the logo file.
                                 Decorative only: 3.0:1, never under text */
  --sc-accent-ink: #FFFFFF;

  /* the intake's second colour, used as a text ROLE (object meta), never as a
     second accent */
  --creps-label:     #3F5C3C;
  --creps-label-dim: #4F6B4C;

  --sc-font-display: "Inter", ui-sans-serif, system-ui, sans-serif;
  --sc-font-text:    "Inter", ui-sans-serif, system-ui, sans-serif;
  --sc-font-mono:    "Inter", ui-sans-serif, system-ui, sans-serif;

  /* glass */
  --glass:      linear-gradient(157deg, rgb(255 255 255 / .78), rgb(255 255 255 / .46));
  --glass-edge: rgb(255 255 255 / .85);
  --glass-blur: blur(20px) saturate(1.5);
  --r-card: 22px;
  --r-media: 18px;
  --r-pill: 999px;

  --sc-shadow-color: 232 24% 22%;
  --sc-e1: 0 1px 2px hsl(var(--sc-shadow-color) / .07),
           0 3px 8px -2px hsl(var(--sc-shadow-color) / .10);
  --sc-e2: 0 2px 4px hsl(var(--sc-shadow-color) / .06),
           0 10px 24px -6px hsl(var(--sc-shadow-color) / .14);
  --sc-e3: 0 4px 10px hsl(var(--sc-shadow-color) / .06),
           0 22px 48px -12px hsl(var(--sc-shadow-color) / .16),
           0 60px 100px -40px hsl(var(--sc-shadow-color) / .18);

  --rail-w: 0rem;             /* the index left the margin; it is a pill now */
  --plate: color-mix(in oklab, var(--sc-surface) 92%, var(--sc-ink));
}

::selection { background: var(--sc-accent); color: var(--sc-accent-ink); }

/* Grain reads roughly twice as loud on paper as it does on a dark ground, and
   at the engine default it turns the canvas grey. Halved, it still stops the
   large flat areas banding. */
.sc-grain { opacity: 0.022; }

body { overflow-x: clip; }

/* --------------------------------------------------------------- type -- */
.d {
  font-family: var(--sc-font-display);
  font-weight: 700;
  line-height: 0.96;
  letter-spacing: var(--sc-track-tight);
  text-wrap: balance;
  margin: 0;
}
.d--xl { font-size: clamp(2.6rem, 1.5rem + 5.4vw, 6.4rem); }
.d--lg { font-size: clamp(2.1rem, 1.4rem + 3.2vw, 4.2rem); }
.d--md { font-size: clamp(1.5rem, 1.2rem + 1.5vw, 2.4rem); letter-spacing: var(--sc-track-snug); }

.p {
  margin: 0;
  max-width: 46ch;
  color: var(--sc-ink-soft);
  font-size: var(--sc-t-base);
  line-height: 1.62;
  text-wrap: pretty;
}
.p--tight { max-width: 34ch; }

/* the museum label: one schema, every object, no exceptions -------------- */
.lab {
  font-family: var(--sc-font-mono);
  font-size: clamp(0.68rem, 0.64rem + 0.14vw, 0.78rem);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  line-height: 1.5;
  margin: 0;
}
.lab__nr   { color: var(--sc-accent); font-variant-numeric: tabular-nums; }
.lab__ttl  { color: var(--sc-ink); display: block; margin-top: 0.15em; }
.lab__meta { color: var(--creps-label-dim); display: block; margin-top: 0.15em; }

/* a label plate that sits over/beside media */
.plate {
  background: color-mix(in oklab, var(--sc-canvas) 82%, transparent);
  backdrop-filter: blur(14px) saturate(1.1);
  -webkit-backdrop-filter: blur(14px) saturate(1.1);
  border-top: 1px solid var(--sc-accent);
  padding: var(--sc-4) var(--sc-5) calc(var(--sc-4) + 2px);
  box-shadow: var(--sc-e2);
}

/* ------------------------------------------------- the object index nav -- */




/* the one action, one label, everywhere ---------------------------------- */
.act-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  background: var(--sc-accent);
  color: var(--sc-accent-ink);
  font-family: var(--sc-font-mono);
  font-size: 0.76rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  padding: 0.72rem 1.05rem;
  border-radius: var(--sc-r-sm);
  box-shadow: var(--sc-e1);
  transition: transform var(--sc-d-fast) var(--sc-ease-out),
              filter var(--sc-d-fast) var(--sc-ease-out);
}
/* 43px was a pixel under the tap-target floor on a phone */
@media (max-width: 899px) { .act-cta { padding: 0.82rem 1.05rem; } }
.act-cta:hover { filter: brightness(1.08); }
.act-cta:active { transform: translateY(1px); }
.act-cta svg { width: 1em; height: 1em; flex: none; }

/* mobile chrome: a slim bottom bar carrying the same one label ----------- */

/* page frame: everything clears the index rail --------------------------- */
.frame { padding-left: 0; }
@media (min-width: 1120px) { .frame { padding-left: var(--rail-w); } }

.wrap { width: 100%; max-width: 78rem; margin-inline: auto; padding-inline: var(--sc-gutter); }

/* ============================================================ ACT 1 vitrine */
/* De maker staat naast zijn naam, niet erachter. Twee kolommen op een computer,
   onder elkaar op een telefoon, met het woordmerk dat over de fotorand valt. */
.vit {
  position: relative;
  min-height: 100svh;
  display: grid;
  align-content: center;
  padding-block: clamp(5rem, 12vh, 9rem) clamp(4rem, 10vh, 7rem);
  overflow: clip;
  isolation: isolate;
}
.vit__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(1.8rem, 5vh, 3.2rem);
  align-items: center;
}
/* De typekolom is precies zo breed als het woordmerk (max-content), en het
   beeld schuift er met een negatieve marge overheen. Zo is de overlap een
   vaste maat in plaats van iets dat uit de kolombreedte volgt: met een
   percentagekolom liep hij van 19 pixels tussenruimte op 900 tot 66 pixels
   overlap op 1920, en verdween de S op de brede maten helemaal achter de foto. */
@media (min-width: 900px) {
  .vit__grid {
    grid-template-columns: max-content minmax(12rem, 1fr);
    column-gap: 0;
  }
}
.vit__type { position: relative; z-index: 3; min-width: 0; }

/* ---- het beeld ----------------------------------------------------------- */
.vit__media {
  position: relative; z-index: 4; margin: 0;
  border-radius: var(--sc-r-md);
  overflow: hidden;
  box-shadow: var(--sc-e3);
  isolation: isolate;
}
.vit__media::after {           /* edge light: sells a raised surface */
  content: ""; position: absolute; inset: 0; pointer-events: none;
  border-radius: inherit;
  box-shadow: inset 0 1px 0 color-mix(in oklab, var(--sc-ink) 16%, transparent),
              inset 0 0 0 1px color-mix(in oklab, var(--sc-ink) 7%, transparent);
}
/* <picture> is de lijst, de foto hangt er 12 procent te groot in.
   Op een telefoon staat het objectlabel als blok onder het beeld, dus daar
   moet het beeld ook zijn eigen hoogte hebben: zonder dit schoof de parallax
   hem omhoog en groeide er een witte strook tussen foto en label. */
.vit__media picture {
  display: block; position: relative; overflow: hidden;
  height: clamp(19rem, 54vh, 32rem);
}
.vit__img {
  position: absolute; left: 0; top: -8%;
  width: 100%; height: 116%;
  object-fit: cover; object-position: 50% 30%;
  display: block;
  will-change: transform;
}
@media (min-width: 900px) {
  .vit__media picture { height: clamp(22rem, 62vh, 36rem); }
  .vit__img { object-position: 50% 34%; }
}

/* ---- het woordmerk -------------------------------------------------------
   Hier zat de handtekening van de pagina: het merk als sjabloon, dat tijdens
   het eerste scherm werd volgespoten. Veertien maskergangen, zes spatten, een
   omtrek in -webkit-text-stroke en een venster per breedte om het binnen beeld
   af te krijgen.

   Casper wilde het niet: "CREPS niet spuitend tijdens scrollen." Alles wat
   erbij hoorde is weg in plaats van uitgezet, want een uitgezet effect blijft
   meerekenen in elke stylesheet die erna komt. Wat overblijft is een woordmerk
   dat gewoon staat. */
.vit__wm { position: relative; width: max-content; }
.vit__mark {
  font-size: clamp(3.4rem, 1.2rem + 15.2vw, 14.8rem);
  line-height: 0.82;
  white-space: nowrap;
  letter-spacing: -0.045em;
  color: var(--sc-ink);
}
.vit__mark em { font-style: normal; color: var(--sc-accent); }

.vit__sub {
  position: relative; z-index: 3;
  margin: 0 0 var(--sc-5);
  font-family: var(--sc-font-mono);
  font-size: clamp(0.7rem, 0.66rem + 0.2vw, 0.84rem);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--creps-label);
}
.vit__zin {
  margin: var(--sc-5) 0 0;
  max-width: 26rem;
  font-size: clamp(1rem, 0.94rem + 0.3vw, 1.16rem);
  line-height: 1.55;
  color: var(--sc-ink-soft);
}
@media (min-width: 900px) {
  /* staat hier en niet bij .vit__grid: daar kwam hij vóór ".vit__media
     { margin: 0 }" en werd hij bij gelijke specificiteit meteen weer
     overschreven, waardoor de overlap op elke breedte precies 0 was. */
  .vit__media { margin-left: clamp(-3.4rem, -3vw, -2.2rem); }
}

.vit__plate {
  position: absolute; z-index: 4;
  left: clamp(0.75rem, 2.4vw, 1.4rem);
  bottom: clamp(0.75rem, 2.4vw, 1.4rem);
  max-width: 20rem;
}

/* ============================================================== ACT 2 index */
.contents { padding-block: clamp(3.5rem, 8vh, 6rem) clamp(4rem, 9vh, 7rem); }
.contents__grid {
  display: grid; gap: var(--sc-7) var(--sc-8);
  grid-template-columns: 1fr;
  align-items: start;
}
@media (min-width: 820px) { .contents__grid { grid-template-columns: minmax(0,1.05fr) minmax(0,0.95fr); } }
.chapters { list-style: none; margin: var(--sc-5) 0 0; padding: 0; }
.chapters li { border-top: 1px solid color-mix(in oklab, var(--sc-ink) 12%, transparent); }
.chapters a {
  display: grid; grid-template-columns: 5.6rem 1fr auto; gap: var(--sc-4);
  align-items: baseline;
  padding: var(--sc-4) 0;
  text-decoration: none; color: var(--sc-ink);
  transition: color var(--sc-d-fast) var(--sc-ease-out);
}
.chapters a:hover { color: var(--sc-accent); }
.chapters .rom { font-family: var(--sc-font-mono); font-size: 0.72rem; letter-spacing: 0.16em; color: var(--creps-label-dim); }
.chapters .nm  { font-family: var(--sc-font-display); font-weight: 600; font-size: clamp(1.15rem, 1rem + 0.7vw, 1.6rem); letter-spacing: -0.015em; }
.chapters .rg  { font-family: var(--sc-font-mono); font-size: 0.72rem; letter-spacing: 0.1em; color: var(--creps-label-dim); font-variant-numeric: tabular-nums; }

/* ================================================================ ACT 3 rail */
.rail {
  display: flex; align-items: stretch; gap: clamp(1.1rem, 2.4vw, 2.4rem);
  padding-inline: var(--sc-gutter);
  will-change: transform;
}
@media (min-width: 1120px) { .rail { padding-left: calc(var(--rail-w) + var(--sc-gutter)); } }
.rail__lead, .rail__note {
  flex: none; width: clamp(14rem, 22vw, 20rem);
  align-self: center;
  display: flex; flex-direction: column; gap: var(--sc-4);
}
.obj {
  flex: none;
  width: clamp(15rem, 22vw, 22rem);
  align-self: center;
  margin: 0;
  display: flex; flex-direction: column; gap: var(--sc-4);
}
.obj__f {
  position: relative;
  border-radius: var(--sc-r-md);
  overflow: hidden;
  background: var(--sc-surface);
  box-shadow: var(--sc-e2);
  transform-style: preserve-3d;
}
.obj__f::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  box-shadow: inset 0 1px 0 color-mix(in oklab, var(--sc-ink) 13%, transparent),
              inset 0 0 0 1px color-mix(in oklab, var(--sc-ink) 6%, transparent);
}
.obj__f img { width: 100%; height: clamp(15rem, 42vh, 27rem); object-fit: cover; display: block; }
.obj--tall .obj__f img { height: clamp(19rem, 54vh, 34rem); }

/* staggered settle: a rail that only slides reads as a slideshow */
@media (prefers-reduced-motion: no-preference) {
  .rail > .obj {
    opacity: calc(0.55 + 0.45 * var(--in, 1));
    transform: translate3d(0, calc((1 - var(--in, 1)) * 26px), 0);
    transition: none;
  }
}

/* ================================================================= ACT 4 hal
   Three planes at three rates. The window is deep and slow, the object in
   front of it is nearer and faster, the copy is nearest and moves with the
   scroll rather than against it. The parallax rate is the only thing that
   separates them, so nothing here is allowed to also carry a transform: the
   engine writes translate3d onto these elements and would overwrite it. */
.hal {
  position: relative;
  padding-block: clamp(4rem, 12vh, 8rem) clamp(4.5rem, 13vh, 9rem);
}
.hal__grid { display: grid; gap: var(--sc-6); grid-template-columns: 1fr; }

.hal__deep, .hal__near { margin: 0; }

/* the deep window. overflow hidden so the slow layer inside can travel
   without growing the box, and taller than the image so the travel has
   somewhere to go. */
.hal__frame {
  position: relative; overflow: hidden;
  border-radius: var(--r-media);
  background: var(--sc-surface);
  box-shadow: var(--sc-e3);
  aspect-ratio: 4 / 5;
}
.hal__frame img {
  position: absolute; left: 0; right: 0; top: -8%;
  width: 100%; height: 116%; object-fit: cover; display: block;
}
.hal__frame::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; border-radius: inherit;
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / .55),
              inset 0 0 0 2px rgb(30 38 56 / .05);
}

.hal__near .fig__f img { width: 100%; display: block; object-fit: cover;
                         height: clamp(9rem, 26vh, 16rem); }

.hal__copy { display: flex; flex-direction: column; gap: var(--sc-5); max-width: 34rem; }

@media (min-width: 900px) {
  .hal__grid {
    grid-template-columns: repeat(12, minmax(0, 1fr));
    align-items: start;
    row-gap: clamp(2rem, 6vh, 4rem);
  }
  .hal__deep { grid-column: 1 / span 6; grid-row: 1 / span 2; }
  .hal__lead { grid-column: 8 / span 5; grid-row: 1; align-self: center;
               padding-top: clamp(2rem, 8vh, 5rem); }
  /* the near plane starts inside the window's column and runs out past it,
     which is what makes the two planes read as two distances rather than as
     two pictures side by side. */
  .hal__near { grid-column: 6 / span 6; grid-row: 2; align-self: end;
               position: relative; z-index: 2; }
  .hal__near figcaption.lab { margin-left: auto; margin-right: 0; display: table; }

  /* het gespiegelde paneel. Zelfde raster, zelfde afstanden, alleen de kolommen
     omgeklapt: het diepe venster naar rechts, de kop naar links. Daardoor leest
     de tweede helft als een antwoord op de eerste en niet als een herhaling,
     terwijl het nog steeds hetzelfde apparaat is en dus hetzelfde bedrag aan
     scroll kost. */
  .hal__grid--om .hal__deep { grid-column: 7 / span 6; }
  .hal__grid--om .hal__lead { grid-column: 1 / span 5; }
  /* spiegelbeeld van de overlap hierboven: het nabije vlak eindigt binnen de
     eerste kolom van het venster in plaats van er netjes naast te stoppen. */
  .hal__grid--om .hal__near { grid-column: 2 / span 6; }
  .hal__grid--om .hal__near figcaption.lab { margin-left: 0; margin-right: auto; }
}

/* de twee panelen zijn één act, dus de ruimte ertussen is ruimer dan een
   rijafstand en smaller dan een sectiepauze. */
.hal__grid + .hal__grid { margin-top: clamp(2.2rem, 6vh, 4.5rem); }

/* ========================================================= ACT 5 werkplaats */
@media (min-width: 900px) {
  /* c rides up over b's row boundary. depth without a single shadow */
}
.fig { margin: 0; position: relative; }
.fig__f {
  position: relative; overflow: hidden; border-radius: var(--sc-r-md);
  background: var(--sc-surface); box-shadow: var(--sc-e3);
}
.fig__f::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  box-shadow: inset 0 1px 0 color-mix(in oklab, var(--sc-ink) 12%, transparent),
              inset 0 0 0 1px color-mix(in oklab, var(--sc-ink) 6%, transparent);
}
.fig__f img { width: 100%; height: 100%; object-fit: cover; display: block; }
.fig figcaption { margin-top: var(--sc-3); }
.h-sm  .fig__f img { height: clamp(13rem, 32vh, 21rem); }
.h-md  .fig__f img { height: clamp(17rem, 46vh, 30rem); }
.h-lg  .fig__f img { height: clamp(21rem, 64vh, 40rem); }
/* one column on a phone, so the same heights would stack 21 objects into a
   scroll nobody finishes. Smaller, but still the largest thing on the screen. */
@media (max-width: 899px) {
  .h-sm  .fig__f img { height: clamp(10rem, 21vh, 14rem); }
  .h-md  .fig__f img { height: clamp(13rem, 30vh, 18rem); }
  .h-lg  .fig__f img { height: clamp(15rem, 40vh, 22rem); }
}

/* ================================================================ ACT 6 verf */
.verf { padding-block: clamp(3.5rem, 9vh, 7rem); }
.verf__grid { display: grid; gap: var(--sc-6); grid-template-columns: 1fr; }
@media (min-width: 900px) {
  .verf__grid { grid-template-columns: repeat(12, 1fr); gap: var(--sc-5); align-items: start; }
  .verf__txt { grid-column: 1 / span 4; grid-row: 1 / span 2; align-self: center; padding-right: var(--sc-5); }
  .verf__1 { grid-column: 5 / span 4; grid-row: 1; }
  .verf__2 { grid-column: 9 / span 4; grid-row: 1; }
  .verf__3 { grid-column: 5 / span 8; grid-row: 2; }
}

/* ============================================================= ACT 7 stilte */
/* ACT 7 stilte — the object hung like a museum piece, with its register entry
   as the wall label beside it rather than a caption floating underneath.
   Two things were wrong before. The photograph was small and the whole screen
   was margin, and the motion was a clip wipe on a small element, which
   devices.md calls a fidget: a wipe reads as a transition only when it runs
   edge to edge across something big. So the object got big and the wipe got
   short, and the drift inside the frame carries the rest. */
.still {
  display: grid; align-items: center;
  padding-block: clamp(3rem, 8vh, 6rem);
}
/* the held screen is a desktop idea. On a phone the same min-height turns the
   act into a column of air with a photograph in it, so the section just takes
   the height of what is in it. */
@media (min-width: 900px) { .still { min-height: 92svh; } }
.still__grid {
  display: grid; gap: clamp(2rem, 5vw, 4rem);
  grid-template-columns: minmax(0, 1fr);
  align-items: center;
}
@media (min-width: 900px) {
  .still__grid { grid-template-columns: minmax(0, 0.62fr) minmax(0, 1fr); }
}
.still__label { max-width: 24rem; }
.still__label h2 { margin: 0.2rem 0 0; }
.still__nr {
  margin: var(--sc-4) 0 0;
  font-weight: 800; letter-spacing: -0.04em; line-height: 0.9;
  font-size: clamp(3.4rem, 8vw, 5.6rem);
  color: var(--sc-accent);
  font-variant-numeric: tabular-nums;
}
/* the frame carries the photograph's own aspect ratio, so nothing is cropped:
   this is the one professional shot in the archive and guessing at a crop of
   it is how you cut the legs off a stool. The drift moves the whole framed
   object instead of the image inside the frame. */
.still__fig { margin: 0; display: flex; justify-content: center; }
.still__f {
  position: relative; overflow: hidden;
  border-radius: var(--r-media);
  background: var(--sc-surface);
  box-shadow: var(--sc-e3);
  /* width-driven, not height-driven: a definite height plus an aspect-ratio
     wins over max-width and pushes the frame past the column on a phone. */
  width: min(100%, 34rem);
  /* Stond op 975/1193, de verhouding van de barkruk die hier vroeger hing.
     Het object is nu U.H.M. en dat is een liggend stuk: een lang blad op één
     kast. In een staand kader viel het blad er aan beide kanten af. */
  aspect-ratio: 4 / 3;
}
@media (min-width: 900px) { .still__f { width: min(100%, calc(56vh * 1.3333)); } }

/* Het anker om de foto is nieuw en had geen eigen hoogte, dus de foto viel
   terug op zijn natuurlijke verhouding en liet de onderste helft van het
   kader wit. Het anker vult nu het kader, net als in de hal. */
.still__f .tolink { position: absolute; inset: 0; }
.still__f::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / .55), inset 0 0 0 2px rgb(30 38 56 / .05);
}
.still__f img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* ============================================== ACT 8 ontleding — THE PEAK */
.exp {
  position: relative;
  width: 100%; height: 100%;
  display: grid; place-items: center;
  overflow: hidden;
}
.exp__head {
  position: absolute; z-index: 6;
  top: clamp(1rem, 3.2vh, 2.6rem);
  left: 50%; translate: -50% 0;
  width: min(92%, 46rem);
  text-align: center;
}
@media (min-width: 1120px) { .exp__head { left: calc(50% + var(--rail-w) / 2); } }

/* the assembly frame keeps the parts in their true photographic relationship */
.exp__frame {
  position: relative;
  width: min(94vw, 62rem);
  aspect-ratio: 1448 / 1086;
  margin-top: clamp(2rem, 7vh, 5rem);
}
@media (min-width: 1120px) { .exp__frame { margin-left: calc(var(--rail-w) * 0.5); } }

.part {
  position: absolute;
  transform-origin: 50% 50%;
  will-change: transform, filter;
}
.part img { width: 100%; height: auto; display: block; }

/* real positions, read straight out of assets/uhm-parts.json */
.part--plant { left: 10.77%; top: 21.18%; width: 22.03%; }
.part--crate { left: 13.60%; top: 38.21%; width: 17.61%; }
.part--plank { left: 7.18%; top: 51.29%; width: 86.19%; }
.part--cube  { left: 51.66%; top: 64.55%; width: 25.00%; }

/* part callouts: arrive only while the assembly is held apart */
.cal {
  position: absolute; z-index: 7;
  font-family: var(--sc-font-mono);
  font-size: clamp(0.6rem, 0.56rem + 0.16vw, 0.72rem);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--sc-ink);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
}
.cal::before {
  content: ""; position: absolute; top: 50%; right: calc(100% + 0.5rem);
  width: var(--cal-len, 3.2rem); height: 1px;
  background: linear-gradient(to left, var(--sc-accent), color-mix(in oklab, var(--sc-accent) 10%, transparent));
  transform: scaleX(var(--cal-s, 0)); transform-origin: right center;
}
.cal--l { text-align: right; }
.cal--l::before { right: auto; left: calc(100% + 0.5rem); transform-origin: left center;
  background: linear-gradient(to right, var(--sc-accent), color-mix(in oklab, var(--sc-accent) 10%, transparent)); }
.cal b { color: var(--sc-accent); font-weight: 400; }

.exp__foot {
  position: absolute; z-index: 6;
  bottom: clamp(0.9rem, 2.8vh, 2.4rem); left: 50%; translate: -50% 0;
  width: min(92%, 40rem); text-align: center;
}
@media (min-width: 1120px) { .exp__foot { left: calc(50% + var(--rail-w) / 2); } }

/* ============================================================ ACT 9 aanvraag */
.ask { padding-block: clamp(4rem, 11vh, 9rem) clamp(6rem, 12vh, 8rem); }
.ask__plate {
  border-top: 2px solid var(--sc-accent);
  padding-top: var(--sc-6);
  display: grid; gap: var(--sc-7);
  grid-template-columns: 1fr;
}
@media (min-width: 860px) { .ask__plate { grid-template-columns: minmax(0,1fr) minmax(0,1fr); } }
.ask__lines { list-style: none; margin: var(--sc-5) 0 0; padding: 0; display: flex; flex-direction: column; }
.ask__lines li { border-top: 1px solid color-mix(in oklab, var(--sc-ink) 12%, transparent); }
.ask__lines a, .ask__lines span {
  display: grid; grid-template-columns: 7.5rem 1fr; gap: var(--sc-4);
  padding: var(--sc-4) 0;
  font-family: var(--sc-font-mono); font-size: 0.8rem; letter-spacing: 0.06em;
  color: var(--sc-ink); text-decoration: none;
  transition: color var(--sc-d-fast) var(--sc-ease-out);
}
.ask__lines a:hover { color: var(--sc-accent); }
.ask__lines .k { color: var(--creps-label-dim); letter-spacing: 0.14em; text-transform: uppercase; font-size: 0.7rem; }
.ask__foot {
  margin-top: clamp(3rem, 8vh, 6rem);
  padding-top: var(--sc-5);
  border-top: 1px solid color-mix(in oklab, var(--sc-ink) 10%, transparent);
  display: flex; flex-wrap: wrap; gap: var(--sc-4) var(--sc-7);
  align-items: baseline; justify-content: space-between;
}

/* ------------------------------------------------------ shared reveals -- */
[data-sc-in] .rise {
  opacity: 0; transform: translate3d(0, 14px, 0);
  transition: opacity 620ms var(--sc-ease-out), transform 620ms var(--sc-ease-out);
}
/* the engine flags either the container or the staggered child. Both spellings
   have to beat the hide rule above, which sits later in the cascade. */
[data-sc-in].sc-in .rise,
[data-sc-in] .sc-in.rise,
[data-sc-in] .sc-in .rise { opacity: 1; transform: none; }
.wipe { clip-path: inset(0 0 100% 0); }

/* focus, always visible, themed, offset ---------------------------------- */
:where(a, button, [tabindex]):focus-visible {
  outline: 2px solid var(--sc-accent);
  outline-offset: 3px;
  border-radius: 3px;
}

/* ------------------------------------------------------- reduced motion -- */
@media (prefers-reduced-motion: reduce) {
  .part { transform: none !important; filter: none !important; }
  .cal { opacity: 1 !important; }
  .cal::before { transform: scaleX(1) !important; }
  .rail > .obj { opacity: 1 !important; transform: none !important; }
}

/* --------------------------------------------------------------- phones -- */
@media (max-width: 700px) {
  .vit__mark { font-size: clamp(3.6rem, 18vw, 6rem); }
  .vit__plate { position: static; margin-top: var(--sc-4); max-width: none; }
  .vit__media { margin-left: 0; }
  .exp__head { top: 1.1rem; }
  .exp__foot { bottom: 4.6rem; }
  body { padding-bottom: 3.4rem; }   /* clear the fixed mobile bar */
}

/* ==========================================================================
   THE SIGNATURE MOVE — driven entirely from --sc-p. No JS, engine untouched.
   s = separation   : ramps up 0.03→0.30, HOLDS to 0.72, returns by 0.96
                      It used to start at 0.18, which on a 3.2vh pinned act is
                      about 360px of scrolling with the object dead still, and
                      readers took that for the bottom of the page. It now
                      starts within the first 60px.
   h = hold         : the window where the callouts and dimension lines live
   ========================================================================== */
.exp {
  --p: var(--sc-p, 0);
  --s: calc(clamp(0, calc((var(--p) - 0.03) / 0.27), 1) - clamp(0, calc((var(--p) - 0.72) / 0.24), 1));
  --h: calc(clamp(0, calc((var(--p) - 0.32) / 0.09), 1) - clamp(0, calc((var(--p) - 0.70) / 0.07), 1));
}

/* a taller frame than the photograph, so the parts have somewhere to go */
.exp__frame {
  container-type: size;
  /* capped by viewport height too, or the assembly overflows the pinned stage
     and the exploded base lands on the closing label */
  width: min(92vw, 60rem, 78svh);
  aspect-ratio: 1448 / 1420;
  position: relative;
  margin-top: clamp(1.5rem, 5vh, 3.5rem);
}
@media (min-width: 1120px) { .exp__frame { margin-left: calc(var(--rail-w) * 0.5); } }

/* the assembly keeps the parts in their true photographic relationship */
.exp__asm {
  position: absolute;
  left: 0; right: 0; top: 50%;
  translate: 0 -50%;
  aspect-ratio: 1448 / 1086;
}

.part { will-change: translate, scale, filter; }

/* separation along the real assembly axis, plus scale and blur as distance */
.part--plant { translate: 0 calc(-23cqh * var(--s)); scale: calc(1 + 0.06 * var(--s)); }
.part--crate { translate: 0 calc(-11cqh * var(--s)); scale: calc(1 + 0.025 * var(--s)); }
.part--plank { translate: 0 calc(  4cqh * var(--s)); }
.part--cube  { translate: 0 calc( 13cqh * var(--s)); scale: calc(1 - 0.05 * var(--s));
               filter: blur(calc(0.9px * var(--s))); }

/* callouts live in the assembly so they travel with their part */
.cal {
  position: absolute; z-index: 7;
  font-family: var(--sc-font-mono);
  font-size: clamp(0.58rem, 0.5rem + 0.26vw, 0.74rem);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--sc-ink);
  white-space: nowrap;
  opacity: var(--h, 0);
  pointer-events: none;
}
.cal b { color: var(--sc-accent); font-weight: 400; }
.cal::before {
  content: ""; position: absolute; top: 50%;
  height: 1px; width: var(--cal-len, 6cqw);
  background: linear-gradient(to left, var(--sc-accent), color-mix(in oklab, var(--sc-accent) 8%, transparent));
  right: calc(100% + 0.45rem);
  transform: scaleX(var(--h, 0)); transform-origin: right center;
}
.cal--r::before {
  right: auto; left: calc(100% + 0.45rem);
  transform-origin: left center;
  background: linear-gradient(to right, var(--sc-accent), color-mix(in oklab, var(--sc-accent) 8%, transparent));
}
.cal--up::before {
  top: auto; bottom: calc(100% + 0.4rem); left: 0.6rem; right: auto;
  width: 1px; height: var(--cal-len, 5cqh);
  transform: scaleY(var(--h, 0)); transform-origin: bottom center;
  background: linear-gradient(to top, var(--sc-accent), color-mix(in oklab, var(--sc-accent) 8%, transparent));
}

/* placement, measured against the assembly box */
.cal--plant { left: 55%;  top: 25%;  --cal-len: 21cqw; translate: 0 calc(-23cqh * var(--s)); }
.cal--crate { left: 55%;  top: 41%;  --cal-len: 23cqw; translate: 0 calc(-11cqh * var(--s)); }
.cal--plank { left: 11%;  top: 74%;  --cal-len: 9cqh;  translate: 0 calc(  4cqh * var(--s)); }
.cal--cube  { left: 18%;  top: 92%;  --cal-len: 30cqw; translate: 0 calc( 13cqh * var(--s)); }

/* the rail's staggered settle, driven off the pan act's own progress */
@media (prefers-reduced-motion: no-preference) {
  .rail > .obj {
    --in: clamp(0, calc((var(--sc-p, 1) + 0.13 - var(--i, 0) * 0.105) / 0.17), 1);
  }
}

@media (max-width: 900px) {
  .cal--plant { left: 46%; top: 8%;  --cal-len: 12cqw; }
  .cal--crate { left: 46%; top: 33%; --cal-len: 14cqw; }
  .cal--plank { left: 8%;  top: 72%; }
  .cal--cube  { left: 8%;  top: 90%; --cal-len: 38cqw; }
}

/* a scrim only where the closing label sits, never a full-frame overlay,
   and a sibling of the copy so the verification pass can measure it */
.exp__scrim {
  position: absolute; z-index: 5; left: 0; right: 0; bottom: 0;
  height: clamp(6rem, 16vh, 11rem);
  background: linear-gradient(to top,
      var(--sc-canvas) 0%,
      color-mix(in oklab, var(--sc-canvas) 82%, transparent) 46%,
      transparent 100%);
  pointer-events: none;
}

/* ==========================================================================
   THE LOOK LAYER
   Fluted glass ground, frosted cards floating on it, Inter set tight.
   Appended, so it wins the cascade over the composition rules above without
   disturbing the act geometry those rules encode.
   ========================================================================== */

/* ---------------------------------------------------------------- ground --
   Two fixed planes under everything. The bleed is the brand colour as light,
   not as ink; the flutes are a rib pattern thin enough that the act's drift
   colour still reads straight through them. */
.bleed, .flutes { position: fixed; inset: 0; pointer-events: none; }
.bleed  { z-index: 0; }
.flutes { z-index: 1; }

.bleed {
  background:
    radial-gradient(30% 52% at -8% 38%,  rgb(251 35 211 / .20), transparent 72%),
    radial-gradient(30% 52% at 108% 64%, rgb(251 35 211 / .17), transparent 72%),
    radial-gradient(44% 26% at 50% 110%, rgb(251 35 211 / .08), transparent 74%);
}

/* Real fluted glass is a row of half-cylinders: a bright specular line where
   each rib turns toward the light, then a fast fall to a dark seam. A single
   repeating gradient does the whole thing. */
.flutes {
  background: repeating-linear-gradient(90deg,
    rgb(255 255 255 / .00)  0px,
    rgb(255 255 255 / .34)  2px,
    rgb(255 255 255 / .82)  5px,
    rgb(255 255 255 / .30)  9px,
    rgb(30 38 56 / .055)   13px,
    rgb(30 38 56 / .085)   14px,
    rgb(255 255 255 / .00) 15px);
}
/* the ribs thin out over the middle of the page, so the copy column is not
   read through corrugation the whole way down */
.flutes::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg,
    transparent 0%,
    color-mix(in oklab, var(--sc-canvas) 52%, transparent) 22%,
    color-mix(in oklab, var(--sc-canvas) 52%, transparent) 78%,
    transparent 100%);
}
.sc-grain { opacity: 0.016; z-index: 2; }
main.frame { position: relative; z-index: 3; }
@media (min-width: 1120px) { .frame { padding-left: 0; } }

/* ----------------------------------------------------------------- glass --
   One recipe. Everything that reads as a floating panel uses it. */
.card, .plate, .rail__lead, .rail__note, .hal__copy,
.verf__txt, .rec__head, .exp__head, .exp__foot, .ask__plate,
.contents__grid > div, .pill {
  background: var(--glass);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-edge);
  border-radius: var(--r-card);
  box-shadow: var(--sc-e2), inset 0 1px 0 rgb(255 255 255 / .9);
}
.card, .rail__lead, .rail__note, .hal__copy,
.exp__head, .exp__foot { padding: clamp(0.9rem, 1.8vw, 1.4rem) clamp(1.2rem, 2.4vw, 1.9rem); }
.ask__plate { padding: clamp(1.6rem, 3vw, 2.6rem); border-top: 1px solid var(--glass-edge); }

/* ------------------------------------------------------------------ type --
   Inter, set the way the reference sets it: heavy, tight, optical sizing on. */
body { font-optical-sizing: auto; letter-spacing: -0.011em; }
.d { font-weight: 800; letter-spacing: -0.032em; line-height: 0.98; }
.d--md { letter-spacing: -0.028em; }
.p { color: var(--sc-ink-soft); line-height: 1.58; letter-spacing: -0.006em; }

/* the label keeps its register, it just stops being monospaced */
.lab { font-weight: 600; letter-spacing: 0.09em; }
.lab__nr  { color: var(--sc-accent); font-weight: 700; }
.lab__ttl { color: var(--sc-ink); font-weight: 700; letter-spacing: -0.012em;
            text-transform: none; font-size: 1.06em; }
.lab__meta{ color: var(--creps-label-dim); font-weight: 500; }

/* a caption under a photograph is a small frosted pill, not loose text */
figcaption.lab {
  display: inline-block;
  margin-top: calc(var(--sc-3) * -0.4);
  position: relative; z-index: 2;
  padding: 0.55rem 0.95rem 0.6rem;
  background: var(--glass);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-edge);
  border-radius: 14px;
  box-shadow: var(--sc-e1), inset 0 1px 0 rgb(255 255 255 / .9);
}

/* <picture> wraps every photograph for the WebP source. display:contents keeps
   it out of the box tree, so a flex or grid parent still lays out the <img>
   itself and no existing layout rule had to move. */
picture { display: contents; }

/* ----------------------------------------------------------------- media --
   Photographs are the one thing that is NOT frosted. They sit on the ribs as
   solid rounded blocks, which is what makes the glass around them read as glass. */
.vit__media, .obj__f, .fig__f, .hal__frame, .still__f {
  border-radius: var(--r-media);
  background: var(--sc-surface);
  box-shadow: var(--sc-e3);
}
.vit__media::after, .obj__f::after, .fig__f::after, .hal__frame::after {
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / .55),
              inset 0 0 0 2px rgb(30 38 56 / .05);
}

/* ------------------------------------------------------------------- CTA --
   A solid pill. The one action, one shape, everywhere. */
.act-cta {
  border-radius: var(--r-pill);
  background: var(--sc-accent);
  color: var(--sc-accent-ink);
  font-family: var(--sc-font-text);
  font-weight: 600;
  font-size: 0.86rem;
  letter-spacing: -0.004em;
  text-transform: none;
  padding: 0.72rem 1.25rem;
  box-shadow: 0 1px 0 rgb(255 255 255 / .28) inset,
              0 8px 20px -8px color-mix(in oklab, var(--sc-accent) 70%, transparent),
              var(--sc-e1);
}
@media (max-width: 899px) { .act-cta { padding: 0.78rem 1.25rem; } }
.act-cta:hover { filter: brightness(1.1); }

[data-sc-progress] { height: 3px; background: var(--sc-accent-hot); }
::selection { background: var(--sc-accent-hot); color: #1A0A1A; }
:where(a, button, [tabindex]):focus-visible { outline-color: var(--sc-accent); }

/* -------------------------------------------------------------- the nav --
   A capsule that floats over the ribs. It is still the object index the
   gallery grammar asks for: every entry carries its object range and jumps. */
.nav {
  position: fixed; z-index: var(--sc-z-chrome, 50);
  top: clamp(0.6rem, 1.6vh, 1.1rem);
  left: 50%; translate: -50% 0;
  display: flex; align-items: center; gap: clamp(0.4rem, 1vw, 0.9rem);
  padding: 0.42rem 0.42rem 0.42rem 1.05rem;
  border-radius: var(--r-pill);
  background: linear-gradient(157deg, rgb(255 255 255 / .86), rgb(255 255 255 / .62));
  -webkit-backdrop-filter: blur(22px) saturate(1.6);
  backdrop-filter: blur(22px) saturate(1.6);
  border: 1px solid rgb(255 255 255 / .9);
  box-shadow: var(--sc-e2), inset 0 1px 0 rgb(255 255 255 / .95);
  max-width: calc(100vw - 1.5rem);
}
.nav__mark {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-weight: 800; font-size: 0.98rem; letter-spacing: -0.02em;
  color: var(--sc-ink); text-decoration: none; white-space: nowrap;
}
.nav__mark:hover { color: var(--sc-accent); }
/* the one mark the brand actually owns: the routed bar from the favicon */
.nav__glyph {
  width: 1.15rem; height: 1.15rem; flex: none; border-radius: 6px;
  background: var(--sc-ink);
  position: relative;
}
.nav__glyph::after {
  content: ""; position: absolute; left: 22%; right: 22%; top: 44%;
  height: 11%; border-radius: 1px; background: var(--sc-accent-hot);
}
.nav__list {
  display: flex; align-items: center; gap: clamp(0.1rem, 0.6vw, 0.5rem);
  list-style: none; margin: 0; padding: 0;
}
.nav__list a {
  display: inline-flex; align-items: baseline; gap: 0.34rem;
  padding: 0.5rem 0.72rem;
  border-radius: var(--r-pill);
  font-size: 0.86rem; font-weight: 500; letter-spacing: -0.008em;
  color: var(--sc-ink-soft); text-decoration: none; white-space: nowrap;
  transition: background var(--sc-d-fast) var(--sc-ease-out),
              color var(--sc-d-fast) var(--sc-ease-out);
}
.nav__n { font-size: 0.7rem; font-weight: 600; letter-spacing: 0.04em;
          color: var(--creps-label-dim); font-variant-numeric: tabular-nums; }
.nav__list a:hover { color: var(--sc-ink); background: rgb(255 255 255 / .7); }
.nav__list a[aria-current="true"] {
  color: var(--sc-ink); background: rgb(255 255 255 / .92);
  box-shadow: var(--sc-e1);
}
.nav__list a[aria-current="true"] .nav__n { color: var(--sc-accent); }
.nav .act-cta { font-size: 0.83rem; padding: 0.6rem 1.05rem; }

/* the capsule keeps the brand and the action on a phone; the chapter index
   stays reachable through the contents plate in act 2, which lists all of them */
/* On a phone the capsule used to drop its links and lean on the chapter index
   in act 2 for navigation. That index is gone, so hiding them here would leave
   the phone with no way to jump at all. They stay, in a strip that swipes. */
@media (max-width: 899px) {
  .nav { gap: 0.4rem; padding-left: 0.7rem; }
  .nav__mark span, .nav__mark { font-size: 0; gap: 0; }   /* mark only, no wordmark */
  .nav__logo { width: 1.6rem; }
  .nav__list {
    flex: 1 1 auto; min-width: 0;
    overflow-x: auto; overscroll-behavior-x: contain;
    scrollbar-width: none; -ms-overflow-style: none;
    scroll-snap-type: x proximity;
  }
  .nav__list::-webkit-scrollbar { display: none; }
  .nav__list li { scroll-snap-align: start; }
  .nav__list a { padding: 0.5rem 0.6rem; font-size: 0.82rem; }
  .nav .act-cta { padding: 0.72rem 0.9rem; font-size: 0.78rem; }
}

/* every act now starts under a floating capsule */
.frame > section:first-child { padding-top: clamp(4.2rem, 9vh, 6rem); }

/* ------------------------------------------------------------- eyebrows --
   The reference sets its small caps in the accent, not in a third colour.
   Sage keeps exactly one job: the object meta line. */
.lab--eye { color: var(--sc-accent); letter-spacing: 0.11em; }
.lab--dim { color: var(--sc-ink-soft); }

/* the hero plate sits ON the photograph now, not hanging off it */
.vit__plate {
  left: clamp(0.9rem, 2vw, 1.6rem);
  bottom: clamp(0.9rem, 2vw, 1.6rem);
  border-radius: 16px;
  padding: 0.85rem 1.15rem 0.9rem;
}
.vit__sub { color: var(--sc-ink-soft); letter-spacing: 0.16em; }
.vit__mark { letter-spacing: -0.05em; }

/* the rail lost the left margin the index used to occupy, so the cards can
   take the width back and keep the travel near one-to-one with the wheel */
.obj { width: clamp(16rem, 26vw, 26rem); }
.rail__lead, .rail__note { width: clamp(15rem, 24vw, 22rem); }

/* ============================================ ACT 5 werkplaats — showcase --
   The reference's recognition block, renamed and filled with real objects:
   a heading card, one object large behind it, and the rest floating over it on
   their own planes at a slight angle. Depth from overlap and rotation, not
   from a drop shadow. */
.rec { padding-block: clamp(3rem, 8vh, 6rem) clamp(4rem, 10vh, 7rem); }
.rec__stage { display: grid; gap: var(--sc-6); grid-template-columns: 1fr; }
.rec__head { align-self: start; }
.rec__hero, .rec__c, .rec__wide { margin: 0; }
.rec__hero figcaption.lab { margin-left: auto; margin-right: 0; display: table; }
.rec__hero .fig__f img,
.rec__c .fig__f img,
.rec__wide .fig__f img { width: 100%; display: block; object-fit: cover; }
.rec__hero .fig__f img { height: clamp(15rem, 44vh, 28rem); }
.rec__c   .fig__f img  { height: clamp(11rem, 30vh, 19rem); }
.rec__wide .fig__f img { height: clamp(13rem, 32vh, 20rem); }
.rec__note {
  margin: 0; justify-self: start;
  padding: 0.7rem 1.1rem; border-radius: 14px;
  font-size: 0.92rem; color: var(--sc-ink-soft); letter-spacing: -0.006em;
  max-width: 26rem;
}

@media (min-width: 900px) {
  .rec__stage {
    grid-template-columns: repeat(12, 1fr);
    align-items: start;
    column-gap: var(--sc-5);
    row-gap: 0;
    perspective: 1600px;
  }
  /* row 1: the card sits ON the object, which is the whole move */
  .rec__head { grid-column: 1 / span 5; grid-row: 1; z-index: 4; margin-top: clamp(1rem, 3vh, 2.4rem); }
  .rec__hero { grid-column: 4 / span 9; grid-row: 1; z-index: 1; }

  /* row 2: three planes, each turned a little out of the page */
  .rec__c    { grid-row: 2; }
  .rec__c--a { grid-column: 1 / span 4;  z-index: 3;
               margin-top: clamp(1.5rem, 4vh, 3rem);
               transform: rotateY(9deg) rotateZ(-1.2deg); transform-origin: 100% 50%; }
  .rec__c--b { grid-column: 5 / span 4;  z-index: 5;
               margin-top: clamp(-3.5rem, -5vh, -2rem);
               transform: rotateY(-4deg) rotateZ(1deg); }
  .rec__c--c { grid-column: 9 / span 4;  z-index: 2;
               margin-top: clamp(2.5rem, 6vh, 4.5rem);
               transform: rotateY(-9deg) rotateZ(1.4deg); transform-origin: 0% 50%; }

  /* row 3: the wide one lies flat again, and the note leans on its corner */
  .rec__wide { grid-column: 3 / span 10; grid-row: 3; z-index: 1;
               margin-top: clamp(2.5rem, 6vh, 4.5rem); }
  .rec__note { grid-column: 1 / span 5; grid-row: 3; z-index: 6; align-self: end;
               margin-bottom: clamp(-1.5rem, -2vh, -0.5rem); }
}

/* the caption pill of a rotated card would shear with it, so it rides flat */
.rec__c figcaption.lab { transform: none; }

/* a fixed capsule means an anchor jump would otherwise land under it */
main.frame > section { scroll-margin-top: 5.5rem; }

/* ------------------------------------------------- the peak, refitted ----
   The head and foot became glass cards, and a fixed capsule now sits over the
   top of the stage. Both cost vertical room the assembly was using, so the
   frame comes down to fit the band that is actually free. */
.exp__head {
  top: clamp(4.6rem, 9.5vh, 6rem);
  width: auto; max-width: min(92%, 34rem);
  border-radius: var(--r-pill);
  padding: 0.7rem clamp(1.2rem, 2.4vw, 1.8rem) 0.78rem;
}
.exp__foot { bottom: clamp(1rem, 3vh, 2.2rem); width: auto; max-width: min(92%, 30rem); }
.exp__frame { width: min(92vw, 60rem, 67svh); }

/* a callout has to survive being read against corrugated glass */
.cal {
  padding: 0.34rem 0.6rem;
  border-radius: 9px;
  background: rgb(255 255 255 / .74);
  -webkit-backdrop-filter: blur(10px) saturate(1.3);
  backdrop-filter: blur(10px) saturate(1.3);
  box-shadow: 0 1px 0 rgb(255 255 255 / .9) inset, var(--sc-e1);
  font-weight: 600;
  letter-spacing: 0.055em;
}
.cal b { font-weight: 700; }
/* the scrim was a dark-page device: on paper the foot card carries itself */
.exp__scrim { display: none; }
@media (max-width: 899px) { .nav .act-cta { padding: 0.72rem 1.1rem; } }

/* ------------------------------------------------------ the phone stack --
   The showcase block's planes collapse into one column on a phone, so five
   objects at desktop heights would turn this act alone into three screenfuls. */
@media (max-width: 899px) {
  .rec__hero .fig__f img { height: clamp(11rem, 28vh, 16rem); }
  .rec__c    .fig__f img { height: clamp(9rem,  19vh, 13rem); }
  .rec__wide .fig__f img { height: clamp(10rem, 21vh, 14rem); }
  .h-sm .fig__f img { height: clamp(9rem,  17vh, 12rem); }
  .h-md .fig__f img { height: clamp(11rem, 24vh, 15rem); }
  .h-lg .fig__f img { height: clamp(13rem, 32vh, 18rem); }
  .card, .rail__lead, .rail__note, .hal__copy,
  .rec__head, .contents__grid > div { padding: 1.15rem 1.25rem; }
  .ask__plate { padding: 1.35rem 1.25rem; }
  .rec { padding-block: clamp(2rem, 5vh, 3rem) clamp(2.5rem, 6vh, 4rem); }
}

/* the mark itself. Three bars woven on the isometric axes, which is the same
   figure the ontleding act performs with a real object. */
.nav__logo { width: 1.95rem; height: auto; flex: none; display: block; }
@media (max-width: 899px) { .nav__logo { width: 1.5rem; } }

/* ==========================================================================
   THE MARK'S THREE COLOURS
   The logo is blue, yellow and pink woven together. Those three stay on the
   page as LIGHT and inside the mark itself. They are no longer handed out one
   per section: that chapter system is gone, and one accent carries the ink.
   ========================================================================== */
:root {
  --bar-blue:   #0027FC;
  --bar-yellow: #FCE901;
  --bar-pink:   #FB23D3;
}

/* the ground carries all three at once, one bar per edge */
.bleed {
  background:
    radial-gradient(40% 60% at -6% 22%,  rgb(26 34 240 / .30), transparent 74%),
    radial-gradient(40% 62% at 106% 58%, rgb(255 128 221 / .52), transparent 74%),
    radial-gradient(58% 38% at 44% 108%, rgb(255 242 0 / .48), transparent 76%),
    radial-gradient(34% 42% at 94% -8%,  rgb(255 242 0 / .38), transparent 74%),
    radial-gradient(34% 48% at 2% 94%,   rgb(26 34 240 / .22), transparent 76%);
}
[data-sc-progress] {
  background: linear-gradient(90deg, var(--bar-blue) 0%, var(--bar-yellow) 52%, var(--bar-pink) 100%);
}

/* the three bars, stated once under the wordmark */
.vit__sub { display: flex; align-items: center; gap: 0.7rem; }
.vit__sub::before {
  content: ""; width: 5.2rem; height: 0.6rem; border-radius: 999px; flex: none;
  background: linear-gradient(90deg,
    var(--bar-blue) 0 33.33%, var(--bar-yellow) 33.33% 66.66%, var(--bar-pink) 66.66% 100%);
}

/* ==========================================================================
   BOX SIZING
   Every glass panel's inner space, in one place. This lives at the end of the
   file on purpose: an earlier version of these values sat in a rule whose
   first selector was .shop__txt, and a sweep for dead .shop rules took the
   whole rule with it, leaving three card types at padding 0 with the text
   against the glass.
   ========================================================================== */
.card, .rail__lead, .rail__note, .hal__copy,
.verf__txt, .rec__head, .contents__grid > div {
  padding: clamp(1.6rem, 2.9vw, 2.5rem);
}
.ask__plate { padding: clamp(2rem, 3.6vw, 3.2rem); }

/* a caption pill is small, so it needs proportionally more air, not less */
figcaption.lab { padding: 0.78rem 1.25rem 0.85rem; }
.plate         { padding: 1.05rem 1.4rem 1.1rem; }
.rec__note     { padding: 0.9rem 1.35rem; }
.exp__head     { padding: 1rem clamp(1.5rem, 2.8vw, 2.1rem) 1.1rem; }
.exp__foot     { padding: 1.15rem clamp(1.4rem, 2.6vw, 2rem) 1.2rem; }

/* and the copy inside them gets room to breathe between its own lines */
.rec__head .p, .verf__txt .p, .rail__lead .p, .hal__copy .p { line-height: 1.62; }

@media (max-width: 899px) {
  .card, .rail__lead, .rail__note, .hal__copy,
  .verf__txt, .rec__head, .contents__grid > div { padding: 1.4rem 1.45rem; }
  .ask__plate { padding: 1.6rem 1.45rem; }
  figcaption.lab { padding: 0.7rem 1.05rem 0.78rem; }
}

/* A caption pill is a label, not a bar: it shrinks to its own text everywhere.
   Inside .obj it was stretching to the card because a column flex container
   stretches its items across. */
.obj > figcaption.lab { align-self: flex-start; }

/* ==========================================================================
   ALIGNMENT
   Every plane in a row starts on the same line. The staggered offsets read as
   depth on a still frame and as a broken grid the moment you actually scroll
   past them, because nothing ever settles onto a shared edge. Variation now
   comes from WIDTH, which keeps the rhythm without breaking the line.
   ========================================================================== */

/* ---- the rail: one height, so seven captions sit on one line -------------- */
.obj__f img,
.obj--tall .obj__f img { height: clamp(15rem, 44vh, 28rem); }
.obj--tall { width: clamp(11rem, 17.5vw, 16rem); }   /* portrait keeps its shape */
.rail { min-height: 100%; align-items: center; }     /* and the strip centres in the stage */

/* ---- the showcase: three planes, one shared top edge --------------------- */
@media (min-width: 900px) {
  .rec__c--a, .rec__c--b, .rec__c--c {
    grid-column: span 4;
    margin-top: clamp(1.5rem, 4vh, 3rem);
  }
  .rec__c--a { grid-column: 1 / span 4; }
  .rec__c--b { grid-column: 5 / span 4; }
  .rec__c--c { grid-column: 9 / span 4; }
  .rec__wide { grid-column: 1 / span 12; margin-top: clamp(2rem, 5vh, 3.5rem); }
  .rec__note { grid-column: 1 / span 5; grid-row: 4; margin-top: var(--sc-5); align-self: start; }
}
.rec__c .fig__f img { height: clamp(11rem, 27vh, 18rem); }

/* ---- verf is nu een voorproefje: twee foto's op een rij, dan een brede ----
   De vijf losse figuren zijn naar /verf verhuisd, dus de tweede rij
   hoeft niet meer over de tekstkolom heen te lopen. */
@media (min-width: 900px) {
  .verf__1, .verf__2, .verf__3 { margin-top: 0; }
  .verf__grid { row-gap: var(--sc-6); }
}
.verf__grid .fig .fig__f img { height: clamp(12rem, 30vh, 19rem); }
/* Het brede vak onderin de teaser. Er stond een foto in die van links naar
   rechts leest; nu staan er vijf panelen in twee rijen, en die vielen bij
   34vh halverwege de onderste rij af. Hoger vak plus een uitsnede die de
   grijze vloer aan de linkerkant laat vallen. */
@media (min-width: 900px) {
  /* .verf__grid .fig .fig__f img hierboven telt vier klassen; met drie werd
     deze regel stil overschreven en bleef het vak op 30vh staan, ook al stond
     hij in een mediaquery. Mediaqueries verhogen geen specificiteit. */
  .verf__grid .verf__3 .fig__f img { height: clamp(17rem, 50vh, 30rem); object-position: 62% 48%; }
}

/* ---- doorverwijzing: een tekstlink die zich als knop gedraagt ------------- */
.more {
  display: inline-flex; align-items: center; gap: 0.45rem;
  font-weight: 600; font-size: 0.95rem; letter-spacing: -0.01em;
  color: var(--sc-ink); text-decoration: none;
  border-bottom: 2px solid color-mix(in oklab, var(--sc-accent) 45%, transparent);
  padding-bottom: 0.12rem;
  transition: color var(--sc-d-fast) var(--sc-ease-out),
              border-color var(--sc-d-fast) var(--sc-ease-out);
}
.more__i { display: inline-flex; width: 0.95em; height: 0.95em; color: var(--sc-accent); }
.more__i svg { width: 100%; height: 100%; }
.more:hover, .more:focus-visible { color: var(--sc-accent); border-bottom-color: var(--sc-accent); }

/* ---- the statement plate is one column now that the index is gone -------- */
@media (min-width: 900px) { .contents__grid { grid-template-columns: minmax(0, 46rem); } }

/* The last 20px of rail drift came from the caption pills: a two-line title
   makes a taller card, and a centred card with a different height starts on a
   different line. One card height fixes both at once. */
.obj {
  align-self: center;
  height: clamp(21rem, 60vh, 37rem);
  justify-content: flex-start;
}
.rail__lead, .rail__note { align-self: center; }

/* The settle used to move each card 26px down and let it rise into place. It
   reads fine on a still frame and wrong the whole time you are actually
   panning, because seven cards are then on seven different lines. The settle
   stays; it is carried by opacity alone, so the row never leaves its line. */
@media (prefers-reduced-motion: no-preference) {
  .rail > .obj { transform: none; opacity: calc(0.42 + 0.58 * var(--in, 1)); }
}

/* The planes were turned a few degrees out of the page. With everything else
   on a shared line that rotation stops reading as depth and starts reading as
   a crooked box, and it drags each caption pill a few pixels off the row.
   Depth now comes from overlap and shadow only. */
.rec__c--a, .rec__c--b, .rec__c--c { transform: none; }
.rec__stage { perspective: none; }

/* the rail photo can take more of the screen now that nothing is offset */
.obj__f img, .obj--tall .obj__f img { height: clamp(15rem, 50vh, 32rem); }
.obj { height: clamp(21rem, 64vh, 40rem); }
/* travel back to roughly one lateral pixel per scrolled pixel */
.obj { width: clamp(16rem, 28vw, 28rem); }
.obj--tall { width: clamp(11rem, 19vw, 17rem); }
@media (max-width: 899px) { .nav .act-cta { padding: 0.78rem 0.9rem; } }

/* a word cut mid-letter reads as broken, not as scrollable: fade the edge so
   the strip says there is more to the right */
@media (max-width: 899px) {
  .nav__list {
    -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 1.6rem), transparent 100%);
            mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 1.6rem), transparent 100%);
  }
}

/* ==========================================================================
   THE SCROLL HINT
   The skill bans a scroll cue outright, on the grounds that a visitor looking
   at a hero already knows what a wheel does. The client asked for one anyway,
   so this is built to be the least annoying version of the thing: it is not a
   mouse icon, it is not an arrow, it uses the page's own pill and label
   language, and it deletes itself after 40px and never returns.
   ========================================================================== */
.hint {
  position: fixed; z-index: var(--sc-z-chrome, 50);
  left: 50%; translate: -50% 0;
  bottom: clamp(1.1rem, 3.2vh, 2rem);
  display: inline-flex; align-items: center; gap: 0.62rem;
  padding: 0.5rem 0.95rem 0.5rem 0.72rem;
  border-radius: var(--r-pill);
  background: linear-gradient(157deg, rgb(255 255 255 / .86), rgb(255 255 255 / .62));
  -webkit-backdrop-filter: blur(22px) saturate(1.6);
  backdrop-filter: blur(22px) saturate(1.6);
  border: 1px solid rgb(255 255 255 / .9);
  box-shadow: var(--sc-e2), inset 0 1px 0 rgb(255 255 255 / .95);
  pointer-events: none;
  opacity: 1;
  transition: opacity .45s ease, translate .45s ease;
}
.hint__txt {
  font-size: 0.7rem; font-weight: 600; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--sc-ink-soft);
}
/* a bead running down a hairline: the movement the page is asking for, drawn
   at the size of a full stop rather than as an animated mouse */
.hint__track {
  position: relative; display: block;
  width: 2px; height: 1.15rem; border-radius: 2px;
  background: color-mix(in oklab, var(--sc-ink) 14%, transparent);
  overflow: hidden;
}
.hint__run {
  position: absolute; left: 0; right: 0; top: 0; height: 46%;
  border-radius: 2px;
  background: linear-gradient(180deg, var(--bar-blue), var(--bar-pink));
}
@media (prefers-reduced-motion: no-preference) {
  .hint__run { animation: hint-run 1.9s cubic-bezier(.65,.05,.36,1) infinite; }
}
@keyframes hint-run {
  0%   { transform: translateY(-115%); }
  55%  { transform: translateY(118%); }
  100% { transform: translateY(118%); }
}
/* gone, and it stays gone */
.scrolled .hint { opacity: 0; translate: -50% 0.5rem; }

/* ---------------------------------------------------------- the peak bar --
   A pinned act holds the frame still while the scroll advances, which is
   exactly the moment a page reads as stuck. This hairline is the act's own
   --sc-p, so the heading plate says "this is going somewhere" without adding
   a second cue to the page. */
.exp__prog {
  display: block; margin-top: 0.7rem;
  height: 2px; border-radius: 2px;
  background: color-mix(in oklab, var(--sc-ink) 10%, transparent);
  overflow: hidden;
}
.exp__prog::after {
  content: ""; display: block; height: 100%; border-radius: inherit;
  width: calc(clamp(0, var(--sc-p, 0), 1) * 100%);
  background: linear-gradient(90deg, var(--bar-blue), var(--bar-yellow) 52%, var(--bar-pink));
}

/* ==========================================================================
   THE WARP
   warp.js redraws the rib field on a canvas so it can bend around the
   pointer. The CSS ribs above stay exactly as they are and stay the
   fallback; .warp-on is only set once the canvas has actually taken over,
   which means no-JS, coarse-pointer and reduced-motion visitors keep the
   static ground rather than a blank one.
   ========================================================================== */
canvas.warp {
  position: fixed; inset: 0; z-index: 1;
  pointer-events: none;
  display: none;
}
.warp-on canvas.warp { display: block; }
.warp-on .flutes { display: none; }

/* ==========================================================================
   THE MAKER
   The page argues that one pair of hands did all of it, and until now it
   never showed them. This sits at the close, on the trust beat, because a
   face changes what the button underneath it means.
   The photographs are shown at their own aspect ratio and never cropped:
   they arrived without a brief and a cover crop guesses at where the
   subject is.
   ========================================================================== */
.maker {
  display: grid; gap: clamp(1.8rem, 4vw, 3.4rem);
  grid-template-columns: 1fr;
  align-items: center;
  margin-bottom: clamp(2.5rem, 7vh, 4.5rem);
}
@media (min-width: 820px) {
  .maker { grid-template-columns: minmax(0, 0.72fr) minmax(0, 1fr); }
}
.maker__f { margin: 0; }
.maker__f img {
  display: block; width: 100%; height: auto;
  max-height: clamp(20rem, 58vh, 34rem); width: auto; max-width: 100%;
  border-radius: var(--r-media);
  background: var(--sc-surface);
  box-shadow: var(--sc-e3);
}
.maker__t { max-width: 34rem; }
.maker__t .p { margin: 0; }

/* the small round face inside the inquiry plate */
.who {
  display: flex; align-items: center; gap: 0.7rem;
  margin: 0 0 var(--sc-4);
  font-size: 0.9rem; color: var(--sc-ink);
}
.who__f {
  width: 2.6rem; height: 2.6rem; flex: none;
  border-radius: 999px; object-fit: cover;
  box-shadow: var(--sc-e1), 0 0 0 1px rgb(255 255 255 / .8);
}

/* ==========================================================================
   THE WERKPLAATS REVEALS, ROUNDED
   The engine writes a plain inset() clip, which has square corners, so a
   photograph mid-wipe is a rectangle being uncovered rather than the card it
   turns into. Measured mid-wipe: inset(0px 38.31% 0px 0px), no round.

   These five are driven from --sc-p in the page instead, with the same
   smoothstep the engine uses and a round on the clip, so the card grows as a
   card and its corners never square off. The engine is untouched.

   The windows live here rather than in a script, which also means they follow
   a resize across the breakpoint instead of keeping whatever they mounted
   with. They are measured values: each one starts when its figure is roughly
   a third on screen and ends while it is still fully in view.
   ========================================================================== */
.rv {
  --rt: clamp(0, calc((var(--sc-p, 1) - var(--rv-a)) / (var(--rv-b) - var(--rv-a))), 1);
  --rs: calc(var(--rt) * var(--rt) * (3 - 2 * var(--rt)));
}
.rv .fig__f {
  clip-path: inset(0 0 0 0 round var(--r-media));
  will-change: clip-path;
}
.rv--up   .fig__f { clip-path: inset(0 0 calc((1 - var(--rs)) * 100%) 0 round var(--r-media)); }
.rv--left .fig__f { clip-path: inset(0 calc((1 - var(--rs)) * 100%) 0 0 round var(--r-media)); }
/* the caption lands at the end of its own photograph, not alongside it */
.rv figcaption.lab {
  opacity: clamp(0, calc((var(--rs) - 0.55) / 0.45), 1);
}

/* phone: the three cards are a column, so each is in view at a different
   point of the act than it is on a desk */
.rec__hero { --rv-a: 0.13; --rv-b: 0.23; }
.rec__c--a { --rv-a: 0.24; --rv-b: 0.34; }
.rec__c--b { --rv-a: 0.36; --rv-b: 0.46; }
.rec__c--c { --rv-a: 0.48; --rv-b: 0.58; }
.rec__wide { --rv-a: 0.59; --rv-b: 0.73; }

@media (min-width: 900px) {
  .rec__hero { --rv-a: 0.11;  --rv-b: 0.25; }
  .rec__c--a { --rv-a: 0.30;  --rv-b: 0.40; }
  .rec__c--b { --rv-a: 0.325; --rv-b: 0.425; }
  .rec__c--c { --rv-a: 0.35;  --rv-b: 0.45; }
  .rec__wide { --rv-a: 0.47;  --rv-b: 0.66; }
}

@media (prefers-reduced-motion: reduce) {
  .rv .fig__f { clip-path: inset(0 0 0 0 round var(--r-media)); }
  .rv figcaption.lab { opacity: 1; }
}

/* ==========================================================================
   THE FOOTER
   One block, identical on all three pages, so the site ends the same way
   wherever you leave it. It is a frosted plate like everything else that
   floats on the ribs, and it carries the build credit the client asked for.
   ========================================================================== */
.foot {
  margin-top: clamp(3rem, 9vh, 6rem);
  padding: clamp(1.8rem, 3.4vw, 2.8rem);
  border-radius: var(--r-card);
  background: var(--glass);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-edge);
  box-shadow: var(--sc-e2), inset 0 1px 0 rgb(255 255 255 / .9);
}
.foot__top {
  display: grid; gap: clamp(1.8rem, 4vw, 3.2rem);
  grid-template-columns: 1fr;
}
@media (min-width: 720px) {
  .foot__top { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) minmax(0, 1.2fr); }
}
.foot__brand { display: flex; align-items: flex-start; gap: 0.85rem; }
.foot__logo { width: 2.1rem; height: auto; flex: none; margin-top: 0.1rem; }
.foot__mark {
  margin: 0; font-weight: 800; font-size: 1.15rem;
  letter-spacing: -0.022em; color: var(--sc-ink);
}
.foot__sub { margin: 0.25rem 0 0; color: var(--sc-ink-soft); font-size: 0.88rem; line-height: 1.5; }
.foot__h {
  margin: 0 0 0.85rem; font-size: 0.7rem; font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--creps-label-dim);
}
.foot__col ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.5rem; }
.foot__col a, .foot__col span { font-size: 0.92rem; color: var(--sc-ink); text-decoration: none; }
.foot__col span { color: var(--sc-ink-soft); }
.foot__col a:hover { color: var(--sc-accent); }

.foot__bar {
  margin-top: clamp(1.6rem, 3.4vh, 2.4rem);
  padding-top: clamp(1rem, 2vh, 1.4rem);
  border-top: 1px solid color-mix(in oklab, var(--sc-ink) 12%, transparent);
  display: flex; flex-wrap: wrap; gap: 0.5rem 1.6rem;
  justify-content: space-between; align-items: baseline;
}
.foot__bar p { margin: 0; font-size: 0.8rem; color: var(--sc-ink-soft); }
.foot__bar a { color: var(--sc-ink); font-weight: 600; text-decoration: none;
               border-bottom: 1px solid color-mix(in oklab, var(--sc-accent) 45%, transparent); }
.foot__bar a:hover { color: var(--sc-accent); border-bottom-color: var(--sc-accent); }

/* ==========================================================================
   THE INQUIRY FORM, THE SKIP LINK AND THE PROSE PAGES
   ========================================================================== */

/* screen-reader-only, for text that explains a link but must not be seen */
.vh {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* the skip link: the only thing on the page that is invisible until focused */
.skip {
  position: fixed; z-index: 200; top: 0.6rem; left: 50%;
  translate: -50% -160%;
  padding: 0.8rem 1.3rem;
  border-radius: var(--r-pill);
  background: var(--sc-accent); color: var(--sc-accent-ink);
  font-weight: 600; font-size: 0.86rem; text-decoration: none;
  box-shadow: var(--sc-e3);
  transition: translate .18s ease;
}
.skip:focus-visible { translate: -50% 0; }

/* ---------------------------------------------------------------- form -- */
.aanvraag {
  margin-top: var(--sc-6);
  display: grid; gap: var(--sc-4) var(--sc-5);
  grid-template-columns: 1fr;
}
@media (min-width: 700px) { .aanvraag { grid-template-columns: 1fr 1fr; } }
.fld { display: flex; flex-direction: column; gap: 0.42rem; min-width: 0; }
.fld--wide { grid-column: 1 / -1; }
.fld label { font-size: 0.82rem; font-weight: 600; color: var(--sc-ink); letter-spacing: -0.005em; }
.fld .req { color: var(--sc-accent); }
.fld .opt { font-weight: 500; color: var(--sc-ink-soft); }

.fld input, .fld select, .fld textarea {
  font: inherit; font-size: 0.95rem; color: var(--sc-ink);
  padding: 0.72rem 0.9rem;
  min-height: 44px;                       /* tap target, WCAG 2.5.8 with room */
  border-radius: 12px;
  border: 1px solid color-mix(in oklab, var(--sc-ink) 16%, transparent);
  background: rgb(255 255 255 / .74);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  width: 100%;
  transition: border-color .16s ease, box-shadow .16s ease;
}
.fld textarea { resize: vertical; min-height: 6.5rem; line-height: 1.5; }
.fld select { appearance: none; padding-right: 2.4rem;
  background-image: linear-gradient(45deg, transparent 50%, var(--sc-ink-soft) 50%),
                    linear-gradient(135deg, var(--sc-ink-soft) 50%, transparent 50%);
  background-position: right 1.05rem center, right 0.75rem center;
  background-size: 6px 6px, 6px 6px; background-repeat: no-repeat; }
.fld input::placeholder, .fld textarea::placeholder { color: color-mix(in oklab, var(--sc-ink-soft) 74%, transparent); }
.fld input:hover, .fld select:hover, .fld textarea:hover { border-color: color-mix(in oklab, var(--sc-ink) 28%, transparent); }
.fld input:focus-visible, .fld select:focus-visible, .fld textarea:focus-visible {
  outline: 2px solid var(--sc-accent); outline-offset: 2px; border-color: transparent;
}
.fld [aria-invalid="true"] { border-color: var(--sc-accent); box-shadow: 0 0 0 3px color-mix(in oklab, var(--sc-accent) 18%, transparent); }

.err  { margin: 0; font-size: 0.82rem; font-weight: 600; color: var(--sc-accent); }
/* Heette .hint en botste daarmee op de scrollhint onderaan het scherm, die
   position:fixed is. De helpteksten in het formulier zweefden daardoor als
   een ballon over de knopbalk. Eigen naam dus. */
.fld__hint { margin: 0.55rem 0 0; font-size: 0.8rem; color: var(--sc-ink-soft); }
.fld__hint--low, .hint--low { color: var(--sc-accent); }

.aanvraag button.act-cta { border: 0; cursor: pointer; font: inherit; }

/* ------------------------------------------------- prose and 404 pages -- */
.prose { max-width: 38rem; margin-top: clamp(2rem, 6vh, 3.5rem); }
.prose h2 {
  margin: clamp(2rem, 5vh, 3rem) 0 0.7rem;
  font-weight: 800; letter-spacing: -0.024em; font-size: 1.32rem; color: var(--sc-ink);
}
.prose h2:first-child { margin-top: 0; }
.prose p { margin: 0 0 0.9rem; color: var(--sc-ink-soft); line-height: 1.65; }
.prose a { color: var(--sc-ink); text-decoration: none;
           border-bottom: 1px solid color-mix(in oklab, var(--sc-accent) 45%, transparent); }
.prose a:hover { color: var(--sc-accent); border-bottom-color: var(--sc-accent); }

.err__links { list-style: none; margin: var(--sc-6) 0 0; padding: 0; display: grid; gap: 0.2rem; max-width: 26rem; }
.err__links a {
  display: block; padding: 0.85rem 0; min-height: 44px;
  border-top: 1px solid color-mix(in oklab, var(--sc-ink) 12%, transparent);
  color: var(--sc-ink); text-decoration: none; font-weight: 600;
}
.err__links a:hover { color: var(--sc-accent); }

/* tap targets in the footer: the links were 18px high, under the 24px floor */
.foot__col a { display: inline-block; padding-block: 0.42rem; min-height: 24px; }
.foot__bar a { display: inline-block; padding-block: 0.3rem; }

/* the wordmark is the "home" link and was 24x25 on a phone, right on the WCAG
   2.2 floor of 24x24. Padding gives it room without changing how it looks. */
.nav__mark { padding: 0.45rem 0.15rem; margin: -0.45rem -0.15rem; }
@media (max-width: 899px) { .nav__mark { padding-inline: 0.35rem; margin-inline: -0.35rem; } }

/* ==========================================================================
   MOBILE NAV, HERZIEN
   Gemeten probleem: in de capsule lag de knop bovenop de derde link. Op 360px
   begon "Stuur een appje" op x=196 terwijl "Verf" op x=213 stond, dus die zat
   eronder. De linkstrip moest daarom horizontaal scrollen, waardoor van de
   204px aan links maar 95 tot 189px zichtbaar was, afhankelijk van het toestel.

   Oplossing: de actie verlaat de capsule en wordt een balk onderin, binnen
   duimbereik. De capsule houdt het merkteken en de drie bestemmingen, die dan
   ruim passen: 35 + 71 + 83 + 45 plus tussenruimte is ongeveer 280px, en dat
   past ook op een toestel van 320px. Geen scrollstrip, geen verborgen menu,
   geen overlap, en niets dat JavaScript nodig heeft.
   ========================================================================== */

/* de balk bestaat alleen op een telefoon */
.mobar { display: none; }

@media (max-width: 899px) {
  /* de knop gaat uit de capsule */
  .nav .act-cta { display: none; }

  /* en de links krijgen de ruimte die daardoor vrijkomt */
  .nav {
    gap: 0.15rem;
    padding: 0.4rem 0.5rem 0.4rem 0.65rem;
    max-width: calc(100vw - 1.2rem);
  }
  .nav__list {
    /* niet krimpen: met flex-shrink en zichtbare overflow werd de capsule
       251px terwijl de inhoud er 262,7 wilde, en die 11,6px was precies
       "Verf" die buiten de rand stak. */
    flex: 0 0 auto;
    min-width: auto;
    overflow: visible;                 /* geen scrollstrip meer */
    -webkit-mask-image: none;          /* dus ook geen fade die iets verbergt */
    mask-image: none;
    scroll-snap-type: none;
    gap: 0.1rem;
  }
  .nav__list a { padding: 0.78rem 0.55rem; }

  /* de balk onderin */
  .mobar {
    display: block;
    position: fixed; z-index: var(--sc-z-chrome, 50);
    left: 0; right: 0; bottom: 0;
    padding: 0.6rem clamp(0.7rem, 3vw, 1.1rem);
    padding-bottom: calc(0.6rem + env(safe-area-inset-bottom, 0px));
    background: linear-gradient(180deg, rgb(255 255 255 / .62), rgb(255 255 255 / .88));
    -webkit-backdrop-filter: blur(22px) saturate(1.6);
    backdrop-filter: blur(22px) saturate(1.6);
    border-top: 1px solid rgb(255 255 255 / .9);
    box-shadow: 0 -10px 30px rgb(30 38 56 / .07);
  }
  .mobar .act-cta {
    display: flex; width: 100%;
    justify-content: center;
    min-height: 52px;                  /* ruim boven de 44px */
    padding-inline: 1rem;
    font-size: 0.95rem;
  }

  /* de voet van de pagina mag niet onder de balk verdwijnen */
  body { padding-bottom: 4.6rem; }

  /* de scrollhint stond precies waar de balk nu zit */
  .hint { bottom: calc(4.9rem + env(safe-area-inset-bottom, 0px)); }
}

/* Er zijn vier bestemmingen sinds Verf erbij kwam, en op 320px pasten
   die niet: de capsule knipt met overflow:hidden, dus "Contact" viel er
   letterlijk af. Letter en padding schalen nu mee met de breedte in plaats
   van op één maat te staan, zodat de vier altijd binnen de rand blijven.
   Gemeten: 320px vraagt 239px van de 255px die er is, 390px 256 van 325. */
@media (max-width: 899px) {
  .nav__list a {
    padding: 0.78rem clamp(0.22rem, 1.4vw, 0.4rem);
    font-size: clamp(0.72rem, 3.3vw, 0.86rem);
    letter-spacing: -0.015em;
  }
}

/* Alle tikdoelen op een telefoon naar 44px. Ze zaten op 31 tot 41, wat de
   WCAG 2.2-drempel van 24 haalt maar onder de maat blijft die een duim
   prettig vindt. De capsule kan het hebben nu de knop eruit is. */
@media (max-width: 899px) {
  .foot__col a { padding-block: 0.55rem; }
  .foot__bar a { padding-block: 0.42rem; }
  .foot__bar p { line-height: 1.9; }
}

/* De hero centreert zijn inhoud verticaal, maar op een telefoon is die inhoud
   hoger dan de sectie. Bij overloop verdeelt align-content:center het verschil
   naar beide kanten, waardoor de bovenmarge kleiner wordt dan opgegeven: op
   320px 67px in plaats van 80px. De capsule eindigt daar op 72px, dus de
   eyebrow schoof eronder. Vanaf de bovenkand uitlijnen maakt de ruimte
   voorspelbaar, en de sectie is op een telefoon toch al hoger dan het scherm. */
@media (max-width: 899px) {
  .vit { align-content: start; }
  /* De bovenmarge van de eerste sectie komt niet van .vit maar van
     .frame > section:first-child, en die selector is specifieker, dus een
     regel op .vit alleen deed niets. Hier wel: 6,6rem is ruim boven de
     capsule, die op een telefoon 61 tot 62px hoog is en op 72 tot 76px
     eindigt. */
  .frame > section:first-child { padding-top: clamp(6.6rem, 11vh, 8rem); }
}

/* Op een smal toestel past "WhatsApp 06 83 40 52 07" niet op een regel: op
   320px liep de aanvraagplaat 22px buiten beeld en dat lekte door naar het
   document, dus de pagina kon horizontaal schuiven. De regels mogen daar
   afbreken in plaats van te duwen. */
@media (max-width: 380px) {
  /* het is een grid van 7,5rem plus de waarde, en dat past niet naast elkaar
     op 320px: de plaat liep 18px buiten beeld en dat lekte door naar het
     document. Onder elkaar dus, met het label als kopregel. */
  .ask__lines a, .ask__lines span { grid-template-columns: 1fr; gap: 0.15rem; }
  .foot__col a, .foot__col span,
  .ask__lines span, .ask__lines a { overflow-wrap: anywhere; }
}

/* ==========================================================================
   DE CAPSULE OP EEN TELEFOON, EN HET INKLAPPEN
   ========================================================================== */

/* Een capsule die om zijn inhoud heen groeit, breekt zodra een lettertype
   iets breder uitvalt dan gemeten: dan steekt de laatste link eruit. Op een
   telefoon spant hij daarom van rand tot rand met een marge, en verdelen de
   drie links de ruimte. Dan kan er niets meer buiten vallen, ongeacht welk
   lettertype er aankomt. */
@media (max-width: 899px) {
  .nav {
    left: 0.6rem; right: 0.6rem; translate: none;
    max-width: none;
    justify-content: space-between;
    overflow: hidden;                 /* laatste vangnet: nooit buiten de rand */
  }
  .nav__list { flex: 1 1 auto; justify-content: space-around; }
  .nav__list a { padding: 0.78rem 0.4rem; }
}

/* ------------------------------------------------------------- ingeklapt --
   Alleen op een telefoon. Op een computer is er ruimte zat en is een balk die
   je eerst moet openvouwen puur verlies: daar blijft alles gewoon staan.

   De links verdwijnen met visibility, niet met het hidden-attribuut: zo zijn
   ze weg uit de tabvolgorde en kan CSS ze bij hover of focus weer terugzetten
   zonder dat markup en weergave elkaar tegenspreken. Het merkteken zelf blijft
   focusbaar, dus focus-within kan het geheel openen. */
@media (max-width: 899px) {
  .nav { transition: left .34s cubic-bezier(.22,.61,.36,1),
                     right .34s cubic-bezier(.22,.61,.36,1),
                     translate .34s cubic-bezier(.22,.61,.36,1),
                     padding .34s cubic-bezier(.22,.61,.36,1); }
  .nav__list, .nav .act-cta { transition: max-width .34s cubic-bezier(.22,.61,.36,1),
                                          opacity .22s ease,
                                          padding .34s cubic-bezier(.22,.61,.36,1); }

  /* ingeklapt hoort hij in het midden te staan, net als de open balk */
  .nav--in {
    left: 50%; right: auto; translate: -50% 0;
    padding: 0.4rem 0.5rem;
  }
  .nav--in .nav__list,
  .nav--in .act-cta {
    visibility: hidden; opacity: 0;
    max-width: 0; margin-inline: 0; padding-inline: 0; overflow: hidden;
    pointer-events: none;
  }
  .nav--in:hover .nav__list, .nav--in:hover .act-cta,
  .nav--in:focus-within .nav__list, .nav--in:focus-within .act-cta,
  .nav--in.nav--open .nav__list, .nav--in.nav--open .act-cta {
    visibility: visible; opacity: 1;
    max-width: 40rem; pointer-events: auto;
  }
  .nav--in:hover, .nav--in:focus-within, .nav--in.nav--open {
    left: 0.6rem; right: 0.6rem; translate: none;
    padding: 0.4rem 0.5rem 0.4rem 0.65rem;
  }

  .nav__mark[aria-expanded="false"] { cursor: pointer; }
}

@media (prefers-reduced-motion: reduce) {
  .nav, .nav__list, .nav .act-cta { transition: none; }
}

/* ==========================================================================
   FOTO'S DIE NAAR HUN PROJECT LINKEN
   Tien foto's op de startpagina zijn ook een project in de portfolio. Die zijn
   nu aanklikbaar. De andere foto's blijven gewoon foto's: een link die naar
   niets leidt is erger dan geen link.
   ========================================================================== */
.tolink { display: block; position: relative; color: inherit; text-decoration: none; }

/* het pijltje verschijnt pas bij aanwijzen of focus, zodat het de foto niet
   permanent van een pictogram voorziet */
.tolink__i {
  position: absolute; top: 0.7rem; right: 0.7rem; z-index: 3;
  display: grid; place-items: center;
  width: 2.2rem; height: 2.2rem;
  border-radius: 999px;
  background: var(--glass);
  -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-edge);
  box-shadow: var(--sc-e1), inset 0 1px 0 rgb(255 255 255 / .9);
  color: var(--sc-accent);
  opacity: 0; translate: 0 -4px;
  transition: opacity .2s ease, translate .2s ease;
  pointer-events: none;
}
.tolink__i svg { width: 0.95rem; height: 0.95rem; }
.tolink:hover .tolink__i,
.tolink:focus-visible .tolink__i { opacity: 1; translate: 0 0; }

/* op een touchscreen is er geen hover, dus daar staat het pijltje er gewoon */
@media (hover: none) {
  .tolink__i { opacity: 1; translate: 0 0; }
}

/* het bijschrift hoort bij dezelfde foto, dus dat kleurt mee */
figure:has(.tolink:hover) .lab__ttl,
figure:has(.tolink:focus-visible) .lab__ttl { color: var(--sc-accent); }

.tolink:focus-visible { outline: 2px solid var(--sc-accent); outline-offset: 3px; border-radius: var(--r-media); }

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

/* In de hal staat de foto absoluut in zijn lijst, dus een blok-anker eromheen
   had geen hoogte: 536x0. Het anker vult de lijst. */
.hal__frame .tolink { position: absolute; inset: 0; }

/* ==========================================================================
   ACT 8 · PRIKBORD — DE PIEK, en de bewegende scene van deze pagina
   De exploded view stond hier; die is er op verzoek van de klant uit en komt
   later in een betere versie terug. Zijn CSS blijft in het hoofdstuk "ACT 8
   ontleding" staan, ongebruikt, zodat er dan niets opnieuw hoeft.

   Elke kaart leest hetzelfde --sc-p uit maar met zijn eigen vertraging (--k):
   hij komt van onder aanzweven, draait zijn scheefstand in en zakt op zijn
   punaise. Dezelfde smoothstep als de wipes van act 5. Engine onaangeraakt.
   ========================================================================== */
.pinb { --pin-paper: #FFFEFB; }
/* Was een pin-act met een scene van 100svh. Nu een gewone sectie, dus de
   hoogte komt van de inhoud en de ruimte eromheen van padding. */
.pinb { padding-block: clamp(3.5rem, 10vh, 7rem); }
.pinb__in {
  width: min(100% - 2rem, 78rem);
  margin-inline: auto;
  display: flex; flex-direction: column;
  gap: clamp(1.6rem, 4vh, 3rem);
}
.pinb__head { max-width: 34rem; }
.pinb__head .d { margin: var(--sc-3) 0 0; }
.pinb__head .p { margin: var(--sc-4) 0 0; }

/* het bord zelf: geen plaatje, alleen een warm vlak met een fijne rasterlijn,
   zodat de kaarten ergens op hangen en niet in het niets zweven */
.pinb__board {
  position: relative;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(0.9rem, 2vw, 1.8rem);
  padding: clamp(1rem, 2.4vw, 2rem);
  border-radius: var(--r-media);
  background:
    linear-gradient(180deg, rgb(255 255 255 / .5), rgb(255 255 255 / .18)),
    repeating-linear-gradient(90deg, rgb(30 38 56 / .045) 0 1px, transparent 1px 22px),
    repeating-linear-gradient(0deg,  rgb(30 38 56 / .045) 0 1px, transparent 1px 22px);
  box-shadow: inset 0 0 0 1px rgb(30 38 56 / .07), var(--sc-e1);
}
/* Vier kaarten naast elkaar maakten het bord een lage strook met veel lucht
   eronder, en dit is de piek van de pagina. Twee bij twee dus: de kaarten
   worden bijna dubbel zo breed en het bord vult de gepinde scene. */
@media (min-width: 900px) {
  .pinb__in { width: min(100% - 2rem, 64rem); }
  .pinb__board { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(1.2rem, 2.6vw, 2.2rem); }
}

/* ---- de kaart ------------------------------------------------------------ */
.pin {
  position: relative; margin: 0;
  padding: 0.55rem 0.55rem 0.75rem;
  border-radius: 10px;
  background: var(--pin-paper);
  box-shadow: 0 1px 2px rgb(30 38 56 / .10), 0 12px 26px rgb(30 38 56 / .10);
  rotate: var(--rot, 0deg);
  transform-origin: 50% 0;
  transition: rotate .45s cubic-bezier(.22,1,.36,1),
              translate .45s cubic-bezier(.22,1,.36,1),
              box-shadow .3s ease;
}

/* Het dansen dat Casper vroeg. Een briefje aan één punaise zwaait om die
   punaise, dus de draaias staat bovenaan in het midden en er komt een klein
   zetje omhoog bij. De uitslag is een halve graad groter dan de rust­stand en
   loopt de andere kant op, zodat elke kaart een eigen richting houdt en het
   bord niet als geheel kantelt. */
@media (hover: hover) {
  .pin:hover {
    rotate: calc(var(--rot, 0deg) * -1.35);
    translate: 0 -3px;
    box-shadow: 0 2px 3px rgb(30 38 56 / .12), 0 18px 34px rgb(30 38 56 / .14);
  }
}
@media (prefers-reduced-motion: reduce) {
  .pin { transition: none; }
  .pin:hover { rotate: var(--rot, 0deg); translate: none; }
}

.pin:nth-child(1) { --rot: -2.4deg; }
.pin:nth-child(2) { --rot:  1.9deg; margin-top: clamp(0.5rem, 1.6vh, 1.4rem); }
.pin:nth-child(3) { --rot: -1.3deg; }
.pin:nth-child(4) { --rot:  2.3deg; margin-top: clamp(0.5rem, 1.6vh, 1.4rem); }

/* De punaise. Vier kaarten, drie merkkleuren en dan weer van voren af aan.

   Dit was een plat gekleurd stipje en dat las als een bolletje, niet als iets
   dat door het papier heen zit. Een punaise heeft drie dingen die je herkent:
   een bolle kop met de lichtinval linksboven, een metalen naald die er onder
   schuin uitsteekt, en een schaduw die daar naast valt in plaats van er recht
   onder. Twee pseudo-elementen, geen extra markup, geen svg.

   ::before is de naald plus de slagschaduw op het papier, ::after de kop.
   De naald staat opzettelijk iets rechts en gedraaid, want een punaise gaat er
   nooit precies loodrecht in. */
.pin::before,
.pin::after { content: ""; position: absolute; pointer-events: none; }

/* Een punaise van voren is niet te herkennen aan zijn naald, want die zit in
   het papier. Twee pogingen liepen daarop stuk: een bol met een naald eronder
   was gewoon een bol, want de naald viel achter de kop weg, en hem eronderuit
   laten steken maakte er een bol met een sprietje van.

   Wat een punaise wél herkenbaar maakt is de omtrek: een brede platte kraag om
   op te duwen, met daarbovenop een kleinere bolle knop. Dat is de vorm die
   hier nu staat.

   ::before is de kraag, ::after de knop. */

/* de kraag: breed, plat, en een tint donkerder dan de knop erboven */
.pin::before {
  z-index: 2;
  top: -0.33rem; left: 50%; translate: -50% 0;
  width: 1.46rem; height: 0.5rem; border-radius: 50%;
  background: linear-gradient(180deg,
    color-mix(in oklab, var(--pin-c, var(--bar-blue)) 82%, #f7f9fc) 0 34%,
    color-mix(in oklab, var(--pin-c, var(--bar-blue)) 74%, #0b1018) 100%);
  box-shadow: inset 0 0.05rem 0 rgb(255 255 255 / .5),
              0 0.14rem 0.26rem rgb(30 38 56 / .38);
}

/* de knop erbovenop, met de lichtinval linksboven */
.pin::after {
  z-index: 3;
  top: -0.68rem; left: 50%; translate: -50% 0;
  width: 0.92rem; height: 0.68rem;
  border-radius: 50% 50% 42% 42%;
  background:
    radial-gradient(ellipse 46% 52% at 32% 22%, rgb(255 255 255 / .9) 0 14%,
                                                rgb(255 255 255 / .28) 46%,
                                                rgb(255 255 255 / 0) 100%),
    linear-gradient(180deg,
      color-mix(in oklab, var(--pin-c, var(--bar-blue)) 88%, #ffffff) 0 30%,
      var(--pin-c, var(--bar-blue)) 72%,
      color-mix(in oklab, var(--pin-c, var(--bar-blue)) 76%, #0b1018) 100%);
  box-shadow: inset 0 0 0 1px rgb(10 14 22 / .1);
}
.pin:nth-child(2) { --pin-c: var(--bar-yellow); }
.pin:nth-child(3) { --pin-c: var(--bar-pink); }

.pin__f {
  border-radius: 6px; overflow: hidden;
  background: #fff;
  box-shadow: inset 0 0 0 1px rgb(30 38 56 / .08);
}
/* contain, niet cover: het zijn lijntekeningen op wit, dus bijsnijden zou de
   ene aanzichttekening halveren en de witte rand valt toch niet op. */
.pin__f img { display: block; width: 100%; height: clamp(7rem, 19vh, 13.5rem); object-fit: contain; }
.pin__b { display: flex; flex-direction: column; gap: 0.12rem; padding: 0.6rem 0.25rem 0; }
.pin__t { font-weight: 700; font-size: 0.92rem; letter-spacing: -0.015em; color: var(--sc-ink); }
.pin__m {
  font-size: 0.66rem; font-weight: 600; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--creps-label-dim);
}

/* het briefje: zelfde papier, maar geel en zonder foto */
.pin--note {
  display: flex; align-items: center;
  background: color-mix(in oklab, var(--bar-yellow) 22%, var(--pin-paper));
}
.pin__note {
  margin: 0; padding: clamp(0.6rem, 1.6vw, 1.2rem);
  font-size: clamp(0.98rem, 1.5vw, 1.15rem); line-height: 1.5; color: var(--sc-ink);
}

@media (prefers-reduced-motion: reduce) {
}

/* ---------------------------------------------------- anker op producten --
   De startpagina linkt nu per stuk door naar het product zelf, dus elk item
   moet een anker zijn dat niet onder de vaste capsule landt. De ring erbij is
   er voor het geval iemand de link deelt: dan zie je meteen welk van de zes
   bedoeld werd, in plaats van dat de pagina op een willekeurige hoogte staat. */
.grid > .item { scroll-margin-top: 6rem; }
.grid > .item:target .item__f {
  box-shadow: 0 0 0 3px var(--sc-accent), var(--sc-e3);
}


/* De brede kaart onderin act 4 is bijna vier keer zo breed als hoog, terwijl
   de foto 4:3 is. Met een gecentreerde uitsnede zie je van die foto de band
   tussen 30 en 70 procent, en de letters staan er lager in: ze lopen van 45
   tot 79 procent. Daardoor werden de voeten van "tekkoo" precies afgesneden.

   Het venster schuift dus omlaag. 69 procent zet het midden van de band op 62
   procent van de foto, en dat is het midden van de letters. Gerekend, niet
   geschat: bij een kader van 1072 bij 320 wordt de foto 804 hoog, dus er is
   484 pixels te schuiven. */
.rec__wide .fig__f img { object-position: 50% 69%; }

/* De tekst bij het stille object is nu woordelijk die van Casper: kop, alinea,
   kenmerkenregel, slotzin. Zelfde opbouw en zelfde aflopende gewichten als bij
   een project in het portfolio, zodat het één stem blijft. */
.still__kop {
  margin: var(--sc-5) 0 0;
  font-weight: 700; font-size: 1.1rem; letter-spacing: -0.015em; color: var(--sc-ink);
}
.still__ken {
  margin: var(--sc-4) 0 0;
  font-size: 0.72rem; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--creps-label-dim);
}
.still__slot { margin: 0.7rem 0 0; font-style: italic; color: var(--sc-ink-soft); }

/* ══ LAADSCHERM ══════════════════════════════════════════════════════════
   Staat bewust niet hier maar in de head van elke pagina, tussen boot:begin
   en boot:eind. Een laadscherm dat wacht op dit bestand van 88 kB is er pas
   als de pagina toch al staat. De uitleg staat daar. */
