/* ==========================================================
   lite.computer — the site stylesheet
   Built S51.2, 2026-08-29.

   Loads AFTER tokens.css, which is GENERATED from
   design-system/brands/lite-computer/brand.json and must not be
   edited by hand. Everything here is site-level: layout,
   components, and the two tokens the brand does not carry.

   Ported from Lite-Computer-Home-Page-Mockup-V4-2026-08-28.html.
   The mockup carried the right brand VALUES under its own short
   names (--bg, --s1, --f-body). Same design, canonical names.
   ========================================================== */

/* ---- 1 · the theme-toggle guard --------------------------
   tokens.css applies its dark palette at bare :root inside the
   prefers-color-scheme query, so a page that sets
   data-theme="light" on a dark OS still renders dark — the
   attribute rule below it only matches "dark". Re-stating the
   light palette under the guard fixes it here without forking a
   generated file. Filed for the design system; delete this block
   once build/tokens.mjs emits the guard itself.
   ---------------------------------------------------------- */
@media (prefers-color-scheme: dark) {
  :root[data-theme="light"] {
    --color-bg: #FAFAF8;
    --color-surface: #F4F2EE;
    --color-ink: #141414;
    --color-accent-text: #6B5326;
    --color-mute: rgba(20, 20, 20, 0.60);
    --color-rule: rgba(20, 20, 20, 0.12);
  }
}

/* Every page carries data-theme="light" on <html>, so the site is light in
   both OS appearances (S51.4, 2026-08-31). This tells the browser to draw its
   own furniture — scrollbars, focus rings, native form controls — light too,
   which it otherwise takes from the OS and would render dark on a dark Mac.
   The dark palettes stay in tokens.css: removing the attribute restores
   follow-the-OS behavior with no CSS change. */
:root[data-theme="light"] { color-scheme: light; }

/* ---- 2 · site-level tokens -------------------------------
   The image slot is a site device, not a brand primitive, so it
   is not in brand.json. Derived from --color-accent so it moves
   when the brand does.
   ---------------------------------------------------------- */
:root {
  --slot-bg: rgba(184, 145, 74, 0.06);
  --slot-rule: rgba(184, 145, 74, 0.38);
  /* Set by the menu script to hold the page still while the panel is open. */
  --menu-lock-top: 0px;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --slot-bg: rgba(184, 145, 74, 0.09);
    --slot-rule: rgba(184, 145, 74, 0.42);
  }
}
:root[data-theme="dark"] {
  --slot-bg: rgba(184, 145, 74, 0.09);
  --slot-rule: rgba(184, 145, 74, 0.42);
}

/* ---- 3 · reset and page ---------------------------------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* Grid and flex children do not shrink below their content unless told. */
.slot, .slot-in, .hero-copy, .panel { min-width: 0; }
.slot-id, .slot-dim, .spec, .foot-legal { overflow-wrap: anywhere; }

body {
  background: var(--color-bg);
  color: var(--color-ink);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: var(--leading-body);
  -webkit-font-smoothing: antialiased;
}

.wide   { max-width: 1240px; margin-inline: auto; padding-inline: var(--space-4); }
.mid    { max-width: 920px;  margin-inline: auto; padding-inline: var(--space-4); }
.narrow { max-width: 60ch;   margin-inline: auto; padding-inline: var(--space-4); }

/* ---- 4 · type -------------------------------------------- */
h1, h2, h3 { font-family: var(--font-display); font-weight: 400; text-wrap: balance; }
h1 { font-size: clamp(32px, 3.7vw, var(--text-headline)); line-height: 1.04; letter-spacing: var(--tracking-headline); max-width: 18ch; }
/* Smaller than a normal h1 on purpose: set in caps and three lines deep, the
   full headline size pushed the hero past the fold and squeezed the image. */
.h1-caps {
  text-transform: uppercase; letter-spacing: 0.005em; max-width: 24ch;
  font-size: clamp(27px, 2.9vw, 43px); line-height: 1.08;
}
.gold { color: var(--color-accent-text); }
h2 { font-size: clamp(28px, 3.1vw, 44px); line-height: 1.08; letter-spacing: var(--tracking-headline); max-width: 19ch; }
h3 { font-size: 19px; line-height: 1.25; }
p + p { margin-top: var(--space-2); }

.mute { color: var(--color-mute); }
.eyebrow {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: var(--tracking-caption);
  text-transform: uppercase;
  color: var(--color-accent-text);
  display: block;
  margin-bottom: var(--space-2);
}
.turn {
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(20px, 2.1vw, 27px);
  line-height: 1.3;
  max-width: 34ch;
}

/* ---- 5 · top bar ----------------------------------------- */
/* The bar is sticky, so a jump to #download would otherwise land with the
   section's heading hidden underneath it. */
/* The dark surface. Two elements share it — the hero stage and the top bar
   while it sits over the hero — so it lives here rather than on .hero. The
   light plate with black letters is a swap of these four values. */
:root {
  --top-h: 80px;
  --hero-bg: #040302;      /* matches the plate's top row, so its edge is invisible */
  --hero-ink: #FAFAF8;
  --hero-mute: rgba(250, 250, 248, 0.62);
  --hero-gold: #B8914A;      /* #6B5326 dies on this ground */
}
html { scroll-padding-top: var(--top-h); scrollbar-gutter: stable; }
.top { position: sticky; top: 0; z-index: 20; background: var(--color-bg); }
.top-in {
  max-width: 1240px; margin-inline: auto;
  height: var(--top-h); padding: 0 var(--space-4);
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-4);
}
.wordmark {
  font-family: var(--font-body); font-size: clamp(28px, 2.6vw, 34px); line-height: 1; letter-spacing: -0.045em;
  display: inline-flex; align-items: baseline;
  color: var(--color-ink); text-decoration: none;
}
.wordmark .disc {
  width: 0.16em; height: 0.16em; border-radius: 50%;
  background: var(--color-accent); margin-left: 0.04em; display: inline-block;
}
/* Absent until the reader is past the hero, so the first screen
   carries exactly one call to action — the one in the hero. */
.btn-sticky {
  opacity: 0; transform: translateY(-6px); pointer-events: none;
  transition: opacity var(--duration-standard) var(--ease-standard),
              transform var(--duration-standard) var(--ease-standard);
  padding: 11px 20px; font-size: var(--text-ui);
}
.top.scrolled .btn-sticky { opacity: 1; transform: none; pointer-events: auto; }
.top.scrolled { border-bottom: var(--hairline) solid var(--color-rule); }
/* Over the dark hero the bar is transparent and inverted. The hamburger draws
   itself from currentColor, so setting colour on the bar reverses it too.
   Home page only — the script sets this class only when a hero exists. */
.top.on-dark { background: var(--hero-bg); color: var(--hero-ink); }
.top.on-dark .wordmark { color: inherit; }
.top.on-dark .menu-btn { color: inherit; }

/* ---- 5b · menu -------------------------------------------
   The button sits to the right of the trial CTA, which is what
   moves the CTA off the edge. Long pages are the reason it
   exists: nothing should need a scroll to the footer to leave.
   ---------------------------------------------------------- */
.top-right { display: flex; align-items: center; gap: var(--space-3); }
.menu-btn {
  appearance: none; -webkit-appearance: none; background: none; cursor: pointer;
  border: 0; color: var(--color-ink);
  padding: 10px 2px; display: inline-flex; align-items: center;
}
.menu-btn:hover { color: var(--color-accent-text); }
/* Three bare lines, weighted to sit beside a 40px wordmark. No box. */
.menu-bars { position: relative; display: block; width: 27px; height: 3px; background: currentColor; border-radius: 2px; }
.menu-bars::before, .menu-bars::after {
  content: ""; position: absolute; left: 0; width: 27px; height: 3px; background: currentColor; border-radius: 2px;
}
.menu-bars::before { top: -8px; }
.menu-bars::after  { top: 8px; }
/* The panel. A drawer from the right on a wide screen; the whole screen on a
   phone, which is what a phone menu is. It slides on the iOS drawer curve
   and its items follow it in a beat apart, so it reads as one motion, not a
   box appearing. Closing is quicker than opening: the reader is leaving.
   (Rebuilt S51.6, 2026-09-06, after Dustin held it against the Veue site.) */
.menu {
  --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 40;
  width: min(360px, 88vw);
  background: var(--color-bg);
  border-left: var(--hairline) solid var(--color-rule);
  padding: var(--space-6) var(--space-4);
  display: grid; gap: var(--space-3); align-content: start;
  overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
  transform: translateX(100%); visibility: hidden;
  transition: transform 280ms var(--ease-drawer), visibility 0s linear 280ms;
}
.menu.open {
  transform: none; visibility: visible;
  transition: transform 440ms var(--ease-drawer), visibility 0s;
}
@media (max-width: 640px) {
  .menu { width: 100%; border-left: 0; padding: var(--space-4) var(--space-3); }
}
/* The items arrive after the panel, one beat apart, and leave with it. */
.menu > a, .menu-foot {
  opacity: 0; transform: translateX(14px);
  transition: opacity 200ms ease, transform 200ms ease;
}
.menu.open > a, .menu.open .menu-foot {
  opacity: 1; transform: none;
  transition: opacity 360ms var(--ease-out-strong), transform 360ms var(--ease-out-strong);
}
.menu.open > a:nth-of-type(1) { transition-delay: 120ms; }
.menu.open > a:nth-of-type(2) { transition-delay: 165ms; }
.menu.open > a:nth-of-type(3) { transition-delay: 210ms; }
.menu.open > a:nth-of-type(4) { transition-delay: 255ms; }
.menu.open > a:nth-of-type(5) { transition-delay: 300ms; }
.menu.open .menu-foot         { transition-delay: 360ms; }
.menu a {
  font-family: var(--font-display); font-size: clamp(22px, 2.4vw, 27px);
  color: var(--color-ink); text-decoration: none; line-height: 1.25;
}
.menu a:hover, .menu a[aria-current="page"] { color: var(--color-accent-text); }
/* An action, not a sixth page. The rule and the button shape are what keep it
   from reading as another nav item. It lands on the download itself, not the
   top of the pricing page, so it is a different destination from "Pricing". */
.menu-foot {
  justify-self: stretch; margin-top: var(--space-4); padding-top: var(--space-4);
  border-top: var(--hairline) solid var(--color-rule);
  display: grid; gap: var(--space-2);
}
/* `.menu a` above outranks `.btn` and was painting the button's label ink on
   an ink button — "just a black box" (Dustin, 2026-09-06) — and setting the
   quiet one in the display face. Both buttons are buttons again. */
.menu-foot .btn {
  font-family: var(--font-body); font-weight: 500; font-size: var(--text-ui);
  padding: 12px 20px; text-align: center; color: var(--color-bg);
}
.menu-foot .btn:hover { color: var(--color-bg); }
.menu-foot .btn-quiet, .menu-foot .btn-quiet:hover { color: var(--color-ink); }
.menu-close {
  appearance: none; -webkit-appearance: none; background: none; border: 0; cursor: pointer;
  color: var(--color-ink); font-size: 30px; line-height: 1;
  justify-self: end; padding: 0 0 var(--space-3) var(--space-3);
}
.menu-close:hover { color: var(--color-accent-text); }
/* The scrim fades rather than snapping. The script still toggles `hidden`;
   the attribute is kept display:block here so the fade-out can play. */
.menu-scrim {
  position: fixed; inset: 0; z-index: 35; background: rgba(20, 20, 20, 0.42);
  opacity: 1; transition: opacity 320ms ease;
}
.menu-scrim[hidden] { display: block; opacity: 0; pointer-events: none; transition: opacity 240ms ease; }
/* The scroll lock is overflow on the root and nothing else. The earlier lock
   pinned the BODY position:fixed and then had to pin the hero stage as well,
   which dragged the hero into view over whatever section the reader was on
   the moment the menu opened (Dustin, 2026-09-06: "it always goes to the hero
   image"). With `scrollbar-gutter: stable` on html the page does not shift
   sideways when the scrollbar goes, and sticky keeps working, so the page
   behind the panel stays exactly where it was. The script still writes
   --menu-lock-top and scrolls back on close; both are harmless. */
html.menu-open { overflow: hidden; }
.vh {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

/* ---- 6 · image slots ------------------------------------- */
.slot {
  border: var(--hairline) dashed var(--slot-rule);
  border-radius: var(--radius-card);
  background: var(--slot-bg);
  display: flex; align-items: center; justify-content: center;
  padding: var(--space-3); text-align: center;
}
.slot-in { display: grid; gap: var(--space-2); max-width: 38ch; }
.slot-id {
  font-family: var(--font-mono); font-size: 11px;
  letter-spacing: var(--tracking-caption); text-transform: uppercase;
  color: var(--color-accent-text);
}
.slot-desc { font-size: var(--text-ui); line-height: var(--leading-ui); }
.slot-dim  { font-family: var(--font-mono); font-size: 11px; color: var(--color-mute); letter-spacing: 0.06em; }
.slot-cap  { font-size: 15px; color: var(--color-mute); font-style: italic; margin-top: var(--space-2); max-width: 56ch; }

.r169 { aspect-ratio: 16/9; }
/* A placed screenshot. Same footprint the empty slot had, so nothing in the
   layout shifts when a slot is filled. */
.shot {
  display: block; width: 100%; height: auto;
  border-radius: var(--radius-card);
  border: var(--hairline) solid var(--color-rule);
  background: var(--color-surface);
  object-fit: cover;
}
/* RECONSTRUCTED 2026-09-09, same loss as .hero-video: S51.7's CSS never
   reached this repo. Every filled slot ships as a PAIR — a .motion video and
   the .still image that stands in for it — and exactly one may ever be shown.
   With no rule at all both rendered, one under the other, which is why every
   screenshot on the home and use-case pages appeared twice. */
.shot.still { display: none; }
@media (prefers-reduced-motion: reduce) {
  .shot.motion { display: none; }
  .shot.still  { display: block; }
}

/* The line under a use-case shot that points at its prompt. */
.prompt-link {
  margin-top: var(--space-2);
  font-size: 14px;
}
.prompt-link a { color: var(--color-mute); text-decoration: none; }
.prompt-link a:hover { color: var(--color-accent-text); }

/* ── Screenshot lift ── added 2026-09-09, and built to be undone ─────────
   MEASURED PROBLEM: a flat page screenshot has almost no edge against this
   background. The shot's own cream is rgb(246,245,241); the page is
   rgb(250,250,248). Seven points apart out of 255 — about 3% — so the image
   dissolves into the page instead of sitting on it. A soft shadow gives it an
   edge without pretending the page lives inside a device.

   ONLY on `.shot.lift`, which is the page and app screenshots. The eight
   photographs of real screens are deliberately left bare (Dustin, 2026-09-09:
   "leave the photos alone, they have enough contrast") — and a drawn frame
   around a photograph of a monitor would be a screen inside a screen.

   TO TURN IT OFF: set --shot-lift to 0 on the next line. Every `lift` class in
   the markup then does nothing, and no HTML has to change.
   TO REMOVE IT ENTIRELY: delete this block. The classes are inert without it. */
:root { --shot-lift: 1; }

.shot.lift {
  box-shadow:
    0 1px 2px rgba(20, 20, 20, calc(0.05 * var(--shot-lift))),
    0 18px 40px -22px rgba(20, 20, 20, calc(0.38 * var(--shot-lift)));
}

.r219 { aspect-ratio: 21/9; }
.r43  { aspect-ratio: 4/3; }
.r11  { aspect-ratio: 1/1; }
.r1610{ aspect-ratio: 16/10; }
.r21  { aspect-ratio: 2/1; }   /* the six-concept gallery: three 16:10 cards across, two rows */

/* ---- 7 · sections ---------------------------------------- */
section { padding-block: var(--space-12); }
.band { background: var(--color-surface); }

/* the solution turn: narrow copy, then a wide two-up */
.solution { margin-top: var(--space-12); }
.solution-head { display: grid; gap: var(--space-2); margin-bottom: var(--space-6); }
.two-up { display: grid; gap: var(--space-6); grid-template-columns: 1fr; }
.two-up > figure { display: grid; gap: var(--space-2); }
.two-up figcaption { font-size: 15px; color: var(--color-mute); font-style: italic; }
@media (min-width: 880px) {
  .two-up { grid-template-columns: 1fr 1fr; grid-template-rows: auto auto; gap: var(--space-4); }
  .two-up > figure { grid-row: span 2; display: grid; grid-template-rows: subgrid; gap: var(--space-2); }
}

/* ---- 8 · hero -------------------------------------------- */
/* A scroll-revealed dark stage. S51.4, his call, and it supersedes the
   one-screen version from earlier the same day.

   The first screen is WORDS ONLY — white on dark, with the top edge of the
   computer screens showing at the bottom. Scrolling lifts the words up into
   the bar and brings the desk into full view; when the runway runs out the
   film band scrolls over the pinned stage on its own.

   The words are never on the photograph. That is what killed both earlier
   versions: type over a full-bleed image loses against these faces, and the
   translucent panel people reach for to fix it always reads as a patch.

   The three colours are custom properties so the light plate with black
   letters is a three-value swap plus one image file. Nothing else cares. */
.hero {
  --p: 0;                    /* scroll progress 0 → 1, written by the script */
  position: relative;
  padding: 0;                /* sections carry 96px by default; the hero must not */
  /* The runway. Only the stage is ever on screen. The desk finishes rising
     after one screen of scrolling and the film band enters from below one
     screen before the runway ends — so at 300svh the band arrived the very
     moment the desk settled, with no pause. The extra 40svh is the hold:
     the desk sits fully revealed for a beat before being covered.
     (S51.6, 2026-09-06, Dustin: "a little bit delayed, just very little".) */
  height: 340svh;
  background: var(--hero-bg);
}
.hero-stage {
  position: sticky; top: var(--top-h);
  height: calc(100svh - var(--top-h)); overflow: hidden;
  background: var(--hero-bg); color: var(--hero-ink);
  /* Anchored to the top, not centred: the lower third of the first screen is
     deliberately empty, and that is the room the screen tops appear in. */
  display: grid; align-items: start; justify-items: center;
}
/* Sits low so only the tops of the screens show, then rises into full view.
   The plate is dropped in at img/hero-desk.jpg; until it exists the stage is
   simply dark, which is still the right first screen. */
.hero-photo {
  position: absolute; inset: 0;
  background: url("img/hero-desk.jpg") center / cover no-repeat;
  /* The plate carries its own black headroom now, so the reveal is a PAN
     across the photograph — the picture fills the stage at every scroll
     position and the page background is never on screen. The element does not
     move. Sliding it used to expose flat CSS black above its top edge, which
     read as a cut against the photograph's own textured black. */
  background-position-y: calc(35% + var(--p) * 65%);
  will-change: background-position;
}
/* RECONSTRUCTED 2026-09-08. S51.7 wrote the hero video into index.html in the
   Space and its CSS never reached this repo; a later sync then copied this
   stylesheet over the Space's, so the original rule is gone from both. Rebuilt
   from what index.html says it must do: sit on top of the plate and pan with
   the same scroll variable, so the runway behaves identically whether the video
   plays or not. object-position mirrors .hero-photo's background-position-y
   exactly, which is what keeps the two in step. */
.hero-video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 50% calc(35% + var(--p, 0) * 65%);
  will-change: object-position;
}

.hero-copy {
  position: relative; z-index: 1;
  display: grid; gap: var(--space-2);
  justify-items: center; text-align: center;
  padding: 9.4svh var(--space-4) 0;       /* the empty lower third is the peek */
  transform: translateY(calc(var(--p) * -26svh));
  opacity: calc(1 - var(--p) * 1.6);    /* gone by about two thirds of the lift */
  will-change: transform, opacity;
}
/* The headline's second half. It sits in exactly the place the h1 vacates and
   is set identically — same face, same size, same colour — so the sentence
   appears to carry on rather than a caption appearing. Zero until the words
   are two thirds gone, full by the time the desk has settled, keyed to the
   same --p.

   var(--p, 0), not var(--p): the scroll handler has not run on first paint,
   and an unset custom property makes the whole calc invalid, which falls back
   to opacity 1 — the line at full strength on top of the hero copy until the
   first scroll. The fallback keeps it at 0. */
.hero-caption {
  position: absolute; top: 0; left: 0; right: 0; z-index: 1;
  margin: 0; padding-inline: var(--space-4);
  text-align: center; pointer-events: none;

  /* CENTRED IN THE BLACK ABOVE THE SCREENS, and derived rather than guessed.
     The monitor's top edge sits at y=942 of the 1404px plate, so it is 462px
     up from the image's bottom. At p=1 the plate is bottom-aligned and cover
     scales it by width, so that 462px lands at 462 × (100vw / 1536) = 30.08vw
     above the stage floor. The box starts at the top of the SCREEN rather than
     the top of the stage — the bar above is the same black and reads as part
     of it — so it is pulled up by --top-h and given that height back. The line
     then centres in the visible black at any width, with no number tuned to
     one screen. The stage clips the overhang, which is empty. Re-derive both
     figures if the plate is ever recropped. */
  top: calc(-1 * var(--top-h));
  height: calc(100% + var(--top-h) - 30.08vw);
  min-height: 4rem;
  /* align-content, NOT place-items. place-items:center also sets
     justify-items:center, which shrinks the text box to its own content width
     — it collapsed a one-line headline to 559px inside a 1440px stage and
     wrapped it onto four lines. This centres the row vertically and lets the
     text block keep the full width; text-align handles the horizontal. */
  display: grid;
  align-content: center;
  /* One full-width column. Without this the implicit column sizes to the
     content, so on a phone the sentence ran off the right edge instead of
     wrapping. minmax(0, 1fr) lets it shrink and wrap. */
  grid-template-columns: minmax(0, 1fr);

  /* Same size as the hero h1, so it reads as that sentence carrying on. */
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(40px, 6.4vw, var(--text-display));
  line-height: 1.02; letter-spacing: var(--tracking-headline);
  color: var(--hero-ink); text-wrap: balance;

  /* Starts at p=0.72, which is where the hero copy reaches zero, so the
     frame is empty for a beat before this arrives. Full by p=0.95. */
  opacity: calc(var(--p, 0) * 4.348 - 3.13);
  will-change: opacity;
}

/* THE INNER SPAN IS LOAD-BEARING. A grid container blockifies its children,
   and the gold <span class="gold">AI</span> counts as one — so the sentence
   became three grid items on three rows: "Give your" / "AI" / "room to work."
   One child means one row, and the sentence stays a sentence. The same trap
   exists in flex. If the span is removed from the markup, this breaks again. */
.hero-caption-line { display: block; }

.hero-copy h1 {
  font-size: clamp(40px, 6.4vw, var(--text-display));
  line-height: 1.02; max-width: 26ch; color: var(--hero-ink);
  margin-bottom: var(--space-1);
}
.hero-copy .gold,
.hero-caption .gold { color: var(--hero-gold); }
.hero-lede { font-size: var(--text-body); line-height: 1.5; color: var(--hero-mute); max-width: 54ch; }
.hero-lede b { color: var(--hero-ink); font-weight: 500; }
.hero .fine, .hero .spec { color: var(--hero-mute); }
/* The page button is dark on cream; on this ground it has to invert. */
.hero .btn { background: var(--hero-ink); color: var(--hero-bg); }

.cta { display: grid; gap: 6px; justify-items: center; margin-top: var(--space-2); }
.hero .cta { gap: 0; }
.hero .cta .fine { margin-top: var(--space-3); }
.hero .cta .spec { margin-top: var(--space-2); }
.btn {
  display: inline-block;
  background: var(--color-ink); color: var(--color-bg);
  font: 500 15px/1 var(--font-body);
  padding: 15px 25px; border-radius: var(--radius-control);
  text-decoration: none;
  transition: transform var(--duration-quick) var(--ease-standard);
}
/* Hover and press live in §17 (motion). The old rule here was a one-pixel
   lift in 120ms, which nobody noticed — Dustin's words, 2026-09-06. */
.fine { font-size: 13px; color: var(--color-mute); }
.spec { font-family: var(--font-mono); font-size: 11px; color: var(--color-mute); letter-spacing: 0.04em; }

/* The film band has to ride OVER the pinned stage — that is the beat where
   the video container covers the hero image. The negative margin is what makes
   it a cover: it starts one screen before the hero's runway ends, so it slides
   across a stage that is still pinned. */
.filmband {
  position: relative; z-index: 2; background: var(--color-bg);
  /* It is pulled up a full screen to slide across the still-pinned stage, so
     it must BE a full screen tall — otherwise the hero's last sliver shows
     below it as a strip of desk between two cream sections. That strip was
     126px, exactly one screen minus this band's own height. */
  margin-top: -100svh;
  min-height: 100svh;
  display: flex; flex-direction: column; justify-content: center;
}

/* Nothing in the copy may be wider than the screen. The lede's 54ch and the
   headline's 16ch are comfortable on a laptop and wider than a phone. */
.hero-copy > * { max-width: 100%; }
.hero-copy h1 { max-width: min(16ch, 100%); }
.hero-lede    { max-width: min(54ch, 100%); }

/* Narrow screens keep the SAME reveal. The stacked phone layout that sat here
   (words on a plain black block, the desk as a separate picture under them)
   came out on 2026-09-06 at Dustin's call: an ordinary website shrinks to a
   phone with its parallax, photo and words intact, and this one should too.
   At cover scale the plate is taller than a phone screen, so the pan itself
   barely moves there — but the words still lift into the bar, the lamp sits
   beside them, the brick falls off into the plate's own black, and the film
   band still rides over the stage. Only the side padding changes. */
@media (max-width: 999px) {
  .hero-copy { padding-inline: var(--space-3); }
  .wide, .mid, .narrow { padding-inline: var(--space-3); }
}
/* ---- the hero at every size: three regimes, decided by the SHAPE of the
   screen, not the device (2026-09-07, after Dustin: "optimize every screen as
   screens increase and decrease in size").

   WIDE  (aspect ratio at or above the plate's own, 1536:1404): the plate fills
         the width, stands taller than the stage, and pans 35% → 100% as --p
         grows. Laptops, desktops, tablets on their side. The rules above.
   TALL  (narrower than the plate): the plate is 150% of the width, centred on
         the monitor, and starts 12svh below its resting place so the first
         screen shows brick, the lamp beside the sentence and the screen tops
         peeking; it rises as the words lift away. Phones and tablets upright.
   SHORT (under 600px tall): a pinned stage cannot hold the words, so the hero
         stacks — words, then the whole desk as a 16:9 picture — below. */
@media (max-aspect-ratio: 1536/1404) {
  .hero-photo {
    background-size: 150% auto;
    background-position-x: 50%;
    background-position-y: calc(100% + (1 - var(--p)) * 12svh);
  }
  /* The video has to take the narrow-screen framing too, or it pans on a
     different curve from the plate underneath it and the two disagree the
     moment the video starts. */
  .hero-video { object-position: 50% calc(100% + (1 - var(--p, 0)) * 12svh); }

  /* Narrow screens draw the plate at 150% of stage width, so the same 462px
     of image is 462 × (150vw / 1536) = 45.12vw above the floor. */
  .hero-caption { height: calc(100% + var(--top-h) - 45.12vw); }
  .hero-copy { padding-top: 6svh; gap: var(--space-1); }
  .hero-copy h1 { font-size: clamp(34px, 9.2vw, 64px); }
  /* Same size as the h1 on the line above, on narrow screens too. The two are
     meant to be read and changed together. */
  .hero-caption { font-size: clamp(34px, 9.2vw, 64px); }
  .hero-lede { font-size: clamp(15px, 4.1vw, 18px); line-height: 1.45; }
  .hero .cta .fine { margin-top: var(--space-2); font-size: clamp(12px, 3.2vw, 13px); }
  .hero .cta .spec { font-size: clamp(10px, 2.7vw, 11px); margin-top: var(--space-1); }
}

/* The one case a pinned stage cannot serve: a window too short to hold the
   words (a phone on its side). Stack there, words first, desk second, and no
   band pull-up, since nothing is pinned to slide over. */
@media (max-height: 599px) {
  .hero { height: auto; background: var(--hero-bg); }
  .hero-stage { position: static; height: auto; overflow: visible; display: grid; padding-bottom: 0; }
  .hero-copy { order: 1; position: static; transform: none; opacity: 1; padding: var(--space-4) var(--space-3) var(--space-3); gap: var(--space-1); }
  .hero-copy h1 { font-size: clamp(30px, 4.5vw, 44px); }
  .hero-caption { display: none; }
  .hero-lede { font-size: 15px; line-height: 1.45; }
  /* The whole desk, wide, the desk itself at the bottom of the frame; the
     plate's black headroom above it merges with the ground. */
  .hero-photo {
    order: 2; position: static; inset: auto;
    width: 100%; aspect-ratio: 16/9;
    background-size: cover; background-position: 50% 100%;
    will-change: auto;
  }
  .filmband { margin-top: 0; min-height: 0; }
}

/* No runway, no movement: the reader gets the words on the dark ground with
   the screen tops below, and the page carries on. They lose the reveal. */
@media (prefers-reduced-motion: reduce) {
  .hero { height: calc(100svh - var(--top-h)); }
  .hero-stage { position: static; }
  .hero-photo, .hero-copy { transform: none; }
  .hero-copy { opacity: 1; }
  /* The words never leave here, so a second line would sit on top of them. */
  .hero-caption { display: none; }
  .filmband { margin-top: 0; }
}

/* ---- 9 · the problem: narrow, no image, pure type -------- */
.problem { display: grid; gap: var(--space-4); }
.problem h2 { max-width: 26ch; }
.problem p { max-width: none; }
.problem .turn { max-width: 64ch; }
.problem .silo { color: var(--color-ink); }

/* ---- 11 · the one inversion, always ink ------------------ */
.band-ink { background: #141414; color: #FAFAF8; }
.band-ink h2 { color: #FAFAF8; }
.band-ink .mute { color: rgba(250, 250, 248, 0.68); }
.band-ink .eyebrow { color: #B8914A; }
.band-ink .fine { color: rgba(250, 250, 248, 0.68); }
.band-ink .spec { color: rgba(250, 250, 248, 0.52); }

.held { text-align: center; display: grid; gap: var(--space-3); justify-items: center; }
.held h2 { max-width: 22ch; }
.held p { max-width: 52ch; }
.principle {
  font-family: var(--font-display); font-style: italic;
  font-size: clamp(19px, 1.9vw, 24px); line-height: 1.35;
  max-width: 38ch; color: rgba(250, 250, 248, 0.78);
}
/* Sits between the consequence and the ask, and stays light:
   one sentence carrying the mechanism, then three short points. */
.reassure { margin-top: var(--space-6); display: grid; gap: var(--space-4); justify-items: center; max-width: 62ch; }
.reassure-lede {
  font-family: var(--font-display); font-size: clamp(20px, 2.1vw, 26px);
  line-height: 1.3; max-width: 30ch; color: #FAFAF8;
}
.reassure-points { display: grid; gap: var(--space-4) var(--space-3); grid-template-columns: 1fr; text-align: center; }
@media (min-width: 760px) {
  .reassure-points { grid-template-columns: repeat(3, 1fr); gap: var(--space-4); text-align: left; }
}
.reassure-points div { display: grid; gap: 4px; align-content: start; }
.reassure-points b { font-weight: 500; font-size: 15px; color: #FAFAF8; }
.reassure-points span { font-size: var(--text-ui); color: rgba(250, 250, 248, 0.62); line-height: var(--leading-ui); }
.close-cta { justify-items: center; margin-top: var(--space-6); }
.btn-invert { background: #FAFAF8; color: #141414; }

/* ---- 12 · footer ----------------------------------------
   Thick. All navigation lives down here, which is what pays for
   a header carrying nothing but the wordmark.
   ---------------------------------------------------------- */
footer {
  border-top: var(--hairline) solid var(--color-rule);
  padding-block: var(--space-12) var(--space-6);
  background: var(--color-surface);
}
.foot {
  max-width: 900px; margin-inline: auto; padding-inline: var(--space-4);
  display: grid; gap: var(--space-12); justify-items: center; text-align: center;
}
.foot-works { display: grid; gap: var(--space-2); justify-items: center; }
.works-claim {
  font-family: var(--font-display); font-size: clamp(24px, 2.6vw, 34px);
  line-height: 1.15; max-width: 24ch; text-wrap: balance;
}
.works-rows { display: grid; gap: 6px; margin-top: var(--space-2); }
.works-rows p { font-family: var(--font-mono); font-size: 13px; color: var(--color-mute); letter-spacing: 0.02em; line-height: var(--leading-ui); }
.works-more { font-size: 15px; color: var(--color-mute); font-style: italic; margin-top: var(--space-1); }

/* Five links, centered and wrapping naturally rather than gridded into columns. */
.foot-nav { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-2) var(--space-6); }
.foot-nav a { font-family: var(--font-display); font-size: var(--text-body); color: var(--color-ink); text-decoration: none; line-height: 1.3; white-space: nowrap; }
.foot-nav a:hover { color: var(--color-accent-text); }
.foot-nav a[aria-current="page"] { color: var(--color-accent-text); }
@media (max-width: 560px) {
  .foot-nav { gap: var(--space-2) var(--space-4); }
}

.foot-print {
  max-width: 900px; margin-inline: auto;
  padding: var(--space-6) var(--space-4) 0;
  margin-top: var(--space-12);
  border-top: var(--hairline) solid var(--color-rule);
  display: grid; gap: var(--space-2); justify-items: center; text-align: center;
}
.foot-legal { font-family: var(--font-mono); font-size: var(--text-caption); color: var(--color-mute); line-height: var(--leading-caption); }
.foot-privacy { text-decoration: none; }
.foot-privacy:hover { color: var(--color-ink); }

/* ---- 13 · focus and motion ------------------------------- */
a:focus-visible, .btn:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* ==========================================================
   14 · INNER PAGES
   Added S51.2. The home page is one-of-a-kind by design; every
   other page shares this furniture so six pages do not become
   six designs.
   ========================================================== */

/* ---- the standard page head ------------------------------ */
.page-head { padding-block: var(--space-12) var(--space-6); }
.page-head h1 { max-width: 20ch; }
.page-head .lede {
  font-size: var(--text-body); line-height: 1.5; color: var(--color-mute);
  max-width: 56ch; margin-top: var(--space-3);
}

/* ---- long-form prose: legal, story ----------------------- */
.prose { max-width: 68ch; display: grid; gap: var(--space-3); }
.prose h2 { font-size: clamp(24px, 2.4vw, 34px); max-width: 24ch; margin-top: var(--space-6); }
.prose h2:first-child { margin-top: 0; }
.prose h3 { font-family: var(--font-body); font-weight: 500; font-size: 17px; margin-top: var(--space-3); }
.prose p { color: var(--color-mute); }
.prose p strong, .prose strong { color: var(--color-ink); font-weight: 500; }
/* :not(.btn) matters. Plain `.prose a` is specificity 0,2,0 and beats `.btn`
   at 0,1,0, so every button inside a prose block was rendering brass on
   near-black — measured 2.54:1 against the brand's 4.5 floor. Caught in the
   S51.2 render, not by reading the CSS. */
.prose a:not(.btn) { color: var(--color-accent-text); }
.prose ul { list-style: none; display: grid; gap: var(--space-2); }
.prose ul li { color: var(--color-mute); padding-left: var(--space-3); position: relative; }
.prose ul li::before {
  content: ""; position: absolute; left: 0; top: 0.65em;
  width: 5px; height: 5px; border-radius: 50%; background: var(--color-accent);
}
.sig { margin-top: var(--space-6); display: grid; gap: 2px; }
.sig b { font-weight: 500; }
.sig span { font-size: var(--text-ui); color: var(--color-mute); }

/* ---- use cases: alternating rows ------------------------- */
.usecase { display: grid; gap: var(--space-4); padding-block: var(--space-12); border-top: var(--hairline) solid var(--color-rule); }
.usecase:first-of-type { border-top: 0; }
.usecase h2 { max-width: 20ch; }
.usecase .no { font-family: var(--font-mono); font-size: 11px; letter-spacing: var(--tracking-caption); text-transform: uppercase; color: var(--color-accent-text); }
.usecase p { color: var(--color-mute); max-width: 52ch; }
.usecase .prov { font-size: var(--text-ui); font-style: italic; color: var(--color-mute); }
@media (min-width: 900px) {
  .usecase { grid-template-columns: 1fr 1fr; gap: var(--space-6); align-items: center; }
  .usecase > .uc-copy { display: grid; gap: var(--space-2); align-content: center; }
  .usecase.flip > .uc-copy { order: 2; }
  .usecase.flip > .slot { order: 1; }
}

/* ---- the one plan --------------------------------------- */
.plan {
  border: var(--hairline) solid var(--color-rule); border-radius: var(--radius-card);
  padding: var(--space-6); display: grid; gap: var(--space-3);
  max-width: 46ch; background: var(--color-bg);
}
.plan .price { font-family: var(--font-display); font-size: clamp(34px, 4vw, 52px); line-height: 1; }
/* Its own line. Inline, it wrapped between "no" and "subscription" under the
   display face and read as part of the price. */
.plan .price small { display: block; font-family: var(--font-body); font-size: var(--text-ui); color: var(--color-mute); margin-top: var(--space-1); letter-spacing: 0; }
.plan p { color: var(--color-mute); }
.plan .btn { justify-self: start; }
/* Two paths out of the plan card: buy outright, or try it first. The quiet
   button is an outline so the paid action stays the obvious one. */
.plan-cta { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
.btn-quiet {
  background: none; color: var(--color-ink);
  box-shadow: inset 0 0 0 var(--hairline) var(--color-ink);
}
.btn-quiet:hover { background: var(--color-surface); }
.team-note {
  margin-top: var(--space-4); max-width: 46ch;
  font-size: var(--text-ui); line-height: var(--leading-ui); color: var(--color-mute);
}

/* ---- requirements and FAQ -------------------------------- */
.reqs { display: grid; gap: var(--space-2); max-width: 52ch; }
.reqs div { display: grid; grid-template-columns: 10ch 1fr; gap: var(--space-2); align-items: baseline; }
.reqs dt, .reqs b { font-family: var(--font-mono); font-size: var(--text-caption); letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-accent-text); }
.reqs span { color: var(--color-mute); font-size: 15px; }

.faq { display: grid; gap: var(--space-3); max-width: 62ch; }
.faq div { display: grid; gap: 4px; padding-bottom: var(--space-3); border-bottom: var(--hairline) solid var(--color-rule); }
.faq div:last-child { border-bottom: 0; }
.faq b { font-weight: 500; }
.faq span { color: var(--color-mute); font-size: 15px; }

/* ---- resource center categories -------------------------- */
.cat {
  padding-block: var(--space-4); border-top: var(--hairline) solid var(--color-rule);
  display: grid; grid-template-columns: 1fr; gap: var(--space-3);
}
.cat:first-of-type { border-top: 0; }
.cat .cat-head { display: grid; gap: 4px; align-content: start; }
.cat .cat-no { font-family: var(--font-mono); font-size: 11px; letter-spacing: var(--tracking-caption); color: var(--color-accent-text); }
.cat h2 { font-size: 22px; max-width: none; }
.cat .cat-sub { font-size: var(--text-ui); color: var(--color-mute); line-height: var(--leading-ui); }
.cat ul { list-style: none; display: grid; gap: 2px; }
.cat li a { color: var(--color-ink); text-decoration: none; font-size: 15px; display: inline-block; padding: 5px 0; }
.cat li a:hover { color: var(--color-accent-text); }
@media (min-width: 900px) {
  .cat { grid-template-columns: 1fr 2fr; gap: var(--space-6); }
  .cat ul { columns: 2; column-gap: var(--space-6); display: block; }
  .cat li { break-inside: avoid; }
}

/* ---- the lost-key form ----------------------------------- */
form.resend { display: grid; gap: var(--space-2); max-width: 420px; }
form.resend label { font-size: var(--text-caption); font-family: var(--font-mono); letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-accent-text); }
form.resend input {
  font: inherit; font-size: var(--text-ui); padding: 12px 14px;
  border: var(--hairline) solid var(--color-rule); border-radius: var(--radius-control);
  background: var(--color-bg); color: var(--color-ink);
}
form.resend input:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
form.resend button { justify-self: start; border: 0; cursor: pointer; }
.resend-note { font-size: 13px; color: var(--color-mute); }

/* ---- the closing ask on inner pages ---------------------- */
.tail { display: grid; gap: var(--space-3); justify-items: center; text-align: center; }
.tail h2 { max-width: 24ch; }
.tail p { color: var(--color-mute); max-width: 48ch; }

/* ---- 15 · help articles ---------------------------------- */
.crumb { font-family: var(--font-mono); font-size: var(--text-caption); letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-mute); margin-bottom: var(--space-2); }
.crumb a { color: var(--color-accent-text); text-decoration: none; }
.crumb a:hover { text-decoration: underline; }
.crumb span { opacity: 0.5; margin-inline: 4px; }
.art-foot {
  margin-top: var(--space-12); padding-top: var(--space-3);
  border-top: var(--hairline) solid var(--color-rule);
  max-width: 68ch; font-size: 15px; color: var(--color-mute);
}
.art-foot a { color: var(--color-accent-text); }
.prose code {
  font-family: var(--font-mono); font-size: 0.88em;
  background: var(--color-surface); padding: 2px 5px; border-radius: 4px;
  overflow-wrap: anywhere;
}

/* ==========================================================
   16 · S51.2 round two — the video, and the copyable prompt
   ========================================================== */

/* ---- the explainer video ---------------------------------
   Its own band directly under the hero. A visitor who has never
   asked an AI for a page learns more from ninety seconds of
   watching one appear than from any paragraph below it.
   ---------------------------------------------------------- */
.filmband { padding-block: var(--space-12); }
.film-head { display: grid; gap: var(--space-2); justify-items: center; text-align: center; margin-bottom: var(--space-6); }
.film-head h2 { max-width: 22ch; }
.film-head p { color: var(--color-mute); max-width: 58ch; }
.film {
  max-width: 1000px; margin-inline: auto;
  border-radius: var(--radius-card); overflow: hidden;
  background: var(--color-surface);
}
.film video, .film img { display: block; width: 100%; height: auto; }
.film-cap { text-align: center; font-size: 15px; color: var(--color-mute); font-style: italic; margin-top: var(--space-3); }

/* ---- the copyable prompt ---------------------------------
   The site gives away the lesson and keeps the answer. The
   prompt is trivially derivable; the folder is the product.
   ---------------------------------------------------------- */
.prompt {
  border: var(--hairline) solid var(--color-rule);
  border-radius: var(--radius-card);
  background: var(--color-surface);
  padding: var(--space-3);
  display: grid; gap: var(--space-2);
  margin-top: var(--space-3);
}
.prompt-label {
  font-family: var(--font-mono); font-size: 11px;
  letter-spacing: var(--tracking-caption); text-transform: uppercase;
  color: var(--color-accent-text);
}
.prompt-text {
  font-family: var(--font-mono); font-size: 13px; line-height: 1.6;
  color: var(--color-ink); white-space: pre-wrap; overflow-wrap: anywhere; margin: 0;
}
.prompt-row { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.prompt-copy {
  font: 500 13px/1 var(--font-body); cursor: pointer;
  background: var(--color-ink); color: var(--color-bg);
  border: 0; border-radius: var(--radius-control); padding: 10px 16px;
  transition: transform var(--duration-quick) var(--ease-standard);
}
.prompt-copy:hover { transform: translateY(-1px); }
.prompt-copy[data-done="1"] { background: var(--color-accent); color: #141414; }
.prompt-note { font-size: 13px; color: var(--color-mute); }

/* On a dark band the prompt has to invert with it. */
.band-ink .prompt { background: rgba(250,250,248,.06); border-color: rgba(250,250,248,.16); }
.band-ink .prompt-text { color: #FAFAF8; }
.band-ink .prompt-copy { background: #FAFAF8; color: #141414; }

/* A use case's prompt sits tighter than a standalone one. */
.usecase .prompt { margin-top: var(--space-2); }
.usecase .prompt-text { font-size: 12px; }


/* ---- 14 · previous and next article ----------------------
   So a reader is never stranded at the bottom of one article
   with only the browser's Back button. The order is the
   Resource Center's order, straight through, across sections.
   ---------------------------------------------------------- */
.art-nav {
  display: grid; gap: var(--space-4); grid-template-columns: 1fr 1fr;
  margin-top: var(--space-6); padding-top: var(--space-4);
  border-top: var(--hairline) solid var(--color-rule);
}
.art-nav a { text-decoration: none; display: grid; gap: 4px; align-content: start; }
.art-nav .dir {
  font-family: var(--font-mono); font-size: 11px;
  letter-spacing: var(--tracking-caption); text-transform: uppercase;
  color: var(--color-mute);
}
.art-nav .t {
  font-family: var(--font-display); font-size: var(--text-body);
  color: var(--color-ink); line-height: 1.25;
}
.art-nav a:hover .t { color: var(--color-accent-text); }
.art-nav .next { text-align: right; }
.art-nav .next-only { grid-column: 2; }
@media (max-width: 560px) {
  .art-nav { grid-template-columns: 1fr; }
  .art-nav .next { text-align: left; }
  .art-nav .next-only { grid-column: 1; }
}

/* ---- fitting a section to one screen ----------------------------
   Every container should be readable without scrolling inside it: the
   screenshots of this page are taken a screen at a time, and a section cut
   in half reads as a mistake. Two levers — less section padding, and a cap
   on how tall any single image may be. The cap is in svh so it answers to
   the reader's screen, not to a number I guessed. ---------------- */
section, .band, .filmband { padding-block: 60px; }
.slot, .shot, .film { max-height: 38svh; width: auto; max-width: 100%; margin-inline: auto; }
/* max-width added S51.5, 2026-09-04: these are height-capped only, so on a
   phone 38svh of a wide image resolved to 459px and 748px inside a 390px
   screen and the home page scrolled sideways. Measured, not guessed. */
.two-up .slot, .two-up .shot { max-height: 34svh; }

/* THE FILM IS THE EXCEPTION TO THE CAP ABOVE, and it has to be, because a cap
   plus overflow:hidden CLIPS a video instead of scaling it. Measured on the
   real page 2026-09-09, the day the film was installed: at 1440x900 the player
   was 652px tall inside a 304px box, so more than half the picture was cut off
   and the poster's own wordmark fell below the fold of its own frame.

   So the film is sized by WIDTH instead, and the width is the one that makes a
   16:9 box exactly 52svh tall. The height then follows the ratio and can never
   overflow. 52 is measured, not chosen: the band leaves 62% of the viewport
   after its padding and heading at 1440x900, 54% at 1280x800 and 57% at
   390x844, and 52 clears the tightest of those. The box tracks the picture, so
   no surface-coloured card shows around a narrower video. */
.filmband .film {
  max-height: none;
  width: auto;
  margin-inline: auto;

  /* THE BEZEL. Chosen 2026-09-09: the film opens on its own near-white logo
     card, which is within a few levels of the page's cream, so the player had
     no edge at all and the picture bled into the section. Nine pixels of the
     ink colour reads as a screen rather than as a border, and needs no colour
     the palette does not already have. It is a token because dark mode would
     otherwise repeat the same mistake inverted — see --film-bezel. */
  /* Fallback spelled out: an undefined custom property computes to nothing
     here, and the bezel would silently disappear rather than fail loudly. */
  background: var(--film-bezel, #17181A);
  padding: 9px;
  border-radius: 16px;
  box-shadow:
    0 1px 2px rgba(20, 20, 20, 0.06),
    0 18px 40px -24px rgba(20, 20, 20, 0.42);

  /* The 18px of bezel is subtracted before the ratio and added back after, so
     the whole framed block is still 52svh tall and the frame does not push the
     film past the room the band has. Box-sizing is border-box site-wide, so
     this max-width includes the padding. */
  max-width: min(100%, calc((52svh - 18px) * 16 / 9 + 18px));
}
.filmband .film video { width: 100%; height: auto; border-radius: 7px; }
/* a caption sat a full section-gap away from the image above it */
section .slot-cap { margin-top: var(--space-1) !important; }


/* Two images in one use case. They live in the page's NARROW column (564px at
   laptop width), so side by side would give each sign ~280px — too small to
   read. Stacked, each gets the full column. */
.two-shots { display: grid; gap: var(--space-2); grid-template-columns: 1fr; }

/* The three-step panels are drawn, not photographed: crisp at any size, in
   the brand's own tokens, and ready to animate. Same footprint as a photo. */
.fig { background: var(--color-surface); color: var(--color-ink); padding: 6%; box-sizing: border-box; }
.fig .fig-gold { fill: var(--color-accent); }
.fig .caret { animation: fig-blink 1.1s steps(2, start) infinite; }
.fig .live  { animation: fig-pulse 2.4s ease-in-out infinite; }
@keyframes fig-blink { to { opacity: 0; } }
@keyframes fig-pulse { 0%,100% { opacity: 1; } 50% { opacity: .35; } }
@media (prefers-reduced-motion: reduce) { .fig .caret, .fig .live { animation: none; } }

/* The three-step infographic as an image. Capped in screen units so the
   section always fits one screen; centred if the cap makes it narrower. */
/* ── The three steps ── panel added 2026-09-09 ────────────────────────────
   The graphic's own background is rgb(252,249,244) and the page is
   rgb(250,250,248) — four points apart, so it dissolved exactly like the use-
   case screenshots did. It gets a panel rather than the shadow the others got,
   because it is an illustration rather than a screenshot: it has no edge of
   its own to lift.

   THE TINT IS NEUTRAL ON PURPOSE. The graphic already contains a warm sand
   panel behind step 3, rgb(243,231,209). A second warm tint around the outside
   would read as a mistake, so this one is grey-cream and sits clearly behind.

   It also buys the room Dustin asked for: it was 29px clear above the graphic
   and 17px below, which is tight for something 390px tall. The padding and the
   margin together give it about 80px above and 64px below.

   TO REMOVE: delete this block and unwrap the div in index.html. */
.steps-panel {
  background: #F0EEE9;
  border-radius: 18px;
  padding: var(--space-4);
  /* Hugs the graphic rather than stretching to the container. The image is
     height-constrained below, so a full-width panel left ~120px of dead tint
     either side and read as a stretched box rather than a mount. */
  width: fit-content;
  max-width: 100%;
  margin: var(--space-6) auto var(--space-4);
}
.steps-image { display: block; width: auto; max-width: 100%; max-height: 44svh; margin: 0 auto; }

/* A phone has no room to give away to padding. */
@media (max-width: 700px) {
  .steps-panel { padding: var(--space-2); border-radius: 14px; margin-top: var(--space-4); }
}


/* ==========================================================
   17 · MOTION — S51.6, 2026-09-06
   The cover effect belongs to the hero alone: the stage pins and
   the film band rides over it. A card stack that carried the same
   idea down the page was built and removed the same day — Dustin:
   "it feels like you always have two things going on at the same
   time." Everything left here is a soft arrival or a hover.

   Nothing here is hidden without JavaScript. The `.reveal` class
   is added BY the script, so a page with no script shows
   everything at once, which is the correct failure.
   ========================================================== */
:root {
  --ease-out-strong: cubic-bezier(0.23, 1, 0.32, 1);   /* entrances: fast start, long settle */
  --duration-reveal: 720ms;      /* the brand's UI timings are under 250ms and right for
                                    buttons; a reveal wants the reader to see it arrive */
}

/* ---- the soft reveal -------------------------------------
   Once, on the way in, never re-hidden. Text rises 16px and fades in;
   pictures fade and settle from 1.5% larger, which reads as the picture
   being placed rather than sliding. Stagger among siblings is written
   by the script as --d. */
.reveal {
  opacity: 0; transform: translateY(16px);
  transition: opacity var(--duration-reveal) var(--ease-out-strong),
              transform var(--duration-reveal) var(--ease-out-strong);
  transition-delay: var(--d, 0ms);
}
img.reveal, figure.reveal, .film.reveal, .two-shots.reveal, .steps-image.reveal {
  transform: translateY(10px) scale(0.985);
}
.reveal.in { opacity: 1; transform: none; }

/* ---- the hero arrives ------------------------------------
   Seen once per visit, so it may take its time. The three blocks — the
   headline, the sentence, the button — arrive a beat apart. */
.hero-copy > * { animation: hero-in 900ms var(--ease-out-strong) both; }
.hero-copy > :nth-child(2) { animation-delay: 140ms; }
.hero-copy > :nth-child(3) { animation-delay: 280ms; }
@keyframes hero-in {
  from { opacity: 0; transform: translateY(18px); }
}

/* ---- buttons: a lift you can see, and a press ------------
   The lift is two pixels with a shadow that grows underneath it, and a
   gold hairline along the bottom edge so the hover reads as ours. The
   press is a small scale-down, which is the interface saying it heard
   you. Hover only on a real pointer: a phone would fire it on tap. */
.btn, .prompt-copy {
  transition: transform 160ms var(--ease-out-strong),
              box-shadow 160ms var(--ease-out-strong),
              background-color 160ms ease;
}
@media (hover: hover) and (pointer: fine) {
  .btn:hover, .top.scrolled .btn-sticky:hover {
    transform: translateY(-2px);
    box-shadow: 0 12px 24px -10px rgba(20, 20, 20, 0.6),
                inset 0 -2px 0 var(--color-accent);
  }
  .hero .btn:hover, .btn-invert:hover {
    box-shadow: 0 14px 28px -10px rgba(0, 0, 0, 0.75),
                inset 0 -2px 0 var(--color-accent);
  }
  .btn-quiet:hover {
    background: var(--color-surface);
    box-shadow: inset 0 0 0 var(--hairline) var(--color-ink),
                0 10px 20px -12px rgba(20, 20, 20, 0.45);
  }
  .prompt-copy:hover { transform: translateY(-2px); box-shadow: 0 10px 20px -10px rgba(20, 20, 20, 0.55); }
}
.btn:active, .top.scrolled .btn-sticky:active, .prompt-copy:active {
  transform: translateY(0) scale(0.97);
  box-shadow: none;
  transition-duration: 90ms;
}

/* ---- the wordmark: the gold dot answers the cursor ------- */
.wordmark .disc { transform-origin: center; }
@media (hover: hover) and (pointer: fine) {
  .wordmark:hover .disc { animation: disc-pulse 560ms var(--ease-out-strong); }
}
@keyframes disc-pulse {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.7); }
  100% { transform: scale(1); }
}

/* ---- reduced motion: nothing moves, nothing is hidden ---- */
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; }
  .hero-copy > * { animation: none; }
}

/* ==========================================================
   18 · WAITLIST MODE — S51.5, 2026-09-06
   While there is no store, no public download and no price, every
   buy / trial / download button reads "Join the waitlist" and opens
   the panel below, and the Pricing links go quiet. waitlist-mode.py
   turns all of it on and off; waitlist.js builds the panel.
   ========================================================== */
/* Pricing, while there is no price: text, not a link. */
a.soon { color: var(--color-mute); cursor: default; }
a.soon:hover { color: var(--color-mute); }
.soon-tag { font-size: 0.72em; letter-spacing: 0.01em; }

/* The panel. A native <dialog>: the browser handles the backdrop, focus and
   Escape. Centred, because it is anchored to nothing in particular. */
.wl {
  border: 0; padding: 0; margin: auto;
  width: min(480px, calc(100vw - 2 * var(--space-3)));
  background: var(--color-bg); color: var(--color-ink);
  border-radius: var(--radius-card);
  box-shadow: 0 30px 80px -20px rgba(20, 20, 20, 0.45);
  opacity: 0; transform: translateY(10px) scale(0.98);
}
.wl[open] {
  opacity: 1; transform: none;
  transition: opacity 220ms var(--ease-out-strong), transform 220ms var(--ease-out-strong);
}
.wl::backdrop { background: rgba(20, 20, 20, 0.42); }
.wl-form, .wl-done { position: relative; padding: var(--space-6) var(--space-4) var(--space-4); display: grid; gap: var(--space-2); }
/* An author `display: grid` outranks the browser's `[hidden] { display: none }`, so
   the form stayed on screen under the thank-you (Dustin, 2026-09-07). Say it here. */
.wl-form[hidden], .wl-done[hidden] { display: none; }
.wl h2 { font-size: clamp(26px, 3vw, 34px); max-width: none; }
.wl-lede { color: var(--color-mute); max-width: 42ch; }
.wl-label { font-family: var(--font-mono); font-size: 11px; letter-spacing: var(--tracking-caption); text-transform: uppercase; color: var(--color-accent-text); margin-top: var(--space-2); }
.wl-row { display: grid; grid-template-columns: 1fr auto; gap: var(--space-1); }
.wl-input {
  font: inherit; font-size: 16px; padding: 13px 14px; min-width: 0;
  border: var(--hairline) solid var(--color-rule); border-radius: var(--radius-control);
  background: var(--color-bg); color: var(--color-ink);
}
.wl-input:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.wl-submit { border: 0; cursor: pointer; }
.wl-submit[disabled] { opacity: 0.6; cursor: default; }
.wl-hp { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }
.wl-note { font-size: var(--text-ui); color: var(--color-accent-text); min-height: 1.5em; }
.wl-note:empty { display: none; }
.wl-fine { font-family: var(--font-mono); font-size: 11px; color: var(--color-mute); letter-spacing: 0.04em; }
.wl-close {
  position: absolute; top: var(--space-2); right: var(--space-2);
  appearance: none; -webkit-appearance: none; background: none; border: 0; cursor: pointer;
  color: var(--color-mute); font-size: 28px; line-height: 1; padding: 4px 8px;
}
.wl-close:hover { color: var(--color-ink); }
.wl-done .btn { justify-self: start; margin-top: var(--space-2); }
@media (max-width: 480px) {
  .wl-row { grid-template-columns: 1fr; }
}
