/* vslabs.app. Every colour, size and family is a custom property from tokens.css; nothing here
   types a hex or a font name outside @font-face. The mat is anchored to the column's left edge,
   the column is a whole number of mat cells, and only keyboard focus lights.
   Brand book pages 10 to 18 are the spec; a comment names the page where a rule comes from. */

/* ---- fonts (self-hosted, OFL). Paths are relative: this file ships under /assets/<version>/ ---- */
@font-face { font-family: "Archivo"; font-weight: 400; font-style: normal; font-display: swap; src: url(fonts/Archivo-Regular.woff2) format("woff2"); }
@font-face { font-family: "Archivo"; font-weight: 500; font-style: normal; font-display: swap; src: url(fonts/Archivo-Medium.woff2) format("woff2"); }
@font-face { font-family: "Archivo"; font-weight: 600; font-style: normal; font-display: swap; src: url(fonts/Archivo-SemiBold.woff2) format("woff2"); }
@font-face { font-family: "Archivo"; font-weight: 700; font-style: normal; font-display: swap; src: url(fonts/Archivo-Bold.woff2) format("woff2"); }
@font-face { font-family: "JetBrains Mono"; font-weight: 400; font-style: normal; font-display: swap; src: url(fonts/JetBrainsMono-Regular.woff2) format("woff2"); }
@font-face { font-family: "JetBrains Mono"; font-weight: 500; font-style: normal; font-display: swap; src: url(fonts/JetBrainsMono-Medium.woff2) format("woff2"); }

/* ---- the three cuts: 390 → 768 → 1280. Never fluid (p.12). The numbers are the breakpoint-768
   and breakpoint-1280 tokens; media queries cannot read a custom property, so lint:site checks. ---- */
:root {
  --col: var(--size-column-390);
  --pad: var(--space-6);
  --display-xl: var(--display-xl-390);
  --display-l: var(--display-l-390);
  --display-m: var(--display-m-390);
  --cells-0: 8; --cells-1: 8; --cells-2: 8; --cells-3: 8;
}
@media (min-width: 768px) {
  :root {
    --col: var(--size-column-768);
    --pad: var(--space-8);
    --display-xl: var(--display-xl-768);
    --display-l: var(--display-l-768);
    --display-m: var(--display-m-768);
    --cells-0: 12; --cells-1: 11; --cells-2: 10; --cells-3: 9;
  }
}
@media (min-width: 1280px) {
  :root {
    --col: var(--size-column-1280);
    --display-xl: var(--display-xl-1280);
    --display-l: var(--display-l-1280);
    --display-m: var(--display-m-1280);
    --cells-0: 16; --cells-1: 14; --cells-2: 12; --cells-3: 10;
  }
}

/* ---- ground and mat ------------------------------------------------------------------------ */
*, *::before, *::after { box-sizing: border-box; }
html { background: var(--lab); overflow-x: clip; -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  min-height: 100vh;
  color: var(--ink);
  font-family: var(--type-body-family);
  font-size: var(--type-body-size);
  line-height: var(--type-body-leading);
  font-weight: var(--type-body-weight);
  background-color: var(--lab);
  background-image:
    linear-gradient(var(--mat-line) var(--size-edge), transparent var(--size-edge)),
    linear-gradient(90deg, var(--mat-line) var(--size-edge), transparent var(--size-edge));
  background-size: var(--mat) var(--mat);
  /* 50% resolves against (area − tile) = W/2 − 18px; half a tile back puts a line on the column's
     left edge, (W − col)/2. The mat holds still: it is the surface, not an effect. */
  background-position: calc(50% - var(--col) / 2 + var(--mat) / 2) 0;
}
body.embed-body { background-image: none; }

/* ---- type ---------------------------------------------------------------------------------- */
.display-xl, .display-l, .display-m, .lede, .caption, .body, .ui { font-family: var(--type-body-family); }
.display-xl { font-size: var(--display-xl); line-height: var(--type-display-xl-leading); font-weight: var(--type-display-xl-weight); letter-spacing: var(--type-display-xl-tracking); margin: 0; }
.display-l { font-size: var(--display-l); line-height: var(--type-display-l-leading); font-weight: var(--type-display-l-weight); letter-spacing: var(--type-display-l-tracking); margin: 0; }
.display-m { font-size: var(--display-m); line-height: var(--type-display-m-leading); font-weight: var(--type-display-m-weight); letter-spacing: var(--type-display-m-tracking); margin: 0; }
.caption { font-size: var(--type-caption-size); line-height: var(--type-caption-leading); font-weight: var(--type-caption-weight); }
.lede { font-size: var(--type-lede-size); line-height: var(--type-lede-leading); font-weight: var(--type-lede-weight); color: var(--ink-muted); margin: 0; }
.body { font-size: var(--type-body-size); line-height: var(--type-body-leading); font-weight: var(--type-body-weight); }
.ui { font-size: var(--type-ui-size); line-height: var(--type-ui-leading); font-weight: var(--type-ui-weight); }
.value, .micro, .micro-l, .note, .index, .code { font-family: var(--type-micro-family); }
.value { font-size: var(--type-value-size); line-height: var(--type-value-leading); font-weight: 400; }
.micro { font-size: var(--type-micro-size); line-height: var(--type-micro-leading); font-weight: var(--type-micro-weight); letter-spacing: var(--type-micro-tracking); text-transform: uppercase; color: var(--ink-caption); }
.micro-l { font-size: var(--type-micro-l-size); line-height: var(--type-micro-l-leading); font-weight: var(--type-micro-l-weight); letter-spacing: var(--type-micro-l-tracking); text-transform: uppercase; }
.note { font-size: var(--type-note-size); line-height: var(--type-note-leading); font-weight: var(--type-note-weight); letter-spacing: var(--type-note-tracking); color: var(--ink-caption); margin: 0; }
.index { font-size: var(--type-index-size); line-height: var(--type-index-leading); font-weight: var(--type-index-weight); letter-spacing: var(--type-index-tracking); text-transform: uppercase; color: var(--ink-caption); }
p { margin: 0; }
.prose { max-width: var(--size-measure); }
.prose p + p, .prose p + ul, .prose ul + p, .prose h2, .prose h3 { margin-top: var(--space-4); }
.prose p + .note { margin-top: var(--space-2); } /* a measured number in prose gets its note under the paragraph (p.16) */
.prose ul { padding-left: var(--space-4); margin: 0; }
.prose strong, .code b { font-weight: 500; }

/* ---- layout: one column, whole cells (p.14) ------------------------------------------------ */
.col { width: var(--col); margin-inline: auto; }
main { display: block; padding: var(--space-8) 0 var(--space-8); outline: none; } /* page head: space-8 above; rule: space-8 above the footer rule */
main > * + * { margin-top: var(--space-6); } /* sections are gapped by space-6 */
.section-label { display: block; color: var(--ink-caption); margin: 0 0 var(--space-4); }
.section-head { display: flex; flex-direction: column; gap: var(--space-4); margin-bottom: var(--space-6); } /* page head: space-6 below */
.page-label { display: block; color: var(--ink-caption); }
/* text a frame already shows on screen, kept for assistive tech and search */
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* ---- header: 72px row, rule beneath, scrolls with the page (p.14) -------------------------- */
.site-header { border-bottom: var(--size-edge) solid var(--ink); }
.header-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); height: var(--space-8); }
.wordmark { color: var(--ink); text-decoration: none; display: inline-flex; align-items: center; }
.wordmark i { font-style: normal; color: var(--lit-ink); }
.nav { position: relative; }
.nav ul { list-style: none; margin: 0; padding: 0; display: flex; align-items: center; gap: var(--space-6); }
.nav a { color: var(--ink-caption); text-decoration: none; display: inline-flex; align-items: center; height: var(--size-chip); white-space: nowrap; transition: color var(--motion-state) ease-out, text-decoration-color var(--motion-state) ease-out; }
.nav a.chip { color: var(--ink); }
@media (hover: hover) {
  .nav a:not(.chip):hover { color: var(--ink); text-decoration: underline var(--size-edge) var(--ink); text-underline-offset: var(--space-1); }
}
.nav-tube {
  position: absolute; left: 0; top: 100%; width: 0; height: var(--size-tube-h);
  border-radius: var(--size-tube-h); background: var(--lit); box-shadow: var(--shadow-tube-glow); pointer-events: none;
  transition: transform var(--motion-tube) ease-in-out, width var(--motion-tube) ease-in-out;
}
.nav-tube[hidden] { display: none; }
@media (max-width: 767px) {
  /* wordmark, then the nav on its own row: three cells, 108px */
  .header-row { flex-wrap: wrap; height: auto; gap: 0; }
  .header-row .wordmark { height: var(--space-8); }
  .nav { width: 100%; height: var(--space-6); display: flex; align-items: center; }
  .nav ul { gap: var(--space-2); }
}

/* ---- footer: rule above, note left, wordmark right (p.14) ---------------------------------- */
.site-footer { border-top: var(--size-edge) solid var(--ink); }
.footer-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); min-height: var(--space-8); padding: var(--space-3) 0; }
.footer-notes { display: flex; flex-direction: column; }
.footer-row .note a { color: var(--ink-caption); }
@media (max-width: 767px) {
  .footer-row { flex-direction: column; align-items: flex-start; }
}

/* ---- links: ink, underlined; never green at rest (p.13) ------------------------------------ */
a {
  color: var(--ink);
  text-decoration: underline var(--size-edge) var(--ink-caption);
  text-underline-offset: var(--space-1);
  transition: text-decoration-color var(--motion-state) ease-out, text-decoration-thickness var(--motion-state) ease-out;
}
a:hover { text-decoration: underline var(--size-edge-focus) var(--ink); }
:where(p, li, .scene-links) a:visited { color: var(--settled-ink); text-decoration-color: var(--settled-ink); } /* visited is settled: done, behind us */
a:focus-visible { background: var(--lit); border-radius: var(--radius-none); text-decoration: underline var(--size-edge-focus) var(--lit-ink); transition: none; }

/* ---- glass controls (p.10, p.13) ------------------------------------------------------------ */
.button, .chip, .card {
  color: var(--ink);
  background: var(--glass-fill);
  border: var(--size-edge) solid var(--glass-edge);
  box-shadow: var(--shadow-glass);
  text-decoration: none;
  transition: background-color var(--motion-state) ease-out, border-color var(--motion-state) ease-out, box-shadow var(--motion-state) ease-out;
}
.button {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  height: var(--size-button); padding: 0 var(--space-4);
  border-radius: var(--radius-pill);
  font-family: var(--type-ui-family); font-size: var(--type-ui-size); font-weight: var(--type-ui-weight); line-height: 1;
  cursor: pointer; white-space: nowrap;
}
.button.primary { border-color: var(--ink); }
.button.l { height: var(--size-button-l); padding: 0 var(--space-6); }
.chip {
  display: inline-flex; align-items: center; gap: var(--space-1);
  height: var(--size-chip); padding: 0 var(--space-2);
  border-radius: var(--radius-pill); border-color: var(--ink);
  font-family: var(--type-micro-family); font-size: var(--type-micro-size); font-weight: var(--type-micro-weight); letter-spacing: var(--type-micro-tracking); line-height: 1;
  text-transform: uppercase; white-space: nowrap; cursor: pointer;
}
.chip.current { cursor: default; }
button.chip, button.button { font: inherit; }
button.chip { font-family: var(--type-micro-family); font-size: var(--type-micro-size); font-weight: var(--type-micro-weight); letter-spacing: var(--type-micro-tracking); }
button.button { font-family: var(--type-ui-family); font-size: var(--type-ui-size); font-weight: var(--type-ui-weight); }
/* The arrow on a primary or a chip carries the hover: it moves space-1 right over 400ms and returns. */
.arrow { display: inline-block; transition: transform var(--motion-state) ease-out; }
@media (hover: hover) {
  .button:hover, .chip[href]:hover, button.chip:not(.current):hover, .card:hover { background: var(--glass-fill-dense); border-color: var(--ink); }
  .button.primary:hover .arrow, .chip:hover .arrow { transform: translateX(var(--space-1)); }
}
/* pressed: the inner highlight goes, cut in; it eases back over 400ms on release */
.button:active, .chip:active, .card:active { box-shadow: none; transition: none; }
.button[aria-pressed="true"], .chip[aria-pressed="true"] { background: var(--glass-fill-dense); box-shadow: none; }
/* disabled: label ink-faint, an ink edge goes ink-faint, highlight off, over 600ms, and it stays */
.button:disabled, .chip:disabled { color: var(--ink-faint); box-shadow: none; cursor: default; transition: color var(--motion-settle) ease-out, border-color var(--motion-settle) ease-out, box-shadow var(--motion-settle) ease-out; }
.button.primary:disabled, .chip:disabled { border-color: var(--ink-faint); }

/* ---- focus: edge at once, then halo, then fill (buttons and chips only) (p.10) -------------- */
:focus-visible {
  outline: var(--size-edge-focus) solid var(--lit-ink);
  outline-offset: 0;
  box-shadow: var(--shadow-lit-bloom);
  transition: box-shadow 200ms ease-out, background-color var(--motion-state) ease-out 100ms, border-color var(--motion-state) ease-out 100ms;
}
.button:focus-visible, .chip:focus-visible, .card:focus-visible { background: var(--lit); border-color: var(--lit-edge); color: var(--ink); }
.stage:focus-visible, .code:focus-visible, .capture-frame:focus-visible, .wordmark:focus-visible, .nav a:not(.chip):focus-visible { background: inherit; }
.nav a:not(.chip):focus-visible { background: var(--lit); color: var(--ink); }
.skip { position: absolute; top: var(--space-2); left: var(--space-2); z-index: 10; transform: translateY(-300%); }
.skip:focus-visible { transform: none; }

/* ---- player -------------------------------------------------------------------------------- */
.player { margin: 0; position: relative; }
.stage { border: var(--size-edge) solid var(--glass-edge); border-radius: var(--radius-frame); overflow: hidden; background: var(--lab); box-shadow: var(--shadow-glass); line-height: 0; cursor: pointer; }
.player[data-static] .stage { cursor: default; }
.stage svg { display: block; width: 100%; height: auto; }
/* Below 768 a scene runs edge to edge: the post frame at the viewport's width, not the column's,
   so a 4:5 frame reads at 390px instead of 288px. Its controls stay in the column. */
@media (max-width: 767px) {
  .player:not(.embed) .stage { margin-inline: calc((var(--col) - 100vw) / 2); border-inline: 0; border-radius: var(--radius-none); }
}
/* the still: start frame, or the end frame under reduced motion (p.18); the script draws over it */
.stage .frame-end { display: none; }
.player-caption { display: flex; gap: var(--space-3); align-items: baseline; margin: var(--space-4) 0 0; color: var(--ink-muted); }
.step-index { font-family: var(--type-value-family); font-weight: 500; color: var(--lit-ink); }
/* From 768 the frame's own caption card is legible, so this line is kept for screen readers only
   (it is the player's live region). Below 768 the frame is 288px and the line shows. */
@media (min-width: 768px) {
  .player-caption { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
}
/* scene controls are chips in a row below the frame, outside it (p.11, p.13, p.14) */
.controls { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-top: var(--space-4); }
.controls .spacer { flex: 1; }
.readout { color: var(--ink-caption); margin-inline: var(--space-2); }
/* below 768 the caption line above carries the step number, so the readout would say it twice */
@media (max-width: 767px) { .controls .readout { display: none; } }
.player.embed .stage { border: 0; border-radius: var(--radius-none); box-shadow: none; }
/* The post frame's footer already carries the wordmark. The chip sits in the frame's top margin, centred
   on that band (36 of 1350 units down), its right edge on the frame's inner edge (72 of 1080 in). The
   bottom band holds the footer's last line, which a 27px chip would touch at 390; the top one is clear
   of the header row and the registration mark at every width. */
.embed-brand { position: absolute; right: calc(100% * 72 / 1080); top: calc(100% * 36 / 1350); transform: translateY(-50%); display: flex; }

/* ---- landing (SITE-BRIEF, "The landing page") ------------------------------------------------ */
/* Each section opens like a page of the brand book: a micro label row with the section's place,
   on a 1px ink rule. Sections sit two space-8 apart. */
.band { margin-top: calc(var(--space-8) * 2); }
.band-rule { display: flex; justify-content: space-between; gap: var(--space-4); margin: 0 0 var(--space-6); padding-bottom: var(--space-2); border-bottom: var(--size-edge) solid var(--ink); }
.band-rule > :last-child { white-space: nowrap; }
/* At 1280 a section's frame sits at 15 cells beside its copy (14, the measure), the sides alternating
   down the page (frame-first puts it on the left); below 1280 the copy comes first and the frame
   follows at its usual width. The copy is first in the markup either way. */
.band-split { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-6); }
.band-split > * { min-width: 0; } /* a row that scrolls sideways must not widen its column */
@media (min-width: 1280px) {
  .band-split { grid-template-columns: calc(var(--mat) * 14) calc(var(--mat) * 15); column-gap: var(--mat); align-items: start; }
  .band-split.frame-first { grid-template-columns: calc(var(--mat) * 15) calc(var(--mat) * 14); }
  .band-split.frame-first > .band-frame { grid-column: 1; grid-row: 1; }
  .band-split.frame-first > .band-copy { grid-column: 2; grid-row: 1; }
}
.band-copy > * + * { margin-top: var(--space-4); }
.band-copy > .poster-row { margin-top: var(--space-6); }
.band-title { margin-bottom: var(--space-4); }
.band > .prose + * { margin-top: var(--space-6); }

/* hero: the page head beside the ferrofluid display (the device on the right at 1280, under the
   copy below it). The hero fills the first viewport at 1280. */
.hero { display: grid; gap: var(--space-6); align-items: center; }
@media (min-width: 1280px) {
  .hero { grid-template-columns: calc(var(--mat) * 14) calc(var(--mat) * 15); column-gap: var(--mat); min-height: calc(100svh - var(--space-8) * 2); }
}
.hero-copy { display: flex; flex-direction: column; gap: var(--space-4); }
.hero-copy .band-rule { margin-bottom: var(--space-2); }
.hero-actions { margin-top: var(--space-2); }

/* The display: a white panel, a round window lit from behind (the wall-light, the one gradient the
   site allows), knobs at the lower left, keys and the status light at the lower right. Sized to the
   viewport so it is whole in the first screen; a cell wider than the column below 768. */
.ferro { --ferro-w: min(calc(var(--col) + var(--space-6) * 2), 100vw); width: var(--ferro-w); aspect-ratio: 1; margin-inline: calc((100% - var(--ferro-w)) / 2); }
@media (min-width: 768px) { .ferro { --ferro-w: min(var(--col), calc(100svh - var(--space-8) * 3)); } }
@media (min-width: 1280px) { .ferro { --ferro-w: min(calc(var(--mat) * 15), calc(100svh - var(--space-8) * 2 - var(--space-6))); margin-inline: 0; justify-self: end; } }
.ferro-panel {
  position: relative; width: 100%; height: 100%;
  border: var(--size-edge) solid var(--glass-edge); border-radius: var(--radius-frame); box-shadow: var(--shadow-glass);
  background: radial-gradient(circle at 50% 44%, var(--glass-white) 30%, transparent 62%), linear-gradient(var(--glass-white), var(--glass-white)), var(--lab);
}
.ferro-id { position: absolute; top: 5%; right: 5.5%; margin: 0; }
.ferro-window {
  position: absolute; left: 50%; top: 44%; width: 60%; aspect-ratio: 1; translate: -50% -50%;
  border-radius: 50%; overflow: hidden; border: var(--size-edge) solid var(--glass-edge);
  background: radial-gradient(circle, var(--glass-white) 15%, transparent 95%), linear-gradient(var(--glass-white), var(--glass-white)), var(--glass-fill);
}
.ferro-still, .ferro-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.ferro-still path { fill: var(--ink); }
.ferro-canvas { visibility: hidden; }
.ferro.is-live .ferro-canvas { visibility: visible; }
.ferro.is-live .ferro-still { display: none; }
.ferro-knobs { position: absolute; left: 5.5%; bottom: 6%; display: flex; flex-direction: column; gap: var(--space-2); }
.knob { --v: 55; position: relative; display: flex; align-items: center; gap: var(--space-2); }
.knob + .knob { --v: 40; }
.knob-face { position: relative; width: var(--size-chip); aspect-ratio: 1; border-radius: 50%; background: var(--glass-fill); border: var(--size-edge) solid var(--glass-edge); box-shadow: var(--shadow-glass); }
/* the indicator turns through 270°, from −135° at 0 to +135° at 100 */
.knob-face::after {
  content: ""; position: absolute; left: 50%; top: 12%; width: var(--size-edge-focus); height: 32%; margin-left: calc(var(--size-edge-focus) / -2);
  border-radius: var(--radius-pill); background: var(--ink); transform-origin: 50% 118.75%; transform: rotate(calc(-135deg + var(--v) * 2.7deg));
}
.knob input { position: absolute; left: 0; top: 0; width: var(--size-chip); height: var(--size-chip); margin: 0; opacity: 0; cursor: ew-resize; }
.knob input:disabled { cursor: default; }
.knob input:focus-visible + .knob-face { outline: var(--size-edge-focus) solid var(--lit-ink); box-shadow: var(--shadow-lit-bloom); }
.knob input:disabled + .knob-face::after { background: var(--ink-faint); }
.ferro-mark { position: absolute; left: 50%; bottom: 5%; translate: -50% 0; margin: 0; }
.ferro-keys { position: absolute; right: 5.5%; bottom: 7%; display: flex; align-items: center; gap: var(--space-2); }
.ferro-keys .key { width: var(--space-3); aspect-ratio: 1; border-radius: 50%; background: var(--glass-fill); border: var(--size-edge) solid var(--glass-edge); box-shadow: var(--shadow-glass); }
.ferro-keys .led { width: calc(var(--space-1) * 1.5); aspect-ratio: 1; border-radius: 50%; margin-left: var(--space-1); background: var(--glass-edge); }
.ferro.is-live .led { background: var(--lit); box-shadow: var(--shadow-lit-bloom); } /* lit: the field is on */

/* story: the scroll is the playhead. Without script, or under reduced motion, it is a frame and a
   list of steps; with both, the frame pins and each step gets its own stretch of scroll. */
.story-head { display: flex; flex-direction: column; gap: var(--space-4); }
.story-head .band-rule { margin-bottom: var(--space-2); }
.story-track { margin-top: var(--space-6); }
.story-steps { list-style: none; margin: var(--space-6) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-4); }
.story-step { display: grid; grid-template-columns: 3ch 1fr; gap: var(--space-3); align-items: baseline; }
.story-step .step-no { font-size: var(--type-caption-size); }
.story-after { margin-top: var(--space-6); }
/* The frame is as large as the viewport allows and never wider than its place: edge to edge below
   768, the column at 768, 15 cells beside the captions at 1280. Below 1280 the captions run no wider
   than the frame, so the pinned frame covers them as they scroll up behind it. */
.story { --story-frame-w: min(100vw, calc((100svh - var(--mat) * 6) * 0.8)); }
@media (min-width: 768px) { .story { --story-frame-w: min(var(--col), calc((100svh - var(--mat) * 6) * 0.8)); } }
.story .story-pin .stage { width: var(--story-frame-w); margin-inline: calc((100% - var(--story-frame-w)) / 2); }
.story-steps { max-width: var(--story-frame-w); margin-inline: auto; }
.story.is-scrubbing .story-pin { position: sticky; top: 0; z-index: 1; }
.story.is-scrubbing .story-step { min-height: 60svh; color: var(--ink-caption); transition: color var(--motion-state) ease-out; }
.story.is-scrubbing .story-step[aria-current="step"] { color: var(--ink); }
/* Below 1280 the frame covers the captions as they scroll, so the current one rides in the pin under
   the frame and the list becomes the stretch of scroll (still read by assistive tech). */
.story-now { display: none; }
@media (max-width: 1279px) {
  .story.is-scrubbing .story-now { display: grid; grid-template-columns: 3ch 1fr; gap: var(--space-3); align-items: baseline; max-width: var(--story-frame-w); min-height: calc(var(--mat) * 5); margin: var(--space-4) auto 0; padding-bottom: var(--space-4); }
  .story.is-scrubbing .story-now .step-no { font-size: var(--type-caption-size); }
  .story.is-scrubbing .story-steps { opacity: 0; pointer-events: none; }
}
@media (min-width: 1280px) {
  /* the head and the captions on the left, 14 cells, the measure; the frame on the right, 15 cells */
  .story {
    --story-frame-w: min(calc(var(--mat) * 15), calc((100svh - var(--space-6) * 2) * 0.8));
    display: grid; grid-template-columns: calc(var(--mat) * 14) calc(var(--mat) * 15); column-gap: var(--mat);
    grid-template-areas: "head pin" "steps pin" "after after"; align-items: start;
  }
  .story-track { display: contents; }
  .story-head { grid-area: head; }
  .story-pin { grid-area: pin; }
  .story-steps { grid-area: steps; max-width: none; margin-inline: 0; }
  .story-after { grid-area: after; }
  .story.is-scrubbing .story-pin { top: calc((100svh - var(--story-frame-w) * 1.25) / 2); }
  .story.is-scrubbing .story-step { min-height: 80svh; }
}

/* scenes: the next scene in the player, then every poster in a row that scrolls sideways */
.poster-row { list-style: none; margin: var(--space-6) 0 0; padding: 0 0 var(--space-3); display: grid; grid-auto-flow: column; grid-auto-columns: calc(var(--mat) * 6); gap: var(--space-3); overflow-x: auto; scroll-snap-type: x mandatory; }
@media (min-width: 768px) { .poster-row { grid-auto-columns: calc(var(--mat) * 7); } }
.poster-row > li { scroll-snap-align: start; }
.card.poster { padding: var(--space-2); }
.note-row { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); }
@media (min-width: 1280px) { .note-row { grid-template-columns: repeat(3, 1fr); } }

/* the lab record: what was built, each with one measured number; the stack; the credentials */
.builds { list-style: none; margin: 0; padding: 0; }
.build { display: grid; gap: var(--space-4); padding: var(--space-6) 0; border-top: var(--size-edge) solid var(--glass-edge); }
.build:last-child { border-bottom: var(--size-edge) solid var(--glass-edge); }
.build-title { margin: 0 0 var(--space-2); font-size: var(--type-lede-size); line-height: var(--type-lede-leading); font-weight: var(--type-display-m-weight); letter-spacing: var(--type-display-m-tracking); }
.build-text .body { max-width: var(--size-measure); }
.build-stack { margin-top: var(--space-3); }
.build .metric { display: flex; flex-direction: column; grid-row: auto; max-width: calc(var(--mat) * 8); }
.build .metric .index { align-self: auto; }
.build-status { align-self: center; }
@media (min-width: 1280px) { .build { grid-template-columns: calc(var(--mat) * 20) 1fr; column-gap: var(--mat); align-items: start; } }
.record-cols { display: grid; gap: var(--space-8); margin-top: var(--space-8); }
@media (min-width: 1280px) { .record-cols { grid-template-columns: 1fr 1fr; gap: var(--mat); } }
.stack { margin: 0; }
.stack-row { display: grid; gap: var(--space-1); padding: var(--space-3) 0; border-top: var(--size-edge) solid var(--glass-edge); }
.stack-row dd { margin: 0; }
.creds { list-style: none; margin: 0; padding: 0; }
.cred { display: grid; grid-template-columns: 1fr auto; gap: var(--space-1) var(--space-3); align-items: baseline; padding: var(--space-3) 0; border-top: var(--size-edge) solid var(--glass-edge); }
.cred .index { grid-column: 1 / -1; }

/* how it's made: the pipeline as a scene, then the hardware's Capture and its measured row */
.made .made-sub { margin-top: var(--space-6); }
.made .capture, .made .metrics { margin-top: var(--space-6); }
.row-note { margin-top: var(--space-2); }

/* closing: one line, the one primary, and the lab elsewhere as text chips (no icons) */
.closing .display-xl { max-width: calc(var(--mat) * 20); margin-bottom: var(--space-4); }
.closing-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-4) var(--space-6); margin-top: var(--space-6); }
.social { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* ---- cards (scene index, landing row, notes list) ----------------------------------------- */
.card { display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-4); border-radius: var(--radius-puck); color: var(--ink); }
.card-frame svg { display: block; width: 100%; height: auto; border-radius: var(--radius-puck); }
.card-title { color: var(--ink); }
.card-meta { display: flex; flex-wrap: wrap; gap: var(--space-2); }
/* The corridor: the newest card starts on the column's left edge, under the page head; each older
   one is narrower and steps in from the left by the cells it lost, so all share a right edge and
   the row recedes toward the upper right. */
.cards { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-6); align-items: flex-start; }
.card-slot { --cells: var(--cells-3); width: calc(var(--mat) * var(--cells)); margin-left: calc(var(--mat) * (var(--cells-0) - var(--cells))); max-width: 100%; }
.card-slot[data-depth="0"] { --cells: var(--cells-0); }
.card-slot[data-depth="1"] { --cells: var(--cells-1); }
.card-slot[data-depth="2"] { --cells: var(--cells-2); }
.card-slot .card { width: 100%; }
.corridor { position: relative; }
.filters { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-bottom: var(--space-3); }
.filters .index { margin-right: var(--space-1); }
.filter-status { margin-bottom: var(--space-6); min-height: var(--space-4); }
.notes-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-4); }

/* ---- scene page ---------------------------------------------------------------------------- */
.scene-page > * + * { margin-top: var(--space-6); }
.steps { list-style: none; margin: 0; padding: 0; max-width: var(--size-measure); }
.step { position: relative; display: grid; grid-template-columns: 3ch 1fr; gap: var(--space-4); padding: var(--space-3) 0; border-top: var(--size-edge) solid var(--glass-edge); }
.step:last-child { border-bottom: var(--size-edge) solid var(--glass-edge); }
.step-no { font-family: var(--type-value-family); font-weight: 500; color: var(--lit-ink); font-size: var(--type-lede-size); line-height: var(--type-body-leading); }
/* The step the player is on is pointed at from the gutter, one mat cell left of the column, in ink.
   Pointed at, never lit: lit lines belong to scenes and Captures (p.15). */
.step-mark { position: absolute; left: calc(-1 * var(--space-6)); top: var(--space-3); visibility: hidden; font-family: var(--type-value-family); font-size: var(--type-lede-size); line-height: var(--type-body-leading); color: var(--ink); }
.step:has(.step-link[aria-current]) .step-mark { visibility: visible; }
.step-link:visited { color: var(--ink); text-decoration-color: var(--ink-caption); } /* a step seen is not a page done */
.footnote { margin-top: var(--space-4); }
.copy-row { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; margin-top: var(--space-3); }

/* ---- code is glass (p.15): a micro label row above, the block, a // note below if it holds a number */
.code-block { margin: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.code-block > figcaption { color: var(--ink-caption); }
.code {
  margin: 0; padding: var(--space-4); max-width: var(--size-code-block);
  background: var(--glass-fill); border: var(--size-edge) solid var(--glass-edge); border-radius: var(--radius-frame); box-shadow: var(--shadow-glass);
  font-size: var(--type-code-size); line-height: var(--type-code-leading); font-weight: var(--type-code-weight);
  white-space: pre; overflow-x: auto; color: var(--ink);
}
.code .comment { color: var(--ink-caption); }
code.inline { font-family: var(--type-code-inline-family); font-size: var(--type-code-inline-size); background: var(--glass-fill); border: var(--size-edge) solid var(--glass-edge); border-radius: var(--radius-pill); padding: 0 var(--space-1); }

/* ---- evidence is dark (p.08, p.15): label row, glass frame around the capture ground, // note ---- */
.capture { margin: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.capture > figcaption { color: var(--ink-caption); }
.capture-frame {
  display: grid; padding: var(--space-4); overflow-x: auto;
  background: var(--glass-white); border: var(--size-edge) solid var(--glass-edge); border-radius: var(--radius-frame); box-shadow: var(--shadow-glass);
}
.capture-ground { background: var(--capture); color: var(--capture-ink); border-radius: var(--radius-puck); overflow: hidden; }
.capture-ground img { display: block; width: 100%; height: auto; opacity: var(--opacity-capture-dim); }
.capture-text { margin: 0; padding: var(--space-4); width: max-content; min-width: 100%; font-family: var(--type-code-family); font-size: var(--type-code-size); line-height: var(--type-code-leading); color: var(--capture-ink); white-space: pre; }
.capture-text .lit-line { font-weight: 400; color: var(--lit); } /* the one lit line, set when the capture is made */
.prose > .capture, .prose > .code, .prose > .code-block { margin-top: var(--space-6); margin-bottom: var(--space-6); }
.note-page > * + * { margin-top: var(--space-6); }

/* ---- metrics: a measured number on a resting puck, never lit (p.16) ------------------------ */
.metrics { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-4) var(--space-3); }
@media (min-width: 768px) { .metrics { grid-template-columns: repeat(4, 1fr); } }
/* Each metric takes three rows of the row (label, puck, note) as a subgrid, so the pucks line up
   when one label wraps; a label sits on its puck, space-2 above it. */
.metric { display: grid; grid-row: span 3; grid-template-rows: subgrid; row-gap: var(--space-2); min-width: 0; }
.metric .index { align-self: end; }
.metric .puck { display: flex; align-items: center; justify-content: center; height: var(--size-puck-h); border-radius: var(--radius-puck); background: var(--glass-fill); border: var(--size-edge) solid var(--glass-edge); box-shadow: var(--shadow-glass); color: var(--ink); }
.metric .note { overflow-wrap: break-word; }
.nobr { white-space: nowrap; }

/* ---- work and about ------------------------------------------------------------------------ */
.offers { display: grid; grid-template-columns: 1fr; gap: var(--space-8); }
.offer { display: flex; flex-direction: column; gap: var(--space-4); }
.offer .metric { max-width: calc(var(--mat) * 6); }
.offer .button { align-self: flex-start; }
/* Three columns only at 1280: at 768 a third of the column is 180px and the offers wrap unevenly.
   Each offer is a subgrid of six rows (head, prose, label, puck, note, action), so the three pucks
   share a row whatever the prose above them runs to. */
@media (min-width: 1280px) {
  .offers { grid-template-columns: repeat(3, 1fr); gap: 0 var(--space-6); }
  .offer { display: grid; grid-row: span 6; grid-template-rows: subgrid; row-gap: var(--space-2); }
  .offer .metric { display: contents; }
  .offer .puck, .offer .metric .note { max-width: calc(var(--mat) * 6); }
  .offer > .body, .offer .metric .index, .offer .button { margin-top: var(--space-2); }
  .offer .button { justify-self: start; align-self: start; }
}
.contact { margin-top: var(--space-6); }
.about > * + * { margin-top: var(--space-6); }
.not-found > * + * { margin-top: var(--space-6); }

/* ---- empty states -------------------------------------------------------------------------- */
.empty { display: flex; flex-direction: column; gap: var(--space-4); }

/* ---- defs carrier: rendered, never display:none, so url(#…) resolves ----------------------- */
.defs { position: absolute; width: 0; height: 0; overflow: hidden; }

/* ---- reduced motion and forced colours: access needs, not themes (p.09, p.17) -------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 0ms !important; animation-duration: 0ms !important; scroll-behavior: auto !important; }
  /* an autoplaying scene shows its end frame as the still (p.18); the visitor steps through it in cuts */
  .player[data-autoplay] .stage .frame-start, .player[data-scroll] .stage .frame-start { display: none; }
  .player[data-autoplay] .stage .frame-end, .player[data-scroll] .stage .frame-end { display: block; }
}
@media (forced-colors: active) {
  :focus-visible { outline: var(--size-edge-focus) solid CanvasText; }
  .button, .chip, .card, .stage, .capture-frame, .code { border: var(--size-edge) solid CanvasText; }
  .nav-tube { forced-color-adjust: none; }
}
