/* ---------------------------------------------------------------------------
   Night work, one light on. Every value is a token below; the reasons are in
   design-system.md beside this site. The ground and the light are sampled from
   the Night Dock's own arrival frame: the hull at night and the one lit window.
   --------------------------------------------------------------------------- */
@font-face {
  font-family: "Newsreader";
  src: url("../fonts/newsreader-latin-opsz-normal.woff2") format("woff2");
  font-weight: 200 800; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Geist";
  src: url("../fonts/geist-latin-wght-normal.woff2") format("woff2");
  font-weight: 100 900; font-style: normal; font-display: swap;
}

:root {
  /* Colour: the dock at night, and the window. */
  --night:   #070d14;   /* the hull at night, 7/13/19 in the frame */
  --hull:    #0d1822;   /* a surface lifted off the night */
  --line:    rgba(236, 228, 216, 0.11);
  --mist:    #8c98a5;   /* secondary text, the mist's grey-blue; 6.6:1 on night */
  --ink:     #ece4d8;   /* the lamp's light on paper, 239/227/213 in the frame */
  --prose:   #c2beb8;   /* long reading text: About, a project page's sections */
  --soft:    #b9b6b0;   /* quieter serif: names, summaries, meta */
  --lamp:    #ffb366;   /* the light itself; used as light, never as a button colour */
  --ember:   #b98a5e;   /* the room's glow, where the light falls off */

  /* Type: one serif for the voice, one sans for the interface. */
  --serif: "Newsreader", "Iowan Old Style", Georgia, serif;
  --sans:  "Geist", system-ui, -apple-system, "Segoe UI", sans-serif;
  --t-small:   0.8125rem;                                    /* 13 */
  --t-ui:      0.9375rem;                                    /* 15 */
  --t-body:    1.1875rem;                                    /* 19 */
  --t-lead:    clamp(1.375rem, 1.05rem + 1.1vw, 2rem);       /* 22 to 32 */
  --t-h3:      clamp(1.625rem, 1.2rem + 1.5vw, 2.5rem);      /* 26 to 40 */
  --t-display: clamp(2.5rem, 1.2rem + 4.8vw, 6.5rem);        /* 40 to 104 */
  --t-mail:    clamp(1.9rem, 0.6rem + 5.6vw, 7.25rem);

  /* Space and measure. */
  --gutter: clamp(20px, 5vw, 80px);
  --max: 1440px;
  --section: clamp(120px, 16vw, 240px);

  /* Motion: one curve for arrivals (Moranta's expo out), opacity quicker than travel. */
  --ease-out: cubic-bezier(0.19, 1, 0.22, 1);
  --ease-io:  cubic-bezier(0.65, 0, 0.35, 1);
  --d-travel: 1000ms;
  --d-fade:   450ms;
}

*, *::before, *::after { box-sizing: border-box; }
html { background: var(--night); color: var(--ink); -webkit-text-size-adjust: 100%; }
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-stopped { overflow: hidden; }
body {
  margin: 0; background: var(--night); color: var(--ink);
  font-family: var(--serif); font-size: var(--t-body); line-height: 1.55;
  font-optical-sizing: auto; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility;
  overflow-x: hidden;
}
::selection { background: rgba(255, 179, 102, 0.35); color: #fff; }
a { color: inherit; }
p, h1, h2, h3, h4, blockquote, figure, dl, dd, ol, ul { margin: 0; }
ol, ul { padding: 0; list-style: none; }
img { display: block; max-width: 100%; height: auto; }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 5px; border-radius: 2px; }
/* Where an in-page link moves focus (site.js), the landing place takes focus without a ring. */
[tabindex="-1"]:focus { outline: none; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.skip { position: absolute; left: var(--gutter); top: -60px; z-index: 50; font: 500 var(--t-ui) var(--sans); background: var(--ink); color: var(--night); padding: 10px 14px; text-decoration: none; }
.skip:focus { top: 16px; }

.wrap { width: 100%; max-width: var(--max); margin: 0 auto; padding: 0 var(--gutter); position: relative; }
main, .contact { position: relative; z-index: 1; }

/* The one light that travels with the reader. site.js moves it between sections; without
   scripts it rests where the hero's light is. */
.lamp {
  position: fixed; z-index: 0; pointer-events: none;
  left: 0; top: 0; width: 120vmax; height: 120vmax;
  transform: translate(calc(72vw - 60vmax), calc(36vh - 60vmax));
  /* One smooth falloff, (1 - t^2)^3, reaching zero flat: three straight stops left a ring where
     the slope broke, about 500 px out (Brent's screen, 2026-09-29). Chrome dithers the gradient
     itself (measured, about half a level of grain), so no image is needed. */
  background: radial-gradient(closest-side, rgba(255, 179, 102, 0.1300) 0%, rgba(253, 178, 102, 0.1261) 10%, rgba(248, 175, 101, 0.1150) 20%, rgba(240, 170, 100, 0.0980) 30%, rgba(230, 165, 99, 0.0771) 40%, rgba(220, 159, 98, 0.0548) 50%, rgba(210, 152, 97, 0.0341) 60%, rgba(200, 147, 96, 0.0172) 70%, rgba(192, 142, 95, 0.0061) 80%, rgba(187, 139, 94, 0.0009) 90%, rgba(185, 138, 94, 0.0000) 100%);
  opacity: 0;
}
html.js .lamp { opacity: 1; }

/* ---------------------------------------------------------------- the bar */
.bar {
  position: fixed; z-index: 20; top: 0; left: 0; right: 0;
  display: flex; align-items: center; justify-content: space-between;
  padding: 22px var(--gutter);
  font-family: var(--sans); font-size: var(--t-ui); font-weight: 450;
  background: linear-gradient(to bottom, rgba(7, 13, 20, 0.85), rgba(7, 13, 20, 0));
}
.bar::before { content: ""; position: absolute; inset: 0; z-index: -1; background: rgba(7, 13, 20, 0.78); -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px); border-bottom: 1px solid var(--line); opacity: 0; transition: opacity var(--d-fade) ease; }
.bar.is-past::before { opacity: 1; }
.bar-home { display: block; color: var(--ink); opacity: 0; transition: opacity var(--d-fade) ease; }
.bar.is-past .bar-home, html:not(.js) .bar-home, .bar-home:focus-visible { opacity: 1; }
.mark-small { display: block; width: 132px; height: auto; fill: currentColor; }
.bar ul { display: flex; gap: clamp(18px, 2.6vw, 40px); }
.bar a { text-decoration: none; color: var(--ink); position: relative; padding: 6px 0; }
.bar nav a::after, .atmos-label::after {
  /* A line of the lamp's light, not ink (Brent, 2026-09-29, from Astra's page). */
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px; background: var(--lamp);
  box-shadow: 0 0 4px 1px rgba(255, 179, 102, 0.55), 0 0 14px 2px rgba(255, 179, 102, 0.22);
  transform: scaleX(0); transform-origin: right; transition: transform 500ms var(--ease-out);
}
.bar nav a:hover::after, .bar nav a:focus-visible::after,
.atmos:hover .atmos-label::after, .atmos:focus-visible .atmos-label::after { transform: scaleX(1); transform-origin: left; }

/* Pause atmosphere: holds the hero's mist still. Low on the first screen, over the dark water,
   away from the signature; the same line of light on hover as the nav. */
.atmos {
  position: absolute; z-index: 2; left: var(--gutter); top: calc(100svh - 76px);
  display: inline-flex; align-items: center; gap: 10px; padding: 8px 0; margin: 0;
  background: none; border: 0; cursor: pointer;
  font-family: var(--sans); font-size: var(--t-small); font-weight: 450; color: var(--mist);
  transition: color 300ms ease;
}
.atmos[hidden] { display: none; }
/* Row 3: a press answers at once, on touch too. The recording is 1300 px wide, so it gives less. */
.atmos { transition: color 300ms ease, transform 160ms var(--ease-out); }
.atmos:active, .osd-name:active { transform: scale(0.97); }
.screen--link:active { transform: scale(0.985); transition: transform 160ms var(--ease-out); }
.atmos:hover, .atmos:focus-visible { color: var(--ink); }
.atmos-label { position: relative; padding: 4px 0; }
.atmos-glyph { width: 8px; height: 10px; border-left: 2px solid currentColor; border-right: 2px solid currentColor; }
.atmos.is-held .atmos-glyph { border: 0; background: currentColor; clip-path: polygon(0 0, 100% 50%, 0 100%); }

/* ---------------------------------------------------------------- hero */
.hero {
  position: relative; min-height: 100svh; display: flex; align-items: flex-start;
  overflow: hidden; isolation: isolate;
  /* The poster behind the canvas: the same light, drawn in CSS, so the hero is lit
     without scripts and before the first frame. */
  background:
    radial-gradient(30vmax 22vmax at 80% 63.5%, rgba(255, 179, 102, 0.20), rgba(185, 138, 94, 0.06) 45%, rgba(7, 13, 20, 0) 75%),
    linear-gradient(to bottom, #04080c 0%, #0b1620 69.6%, #04080d 70.4%, #05090e 100%);
}
/* Where the canvas never comes (no scripts, no WebGL), the poster also carries the lamp itself and the
   light along the horizon under it. With scripts the lamp comes on in the opening instead. */
html:not(.js) .hero, html.no-gl .hero {
  background:
    radial-gradient(0.8vmax 0.8vmax at 80% 63.5%, #fff3e4, rgba(255, 210, 160, 0.8) 40%, rgba(255, 179, 102, 0) 100%),
    radial-gradient(5vmax 3vmax at 80% 63.5%, rgba(255, 179, 102, 0.28), rgba(255, 179, 102, 0) 100%),
    radial-gradient(18vmax 0.6vh at 80% 70%, rgba(255, 179, 102, 0.22), rgba(255, 179, 102, 0) 100%),
    radial-gradient(30vmax 22vmax at 80% 63.5%, rgba(255, 179, 102, 0.20), rgba(185, 138, 94, 0.06) 45%, rgba(7, 13, 20, 0) 75%),
    linear-gradient(to bottom, #04080c 0%, #0b1620 69.6%, #04080d 70.4%, #05090e 100%);
}
.mist { position: absolute; inset: 0; width: 100%; height: 100%; z-index: -1; opacity: 0; transition: opacity 1600ms ease; }
.mist.is-on { opacity: 1; }
/* The foot of the hero fades out rather than being painted to the night: the page under it is
   the same night at rest, and the travelling light shows through it as it leaves the hero. */
.hero { -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 22vh), transparent); mask-image: linear-gradient(to bottom, #000 calc(100% - 22vh), transparent); }
.hero-in { padding-top: max(120px, 22svh); padding-bottom: 12vh; }
.hero-name { font-size: inherit; font-weight: inherit; }
.sig { display: block; width: min(86vw, 1180px); height: auto; overflow: visible; }
/* The role line and the intro stand above the horizon (70 percent down), so on a short screen
   the name starts higher and is held to the height; from 760 px tall up it is as before. */
@media (min-width: 641px) and (max-height: 760px) { .hero-in { padding-top: max(96px, 17svh); } .sig { width: min(86vw, 1180px, 150svh); } }
.sig-ink, .sig-caps { fill: var(--ink); }
.sig-hot { fill: #ffd2a0; opacity: 0; }
html.js .sig-hot { filter: url(#sig-glow); }
.hero-line {
  margin-top: clamp(20px, 4svh, 48px); max-width: 22em;
  font-size: var(--t-lead); font-weight: 300; line-height: 1.3; color: var(--ink);
}
.hero-line-l { display: block; }
/* "AI to work." is lit by the lamp as the case's decision is: warmer ink and a glow, never a
   colour of its own, a clear step warmer than the line (round 4). site.js lights it with the pen's band after the capitals; without scripts, or under
   reduced motion, it is lit from the start. */
.hero-lit { position: relative; display: inline-block; white-space: nowrap; color: #ffdcb4; text-shadow: 0 0 16px rgba(255, 179, 102, 0.62), 0 0 56px rgba(255, 179, 102, 0.34); transition: text-shadow 1100ms var(--ease-out); }
html.js:not(.rm) .hero-lit:not(.is-lit) { color: var(--ink); }
html.js:not(.rm) .hero-lit:not(.is-lit):not(.is-lighting) { text-shadow: 0 0 16px rgba(255, 179, 102, 0), 0 0 56px rgba(255, 179, 102, 0); }
/* Round 4, change 1: the pen's slanted band of light crosses the three words once, left to right, and
   leaves them lit. site.js lays this copy of the words over them for the crossing and removes it after;
   left of the band the words are already lit, right of it the ink shows through. */
.hero-band {
  position: absolute; left: 0; top: 0; white-space: nowrap; pointer-events: none; -webkit-user-select: none; user-select: none;
  color: transparent; text-shadow: none;
  background: linear-gradient(112deg, #ffdcb4 0%, #ffdcb4 40%, #ffd2a0 45%, #fff6ea 48%, #fff6ea 50%, #ffd2a0 53%, rgba(255, 210, 160, 0) 58%);
  background-size: 300% 100%; background-position: 100% 0;
  -webkit-background-clip: text; background-clip: text;
}
/* The band alone, on a second copy, so its glow is the band's and not the lit words' (theirs is the
   text-shadow above, rising as the band sets out). */
.hero-band.is-hot {
  background-image: linear-gradient(112deg, rgba(255, 210, 160, 0) 0%, rgba(255, 210, 160, 0) 41%, #ffd2a0 45%, #fff8ee 48%, #fff8ee 50%, #ffd2a0 53%, rgba(255, 210, 160, 0) 58%);
  filter: drop-shadow(0 0 0.18em rgba(255, 200, 140, 0.9)) drop-shadow(0 0 0.6em rgba(255, 179, 102, 0.55));
}
/* The same light on a chapter's lit words ("You decide.", "One shared core."): it comes to rest on
   them once their heading has risen. The glow is set in em so it keeps its proportion at display size. */
.lit { color: #ffecd6; text-shadow: 0 0 0.3em rgba(255, 179, 102, 0.5), 0 0 0.9em rgba(255, 179, 102, 0.24); transition: color 1400ms ease, text-shadow 1800ms var(--ease-out); }
html.js:not(.rm) .lit:not(.is-lit) { color: inherit; text-shadow: 0 0 0.3em rgba(255, 179, 102, 0), 0 0 0.9em rgba(255, 179, 102, 0); }
.lit.is-settled, html:not(.js) .lit, html.rm .lit { transition: color 300ms ease, text-shadow 300ms ease; }
.hero-intro {
  margin-top: clamp(12px, 2svh, 22px); max-width: 30em;
  font-size: clamp(1rem, 0.9rem + 0.3vw, 1.1875rem); line-height: 1.55; color: var(--soft); text-wrap: pretty;   /* 16 to 19 */
}

/* ---------------------------------------------------------------- shared type */
.display {
  font-size: var(--t-display); font-weight: 300; line-height: 1.02; letter-spacing: -0.025em;
  max-width: 14em; text-wrap: balance;
}
.lede, .lead { font-size: var(--t-lead); font-weight: 300; line-height: 1.38; max-width: 30em; text-wrap: pretty; }
.body { font-size: var(--t-body); line-height: 1.6; max-width: 34em; color: var(--ink); text-wrap: pretty; }
.meta { font-family: var(--sans); font-size: var(--t-small); color: var(--mist); letter-spacing: 0.01em; }
.text-link {
  display: inline-block; margin-top: 22px; font-family: var(--sans); font-size: var(--t-ui); font-weight: 500;
  color: var(--ink); text-decoration: underline; text-decoration-color: rgba(236, 228, 216, 0.35);
  text-underline-offset: 6px; text-decoration-thickness: 1px; transition: text-decoration-color 300ms ease, color 300ms ease;
}
/* Row 2 of round 3's micro animations: on hover or focus the resting underline gives way to the nav's
   line of the lamp's light, drawn in over 500 ms (the nav's approved timing), and a leaving link's arrow
   moves 3 px along its own direction. */
.text-link { position: relative; }
.text-link::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -7px; height: 1px; background: var(--lamp);
  box-shadow: 0 0 4px 1px rgba(255, 179, 102, 0.55), 0 0 14px 2px rgba(255, 179, 102, 0.22);
  transform: scaleX(0); transform-origin: right; transition: transform 500ms var(--ease-out);
}
.text-link--out::after { right: 1.02em; }
.text-link-arrow { display: inline-block; width: 0.62em; height: 0.62em; margin-left: 0.4em; vertical-align: 0.05em; fill: none; stroke: currentColor; stroke-width: 1.3; stroke-linecap: round; stroke-linejoin: round; transition: transform 200ms var(--ease-out); }
.text-link:focus-visible { text-decoration-color: transparent; }
.text-link:focus-visible::after { transform: scaleX(1); transform-origin: left; }
@media (hover: hover) and (pointer: fine) {
  .text-link:hover { text-decoration-color: transparent; }
  .text-link:hover::after { transform: scaleX(1); transform-origin: left; }
  .text-link--out:hover .text-link-arrow { transform: translate(2px, -2px); }
}

section { position: relative; }

/* ---------------------------------------------------------------- work
   Three projects in one pattern: a title, one or two plain lines, the project large. */
.project { padding-top: var(--section); }
.project-head .lede { margin-top: clamp(24px, 2.6vw, 40px); color: var(--mist); }
.project-media { margin-top: clamp(48px, 6vw, 96px); }
.screen {
  position: relative; aspect-ratio: 1600 / 1000; width: min(100%, calc(78svh * 1.6)); margin: 0 auto;
  border-radius: 4px; overflow: hidden; border: 1px solid var(--line); background: var(--night);
  box-shadow: 0 60px 120px -60px rgba(0, 0, 0, 0.95);
}
.screen-poster, .screen-video { display: block; width: 100%; height: 100%; object-fit: cover; }
.screen-video { position: absolute; inset: 0; opacity: 0; transition: opacity 900ms ease; }
.screen-video.is-on { opacity: 1; }
.screen--link { display: block; color: var(--ink); text-decoration: none; transition: border-color 600ms ease, box-shadow 900ms var(--ease-out); }
.screen--link:hover, .screen--link:focus-visible { border-color: rgba(255, 179, 102, 0.35); box-shadow: 0 60px 120px -60px rgba(0, 0, 0, 0.95), 0 0 80px -20px rgba(255, 179, 102, 0.25); }
.screen-cue {
  position: absolute; z-index: 1; left: 50%; bottom: 24px; transform: translate(-50%, 8px); opacity: 0;
  font-family: var(--sans); font-size: var(--t-ui); font-weight: 500; padding: 10px 16px; border-radius: 3px;
  background: rgba(7, 13, 20, 0.72); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); border: 1px solid var(--line);
  transition: opacity var(--d-fade) ease, transform 700ms var(--ease-out);
}
.screen--link:hover .screen-cue, .screen--link:focus-visible .screen-cue { opacity: 1; transform: translate(-50%, 0); }
@media (hover: none) { .screen-cue { opacity: 1; transform: translate(-50%, 0); } }
/* On a phone the whole dashboard is too small to read; the square keeps the galaxy and Claude. */
@media (max-width: 640px) { .screen { aspect-ratio: 1; } .screen-poster, .screen-video { object-position: 47% 50%; } }

/* The demo, in one screen: the case's four steps in a row under the dashboard. site.js lights
   them one after another, left to right, and the light ends on the person deciding. Without
   scripts, or under reduced motion, they are all lit. */
.demo { margin-top: clamp(56px, 6vw, 96px); display: grid; gap: clamp(24px, 2.6vw, 36px); }
.demo-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 6px 24px; }
/* The row takes the recording's width, so the steps read as its caption. */
@media (min-width: 900px) { .demo { max-width: calc(min(var(--max) - 2 * var(--gutter), 78svh * 1.6) + 2 * var(--gutter)); } }
.demo-title { font-size: var(--t-h3); font-weight: 350; line-height: 1.1; letter-spacing: -0.01em; }
.demo-sub { font-family: var(--sans); font-size: var(--t-small); color: var(--mist); }
.demo-steps { position: relative; display: grid; gap: 22px; padding-left: 24px; }
.demo-steps::before, .demo-steps::after { content: ""; position: absolute; left: 0; top: 0; width: 1px; }
.demo-steps::before { bottom: 0; background: var(--line); }
.demo-step { font-size: clamp(1.25rem, 1rem + 0.55vw, 1.5rem); font-weight: 300; line-height: 1.25; text-wrap: balance; }
.demo-n { display: block; margin-bottom: 6px; font-family: var(--sans); font-size: var(--t-small); color: var(--mist); font-variant-numeric: tabular-nums; }
.demo .text-link { margin-top: 8px; justify-self: start; }
html.js:not(.rm) .demo-steps::after { height: calc(100% * var(--p, 0)); background: linear-gradient(to bottom, rgba(255, 179, 102, 0), var(--lamp)); box-shadow: 0 0 12px var(--lamp); }
@media (min-width: 900px) {
  .demo-steps { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: clamp(20px, 2.4vw, 40px); padding: 26px 0 0; }
  .demo-steps::before, .demo-steps::after { top: 0; left: 0; bottom: auto; height: 1px; }
  .demo-steps::before { right: 0; width: auto; }
  html.js:not(.rm) .demo-steps::after { height: 1px; width: calc(100% * var(--p, 0)); background: linear-gradient(to right, rgba(255, 179, 102, 0), var(--lamp)); }
}
html.js:not(.rm) .demo-step { opacity: 0.26; transition: opacity 700ms ease, color 1200ms ease, text-shadow 1200ms var(--ease-out); }
html.js:not(.rm) .demo-step.is-lit { opacity: 1; }
/* The last step is the person deciding: the one light comes to rest on it. */
.demo-step.is-decision.is-lit, html:not(.js) .demo-step.is-decision, html.rm .demo-step.is-decision { color: #fff3e4; text-shadow: 0 0 28px rgba(255, 179, 102, 0.45); }

/* A chapter's title is the way to the project's page; it reads as the heading it is, and the
   text link under the chapter says the same thing in words. */
.chapter-title a { color: inherit; text-decoration: none; padding-block: 0.04em; }
/* Row 1: a chapter title that is a link warms, its lit words' glow rises one step, and the nav's line of
   light draws under its last line (site.js measures that line; without it, under the whole title). */
.chapter-title, .pp-next-t { position: relative; }
.chapter-title a, .pp-next a { transition: color 300ms ease; }
.chapter-title::after, .pp-next-t::after {
  content: ""; position: absolute; left: var(--ul-x, 0); top: var(--ul-y, 100%); width: var(--ul-w, 100%); height: 1px; background: var(--lamp);
  box-shadow: 0 0 4px 1px rgba(255, 179, 102, 0.55), 0 0 14px 2px rgba(255, 179, 102, 0.22);
  transform: scaleX(0); transform-origin: right; transition: transform 500ms var(--ease-out); pointer-events: none;
}
.chapter-title:has(a:focus-visible) a, .pp-next a:focus-visible { color: #fff3e4; }
.chapter-title:has(a:focus-visible)::after, .pp-next a:focus-visible .pp-next-t::after { transform: scaleX(1); transform-origin: left; }
.chapter-title a:focus-visible .lit.is-lit { text-shadow: 0 0 0.3em rgba(255, 179, 102, 0.68), 0 0 1em rgba(255, 179, 102, 0.34); }
@media (hover: hover) and (pointer: fine) {
  .chapter-title a:hover, .pp-next a:hover { color: #fff3e4; }
  .chapter-title:has(a:hover)::after, .pp-next a:hover .pp-next-t::after { transform: scaleX(1); transform-origin: left; }
  .chapter-title a:hover .lit.is-lit { text-shadow: 0 0 0.3em rgba(255, 179, 102, 0.68), 0 0 1em rgba(255, 179, 102, 0.34); }
}
.chapter-on { display: flex; flex-wrap: wrap; gap: 8px 32px; }
.chapter-on-wrap { margin-top: clamp(28px, 3vw, 44px); }
.chapter-on .text-link { margin-top: 0; }

/* ---------------------------------------------------------------- the 3D site */
.dock-track { margin-top: clamp(48px, 6vw, 96px); }
.dock-fig figcaption { margin-top: 18px; font-family: var(--sans); font-size: var(--t-small); color: var(--mist); max-width: 60em; }
.compare { position: relative; display: grid; grid-template-columns: 1fr; gap: 16px; }
.compare img { width: 100%; border-radius: 3px; }
.compare-edge, .compare-tag { display: none; }
@media (min-width: 700px) { .compare { grid-template-columns: 1fr 1fr; } }
html.st .dock-track { height: 170vh; }
html.st .dock-track .dock-fig { position: sticky; top: 0; min-height: 100vh; display: flex; flex-direction: column; justify-content: center; }
html.st .dock-track .compare { display: block; aspect-ratio: 1200 / 750; max-height: 78vh; margin: 0 auto; width: min(100%, calc(78vh * 1.6)); border-radius: 3px; overflow: hidden; box-shadow: 0 60px 120px -60px rgba(0, 0, 0, 0.95); }
html.st .dock-track .compare img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border-radius: 0; }
html.st .dock-track .compare .is-after { clip-path: inset(0 0 0 calc(var(--w, 1) * 100%)); }
html.st .dock-track .compare-edge { display: block; position: absolute; top: 0; bottom: 0; left: calc(var(--w, 1) * 100%); width: 1px; background: #ffe2c2; box-shadow: 0 0 18px 3px rgba(255, 179, 102, 0.8), 0 0 60px 10px rgba(255, 179, 102, 0.25); opacity: calc(var(--w, 1) * (1 - var(--w, 1)) * 5); }
html.st .dock-track .compare-tag { display: block; position: absolute; bottom: 16px; font-family: var(--sans); font-size: var(--t-small); color: var(--ink); background: rgba(7, 13, 20, 0.6); padding: 5px 10px; border-radius: 2px; backdrop-filter: blur(6px); }
/* Each tag only while its picture holds that side: Previs fades as the wipe's edge reaches it, so it never sits on the
   finished render (or over its baked-in name on a phone); Last build arrives once the build has its side. */
html.st .dock-track .is-before-tag { left: 16px; opacity: clamp(0, calc((var(--w, 1) - 0.15) * 6), 1); }
html.st .dock-track .is-after-tag { right: 16px; opacity: clamp(0, calc((0.85 - var(--w, 1)) * 6), 1); }
html.st .dock-track .dock-fig figcaption { margin-left: auto; margin-right: auto; width: min(100%, calc(78vh * 1.6)); max-width: none; }
html.st.rm .dock-track { height: auto; }
html.st.rm .dock-track .dock-fig { position: static; min-height: 0; }
html.st.rm .dock-track .compare { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; aspect-ratio: auto; max-height: none; width: 100%; overflow: visible; box-shadow: none; }
html.st.rm .dock-track .compare img { position: static; height: auto; clip-path: none !important; }
html.st.rm .dock-track .compare-edge, html.st.rm .dock-track .compare-tag { display: none; }

/* ---------------------------------------------------------------- os */
.os-stage { margin-top: clamp(48px, 6vw, 96px); }

.os-list { display: grid; gap: 14px; font-family: var(--sans); font-size: var(--t-ui); color: var(--mist); border-top: 1px solid var(--line); padding-top: 24px; }
.os-list strong { color: var(--ink); font-weight: 500; margin-right: 8px; }

/* The drawing (round 3): two sources above, their light running down into the core, the scopes as
   ground the light falls on. Shown with scripts from 900 px; otherwise the list above says the same.
   Sizes are in container units, so the labels scale with the lines. */
.osd { display: none; position: relative; container-type: inline-size; max-width: 1200px; margin: 0 auto; }
@media (min-width: 900px) {
  html.js .osd { display: block; }
  html.js .os-list { display: none; }
}
.osd-svg { display: block; width: 100%; height: auto; overflow: visible; }
.osd-path { fill: none; stroke: rgba(255, 179, 102, 0.42); stroke-width: 1.5; stroke-dasharray: 1; stroke-dashoffset: 0; }
.osd-path--out { stroke: rgba(255, 179, 102, 0.26); stroke-width: 1.2; }
.osd-src { fill: var(--lamp); filter: drop-shadow(0 0 6px rgba(255, 179, 102, 0.8)); }
.osd-core { fill: #fff4e6; }
.osd-part { position: absolute; width: max-content; }
.osd-part--left { transform: translate(-100%, -50%); text-align: right; }
.osd-part--right, .osd-part--core { transform: translate(0, -50%); text-align: left; }
.osd-part--below { transform: translate(-50%, 0); text-align: center; }
.osd-name {
  display: inline-block; margin: -0.25em -0.3em; padding: 0.25em 0.3em; border: 0; border-radius: 2px; background: none; cursor: pointer;
  font-family: var(--serif); font-size: max(18px, 2.6cqw); font-weight: 350; line-height: 1.1; letter-spacing: -0.01em; color: var(--ink);
}
.osd-name:focus-visible { outline-offset: 2px; }
/* Round 4, change 2: the two pools are links to their projects' pages. Lit like the other parts, and
   the nav's line of light draws under the name (500 ms, the nav's approved timing). */
.osd-name--link { position: relative; text-decoration: none; }
.osd-name--link::after {
  content: ""; position: absolute; left: 0.3em; right: 0.3em; bottom: 0.14em; height: 1px; background: var(--lamp);
  box-shadow: 0 0 4px 1px rgba(255, 179, 102, 0.55), 0 0 14px 2px rgba(255, 179, 102, 0.22);
  transform: scaleX(0); transform-origin: right; transition: transform 500ms var(--ease-out);
}
.osd-part.is-on .osd-name--link::after { transform: scaleX(1); transform-origin: left; }
/* The pool of light above the name is part of the link, so pointing at the light itself lights it and opens it. */
.osd-name--link::before { content: ""; position: absolute; left: 50%; bottom: 100%; width: 30cqw; height: 5.5cqw; transform: translateX(-50%); }
.os-list-link { margin-right: 8px; font-weight: 500; color: var(--ink); text-decoration: underline; text-decoration-color: rgba(236, 228, 216, 0.35); text-underline-offset: 5px; text-decoration-thickness: 1px; }
.os-list-link:hover, .os-list-link:focus-visible { text-decoration-color: var(--lamp); }
.osd-part--core .osd-name { font-size: max(22px, 3.4cqw); font-weight: 300; color: #ffe7cc; }
.osd-line { display: block; margin-top: 0.4cqw; font-family: var(--sans); font-size: max(13px, 1.3cqw); color: var(--mist); }
/* Words that may sit over a line of light keep a little night around them, so they stay readable. */
.osd-line, .osd-note { text-shadow: 0 0 3px var(--night), 0 0 8px var(--night), 0 0 14px var(--night); }
.osd-note {
  position: absolute; top: 100%; margin-top: max(10px, 1cqw); width: max-content; max-width: 24cqw; pointer-events: none; opacity: 0;
  font-family: var(--sans); font-size: max(13px, 1.2cqw); line-height: 1.4; color: var(--mist); text-wrap: balance;
}
.osd-part--left .osd-note { right: 0; }
.osd-part--right .osd-note, .osd-part--core .osd-note { left: 0; }
.osd-part--below .osd-note { left: 50%; --nx: -50%; }
/* Row 4: the path to the core lights in 220 ms; the note comes in from 4 px below in 200 ms. */
.osd-path { transition: stroke 220ms ease, filter 220ms ease; }
.osd-name { transition: color 220ms ease, text-shadow 220ms ease, transform 160ms var(--ease-out); }
.osd-note { transform: translate(var(--nx, 0), 4px); transition: opacity 200ms var(--ease-out), transform 200ms var(--ease-out); }
.osd-part.is-on .osd-note { transform: translate(var(--nx, 0), 0); }
/* A part that is on (hovered, focused, or opened by a press): its path to the core lights, its name
   warms and its note shows. The core lights every path. site.js keeps data-on. */
.osd-part.is-on .osd-note { opacity: 1; }
.osd-part.is-on .osd-name { color: #fff3e4; text-shadow: 0 0 0.4em rgba(255, 179, 102, 0.45); }
.osd[data-on~="rt0"] .osd-path[data-part="rt0"], .osd[data-on~="rt1"] .osd-path[data-part="rt1"],
.osd[data-on~="sc0"] .osd-path[data-part="sc0"], .osd[data-on~="sc1"] .osd-path[data-part="sc1"],
.osd[data-on~="core"] .osd-path { stroke: var(--lamp); filter: drop-shadow(0 0 4px rgba(255, 179, 102, 0.7)); }
/* Drawn on scroll: the sources first, their light reaching the core by halfway, then the core's light
   running down to the ground. A part with focus is always shown. */
html.js:not(.rm) .osd-path--in { stroke-dashoffset: calc(1 - clamp(0, var(--draw, 0) * 2, 1)); }
html.js:not(.rm) .osd-path--out { stroke-dashoffset: calc(1 - clamp(0, var(--draw, 0) * 2 - 1, 1)); }
html.js:not(.rm) .osd-src, html.js:not(.rm) .osd-part--left, html.js:not(.rm) .osd-part--right { opacity: clamp(0, var(--draw, 0) * 4, 1); }
html.js:not(.rm) .osd-part--core { opacity: clamp(0, (var(--draw, 0) - 0.4) * 4, 1); }
html.js:not(.rm) .osd-part--below { opacity: clamp(0, (var(--draw, 0) - 0.8) * 5, 1); }
html.js:not(.rm) .osd-part:focus-within, html.js:not(.rm) .osd-part:has([aria-pressed="true"]) { opacity: 1; }
html.js:not(.rm) .osd-halo { transform-box: fill-box; transform-origin: center; transform: scale(calc(0.4 + var(--draw, 0) * 0.6)); opacity: calc(0.3 + var(--draw, 0) * 0.7); }

/* ---------------------------------------------------------------- a project's own page
   The chapter's title first, then the project large, a few short sections, its links, and the
   next project. The bar is solid from the start, since there is no hero under it. */
.pp-head { padding-top: clamp(150px, 24vh, 280px); }
.pp-head .lede { margin-top: clamp(24px, 2.6vw, 40px); color: var(--mist); }
.pp .project-media, .pp-fig, .pp-os { margin-top: clamp(56px, 7vw, 112px); }
.pp-fig figcaption { margin-top: 18px; font-family: var(--sans); font-size: var(--t-small); color: var(--mist); }
.pp-body { margin-top: var(--section); display: grid; gap: clamp(56px, 6vw, 96px); }
.pp-section { display: grid; gap: 18px; max-width: 34em; }
.pp-h { font-size: var(--t-h3); font-weight: 350; line-height: 1.1; letter-spacing: -0.01em; }
.pp-section .body { color: var(--mist); }
/* From 900 px each section is a heading on the left and its text on the right, the split About uses,
   so the text keeps its measure and the width under the project's image is not left empty. The links
   line up with the text. */
.pp-text { display: grid; gap: 1.1em; }
@media (min-width: 900px) {
  .pp-section, .pp-links { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); column-gap: clamp(40px, 6vw, 120px); align-items: baseline; }
  .pp-section { max-width: none; }
  .pp-links { display: grid; }
  .pp-links-in { grid-column: 2; }
  .pp-section .body { max-width: 34em; }
}
/* The links sit twice the sections' gap below them, so they read as the page's way on, not a section. */
.pp-links { margin-top: clamp(112px, 12vw, 192px); }
.pp-links-row { display: flex; flex-wrap: wrap; gap: 8px 32px; }
.pp-credit { margin-bottom: 20px; font-family: var(--sans); font-size: var(--t-small); color: var(--mist); }
.pp-links .text-link { margin-top: 0; }
.pp-next { margin-top: var(--section); }
.pp-next a { display: grid; justify-items: start; gap: 10px; padding-top: 28px; border-top: 1px solid var(--line); text-decoration: none; color: var(--ink); }
.pp-next-k { font-family: var(--sans); font-size: var(--t-small); color: var(--mist); }
/* A step down from the page's title, so the page does not end as loud as it opens. */
.pp-next-t { font-size: var(--t-h3); font-weight: 300; line-height: 1.1; letter-spacing: -0.01em; }

/* ---------------------------------------------------------------- about */
.about { padding-top: var(--section); }
.about-grid { display: grid; gap: 48px; }
.portrait { position: relative; max-width: 520px; }
.portrait img {
  width: 100%;
  -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 22%, #000 78%, transparent 100%), linear-gradient(to bottom, transparent 0%, #000 12%, #000 72%, transparent 100%);
  -webkit-mask-composite: source-in;
          mask-image: linear-gradient(to right, transparent 0%, #000 22%, #000 78%, transparent 100%), linear-gradient(to bottom, transparent 0%, #000 12%, #000 72%, transparent 100%);
          mask-composite: intersect;
}
.about-text .prose { margin-top: 36px; display: grid; gap: 1.1em; max-width: 29em; color: var(--prose); }
.facts { margin-top: 44px; display: grid; gap: 0; font-family: var(--sans); font-size: var(--t-ui); border-top: 1px solid var(--line); max-width: 40em; }
.facts div { display: grid; grid-template-columns: 9.5em 1fr; gap: 16px; padding: 14px 0; border-bottom: 1px solid var(--line); }
.facts dt { color: var(--mist); }
@media (min-width: 900px) {
  .about-grid { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: clamp(40px, 6vw, 120px); align-items: start; }
  .about-text { padding-top: 6vh; }
}

/* ---------------------------------------------------------------- contact */
.contact { padding: var(--section) 0 40px; }
.contact-title { font-family: var(--sans); font-size: var(--t-ui); font-weight: 450; color: var(--mist); }
.mail {
  display: inline-block; margin-top: 18px; font-size: var(--t-mail); font-weight: 300; line-height: 1.05; letter-spacing: -0.03em;
  text-decoration: none; color: var(--ink); overflow-wrap: anywhere;
  transition: color 600ms ease, text-shadow 900ms var(--ease-out);
}
.mail:hover, .mail:focus-visible { color: #fff3e4; text-shadow: 0 0 28px rgba(255, 179, 102, 0.55), 0 0 90px rgba(255, 179, 102, 0.3); }
.contact-line { margin-top: 24px; color: var(--mist); font-size: var(--t-body); }
.contact-links { margin-top: 28px; display: flex; gap: 32px; font-family: var(--sans); font-size: var(--t-ui); }
.contact-links a { text-decoration: underline; text-decoration-color: rgba(236, 228, 216, 0.35); text-underline-offset: 6px; }
.contact-links a:hover { text-decoration-color: var(--ink); }
.foot { margin-top: clamp(96px, 12vw, 200px); padding-top: 24px; border-top: 1px solid var(--line); display: flex; justify-content: space-between; align-items: center; font-family: var(--sans); font-size: var(--t-small); color: var(--mist); }
.foot .mark-small { width: 110px; color: var(--mist); }

/* ---------------------------------------------------------------- motion on scroll
   Keyed off html.st (GSAP running) and not .rm, so without GSAP or with reduced motion
   nothing waits for a script that will not come. site.js adds the classes named here. */

/* Titles stay readable throughout entry. No line masks or hidden pre-font state. */
[data-lines]:focus-within { opacity: 1 !important; }

/* The project images open from a slit of light, like a shutter, once. */
html.st:not(.rm) [data-shutter]:not(.is-open) { clip-path: inset(calc((1 - var(--o, 0)) * 50% - 1px) 0 round 4px); }
html.st:not(.rm) [data-shutter]:not(.is-open)::after {
  content: ""; position: absolute; z-index: 2; left: 0; right: 0; top: 50%; height: 2px; margin-top: -1px; pointer-events: none;
  background: linear-gradient(90deg, rgba(255, 179, 102, 0), #ffe2c2 18%, #fff4e6 50%, #ffe2c2 82%, rgba(255, 179, 102, 0));
  box-shadow: 0 0 18px 4px rgba(255, 179, 102, 0.55);
  opacity: calc((1 - var(--o, 0)) * (1 - var(--o, 0)));
}

/* ---------------------------------------------------------------- arrivals
   Only with scripts and without reduced motion, and keyed off one attribute so the
   pre-state and the arrival share a selector. site.js adds .is-in. */
html.js:not(.rm) [data-reveal] { opacity: 0; transform: translateY(36px); transition: opacity 700ms ease, transform 1200ms var(--ease-out); }
html.js:not(.rm) [data-reveal].is-in { opacity: 1; transform: none; }

/* Row 5, between pages: a cross-document view transition. The project's title travels from the chapter
   to the page's head (and back) in 380 ms on the page's arrival curve; the rest crossfades in 250 ms;
   the bar holds still. Browsers without it simply navigate; under reduced motion there is none. */
@view-transition { navigation: auto; }
@media (prefers-reduced-motion: reduce) { @view-transition { navigation: none; } }
.bar { view-transition-name: bar; }
.chapter-title, .pp-title, .feature-title { view-transition-class: title; }
::view-transition-group(*.title) { animation-duration: 380ms; animation-timing-function: var(--ease-out); }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 250ms; }
/* The title is the same line on both pages, so it travels as one piece: the arriving title alone, with
   no crossfade inside it (the two boxes differ a little and would show a double). */
::view-transition-old(*.title) { display: none; }
::view-transition-new(*.title) { animation: none; }
/* A title with no partner on the page left (reached from the drawing's pools, or by Next) fades in with
   the rest instead of appearing at once over the old page (round 4, change 2). */
::view-transition-new(*.title):only-child { animation: vt-title-in 250ms ease both; }
@keyframes vt-title-in { from { opacity: 0; } }
/* And one with no partner on the page arrived at (a pool clicked on the Brent OS page) fades out with the
   rest rather than vanishing on the first frame. */
::view-transition-old(*.title):only-child { display: block; animation: vt-title-out 250ms ease both; }
@keyframes vt-title-out { to { opacity: 0; } }
html.vt-in [data-lines][style*="view-transition-name"] { visibility: visible !important; opacity: 1 !important; }

/* Under reduced motion the colour and light of every hover stays and nothing moves. */
html.rm .text-link-arrow, html.rm .osd-note, html.rm .atmos, html.rm .osd-name, html.rm .screen--link { transition-property: color, opacity, text-shadow, stroke; }
html.rm .text-link--out:hover .text-link-arrow, html.rm .atmos:active, html.rm .osd-name:active, html.rm .screen--link:active { transform: none; }
html.rm .osd-note, html.rm .osd-part.is-on .osd-note { transform: translate(var(--nx, 0), 0); }

@media (max-width: 640px) {
  .bar { padding-top: 16px; padding-bottom: 16px; }
  .bar ul { gap: 16px; font-size: var(--t-small); }
  .mark-small { width: 96px; }
  .hero-in { padding-top: 14vh; }
  .facts div { grid-template-columns: 1fr; gap: 2px; }
}

/* Collection architecture: the hero is the spectacle; work has room to be understood. */
:root {
  --work-space: clamp(72px, 10vw, 144px);
  --feature-type: clamp(2.875rem, 1.45rem + 3.8vw, 4.75rem);
  --support-type: clamp(2rem, 1.4rem + 1.6vw, 2.625rem);
  --work-meta: 0.875rem;
}
[id] { scroll-margin-top: max(110px, 6.5rem); }
.section-label { font: 450 var(--work-meta)/1.5 var(--sans); color: var(--mist); }
.curated { padding-top: 64px; }
.section-head { display: flex; align-items: baseline; justify-content: space-between; gap: 24px; padding-bottom: 36px; border-bottom: 1px solid var(--line); }
.section-head .section-label { color: var(--ink); font-size: 18px; }
.section-head .text-link, .project-actions .text-link { margin-top: 0; }
.feature { display: grid; gap: 48px; padding-block: 52px; }
.feature-copy, .feature-visual { min-width: 0; }
.feature-title, .feature-name, .pp-title, .catalogue-copy h2 { overflow-wrap: anywhere; }
.feature-lead { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: 48px clamp(40px, 5vw, 88px); }
.feature-lead .feature-visual { align-self: center; }
.project-meta { display: flex; flex-wrap: wrap; gap: 8px 24px; color: var(--mist); font: 400 var(--work-meta)/1.5 var(--sans); }
.project-status { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; }
.project-status::before { content: ''; width: 5px; height: 5px; border-radius: 50%; background: currentColor; opacity: .7; }
.feature-name { font: 450 17px/1.5 var(--sans); margin-top: 38px; }
.feature-title { position: relative; font-size: var(--feature-type); font-weight: 300; line-height: 1.06; letter-spacing: -.025em; margin-top: 16px; max-width: 13ch; text-wrap: balance; }
.feature-title a, .catalogue-copy h2 a { text-decoration: none; transition: color 220ms ease; }
.feature-title a:hover, .feature-title a:focus-visible, .catalogue-copy h2 a:hover { color: #fff3e4; }
.feature-title::after {
  content: ''; position: absolute; left: var(--ul-x, 0); top: var(--ul-y, 100%); width: var(--ul-w, 100%); height: 1px; background: var(--lamp); pointer-events: none;
  box-shadow: 0 0 4px 1px rgba(255,179,102,.55), 0 0 14px 2px rgba(255,179,102,.22);
  transform: scaleX(0); transform-origin: right; transition: transform 500ms var(--ease-out);
}
.feature-title:has(a:focus-visible)::after { transform: scaleX(1); transform-origin: left; transition: none; }
html.st:not(.rm) .feature-title:not(.is-done)::after { opacity: 0; }
@media (hover: hover) and (pointer: fine) {
  .feature-title:has(a:hover)::after { transform: scaleX(1); transform-origin: left; }
  .feature-title a:hover .lit.is-lit { text-shadow: 0 0 .3em rgba(255,179,102,.68), 0 0 1em rgba(255,179,102,.34); }
}
/* New arrivals reuse the original masked heading language, with less travel for evidence.
   Ordinary scroll reveals run once. Focus always exposes the link immediately. */
html.js:not(.rm) .feature [data-reveal], html.js:not(.rm) .catalogue [data-reveal] {
  transform: translateY(24px); transition: opacity 650ms ease, transform 1200ms var(--ease-out);
}
html.js:not(.rm) .feature [data-reveal].is-in, html.js:not(.rm) .catalogue [data-reveal].is-in { opacity: 1; transform: none; }
html.rm .feature-title::after { transition: none; }
.feature-summary { max-width: 34em; color: var(--mist); margin-top: 28px; font-size: 21px; line-height: 1.55; text-wrap: pretty; }
.project-actions { display: flex; align-items: baseline; flex-wrap: wrap; gap: 18px 28px; margin-top: 28px; }
.work-preview { display: block; position: relative; text-decoration: none; color: var(--ink); }
.preview-frame { display: block; position: relative; overflow: hidden; border: 1px solid var(--line); border-radius: 2px; }
.work-preview img { width: 100%; aspect-ratio: 1.6; object-fit: cover; }
.feature-lead .preview-frame { box-shadow: 0 28px 56px -36px #000; }
.preview-action { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding-block: 16px; font: 450 var(--work-meta)/1.5 var(--sans); }
.preview-action > span:first-child { text-decoration: underline; text-decoration-color: rgba(236,228,216,.35); text-underline-offset: 5px; }
.preview-action > span:last-child { color: var(--lamp); font-size: 20px; transition: transform 500ms var(--ease-out); }
.work-preview:focus-visible { outline-offset: 7px; }
.work-preview:hover .preview-action > span:first-child { text-decoration-color: var(--lamp); }
@media (hover: hover) and (pointer: fine) {
  .work-preview:hover .preview-action > span:last-child { transform: translate(3px, -3px); }
}
.evidence { position: relative; padding-top: 24px; margin-top: 20px; border-top: 1px solid var(--line); }
.evidence h4 { font-size: 28px; font-weight: 350; line-height: 1.2; margin-top: 14px; letter-spacing: -.015em; }
.evidence-copy > p { margin-top: 14px; max-width: 52ch; color: var(--mist); }
.evidence .evidence-note { font: 400 13px/1.6 var(--sans); }
.feature-lead > .evidence { grid-column: 1 / -1; display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: clamp(40px, 5vw, 88px); margin: 0; padding-top: 24px; }
.feature-lead > .evidence .evidence-copy > p:first-child { margin-top: 0; }
.feature-lead > .evidence::before { content: ''; position: absolute; top: -1px; left: 0; width: 100%; height: 1px; background: var(--lamp); transform-origin: left; }
html.js:not(.rm) .feature-lead > .evidence::before { transform: scaleX(0); transition: transform 1500ms var(--ease-out) 300ms; }
html.js:not(.rm) .feature-lead > .evidence.is-in::before { transform: scaleX(1); }
.core-trace { display: grid; grid-template-columns: auto minmax(12px, 1fr) auto minmax(12px, 1fr) auto; align-items: center; gap: 12px; margin: 32px 0; padding-block: 14px; font: 400 .8125rem/1.5 var(--sans); color: var(--mist); text-decoration: none; }
.core-trace-node { position: relative; padding: 14px 8px; color: var(--ink); font: 400 1.375rem/1.2 var(--serif); white-space: nowrap; transition: color 220ms, text-shadow 400ms; }
.core-trace-node::before { content: ''; position: absolute; width: 5px; height: 5px; border-radius: 50%; background: var(--lamp); top: -5px; left: calc(50% - 2.5px); box-shadow: 0 0 12px rgba(255,179,102,.5); }
.core-connection { position: relative; height: 1px; background: rgba(255,179,102,.28); }
.core-connection::after { content: ''; display: block; height: 1px; background: var(--lamp); transform: scaleX(0); transform-origin: left; transition: transform 700ms var(--ease-out); }
.core-connection:nth-last-child(2)::after { transform-origin: right; }
.core-trace:is(:hover, :focus-visible) .core-connection::after { transform: scaleX(1); }
.core-trace:is(:hover, :focus-visible) .core-trace-node { color: #fff3e4; text-shadow: 0 0 22px rgba(255,179,102,.7); }
.supporting-work { border-top: 1px solid var(--line); margin-top: 32px; }
.feature-support { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: clamp(40px, 5vw, 88px); padding-block: 64px; }
.feature-support .feature-title { font-size: var(--support-type); max-width: 18ch; }
.feature-support .feature-name { margin-top: 24px; }
.feature-support .feature-summary { font-size: 19px; }
.feature-support .feature-visual { align-self: center; }
.feature-support .evidence { margin: 0; border: 0; border-inline-start: 1px solid rgba(255,179,102,.28); padding: 8px 0 8px 40px; }
.feature-support .evidence h4 { font-size: 32px; max-width: 20ch; }
.supporting-work:has(.feature-support:nth-child(2)) { display: grid; grid-template-columns: 1fr 1fr; gap: 56px; }
.supporting-work:has(.feature-support:nth-child(2)) .feature-support { grid-template-columns: 1fr; gap: 32px; align-content: start; }
.supporting-work:has(.feature-support:nth-child(2)) .feature-visual { align-self: start; }
.feature:has(.feature-visual:empty) { grid-template-columns: 1fr; }
.feature-visual:empty { display: none; }
.collection-link { display: flex; justify-content: space-between; gap: 24px; align-items: baseline; padding-block: 30px; border-block: 1px solid var(--line); }
.collection-link p { font-size: 24px; font-weight: 300; }
.collection-link .text-link { margin: 0; }
.legacy-project { display: none; }
.legacy-project:target { display: block; padding-top: 12px; }
.about { padding-top: var(--work-space); }
.about-text { padding-top: 24px; }
.about-text .lead { margin-top: 24px; font-size: clamp(28px, 2.7vw, 40px); line-height: 1.2; }
.about-text .prose { margin-top: 28px; }
.about-grid { grid-template-columns: minmax(0, 4fr) minmax(0, 7fr); gap: clamp(48px, 7vw, 112px); align-items: center; }
.portrait { max-width: 400px; }
.facts { margin-top: 28px; }
.contact { padding-top: var(--work-space); }
.contact .wrap { padding-top: 36px; }
.mail { font-size: clamp(28px, 4.8vw, 64px); }
.foot { margin-top: 64px; }
.work-index { padding-top: 160px; }
.index-head { max-width: 720px; }
.index-head h1 { margin-top: 16px; }
.index-head .lede { margin-top: 24px; color: var(--mist); }
.catalogue { margin-top: 64px; }
.catalogue-entry { display: grid; grid-template-columns: minmax(180px, 280px) minmax(0, 1fr) auto; gap: 36px; align-items: start; padding-block: 40px; border-top: 1px solid var(--line); }
.catalogue-entry .work-preview { margin-top: 4px; }
.catalogue-copy h2 { font-size: clamp(28px, 2.6vw, 38px); font-weight: 350; line-height: 1.2; margin-top: 12px; letter-spacing: -.015em; }
.catalogue-copy > p:not(.project-meta) { color: var(--mist); margin-top: 16px; max-width: 50ch; }
.catalogue-copy .project-actions { margin-top: 20px; }
.catalogue-status { padding-top: 2px; font: 400 var(--work-meta)/1.5 var(--sans); color: var(--mist); }
.catalogue-entry--text { grid-template-columns: minmax(0, 1fr) auto; }
.catalogue-entry--text .catalogue-copy { max-width: 730px; }
.archive { margin-top: 80px; }
.archive .catalogue { margin-top: 24px; }
.pp-head { padding-top: 120px; }
.pp-head > .text-link { margin: 0 0 44px; }
.pp-head .project-meta { margin-bottom: 22px; }
.pp-title { font-size: clamp(42px, 5.2vw, 80px); max-width: 18ch; }
.pp-head .lede { margin-top: 0; max-width: 48ch; font-size: clamp(1.375rem, 1.05rem + .65vw, 1.75rem); font-weight: 400; line-height: 1.45; color: var(--ink); text-wrap: pretty; }
.pp-head .pp-credit { margin-block: 24px 0; max-width: 60ch; font-size: 1.125rem; line-height: 1.65; }
.pp .pp-fig, .pp .pp-os { margin-top: 64px; }
.project-video { display: block; width: 100%; height: auto; background: var(--night); border: 1px solid var(--line); }
.pp-fig { max-width: 1280px; }
.comparison-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
.comparison-pair img { width: 100%; }
.comparison-pair p { margin-top: 12px; font: 400 14px/1.5 var(--sans); }
.pp-body { margin-top: 80px; gap: 48px; }
.pp-next { margin-top: 80px; }
.pp-next > .text-link { display: inline-block; padding: 0; border: 0; }
.pp-next > a:not(.text-link) { margin-top: 32px; }
.pp .demo { margin-top: 64px; }
@media (max-width: 960px) {
  .feature-lead, .feature-support { grid-template-columns: minmax(0, 1fr); gap: 36px; }
  .feature-lead > .evidence { grid-template-columns: 1fr 1.3fr; gap: 36px; }
  .feature-title { max-width: 22ch; }
  .feature-summary { max-width: 46ch; }
  .feature-support .evidence { max-width: 650px; }
  .catalogue-entry { grid-template-columns: 200px minmax(0, 1fr); gap: 28px; }
  .catalogue-entry .work-preview { grid-column: 1; grid-row: 1 / span 2; }
  .catalogue-copy { grid-column: 2; grid-row: 1; }
  .catalogue-status { grid-column: 2; grid-row: 2; }
  .catalogue-entry--text { grid-template-columns: 1fr; }
  .catalogue-entry--text .catalogue-copy { grid-column: 1; }
  .catalogue-entry--text .catalogue-status { grid-column: 1; }
  .about-grid { grid-template-columns: minmax(0, 3fr) minmax(0, 5fr); gap: 32px; }
}
@media (max-width: 640px) {
  .bar { gap: 8px; }
  .bar nav { flex: 1; min-width: 0; }
  .bar ul { gap: 0 14px; flex-wrap: wrap; justify-content: flex-end; }
  .bar a { padding-block: 14px; }
  .mark-small { width: 84px; }
  .curated { padding-top: 36px; }
  .section-head { padding-bottom: 24px; }
  .feature { padding-block: 32px; }
  .feature-name { margin-top: 26px; font-size: 16px; }
  .feature-summary { font-size: 19px; margin-top: 22px; }
  .feature-title { max-width: 14ch; }
  .feature-lead > .evidence { grid-template-columns: 1fr; gap: 20px; padding-top: 24px; }
  .feature-lead > .evidence .evidence-copy > p:first-child { margin-top: 0; }
  .core-trace { gap: 8px; font-size: 12px; }
  .core-trace-node { padding-inline: 12px; }
  .project-meta { gap: 8px 16px; font-size: 13px; }
  .project-actions { gap: 16px 22px; }
  .project-actions a, .section-head a, .collection-link a { padding-block: 7px; }
  .evidence h4 { font-size: 26px; }
  .supporting-work { margin-top: 16px; }
  .supporting-work:has(.feature-support:nth-child(2)) { grid-template-columns: 1fr; gap: 0; }
  .feature-support { padding-block: 40px; }
  .feature-support .evidence { padding-inline-start: 24px; }
  .feature-support .evidence h4 { font-size: 28px; }
  .collection-link { display: block; }
  .collection-link p { font-size: 22px; margin-bottom: 10px; }
  .about-grid { grid-template-columns: 1fr; gap: 0; }
  .portrait { max-width: 230px; margin-inline: auto; }
  .about-text { padding-top: 0; }
  .about-text .lead { font-size: 30px; }
  .work-index { padding-top: 120px; }
  .catalogue { margin-top: 40px; }
  .catalogue-entry { grid-template-columns: 1fr; gap: 22px; padding-block: 32px; }
  .catalogue-entry .work-preview { max-width: 360px; }
  .catalogue-entry .work-preview, .catalogue-copy { grid-column: 1; grid-row: auto; }
  .catalogue-copy .project-meta { padding: 0; }
  .catalogue-status { grid-column: 1; grid-row: auto; justify-self: start; }
  .pp-head { padding-top: 100px; }
  .pp-head > .text-link { margin-bottom: 28px; }
  .pp-head .pp-credit { font-size: 1.125rem; }
  .pp .pp-fig, .pp .pp-os { margin-top: 40px; }
  .comparison-pair { grid-template-columns: 1fr; gap: 28px; }
  .pp-body { margin-top: 56px; }
  .foot { margin-top: 48px; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { scroll-behavior: auto !important; }
  .feature-title a, .catalogue-copy h2 a, .preview-action > span:last-child { transition: none; }
}
html.rm .preview-action > span:last-child { transition: none; transform: none; }
@media (max-width: 360px) {
  .bar ul { gap: 11px; }
  .mark-small { width: 78px; }
}

/* Interaction detail: the same warm light, expressed as a direction and a response.
   Text remains still. Only the arrow and preview move, so links are easy to follow. */
.project-button { display: inline-flex; align-items: center; justify-content: space-between; gap: 24px; max-width: 100%; padding: 6px 6px 6px 20px; border: 1px solid rgba(236,228,216,.28); border-radius: 2px; font: 450 .9375rem/1.4 var(--sans); text-decoration: none; transition: border-color 220ms, background-color 220ms; }
.action-disc { flex: 0 0 42px; width: 42px; height: 42px; display: grid; place-items: center; border: 1px solid rgba(236,228,216,.22); border-radius: 50%; color: var(--ink); transition: color 220ms, border-color 220ms, background-color 220ms; }
.action-arrow { width: 22px; height: 22px; overflow: visible; stroke: currentColor; stroke-width: 1.35; stroke-linecap: round; stroke-linejoin: round; transition: transform 450ms var(--ease-out); }
.is-external .action-arrow { rotate: -45deg; }
.project-button .action-disc { border-color: transparent; border-left-color: var(--line); border-radius: 0; }
.project-button:is(:hover, :focus-visible) { border-color: var(--lamp); background: rgba(255,179,102,.055); }
:is(.project-button, .work-preview, .next-project):is(:hover, :focus-visible) .action-disc { color: var(--lamp); border-color: rgba(255,179,102,.55); background: rgba(255,179,102,.055); }
:is(.project-button, .work-preview, .next-project):is(:hover, :focus-visible) .action-arrow { transform: translateX(3px); }
.project-button:active .action-arrow { transform: translateX(5px); transition-duration: 100ms; }
.work-preview img { transition: transform 900ms var(--ease-out); }
.preview-frame { transition: border-color 220ms; }
.work-preview:is(:hover, :focus-visible) .preview-frame { border-color: rgba(255,179,102,.55); }
.preview-action > span:last-child { font-size: inherit; transform: none !important; }
@media (hover: hover) and (pointer: fine) {
  .work-preview:hover img { transform: scale(1.025); }
}
.feature-lead { row-gap: 20px; padding-bottom: 36px; }
.feature-summary { color: #aeb5bd; }
.evidence-copy > p { font: 400 1rem/1.65 var(--sans); color: #b8bdc3; text-wrap: pretty; }
.evidence-copy { container-type: inline-size; }
.evidence .evidence-note { font-size: .8125rem; color: var(--mist); }
.evidence-copy > .text-link { margin-top: 16px; }
.supporting-work { margin-top: 8px; }
.feature-support .evidence { padding-inline-start: 32px; }
.pp-intro { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: clamp(40px, 5vw, 88px); align-items: start; }
.pp-identity, .pp-description { min-width: 0; }
.pp-title { font-size: clamp(2.625rem, 4.6vw, 4.75rem); line-height: 1.05; }
.pp-head .project-actions { margin-top: 24px; }
.pp .pp-os { max-width: 1120px; margin-top: 40px; }
/* Names are legible before the connection draws, including when scrolling stops. */
html.js:not(.rm) .osd-part { opacity: 1; }
.osd-name { text-underline-offset: .2em; text-decoration: underline; text-decoration-color: rgba(236,228,216,.22); text-decoration-thickness: 1px; }
.osd-part--core .osd-name { text-decoration-color: rgba(255,179,102,.25); }
.osd-part.is-on .osd-name { text-decoration-color: var(--lamp); }
.next-project { position: relative; padding-right: 72px; }
.next-project .action-disc { position: absolute; right: 0; bottom: 4px; width: 52px; height: 52px; }
.next-project::before { content: ''; position: absolute; top: -1px; left: 0; right: 0; height: 1px; background: var(--lamp); transform: scaleX(0); transform-origin: right; transition: transform 700ms var(--ease-out); }
.next-project:is(:hover, :focus-visible)::before { transform: scaleX(1); transform-origin: left; }
.catalogue-entry { position: relative; }
.catalogue-entry::before { content: ''; position: absolute; top: -1px; left: 0; right: 0; height: 1px; background: var(--lamp); transform: scaleX(0); transform-origin: right; transition: transform 700ms var(--ease-out); pointer-events: none; }
.catalogue-entry:has(a:hover)::before, .catalogue-entry:focus-within::before { transform: scaleX(1); transform-origin: left; }
@media (max-width: 960px) {
  .pp-intro { grid-template-columns: 1fr; gap: 28px; }
  .pp-head .lede { max-width: 52ch; }
}
@media (max-width: 640px) {
  .project-actions .project-button { padding: 6px 6px 6px 16px; }
  .feature-lead { row-gap: 24px; }
  .feature-support .evidence { padding-inline-start: 20px; }
  .core-trace { gap: 8px; }
  .core-trace-node { padding-inline: 0; font-size: 1.125rem; }
  .pp .pp-os { margin-top: 36px; }
}
@media (max-width: 420px) {
  .core-trace { grid-template-columns: minmax(0, 1fr) 12px auto 12px minmax(0, 1fr); font-size: .8125rem; gap: 5px; }
}
@container (max-width: 15rem) {
  .core-trace { grid-template-columns: minmax(0, 1fr); justify-items: start; gap: 8px; }
  .core-trace > span { min-width: 0; }
  .core-trace-node { white-space: normal; }
  .core-connection { height: 16px; width: 1px; margin-left: 3px; }
  .core-connection::after { height: 100%; }
  .core-trace-node::before { display: none; }
}
html.rm :is(.action-arrow, .action-disc, .project-button, .work-preview img, .core-trace-node, .core-connection::after, .next-project::before, .catalogue-entry::before) { transition: none; transform: none; }
@media (prefers-reduced-motion: reduce) {
  :is(.action-arrow, .action-disc, .project-button, .work-preview img, .core-trace-node, .core-connection::after, .next-project::before, .catalogue-entry::before) { transition: none; transform: none; }
}

/* The preview catches the light like a print on a dark table. The image underneath
   stays intact, and its normal caption remains the action on every input type. */
.preview-light, .preview-cue, .preview-corners { pointer-events: none; position: absolute; opacity: 0; transition: opacity 180ms ease; }
.preview-light { left: -180px; top: -180px; width: 360px; height: 360px; background: radial-gradient(circle, rgba(255,210,160,.19), rgba(255,179,102,.075) 35%, transparent 70%); mix-blend-mode: screen; }
.preview-cue { left: 0; top: 0; display: flex; align-items: center; gap: 24px; padding: 10px 14px; border: 1px solid rgba(255,179,102,.6); background: #111a21; color: #fff0df; border-radius: 2px; font: 450 .8125rem/1.3 var(--sans); }
.preview-cue .action-arrow { width: 18px; height: 18px; }
.preview-corners { inset: 10px; --corner: rgba(255,179,102,.7); background: linear-gradient(var(--corner) 0 0) left top / 18px 1px, linear-gradient(var(--corner) 0 0) left top / 1px 18px, linear-gradient(var(--corner) 0 0) right top / 18px 1px, linear-gradient(var(--corner) 0 0) right top / 1px 18px, linear-gradient(var(--corner) 0 0) left bottom / 18px 1px, linear-gradient(var(--corner) 0 0) left bottom / 1px 18px, linear-gradient(var(--corner) 0 0) right bottom / 18px 1px, linear-gradient(var(--corner) 0 0) right bottom / 1px 18px; background-repeat: no-repeat; }
@media (hover: hover) and (pointer: fine) {
  .preview-frame.is-pointed :is(.preview-light, .preview-cue, .preview-corners) { opacity: 1; }
}
.work-preview:focus-visible .preview-corners { opacity: 1; }
.hero-discover { position: absolute; z-index: 2; top: calc(100svh - 92px); right: var(--gutter); display: flex; align-items: center; gap: 20px; min-height: 56px; color: var(--ink); font: 450 .875rem/1.4 var(--sans); text-decoration: none; }
.hero-stage { position: relative; }
.hero-stage .hero-in { padding-bottom: max(12vh, 8rem); }
.hero-controls { position: absolute; z-index: 2; bottom: 28px; left: var(--gutter); right: var(--gutter); display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px 24px; }
.hero-controls .atmos, .hero-controls .hero-discover { position: static; }
.hero-controls .hero-discover { margin-left: auto; }
.hero-discover .action-disc { width: 56px; height: 56px; flex-basis: 56px; }
.is-down .action-arrow { rotate: 90deg; }
.hero-discover:is(:hover, :focus-visible) .action-disc { color: var(--lamp); border-color: var(--lamp); background: rgba(255,179,102,.06); }
.hero-discover:is(:hover, :focus-visible) .action-arrow { transform: translateX(4px); }
.hero-discover > span:first-child { text-decoration: underline; text-underline-offset: 6px; text-decoration-color: rgba(236,228,216,.3); }
.project-button:active { scale: .98; }
.project-button { transition: border-color 220ms, background-color 220ms, scale 160ms var(--ease-out); }
@media (max-width: 640px) {
  .hero-discover { top: calc(100svh - 80px); gap: 10px; font-size: .8125rem; }
  .hero-discover .action-disc { width: 42px; height: 42px; flex-basis: 42px; }
  .atmos { font-size: .75rem; }
}
@media (max-width: 360px) {
  .hero-discover { gap: 8px; }
  .hero-discover .action-disc { width: 36px; height: 36px; flex-basis: 36px; }
}
html.rm .preview-light, html.rm .preview-cue { display: none; }
html.rm .project-button:active { scale: 1; }
html.rm .hero-discover:is(:hover, :focus-visible) .action-arrow { transform: none; }
.os-list { position: relative; border: 0; padding-top: 0; gap: 28px; }
.os-list::before { content: ''; position: absolute; left: 3px; top: 8px; bottom: 16px; width: 1px; background: rgba(255,179,102,.28); transform-origin: top; }
.os-list li { position: relative; padding-left: 30px; }
.os-list li::before { content: ''; position: absolute; left: 0; top: 8px; width: 7px; height: 7px; border: 1px solid var(--ember); border-radius: 50%; background: var(--night); }
.os-list strong, .os-list-link { display: block; width: fit-content; margin: 0 0 6px; }
.os-list .os-list-core { padding-block: 8px; }
.os-list-core strong { font: 400 1.75rem/1.2 var(--serif); color: #ffe7cc; }
.os-list .os-list-core::before { top: 17px; background: var(--lamp); box-shadow: 0 0 18px 4px rgba(255,179,102,.25); }
@media (prefers-reduced-motion: reduce) {
  .preview-light, .preview-cue { display: none; }
  .project-button:active { scale: 1; }
  .hero-discover:is(:hover, :focus-visible) .action-arrow { transform: none; }
}

/* Editorial pass: one type hierarchy, open actions, and a working-context study.
   This replaces the small category eyebrows and boxed controls in the first pass. */
.reveal-word { display: inline-block; vertical-align: baseline; max-width: 100%; overflow-wrap: anywhere; }
/* Each word carries its own mask while its heading rises (a clip-path, so the baseline stays where it
   is), generous at the sides and below for italics, descenders and the lit words' glow. Off once arrived. */
html.js:not(.rm) [data-lines]:not(.is-done) .reveal-word { clip-path: inset(-0.4em -0.2em -0.28em -0.2em); }
.reveal-in { display: inline-block; }
.section-head .section-label { font: 400 clamp(2rem, 2.9vw, 2.75rem)/1.1 var(--serif); letter-spacing: -.025em; }
.section-head { padding-bottom: 28px; flex-wrap: wrap; }
.feature-name, .feature-support .feature-name { margin-top: 0; font: 400 1.25rem/1.4 var(--serif); color: var(--soft); }
.feature-title { margin-top: 24px; font-weight: 350; line-height: 1.08; letter-spacing: -.03em; }
.feature-summary, .feature-support .feature-summary { font: 400 1.25rem/1.55 var(--serif); color: var(--soft); max-width: 36ch; margin-top: 28px; }
.feature-state { margin-top: 20px; color: #a8adb2; font: 400 .75rem/1.5 var(--sans); letter-spacing: .08em; text-transform: uppercase; }
.feature-state .project-status::before { display: none; }
.feature-lead { padding-block: 56px 40px; row-gap: 44px; }
.feature-support { padding-block: 72px; }
.feature-support .feature-title { font-size: clamp(2.5rem, 3.55vw, 3.5rem); max-width: 16ch; }
.feature-support .feature-visual { align-self: stretch; display: grid; align-content: center; }
.project-actions { margin-top: 32px; }
.project-button, .project-actions .project-button { position: relative; border: 0; border-radius: 0; padding: 0 0 10px; gap: 28px; font: 450 .9375rem/1.5 var(--sans); background: none; }
.project-button::after { content: ''; position: absolute; bottom: 0; height: 1px; left: 0; right: 0; background: var(--ink); opacity: .25; transform-origin: left; transition: opacity 220ms; }
.project-button .action-disc { border: 1px solid rgba(236,228,216,.35); border-radius: 50%; width: 48px; height: 48px; flex-basis: 48px; }
.project-button:is(:hover, :focus-visible) { background: none; }
.project-button:is(:hover, :focus-visible)::after { opacity: .8; }
.project-button:is(:hover, :focus-visible) .action-disc { color: var(--night); background: var(--ink); border-color: var(--ink); }
.project-button:active { scale: 1; }
.project-button .action-arrow { transition: transform 240ms var(--ease-out); }
.preview-cue { width: 78px; height: 78px; justify-content: center; flex-direction: column; gap: 3px; border: 0; border-radius: 50%; background: var(--ink); color: var(--night); font-size: .8125rem; }
.preview-corners { display: none; }
.preview-action > span:first-child { text-decoration: none; }
.preview-action { font-weight: 400; }
.evidence h4 { margin: 0; font-size: clamp(1.75rem, 2.6vw, 2.25rem); font-weight: 400; line-height: 1.2; max-width: 17ch; }
.evidence-copy > p { font: 400 1.1875rem/1.55 var(--serif); color: var(--prose); max-width: 52ch; }
.evidence .evidence-note { font: 400 .8125rem/1.6 var(--sans); max-width: 54ch; margin-top: 20px; }
.feature-lead > .evidence { padding-top: 32px; }
.context-preview { position: relative; padding: 36px clamp(24px, 3vw, 48px) 30px; border-block: 1px solid var(--line); background: linear-gradient(160deg, rgba(236,228,216,.028), transparent 70%); }
.context-tools { display: grid; grid-template-columns: 1fr 1fr; }
.context-tool { display: flex; align-items: center; flex-direction: column; gap: 12px; font: 400 .8125rem/1.4 var(--sans); color: var(--soft); }
.context-tool img { width: 36px; height: 36px; object-fit: contain; }
.context-paths { display: block; width: 100%; height: 70px; margin-top: 18px; overflow: visible; }
.context-paths path { stroke: var(--ember); stroke-width: 1; vector-effect: non-scaling-stroke; }
html.js:not(.rm) .context-paths path { stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset 1800ms var(--ease-io) 250ms; }
html.js:not(.rm) .context-preview.is-in .context-paths path { stroke-dashoffset: 0; }
.context-core { position: relative; display: flex; flex-direction: column; align-items: center; gap: 16px; font: 400 2.5rem/1.1 var(--serif); letter-spacing: -.025em; padding-bottom: 32px; }
.context-spark { width: 7px; height: 7px; border-radius: 50%; background: var(--lamp); box-shadow: 0 0 28px 8px rgba(255,179,102,.3); }
.project-meta { font: 400 1rem/1.5 var(--serif); color: var(--soft); }
.project-meta .project-status { font: 400 1rem/1.5 var(--sans); letter-spacing: .04em; align-self: center; }
.project-meta .project-status::before { width: 3px; height: 3px; }
.osd-name { display: inline-flex; align-items: center; gap: 12px; }
.tool-mark { width: 32px; height: 32px; flex: 0 0 32px; object-fit: contain; }
@media (max-width: 960px) {
  .feature-support .context-preview { max-width: 650px; width: 100%; }
  .feature-title { max-width: 17ch; }
}
@media (max-width: 640px) {
  .feature-lead { padding-block: 36px; row-gap: 32px; }
  .feature-title { margin-top: 18px; font-size: clamp(2.875rem, 10vw, 3.5rem); max-width: 14ch; }
  .feature-support .feature-title { font-size: clamp(2.5rem, 9vw, 3rem); max-width: 15ch; }
  .feature-name, .feature-support .feature-name { font-size: 1.125rem; }
  .feature-summary, .feature-support .feature-summary { font-size: 1.1875rem; margin-top: 24px; }
  .feature-support { padding-block: 44px; gap: 36px; }
  .context-preview { padding: 28px 20px 20px; }
  .context-core { font-size: 2.25rem; }
}
html.rm .context-paths path { transition: none; }
@media (prefers-reduced-motion: reduce) {
  .context-paths path { transition: none; }
}
.os-list strong:has(.tool-mark) { display: flex; align-items: center; gap: 12px; }

/* Two concise introductions. Typography, preview and motion carry their presence. */
.feature-showcase { display: block; padding-block: 64px 88px; }
.showcase-intro { display: grid; grid-template-columns: minmax(0, 8fr) minmax(0, 4fr); gap: 64px; align-items: end; }
.feature-showcase .feature-title { font-size: clamp(3.5rem, 7.2vw, 7rem); font-weight: 300; line-height: 1.02; max-width: 13ch; margin-top: 28px; }
.feature-showcase .feature-title .lit { display: block; margin-left: .65em; white-space: normal; }
.showcase-summary { padding-bottom: 8px; }
.showcase-summary .feature-summary { margin-top: 0; max-width: 32ch; }
.workspace-window { margin-top: 44px; }
/* The lead's loop runs 12 s on its own, so it carries the clip's Pause, under the picture on the right (WCAG 2.2.2);
   the home's Snafu story the same. */
.workspace-window .clip-toggle, .sl-stage .clip-toggle { position: relative; right: auto; bottom: auto; display: flex; width: max-content; margin: 8px 0 0 auto; }
.workspace-window .clip-toggle[hidden] { display: none; }

.workspace-window .preview-action { display: none; }
.feature-context.feature-support { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); padding-block: 96px; }
.feature-context .feature-copy { grid-column: 2; grid-row: 1; align-self: center; }
.feature-context .feature-visual { grid-column: 1; grid-row: 1; }
.feature-context .feature-title { font-size: clamp(2.75rem, 4.2vw, 4rem); max-width: 14ch; }
.feature-context .feature-title .lit { display: block; }
.context-preview { border: 0; background: none; padding: 30px 36px; }
.context-core::before { content: ''; position: absolute; width: 290px; height: 200px; top: -88px; background: radial-gradient(ellipse, rgba(255,179,102,.1), transparent 68%); pointer-events: none; z-index: -1; }
.context-paths { height: 120px; }
.context-core { font-size: 3.5rem; padding-bottom: 48px; }
.context-spark { box-shadow: 0 0 24px 7px rgba(255,179,102,.4); }
.context-tools .context-tool { font-size: .9375rem; }
.context-tool img { width: 44px; height: 44px; }
.feature-state { text-transform: none; letter-spacing: 0; font-size: .8125rem; }
/* A connection is present before its light travels. No disconnected first frame. */
.osd-guide { fill: none; stroke: rgba(255,179,102,.12); stroke-width: 1; }
.supporting-work:has(.feature-support:nth-child(2)) .feature-context > :is(.feature-copy,.feature-visual) { grid-column: 1; grid-row: auto; }
@media (max-width: 960px) {
  .showcase-intro { grid-template-columns: 1fr; gap: 32px; }
  .showcase-summary .feature-summary { max-width: 48ch; }
  .feature-showcase .feature-title { font-size: clamp(3.5rem, 9vw, 6rem); }
  .feature-context.feature-support { grid-template-columns: 1fr; gap: 40px; padding-block: 64px; }
  .feature-context .feature-copy, .feature-context .feature-visual { grid-column: 1; grid-row: auto; }
  .feature-context .feature-title { max-width: 20ch; }
  .context-preview { max-width: 600px; margin-inline: auto; }
}
@media (max-width: 640px) {
  .feature-showcase { padding-block: 36px 56px; }
  .feature-showcase .feature-title { font-size: clamp(2.3rem, 12.2vw, 4.25rem); max-width: 14ch; line-height: 1.08; }
  .feature-showcase .feature-title .lit { margin-left: .3em; }
  .showcase-intro { gap: 28px; }
  .showcase-summary { padding: 0; }
  .workspace-window { margin-top: 40px; }
  .context-preview { padding: 20px 10px 0; }
  .context-paths { height: 95px; }
  .context-core { font-size: 2.75rem; padding-bottom: 36px; }
  .feature-context .feature-title { font-size: clamp(2.5rem, 10.5vw, 3.25rem); }
}

/* Readable supporting text and a single linked OS illustration. */
.context-preview { display: block; text-decoration: none; color: inherit; }
.context-preview:is(:hover, :focus-visible) .context-spark { box-shadow: 0 0 32px 10px rgba(255,179,102,.6); }
.project-meta, .feature-state, .context-tools .context-tool, .pp-fig figcaption { font-size: 1rem; line-height: 1.5; }

/* ---------------------------------------------------------------- Claude's takeover, round 1 (2026-10-02)
   The dashboard's recording over the lead's poster, and Brent OS as a full chapter on the home page. */
.preview-video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity 400ms cubic-bezier(.23,1,.32,1); }
.preview-video.is-on { opacity: 1; }
.feature-chapter { display: block; padding-block: clamp(96px, 11vw, 168px) 24px; border-top: 1px solid var(--line); }
.feature-chapter .feature-title { font-size: clamp(3rem, 6.2vw, 6rem); font-weight: 300; line-height: 1.02; max-width: 13ch; margin-top: 28px; }
.feature-chapter .feature-title .lit { display: block; }
.chapter-stage { margin-top: clamp(48px, 6vw, 96px); }
.chapter-stage .osd { max-width: 1120px; }
@media (max-width: 640px) {
  .feature-chapter { padding-block: 64px 8px; }
  .feature-chapter .feature-title { font-size: clamp(2.5rem, 11vw, 3.5rem); max-width: 14ch; line-height: 1.06; }
}
/* On a phone the whole dashboard is too small to read; the square keeps the galaxy and Claude (the live site's crop). */
@media (max-width: 640px) {
  .feature-showcase .work-preview img, .feature-showcase .preview-video { aspect-ratio: 1; object-position: 47% 50%; }
}

/* ---------------------------------------------------------------- Claude's takeover, round 2 (2026-10-02)
   A project's page as a spread: the statement at display size, the opening line beside a facts rail,
   the project on a full stage, the findings in the split, the next project large with its cover. */
.sp-head { padding-top: clamp(124px, 17vh, 200px); }
.sp-crumb .text-link { margin: 0; }
.sp-name { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 22px; margin-top: clamp(40px, 6vh, 72px); font: 400 1.25rem/1.4 var(--serif); color: var(--soft); }
.sp-name .project-status { font: 400 .9375rem/1.5 var(--sans); color: var(--mist); }
.sp .sp-title { margin-top: 18px; max-width: 12.5ch; font-size: clamp(3rem, 1.1rem + 6.2vw, 7.5rem); font-weight: 300; line-height: 1; letter-spacing: -.032em; text-wrap: balance; }
.sp-title .lit { display: block; }
.sp-intro { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: 40px clamp(40px, 6vw, 120px); align-items: start; margin-top: clamp(48px, 6vw, 96px); padding-top: 32px; border-top: 1px solid var(--line); }
.sp-lede .lede { max-width: 28em; font-size: clamp(1.375rem, 1.1rem + .7vw, 1.875rem); font-weight: 350; line-height: 1.4; color: var(--ink); text-wrap: pretty; }
.sp-lede .project-actions { margin-top: 32px; }
.sp-facts.sp-mine div { border-bottom: 0; padding: 0; }
.sp-facts.sp-mine dd { max-width: 30em; font: 400 clamp(1.125rem, 1rem + .3vw, 1.3125rem)/1.5 var(--serif); color: #d6d0c7; }
.sp-side .project-actions { margin-top: 32px; }
.sp-under { margin-top: clamp(24px, 2.6vw, 40px); }
.sp-under .lede { max-width: 32em; font-size: clamp(1.25rem, 1.05rem + .55vw, 1.625rem); font-weight: 350; line-height: 1.42; color: #c9c4bc; text-wrap: pretty; }
.sp-under + .al { margin-top: clamp(40px, 4.4vw, 72px); }
.sp-facts { font-family: var(--sans); font-size: .9375rem; line-height: 1.5; }
.sp-facts div { display: grid; grid-template-columns: 6.5em minmax(0, 1fr); gap: 20px; padding: 13px 0; border-bottom: 1px solid var(--line); }
.sp-facts div:first-child { padding-top: 0; }
.sp-facts dt { color: var(--mist); }
.sp-facts dd { color: var(--ink); text-wrap: pretty; }
/* On a phone My part's text takes the full width under its label and badge (design review 3: 18 characters a line
   at 320 beside them). */
@media (max-width: 560px) {
  .sp-facts.sp-mine div { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .sp-mine dt { display: flex; align-items: flex-end; gap: 16px; }
}
/* A clip fits under the fixed bar on a desktop, its Pause in view with it (the Snafu clip's review). */
@media (min-width: 641px) { .sp-section > .proof--clip { max-width: min(100%, calc((100svh - 160px) * 1.6)); margin-inline: auto; } }
/* The TUI badge under "My part": a staff card on a lanyard, its pivot at the lanyard's top. */
.sp-badge { display: block; width: 72px; margin-top: 12px; transform-origin: 50% 0; will-change: transform; }
.sp-badge::before { content: ""; display: block; width: 1px; height: 18px; margin: 0 auto; background: linear-gradient(rgba(240, 244, 238, 0), rgba(240, 244, 238, .45)); }
.sp-badge-card { display: block; padding: 4px 4px 6px; border-radius: 8px; background: var(--lg-raised); border: 1px solid rgba(240, 244, 238, .12);
  box-shadow: 0 10px 22px rgba(0, 0, 0, .3); }
.sp-badge-card::before { content: ""; display: block; width: 16px; height: 3px; margin: 1px auto 5px; border-radius: 2px; background: var(--lg-bg); }
.sp-badge img { display: block; width: 100%; height: auto; border-radius: 4px; }
.sp-badge-name { display: block; margin-top: 5px; font: 500 .6875rem/1 var(--sans); color: var(--lg-ink); text-align: center; }
.sp-stage { margin-top: clamp(64px, 8vw, 128px); }
.sp-frame { display: block; position: relative; overflow: hidden; border: 1px solid var(--line); border-radius: 4px; color: var(--ink); text-decoration: none; box-shadow: 0 60px 120px -60px #000; }
.sp-frame img { width: 100%; aspect-ratio: 1.6; object-fit: cover; }
.sp-frame:is(:hover, :focus-visible) { border-color: rgba(255,179,102,.45); }
.sp-stage figcaption { margin-top: 16px; font: 400 1rem/1.5 var(--sans); color: var(--mist); }
.sp-stage--os .osd { max-width: 1120px; }
.sp-stage.dock-track { margin-top: clamp(40px, 5vw, 80px); }
.sp-body { display: grid; gap: clamp(64px, 7vw, 112px); margin-top: clamp(104px, 12vw, 184px); }
.sp-section { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: 20px clamp(40px, 6vw, 120px); align-items: start; padding-top: 28px; border-top: 1px solid var(--line); }
.sp .sp-h { max-width: 13ch; font-size: clamp(1.875rem, 1.2rem + 1.7vw, 2.875rem); font-weight: 300; line-height: 1.08; letter-spacing: -.02em; text-wrap: balance; }
.sp-text { display: grid; gap: 1.1em; }
.sp-text p { max-width: 29em; font-size: 1.1875rem; line-height: 1.62; color: var(--prose); text-wrap: pretty; }
.sp-next { margin-top: clamp(128px, 15vw, 232px); }
.sp-next-link { position: relative; display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "k cover" "t cover" "disc cover"; align-items: end; gap: 14px clamp(32px, 5vw, 80px); padding-top: 32px; border-top: 1px solid var(--line); color: var(--ink); text-decoration: none; }
.sp-next-link::before { content: ''; position: absolute; top: -1px; left: 0; right: 0; height: 1px; background: var(--lamp); box-shadow: 0 0 4px 1px rgba(255,179,102,.55), 0 0 14px 2px rgba(255,179,102,.22); transform: scaleX(0); transform-origin: right; transition: transform 700ms var(--ease-out); }
.sp-next-k { grid-area: k; font: 400 .9375rem/1.5 var(--sans); color: var(--mist); }
.sp-next-t { grid-area: t; font-size: clamp(2.75rem, 1rem + 5.4vw, 7rem); font-weight: 300; line-height: .98; letter-spacing: -.032em; transition: color 300ms ease; }
.sp-next-link .action-disc { grid-area: disc; margin-top: 18px; width: 52px; height: 52px; }
.sp-next-cover { position: relative; grid-area: cover; align-self: center; width: clamp(240px, 28vw, 420px); aspect-ratio: 1.6; border: 1px solid var(--line); border-radius: 3px; opacity: .5; transition: opacity 300ms cubic-bezier(.23,1,.32,1), border-color 300ms ease; }
.sp-next-cover::after { content: ''; position: absolute; inset: 0; border-radius: inherit; box-shadow: 0 0 90px -20px rgba(255,179,102,.35); opacity: 0; transition: opacity 300ms cubic-bezier(.23,1,.32,1); pointer-events: none; }
.sp-next-cover img { width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }
.sp-next-link:is(:hover, :focus-visible)::before { transform: scaleX(1); transform-origin: left; }
.sp-next-link:is(:hover, :focus-visible) .sp-next-t { color: #fff3e4; }
.sp-next-link:is(:hover, :focus-visible) .sp-next-cover { opacity: 1; border-color: rgba(255,179,102,.45); }
.sp-next-link:is(:hover, :focus-visible) .sp-next-cover::after { opacity: 1; }
.sp-next-link:is(:hover, :focus-visible) .action-disc { color: var(--lamp); border-color: rgba(255,179,102,.55); background: rgba(255,179,102,.055); }
@media (max-width: 900px) {
  .sp-intro, .sp-section { grid-template-columns: minmax(0, 1fr); }
  .sp-next-link { grid-template-columns: minmax(0, 1fr); grid-template-areas: "k" "t" "cover" "disc"; }
  .sp-next-cover { width: 100%; max-width: 520px; margin-top: 12px; opacity: .8; }
}
@media (max-width: 640px) {
  .sp-head { padding-top: 104px; }
  .sp-name { margin-top: 36px; font-size: 1.125rem; }
  .sp .sp-title { font-size: clamp(2.6rem, 12vw, 3.75rem); line-height: 1.04; }
  .sp-intro { margin-top: 36px; padding-top: 24px; }
  .sp-stage { margin-top: 48px; }
  .sp-frame img { aspect-ratio: 1; object-position: 47% 50%; }
  .sp-body { margin-top: 80px; }
  .sp-next-t { font-size: clamp(2.5rem, 11vw, 3.5rem); }
}
html.rm .sp-next-link::before, html.rm .sp-next-cover, html.rm .sp-next-cover img { transition: none; }

/* ---------------------------------------------------------------- Claude's takeover, round 3 (2026-10-02)
   The Work index as a lit list. Without a fine pointer (a phone, a pen) and without scripts, the cover
   sits in the row; with one, site.js floats it beside the pointer and the row under it is lit. */
.work-index { padding-top: clamp(132px, 18vh, 200px); }
.index-head { max-width: none; }
.index-head .index-title { margin: 0; font-size: clamp(4.5rem, 2rem + 9vw, 11rem); font-weight: 300; line-height: .9; letter-spacing: -.045em; }
.index-head .lede { margin-top: clamp(20px, 2.4vw, 36px); max-width: 26em; color: var(--mist); }
.lit-index { margin-top: clamp(64px, 8vw, 128px); border-bottom: 1px solid var(--line); }
.li-row { position: relative; border-top: 1px solid var(--line); }
.li-row::before { content: ''; position: absolute; top: -1px; left: 0; right: 0; height: 1px; background: var(--lamp); box-shadow: 0 0 4px 1px rgba(255,179,102,.55), 0 0 14px 2px rgba(255,179,102,.22); transform: scaleX(0); transform-origin: right; transition: transform 300ms cubic-bezier(.23,1,.32,1); pointer-events: none; }
.li-link { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "copy side" "cover cover"; gap: 20px 40px; padding-block: clamp(28px, 3.4vw, 48px); color: var(--ink); text-decoration: none; }
.li-copy { grid-area: copy; display: grid; gap: 10px; min-width: 0; }
.li-what { font: 400 1rem/1.4 var(--serif); color: var(--soft); }
.li-name { font-size: clamp(2.5rem, 1rem + 4.8vw, 6.25rem); font-weight: 300; line-height: .98; letter-spacing: -.035em; overflow-wrap: anywhere; text-wrap: balance; transition: color 220ms ease; }
.li-line { max-width: 44ch; margin-top: 8px; font-size: 1.125rem; line-height: 1.55; color: var(--mist); text-wrap: pretty; }
.li-side { grid-area: side; display: flex; align-items: center; gap: 24px; align-self: start; padding-top: 4px; }
.li-side .project-status { font: 400 .9375rem/1.5 var(--sans); color: var(--mist); }
.li-cover { grid-area: cover; display: block; width: min(100%, 520px); aspect-ratio: 1.6; overflow: hidden; border: 1px solid var(--line); border-radius: 3px; }
.li-cover img { width: 100%; height: 100%; object-fit: cover; }
.li-link:is(:hover, :focus-visible) .li-name { color: #fff3e4; text-shadow: 0 0 .5em rgba(255,179,102,.22); }
.li-row:has(.li-link:is(:hover, :focus-visible))::before { transform: scaleX(1); transform-origin: left; }
.li-link:is(:hover, :focus-visible) .action-disc { color: var(--lamp); border-color: rgba(255,179,102,.55); background: rgba(255,179,102,.055); }
.li-link:is(:hover, :focus-visible) .action-arrow { transform: translateX(3px); }
.archive { margin-top: clamp(80px, 10vw, 144px); }
.archive .lit-index { margin-top: 24px; }
/* With a fine pointer and scripts, the covers leave the rows and float in the light. */
.li-float { display: none; }
@media (hover: hover) and (pointer: fine) {
  html.js .li-cover { display: none; }
  html.js .li-link { grid-template-areas: "copy side"; }
  html.js .li-float { display: block; position: fixed; z-index: 3; left: 0; top: 0; width: clamp(280px, 26vw, 440px); aspect-ratio: 1.6; pointer-events: none; opacity: 0; visibility: hidden; border-radius: 4px; overflow: hidden; border: 1px solid rgba(255,179,102,.4); box-shadow: 0 40px 90px -30px #000, 0 0 120px -20px rgba(255,179,102,.38); transform-origin: 50% 60%; }
  html.js .li-float img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity 260ms ease; }
  html.js .li-float img.is-on { opacity: 1; }
  /* The lamp's light falls across the cover from above. */
  html.js .li-float::after { content: ''; position: absolute; inset: 0; background: radial-gradient(120% 90% at 30% 0%, rgba(255,214,170,.16), rgba(255,179,102,0) 60%); mix-blend-mode: screen; }
  html.js .lit-index .li-row { transition: opacity 220ms cubic-bezier(.23,1,.32,1); }
  html.js .lit-index.is-pointed .li-row:not(.is-on) { opacity: .32; }
}
@media (max-width: 760px) {
  .li-link { grid-template-columns: minmax(0, 1fr); grid-template-areas: "cover" "copy" "side"; gap: 18px; }
  .li-cover { width: 100%; }
  .li-name { font-size: clamp(2.375rem, 11vw, 3.5rem); }
  .li-side { justify-content: space-between; padding-top: 0; }
}
html.rm .li-row::before, html.rm .lit-index .li-row { transition: none; }
/* The cover passes behind the type, so a long name stays readable over its own image; the lit name keeps
   a little night around it. */
.lit-index { position: relative; z-index: 1; }
@media (hover: hover) and (pointer: fine) {
  html.js .li-float { z-index: 0; }
  html.js .li-row.is-on .li-name { text-shadow: 0 0 .5em rgba(255,179,102,.22), 0 0 18px rgba(7,13,20,.75), 0 0 40px rgba(7,13,20,.5); }
  html.js .li-row.is-on .li-line, html.js .li-row.is-on .li-what { text-shadow: 0 0 12px rgba(7,13,20,.9), 0 0 24px rgba(7,13,20,.7); }
}
.li-link:focus-visible { outline-offset: 10px; }

/* ---------------------------------------------------------------- the review round (2026-10-02)
   Two independent reviewers, scored blind before any reference (the faults both found, checked in the code). */
/* The bar: copy under it no longer reads through it, and without scripts it has its ground from the start. */
.bar::before { background: rgba(7, 13, 20, 0.92); }
html:not(.js) .bar::before { opacity: 1; }
/* Focus never lands under the fixed bar. */
html { scroll-padding-top: 104px; }
@media (max-width: 640px) { html { scroll-padding-top: 88px; } }
/* A title link that wraps to two lines takes its ring around the whole title, not its first line box. */
.feature-title a:focus-visible { outline: none; }
.feature-title:has(a:focus-visible) { outline: 2px solid var(--ink); outline-offset: 10px; border-radius: 2px; }
/* Touch targets of at least 44 px without moving the type: the hit area grows, the words stay put. */
.bar nav a::before { content: ""; position: absolute; inset: -6px -13px; }
/* The same for the rest the review measured under 44 px on a phone (2026-10-03): the mark home and the atmosphere
   button (40 tall), the Brent OS list's links and "All work" (23), the email (29). Each has space or plain text
   around it, so the grown areas never overlap another target. */
.bar-home, .atmos, .os-list-link, .mail { position: relative; }
.bar-home::before, .atmos::before { content: ""; position: absolute; inset: -3px -2px; }
.os-list-link::before, .sp-crumb .text-link::before { content: ""; position: absolute; inset: -11px -6px; }
.mail::before { content: ""; position: absolute; inset: -8px 0; }
.contact-links a { display: inline-block; padding-block: 12px; margin-block: -12px; }
/* The band between the dashboard and Brent OS, about 260 px of nothing on desktop, closed to about 160. */
.feature-showcase { padding-bottom: 56px; }
.feature-chapter { padding-top: clamp(72px, 7.5vw, 112px); }
/* The portrait is cut out (its flat 5/10/18 backdrop keyed with FFmpeg's colorkey; the darkest trousers sit at
   35/36/44, well clear), so he stands on the page's own ground wherever the light is; one fade at the foot,
   where the photograph ends mid-leg. */
.portrait img {
  -webkit-mask-image: linear-gradient(to bottom, #000 74%, transparent 100%);
          mask-image: linear-gradient(to bottom, #000 74%, transparent 100%);
  -webkit-mask-composite: source-over; mask-composite: add;
}

/* ---------------------------------------------------------------- Brent OS as a cover (the review round)
   The drawing at the covers' 1.6:1 (build.js osCover). Finished and still by default: without scripts,
   under reduced motion, and wherever site.js shows it finished. .is-drawing plays its story once per
   visit (about 2.9 s); .is-live, while pointed at, carries a spark into the core every 3.6 s. */
.os-cover { display: block; width: 100%; height: 100%; font-family: var(--sans); }
.os-cover .oc-guides path { fill: none; stroke: rgba(255, 179, 102, 0.1); stroke-width: 1.2; }
.os-cover .oc-in, .os-cover .oc-out { fill: none; stroke: rgba(255, 179, 102, 0.55); stroke-width: 1.7; stroke-dasharray: 1; stroke-dashoffset: 0; }
.os-cover .oc-out { stroke: rgba(255, 179, 102, 0.36); stroke-width: 1.4; }
.os-cover .oc-spark { fill: none; stroke: #fff4e6; stroke-width: 3.4; stroke-linecap: round; stroke-dasharray: 0.06 2; stroke-dashoffset: 0.06; opacity: 0; }
.os-cover .oc-src { fill: var(--lamp); }
.os-cover .oc-core { fill: #fff4e6; transform-box: fill-box; transform-origin: center; }
.os-cover .oc-halo { opacity: 0.9; transform-box: fill-box; transform-origin: center; }
.os-cover .oc-pool { opacity: 1; }
.os-cover .oc-name { fill: var(--ink); font-size: 29px; font-weight: 450; }
.os-cover .oc-core-name { fill: #ffe7cc; font-family: var(--serif); font-size: 46px; font-weight: 300; letter-spacing: -0.01em; }
.os-cover .oc-scope { fill: var(--mist); font-size: 25px; }
/* Under each lit strand, its own soft light; the bloom is the core lighting the room. */
.os-cover .oc-under :is(.oc-in, .oc-out) { stroke: rgba(255, 179, 102, 0.5); stroke-width: 7; }
.os-cover .oc-bloom { opacity: 1; transform-box: fill-box; transform-origin: center; }
/* The spark's tail: a longer, dimmer dash ending where the head ends, so the light trails behind it. */
.os-cover .oc-tail { stroke: #ffc78f; stroke-width: 2.2; stroke-dasharray: 0.2 2; stroke-dashoffset: 0.2; }

/* The story: the strands draw down, each led by its spark; the core lights as they meet; the light runs on. */
html.js:not(.rm) .os-cover.is-drawing .oc-in { animation: oc-draw 1s var(--ease-io) calc(0.15s + var(--k) * 0.12s) both; }
html.js:not(.rm) .os-cover.is-drawing .oc-spark--in { animation: oc-run 1s var(--ease-io) calc(0.15s + var(--k) * 0.12s) both; }
html.js:not(.rm) .os-cover.is-drawing .oc-src, html.js:not(.rm) .os-cover.is-drawing .oc-mark, html.js:not(.rm) .os-cover.is-drawing .oc-name { animation: oc-fade 0.6s ease-out both; }
html.js:not(.rm) .os-cover.is-drawing .oc-core { animation: oc-ignite 0.9s var(--ease-out) 1.05s both; }
html.js:not(.rm) .os-cover.is-drawing .oc-halo { animation: oc-halo 1.2s var(--ease-out) 1.05s both; }
html.js:not(.rm) .os-cover.is-drawing .oc-core-name { animation: oc-fade 0.7s ease-out 1.2s both; }
html.js:not(.rm) .os-cover.is-drawing .oc-out { animation: oc-draw 0.9s var(--ease-io) calc(1.3s + var(--k) * 0.1s) both; }
html.js:not(.rm) .os-cover.is-drawing .oc-spark--out { animation: oc-run 0.9s var(--ease-io) calc(1.3s + var(--k) * 0.1s) both; }
html.js:not(.rm) .os-cover.is-drawing .oc-pool { animation: oc-fade 0.9s ease-out calc(1.95s + var(--k) * 0.1s) both; }
html.js:not(.rm) .os-cover.is-drawing .oc-scope { animation: oc-names-late 0.9s ease-out 2s both; }
/* Before its story, a copy waiting to play is dark (only the room and the faint guides). */
html.js:not(.rm) .os-cover:not(.is-drawn):not(.is-drawing) :is(.oc-in, .oc-out) { stroke-dashoffset: 1; }
html.js:not(.rm) .os-cover:not(.is-drawn):not(.is-drawing) :is(.oc-src, .oc-mark, .oc-name, .oc-core, .oc-halo, .oc-core-name, .oc-pool, .oc-scope) { opacity: 0; }
@keyframes oc-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes oc-run { 0% { stroke-dashoffset: 0.06; opacity: 1; } 92% { opacity: 1; } 100% { stroke-dashoffset: -1; opacity: 0; } }
@keyframes oc-run-tail { 0% { stroke-dashoffset: 0.2; opacity: 0.55; } 88% { opacity: 0.55; } 100% { stroke-dashoffset: -0.86; opacity: 0; } }
@keyframes oc-bloom { from { opacity: 0; transform: scale(0.6); } to { opacity: 1; transform: scale(1); } }
@keyframes oc-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes oc-names-late { from { opacity: 0; } to { opacity: 1; } }
@keyframes oc-ignite { 0% { opacity: 0; transform: scale(0.4); } 35% { opacity: 1; transform: scale(1.7); } 100% { opacity: 1; transform: scale(1); } }
@keyframes oc-halo { from { opacity: 0; transform: scale(0.35); } to { opacity: 0.9; transform: scale(1); } }

/* Live: context keeps arriving. Each source sends a spark in turn, the core answers, the light runs on. */
html.js:not(.rm) .os-cover.is-live .oc-spark--in { animation: oc-pulse-in 3.6s var(--ease-io) calc(0.2s + var(--k) * 0.3s) infinite; }
html.js:not(.rm) .os-cover.is-live .oc-spark--out { animation: oc-pulse-out 3.6s var(--ease-io) calc(0.2s + var(--k) * 0.3s) infinite; }
html.js:not(.rm) .os-cover.is-live .oc-halo { animation: oc-breathe 3.6s ease-in-out 0.2s infinite; }
html.js:not(.rm) .os-cover.is-live.is-drawing .oc-spark--in { animation: oc-run 1s var(--ease-io) calc(0.15s + var(--k) * 0.12s) both, oc-pulse-in 3.6s var(--ease-io) calc(3s + var(--k) * 0.3s) infinite; }
html.js:not(.rm) .os-cover.is-live.is-drawing .oc-spark--out { animation: oc-run 0.9s var(--ease-io) calc(1.3s + var(--k) * 0.1s) both, oc-pulse-out 3.6s var(--ease-io) calc(3s + var(--k) * 0.3s) infinite; }
html.js:not(.rm) .os-cover.is-live.is-drawing .oc-halo { animation: oc-halo 1.2s var(--ease-out) 1.05s both, oc-breathe 3.6s ease-in-out 3s infinite; }
@keyframes oc-pulse-in { 0% { stroke-dashoffset: 0.06; opacity: 0; } 2% { opacity: 1; } 30% { stroke-dashoffset: -1; opacity: 1; } 31%, 100% { stroke-dashoffset: -1; opacity: 0; } }
@keyframes oc-pulse-in-tail { 0% { stroke-dashoffset: 0.2; opacity: 0; } 2% { opacity: 0.55; } 27% { opacity: 0.55; } 30% { stroke-dashoffset: -0.86; opacity: 0; } 31%, 100% { stroke-dashoffset: -0.86; opacity: 0; } }
@keyframes oc-pulse-out-tail { 0%, 33% { stroke-dashoffset: 0.2; opacity: 0; } 35% { opacity: 0.55; } 57% { opacity: 0.55; } 60% { stroke-dashoffset: -0.86; opacity: 0; } 61%, 100% { stroke-dashoffset: -0.86; opacity: 0; } }
@keyframes oc-pulse-out { 0%, 33% { stroke-dashoffset: 0.06; opacity: 0; } 35% { opacity: 1; } 60% { stroke-dashoffset: -1; opacity: 1; } 61%, 100% { stroke-dashoffset: -1; opacity: 0; } }
@keyframes oc-breathe { 0%, 26% { opacity: 0.9; transform: scale(1); } 36% { opacity: 1; transform: scale(1.09); } 62%, 100% { opacity: 0.9; transform: scale(1); } }

/* The tails and the bloom follow the same story. */
html.js:not(.rm) .os-cover.is-drawing .oc-tail.oc-spark--in { animation: oc-run-tail 1s var(--ease-io) calc(0.15s + var(--k) * 0.12s) both; }
html.js:not(.rm) .os-cover.is-drawing .oc-tail.oc-spark--out { animation: oc-run-tail 0.9s var(--ease-io) calc(1.3s + var(--k) * 0.1s) both; }
html.js:not(.rm) .os-cover.is-drawing .oc-bloom { animation: oc-bloom 1.6s var(--ease-out) 1.05s both; }
html.js:not(.rm) .os-cover.is-live .oc-tail.oc-spark--in { animation: oc-pulse-in-tail 3.6s var(--ease-io) calc(0.2s + var(--k) * 0.3s) infinite; }
html.js:not(.rm) .os-cover.is-live .oc-tail.oc-spark--out { animation: oc-pulse-out-tail 3.6s var(--ease-io) calc(0.2s + var(--k) * 0.3s) infinite; }
html.js:not(.rm) .os-cover.is-live.is-drawing .oc-tail.oc-spark--in { animation: oc-run-tail 1s var(--ease-io) calc(0.15s + var(--k) * 0.12s) both, oc-pulse-in-tail 3.6s var(--ease-io) calc(3s + var(--k) * 0.3s) infinite; }
html.js:not(.rm) .os-cover.is-live.is-drawing .oc-tail.oc-spark--out { animation: oc-run-tail 0.9s var(--ease-io) calc(1.3s + var(--k) * 0.1s) both, oc-pulse-out-tail 3.6s var(--ease-io) calc(3s + var(--k) * 0.3s) infinite; }
html.js:not(.rm) .os-cover:not(.is-drawn):not(.is-drawing) .oc-bloom { opacity: 0; }

/* Where the cover sits. */
.li-float-os { position: absolute; inset: 0; opacity: 0; transition: opacity 260ms ease; }
.li-float-os.is-on { opacity: 1; }
/* A story begun while the pointer crossed the row waits, paused, until the drawing is shown again (review round, motion check). */
/* !important: each story rule's animation shorthand resets the play state, at up to seven classes. */
.li-float-os:not(.is-on) [data-os-cover] * { animation-play-state: paused !important; }
.li-cover--os { background: var(--night); }
.sp-next-cover--os { background: var(--night); overflow: hidden; }

/* ---------------------------------------------------------------- a section's proof (the review round)
   Live text in a sheet under the light: a check's own output, or rows of the routing map. On arrival the
   lines come in one after another (60 ms apart, 500 ms, the site's ease out); the line that matters then
   lights, and on the map the light runs down the paths and rests on its row. Without scripts and under
   reduced motion, all of it is there and lit. */
.proof { margin-top: 36px; }
.proof-sheet { width: 100%; background: rgba(13, 24, 34, 0.72); border: 1px solid var(--line); border-radius: 3px; box-shadow: 0 30px 80px -40px rgba(0, 0, 0, 0.8); }
.proof figcaption { margin-top: 14px; font: 400 0.9375rem/1.5 var(--sans); color: var(--mist); }
.proof--notice .proof-sheet { padding: 22px 26px 24px; font: 400 0.8125rem/1.7 ui-monospace, "Cascadia Mono", "SF Mono", Consolas, monospace; color: var(--mist); overflow-wrap: anywhere; }
.proof--notice :is(.proof-title, .proof-line) { font: inherit; max-width: none; }
.proof-title { color: var(--ink); margin-bottom: 10px; }
.proof-line + .proof-line { margin-top: 4px; }
.proof .is-key { color: #ffdcb4; text-shadow: 0 0 14px rgba(255, 179, 102, 0.45); }
.proof-table { border-collapse: separate; border-spacing: 0; font-family: var(--sans); font-size: 0.9375rem; }
.proof-table th { text-align: left; font-weight: 450; color: var(--mist); padding: 14px 22px 10px; border-bottom: 1px solid var(--line); }
.proof-table td { padding: 12px 22px; border-bottom: 1px solid rgba(236, 228, 216, 0.06); vertical-align: top; }
.proof-table tr:last-child td { border-bottom: 0; }
.proof-table td:first-child { color: var(--ink); width: 46%; }
.proof-table code { font: 400 0.8125rem/1.6 ui-monospace, "Cascadia Mono", "SF Mono", Consolas, monospace; color: var(--mist); overflow-wrap: anywhere; }
.proof-table tr.is-key td { background: rgba(255, 179, 102, 0.07); }
.proof-table tr.is-key code, .proof-table tr.is-key td:first-child { color: #ffdcb4; text-shadow: 0 0 14px rgba(255, 179, 102, 0.45); }
/* A clip: the loop over its poster, across the section's full width below the text (the reviews of round 4:
   at the text column's 704 px its captions and the case's text were too small), the square cut on a phone.
   Its pause button ends the caption line, outside the picture. */
.sp-section > .proof--clip { grid-column: 1 / -1; margin-top: 12px; }
.proof-clip { aspect-ratio: 1600 / 1000; background: var(--night); box-shadow: 0 30px 80px -40px rgba(0, 0, 0, 0.8); }
.proof-clip img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* A clip that opens on its first frame (Snafu's S) waits in that frame's colour, not its poster, wherever it will
   play; site.js adds .is-poster when it cannot (reduced motion, a refused or failed video). */
html.js:not(.rm) .proof-clip[data-loop-dark] { background: #102a2e; }
html.js:not(.rm) .proof-clip[data-loop-dark]:not(.is-poster) picture { visibility: hidden; }
.proof--clip { position: relative; }
.proof--clip figcaption { padding-right: 104px; }
.clip-toggle { position: absolute; right: 0; bottom: -12px; display: inline-flex; align-items: center; gap: 10px; min-height: 44px; padding: 0 2px;
  border: 0; background: none; font: 400 0.9375rem/1 var(--sans); color: var(--mist); cursor: pointer; transition: color 220ms ease; }
.clip-toggle::before { content: ""; width: 8px; height: 10px; border-left: 2px solid currentColor; border-right: 2px solid currentColor; box-sizing: border-box; }
.clip-toggle.is-held::before { width: 0; height: 0; border-left: 9px solid currentColor; border-right: 0;
  border-top: 5px solid transparent; border-bottom: 5px solid transparent; }
.clip-toggle[hidden] { display: none; }
.clip-toggle:hover, .clip-toggle.is-held { color: var(--ink); }
@media (max-width: 640px) {
  .proof-clip { aspect-ratio: 1; }
  .proof--notice .proof-sheet { padding: 18px 18px 20px; font-size: 0.75rem; }
  .proof-table th, .proof-table td { padding-inline: 14px; }
  .proof-table td:first-child { width: 44%; }
}
/* The arrival. */
html.js:not(.rm) .proof :is(.proof-title, .proof-line, tr) { transition: opacity 500ms var(--ease-out), transform 500ms var(--ease-out); transition-delay: calc(var(--i) * 60ms); }
html.js:not(.rm) .proof:not(.is-in) :is(.proof-title, .proof-line, tr) { opacity: 0; transform: translateY(8px); }
html.js:not(.rm) .proof .is-key { transition: opacity 500ms var(--ease-out), transform 500ms var(--ease-out), color 900ms ease, text-shadow 1200ms var(--ease-out); transition-delay: calc(var(--i) * 60ms), calc(var(--i) * 60ms), 900ms, 900ms; }
html.js:not(.rm) .proof:not(.is-in) .is-key { color: inherit; text-shadow: 0 0 14px rgba(255, 179, 102, 0); }
/* The key row's words light as the pass reaches them (500 + 2 x 90 ms + 40% of 700 ms), never before. */
html.js:not(.rm) .proof-table tr.is-key td { transition: background-color 900ms ease 1000ms, color 600ms ease 960ms, text-shadow 900ms var(--ease-out) 960ms; }
html.js:not(.rm) .proof-table tr.is-key code { transition: color 600ms ease 960ms, text-shadow 900ms var(--ease-out) 960ms; }
html.js:not(.rm) .proof:not(.is-in) tr.is-key td { background: transparent; }
html.js:not(.rm) .proof:not(.is-in) tr.is-key :is(code, td:first-child) { color: inherit; text-shadow: none; }
/* On the map the light runs down the paths, one row after another, before it rests. */
html.js:not(.rm) .proof--map.is-in tbody code { animation: proof-pass 700ms ease-in-out both; animation-delay: calc(500ms + var(--i) * 90ms); }
html.js:not(.rm) .proof--map.is-in tbody tr.is-key code { animation: none; }
@keyframes proof-pass { 0%, 100% { color: var(--mist); text-shadow: 0 0 10px rgba(255, 179, 102, 0); } 40% { color: #ffdcb4; text-shadow: 0 0 10px rgba(255, 179, 102, 0.5); } }

/* ------------------------------------------------ Snafu's page (2026-10-03, night)
   The site's night and lamp, with Snafu's own two colours let into the type on this page only (Brent:
   "integrate in the typography a little bit of the colours of Snafu"): its sage, the app's colour for a
   confirmed place, on held seats, held lines and the title's lit words; its amber on its route-shaped S. */
[data-page="snafu"] { --sage: var(--lg-green); --sage-hi: #d6ecdd; --s-amber: var(--lg-amber); --s-sky: var(--lg-sky); }
[data-page="snafu"] .sp-title .lit, #snafu.feature-showcase .feature-title .lit { color: #d6ecdd; text-shadow: 0 0 .3em rgba(169, 209, 181, .42), 0 0 .9em rgba(169, 209, 181, .2); }
html.js:not(.rm) [data-page="snafu"] .sp-title .lit:not(.is-lit), html.js:not(.rm) #snafu.feature-showcase .feature-title .lit:not(.is-lit) { color: inherit; text-shadow: 0 0 .3em rgba(169, 209, 181, 0), 0 0 .9em rgba(169, 209, 181, 0); }

/* The arrival lines. x is the clock from 18:30; each row's line ends where its vehicle reaches the hotel
   (--w), at the moment the sweep gets there (--t, seconds into the draw). The drawn state is the default;
   with scripts on and motion allowed, the clock runs once from 0.7 s. --clock is registered so it animates. */
@property --clock { syntax: '<number>'; inherits: true; initial-value: 1; }
.al { --label: 15em; --gap: 24px; margin-top: clamp(28px, 3vw, 48px); }
.al-rows { position: relative; display: grid; gap: clamp(14px, 1.6vw, 24px); padding-top: 34px; }
.al-row { display: grid; grid-template-columns: var(--label) minmax(0, 1fr); align-items: center; gap: var(--gap); }
.al-name { font: 400 .9375rem/1.35 var(--sans); color: var(--mist); }
.al-name b { display: block; font: 400 1.125rem/1.3 var(--serif); color: #d6d0c7; }
.al-track { position: relative; height: 14px; }
.al-line, .al-dash { position: absolute; left: 0; top: 6px; height: 2px; border-radius: 2px; width: min(var(--w), calc(var(--clock) * 100%)); }
.al-line { background: linear-gradient(90deg, rgba(169, 209, 181, .06), var(--sage)); }
.al-dash { width: var(--w); opacity: 0; background: repeating-linear-gradient(90deg, rgba(140, 152, 165, .5) 0 6px, transparent 6px 11px); }
.al-dot { position: absolute; top: 2px; left: min(var(--w), calc(var(--clock) * 100%)); width: 10px; height: 10px; margin-left: -5px; border-radius: 50%; background: var(--sage-hi); }
.al-t { position: absolute; left: calc(var(--w) + 14px); top: -3px; font: 450 .9375rem/1.3 var(--sans); color: var(--ink); font-variant-numeric: tabular-nums; white-space: nowrap; }
.al-t i { font-style: normal; font-weight: 400; color: var(--mist); }
/* No ride booked: an open ring where the transfer should start and a dashed stub that goes nowhere, in amber. */
.is-missing .al-line { opacity: 0; }
.is-missing .al-dash { left: 9px; width: 24px; opacity: 1; background: repeating-linear-gradient(90deg, rgba(244, 185, 117, .85) 0 4px, transparent 4px 8px); }
.is-missing .al-dot { margin-left: 0; background: transparent; border: 1.5px solid var(--s-amber); }
.is-missing .al-t { left: 44px; }
:is(.is-missing, .is-gone) .al-t i { color: var(--s-amber); }
.is-gone .al-line { opacity: 0; }
.is-gone .al-dash { opacity: 1; }
.is-gone .al-dot { background: transparent; border: 1px solid rgba(244, 185, 117, .7); }
.is-gone .al-t { color: var(--mist); }
/* The lamp on the last arrival is light, never a warning: paler than amber (Brent, 2026-10-03, night). */
.is-lit .al-line { background: linear-gradient(90deg, rgba(169, 209, 181, .06), var(--sage) 70%, #eef8f1); }
.is-lit .al-dot { background: #fffaf2; box-shadow: 0 0 0 4px rgba(255, 240, 222, .18), 0 0 24px 6px rgba(255, 226, 190, .38); }
.is-lit .al-t { left: var(--w); top: -24px; transform: translateX(-50%); color: var(--ink); }
/* At the end the waiting row is resolved: what was missing stays named, no longer in the problem's amber. */
.is-resolved .al-dash { background: repeating-linear-gradient(90deg, rgba(181, 201, 199, .45) 0 4px, transparent 4px 8px); }
.is-resolved .al-dot { border-color: rgba(181, 201, 199, .5); }
.is-resolved .al-t i { color: var(--mist); }
.al-deadline { position: absolute; top: 28px; bottom: 0; width: 1px; left: calc(var(--label-w, 15em) + var(--gap) + (100% - var(--label-w, 15em) - var(--gap)) * var(--x-n)); background: rgba(236, 228, 216, .5); }
.al-deadline span { position: absolute; top: -28px; left: 0; transform: translateX(calc(-100% - 10px)); white-space: nowrap; font: 450 .9375rem/1.3 var(--sans); color: var(--ink); }
.al-sweep { position: absolute; top: 34px; bottom: -6px; left: calc(var(--label-w, 15em) + var(--gap)); right: 0; pointer-events: none; opacity: 0; }
.al-sweep::after { content: ""; position: absolute; top: 0; bottom: 0; left: calc(var(--clock) * 100%); width: 1px; background: linear-gradient(180deg, transparent, rgba(236, 228, 216, .55) 20%, rgba(236, 228, 216, .55) 80%, transparent); }
.al-axis { display: grid; grid-template-columns: var(--label) minmax(0, 1fr); gap: var(--gap); margin-top: 18px; }
.al-ticks { position: relative; height: 22px; border-top: 1px solid var(--line); font: 400 .8125rem/1 var(--sans); color: var(--mist); font-variant-numeric: tabular-nums; }
.al-ticks span { position: absolute; top: 8px; transform: translateX(-50%); }
.al-ticks span:first-child { transform: none; }
.al figcaption { margin-top: 14px; font: 400 .9375rem/1.5 var(--sans); color: var(--mist); }
html.js:not(.rm) .al-rows { animation: al-clock calc(var(--tend) * 1s) linear .7s both; }
html.js:not(.rm) .al-sweep { animation: al-sweep calc(var(--tend) * 1s + .9s) ease .6s both; }
html.js:not(.rm) .al-row:not(.is-missing) .al-t { animation: al-in 420ms cubic-bezier(.23, 1, .32, 1) calc(.7s + var(--t) * 1s) both; }
html.js:not(.rm) .al-row:not(.is-missing) .al-dot { animation: al-in 200ms ease-out .7s both; }
html.js:not(.rm) .is-missing :is(.al-dash, .al-dot, .al-t) { animation: al-in 500ms cubic-bezier(.23, 1, .32, 1) .45s both; }
html.js:not(.rm) .is-gone .al-line { animation: al-out 380ms ease calc(.85s + var(--t) * 1s) both; }
html.js:not(.rm) .is-gone .al-dash { animation: al-in 380ms ease calc(.85s + var(--t) * 1s) both; }
html.js:not(.rm) .is-gone .al-dot { animation: al-in 200ms ease-out .7s both, al-gone 380ms ease calc(.85s + var(--t) * 1s) both; }
html.js:not(.rm) .is-lit .al-dot { animation: al-in 200ms ease-out .7s both, al-arrive 1400ms cubic-bezier(.23, 1, .32, 1) calc(.7s + var(--t) * 1s) both; }
html.js:not(.rm) .al-deadline { animation: al-in 900ms ease .3s both; }
@keyframes al-clock { from { --clock: 0; } to { --clock: var(--end); } }
@keyframes al-sweep { 0% { opacity: 0; } 12%, 80% { opacity: 1; } 100% { opacity: 0; } }
@keyframes al-in { from { opacity: 0; } }
@keyframes al-out { to { opacity: 0; } }
@keyframes al-gone { from { background: var(--sage-hi); border-color: transparent; } }
@keyframes al-arrive { from { background: var(--sage-hi); box-shadow: 0 0 0 0 rgba(255, 240, 222, 0), 0 0 0 0 rgba(255, 226, 190, 0); } 35% { box-shadow: 0 0 0 7px rgba(255, 240, 222, .2), 0 0 40px 12px rgba(255, 226, 190, .45); } }
@media (max-width: 640px) {
  .al-rows { padding-top: 40px; gap: 26px; }
  .al-row, .al-axis { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .al-axis > span { display: none; }
  .al-deadline, .al-sweep { --label-w: 0px; --gap: 0px; }
  .al-deadline span { left: auto; right: -1px; transform: translateY(-4px); }
  .al-sweep { top: 40px; }
  .al-row:not(.is-missing) .al-track { margin-top: 18px; }
  .al-row:not(.is-missing) .al-t { top: auto; bottom: 10px; left: auto; right: calc(100% - var(--w) - 5px); transform: none; }
  .al-name b { font-size: 1.0625rem; }
}

/* A demo not yet open: the button's shape, inert, with its reason beside it. */

/* The manifest: one mark per guest, grouped by vehicle, in four saved states the visitor picks. */
.mf-board { --ink: var(--lg-ink); --mist: var(--lg-muted); --line: var(--lg-line); position: relative; padding: clamp(24px, 3vw, 44px); border-radius: 22px; color: var(--lg-ink);
  background: radial-gradient(120% 85% at 72% -8%, #1d454b 0%, var(--lg-bg) 52%, #0b2124 100%);
  box-shadow: inset 0 1px rgba(255, 255, 255, .09), inset 0 0 0 1px rgba(169, 209, 181, .07), 0 60px 140px -60px #000, 0 -40px 120px -70px rgba(255, 179, 102, .4); }
.mf-top { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 8px 32px; font: 400 .9375rem/1.5 var(--sans); color: var(--mist); }
.mf-top b { font-weight: 450; color: var(--ink); }
.mf-steps { display: none; grid-template-columns: repeat(4, minmax(0, 1fr)); margin-top: clamp(24px, 2.6vw, 36px); border-top: 1px solid var(--line); }
.mf-board.is-live .mf-steps { display: grid; }
.mf-step { position: relative; display: grid; gap: 2px; padding: 16px 16px 6px 0; min-height: 44px; text-align: left; font: 400 .9375rem/1.4 var(--sans); color: var(--mist); background: none; border: 0; cursor: pointer; transition: color 180ms ease; }
.mf-step span { font-variant-numeric: tabular-nums; font-weight: 450; color: var(--mist); }
.mf-step::before { content: ''; position: absolute; top: -1px; left: 0; right: 16px; height: 1px; background: var(--s-sky); box-shadow: 0 0 4px 1px rgba(187, 220, 244, .5), 0 0 14px 2px rgba(187, 220, 244, .2); transform: scaleX(0); transform-origin: left; transition: transform 500ms cubic-bezier(.23, 1, .32, 1); }
.mf-step[aria-pressed="true"] { color: var(--ink); }
.mf-step[aria-pressed="true"] span { color: var(--s-sky); }
.mf-step[aria-pressed="true"]::before { transform: scaleX(1); }
.mf-step:focus-visible { outline: 2px solid var(--s-sky); outline-offset: 4px; }
@media (hover: hover) and (pointer: fine) { .mf-step:not([aria-pressed="true"]):hover { color: #dbe6e3; } }
.mf-say { margin-top: clamp(32px, 3.6vw, 52px); max-width: 30em; font: 350 clamp(1.375rem, 1.1rem + .7vw, 1.875rem)/1.35 var(--serif); color: var(--ink); text-wrap: pretty; min-height: 2.7em; }
.mf-groups { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 28px clamp(32px, 4vw, 64px); margin-top: clamp(28px, 3vw, 44px); }
.mf-group { display: grid; gap: 14px; }
.mf-name { font: 400 1.125rem/1.3 var(--serif); color: var(--lg-ink); }
.mf-name.is-gone { color: var(--mist); text-decoration: line-through; text-decoration-color: rgba(244, 185, 117, .8); text-decoration-thickness: 1px; }
.mf-seats { --s: clamp(18px, 2.6vw, 40px); display: grid; grid-template-columns: repeat(var(--cols), var(--s)); gap: clamp(6px, .7vw, 10px); }
.mf-seat { width: var(--s); height: var(--s); border-radius: 22% 22% 12% 12%; border: 1px solid rgba(181, 201, 199, .42); background: rgba(181, 201, 199, .3); transition: background-color 220ms cubic-bezier(.23, 1, .32, 1), border-color 220ms cubic-bezier(.23, 1, .32, 1); }
.mf-seat.is-held { border-color: var(--sage); background: var(--sage); }
.mf-group.is-gone .mf-seat { border: 1px dashed rgba(244, 185, 117, .75); background: transparent; }
.mf-seat.is-wc { display: grid; place-items: center; }
.mf-seat.is-wc svg { width: 72%; height: 72%; color: var(--ink); }
.mf-seat.is-wc.is-held svg { color: var(--lg-bg); }
.mf-foot { font: 400 .9375rem/1.45 var(--sans); color: var(--mist); font-variant-numeric: tabular-nums; }
.mf-sum { display: flex; flex-wrap: wrap; gap: 8px 40px; margin-top: clamp(28px, 3vw, 44px); padding-top: 18px; border-top: 1px solid var(--line); font: 400 .9375rem/1.5 var(--sans); color: var(--ink); font-variant-numeric: tabular-nums; }
.mf-sum .is-ok { color: var(--sage-hi); }
.mf-sum .is-ask { color: var(--s-amber); }
.mf-budget { height: 3px; margin-top: 14px; background: var(--lg-raised); border-radius: 2px; overflow: hidden; }
.mf-budget span { display: block; height: 100%; background: var(--s-sky); box-shadow: 0 0 10px rgba(187, 220, 244, .5); transform: scaleX(var(--b)); transform-origin: left; transition: transform 220ms cubic-bezier(.23, 1, .32, 1); }
.mf figcaption { margin-top: 16px; font: 400 1rem/1.5 var(--sans); color: var(--mist); max-width: 60em; }
html.rm .mf-step::before, html.rm .mf-seat, html.rm .mf-budget span { transition: none; }
@media (max-width: 640px) {
  .mf-board { padding: 20px 16px; margin-inline: calc(var(--gutter) * -1 + 8px); }
  .mf-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); border-top: 0; }
  .mf-step { border-top: 1px solid var(--line); padding: 14px 12px 10px 0; }
  .mf-seats { --s: 22px; gap: 6px; grid-template-columns: repeat(auto-fill, var(--s)); }
  .mf-group { width: 100%; }
  .mf-say { min-height: 0; }
}

/* A saved AI reading as live text: the words the model quoted lit once the sheet has arrived. */
.proof--reading .proof-sheet > .rd-part { padding: 20px 24px; }
.sp-section > .proof--reading { grid-column: 1 / -1; margin-top: 12px; }
@media (min-width: 901px) {
  .proof--reading .proof-sheet { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
  .proof--reading .rd-part:first-child { grid-row: span 2; border-right: 1px solid var(--line); }
  .proof--reading .rd-part:first-child + .rd-part { border-top: 0; }
  .rd-counts dd { white-space: nowrap; }
}
.rd-part + .rd-part { border-top: 1px solid var(--line); }
.rd-k { font: 400 .9375rem/1.5 var(--sans); color: var(--mist); }
.rd-msg { margin-top: 8px; font: 400 1.125rem/1.6 var(--serif); color: #d6d0c7; }
.rd-quote { color: #fff1e0; background: linear-gradient(transparent 62%, rgba(187, 220, 244, .24) 62%); padding: 0 1px; transition: background-size 900ms cubic-bezier(.23, 1, .32, 1) 700ms; background-size: 100% 100%; background-repeat: no-repeat; }
html.js:not(.rm) .proof--reading:not(.is-in) .rd-quote { background-size: 0% 100%; color: inherit; }
.rd-counts { display: grid; gap: 4px; margin-top: 10px; font: 400 1rem/1.5 var(--sans); }
.rd-counts div { display: grid; grid-template-columns: 11em 1fr; gap: 16px; }
.rd-counts dt { color: var(--mist); }
.rd-counts dd { color: var(--ink); }
.rd-counts dd.is-open { color: var(--s-amber); }
.rd-qs { margin-top: 8px; display: grid; gap: 6px; padding: 0; font: 400 1.0625rem/1.5 var(--serif); color: var(--ink); list-style: none; }
html.js:not(.rm) .proof--reading .rd-part { transition: opacity 500ms var(--ease-out), transform 500ms var(--ease-out); transition-delay: calc(var(--i) * 90ms); }
html.js:not(.rm) .proof--reading:not(.is-in) .rd-part { opacity: 0; transform: translateY(8px); }

/* Tables of the real thing: offers and parts, the rows that matter lit. */
.tbl-scroll { overflow-x: auto; overflow-y: hidden; }
.proof--table.is-wide { grid-column: 1 / -1; margin-top: 12px; }
.tbl { width: 100%; border-collapse: separate; border-spacing: 0; font: 400 .9375rem/1.45 var(--sans); font-variant-numeric: tabular-nums; }
.tbl th { padding: 14px 18px 10px; text-align: left; font-weight: 400; color: var(--mist); border-bottom: 1px solid var(--line); white-space: nowrap; }
.tbl td { padding: 12px 18px; vertical-align: top; color: #a9a6a1; border-bottom: 1px solid rgba(236, 228, 216, .06); }
.tbl tr:last-child td { border-bottom: 0; }
.tbl td:first-child { color: var(--prose); }
.tbl .num { text-align: right; white-space: nowrap; }
.th-wc { display: none; }
.tbl tr.is-key td { color: var(--ink); text-shadow: none; }
.tbl tr.is-key td:first-child { color: var(--sage-hi); }
.tbl .st { white-space: nowrap; color: var(--ink); }
.tbl .st i { font-style: normal; color: var(--mist); }
.tbl .st::before { content: ""; display: inline-block; width: 6px; height: 6px; margin-right: 9px; border-radius: 50%; vertical-align: 2px; background: currentColor; }
.tbl :is(.st--built, .st--live, .st--run) { color: var(--sage-hi); }
.tbl .st--pilot { color: var(--ink); }
.tbl .st--pilot::before { background: linear-gradient(90deg, currentColor 50%, transparent 50%); box-shadow: inset 0 0 0 1px currentColor; }
.tbl .st--next { color: var(--mist); }
.tbl .st--next::before { background: none; border: 1px dashed currentColor; width: 5px; height: 5px; }
.tbl--build td:first-child { color: var(--ink); }
html.js:not(.rm) .proof--table tr { transition: opacity 500ms var(--ease-out), transform 500ms var(--ease-out); transition-delay: calc(var(--i) * 50ms); }
html.js:not(.rm) .proof--table:not(.is-in) tr { opacity: 0; transform: translateY(8px); }
@media (max-width: 640px) {
  .tbl--build thead { display: none; }
  .tbl--build tr { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px 16px; padding: 14px 16px; border-bottom: 1px solid var(--line); }
  .tbl--build td { padding: 0; border: 0; }
  .tbl--build td:nth-child(3) { grid-column: 1 / -1; }
  .tbl--build td:nth-child(2) { grid-column: 1; grid-row: 2; color: var(--mist); }
  .tbl--build td.st { grid-column: 2; grid-row: 1; }
  .tbl--offers th:nth-child(6) { display: none; }
  .tbl.tbl--offers :is(th, td) { padding: 0; }
  .tbl--offers .th-full { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .tbl--offers .th-wc { display: inline-block; width: 16px; height: 16px; vertical-align: -3px; }
  .tbl--offers tr { display: grid; grid-template-columns: minmax(0, 1fr) 2em 2em 3.2em 3.6em; column-gap: 10px; padding: 12px 12px; border-bottom: 1px solid rgba(236, 228, 216, .06); }
  .tbl--offers :is(th, td) { padding: 0; border: 0; }
  .tbl--offers thead tr { padding-top: 14px; border-bottom-color: var(--line); }
  .tbl--offers td:nth-child(6) { grid-column: 1 / -1; margin-top: 4px; color: var(--mist); }
  .tbl th, .tbl td { padding-inline: 12px; }
}

/* A picture not yet at the level: a marked frame, never shipped (tools/check.cjs). */
.pending-frame { display: grid; place-content: center; gap: 8px; padding: 24px; text-align: center; border: 1px dashed rgba(244, 185, 117, .4); border-radius: 4px; background: repeating-linear-gradient(135deg, rgba(236, 228, 216, .025) 0 14px, transparent 14px 28px), var(--night); }
.pending-t { font: 300 clamp(1.5rem, 1rem + 1.4vw, 2.25rem)/1.2 var(--serif); color: var(--ink); }
.pending-n { max-width: 32em; font: 400 .9375rem/1.5 var(--sans); color: var(--s-amber); }

/* ------------------------------------------------ Snafu's story on the home, in Lagoon (2026-10-03, morning)
   Brent's pick for Snafu, with his two conditions: green only for a held place, sky only for an action (the
   approve press, the budget), never a status; amber only for a problem. The lamp stays light: it lands on 19:55.
   The HTML is the run's end; snafu-lead.js plays the run while the window is seen. */
:root { --lg-bg: #102a2e; --lg-surface: #17383d; --lg-raised: #24494f; --lg-ink: #f0f4ee; --lg-muted: #b5c9c7;
  --lg-sky: #bbdcf4; --lg-green: #a9d1b5; --lg-amber: #f4b975; --lg-line: rgba(240, 244, 238, .07); }
.sl-stage { position: relative; margin-top: 44px; }
.sl-window { position: relative; display: block; overflow: hidden; isolation: isolate; border-radius: 22px; color: var(--lg-ink); text-decoration: none;
  padding: clamp(20px, 3vw, 40px) clamp(20px, 3.4vw, 48px) clamp(18px, 2.4vw, 30px);
  background: radial-gradient(120% 85% at 72% -8%, #1d454b 0%, var(--lg-bg) 52%, #0b2124 100%);
  box-shadow: inset 0 1px rgba(255, 255, 255, .09), inset 0 0 0 1px rgba(169, 209, 181, .07), 0 60px 140px -60px #000, 0 -40px 120px -70px rgba(255, 179, 102, .45);
  transition: box-shadow 400ms var(--ease-out); }
.sl-window::after { content: ""; position: absolute; inset: 0 8% auto; height: 1px; background: linear-gradient(90deg, transparent, rgba(255, 214, 170, .55), transparent); pointer-events: none; }
.sl-window:focus-visible { outline: 2px solid var(--lamp); outline-offset: 5px; }
@media (hover: hover) and (pointer: fine) {
  .sl-window:hover { box-shadow: inset 0 1px rgba(255, 255, 255, .12), inset 0 0 0 1px rgba(255, 179, 102, .28), 0 60px 140px -60px #000, 0 -40px 120px -60px rgba(255, 179, 102, .6); }
}
/* The lagoon's light: soft pools drifting under the surface, only while the window is seen. */
.sl-light { position: absolute; inset: -30%; z-index: -1; pointer-events: none;
  background: radial-gradient(28% 22% at 30% 40%, rgba(187, 220, 244, .085), transparent 70%), radial-gradient(26% 24% at 68% 62%, rgba(169, 209, 181, .07), transparent 70%), radial-gradient(18% 14% at 52% 30%, rgba(240, 244, 238, .04), transparent 70%);
  animation: sl-drift 22s ease-in-out infinite alternate paused; }
.sl-window.is-seen .sl-light { animation-play-state: running; }
@keyframes sl-drift { from { transform: translate3d(-4%, -2%, 0) rotate(0deg) scale(1); } to { transform: translate3d(5%, 3%, 0) rotate(8deg) scale(1.08); } }
.sl-warm { position: absolute; z-index: -1; right: -10%; bottom: -30%; width: 70%; height: 90%; pointer-events: none; opacity: .55;
  background: radial-gradient(closest-side, rgba(255, 179, 102, .16), rgba(255, 179, 102, .05) 50%, transparent); }
.sl-in, .sl-head { display: block; }
/* Behind Snafu's tile while it opens the story large in the window's middle (snafu-lead.js). */
.sl-halo { position: absolute; z-index: -1; left: 50%; top: 46%; width: 560px; height: 560px; margin: -280px 0 0 -280px; pointer-events: none; opacity: 0;
  background: radial-gradient(closest-side, rgba(169, 209, 181, .16), rgba(187, 220, 244, .06) 45%, transparent); }

.sl-top { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 24px; font: 400 .875rem/1.4 var(--sans); color: var(--lg-muted); }
.sl-brand { display: inline-flex; align-items: center; gap: 10px; font: 500 1.0625rem/1 var(--sans); color: var(--lg-ink); letter-spacing: -.005em; }
.sl-status { margin-left: auto; display: inline-flex; align-items: center; gap: 9px; padding: 7px 13px 7px 11px; border-radius: 999px; color: var(--lg-ink);
  background: rgba(240, 244, 238, .045); box-shadow: inset 0 0 0 1px rgba(240, 244, 238, .1); transition: box-shadow 300ms ease, background-color 300ms ease; }
.sl-status i { width: 7px; height: 7px; border-radius: 50%; background: var(--lg-muted); box-shadow: 0 0 0 3px rgba(181, 201, 199, .14); transition: background-color 300ms ease, box-shadow 300ms ease; }
.sl-status.is-ok { box-shadow: inset 0 0 0 1px rgba(169, 209, 181, .32); }
.sl-status.is-ok i { background: var(--lg-green); box-shadow: 0 0 0 3px rgba(169, 209, 181, .18), 0 0 12px 1px rgba(169, 209, 181, .55); }
.sl-status.is-problem { box-shadow: inset 0 0 0 1px rgba(244, 185, 117, .36); }
.sl-status.is-problem i { background: var(--lg-amber); box-shadow: 0 0 0 3px rgba(244, 185, 117, .18), 0 0 12px 1px rgba(244, 185, 117, .5); }

.sl-say { display: block; margin-top: clamp(22px, 2.6vw, 34px); min-height: 2.4em; max-width: 21em;
  font: 330 clamp(1.5rem, .95rem + 1.45vw, 2.5rem)/1.18 var(--serif); letter-spacing: -.012em; color: var(--lg-ink); text-wrap: balance; font-variant-numeric: tabular-nums; }
/* The words the AI quoted from the notice, marked as the app's highlighter does: sky, swept in once. */
.sl-quote { color: #f4fbff; background: linear-gradient(transparent 62%, rgba(187, 220, 244, .28) 62%) no-repeat; background-size: 100% 100%; animation: sl-mark 700ms var(--ease-out) 350ms both; }
@keyframes sl-mark { from { background-size: 0% 100%; } }
html.rm .sl-quote { animation: none; }
/* Held with the story: paused while the window is unseen or Pause is pressed. */
.sl-window:not(.is-seen) .sl-quote { animation-play-state: paused; }
.sl-lit { color: #e8f8ed; text-shadow: 0 0 .3em rgba(169, 209, 181, .62), 0 0 1.1em rgba(169, 209, 181, .3); }
.sl-mask { display: block; clip-path: inset(-.25em -2em -.18em -.1em); }
.sl-say-l { display: block; }

/* The chart: name, seats, track. Its deadline is one rule across the tracks on a wide screen, a tick in each track
   where the lanes stack. --s is a seat, --sg the gap between seats. */
.sl-chart { --name: 12.5em; --s: 17px; --sg: 5px; --cg: clamp(20px, 2.2vw, 36px); --seats: calc(18 * var(--s) + 17 * var(--sg));
  position: relative; display: block; margin-top: clamp(14px, 1.6vw, 22px); padding-top: 26px; font-size: 1rem; }
.sl-lane, .sl-axis, .sl-over { display: grid; grid-template-columns: var(--name) var(--seats) minmax(0, 1fr); column-gap: var(--cg); align-items: center; }
.sl-lane { padding-block: 13px; border-top: 1px solid var(--lg-line); }
.sl-lane:nth-child(2) { border-top: 0; }
/* Names and times sit above a travelling guest (z 2), so a flight passes under the text, never over it. */
.sl-name { position: relative; z-index: 3; display: block; font: 400 1.125rem/1.2 var(--serif); letter-spacing: -.005em; color: var(--lg-ink); transition: opacity 500ms var(--ease-out), color 400ms ease; }
.sl-name small { display: block; margin-top: 3px; font: 400 .8125rem/1.35 var(--sans); color: var(--lg-muted); }
.sl-seats { position: relative; justify-self: start; display: grid; grid-template-columns: repeat(var(--cols), var(--s)); gap: var(--sg); align-content: center; }
.sl-slot { position: relative; display: block; width: var(--s); height: var(--s); }
.sl-slot::before { content: ""; position: absolute; inset: 0; border-radius: 4px 4px 3px 3px; box-shadow: inset 0 0 0 1px rgba(181, 201, 199, .17); transition: opacity 500ms var(--ease-out); }
.sl-g { position: absolute; inset: 0; z-index: 2; display: grid; place-items: center; border-radius: 4px 4px 3px 3px;
  background: rgba(181, 201, 199, .3); box-shadow: inset 0 0 0 1px rgba(181, 201, 199, .42);
  transition: background-color 280ms var(--ease-out), box-shadow 280ms var(--ease-out); }
.sl-window.is-seen .sl-g { will-change: transform; }
.sl-g svg { width: 84%; height: 84%; color: var(--lg-ink); transition: color 280ms ease; }
.sl-g:empty::after, .mf-seat:not(.is-wc)::after { content: ""; position: absolute; left: 24%; right: 24%; bottom: 18%; height: 1.5px; border-radius: 1px; background: rgba(240, 244, 238, .45); }
.sl-g.is-held:empty::after, .mf-seat.is-held::after { background: rgba(16, 42, 46, .5); }
.mf-seat { position: relative; }
.sl-g.is-held { background: var(--lg-green); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .28), 0 0 10px rgba(169, 209, 181, .32); }
.sl-g.is-held svg { color: var(--lg-bg); }
.sl-g.is-lost { background: transparent; box-shadow: none; outline: 1px dashed rgba(244, 185, 117, .9); outline-offset: -1px; }
.sl-g.is-fly { box-shadow: inset 0 0 0 1px rgba(240, 244, 238, .7), 0 0 14px 2px rgba(220, 240, 255, .45); }
.sl-glint { position: absolute; inset: -4px; z-index: 3; overflow: hidden; pointer-events: none; border-radius: 6px; }
.sl-glint i { position: absolute; top: 0; bottom: 0; left: 0; width: 38%; opacity: 0; mix-blend-mode: screen;
  background: linear-gradient(100deg, transparent, rgba(240, 255, 246, .55) 50%, transparent); transform: translateX(-120%); }

/* --k draws a line from 0 to 1 by transforms only: the line scales from its start, the dot and (on a phone) the
   time ride with its end by translate, --f being the line's length in percent of the track (1cqw = 1 percent). */
.sl-track { position: relative; display: block; height: 16px; --k: 1; container-type: inline-size; transition: opacity 500ms var(--ease-out); }
.sl-track::before { content: ""; position: absolute; left: 0; right: 0; top: 7px; height: 1px; background: var(--lg-line); }
/* A proposed line is ink; it turns green only once its places are held (Brent's rule: green for a held place). */
.sl-line { position: absolute; left: 0; top: 6px; height: 3px; border-radius: 3px; width: var(--w); scale: var(--k) 1; transform-origin: 0 50%;
  background: linear-gradient(90deg, rgba(240, 244, 238, .04), rgba(240, 244, 238, .5)); transition: opacity 400ms ease; }
.sl-line::before { content: ""; position: absolute; inset: 0; border-radius: inherit; opacity: 0; transition: opacity 500ms var(--ease-out);
  background: linear-gradient(90deg, rgba(169, 209, 181, .06), var(--lg-green)); }
.is-kept .sl-line::before { opacity: 1; }
.sl-line::after { content: ""; position: absolute; inset: 0; border-radius: inherit; opacity: 0; transition: opacity 1400ms var(--ease-out);
  background: linear-gradient(90deg, rgba(169, 209, 181, .06), var(--lg-green) 70%, #eef8f1); }
.sl-dash { position: absolute; left: 0; top: 6.5px; height: 2px; width: var(--w); opacity: 0; transition: opacity 400ms ease;
  background: repeating-linear-gradient(90deg, rgba(181, 201, 199, .5) 0 6px, transparent 6px 11px); }
/* The script pops the dot by --ds and nudges the time by --tx, never by transform, which would clear translate. */
.sl-dot { position: absolute; z-index: 3; top: 2px; left: var(--w); translate: calc((var(--k) - 1) * var(--f) * 1cqw) 0; transform: scale(var(--ds, 1)); width: 11px; height: 11px; margin-left: -5.5px; border-radius: 50%;
  background: #e2f1e7; box-shadow: 0 0 0 3px rgba(169, 209, 181, .2); transition: background-color 400ms ease, box-shadow 400ms ease; }
.sl-t { position: absolute; z-index: 3; left: calc(var(--w) + 14px); top: -4px; transform: translateX(var(--tx, 0px)); font: 400 1.25rem/1 var(--serif); color: var(--lg-ink); white-space: nowrap; font-variant-numeric: tabular-nums; transition: color 400ms ease; }
.sl-t i { margin-left: 2px; font: 400 .875rem/1 var(--sans); color: var(--lg-muted); transition: opacity 300ms ease, color 300ms ease; }
.sl-tick { display: none; position: absolute; left: var(--x-dl); top: 0; width: 1px; height: 16px; background: rgba(240, 244, 238, .35); }
/* No ride booked: an open amber ring where the transfer should start, and a dashed stub that goes nowhere. */
.is-missing .sl-name { color: var(--lg-muted); }
.is-missing .sl-line { opacity: 0; }
.is-missing .sl-dash { left: 10px; width: 26px; opacity: 1; background: repeating-linear-gradient(90deg, rgba(244, 185, 117, .85) 0 4px, transparent 4px 8px); }
.is-missing .sl-dot { margin-left: 0; background: transparent; box-shadow: inset 0 0 0 1.5px var(--lg-amber), 0 0 10px rgba(244, 185, 117, .35); }
.is-missing .sl-t { left: 48px; }
.is-missing .sl-t i { color: var(--lg-amber); }
.sl-lane:not(.is-missing):not(.is-gone) .sl-t i { display: none; }
.is-missing .sl-slot::before { opacity: .38; }
.is-gone .sl-slot::before { opacity: .7; }
.is-gone .sl-name { color: var(--lg-muted); }
.is-gone .sl-n { text-decoration: line-through; text-decoration-color: rgba(244, 185, 117, .8); text-decoration-thickness: 1px; }
.is-gone .sl-line { opacity: 0; }
.is-gone .sl-dash { opacity: 1; }
.is-gone .sl-dot { background: transparent; box-shadow: inset 0 0 0 1px rgba(244, 185, 117, .75); }
.is-gone .sl-t { color: var(--lg-muted); }
.is-gone .sl-t i { color: var(--lg-amber); }
.is-lit .sl-line::after { opacity: 1; }
.is-lit .sl-dot { background: #fffaf2; box-shadow: 0 0 0 4px rgba(255, 240, 222, .2), 0 0 26px 8px rgba(255, 226, 190, .4); }
.is-lit .sl-t { color: var(--lg-ink); font-size: 1.875rem; }
.is-lit .sl-track.is-end .sl-t { top: -38px; }
/* At the end the waiting lane is resolved: "no ride booked" stays named, muted, no longer the problem's amber. */
.sl-lane.is-resolved .sl-t i { color: var(--lg-muted); }
.sl-lane.is-resolved .sl-dash { background: repeating-linear-gradient(90deg, rgba(181, 201, 199, .45) 0 4px, transparent 4px 8px); }
.sl-lane.is-resolved .sl-dot { box-shadow: inset 0 0 0 1.5px rgba(181, 201, 199, .5); }
.sl-track.is-end .sl-t, .is-gone .sl-t { left: auto; right: calc(100% - var(--w) - 6px); top: -28px; }
.sl-bloom { position: absolute; left: var(--w); top: 8px; width: 220px; height: 220px; margin: -110px 0 0 -110px; pointer-events: none; mix-blend-mode: screen;
  background: radial-gradient(closest-side, rgba(255, 240, 222, .30), rgba(255, 214, 170, .08) 45%, transparent); }
/* A lane not yet in the story: its name, seats' outlines and track hidden; the guests inside it are not. */
.sl-lane.is-off :is(.sl-name, .sl-track), .sl-lane.is-off .sl-slot::before { opacity: 0; }

.sl-over { position: absolute; inset: 0 0 34px; pointer-events: none; }
.sl-dl { position: relative; display: block; height: 100%; }
.sl-dl::before { content: ""; position: absolute; left: var(--x-dl); top: 0; bottom: 0; width: 1px;
  background: linear-gradient(180deg, rgba(240, 244, 238, .5), rgba(240, 244, 238, .32) 85%, transparent); }
.sl-dl b { position: absolute; left: var(--x-dl); top: -4px; transform: translateX(calc(-100% - 10px)); font: 450 .8125rem/1 var(--sans); color: var(--lg-ink); white-space: nowrap; }
.sl-axis { margin-top: 6px; }
.sl-ticks { position: relative; display: block; height: 22px; border-top: 1px solid var(--lg-line); font: 400 .75rem/1 var(--sans); color: var(--lg-muted); font-variant-numeric: tabular-nums; }
.sl-ticks span { position: absolute; top: 9px; transform: translateX(-50%); }
.sl-ticks span:first-child { transform: none; }

.sl-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 14px 32px; margin-top: clamp(18px, 2.2vw, 28px); padding-top: 18px; border-top: 1px solid var(--lg-line);
  font: 400 .875rem/1.4 var(--sans); color: var(--lg-muted); }
.sl-money { display: grid; gap: 9px; }
.sl-money-t { color: var(--lg-ink); font-variant-numeric: tabular-nums; }
.sl-budget { display: block; width: 220px; height: 3px; border-radius: 3px; background: var(--lg-raised); overflow: hidden; }
.sl-budget i { display: block; height: 100%; border-radius: 3px; background: var(--lg-sky); box-shadow: 0 0 10px rgba(187, 220, 244, .55); transform: scaleX(var(--b)); transform-origin: left; }
.sl-label { margin-left: auto; }
.sl-approve, .sl-cursor { display: none; }
html.js:not(.rm) .sl-approve { position: relative; display: inline-flex; align-items: center; justify-content: center; min-width: 8.6em; min-height: 38px; padding: 0 16px; border-radius: 9px; transition: background-color 180ms var(--ease-out), box-shadow 180ms var(--ease-out), color 0s;
  background: var(--lg-sky) linear-gradient(rgba(255, 255, 255, .24), transparent); color: var(--lg-bg); font: 500 .875rem/1 var(--sans);
  box-shadow: inset 0 1px rgba(255, 255, 255, .5), inset 0 -1px rgba(0, 0, 0, .12), 0 2px 8px rgba(0, 0, 0, .28); }
html.js:not(.rm) .sl-approve.is-done { background: rgba(240, 244, 238, .04); color: var(--lg-ink); box-shadow: inset 0 0 0 1px rgba(240, 244, 238, .22); }
.sl-approve b { font-weight: inherit; }
.sl-ripple { position: absolute; left: 62%; top: 58%; width: 40px; height: 40px; margin: -20px; border-radius: 50%; pointer-events: none; opacity: 0;
  box-shadow: 0 0 0 1px rgba(187, 220, 244, .9), 0 0 18px rgba(187, 220, 244, .6); }
html.js:not(.rm) .sl-cursor { position: absolute; left: 0; top: 0; z-index: 6; display: block; width: 24px; height: 24px; opacity: 0; pointer-events: none;
  filter: drop-shadow(0 3px 5px rgba(0, 0, 0, .45)); }
html.rm .sl-light { animation: none; }
html.rm .sl-in { transition: opacity 450ms ease; }

@media (max-width: 1080px) {
  .sl-lane { grid-template-columns: var(--name) minmax(0, 1fr); grid-template-areas: "name seats" "track track"; row-gap: 6px; padding-block: 8px; }
  .sl-name { grid-area: name; } .sl-seats { grid-area: seats; } .sl-track { grid-area: track; }
  .sl-track { margin-top: 18px; }
  :is(.is-missing, .is-wait) .sl-track { margin-top: 2px; }
  .sl-over { display: block; position: static; inset: auto; }
  .sl-dl { height: auto; }
  .sl-dl::before { display: none; }
  .sl-dl b { position: static; display: block; transform: none; text-align: right; margin: 0 0 6px; }
  /* Stacked lanes are two rows each; tighter, so four of them fit a tablet held landscape (design review 4). */
  .sl-chart { padding-top: 0; --s: 14px; --sg: 4px; }
  .sl-tick { display: block; }
  .sl-axis { grid-template-columns: minmax(0, 1fr); }
  .sl-axis > span:not(.sl-ticks) { display: none; }
  .sl-ticks span:last-child { transform: translateX(-100%); }
}
/* A short screen above phone width (under 760 px of window: a 1366 x 768 laptop, a tablet held landscape; a
   1440 x 900 laptop keeps its air): the window's air is taken in, so the sentence and every lane are in view
   together under the bar (design review 4). */
@media (min-width: 641px) and (max-height: 760px) {
  .sl-window { padding-top: clamp(18px, 2vw, 24px); padding-bottom: clamp(14px, 1.6vw, 20px); }
  .sl-say { margin-top: clamp(12px, 1.4vw, 16px); font-size: clamp(1.5rem, .95rem + 1.2vw, 2.125rem); }
  .sl-chart { margin-top: 8px; }
  .sl-lane { padding-block: 8px; }
  .sl-foot { margin-top: 12px; padding-top: 12px; }
}
@media (min-width: 641px) and (max-width: 1080px) and (max-height: 760px) {
  .sl-lane { padding-block: 6px; }
  .sl-track { margin-top: 6px; }
  .sl-chart { margin-top: 2px; }
}
@media (max-width: 640px) {
  .sl-stage { margin-inline: calc(var(--gutter) * -1 + 6px); }
  .sl-window { --pad-y: 18px; --pad-x: 16px; border-radius: 16px; padding: var(--pad-y) var(--pad-x) 16px; }
  .sl-route { display: none; }
  /* The lanes not yet used keep their empty places faintly, so the reserved height reads as places still to
     be found, not as a blank panel; no vehicle is named before Snafu proposes it. */
  .sl-lane.is-off .sl-slot::before { opacity: .5; }
  .sl-status { padding: 6px 11px 6px 9px; font-size: .8125rem; }
  .sl-say { margin-top: 16px; min-height: 3.6em; font-size: 1.3125rem; }
  .sl-chart { --s: 13px; --sg: 4px; margin-top: 4px; }
  .sl-lane { grid-template-columns: minmax(0, 1fr); grid-template-areas: "name" "seats" "track"; row-gap: 8px; padding-block: 10px 8px; }
  .sl-track { margin-top: 18px; }
  :is(.is-missing, .is-wait) .sl-track { margin-top: 2px; }
  .sl-foot { margin-top: 12px; padding-top: 14px; gap: 12px 20px; }
  .sl-t, .sl-track.is-end .sl-t { left: auto; right: calc(100% - var(--w) - 5px); translate: calc((var(--k) - 1) * var(--f) * 1cqw) 0; top: -22px; }
  .sl-t { font-size: 1.0625rem; }
  .is-lit .sl-t { font-size: 1.375rem; }
  .is-lit .sl-track.is-end .sl-t { top: -28px; }
  /* The cancelled time beside its open ring, not above it, where the lane's seats are. */
  .is-gone .sl-t { left: calc(var(--w) + 12px); right: auto; top: -4px; }
  :is(.is-missing, .is-wait) .sl-t { right: auto; left: 48px; top: -2px; translate: none; }
  .sl-name { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; }
  .sl-name, .sl-t { text-shadow: 0 0 2px var(--lg-bg), 0 0 7px var(--lg-bg), 0 0 12px var(--lg-bg); }
  .sl-name small { margin-top: 0; }
  .sl-label { margin-left: 0; order: 3; flex-basis: 100%; font-size: .8125rem; }
  .sl-budget { width: 150px; }
  html.js:not(.rm) .sl-approve { margin-left: auto; }
}
/* Under 360 px the waiting lane's 18 places fit inside the window (18 x 12 + 17 x 3 = 267 px; at 320 the window
   leaves 276). With 13 and 4 its last column was cut off (design review 3). */
@media (max-width: 360px) {
  .sl-chart { --s: 12px; --sg: 3px; }
}
/* Up to 400 px "cancelled" goes under its time, clear of the deadline's tick and inside the window. */
@media (max-width: 400px) {
  .is-gone .sl-t i { display: block; }
  .is-gone .sl-t { top: -14px; }
  /* The longest sum ("MXN 16,000 of MXN 18,000") stays beside Approve, so the window keeps its height while the
     story plays (accessibility review 4: it grew 43 px and back at 360). */
  .sl-foot { column-gap: 12px; }
  .sl-money-t { font-size: .8125rem; }
}
/* Under 350 px the longest status ("Approved, places reserved") cannot share a row with the name, so it always
   sits on its own row, rather than dropping there and back while the story plays (40 px at 320). */
@media (max-width: 350px) {
  .sl-brand { flex-basis: 100%; }
  .sl-status { margin-left: 0; }
}
/* On a phone the window is taller than the screen, so its sentence and status stay pinned under the bar while the
   lanes pass beneath them (Brent, 2026-10-04, from design review 4). Clip, not hidden: a hidden overflow is a
   scroll box, and sticky would hold to it instead of the page. The head takes the window's colour only once pinned
   (.is-pinned, snafu-lead.js), so at rest it is the window's own top. */
@media (max-width: 640px) and (max-height: 900px) {
  .sl-window { overflow: clip; }
  .sl-head { position: sticky; z-index: 5; top: 70px;
    margin: calc(var(--pad-y) * -1) calc(var(--pad-x) * -1 + 1px) 0; padding: var(--pad-y) calc(var(--pad-x) - 1px) 0; transition: background-color 200ms ease; }
  .sl-head::after { content: ""; position: absolute; left: 0; right: 0; top: 100%; height: 18px; pointer-events: none; opacity: 0;
    background: linear-gradient(var(--lg-bg), transparent); transition: opacity 200ms ease; }
  .sl-window:not(.is-opening) .sl-head.is-pinned { background-color: var(--lg-bg); }
  .sl-window:not(.is-opening) .sl-head.is-pinned::after { opacity: 1; }
  /* Three full lines held, so the pinned head keeps one height as the sentence changes (360 to 375 px moved 4.7 px). */
  .sl-head .sl-say { padding-bottom: 6px; min-height: calc(3lh + 6px); }
}
/* Forced colours drop backgrounds and shadows, which draw the guests, the held places, the dots, bars and deadline;
   they are drawn here in the system's text colour, as the fold's icon is (accessibility review 3). */
@media (forced-colors: active) {
  .sl-g { border: 1px solid CanvasText; }
  .sl-g.is-held, .mf-seat.is-held, .sl-dot, .al-dot, .al-line, .al-deadline, .mf-step[aria-pressed="true"]::before { forced-color-adjust: none; background: CanvasText; }
  .sl-g.is-held svg, .mf-seat.is-wc.is-held svg { color: Canvas; }
  .mf-step[aria-pressed="true"]::before { transform: none; }
  /* The manifest's held places, as the story's (accessibility review 4). */
  .mf-seat.is-held { border-color: CanvasText; }
  .mf-seat.is-wc svg { color: CanvasText; }
  .mf-seat.is-held::after { background: Canvas; }
  /* The atmosphere's Play triangle is a clipped background, which forced colours drop. */
  .atmos.is-held .atmos-glyph { forced-color-adjust: none; background: ButtonText; }
}

/* ------------------------------------------------ Snafu's S as a route (2026-10-03, late evening)
   The app's landing tile (arrival e675f12), re-drawn here: a Lagoon app tile whose S is a journey. The HTML is the
   finished S; assets/route-s.js plays it on Snafu's page, and the home's story draws its small one in step with its
   beats. --glow is the tile's one glow as the route lands. */
.rs { --glow: 0; position: relative; display: inline-grid; place-items: center; flex: none; width: 112px; height: 112px; border-radius: 30px;
  background: radial-gradient(120% 90% at 30% 10%, rgba(255, 255, 255, .1), transparent 55%), linear-gradient(160deg, #21494f, #123236 70%);
  box-shadow: inset 0 1px rgba(255, 255, 255, .12), inset 0 -1px rgba(0, 0, 0, .3), 0 1px 2px rgba(0, 0, 0, .4), 0 24px 48px -18px rgba(0, 0, 0, .75), 0 0 0 1px rgba(240, 244, 238, .06); }
.rs::after { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; opacity: var(--glow);
  box-shadow: 0 0 0 1px rgba(169, 209, 181, .5), 0 0 36px 4px rgba(169, 209, 181, .25); }
.rs-svg { width: 59%; height: 59%; overflow: visible; }
.rs path { fill: none; stroke-width: 4.6; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 1 1; }
.rs-track { stroke: rgba(240, 244, 238, .1); }
.rs-line { stroke: var(--lg-ink); stroke-dashoffset: 0; }
.rs circle { transform-box: fill-box; transform-origin: center; }
.rs-start { fill: var(--lg-ink); }
.rs-end { fill: var(--lg-green); }
.rs-ring { fill: none; stroke: var(--lg-green); stroke-width: 1; opacity: 0; }
.rs-snag { fill: var(--lg-amber); opacity: 0; }
.rs-car { fill: #fff; opacity: 0; filter: drop-shadow(0 0 3px #fff); }
/* Before its first run on Snafu's page the route waits undrawn; the script owns it from there. */
html.js:not(.rm) [data-route-play] .rs-line { stroke-dashoffset: 1; }
html.js:not(.rm) [data-route-play] :is(.rs-start, .rs-end) { opacity: 0; }
/* The small tile in the story window's header. */
.rs--mini { width: 40px; height: 40px; border-radius: 11px; }
.rs--mini path { stroke-width: 5.2; }
.rs--mini .rs-ring { stroke-width: 1.6; }
.rs--mini::after { box-shadow: 0 0 0 1px rgba(169, 209, 181, .55), 0 0 14px 2px rgba(169, 209, 181, .35); }
/* Beside the name above the title on Snafu's page, as an app's header sets its icon. */
.sp-id { display: flex; align-items: center; gap: 22px; margin-top: clamp(40px, 6vh, 72px); }
.sp-id .sp-name { margin-top: 0; }
.sp-id + .sp-title { margin-top: 22px; }
.rs--tile { width: 88px; height: 88px; border-radius: 24px; }
@media (max-width: 640px) {
  .sp-id { margin-top: 32px; gap: 16px; }
  .rs--tile { width: 64px; height: 64px; border-radius: 18px; }
}
.nw { white-space: nowrap; }

/* The case named with its flag above the arrival lines, as on Snafu's case chooser. The flag catches the light a
   few times as the page opens (the app's flag ripples), then rests; still under reduced motion. */
.al-case { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; margin-bottom: 6px; font: 400 .9375rem/1.4 var(--sans); color: var(--mist); }
.al-case b { font: 400 1.125rem/1.3 var(--serif); color: #d6d0c7; }
.flag-mx { position: relative; display: inline-block; flex: none; width: 21px; height: 14px; overflow: hidden; border-radius: 2px;
  background: linear-gradient(90deg, #0b6b48 0 33.4%, #f2efe8 33.4% 66.6%, #c8202f 66.6%); box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .25), 0 1px 3px rgba(0, 0, 0, .4); }
.flag-mx i { position: absolute; left: 50%; top: 50%; width: 4px; height: 4px; margin: -2px 0 0 -2px; border-radius: 50%; background: #8c6b3d; }
.flag-mx::after { content: ""; position: absolute; inset: 0; opacity: 0; background: linear-gradient(100deg, transparent 20%, rgba(255, 255, 255, .45) 45%, rgba(0, 0, 0, .12) 60%, transparent 80%); background-size: 260% 100%; }
html.js:not(.rm) .flag-mx::after { animation: flag-ripple 1.6s cubic-bezier(.77, 0, .175, 1) 4.6s 1; }
@keyframes flag-ripple { 0% { opacity: 1; background-position: 120% 0; } 100% { opacity: 1; background-position: -60% 0; } }

/* A fixed check's finding beside the AI's reading: plain, in ink, not a quote. */
.rd-found { margin-top: 8px; font: 400 1.0625rem/1.5 var(--serif); color: var(--ink); }

/* A folded section: its title is the button; open, it lays out as any section. */
.sp-fold { display: block; }
.sp-fold summary { display: flex; align-items: center; justify-content: space-between; gap: 24px; min-height: 44px; list-style: none; cursor: pointer; }
.sp-fold summary::-webkit-details-marker { display: none; }
.sp-fold summary:focus-visible { outline: 2px solid var(--lamp); outline-offset: 6px; border-radius: 2px; }
.sp-fold .sp-h { max-width: none; }
.sp-fold-i { position: relative; flex: none; width: 44px; height: 44px; border-radius: 50%; box-shadow: inset 0 0 0 1px rgba(236, 228, 216, .22); transition: box-shadow 200ms var(--ease-out); }
.sp-fold-i::before, .sp-fold-i::after { content: ""; position: absolute; left: 50%; top: 50%; width: 14px; height: 1.5px; margin: -.75px 0 0 -7px; background: var(--ink); transition: transform 300ms var(--ease-out); }
.sp-fold-i::after { transform: rotate(90deg); }
.sp-fold details[open] .sp-fold-i::after { transform: rotate(90deg) scaleX(0); }
@media (hover: hover) and (pointer: fine) { .sp-fold summary:hover .sp-fold-i { box-shadow: inset 0 0 0 1px rgba(255, 179, 102, .6); } }
html.rm .sp-fold-i, html.rm .sp-fold-i::after { transition: none; }
@media (forced-colors: active) {
  .sp-fold-i { box-shadow: none; border: 1px solid CanvasText; }
  .sp-fold-i::before, .sp-fold-i::after { forced-color-adjust: none; background: CanvasText; }
}
.sp-fold-in { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: 20px clamp(40px, 6vw, 120px); margin-top: 24px; }
.sp-fold-in > .sp-text { grid-column: 2; }
@media (max-width: 900px) { .sp-fold-in { grid-template-columns: minmax(0, 1fr); } .sp-fold-in > .sp-text { grid-column: 1; } }
/* Wide, open: the title and its button keep the left column and the text starts beside them, as in every
   other section. The content's own slot shares the title's cell, so closing still hides it. A browser that
   cannot lay out a details element as a grid stacks them as before. */
@media (min-width: 901px) {
  .sp-fold details { display: grid; grid-template-columns: minmax(0, 1fr); }
  .sp-fold summary { grid-area: 1 / 1; z-index: 1; align-self: start; justify-self: start; justify-content: flex-start; max-width: 40%; }
  .sp-fold details::details-content { grid-area: 1 / 1; }
  .sp-fold-in { grid-area: 1 / 1; margin-top: 0; row-gap: 48px; }
}
