/* ==========================================================================
   5am9t1.com — Sam Dedewo
   Reference system: Linear (near-black, one violet accent, restrained type).
   No-AI-look: HOUSE. Allowed and used: A8 one gradient (the contact band),
   A9 glass (the fixed nav), A12 hover (image zoom, link colour).
   2026-09-22: under the photo wall and marquee, the reel (one real video
   through the production line) and 5 full-screen case chapters.
   Banned and absent: card frames, side stripes, tinted selections, accent
   bars, tracked small caps, eyebrow labels, shadows and glow, text panels
   on photos, highlight words, pill badges, rule-of-three copy.
   ========================================================================== */

@import url("/assets/fonts/fonts.css");

:root {
  /* colour: one job each. Contrast measured, see the build receipt. */
  --bg: #0B0A10;          /* page ground, violet-tinted near-black */
  --surface: #13111B;     /* one tone step up, for the proof band */
  --ink: #EDEAFB;         /* headings and body */
  --ink-2: #A29CC2;       /* secondary text */
  --line: #2A2540;        /* hairline rules */
  --accent: #8B7CF6;      /* the action colour: primary button, focus */
  --on-accent: #0B0A10;   /* text on the accent */

  /* type: one family; Unbounded only for display at 32px and above */
  --font: "Instrument Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  --display: "Unbounded", "Arial Black", Impact, sans-serif;

  /* spacing scale: 8 12 16 20 24 32 44 56 80 120 */
  --s1: 8px; --s2: 12px; --s3: 16px; --s4: 20px; --s5: 24px;
  --s6: 32px; --s7: 44px; --s8: 56px; --s9: 80px; --s10: 120px;
  /* space above and below each chapter and section (round 23): 80 px up to 889 px tall screens,
     then 9% of the screen height, up to 120 px. Two blocks meet, so the gap is twice this. */
  --s-block: clamp(var(--s9), 9svh, var(--s10));

  --radius: 10px;
  --wrap: 1200px;
  --nav-h: 64px;
  --pad: 24px;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

@media (max-width: 640px) { :root { --pad: 16px; } }

*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; scroll-padding-top: var(--nav-h); }   /* a #section jump stops below the sticky header */
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 400 16px/1.6 var(--font);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img, video { display: block; max-width: 100%; height: auto; }  /* video too: its height attribute is a fixed pixel height */
a { color: inherit; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }

.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding: 0 var(--pad); }

.skip {
  position: absolute; left: -9999px; top: var(--s3);
  background: var(--ink); color: var(--bg); padding: var(--s2) var(--s3); border-radius: 6px;
  z-index: 100; text-decoration: none; font-weight: 600;
}
.skip:focus { left: var(--s3); }

/* --- links: A12, a 150ms colour change, no bar, no glow -------------------- */
.link {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--line);
  text-underline-offset: 4px;
  transition: color 150ms var(--ease), text-decoration-color 150ms var(--ease);
}
.link:hover { color: var(--accent); text-decoration-color: var(--accent); }
/* links that stand alone (not inside a sentence) get a full 44px tap height */
.chapter-links .link, .where .link, .footer a:not(.social-icon) { display: inline-flex; align-items: center; min-height: 44px; }
/* no heading ends on a single word */
h1, h2, h3 { text-wrap: balance; }

/* --- buttons: one shape; primary by fill, secondary by outline ------------ */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 48px; padding: 0 var(--s5);
  border-radius: var(--radius);
  font: 600 16px/1 var(--font);
  text-decoration: none;
  transition: background-color 150ms var(--ease), color 150ms var(--ease), transform 150ms var(--ease);
}
.btn:active { transform: translateY(1px); }
.btn-primary { background: var(--accent); color: var(--on-accent); }
.btn-primary:hover { background: #9D90FA; }
.btn-secondary { color: var(--ink); outline: 1px solid rgba(237, 234, 251, .5); outline-offset: -1px; }
.btn-secondary:hover { outline-color: var(--ink); }

/* ==========================================================================
   NAV — A9 glass. It sits over the photo wall, where a solid bar would cut
   the top row of work off. Solid fallback where backdrop-filter is missing.
   ========================================================================== */
.nav {
  position: fixed; inset: 0 0 auto 0; z-index: 50;
  background: rgba(11, 10, 16, .88);
}
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .nav {
    background: rgba(11, 10, 16, .58);
    -webkit-backdrop-filter: blur(14px) saturate(1.2);
    backdrop-filter: blur(14px) saturate(1.2);
  }
}
.nav-inner { display: flex; align-items: center; justify-content: space-between; height: var(--nav-h); }
.brand { display: inline-flex; align-items: center; min-height: 44px; font: 700 18px/1 var(--font); letter-spacing: -.01em; text-decoration: none; }
.nav-links { display: flex; align-items: center; gap: var(--s6); list-style: none; margin: 0; padding: 0; }
.nav-links a { display: inline-flex; align-items: center; justify-content: center; min-height: 44px; min-width: 44px; text-decoration: none; color: var(--ink-2); font-size: 15px; transition: color 150ms var(--ease); }
.nav-links a {
  background: linear-gradient(currentColor, currentColor) left calc(50% + 12px) / 0 1px no-repeat;
  transition: color 150ms var(--ease), background-size 200ms var(--ease);
}
.nav-links a:hover, .nav-links a:focus-visible { color: var(--ink); background-size: 100% 1px; }
.nav-links .nav-contact, .nav-links .nav-build { color: var(--ink); }   /* the two links every visitor needs, shown at every width */
@media (max-width: 899px) { .nav-links .nav-hide { display: none; } }

/* ==========================================================================
   HERO — the wall of real work (v2, restored 2026-09-22 at Sam's request).
   A8: a night-violet scrim, so the name reads over any photo behind it.
   ========================================================================== */
.hero {
  position: relative;
  min-height: min(92svh, 900px);
  display: flex; align-items: flex-end;
  overflow: hidden;
  isolation: isolate;
  background: var(--bg);
}
.wall {
  position: absolute; inset: var(--nav-h) 0 0 0; z-index: -2;   /* starts under the header, so the top row's heads are not behind it (round 18) */
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(3, 1fr);
  gap: 2px;
}
.tile { position: relative; overflow: hidden; display: block; }
.tile picture { display: contents; }   /* tiles 7-12: <picture> with a desktop-only source; the img still fills the tile (round 20) */
.tile img {
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 20%;   /* crop from the bottom: heads stay in */
  transition: transform 250ms var(--ease);
}
.tile:hover img { transform: scale(1.04); }
.scrim {
  position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: linear-gradient(to top,
    rgba(11, 10, 16, .97) 0%,
    rgba(11, 10, 16, .86) 30%,
    rgba(38, 22, 92, .42) 62%,
    rgba(11, 10, 16, .50) 100%);
}
.hero-copy { padding-bottom: var(--s9); padding-top: 160px; }
.hero h1 {
  font: 800 clamp(48px, 7.5vw, 96px)/.98 var(--display);
  letter-spacing: -.01em;
  margin: 0 0 var(--s4);
}
.hero .role { font-size: clamp(17px, 1.6vw, 20px); font-weight: 500; color: var(--ink); margin: 0 0 var(--s3); max-width: 60ch; text-wrap: balance; }
.hero .lead { font-size: 18px; color: var(--ink-2); margin: 0 0 var(--s6); max-width: 52ch; }
.hero-actions { display: flex; flex-wrap: wrap; gap: var(--s2); }

@media (max-width: 800px) {
  .wall { grid-template-columns: repeat(2, 1fr); grid-template-rows: repeat(3, 1fr); }
  .wall .tile:nth-child(n+7) { display: none; }
}
@media (max-width: 640px) { .hero .lead { font-size: 16px; } }

/* ==========================================================================
   MARQUEE — display capitals at 40px and above, so the tracked-caps ban
   (under 32px) does not apply. Paused off screen, static under reduced
   motion. It never shares the screen with the pinned line below it.
   ========================================================================== */
.marquee { overflow: hidden; border-block: 1px solid var(--line); padding: var(--s5) 0; }
.marquee-track { display: flex; width: max-content; animation: slide 48s linear infinite; }
.marquee.paused .marquee-track { animation-play-state: paused; }
.marquee span {
  font: 700 clamp(40px, 6vw, 80px)/1 var(--display);
  color: var(--ink-2);
  white-space: nowrap;
  padding-right: .6em;
}
@keyframes slide { to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .marquee-track { animation: none; } }

/* ==========================================================================
   REEL — the scroll-driven production line, under the header (2026-09-22).
   One real NeuroLoop 100 video goes through the line that made it, one stage
   per slice of scroll. assets/reel.js turns scroll into one number and marks
   the current stage; everything below derives from that, so scrolling back
   reverses cleanly (M3).
   Without JS, or under reduced motion, there is no pin: the stage shows the
   finished video and all 7 steps are a plain list (M2).
   ========================================================================== */
.visually-hidden {
  position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.reel-grid {
  display: grid;
  grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr);
  column-gap: var(--s8);
  align-items: start;                     /* static list: the name stays at the top, not centred on a long column */
  padding-block: var(--s8) var(--s9);
}
.reel:not(.is-live) .line-copy { padding-top: var(--s9); }
.line-copy h2 {
  font: 800 clamp(36px, 4.2vw, 60px)/1 var(--display);
  letter-spacing: -.01em;
  margin: 0 0 var(--s5);
}
.line-copy .lead { font-size: 18px; color: var(--ink-2); margin: 0 0 var(--s6); max-width: 40ch; }
.hero-note { display: none; font-size: 15px; color: var(--ink-2); margin: calc(var(--s6) * -1 + var(--s3)) 0 var(--s6); max-width: 40ch; }

/* --- the line: the stage (the real object) beside the 7 steps ------------- */
.line {
  margin: 0;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: var(--s7);
  align-items: start;
}
.line-title { grid-column: 1 / -1; margin: 0 0 var(--s5); font-size: 15px; color: var(--ink-2); max-width: 56ch; }
.stage {
  position: relative;
  height: min(64svh, 620px);
  aspect-ratio: 9 / 16;
  border-radius: var(--radius);
  overflow: hidden; overflow: clip;
  background: var(--surface);
  outline: 2px solid transparent;          /* the gate's pass state lands on the stage itself */
  outline-offset: 4px;
  transition: outline-color 250ms var(--ease);
}
.s-layer { position: absolute; inset: 0; margin: 0; }
.s-bg, .s-video { display: block; width: 100%; height: 100%; object-fit: cover; }
.s-idea { display: grid; place-content: center; text-align: center; padding: var(--s5); }
.s-topic { font: 700 clamp(22px, 2vw, 28px)/1.15 var(--display); margin: 0 0 var(--s2); }
.s-sub { margin: 0; color: var(--ink-2); }
.s-script {
  list-style: none; padding: var(--s6) var(--s5);
  display: grid; align-content: center; gap: var(--s3);
  font-size: 15px; line-height: 1.5; color: var(--ink-2);
}
.s-script strong { color: var(--ink); font-weight: 600; }

.line-progress { display: none; }
.line-skip { display: none; }

.steps { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s5); align-content: start; }
/* each heading sets its own number: live mode hides or flattens the others, and hidden boxes do not count */
.steps li:nth-child(1) h3 { counter-set: step 1; }
.steps li:nth-child(2) h3 { counter-set: step 2; }
.steps li:nth-child(3) h3 { counter-set: step 3; }
.steps li:nth-child(4) h3 { counter-set: step 4; }
.steps li:nth-child(5) h3 { counter-set: step 5; }
.steps li:nth-child(6) h3 { counter-set: step 6; }
.steps li:nth-child(7) h3 { counter-set: step 7; }
.steps h3 { display: flex; gap: var(--s2); align-items: baseline; margin: 0 0 var(--s1); font: 600 17px/1.3 var(--font); }
.steps h3::before { content: counter(step); min-width: 1.1em; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.detail { font-size: 15px; color: var(--ink-2); }
.detail p { margin: 0 0 var(--s2); }
.detail blockquote { margin: 0 0 var(--s2); color: var(--ink); }
.detail .spec { color: var(--ink); }
.checks { margin: 0; padding-left: 1.1em; }
.checks li { margin-bottom: var(--s1); }
.line-proof { margin-top: var(--s4) !important; }
.line-proof strong { display: block; font: 700 28px/1 var(--display); color: var(--ink); margin-bottom: var(--s1); }

/* --- live: pinned, one step at a time (reel.js adds .is-live) -------------- */
.reel.is-live .hero-note { display: block; }
.reel.is-live .reel-grid {
  grid-template-rows: calc(100svh - var(--nav-h)) auto;
  align-items: stretch;
  padding-block: 0;
}
.reel.is-live .line-copy,
.reel.is-live .line {
  position: sticky; top: var(--nav-h);
  height: calc(100svh - var(--nav-h));
  align-content: center;
}
.reel.is-live .line-copy { display: flex; flex-direction: column; justify-content: center; }
.reel-runway { display: none; }
.reel.is-live .reel-runway { display: block; grid-column: 1 / -1; height: calc(7 * 34svh); }

.reel.is-live .s-layer { opacity: 0; transition: opacity 500ms var(--ease); }
.reel.is-live .s-layer.on { opacity: 1; }
.reel.is-live .stage.passed { outline-color: var(--accent); }

.reel.is-live .steps { gap: 0; grid-template-columns: minmax(0, 1fr); }
.reel.is-live .steps > li { display: contents; }
.reel.is-live .steps h3 {
  grid-column: 1; margin: 0; padding: 4px 0;
  color: var(--ink-2); font-weight: 500;
  transition: color 250ms var(--ease);
}
.reel.is-live .steps h3.done { color: var(--ink); }
.reel.is-live .steps h3.now { color: var(--ink); font-weight: 700; }
.reel.is-live .steps h3.now::before { color: var(--accent); }
.reel.is-live .detail {
  grid-row: 8; grid-column: 1;
  margin-top: var(--s5);
  opacity: 0; pointer-events: none;      /* opacity, not visibility: screen readers still read every step */
  transition: opacity 250ms var(--ease);
}
.reel.is-live .detail.now { opacity: 1; pointer-events: auto; }

/* --- phone: the copy scrolls first, then only the line pins ---------------- */
@media (max-width: 899px) {
  .reel-grid { grid-template-columns: minmax(0, 1fr); row-gap: var(--s7); padding-block: var(--s7) var(--s9); }
  .line { grid-template-columns: minmax(0, 1fr); justify-items: center; row-gap: var(--s5); }
  .line-title { text-align: center; margin: 0; }
  .stage { height: min(60svh, 560px); }
  .steps { width: 100%; }

  .reel.is-live .reel-grid { grid-template-rows: auto calc(100svh - var(--nav-h)) auto; row-gap: 0; }
  .reel.is-live .line-copy { position: static; height: auto; padding-block: var(--s7) var(--s6); }
  .reel.is-live .line { row-gap: var(--s3); align-content: center; }
  .reel.is-live .line-title { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .reel.is-live .stage { height: min(48svh, 440px); }
  .reel.is-live .line-progress { display: flex; gap: 4px; width: 100%; max-width: 420px; }
  .line-progress span { flex: 1; height: 3px; border-radius: 2px; background: var(--line); transition: background-color 250ms var(--ease); }
  .line-progress span.done { background: var(--ink-2); }
  .line-progress span.now { background: var(--accent); }
  .reel.is-live .steps { max-width: 420px; }
  .reel.is-live .steps h3 { display: none; }
  .reel.is-live .steps h3.now { display: flex; grid-row: 1; }
  .reel.is-live .detail { grid-row: 2; margin-top: var(--s1); min-height: 7.5em; }
  .reel.is-live .line-skip { display: inline-flex; align-items: center; min-height: 44px; font-size: 15px; }
  .reel.is-live .reel-runway { height: calc(7 * 28svh); }
}

/* ==========================================================================
   CHAPTERS — one case each. Each piece keeps its own aspect
   ratio (portrait clips are never cropped to landscape). No entrance
   animation: the content is already there (M1).
   Round 23 (Sam, 2026-09-26: "reduce the height of the gaps"): no longer one
   full screen each. min-height: 100svh centred the content in a screen-tall
   box, so the empty space grew with the screen: 548 px between LuvBugz and
   K!NG on a 1728x1117 MacBook, 871 px at 2560x1440, and uneven per chapter.
   Now the gap is the padding only: 160 px on screens up to 889 px tall,
   rising with the screen to 240 px at 1333 px tall and above.
   ========================================================================== */
.chapter { display: grid; align-items: center; padding-block: var(--s-block); }
.chapter-inner { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: var(--s8); align-items: center; }
.chapter.flip .chapter-inner { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); }
.chapter.flip .chapter-media { order: 2; }
/* --- chapter galleries: mixed sizes, each clip opens full size (gallery.js) -
   Portrait bento: one 9:16 main tile, then a landscape tile over a tall one
   (g-stack: two equal portrait tiles). Landscape bento: one wide main tile,
   two tiles under it. Sizes come from one height, --gh, capped by the column
   width through container units, so the bento never overflows.
   cqi measures the nearest ANCESTOR container, so the 2-column grid is the
   container and --col is the media column: 7 of 12 parts after the gap, or
   the full width once the grid stacks (below 900px). ----------------------- */
.chapter-inner, .case-hero-grid { container-type: inline-size; }
.chapter-media { position: relative; margin: 0; width: 100%; --col: calc((100cqi - var(--s8)) * 7 / 12); }
.gallery { --gap: 12px; }
.g-tile { position: relative; margin: 0; min-width: 0; min-height: 0; overflow: hidden; overflow: clip; border-radius: var(--radius); background: var(--surface); }
.g-tile video, .g-tile img { display: block; width: 100%; height: 100%; object-fit: cover; transition: transform 250ms var(--ease); }
.g-tile:has(.g-open:hover) video, .g-tile:has(.g-open:hover) img { transform: scale(1.03); }
.g-open { position: absolute; inset: 0; z-index: 1; margin: 0; padding: 0; border: 0; background: transparent; cursor: pointer; }
.g-open:focus-visible { outline: 2px solid var(--accent); outline-offset: -4px; border-radius: var(--radius); }
.g-play {                                /* K4: the play control sits in its own chip */
  position: absolute; left: var(--s2); bottom: var(--s2);
  width: 44px; height: 44px; border-radius: 50%;
  background: rgba(11, 10, 16, .72); display: grid; place-items: center;
  transition: background-color 150ms var(--ease);
}
.g-play::before { content: ""; margin-left: 3px; border-style: solid; border-width: 7px 0 7px 12px; border-color: transparent transparent transparent var(--ink); }
.g-open:hover .g-play { background: var(--accent); }
.g-open:hover .g-play::before { border-left-color: var(--on-accent); }
.g-tile .clip-toggle { z-index: 2; }

.g-port {
  --gh: min(76svh, 720px, calc((var(--col) - var(--gap)) / 1.0625));
  display: grid; justify-content: center; gap: var(--gap);
  grid-template-columns: calc(var(--gh) * .5625) calc(var(--gh) * .5);
  grid-template-rows: calc(var(--gh) * .5 * .5625) minmax(0, 1fr);   /* minmax: a video's natural height must not grow the row */
  height: var(--gh);
}
.g-port .g-main { grid-row: 1 / 3; }
.g-port.g-stack {
  --gh: min(76svh, 720px, calc((var(--col) - var(--gap)) / .8438));
  grid-template-columns: calc(var(--gh) * .5625) calc((var(--gh) - var(--gap)) / 2 * .5625);
  grid-template-rows: minmax(0, 1fr) minmax(0, 1fr);
}
.g-land { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap); }
.g-land .g-main { grid-column: 1 / -1; aspect-ratio: 16 / 9; }
.g-land .g-tile:not(.g-main) { aspect-ratio: 16 / 9; }
.g-land.g-tall-row .g-tile:not(.g-main) { aspect-ratio: 4 / 5; }
.g-hint { margin: var(--s5) 0 0; font-size: 14px; color: var(--ink-2); }
@media (max-width: 899px) { .chapter-media { --col: 100cqi; } .g-port { --gh: min(64svh, 600px, calc((var(--col) - var(--gap)) / 1.0625)); } .g-port.g-stack { --gh: min(64svh, 600px, calc((var(--col) - var(--gap)) / .8438)); } }

/* --- the full-size player (native dialog: Esc, focus trap, backdrop) ------- */
.lightbox { padding: 0; border: 0; background: transparent; max-width: none; max-height: none; overflow: visible; }
.lightbox::backdrop { background: rgba(11, 10, 16, .92); }
.lb-frame { position: relative; display: grid; justify-items: center; gap: var(--s2); }
.lb-body video { display: block; max-width: min(92vw, 1100px); max-height: 80svh; border-radius: var(--radius); background: #000; }
.lb-body iframe { display: block; width: min(92vw, 1100px); aspect-ratio: 16 / 9; max-height: 80svh; border: 0; border-radius: var(--radius); }
.lb-title { margin: 0; font-size: 15px; color: var(--ink-2); text-align: center; max-width: 60ch; }
.lb-close {
  position: fixed; top: var(--s3); right: var(--s3);
  width: 44px; height: 44px; border: 0; border-radius: 50%;
  background: rgba(237, 234, 251, .12); color: var(--ink); font: 400 26px/1 var(--font); cursor: pointer;
  transition: background-color 150ms var(--ease);
}
.lb-close:hover { background: rgba(237, 234, 251, .24); }
.chapter-copy h3 { font: 700 clamp(34px, 3.8vw, 54px)/1.05 var(--display); letter-spacing: -.01em; margin: 0 0 var(--s3); }
.chapter-copy .role { margin: 0 0 var(--s5); font-size: 15px; color: var(--ink-2); }
.chapter-copy .what { margin: 0 0 var(--s5); font-size: 19px; line-height: 1.5; max-width: 36ch; }
.chapter-copy .stat { margin: 0 0 var(--s6); color: var(--ink-2); max-width: 34ch; }
.chapter-copy .stat strong { display: block; margin-bottom: var(--s1); font: 700 clamp(32px, 3.2vw, 44px)/1 var(--display); color: var(--ink); }
.chapter-links { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s5); }
@media (max-width: 899px) {
  .chapter { min-height: 0; padding-block: var(--s9); }
  .chapter-inner, .chapter.flip .chapter-inner { grid-template-columns: minmax(0, 1fr); gap: var(--s6); }
  .chapter.flip .chapter-media { order: 0; }
}

.section .studio-head:first-of-type { margin-top: 0; }

/* ==========================================================================
   SECTIONS
   ========================================================================== */
/* Round 23 (Sam, 2026-09-26, the gap above "3D renders": "and here please"): was a fixed 120 px,
   so 240 px between any two sections. Now the same rhythm as the chapters (--s-block). */
.section { padding: var(--s-block) 0; }
@media (max-width: 640px) { .section { padding: var(--s9) 0; } }
.section h2 {
  font: 600 clamp(34px, 4.2vw, 52px)/1.1 var(--font);
  letter-spacing: -.015em;
  margin: 0 0 var(--s8);
  max-width: 20ch;
}
.section h3 { font: 600 24px/1.25 var(--font); letter-spacing: -.01em; margin: 0 0 var(--s2); }
.muted { color: var(--ink-2); }

/* --- intro + the one sourced stats row (LD1) ------------------------------ */
.intro { font-size: clamp(20px, 2.2vw, 26px); line-height: 1.45; max-width: 34ch; margin: 0 0 var(--s9); font-weight: 500; }
.proof {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s6);
  margin: 0; padding: var(--s6) 0 0; border-top: 1px solid var(--line);
}
.proof div { margin: 0; }
.proof dt { font: 700 clamp(36px, 4vw, 52px)/1 var(--display); margin: 0 0 var(--s2); }
.proof dd { margin: 0; color: var(--ink-2); font-size: 15px; max-width: 22ch; }
@media (max-width: 800px) { .proof { grid-template-columns: repeat(2, 1fr); row-gap: var(--s7); } }

/* --- selected work: open rows, image and text, alternating. Not a card grid */
.work { display: grid; gap: var(--s10); }
.row { display: grid; grid-template-columns: 7fr 5fr; gap: var(--s8); align-items: center; }
.row:nth-child(even) { grid-template-columns: 5fr 7fr; }
.row:nth-child(even) .shot { order: 2; }
.shot { display: block; overflow: hidden; overflow: clip; border-radius: var(--radius); }  /* clip, not hidden: hidden makes a scroll container and freezes view() timelines at 50% */
.shot img { width: 100%; transition: transform 250ms var(--ease); }
a.shot:hover img { transform: scale(1.03); }  /* links only: studio images go nowhere, so they do not move */
.shot.portrait { width: 100%; max-width: 480px; justify-self: center; }  /* width: a centred frame shrinks to its image, a lazy image has no size until it loads, so both stayed 0 and it never loaded */
.row p { margin: 0 0 var(--s3); color: var(--ink-2); max-width: 52ch; }
.row .what { color: var(--ink); font-size: 18px; }
.row .where { font-size: 15px; margin-top: var(--s5); }
@media (max-width: 800px) {
  .row, .row:nth-child(even) { grid-template-columns: 1fr; gap: var(--s5); }
  .row:nth-child(even) .shot { order: 0; }
  .work { gap: var(--s9); }
}

/* --- clips: real footage beside the text. Two side by side, or one alone --- */
.pair { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3); align-items: start; }
.clip { position: relative; margin: 0; }
.clip video, .clip img { display: block; width: 100%; border-radius: var(--radius); background: var(--surface); }
.pair .clip video, .pair .clip img { aspect-ratio: 3 / 4; object-fit: cover; }
.clip.solo { max-width: 400px; justify-self: center; width: 100%; }
.clip.solo video { aspect-ratio: 9 / 16; object-fit: cover; }
.clip figcaption { margin-top: var(--s1); font-size: 14px; color: var(--ink-2); }

/* the pause control every clip carries (K4: its own chip over the image) */
.clip-toggle {
  position: absolute; top: var(--s2); right: var(--s2);
  width: 44px; height: 44px; border: 0; border-radius: 50%;
  background: rgba(11, 10, 16, .72); color: var(--ink);
  display: grid; place-items: center; cursor: pointer;
  transition: background-color 150ms var(--ease);
}
.clip-toggle:hover { background: rgba(11, 10, 16, .92); }
.clip-toggle::before {           /* paused: a play triangle */
  content: ""; width: 0; height: 0; margin-left: 3px;
  border-style: solid; border-width: 7px 0 7px 12px;
  border-color: transparent transparent transparent currentColor;
}
.clip-toggle[data-state="playing"]::before {   /* playing: two pause bars */
  width: 10px; height: 14px; margin: 0; border: 0;
  background: linear-gradient(90deg, currentColor 0 35%, transparent 35% 65%, currentColor 65%);
}
.shot { position: relative; }

/* --- YouTube: a still until tapped, then the no-cookie player ------------- */
.yt { position: relative; aspect-ratio: 16 / 9; border-radius: var(--radius); overflow: hidden; overflow: clip; background: var(--surface); }
.yt-play { all: unset; position: absolute; inset: 0; cursor: pointer; display: block; }
.yt-play img { width: 100%; height: 100%; object-fit: cover; transition: transform 250ms var(--ease); }
.yt-play:hover img { transform: scale(1.03); }
.yt-play:focus-visible { outline: 2px solid var(--accent); outline-offset: -4px; }
.yt-icon {
  position: absolute; left: 50%; top: 50%; width: 72px; height: 72px; margin: -36px 0 0 -36px;
  border-radius: 50%; background: var(--accent);
  transition: background-color 150ms var(--ease);
}
.yt-icon::before {
  content: ""; position: absolute; left: 29px; top: 23px;
  border-style: solid; border-width: 13px 0 13px 21px;
  border-color: transparent transparent transparent var(--on-accent);
}
.yt-play:hover .yt-icon { background: #9D90FA; }
.yt iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* --- the studio and where it started: image rows, captions below ---------- */
.section .studio-head { margin-top: var(--s10); }  /* beats `.section h3`, which zeroed this */
.studio, .early { display: grid; gap: var(--s5); margin-top: var(--s5); }
.studio { grid-template-columns: repeat(3, 1fr); }
.early { grid-template-columns: repeat(4, 1fr); }
.studio figure, .early figure, .live figure { margin: 0; }
.studio .shot img, .studio .shot video { display: block; width: 100%; aspect-ratio: 4 / 5; object-fit: cover; }
.studio figcaption, .early figcaption, .live figcaption { margin-top: var(--s2); font-size: 15px; color: var(--ink-2); }
.studio figcaption strong, .early figcaption strong, .live figcaption strong { color: var(--ink); font-weight: 600; }
.early .shot img, .early .shot video { display: block; width: 100%; aspect-ratio: 1 / 1; object-fit: cover; }
.early .shot img[src*="rezex"] { object-position: 100% 50%; }     /* the front of the DVD cover */
.early .shot video { object-position: 0% 50%; }                   /* keep the Painted By Me logo in frame */
.early .shot.logo, .early .shot.card { background: var(--surface); }
.early .shot.logo img { object-fit: contain; padding: var(--s5); }
.early .shot.card img { object-fit: contain; padding: var(--s3); }
.early audio { display: block; width: 100%; margin-top: var(--s2); color-scheme: dark; }
@media (max-width: 800px) { .studio { grid-template-columns: 1fr 1fr; } .studio figure:first-child { grid-column: span 2; } .studio figure:first-child video { aspect-ratio: 16 / 9; } }
@media (max-width: 1000px) { .early { grid-template-columns: 1fr 1fr; row-gap: var(--s7); } }
@media (max-width: 560px) { .early { grid-template-columns: 1fr; } }

/* --- also built: two plain lists separated by hairline rules --------------- */
.also { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s8); margin-top: var(--s10); }
.plain { list-style: none; margin: 0; padding: 0; }
.plain li { padding: var(--s2) 0; border-bottom: 1px solid var(--line); color: var(--ink-2); font-size: 15px; }
.plain li strong { color: var(--ink); font-weight: 600; }
@media (max-width: 800px) { .also { grid-template-columns: 1fr; gap: var(--s7); } }

/* --- the machine ------------------------------------------------------------ */
.machine-grid { display: grid; grid-template-columns: 5fr 7fr; gap: var(--s8); align-items: start; }
.machine-grid p { color: var(--ink-2); margin: 0 0 var(--s3); max-width: 52ch; }
.machine-grid p.what { color: var(--ink); font-size: 18px; }
.bullets { margin: var(--s5) 0 0; padding-left: 1.1em; color: var(--ink-2); }
.bullets li { margin-bottom: var(--s2); }
@media (max-width: 900px) { .machine-grid { grid-template-columns: 1fr; } }

/* --- music: an editorial list --------------------------------------------- */
.music { display: grid; grid-template-columns: 5fr 7fr; gap: var(--s8); }
.music .plain li { font-size: 16px; padding: var(--s3) 0; }
@media (max-width: 800px) { .music { grid-template-columns: 1fr; gap: var(--s5); } }

/* --- what I can build: open two-column text, no frames --------------------- */
.offers { display: grid; grid-template-columns: 1fr 1fr; column-gap: var(--s8); row-gap: var(--s7); margin: 0; }
.offers div { border-top: 1px solid var(--line); padding-top: var(--s5); }
.offers dt { font: 600 20px/1.3 var(--font); margin: 0 0 var(--s1); }
.offers dd { margin: 0; color: var(--ink-2); max-width: 46ch; }
@media (max-width: 800px) { .offers { grid-template-columns: 1fr; } }

/* --- contact ---------------------------------------------------------------- */
.contact { border-top: 1px solid var(--line); }
.contact h2 { max-width: 16ch; }
.contact p { color: var(--ink-2); max-width: 46ch; margin: 0 0 var(--s6); font-size: 18px; }

/* --- footer ----------------------------------------------------------------- */
.footer { border-top: 1px solid var(--line); padding: var(--s6) 0 var(--s8); color: var(--ink-2); font-size: 14px; }
.footer-inner { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--s3); }
.footer a { color: var(--ink-2); }
.footer a:hover { color: var(--ink); }

/* ==========================================================================
   DRESS (house pass, 2026-09-21, second pass the same night)
   D1 the particle network fixed behind the whole page, as on the old
      5am9t1.com (assets/network.js). The hero's photo wall covers it.
   D2 the page's second and last gradient: a night-violet wash on the
      contact band. Its edges are clear so the network runs through it.
   D3 CSS parallax, scroll-driven, no script. The wall drifts in 2
      directions as the page leaves the hero; work images drift inside
      their frames. Browsers without scroll timelines get the still page.
   ========================================================================== */
.network { position: fixed; inset: 0; width: 100%; height: 100%; z-index: -1; pointer-events: none; }

.contact {
  background: linear-gradient(180deg, rgba(11, 10, 16, 0) 0%, rgba(27, 19, 64, .9) 52%, rgba(11, 10, 16, 0) 100%);
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .wall .tile img {
      scale: 1.14;
      animation: drift-down linear both;
      animation-timeline: scroll(root);
      animation-range: 0 100vh;
    }
    .wall .tile:nth-child(odd) img { animation-name: drift-rise; }
    .hero-copy {
      animation: copy-lift linear both;
      animation-timeline: scroll(root);
      animation-range: 0 80vh;
    }
    .shot img, .yt-play img {      /* both frames clip their content, so the drift never shows an edge */
      scale: 1.1;
      animation: drift-frame linear both;
      animation-timeline: view();
      animation-range: cover;
    }
  }
}

/* D4 (round 17, 2026-09-22): D3 targeted the v2 layout, so from round 2 on
   nothing below the hero moved. Home only (ids), so the case pages are unchanged.
   - chapter and render images drift inside their clipped tiles (the frame
     never shows an edge: scale 1.1 covers the 4% travel); the wide render
     banner drifts twice as far
   - on 2 columns the chapter text moves slower than its gallery (depth)
   - logos float inside their tiles, odd and even in opposite directions,
     echoing the hero wall; the 20% tile padding absorbs the travel, so the
     seamless wall grid never moves
   Uses scale/translate, so the tiles' hover zoom (transform) still adds on top. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    #work .g-tile img, #work .g-tile video,
    #renders .g-tile img, #renders .g-tile video {
      scale: 1.1;
      animation: drift-frame-low linear both;
      animation-timeline: view();
      animation-range: cover;
    }
    #renders .r-contain .g-tile img { scale: 1.06; animation-name: drift-frame-soft; }
    #renders .r-full .g-tile img, #renders .r-full .g-tile video { scale: 1.2; animation-name: drift-frame-far; }
    /* Round 24b/24c: NeuroLoop 100 and Barz are a whole iPhone standing on the tile colour, with room around it.
       The 1.1 zoom + 5% drift would crop the phone's foot at the end of the scroll, and a device
       sliding inside its frame reads as a mistake; it stands still, like a product shot. */
    #nl100 .g-tile img, #nl100 .g-tile video,
    #barz .g-tile img, #barz .g-tile video { scale: none; animation: none; }
    #logos .logo img {
      animation: float-up linear both;
      animation-timeline: view();
      animation-range: cover;
    }
    #logos .logo:nth-child(even) img { animation-name: float-down; }
  }
  @media (prefers-reduced-motion: no-preference) and (min-width: 900px) {
    #work .chapter-copy {
      animation: copy-slow linear both;
      animation-timeline: view();
      animation-range: cover;
    }
  }
}
/* Round 18 (Sam: "move down slightly so you can see the heads"): same lag direction, but each range
   is shifted down. At scale 1.1 the top crop is now 6% on entry, 3% mid-screen, 0 on exit
   (was 9%, 5%, 1%). The extra crop goes to the bottom of the picture instead. */
@keyframes drift-frame-low { from { translate: 0 -1%; } to { translate: 0 5%; } }       /* scale 1.1: 5% margin */
@keyframes drift-frame-soft { from { translate: 0 -0.5%; } to { translate: 0 3%; } }    /* scale 1.06: 3% margin */
@keyframes drift-frame-far { from { translate: 0 -2%; } to { translate: 0 10%; } }      /* scale 1.2: 10% margin */
@keyframes float-up { from { translate: 0 6%; } to { translate: 0 -6%; } }
@keyframes float-down { from { translate: 0 -6%; } to { translate: 0 6%; } }
@keyframes copy-slow { from { translate: 0 -40px; } to { translate: 0 40px; } }   /* lags the page = reads as further away */
@keyframes drift-down { to { translate: 0 7%; } }
@keyframes drift-up { to { translate: 0 -5%; } }
/* Round 18: the wall is scaled 1.14 about its centre, so 7% is the most it can move before an edge
   shows. Odd tiles now START at +7% (image top at the tile top) and rise to 0, so no tile ever
   crops more than 7% off the top; even tiles still drift down, so the columns still move apart. */
@keyframes drift-rise { from { translate: 0 7%; } to { translate: 0 0%; } }
@keyframes copy-lift { to { translate: 0 -56px; } }
@keyframes drift-frame { from { translate: 0 -4%; } to { translate: 0 4%; } }

/* --- K!₦G music videos: two click-to-load players under the row ----------- */
.mv { grid-column: 1 / -1; display: grid; grid-template-columns: 1fr 1fr; gap: var(--s5); }
.mv figure { margin: 0; }
.mv figcaption { margin-top: var(--s2); font-size: 15px; color: var(--ink-2); }
.mv figcaption strong { color: var(--ink); font-weight: 600; }
@media (max-width: 800px) { .mv { grid-template-columns: 1fr; } }

/* --- Skinner & Vale: the customiser and the jacket at one height ---------- */
.sv-pair { grid-template-columns: 1.268fr 0.75fr; align-items: stretch; }
.sv-pair img { width: 100%; height: 100%; object-fit: cover; }

/* ==========================================================================
   LOGO WALL — one mosaic, 2px seams like the hero wall. Tiles reflow with
   auto-fill, so adding or removing a logo never needs a column count.
   Logos sit in greyscale and take their colour on hover (colour, no motion:
   the tiles are not links).
   ========================================================================== */
.section-lead { color: var(--ink-2); max-width: 52ch; margin: calc(var(--s7) * -1) 0 var(--s8); font-size: 18px; }
.logo-wall {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 2px;
  grid-template-columns: repeat(6, 1fr);
  border-radius: var(--radius); overflow: hidden; overflow: clip;
}
/* fixed steps, not auto-fill: 6, 4, 3 and 2 all divide 12, so a full wall never leaves an orphan row.
   Keep the logo count a multiple of 12 (fill gaps with placeholders) and every width stays even. */
@media (max-width: 1000px) { .logo-wall { grid-template-columns: repeat(4, 1fr); } }
@media (max-width: 760px) { .logo-wall { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 520px) { .logo-wall { grid-template-columns: repeat(2, 1fr); } }
.logo {
  position: relative; aspect-ratio: 1 / 1;
  display: grid; place-items: center; padding: 20%;
  background: var(--surface);
}
.logo img {
  position: absolute; inset: 20%; width: 60%; height: 60%; object-fit: contain;  /* absolute: the logo's own height must never stretch its tile */
  filter: grayscale(1); opacity: .8;
  transition: filter 250ms var(--ease), opacity 250ms var(--ease);
}
.logo:hover img { filter: none; opacity: 1; }
@media (hover: none) { .logo img { filter: none; opacity: 1; } }  /* phones cannot hover: show the colour */
.logo.on-light { background: var(--ink); }
.logo-name { position: absolute; left: var(--s2); bottom: var(--s2); font-size: 12px; line-height: 1.3; color: var(--ink-2); }
.logo.on-light .logo-name { color: #4A4560; }
.logo-mark { font: 600 clamp(16px, 1.8vw, 22px)/1.1 var(--font); color: var(--ink-2); text-align: center; }

/* ==========================================================================
   CONTACT FORM — fields carry a real 1px boundary (WCAG 1.4.11 needs 3:1
   for a control edge; #6F6893 on the band measures above that).
   ========================================================================== */
.contact-grid { display: grid; grid-template-columns: 5fr 7fr; gap: var(--s8); align-items: start; }
@media (max-width: 900px) { .contact-grid { grid-template-columns: 1fr; gap: var(--s7); } }
.contact .contact-direct { font-size: 16px; }
.contact-form { margin: 0; }
.contact-form .field { margin: 0 0 var(--s4); }
.contact-form label { display: block; margin: 0 0 var(--s1); font-size: 15px; font-weight: 600; color: var(--ink); }
.contact-form input, .contact-form textarea {
  width: 100%; min-height: 48px; padding: 12px 14px;
  font: 400 16px/1.5 var(--font); color: var(--ink);
  background: rgba(11, 10, 16, .6);
  border: 1px solid #6F6893; border-radius: 8px;
  transition: border-color 150ms var(--ease);
}
.contact-form textarea { resize: vertical; min-height: 150px; }
.contact-form input:hover, .contact-form textarea:hover { border-color: var(--ink-2); }
.contact-form input:focus-visible, .contact-form textarea:focus-visible { border-color: var(--accent); outline: 2px solid var(--accent); outline-offset: 1px; }
.contact-form [aria-invalid="true"] { border-color: #F5A3A3; }
.contact-form .hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.contact-form .form-status { min-height: 1.5em; margin: var(--s3) 0 0; font-size: 15px; color: var(--ink-2); max-width: none; }
.contact-form .form-status[data-kind="ok"] { color: #8EE3B0; }
.contact-form .form-status[data-kind="error"] { color: #F5A3A3; }
.contact-form .form-note { margin: var(--s2) 0 0; font-size: 13px; color: var(--ink-2); max-width: none; }
.reel.is-live[data-step="1"] .stage .clip-toggle,
.reel.is-live[data-step="2"] .stage .clip-toggle,
.reel.is-live[data-step="3"] .stage .clip-toggle { opacity: 0; pointer-events: none; }

/* ==========================================================================
   CASE PAGES — /work/<slug>/ (2026-09-22). Same tokens, same rules: no
   card frames, no text over media, one stats figure at most (LD1).
   ========================================================================== */
.case-hero { padding: calc(var(--nav-h) + var(--s9)) 0 var(--s9); }
.case-hero-grid { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: var(--s8); align-items: center; }
.crumbs { margin: 0 0 var(--s5); font-size: 15px; color: var(--ink-2); }
.crumbs ol { display: flex; flex-wrap: wrap; gap: var(--s1); list-style: none; margin: 0; padding: 0; }
.crumbs li + li::before { content: "/"; margin-right: var(--s1); color: var(--line); }
.crumbs a { color: var(--ink-2); text-decoration: none; transition: color 150ms var(--ease); }
.crumbs a:hover { color: var(--ink); }
/* home About: the way through to /about/, and that page's own short header */
.about-more { margin-top: var(--s8); display: grid; justify-items: start; gap: var(--s5); }
.about-more p { margin: 0; color: var(--ink-2); max-width: 60ch; }
.about-hero { padding-bottom: 0; }
.case-hero h1 { font: 800 clamp(40px, 4.6vw, 72px)/1 var(--display); letter-spacing: -.01em; margin: 0 0 var(--s5); }
.case-hero .what { margin: 0 0 var(--s3); font-size: clamp(19px, 1.7vw, 22px); line-height: 1.45; max-width: 36ch; }
.case-hero .role { margin: 0; color: var(--ink-2); }
.pair.tall .clip video, .pair.tall .clip img { aspect-ratio: 9 / 16; object-fit: cover; }

.case-section { padding: var(--s9) 0; border-top: 1px solid var(--line); }
.case-section h2 { font: 600 clamp(28px, 3vw, 40px)/1.15 var(--font); letter-spacing: -.01em; margin: 0; }
.case-row { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: var(--s8); align-items: start; }
.case-row p { margin: 0 0 var(--s3); color: var(--ink-2); max-width: 54ch; }
.case-row .lede { color: var(--ink); font-size: 18px; }
.case-row .where { margin-top: var(--s5); font-size: 15px; }
.big-stat { font: 700 clamp(40px, 4.4vw, 60px)/1 var(--display) !important; color: var(--ink) !important; margin: 0 0 var(--s2) !important; }
.case-mv { margin-top: var(--s8); }

.case-end { padding-bottom: var(--s10); }
.case-next { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: var(--s8); align-items: center; text-decoration: none; }
.case-next-media { display: block; overflow: hidden; overflow: clip; border-radius: var(--radius); }
.case-next-media img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; transition: transform 250ms var(--ease); }
.case-next:hover .case-next-media img { transform: scale(1.03); }
.case-next-label { display: block; margin-bottom: var(--s2); font-size: 15px; color: var(--ink-2); }
.case-next-title { display: block; font: 700 clamp(32px, 3.6vw, 52px)/1.05 var(--display); transition: color 150ms var(--ease); }
.case-next:hover .case-next-title { color: var(--accent); }
.case-contact { margin-top: var(--s10); padding-top: var(--s8); border-top: 1px solid var(--line); }
.case-contact p { margin: 0 0 var(--s5); font: 600 clamp(24px, 2.6vw, 34px)/1.2 var(--font); }

@media (max-width: 899px) {
  .case-hero { padding-top: calc(var(--nav-h) + var(--s7)); }
  .case-hero-grid, .case-row, .case-next { grid-template-columns: minmax(0, 1fr); gap: var(--s6); }
}

/* --- the Websites chapter: one line per site, links to the live sites ------ */
/* Websites: the three sites side by side, stills until tapped (no autoplay) */
.chapter-sites { min-height: 0; }
.chapter-sites .chapter-copy { max-width: 60ch; }
.site-row { list-style: none; margin: var(--s7) 0 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s5); }
.site-row .g-tile { aspect-ratio: 16 / 10; }
.site-row p { margin: var(--s3) 0 0; color: var(--ink-2); font-size: 15px; }
.site-row p strong { color: var(--ink); font-weight: 600; }
@media (max-width: 899px) { .site-row { grid-template-columns: minmax(0, 1fr); gap: var(--s6); } }
.site-list { list-style: none; margin: 0 0 var(--s2); padding: 0; }
.site-list li { padding: var(--s2) 0; border-bottom: 1px solid var(--line); color: var(--ink-2); font-size: 15px; max-width: 46ch; }
.site-list li strong { color: var(--ink); font-weight: 600; }

/* ==========================================================================
   REEL — continuous scroll feedback (Sam, 2026-09-22: "when you're scrolling
   something is happening"). reel.js sets --p (whole line, 0 to 1) and --sp
   (the current stage, 0 to 1) on every scroll event, so something moves on
   every tick, and it all reverses on the way back up. Live mode only: under
   reduced motion none of this runs. No blur, no filters (M5).
   ========================================================================== */
.reel.is-live .s-idea { transform: scale(calc(.92 + .08 * var(--sp, 0))); }
.reel.is-live .s-script li {                       /* the script writes itself, line by line */
  opacity: clamp(.12, calc(var(--sp, 0) * 6 - var(--i, 0)), 1);
  translate: 0 calc((1 - clamp(0, calc(var(--sp, 0) * 6 - var(--i, 0)), 1)) * 10px);
}
.reel.is-live[data-step="3"] .s-bg { clip-path: inset(calc((1 - var(--sp, 0)) * 100%) 0 0 0); }   /* the image comes up from the prompt */
.reel.is-live[data-step="4"] .s-video { clip-path: inset(0 calc((1 - var(--sp, 0)) * 100%) 0 0); } /* the render wipes across it */
.reel.is-live .s-bg, .reel.is-live .s-video { scale: calc(1.12 - .12 * var(--p, 0)); }            /* a slow push-in over the whole line */
.reel.is-live .checks li { opacity: clamp(.15, calc(var(--sp, 0) * 4 - var(--i, 0)), 1); }       /* the gate ticks off each check */

.reel.is-live .steps h3 { position: relative; }
.reel.is-live .steps h3.now::after {               /* the active step fills as you scroll through it */
  content: ""; position: absolute; left: 0; bottom: 0; height: 2px; border-radius: 1px;
  width: calc(var(--sp, 0) * 100%); background: var(--accent);
}
.reel.is-live .line-progress span.now { background: linear-gradient(to right, var(--accent) calc(var(--sp, 0) * 100%), var(--line) 0); }

.line-foot { display: none; }
.reel.is-live .line-foot { display: flex; grid-column: 1 / -1; align-items: center; justify-content: space-between; gap: var(--s4); margin-top: var(--s5); width: 100%; max-width: 420px; }
.scroll-cue { display: inline-flex; align-items: center; gap: var(--s2); margin: 0; font-size: 14px; color: var(--ink-2); transition: opacity 250ms var(--ease); }
.scroll-cue::after {
  content: ""; width: 8px; height: 8px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg); animation: cue-bob 1.4s var(--ease) infinite;
}
.reel:not(.in-view) .scroll-cue::after { animation-play-state: paused; }
.reel.is-live[data-step="7"] .scroll-cue { opacity: 0; }
@keyframes cue-bob { 0%, 100% { translate: 0 -3px; } 50% { translate: 0 3px; } }

/* --- logo wall: real files on the ground each was drawn for (2026-09-22) --- */
.logo.on-white { background: #FFFFFF; }
.logo.on-black { background: #000000; }
.logo.on-white .logo-name { color: #4A4560; }
.early .shot.card video { display: block; width: 100%; aspect-ratio: 1 / 1; object-fit: contain; padding: var(--s3); }

/* --- contact form: the submit button (a real <button> needs its border reset)
   and the quote questions as chips (F2: small option sets are chips) ------- */
.btn { border: 0; cursor: pointer; }
.contact-form .btn-primary { min-width: 200px; min-height: 52px; font-size: 17px; }
.contact-form .btn-primary:disabled { opacity: .6; cursor: progress; }
.contact-form fieldset { border: 0; padding: 0; margin: 0 0 var(--s5); min-width: 0; }
.contact-form legend { display: block; margin: 0 0 var(--s2); padding: 0; font-size: 15px; font-weight: 600; color: var(--ink); }
.contact-form legend .hint { font-weight: 400; color: var(--ink-2); }
.choice { display: flex; flex-wrap: wrap; gap: var(--s2); }
.choice legend { width: 100%; }
.contact-form .chip {
  display: inline-flex; align-items: center; gap: var(--s1); min-height: 44px; margin: 0;
  padding: 0 var(--s3); border: 1px solid #6F6893; border-radius: 999px;
  font-size: 15px; font-weight: 500; color: var(--ink-2); cursor: pointer;
  transition: border-color 150ms var(--ease), color 150ms var(--ease), background-color 150ms var(--ease);
}
.contact-form .chip input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.contact-form .chip:hover { border-color: var(--ink-2); color: var(--ink); }
.contact-form .chip:has(input:checked) { border-color: var(--accent); color: var(--ink); font-weight: 600; }  /* F4: border, colour and weight change; no tinted fill (AI-look ban) */
.contact-form .chip:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.quote-fields[hidden] { display: none; }
.contact-form textarea::placeholder { color: #6F6893; }

/* --- social icons: header (every size) and footer. One icon set, one size,
   currentColor so they follow the link colours (K3). 44 px tap targets. --- */
.nav-links .nav-social { display: flex; align-items: center; gap: 0; margin-left: var(--s2); }   /* far right, after the text links */
.social-icon {
  display: inline-flex !important; align-items: center; justify-content: center;
  width: 44px; min-height: 44px; color: var(--ink-2); background: none !important;
  transition: color 150ms var(--ease);
}
.social-icon:hover, .social-icon:focus-visible { color: var(--ink); }
.nav-links { gap: var(--s5); }
@media (max-width: 640px) {
  .nav-links { gap: var(--s1); }
  /* Phones: "What I can build" and "Contact" need the room. The same three links are in every footer. */
  .nav-links .nav-social { display: none; }
}
.footer .socials { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s1); margin: 0; }
.footer .footer-link { margin-left: var(--s2); }

/* --- CV detail blocks (2026-09-22): design list under the logo wall, the
   tools list, song credits. Same plain-list language as "Also built". ---- */
.design-more { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s8); margin-top: var(--s8); }
@media (max-width: 800px) { .design-more { grid-template-columns: 1fr; gap: 0; } }
.tools-head { margin: var(--s9) 0 var(--s5); font: 600 24px/1.25 var(--font); }
.tools { display: grid; grid-template-columns: 1fr 1fr; column-gap: var(--s8); row-gap: var(--s5); margin: 0; }
.tools div { border-top: 1px solid var(--line); padding-top: var(--s3); }
.tools dt { font-weight: 600; margin: 0 0 var(--s1); }
.tools dd { margin: 0; color: var(--ink-2); font-size: 15px; max-width: 60ch; }
@media (max-width: 800px) { .tools { grid-template-columns: 1fr; } }

.nav .social-icon svg { width: 15px; height: 15px; }   /* smaller glyphs in the header; the tap area stays 44 px tall */

/* --- menu button + panel, below 900 px (built by top.js, 2026-09-23) ------- */
.nav-toggle { display: none; }
@media (max-width: 899px) {
  .nav-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    width: 44px; height: 44px; margin: 0 -10px 0 var(--s1); padding: 0;
    background: none; border: 0; color: var(--ink); cursor: pointer;
  }
}
.nav-menu {
  position: fixed; inset: var(--nav-h) 0 auto 0; z-index: 49;
  max-height: calc(100svh - var(--nav-h)); overflow-y: auto; overscroll-behavior: contain;
  background: rgba(11, 10, 16, .97);
  padding: var(--s2) var(--pad) var(--s6);
}
.nav-menu[hidden] { display: none; }
.nav-menu ul { list-style: none; margin: 0 auto; padding: 0; max-width: var(--wrap); }
.nav-menu li a {
  display: flex; align-items: center; min-height: 52px;
  font: 600 22px/1.2 var(--font); color: var(--ink); text-decoration: none;
  transition: color 150ms var(--ease);
}
.nav-menu li a:hover, .nav-menu li a:focus-visible { color: var(--accent); }
.nav-menu-social { display: flex; gap: var(--s1); max-width: var(--wrap); margin: var(--s4) auto 0; margin-left: -10px; }
.nav-menu .social-icon svg { width: 20px; height: 20px; }
/* The narrowest phones (320 px): "Contact" moves into the menu, or the row runs into the logo. */
@media (max-width: 359px) { .nav-links li:has(> .nav-contact) { display: none; } }
html.nav-open { overflow: hidden; }   /* the page behind does not scroll while the menu is open */
@media (min-width: 900px) { .nav-menu { display: none !important; } }

/* --- 3D renders: a mixed-size grid, captions under each tile (no text on
   the render), every tile opens full size. ------------------------------- */
.render-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s5) var(--s3); }
.render { margin: 0; }
.render .g-tile { aspect-ratio: 1 / 1; }
.render.r-wide { grid-column: span 2; }
.render.r-wide .g-tile { aspect-ratio: 16 / 9; }
.render-grid { align-items: start; }
.render.r-full { grid-column: 1 / -1; }
.render.r-full .g-tile { aspect-ratio: 3 / 1; }
.render.r-contain .g-tile img { object-fit: contain; padding: var(--s3); }
.render figcaption { margin-top: var(--s2); font-size: 14px; color: var(--ink-2); }
.render figcaption strong { color: var(--ink); font-weight: 600; }
.g-zoom { position: absolute; right: var(--s2); bottom: var(--s2); width: 44px; height: 44px; border-radius: 50%; background: rgba(11, 10, 16, .72); display: grid; place-items: center; transition: background-color 150ms var(--ease); }
.g-zoom::before { content: ""; width: 12px; height: 12px; border: 2px solid var(--ink); border-radius: 50%; transform: translate(-2px, -2px); }
.g-zoom::after { content: ""; position: absolute; width: 7px; height: 2px; background: var(--ink); transform: translate(6px, 6px) rotate(45deg); }
.g-open:hover .g-zoom { background: var(--accent); }
.lb-body img.lb-logo { width: min(90vw, 80svh); height: min(90vw, 80svh); padding: 7%; object-fit: contain; background: var(--surface); }
.logo .g-open { cursor: zoom-in; }
.logo .g-open:focus-visible { outline: 2px solid var(--accent); outline-offset: -4px; }
.lb-body img { display: block; max-width: min(92vw, 1200px); max-height: 82svh; border-radius: var(--radius); background: var(--surface); }
@media (max-width: 800px) { .render-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } .render.r-wide { grid-column: 1 / -1; } .render.r-full .g-tile { aspect-ratio: 2 / 1; } }

/* --- case pages: gallery hero + grids of pieces with captions (2026-09-22) -- */
.case-hero .chapter-media { justify-self: stretch; }
.case-links { margin-top: var(--s6); }
.case-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s5) var(--s3); margin-top: var(--s7); }
.case-grid.case-grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.case-grid .g-tile { aspect-ratio: 16 / 9; }
.case-grid.case-grid-tall .g-tile { aspect-ratio: 4 / 5; }
.case-cap { margin: var(--s2) 0 0; font-size: 14px; color: var(--ink-2); }
.case-row p strong { color: var(--ink); font-weight: 600; }
@media (max-width: 800px) { .case-grid, .case-grid.case-grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 520px) { .case-grid, .case-grid.case-grid-2 { grid-template-columns: minmax(0, 1fr); } }
