/* Video-placement wash behind every hero — DISABLED: the hero is plain
   black ground until the real video plays. The per-surface palette rules
   below are kept dormant (they only paint a pseudo that no longer renders);
   flip `content: none` back to `content: ""` here to bring the whole wash +
   grain system back at once. Intent: each surface paints ONLY its weather
   colour(s) from the locked six, film grain on top, slow drift, still under
   reduced-motion. */
.page-hero::before,
.page-hero::after {
  content: none; /* no pseudo generated → hero shows the bare ground */
  position: absolute;
  inset: -8%; /* overscan so the drifting layer never bares an edge */
  z-index: -1;
  pointer-events: none;
}
/* Fallback / brand (studio) — hard rain + thunder */
.page-hero::before {
  background:
    radial-gradient(58% 55% at 22% 28%, color-mix(in srgb, var(--hard-rain) 26%, transparent), transparent 70%),
    radial-gradient(55% 50% at 82% 24%, color-mix(in srgb, var(--hard-rain) 14%, transparent), transparent 72%),
    radial-gradient(66% 62% at 70% 84%, color-mix(in srgb, var(--thunder) 16%, transparent), transparent 72%);
  animation: heroWashDrift 24s ease-in-out infinite alternate;
}
/* Home — light rain wash, almost gone */
body[data-surface="home"] .page-hero::before {
  background:
    radial-gradient(58% 55% at 22% 28%, color-mix(in srgb, var(--rain) 5%, transparent), transparent 72%),
    radial-gradient(55% 50% at 82% 24%, color-mix(in srgb, var(--rain) 3%, transparent), transparent 74%),
    radial-gradient(62% 58% at 68% 82%, color-mix(in srgb, var(--rain) 2.5%, transparent), transparent 72%);
}
/* Studio agent — hard rain */
body[data-surface="chat"] .page-hero::before {
  background:
    radial-gradient(58% 55% at 22% 28%, color-mix(in srgb, var(--hard-rain) 28%, transparent), transparent 70%),
    radial-gradient(55% 50% at 82% 24%, color-mix(in srgb, var(--hard-rain) 16%, transparent), transparent 72%),
    radial-gradient(62% 58% at 68% 82%, color-mix(in srgb, var(--hard-rain) 12%, transparent), transparent 70%);
}
/* Studio 333 — the cloud alone (ink / lit white) */
body[data-surface="studio"] .page-hero::before {
  background:
    radial-gradient(58% 55% at 22% 28%, color-mix(in srgb, var(--lit) 22%, transparent), transparent 70%),
    radial-gradient(55% 50% at 82% 24%, color-mix(in srgb, var(--lit) 12%, transparent), transparent 72%),
    radial-gradient(62% 58% at 68% 82%, color-mix(in srgb, var(--lit) 10%, transparent), transparent 70%);
}
/* Studio services — lightning */
body[data-surface="clients"] .page-hero::before {
  background:
    radial-gradient(58% 55% at 22% 28%, color-mix(in srgb, var(--thunder) 26%, transparent), transparent 70%),
    radial-gradient(55% 50% at 82% 24%, color-mix(in srgb, var(--thunder) 14%, transparent), transparent 72%),
    radial-gradient(62% 58% at 68% 82%, color-mix(in srgb, var(--thunder) 12%, transparent), transparent 70%);
}
/* Studio communities — rising suns */
body[data-surface="ventures"] .page-hero::before {
  background:
    radial-gradient(58% 55% at 22% 28%, color-mix(in srgb, var(--sun) 26%, transparent), transparent 70%),
    radial-gradient(55% 50% at 82% 24%, color-mix(in srgb, var(--sun) 14%, transparent), transparent 72%),
    radial-gradient(62% 58% at 68% 82%, color-mix(in srgb, var(--sun) 12%, transparent), transparent 70%);
}
/* Retreat / SCENT.TECH — snow gold */
body[data-surface="retreat"] .page-hero::before {
  background:
    radial-gradient(58% 55% at 22% 28%, color-mix(in srgb, var(--snow) 26%, transparent), transparent 70%),
    radial-gradient(55% 50% at 82% 24%, color-mix(in srgb, var(--snow) 14%, transparent), transparent 72%),
    radial-gradient(62% 58% at 68% 82%, color-mix(in srgb, var(--snow) 12%, transparent), transparent 70%);
}
/* Community Coffee — rain blue only (the light-rain drops, not hard rain) */
body[data-surface="coffee"] .page-hero::before {
  background:
    radial-gradient(58% 55% at 22% 28%, color-mix(in srgb, var(--rain) 28%, transparent), transparent 70%),
    radial-gradient(55% 50% at 82% 24%, color-mix(in srgb, var(--rain) 16%, transparent), transparent 72%),
    radial-gradient(62% 58% at 68% 82%, color-mix(in srgb, var(--rain) 12%, transparent), transparent 70%);
}
/* Studio archive — all segments, quiet multi from the six */
body[data-surface="system"] .page-hero::before {
  background:
    radial-gradient(50% 50% at 18% 30%, color-mix(in srgb, var(--hard-rain) 14%, transparent), transparent 70%),
    radial-gradient(48% 48% at 78% 22%, color-mix(in srgb, var(--rain) 12%, transparent), transparent 72%),
    radial-gradient(52% 52% at 72% 78%, color-mix(in srgb, var(--thunder) 12%, transparent), transparent 72%),
    radial-gradient(46% 46% at 20% 80%, color-mix(in srgb, var(--sun) 10%, transparent), transparent 70%),
    radial-gradient(44% 44% at 50% 50%, color-mix(in srgb, var(--snow) 10%, transparent), transparent 68%);
}
.page-hero::after {
  background-image: var(--grain);   /* THE ONE GRAIN tile (tokens.css) — shared with the photograph dress */
  background-size: 180px 180px;
  opacity: 0.06;
  mix-blend-mode: soft-light; /* grain settles into the colour, not on top of it */
}
@keyframes heroWashDrift {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(0, -2%, 0) scale(1.08); }
}
@media (prefers-reduced-motion: reduce) {
  .page-hero::before { animation: none; }
}

/* ── Cloud-particle field behind every hero ──────────────────────────────
   Heroes sit over the persistent #shellField. A leftover .hero-particles
   plate is still allowed (z-index:-1 inside the hero) but the section kit
   no longer injects one — the field is the ground. Scoped with :has() so
   only heroes that still carry a plate become a stacking context. White by
   default (the page defines no --starN), soft, and pointer-through. */
.page-hero:has(> .hero-particles) { position: relative; isolation: isolate; }
.hero-particles {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}
.hero-particles canvas { opacity: var(--cloud-field, 0.77); }
.page-hero-center {
  grid-row: 2; /* one child in three zone rows — pin it to the centre band */
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  text-align: center;
}
.page-hero-mark {
  width: 120px;
  height: 120px;
  display: block;
  object-fit: contain;
  user-select: none;
  -webkit-user-select: none;
}
.hero-headline {
  margin: 0;
  font-size: var(--t-hero);
  font-weight: 500;
  letter-spacing: var(--track-wordmark); /* hero h1s track the wordmark, 0.04em (William, 2026-08-06) */
  text-transform: lowercase; /* hero titles run lowercase paths (William, 2026-07-29) */
  line-height: 1.15;
  color: var(--ink);
}
/* THE 3D HERO WORD (scent) — the headline extruded (wordmark-3d.js). The 3D
   canvas stands in the headline's seat; the <h1>'s own text stays in the DOM,
   visually hidden, so the page still says its name to readers + crawlers. The
   host box is a hair taller than the flat line so the extruded top/side faces
   never clip; tune per-page with --wm3d-h. */
.hero-headline--3d { line-height: 0; }
.wordmark-3d {
  display: block;
  width: 100%;
  height: var(--wm3d-h, clamp(66px, 16vw, 82px));
  pointer-events: none;
}
/* The shared visually-hidden helper — off-screen for sight, present for
   assistive tech + crawlers (the one true a11y-hidden; reuse, never re-invent). */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
/* THE ONE HERO BYLINE (William, 2026-07-30) — every "By rainyseason.cr"
   credit under a page word reads the SAME: mono (Fira Code), --t-caption,
   500, 0.14em, uppercase, quiet --ink-3. .page-hero-credit is the canonical
   class; .page-hero-byline (the old Amarna "By"+1.5em lockup), .hero-byline
   (the stage pages' grey #8A879A fork) and .hero-maker (scent's "by SCENT.TECH")
   all fold into it here, and their per-page forks are deleted so nothing
   drifts. Co-branded credits (scent's SCENT.TECH, endurance's triathlon.tech)
   keep their words but wear this one face. */
.page-hero-credit,
.page-hero-byline,
.hero-byline,
.hero-maker {
  margin: 0;
  font-family: var(--font-code, "Fira Code", ui-monospace, monospace);
  font-size: var(--t-caption);
  font-weight: 500;
  letter-spacing: var(--track-eyebrow);
  text-transform: lowercase;
  color: var(--ink-3);
  line-height: 1.2;
  text-align: center;
}
/* Any inner spans (the old byline-by/byline-name lockup, scent's maker-by/scent)
   inherit the one credit face — no serif step-up, no 1.5em name. */
.page-hero-byline .byline-by,
.page-hero-byline .byline-name,
.hero-maker .maker-by,
.hero-maker .scent {
  font-family: inherit;
  font-size: inherit;
  font-weight: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
}
/* Statement — the hero's most important message, one line under the name.
   A hero display size, like .hero-headline, so it sits off the --t-* ramp.
   Still nothing else on that screen. */
.page-hero-statement {
  margin: 0;
  font-size: 18px;
  color: var(--ink-2);
  letter-spacing: var(--track-wordmark); /* hero body statements track the wordmark, 0.04em (William, 2026-08-06) */
  line-height: 1.45; /* a breath more than the old 1.35; still display-tight (2026-08-05) */
  /* Held to the buttons-component width so it only ever wraps to two lines.
     Fira Code is monospace, so ~34ch ≈ the two-button row beneath it. */
  max-width: 34ch;
}
/* Hero cluster type — ONE source for every page hero (home, team, …) so the
   eyebrow and body lead can never drift apart.
   Page-specific placement (alignment, measure of the column, the stack gap)
   stays on each page; the type itself lives here. The stack rhythm is the
   home reference: an eyebrow, a mono body, two CTAs, the curl — 24px apart. */
.hero-eyebrow {
  margin: 0;
  font-size: var(--t-caption); /* 11px — small eyebrow */
  font-weight: 500;
  letter-spacing: var(--track-eyebrow);
  text-transform: lowercase;
  color: var(--ink); /* full white */
  line-height: 1.2;
}
/* The parent-brand credit as the hero eyebrow — the locked product hero opens
   "By rainyseason.cr" above the page word. Never
   uppercased: the domain is always the lowercase wordmark. Quiet ink so it
   reads as a credit, not a headline. */
.hero-eyebrow--credit {
  text-transform: none;
  letter-spacing: var(--track-head);
  color: var(--ink-3);
}
.hero-lead {
  margin: 0;
  font-family: "Fira Code", ui-monospace, monospace;
  font-size: var(--t-body);
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.7;
  text-transform: none;
  color: var(--ink-2);
  word-spacing: 0.02em;
  text-align: left;
  /* Full column width on mobile — a measure cap there only wraps short of the
     rest of the cluster. The 42ch reading measure kicks in from tablet up. */
}
@media (min-width: 761px) {
  .hero-lead { max-width: 42ch; }
}

/* --- The stage hero (one source) ---------------------------------------
   The front-door hero as a STAGE: the live 3D mark rides the upper 1fr row,
   centred in the gap between the menu bar and the copy; the copy cluster
   (eyebrow at h1 scale · mono lead · CTAs · curl) anchors bottom-left.
   Home and experiences mount this same grammar — placement, ground and type
   scale all live here, never per page.
   Markup:
     <header class="page-hero stage-hero">
       <div id="weatherMark3d" class="hero-symbol" aria-hidden="true"></div>
       <div class="page-hero-center"> p.hero-eyebrow · h1.hero-lead · .btn-row </div>
     </header> */
/* The stage starts flush with the viewport top — no 64px surface pad. The
   menu bar overlays, which is fine: the cluster anchors to the bottom so it
   never hides behind it. */
/* A stage-hero fills the viewport behind the fixed bar, so the surface drops
   its bar padding — whether the hero is a direct child or wrapped (e.g. scent's
   .page token wrapper). */
.surface:has(.stage-hero) { padding-top: 0; }
/* Bottom-anchored, left-aligned. Explicit height: 100dvh (not just
   min-height) so the containing block is definite for the parked rain
   video iframe's inset: 0 to resolve against — NOTE the parked markup in
   git history targets the old .home-stage class; re-target to .stage-hero
   on restore. Overrides .page-hero and .has-tabbar on every breakpoint. */
.page-hero.stage-hero,
.has-tabbar .page-hero.stage-hero {
  /* CENTRED — the private line gate grammar (private line.css .gate-hero): the 3D
     mark rides the top, the words float in the free air between mark and
     CTAs (auto margins), the CTAs hold the floor. One look on both origins. */
  display: flex;
  flex-direction: column;
  align-items: center;
  /* The bottom pad is the private line floor (--btn-floor) so the CTA stack
     lands at the same screen height as the gate's buttons. */
  padding: 24px clamp(24px, 5vw, 48px) max(var(--btn-floor, 16px), env(safe-area-inset-bottom));
  /* min-height only: on a short viewport the hero GROWS past the screen and
     the page scrolls, rather than the content overflowing the grid into the
     button floor (measured: home's 3-line statement + the follow lock ate
     14px of floor at 720 with a hard height). If the parked rain video
     returns, its absolute inset resolves against the padding box either way.
     SVH, not dvh (William, 2026-08-08: the curl bar hid behind the phone's
     URL bar): iOS resolves dvh as the LARGE viewport in several releases, so
     the hero floored itself under the collapsed-bar height and the floor row
     loaded off-screen. The SMALL viewport is the honest first screen — the
     floor is visible above the URL bar from the first paint, and when the
     bar collapses the page shows the next section sooner. Plain vh stays as
     the pre-15.4 fallback. */
  min-height: 100vh;
  min-height: 100svh;
  /* Transparent so the persistent particle field (#shellField, behind the
     surface) shows through the hero — the field is the stage's ground now, over
     the body's black. (Was pinned #000 while the rain video was parked; the
     field replaces it. Restore the video from git if it returns.) */
  background: transparent;
  /* faq.css isolates every .page-hero so a local wash stays behind the mark.
     A stage-hero has no wash: it must NOT form a stacking context, or WebKit
     (Desk live) paints an opaque plate over #shellField. Local .hero-particles
     still isolate via :has() below. */
  isolation: auto;
  overflow: visible;
}
.stage-hero .page-hero-center {
  /* The base .page-hero-center is already a centred flex column (gap 24).
     Fill the air below the mark; auto margins on the eyebrow and the CTA row
     centre the words vertically, private line-style. */
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  max-width: var(--hero-cluster-w, 430px);
  /* No z-index. A stacking context on this flex column is a WKWebView
     compositor plate over #shellField (type and the 3D mark stay, stars vanish).
     Copy still paints above the field: #shellField is first in body, in-flow
     type comes later. The 3D mark is a sibling in an earlier grid row. */
}
.stage-hero .hero-eyebrow { margin-top: auto; }
.stage-hero .btn-row { margin-top: auto; }
/* The live 3D mark, vertically centred in the gap between the menu bar and
   the bottom copy. It's the upper grid row's item, centred there with
   align-self, so it self-adjusts as the copy grows or shrinks. Transparent
   canvas, so the black ground shows through behind the metallic mark.
   Auto-mounts via weather-mark-3d.js on #weatherMark3d. Height is the size
   knob (the mark scales with it), nudge to taste. */
/* The .hero-symbol MOUNT spec (seat, size, transform, ladder) now lives in the
   ONE shared source, parts/cloud.css — the same file the private line imports, so
   the mark can never drift between origins. Only the app's GRID PLACEMENT of the
   mount stays here (.stage-hero--center .hero-symbol, below). */
/* The stage eyebrow is the page word, run at h1 scale. */
.stage-hero .hero-eyebrow { font-size: var(--t-h1); }
/* The /path title rides the same --hero-lift as the 3D mark, so the hero's
   floating pieces move as one. Scoped to real heroes: pages that only borrow
   .hero-headline for its TYPE (section statement titles) keep their seats;
   the --center variant's centred title rides too. */
.page-hero .hero-headline,
.stage-hero--center .hero-eyebrow { transform: translateY(calc(-1 * var(--hero-lift, 33px) + var(--hero-title-drop, 0px))); }
/* The stage lead carries hand-set line breaks, so drop the shared 42ch
   measure and let the 720px cluster bound it. Centred with the cluster. */
.stage-hero .hero-lead { max-width: none; text-align: center; }

/* --- The centred hero (William, 2026-07-29) — ROLLING OUT ------------------
   The one hero spec, every surface + the private line gate:
     · the H1 sits at the EXACT vertical centre of the first screen
     · the 3D mark hugs directly ABOVE the H1
     · the body copy, then the curl, sit directly BELOW the H1
     · the private line CTA is ALWAYS the bottom button, holding the floor
   Zone rows 1fr/auto/1fr put the H1 at true centre — no magic offsets (the
   page-grid law). Proven on /services first (the reference William eyeballs),
   then this folds into .stage-hero and rolls to every hero + the private line
   gate, and the law is recorded. Markup: the H1 is a DIRECT child of the
   header (so it can own the centre row); everything below it stays in
   .page-hero-center; the mark is the hero-symbol as before.
     <header class="page-hero stage-hero stage-hero--center">
       <div class="hero-symbol" id="weatherMark3d"></div>   (row 1, hugs above)
       <h1 class="hero-eyebrow">TITLE</h1>                     (row 2, dead centre)
       <div class="page-hero-center"> byline · lead · curl · .btn-row </div>
     </header> */
.page-hero.stage-hero--center {
  display: grid;
  grid-template-rows: 1fr auto 1fr;
  justify-items: center;
  align-items: stretch;
}
/* THE ONE CLOUD SEAT (William, 2026-08-06: "all clouds at the same height,
   fixed — no overrides"): the mount top-anchors in the top zone on the BASE
   .hero-symbol spec alone — --wx3d-seat under the hero's top edge (24px pad
   + 48 = 72 = bar 64 + 8 gap), --wx3d-h tall, the shared lift-minus-drop ride.
   The old align-self:end hung the cloud off the bottom of the 1fr air zone,
   so its height moved with the viewport and no two windows agreed. Now the
   seat is absolute on every hero, both origins, at every height; only
   grid-row 1 is stated here so the grid can't re-place it. */
.stage-hero--center .hero-symbol {
  grid-row: 1;
  align-self: start;
}
/* The title sits at the EXACT vertical centre — whatever its class (services'
   hero-eyebrow, scent's hero-headline, home's hero-lead). It must be a DIRECT
   child of the header so it can own the centre row. Every product hero shares
   this, so every H1 lands on the same line and every cloud above it too. */
.page-hero.stage-hero--center > h1,
.page-hero.stage-hero--center > .hero-lockup {
  grid-row: 2;
  margin: 0;         /* clear the stage's margin-top:auto */
  align-self: center;
}
/* Stage-hero titles are the SAME title as .hero-headline — one size, one
   kerning, one weight — so /services, /studio and /network never drift
   (William, 2026-07-29). Higher specificity clears any page-local hero-eyebrow.
   :not(.hero-lead) — home's H1 IS the studio description (.hero-lead), not a
   path title, so it keeps its body size (William, 2026-07-30). */
.page-hero.stage-hero--center h1:not(.hero-lead) {
  font-size: var(--t-hero);
  font-weight: 500;
  letter-spacing: var(--track-wordmark); /* match the wordmark 0.04em (William, 2026-08-06) */
  text-transform: lowercase;
}
/* A title block that carries a line ABOVE the H1 (home's eyebrow, scent's
   theme) rides at the centre as ONE lockup, so the H1 still lands on the
   shared centre line with its label hugging just above it. */
.page-hero.stage-hero--center > .hero-lockup {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}
/* .page-hero prefix wins over any page-local .stage-hero .page-hero-center
   override (the services page still carries the old stage layout locally). */
.page-hero.stage-hero--center .page-hero-center {
  grid-row: 3;         /* everything under the H1 hangs in the bottom zone */
  align-self: stretch; /* FILL the bottom zone so the button row can floor at the base */
  justify-content: flex-start; /* body copy + curl hug the top, under the H1 */
  width: 100%;
  margin-top: var(--hero-copy-gap, 12px); /* the word-to-copy gap — one token, every hero */
  padding-top: 0;      /* drop the old stage top-pad so the copy hugs the H1 */
}
/* The copy rides WITH the word: every centre-zone row except the floored
   button stack lifts by the same --hero-lift, so the body copy holds its
   --hero-copy-gap under the /path word wherever the word rides; per-page
   first-child margins are zeroed so the gap is the token alone. */
.page-hero.stage-hero--center .page-hero-center > :not(.btn-row) {
  transform: translateY(calc(-1 * var(--hero-lift, 55px) + var(--hero-title-drop, 0px)));
}
/* THE FOLLOW-MESSAGE LAW (William, 2026-08-05): the message after the hero
   body sits at a LOCKED height — the CHIP LINE (Costa Rica; Serving local
   and global clients) rests exactly --hero-follow-gap above the button
   stack, on every hero, at every viewport height, regardless of statement
   length. A dateline HANGS 8px below the chip INSIDE the gap (its negative
   top margin places it; its bottom margin returns the difference less its
   own 1lh, so the chip's lock stays exact with or without a dateline). The
   chip's auto top takes the free air; a zone carrying the chip zeroes its
   flex gap and the button row's auto top so the token alone spans
   message-to-stack. No ride: the lock is the rendered distance. */
.page-hero.stage-hero--center .page-hero-center > .hero-sentence {
  transform: none;
  margin-bottom: var(--hero-follow-gap, 96px);
}
.page-hero.stage-hero--center .page-hero-center > .page-hero-dates {
  transform: none;
  margin-top: calc(-1 * var(--hero-follow-gap, 96px) + 8px);
  margin-bottom: calc(var(--hero-follow-gap, 96px) - 8px - 1lh);
}
.page-hero.stage-hero--center .page-hero-center:has(.hero-sentence) { gap: 0; }
.page-hero.stage-hero--center .page-hero-center:has(.hero-sentence) .btn-row { margin-top: 0; }
.page-hero.stage-hero--center .page-hero-center > :first-child { margin-top: 0; }
/* CHIP-LED cluster — THE PRIVATE LINE SEAT (William, 2026-08-06: every hero
   body statement sits as the private line's "A private encrypted line" tagline,
   CLOSE to the H1): the leading chip RIDES the shared lift with the word
   (clearing the follow-law's no-ride above), so its --hero-copy-gap seat is
   the TRUE rendered distance under the title, exactly as the gate's tagline;
   the follow statement rides too and stacks --hero-copy-gap under the chip —
   no follow lock, no mid-air float. The button stack keeps its auto top and
   holds the floor alone. */
.page-hero.stage-hero--center .page-hero-center > .hero-sentence:first-child {
  margin-bottom: 0;
  transform: translateY(calc(-1 * var(--hero-lift, 55px) + var(--hero-title-drop, 22px)));
}
.page-hero.stage-hero--center .page-hero-center:has(> .hero-sentence:first-child) > .page-hero-statement {
  transform: translateY(calc(-1 * var(--hero-lift, 55px) + var(--hero-title-drop, 22px)));
  margin-top: var(--hero-copy-gap, 12px);
  margin-bottom: 0;
}
.page-hero.stage-hero--center .page-hero-center:has(> .hero-sentence:first-child) .btn-row {
  margin-top: auto;
}
/* The statement in the follow seat runs FINE — /scent is the reference body
   (William, 2026-08-06: all hero bodies read as /scent's): button-lead size
   (--t-body, level with the CTA words — was --t-small), the SOFT ceiling ink
   (--ink-2, the 72% rung — /scent's chip lead reads there under its page
   ceiling; now the shell default so every hero body matches without a
   page-local re-pin, William 2026-08-06), the 34ch measure with plain wrap
   (balance made a runt on home's three-liner, measured 2026-08-05; hand-set
   brs pass through untouched). The former page-local pins on /scent and home
   are folded in here — one spec. */
.page-hero-statement--fine {
  font-size: var(--t-body);
  color: var(--ink-2);
  max-width: 34ch;
  text-wrap: wrap;
}
/* The dateline wears the SAME fine dress as the follow line, the SAME size
   (William, 2026-08-05: Costa Rica over the date, two clean lines inside
   the one follow element) — only the tabular digits are its own. As a
   direct child of the centre zone it still hangs on the dateline law. */
.page-hero-dates {
  font-size: var(--t-small);
  letter-spacing: 0;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
/* THE FOLLOW LINE — its OWN component (William, 2026-08-06): home's serving
   line and /scent's Costa Rica + date are NOT hero body copy — when the body
   clustered up to the title (THE PRIVATE LINE SEAT above) these must stay DOWN.
   Wears the fine dress; CENTRED in the air between the sentence and the button
   stack (William, 2026-08-10): auto top AND auto bottom split the free space
   evenly, so the message rests midway — equal gap above and below — instead of
   locked --hero-follow-gap above the buttons. A dateline lives inside it as a
   span (.page-hero-dates), riding the centre with it. */
.hero-subline {
  margin: auto 0;
  font-size: var(--t-small);   /* one step down from the body statement (William, 2026-08-06) — level with its own dateline */
  text-transform: uppercase;   /* the follow line runs in capitals (William, 2026-08-06) */
  letter-spacing: var(--track-title);   /* up the ladder again: the house heading rung, 0.06 (William, 2026-08-06) */
  color: var(--ink-2);
  max-width: 34ch;
  text-wrap: wrap;
}
.page-hero.stage-hero--center .page-hero-center > .hero-subline { transform: none; }
.page-hero.stage-hero--center .page-hero-center:has(> .hero-sentence:first-child):has(> .hero-subline) .btn-row { margin-top: 0; }
/* The symbol-button state model lives in button.css now (the app standard,
   William 2026-08-05) — hero primaries read it like every symbol button. */
/* The private line CTA row holds the floor, so the curl (a sibling above it in
   .page-hero-center) stays directly under the body copy. */
.stage-hero--center .page-hero-center .btn-row { margin-top: auto; }
/* THE HERO FITS THE PHONE (William, 2026-08-08, proven on the scent door):
   the 1fr/auto/1fr centring theatre equalises its two air zones and will not
   compress below their shared size, so on short viewports the floor row (the
   CTA, the curl bar) loaded past the screen. Below 740 the hero stacks from
   the top instead — mount, word, then one remaining zone whose auto margins
   still floor the buttons — and the 3D window gives up height share. The
   shortest class tightens the copy gaps too. Tall viewports never enter the
   gates, so desktop stays pixel-identical. Placed AFTER the --center grid
   spec above: the re-template ties it on specificity and must win the
   cascade by order. */
@media (max-height: 740px) {
  /* The stage-hero cloud height itself steps down in parts/cloud.css (the
     MARKETING-HERO profile); this block only re-templates the grid so the floor
     row (CTA + curl) never loads past a short screen — the reason that ladder is
     aggressive in the first place. */
  .page-hero.stage-hero--center { grid-template-rows: auto auto 1fr; align-content: start; }
}
@media (max-height: 600px) {
  .stage-hero .page-hero-center { gap: 14px; }
}
/* THE HERO LEAD — the app-wide LOCK (William, 2026-08-05): every page hero's
   lead line wears this black mono chip (+ --lead below), tight under the
   /path word. A page with a follow line (home's serving line, scent's Costa
   Rica) dresses it as .page-hero-statement--fine at the follow lock; the
   dateline law rides beneath it unchanged. prod-audit enforces the chip. On
   a bare place chip (no --lead) the wide --track-head caps tracking stays. */
.hero-sentence {
  margin: auto 0;
  padding: 2px 6px;
  background: #000;
  color: var(--ink-2); /* the soft ceiling (72% rung) — chip leads read as /scent's, the shell default (William, 2026-08-06) */
  font-family: var(--font-code, "Fira Code", ui-monospace, monospace);
  font-size: var(--t-body);
  letter-spacing: var(--track-head);
  line-height: 1.2;
  /* Written as typed (William, 2026-08-05) — no case transform of its own.
     A long chip WRAPS (home's studio line wears the chip now): balanced rag,
     centred like the stage cluster. Short chips (Costa Rica) render exactly
     as before. */
  max-width: 34ch;
  text-wrap: balance;
  text-align: center;
}
/* The statement-length chip — a full lead line in the chip dress (home's
   studio line). THREE lines on the 34ch measure (the first line, "A
   decentralised creative studio", is 31ch — a tighter cap breaks it to
   four); the chip's wide caps tracking comes off (kerning at the
   statement's own 0, which also keeps 34ch holding 34 characters) and the
   leading opens past the one-liner's 1.2 (William, 2026-08-05). */
.hero-sentence--lead {
  letter-spacing: 0;
  line-height: 1.75;   /* opened from 1.5 — more air between the statement's lines (William, 2026-08-10) */
}

/* Base heroes (static mark) share the ONE vertical rhythm: mark · h1 · credit ·
   CURL · body · buttons (William, 2026-07-30). The DOM keeps the curl before the
   private line (the census law); CSS order lifts it above the body so every hero,
   3D or static, reads the same top to bottom. */
.page-hero:not(.stage-hero) .page-hero-center > .btn--curl { order: 1; }
.page-hero:not(.stage-hero) .page-hero-center > .page-hero-statement,
.page-hero:not(.stage-hero) .page-hero-center > .hero-sentence--lead { order: 2; }
.page-hero:not(.stage-hero) .page-hero-center > .btn-row { order: 3; }
/* Base heroes run left-ragged, and their centre column is not a centring
   flex — the chip sheds the stage's auto margins and centred rag there,
   shrink-wraps to its text, and keeps the statement's old seat (order 2). */
.page-hero:not(.stage-hero) .page-hero-center > .hero-sentence {
  margin: 0;
  width: fit-content;
  text-align: left;
}

