/* site-home.css — MOVED VERBATIM from index.html's three inline <style> blocks
   (D507, 17 Oct), so the homepage and closer-look.html share ONE copy. */

@font-face{
  font-family:'Space Grotesk';
  src:url('/assets/fonts/SpaceGrotesk[wght].woff2') format('woff2-variations');
  font-weight:300 700; font-display:swap;
}
/* ⭐ INTER — the body face. FONT_DECISION_v8 §1.1: Space Grotesk is a DISPLAY
   face and was being used as a workhorse, for navigation AND body copy. */
@font-face{
  font-family:'Inter';
  src:url('/assets/fonts/Inter[wght].woff2') format('woff2-variations');
  font-weight:400 700; font-display:swap;
}
:root{
  /* ⭐ PAGE_MOCKUP_PROMPT_v8 §4.1. ⚠️ The accent is BUTTONS ONLY. */
  /* ⭐ the fixed header's UNSTUCK height, read by `.hdr` and by `.hero` */
  --hdr-h:130px;
  --ink:#0A0A0A; --paper:#F2F4F5; --muted:#8A8F98; --accent:#2EE68A;
  --accent-ink:#052E1B; --rule:rgba(255,255,255,.14);
  --panel:#12181A;
  /* ⭐ §5 — personality in the display face, neutrality in the body face. */
  --font-display:'Space Grotesk','Segoe UI',sans-serif;
  --font-body:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
  --font:var(--font-body);          /* ⚠️ legacy alias, body by default */
  --pad:clamp(20px,5vw,64px); --wrap:1200px;
}
*{box-sizing:border-box}
/* ⭐ §5 — the display face is for headings, navigation and buttons ONLY.
   ⚠️ Space Grotesk runs tight, hence the negative tracking. */
h1,h2,h3,.nav,.btn,.brand,.eyebrow,.lv,.step h3,.player h3{
  font-family:var(--font-display); letter-spacing:-.01em;
}
h1,h2{letter-spacing:-.02em}
/* ⛔ numbers that sit in a column must not jitter — §4.1 */
.numbers li::before,.leaks li::before,.step::before{font-variant-numeric:tabular-nums}
html{scroll-behavior:smooth}
@media (prefers-reduced-motion:reduce){ html{scroll-behavior:auto} }
body{margin:0; background:var(--ink); color:var(--paper); font-family:var(--font-body);
  /* ⚠️ 18px, ⛔ NOT 16. §5: research says 16 is the MINIMUM and our
     audience is 50+. Line height 1.6; 1.5 is the floor. */
  font-size:18px; line-height:1.6; letter-spacing:0; -webkit-font-smoothing:antialiased}
img{max-width:100%; display:block}
a{color:inherit}
.wrap{max-width:var(--wrap); margin:0 auto; padding:0 var(--pad)}

/* ---------- header ------------------------------------------------------ */
/* ⛔ THE BAR IS SIZED BY THE MARK, NOT THE OTHER WAY ROUND. A 3x wordmark in
   a fixed 72px header is a clipped wordmark — measured hanging out at y -21
   and y 93 of a 0..72 bar. */
/* ⭐ ONE NUMBER FOR THE MARK, AND THE BAR AND THE SCROLL OFFSET BOTH READ IT.
   The wordmark is what sets the bar's height, so anything that needs to know
   how tall the bar is has to ask the mark -- not carry its own copy of the
   clamp. */
/* ⛔⛔ THE HEADER'S HEIGHT IS A TOKEN BECAUSE THE HERO HAS TO CLEAR IT —
   2026-10-02. The new hero pins its type as percentages of the plate, and the
   plate starts at the hero's own top edge, so a FIXED 130px header sits over the
   top 16% of it. MEASURED: `IMG.wordmark` spans y 9.8..119.2 and the headline's
   gold span y 87.4..136.4 — the wordmark painted across the top 32px of the words
   "solid poker", 65% of their height, at 1440x900.
   ⭐ So `.hero` reads this value rather than typing a second copy of it, which is
   the direction this codebase's oldest defect runs in. `check_seat_occlusion`
   gates the outcome.
   ⚠️ `.hdr.stuck` is a DIFFERENT height (96px) and is deliberately not this
   token: the hero only ever meets the UNSTUCK header, at scroll 0. */
.hdr{--fs-mark-h:clamp(52px,7.6vw,114px);
  position:fixed; inset:0 0 auto 0; z-index:50; min-height:var(--hdr-h); display:flex;
  align-items:center; background:rgba(10,10,10,0); border-bottom:1px solid transparent;
  transition:background .25s ease, border-color .25s ease, height .25s ease}
/* ⛔ `height:56px` WAS HERE AND HAD NEVER ONCE APPLIED. Measured at 1280: the
   stuck bar is 96px, the CSS said 56, and `min-height:130px` said 130 --
   three numbers, none of them the truth, because the MARK sizes the bar and
   the comment above says so. That is defect #22 (the-ten-leaks.html's
   `.hdr{height:72px}` against a 109px mark) in the file that already carried
   the rule. A height that never wins is not harmless: it is the number the
   next person reaches for. Removed; only the appearance change is stuck. */
.hdr.stuck{background:rgba(10,10,10,.93);
  -webkit-backdrop-filter:blur(10px); backdrop-filter:blur(10px);
  border-bottom-color:var(--rule)}
.hdr .wrap{display:flex; align-items:center; gap:24px; width:100%}
.brand{display:flex; align-items:center; text-decoration:none; flex:none}
/* ⭐ 3x — Eric, 2026-08-25. Was 38px. This is the first thing anybody sees
   and it was competing with the nav links rather than leading them.
   ⚠️ CLAMPED, because a flat 114px is 363px WIDE and fills a 360px phone
   edge to edge. 3x on a desktop, proportionate on a handset. */
.brand .wordmark{height:var(--fs-mark-h); width:auto; max-width:62vw; display:block}
/* ⛔⛔ AND THE ANCHORS HAVE TO CLEAR IT. The header is `position:fixed`, so it
   is not in flow and an anchor jump lands the target's top edge at y=0 --
   underneath it. Measured: `#players`, `#teams` and `#why` all landed with
   their first 96px hidden behind the bar, on a page whose own nav links are
   those three anchors. `#levels` looked fine only because it happens to have
   179px of padding above its heading.
   ⚠️ Derived from the same --fs-mark-h the bar is, plus the breathing room,
   so it cannot drift when the mark is resized. */
html{scroll-padding-top:calc(clamp(52px,7.6vw,114px) + 34px)}
/* Shrinks on scroll so the sticky header stays a header, but proportionally. */
.hdr.stuck{min-height:96px}
.hdr.stuck .brand .wordmark{height:clamp(42px,6vw,90px)}
footer .brand .wordmark{height:132px}   /* 3x, was 44px */
.nav{display:flex; gap:26px; margin-left:auto; font-size:15px}
.nav a{color:var(--paper); opacity:.82; text-decoration:none; padding:8px 0}
.nav a:hover{opacity:1}
/* ⛔ D296 (Eric, 8 Oct): "menus at the top should be persistent". This used to
   be `.hdr.stuck .nav{display:none}` (with the brand pushed right), §4.2's
   "the header collapses after the hero", since 24 Aug. Every menu target sits
   below 600px, so clicking any item landed on the section and the three links
   vanished. They stay now; the bar still shrinks when stuck.
   Guard: check_home_nav_persist.py. ⚠️ Phones (≤ 860px) have no menu at all
   (below); a phone design is Eric's. */

/* ---------- buttons ----------------------------------------------------- */
.btn{display:inline-flex; align-items:center; justify-content:center;
  min-height:56px; padding:0 30px; border-radius:10px; font:inherit;
  /* ⚠️ AFTER `font:inherit`, which is a SHORTHAND and resets
     font-family — the display-face rule above loses to it on order.
     Buttons are display face per §5. */
  font-family:var(--font-display);
  font-size:16px; font-weight:700; letter-spacing:.02em; text-decoration:none;
  border:2px solid transparent; cursor:pointer;
  transition:filter .12s ease, transform .12s ease}
.btn-primary{background:var(--accent); color:var(--accent-ink)}
.btn-primary:hover{filter:brightness(1.08)}
.btn:active{transform:translateY(1px)}
.btn:focus-visible{outline:3px solid #fff; outline-offset:3px}
.btn-ghost{background:transparent; color:var(--paper); border-color:rgba(242,244,245,.45)}
.btn-ghost:hover{border-color:var(--paper)}
.btn-sm{min-height:46px; padding:0 20px; font-size:15px}
.hdr .btn{min-height:44px; padding:0 20px; font-size:15px}
/* ⭐⭐ D318 (9 Oct): "THE PHONE MENU IS A MENU BUTTON at ≤860px. Not a second row,
   not none." The bar is fixed, so the button is on screen at every scroll
   position and after every jump — D296's "persistent" — and the three links open
   as a panel under the bar. Hidden above 860px, where the links are inline. */
.nav-toggle{display:none}
@media (max-width:860px){
  .nav-toggle{display:inline-flex; align-items:center; justify-content:center;
    margin-left:auto; min-height:44px; min-width:44px; padding:0 14px; flex:none;
    background:transparent; color:var(--paper); font:inherit; font-size:15px;
    border:1px solid rgba(244,246,245,.35); border-radius:10px; cursor:pointer}
  .hdr.nav-open .nav{display:flex; flex-direction:column; gap:0; position:absolute;
    top:100%; left:0; right:0; margin:0; padding:6px 16px 12px;
    background:rgba(10,10,10,.97); border-top:1px solid rgba(244,246,245,.12)}
  .hdr.nav-open .nav a{display:flex; align-items:center; min-height:44px; padding:0; opacity:1}
}
.cta-row{display:flex; gap:14px; flex-wrap:wrap}

/* ---------- hero -------------------------------------------------------- */
.hero{position:relative; overflow:hidden}
/* ⛔⛔ THE OLD HERO'S BACKGROUND AND SCRIM ARE DELETED — 2026-10-02, with the
   scene they served. `.hero::before` painted `--hero-bg` and `.hero::after` laid
   a 94%-opaque black gradient over it, and its own comment was right for the
   hero it belonged to: "text over open water fails 4.5:1" is true when the
   background is a dim photo and the text sits on top of it.
   ⛔ THE NEW HERO IS THE OPPOSITE ARRANGEMENT. The plate draws four surfaces
   EMPTY and the type sits ON them, so a full-bleed scrim is not contrast
   insurance — it is a sheet over the artwork.
   ⚠️⚠️ AND IT BROKE THE PAGE SILENTLY. `z-index:1` on the pseudo-element against
   `z-index:auto` on every zone put the scrim above all of them. MEASURED: the
   headline computed `rgb(244,246,245)` at opacity 1, every zone landed on its
   spec'd percentage to the decimal, 9 of 9 images loaded — and the hero was
   unreadable. `elementFromPoint` at the headline returned `SECTION.hero`.
   ⭐ Only the SCREENSHOT showed it. Every number said the page was correct. */
.hero .wrap{position:relative; z-index:2}
h1{margin:0 0 20px; font-size:clamp(34px,5.2vw,58px); line-height:1.06;
  letter-spacing:-.02em; font-weight:700; text-wrap:balance}
.sub{margin:0 0 26px; font-size:clamp(18px,2.1vw,21px) !important; color:#D5DBDD; max-width:34ch}

/* ---------- sections ---------------------------------------------------- */
section{position:relative}
/* ⛔⛔ `padding-block`, NOT THE SHORTHAND. This was
   `padding: clamp(...) 0`, and a shorthand writes ALL FOUR sides — so the `0`
   silently reset padding-left and padding-right. `.sec` is declared after
   `.wrap`, so any element carrying BOTH classes lost the page indent.
   ⚠️ Measured: `#levels` uses `class="sec wrap"` on one element and its
   heading sat at x=40 while every other section sat at x=104. Eric spotted it
   as "this indent is not the same as the rest of the page".
   ⭐ Same family as defect #19 -- two rules writing one property, where the
   winner is whichever came last. The fix is to stop writing the axis we do
   not mean, not to add a more specific override. */
/* ⭐⭐ 44px A SIDE, BECAUSE TWO OF THEM MEET. Eric, 4 Sep: every green header
   must sit the same distance below what precedes it, and he pointed at THE
   PLAN — 88px — as the one that is right.
   ⛔ A section-top eyebrow gets NO margin of its own (the rule further down),
   so its gap is the previous section's padding-BOTTOM plus this one's
   padding-TOP. At 100 each that measured 200px; at 44 each it is 88, the same
   88 a mid-section eyebrow gets from --eyebrow-above.
   ⚠️ Measured before the change: 200 · 88 · 200 · 216 · 64 · 298 · 138 · 134 ·
   64. Nine green headers, seven different gaps. */
.sec{padding-block:44px}
/* ⭐⭐⭐ STANDING RULE — TWO CLEAR LINES BEFORE A MAJOR HEADING.
   Eric, 4 September: "needs to be a few lines of space here. DO NOT crowd
   stuff like this on the home page. Write a rule that at least 2 spaces of
   blank space need to be there before a major heading."
   ⚠️ It came from the SHARKBAIT wordmark running straight into "You will find
   out which leaks are yours." — a logo and a heading touching read as one
   block, so the heading stopped announcing anything.
   ⛔ IT IS A FLOOR, NOT A SETTING. `margin-top` here can be overridden
   upward by a section that wants more; what it cannot do is fall below two
   lines of the heading's own leading. 2 x 1.12 line-height on the clamp's
   own size is what "two blank lines" means at any width.
   ⚠️ `:first-child` is exempt: a heading at the top of its section has the
   section's own spacing above it, and adding more would open a hole. */
h2{margin:clamp(56px,7vw,88px) 0 14px; font-size:clamp(26px,3.3vw,40px); line-height:1.12;
  letter-spacing:-.02em; text-wrap:balance}
/* ⚠️ THE EXEMPTIONS, EACH FOR A REASON. A heading that OPENS its section
   already has the section's padding above it; stacking the floor on top of
   that opens a hole rather than closing one. */
h2:first-child, section > h2:first-of-type, .wrap > h2:first-child,
header h2, figure h2 { margin-top:0 }

/* ⛔⛔ AND THE UNIT IS THE EYEBROW PLUS THE HEADING, NOT THE HEADING ALONE.
   Eric, 4 Sep, on "THE PLAY IT OUT / You fold. We show you what would have
   happened." — the h2 had its two clear lines and they did nothing, because
   the EYEBROW sat above it and was still jammed against the bullet before.
   ⭐ A reader does not see two elements there. They see one heading with a
   label on top, so the space belongs above the label and the h2 keeps only
   the small gap that binds it to its eyebrow. */
/* ⚠️ AND IT HAS TO BEAT `:first-child`. Measured: the Play it Out eyebrow is
   the first element of its own `.wrap`, and a first-child reset was zeroing
   the floor — four of the five eyebrow+heading pairs came back at 0px while
   only "The plan" took the 88. The section's padding is not the same thing as
   two clear lines, which is the whole of Eric's complaint. */
.eyebrow:has(+ h2),
.wrap > .eyebrow:first-child:has(+ h2),
section .eyebrow:has(+ h2) { margin-top:var(--eyebrow-above) }   /* ⭐ one number */
.eyebrow + h2 { margin-top:0 }
/* ⚠️ `:has()` is well supported now, but a browser without it must not lose
   the space entirely — so the h2 keeps its own floor there and the pair simply
   sits a little further apart. That is the safe direction to fail in. */
@supports not (selector(:has(*))) {
  .eyebrow + h2 { margin-top:clamp(24px,3vw,36px) }
}

.lede{margin:0 0 34px; color:var(--muted); font-size:18px; max-width:58ch}
/* ⭐ a `.lede` that CLOSES a section rather than opening one — the margin is
   the only difference, so it borrows the type and the measure rather than
   declaring a second 18px muted rule. ⛔ (0,2,0), so it beats `.lede` on the
   one property it changes and inherits the rest; raise specificity, never
   reorder and hope (#19, #21). */
.lede.how-close{margin:30px 0 0}
/* ⛔⛔ THE EYEBROW SPACING IS ASYMMETRIC ON PURPOSE — §1e.4, and it is a
   TOKEN, not a per-instance nudge.
   ⚠️ Eric: "THE PLAN sits closer to the paragraph above it than to its own
   heading — it reads as the last line of the previous section." An eyebrow
   with equal air above and below reads as a CAPTION for whatever comes next
   or last, because nothing tells the eye which side it belongs to.
   ⭐ THE RULE, §1e.4: at least TWO TEXT LINES above it (a FLOOR, not a
   target), and the gap below is roughly A THIRD of that. Then the eyebrow is
   unambiguously the top of its own block.
   ⚠️ Same defect as the Murk caption, one section up, which is why the two
   were reported together. */
:root{ --eyebrow-above:88px; --eyebrow-below:20px; }   /* ⭐ 88 — Eric's THE PLAN gap, 4 Sep */
.eyebrow{margin:var(--eyebrow-above) 0 var(--eyebrow-below); font-size:13px;
  letter-spacing:.16em;
  text-transform:uppercase; color:var(--accent); font-weight:700}
/* ⛔ except at the very TOP of a section, where the section's own padding is
   the space above and a second copy of it would double.
   ⚠️⚠️ `:first-child` ALONE IS THE WRONG TEST AND IT ZEROED THE ONE ERIC
   REPORTED. The problem/plan merge left #problem with TWO `.wrap` blocks, and
   THE PLAN is the first child of the SECOND one — so it looked like the top
   of a section to the selector while sitting directly under the previous
   block's last paragraph on screen. Measured: mt went to 0px, which is the
   defect §1e.4 describes, restored by the rule written to fix it.
   ⭐ `:first-of-type` is the honest test: only the section's OWN first wrap. */
/* ⛔⛔ .prod-block CAME OFF THIS LIST. The rule exists because a SECTION's
   own padding supplies the space above an eyebrow that opens it — but a
   .prod-block has padding-top 0, so zeroing the margin left THE PLAY IT OUT
   sitting hard against the Two Numbers box above it. Eric: "need the normal
   spacing i asked for before the new green heading."
   ⭐ A prod-block eyebrow keeps --eyebrow-above like any other. */
.sec > .wrap:first-of-type > .eyebrow:first-child,
.stakes-in > .eyebrow:first-child { margin-top:0; }

/* ⭐⭐ AN EYEBROW THAT OPENS A GROUP, NOT A SECTION. "The tools that help you"
   heads BOTH SharkSense and Shark Bait, so it lives in its own wrap between
   them — which made it `section > .wrap > .eyebrow:first-child` and the rule
   above zeroed its top margin. Measured: 0px, sitting hard against the
   villains' closing line.
   ⛔ Not fixed by out-specifying that selector: this rule says WHICH of the
   two situations it is, and sits after it so ORDER settles it. */
/* ⚠️ SPECIFICITY, NOT ORDER. The zeroing selector above is
   `section > .wrap > .eyebrow:first-child:not(:has(+ h2))` — one element,
   three classes and a pseudo-class — so a bare `.eyebrow.is-group` (0,2,0)
   loses to it wherever it sits. Measured: margin-top stayed 0px.
   ⛔ CLAUDE.md already records the rule: "when two rules disagree, RAISE
   SPECIFICITY; do not reorder and hope." I reordered and hoped. */
section > .wrap > .eyebrow.is-group:first-child { margin-top:var(--eyebrow-above); }

/* ⭐⭐ THE GAP ABOVE A GREEN HEADER IS THE HEADER'S TO OWN. Eric, 4 Sep:
   "make all spacing above green headers the same" — he pointed at THE PLAN,
   88px. Measured, several read 104: the 88 plus a 16px bottom margin on the
   paragraph before them, which is invisible in the CSS and decides the gap.
   ⛔ Two cases, because an eyebrow can follow its neighbour or open a section:
     · same container — zero the previous sibling's bottom margin
     · new section    — zero the last child of the previous wrap, so the gap
                        is exactly the two 44px paddings */
/* ⚠️ AND THE MARGIN IS ON THE PARAGRAPH INSIDE, NOT THE BLOCK. Zeroing
   `.philosophy` did nothing because the 16px sits on its last <p>. Reach one
   level in as well, or the rule looks right and changes nothing. */
/* ⚠️ AND IT HAS TO REACH ANY DEPTH. The villains header read 104 because the
   paragraph adding the extra 16px is `.wrap > .plan > .step > p` — three
   levels in, where a two-level rule could not see it. A descendant chain of
   last-children is the honest reach: whatever ends a section, its bottom
   margin is not part of the next header's gap. */
.wrap > *:has(+ .eyebrow),
.wrap > *:has(+ .eyebrow) *:last-child { margin-bottom:0 }
.sec > .wrap > *:last-child,
.sec > .wrap > *:last-child *:last-child { margin-bottom:0 }

/* ⚠️ #levels IS NOT A .sec, so it carries no padding-block and its last
   paragraph's own margin decided the gap — measured 78px against the 88
   every other green header now reads. It gets the same 44 a section does,
   and its trailing margin is zeroed like theirs. */
#levels { padding-bottom:44px }
#levels > .wrap > *:last-child,
#levels > .wrap > *:last-child *:last-child { margin-bottom:0 }

/* ---------- the feelings ------------------------------------------------ */
/* ⭐ STORYBRAND §3 — four feelings, four visitors, one section. */
/* ⚠️ .feels / .feel are GONE with the RECOGNITION section --
   00_HOMEPAGE_ORDER_FINAL_v8 Part 5 item 1. The six audience cards in
   #players carry the internal problem now, in the reader’s own voice. */

/* ---------- the four players -------------------------------------------- */
/* ⭐⭐ WHICH ONE ARE YOU — WHICH_ONE_ARE_YOU_v8. The photograph IS the card
   and the words sit under it: "a list says people like you, a face says
   that's me." ⛔ SIX, not four — six across is an even grid, four is a 3+1
   orphan, and the six already cover the four plus grandpa and corporate. */
.players{display:grid; grid-template-columns:repeat(3,1fr); gap:16px}
.player{background:#102A24; border:1px solid var(--rule); border-radius:14px;
  margin:0; overflow:hidden; display:flex; flex-direction:column}
/* ⛔ 3:4, object-fit:cover, never stretched (Part 4). */
.player img{display:block; width:100%; height:auto; aspect-ratio:3/4;
  object-fit:cover; object-position:50% 20%;
  filter:saturate(.82) contrast(1.06)}
.player figcaption{padding:16px 18px 20px}
.player b{display:block; font:600 12px/1.35 ui-monospace,monospace;
  letter-spacing:.09em; text-transform:uppercase; color:#EAF2EF}
/* ⭐ THE SUBSTORY — Eric, 4 Sep: a title and one line under it. Roman and
   quiet against the uppercase title, because the argument of this section is
   that the reader recognises themselves in the PHOTOGRAPH; the words only
   confirm it. ⛔ Second person, never a quote: nobody testifies (§3.1). */
/* ⚠️ `max-width:none` IS LOAD-BEARING. A bare `.sub` already exists at the
   top of this sheet for the hero subtitle and it sets `max-width:34ch` --
   which a card 1/3 of the page wide inherits, wrapping a seven-word line into
   a narrow column. Specificity decides the properties this rule DECLARES;
   everything it leaves out still comes from the other one. */
.player .sub{display:block; margin-top:7px; font-size:15px; line-height:1.5;
  color:var(--muted); text-transform:none; letter-spacing:0;
  max-width:none; margin-bottom:0}
/* ⛔⛔ BRASS, NOT #4ADE80. Part 4: Tailwind's default green is in no spec of
   ours, and it was on every one of these labels. */
.player em{display:block; font-family:var(--font-display); font-style:normal;
  font-weight:700; font-size:21px; line-height:1.05; color:#C9A84C;
  margin:2px 0 12px}
/* ⭐ TWO VOICES, VISIBLY: the quote is theirs and italic, the answer is ours
   and roman (Part 4). ⛔ Under fifteen words each — the photograph does the
   recognising, the words only confirm it. */
.player .said{margin:0 0 10px; font-size:18px; line-height:1.6;
  font-style:italic; color:var(--paper)}
.player .ans{margin:0; font-size:16px; line-height:1.65; color:var(--muted)}
.players-cta{margin:26px 0 0}
@media (max-width:900px){ .players{grid-template-columns:repeat(2,1fr)} }
@media (max-width:560px){ .players{grid-template-columns:1fr} }

/* ---------- the play it out picture ------------------------------------- */
/* ⭐ IT IS 2146x733 — nearly 3:1 — so it needs the full measure and nothing
   beside it. ⛔ No caption: the plate carries its own three headings, and a
   caption under a picture that already says 1 · 2 · 3 is the page explaining
   its own art. */
/* ⭐⭐ IT BREAKS OUT OF THE READING MEASURE, and that is a legibility
   decision rather than a design one. The strip is 2146x733; inside the
   1072px wrap it renders at half size, which puts the words baked into it —
   Tiger's line, the four names, POT $34 — at 10 to 12 CSS pixels, two
   sections under a block whose whole claim is `18px minimum instructional
   text`. ⛔ A picture is not exempt from the floor just because no guard can
   measure inside it.
   ⚠️ 96vw, NOT 100vw: a viewport-width child inside a centred column sits
   under the scrollbar and the page then scrolls sideways. And index.html has
   no nav rail, so — unlike about.html's photo strip — there is no `--fs-nav-w`
   to subtract. */
.pio-art{margin:30px 0 0; width:min(1600px, 96vw);
  margin-left:calc(50% - min(800px, 48vw))}
.pio-art img{display:block; width:100%; height:auto; border-radius:14px;
  border:1px solid var(--rule)}

/* ---------- easy on the eyes ------------------------------------------- */
/* ⭐⭐ THE ONE CLAIM ON THIS PAGE A READER CAN CHECK WITHOUT TRUSTING US.
   Every other section asks them to believe something about teaching. This one
   is two pictures of type, side by side, and the difference is visible before
   a word of the caption is read -- which is why the pictures are larger than
   the words and the words are a caption rather than an argument. */
.eyes{margin:44px 0 0; padding-top:34px; border-top:1px solid var(--rule)}
.eyes > h3{margin:0 0 6px; font-family:var(--font-display); font-weight:700;
  font-size:clamp(24px,3vw,34px); line-height:1.1; color:var(--paper);
  text-wrap:balance}
.eyes-pair{display:grid; grid-template-columns:1fr 1fr; gap:20px;
  margin:22px 0 0; align-items:start}
.eyes-pair figure{margin:0}
/* ⚠️ THE LABEL IS TWO FACTS AND THEY ARE NOT THE SAME KIND OF THING -- who
   this is, then what its type measures. Stacked, so neither reads as a
   subtitle of the other. */
/* ⭐ D472 (Eric, 14 Oct): 13px -> 18px, the D303 floor. Scoped to THIS block
   only; whether D303 covers eyebrow labels site-wide is Eric's, still open. */
.eyes-pair .who{display:block; font:700 18px/1.3 ui-monospace,monospace;
  letter-spacing:.11em; text-transform:uppercase; color:var(--muted)}
.eyes-pair .ours .who{color:#C9A84C}
.eyes-pair .px{display:block; margin:5px 0 12px; font-size:19px;
  line-height:1.4; color:var(--paper); font-weight:600}
.eyes-pair img{display:block; width:100%; height:auto; border-radius:12px;
  border:1px solid var(--rule)}
.eyes-pair .ours img{border-color:rgba(91,233,192,.45)}
/* ⭐ THE STRONG LINE IS ERIC'S, WORD FOR WORD, and it is the only sentence
   in the block. ⛔ Nothing under it: a second sentence would turn a
   demonstration back into a claim.
   ⚠️ REPLACED 2026-09-11, also his, also verbatim: "See the difference? We
   designed Felt Shark to be comfortable to read." The 8 September line listed
   the four things we did (50% larger type, contrast, controls, comfort); this
   one asks the reader to look at the two pictures instead. ⛔ Do not restore
   the old sentence as "the verbatim one" — both were, and this is the later. */
/* ⭐⭐ WHY FELT SHARK IS DIFFERENT — Eric, 2026-09-11. Three cards, one line
   each, high on the page: "we want to move the idea of SharkSense, SharkBait
   and Play it out UP in the page. Right after The Problem/Ten Leaks and BEFORE
   Learn->Play->Prove."
   ⛔ The three ideas exist ONCE on this page now. He was asked directly what
   happened to the long blocks that used to carry them inside #product and
   answered "Move them up — nothing stays behind." */
.diff-cards{list-style:none; margin:26px 0 0; padding:0; display:grid;
  grid-template-columns:repeat(3,1fr); gap:22px}
.diff-cards li{margin:0; display:flex; flex-direction:column; gap:10px}
/* ⭐ THE PICTURE IS THE CARD'S SUBJECT, so it sits on a felt-dark plate with a
   fixed aspect — three marks of different native shapes in a row read as three
   unrelated blocks otherwise, which is the subgrid lesson from the villain
   cards one section down. */
.diff-shot{margin:0; background:rgba(3,12,18,.55);
  border:1px solid var(--rule); border-radius:12px; padding:14px;
  display:flex; align-items:center; justify-content:center; min-height:132px}
.diff-shot img{display:block; width:100%; height:auto; max-height:150px;
  object-fit:contain}
.diff-cards h3{margin:0; font-family:var(--font-display); font-weight:700;
  font-size:clamp(19px,1.7vw,23px) !important; line-height:1.25;
  letter-spacing:.01em; color:var(--paper)}
/* ⛔ `!important` ON BOTH SIZES BECAUSE THE 18px FLOOR IS A FLOOR, NOT A CAP —
   defect #43, Eric: "18px is NOT a ceiling. It is a MIN only." An element the
   design deliberately sets above 18 carries the marker in its OWN rule, where
   the number already lives. The h3 would otherwise be flattened to 18px and the
   card line, being a <p>, is held AT 18 by the floor, which is correct. */
/* ⭐ THE TWO DOORS, beneath the control. Smaller than the lede but NOT below
   the 18px floor — our reader is seventy-eight and this line is a routing
   instruction, not decoration. No `!important` is needed: it is a <p>, so the
   floor already holds it at 18.
   ⚠️ AND THE WORD `!important` IS WHY THIS COMMENT WAS BROKEN ONCE — it was
   written through a shell string, where `!` is history expansion, and bash ate
   it ("line 27: !important: command not found"). CLAUDE.md records the same
   trap three times (backticks eaten writing a CLAUDE.md entry, `\n` collapsed
   in a heredoc, a `\b` becoming a BACKSPACE): write prose with a file tool,
   never through a shell. Fourth instance, fixed the same minute. */
.close-doors{margin:16px 0 0; color:#C9D6D1; max-width:64ch}
.close-doors a{color:var(--paper); text-underline-offset:3px}
.diff-cards p{margin:0; font-size:18px; line-height:1.6; color:#C9D6D1}
@media (max-width:860px){ .diff-cards{grid-template-columns:1fr; gap:26px} }
.eyes-line{margin:24px 0 0; font-family:var(--font-display); font-weight:700;
  /* ⛔⛔ `!important` BECAUSE THE FLOOR WAS CAPPING THIS LINE. It is a <p>, so
     legibility-floor's `body p { font-size: max(18px,1em) !important }` beat
     this clamp and MEASURED 18px where the design asks for 25px at 1280.
     ⚠️ That is defect #43 — Eric: "18px is NOT a ceiling. It is a MIN only.
     Fix the legibility floor. It is acting as a cap." The fix recorded then was
     that the elements deliberately set ABOVE 18 carry `!important` in their OWN
     rule, where the number already lives; six were listed and this is a
     SEVENTH that was missed, so the section's punchline sentence rendered at
     the floor. ⛔ No size is restated in the floor. */
  font-size:clamp(19px,2.2vw,25px) !important; line-height:1.35;
  color:var(--paper); text-wrap:balance}
@media (max-width:640px){ .eyes-pair{grid-template-columns:1fr; gap:26px} }

/* ---------- the two numbers --------------------------------------------- */
.numbers{background:var(--panel); border:1px solid var(--rule); border-radius:18px;
  padding:clamp(28px,4.4vw,48px)}
.numbers ol{list-style:none; counter-reset:q; margin:0 0 24px; padding:0; display:grid; gap:14px}
/* ⛔⛔ EVERY INLINE CHILD OF A GRID IS ITS OWN GRID ITEM.
   `.numbers li` is a grid, so `<li>Of those, ... <strong>RAISE</strong>?</li>`
   produced FOUR items: the ::before counter, the run of text, the <strong>,
   and the trailing "?". Auto-flow put <strong> in the 38px NUMBER column on
   a second row — which is why the word the question is about appeared alone,
   bolded, under the list. It looked like a text orphan and no amount of
   nowrap could fix it, because nothing was wrapping.
   ⭐ .q IS ONE ITEM CONTAINING THE WHOLE SENTENCE, so <strong> is back in
   normal inline flow where it belongs. */
.numbers li > .q{grid-column:2}
.numbers li{counter-increment:q; display:grid; grid-template-columns:38px 1fr;
  gap:14px; align-items:baseline; font-size:clamp(17px,2.1vw,20px)}
.numbers li::before{content:counter(q) "."; color:var(--accent); font-weight:700;
  font-variant-numeric:tabular-nums}
/* ===== G4 · THE TWO NUMBERS — HOMEPAGE_GRAPHICS_v8 Part 1 =================
   ⛔ Colour is never the only carrier: every bar has a word label and a
   percentage, and the gap is stated as a sentence underneath. */
/* ⛔⛔ THE PLACEHOLDER FLOOR — defect #24, and it caught this page too.
   Chrome fills an unstyled ::placeholder with rgb(117,117,117), which on the
   G4 inputs' #0B1113 field measures 4.13:1 against a 4.5 floor. Not styled
   wrong; not styled at all — which cannot be grepped for, only measured.
   ⚠️ The app's copy of this rule lives in css/legibility-floor.css, and this
   page deliberately links NO stylesheet: it is the LCP page and a blocking
   request for one rule is a worse trade than a repeated literal. ⭐ The guard
   is measurement, not comparison — _placeholder-contrast.html reads the
   COMPUTED colour on every page in the manifest, so a drift here fails a
   test whatever the source says. */
::placeholder{color:rgb(138,148,144); opacity:1}
/* ⚠️ opacity:1 is not decoration: Firefox dims placeholders by default, so a
   colour-only fix does not hold in the browser it was not measured in. */
.tn-ask{display:grid; gap:18px; margin:0 0 24px}
.tn-q{display:grid; grid-template-columns:1fr auto; gap:16px;
  align-items:center; font-size:clamp(17px,2.1vw,20px)}
/* ⚠️ 56pt floor, and on the INPUT — a label a thumb cannot hit is not a
   control. index.html's own .btn floor is 56px; this matches it. */
.tn-q input{min-height:56px; width:92px; padding:0 14px; font:inherit;
  font-family:var(--font-display); font-size:24px; font-weight:700;
  text-align:center; color:var(--paper); background:#0B1113;
  border:2px solid var(--rule); border-radius:10px}
.tn-q input:focus-visible{outline:3px solid #fff; outline-offset:2px}
.tn-out{margin:0; outline:none}
.tn-out:focus-visible{outline:3px solid #fff; outline-offset:4px}
.tn-bars{display:grid; gap:12px; margin:0 0 20px}
.tn-row{display:grid; grid-template-columns:110px 1fr 56px; gap:14px;
  align-items:center; font-size:16px}
.tn-label{font-family:var(--font-display); font-weight:700; letter-spacing:.02em}
.tn-track{display:block; height:22px; background:rgba(255,255,255,.08);
  border-radius:6px; overflow:hidden}
.tn-fill{display:block; height:100%; border-radius:6px}
/* ⭐ the gap row is hatched as well as coloured — the third signal, after
   the word "The gap" and the percentage. */
.tn-gapfill{background-image:repeating-linear-gradient(45deg,
  rgba(0,0,0,.28) 0 6px, rgba(0,0,0,0) 6px 12px)}
.tn-num{font-variant-numeric:tabular-nums; font-weight:700; text-align:right}
.tn-said{font-size:clamp(17px,2.1vw,20px); line-height:1.6; margin:0 0 24px;
  text-wrap:balance}
.limp-table{margin:26px 0 30px; padding:0}
/* ⛔ height:auto pairs with the width/height attributes, or the
   attribute height wins over the natural ratio — the same trap the
   audience strip hit. */
.limp-table img{display:block; width:100%; height:auto; max-width:858px;
  margin:0 auto; border-radius:14px}
/* ⭐ 18px, not 16. This is a sentence a reader reads, not a chart label,
   so item 60's floor applies to it — _typography-audit caught it. */
.limp-table .lt-cap{margin:14px auto 0; max-width:858px; color:var(--muted);
  font-size:18px; line-height:1.6; text-wrap:balance}
@media (max-width:520px){
  .tn-q{grid-template-columns:1fr; justify-items:start; gap:10px}
  .tn-row{grid-template-columns:96px 1fr 48px; gap:10px}
}
.numbers .so{margin:0 0 14px; color:#D5DBDD; max-width:58ch}
.numbers .fix{margin:0 0 14px; color:var(--paper); font-weight:700; max-width:58ch}

/* ---------- the plan ----------------------------------------------------- */
/* ⭐ §4 — "a numbered plan removes the fear that this will be complicated.
   That is its entire job." ⛔ Three steps. Never four. */
.plan{display:grid; grid-template-columns:repeat(auto-fit,minmax(262px,1fr)); gap:24px;
  counter-reset:p}
/* ⚠️ FLEX COLUMN SO THE THREE PICTURES SHARE A TOP EDGE. LEARN's line
   is one line, PLAY's is two and PROVE's is three, so the images began
   at three different heights — the same "a plan that looks unplanned"
   the equal aspect-ratio was chosen to avoid, arriving through the copy
   instead of the pictures. `margin-top:auto` on the shot pins it to the
   bottom of its step whatever the sentence does next. */
.step{counter-increment:p; display:flex; flex-direction:column}
.step::before{content:counter(p); display:flex; align-items:center; justify-content:center;
  width:42px; height:42px; border-radius:50%; background:var(--accent);
  color:var(--accent-ink); font-weight:700; font-size:18px; margin-bottom:15px}
.step h3{margin:0 0 7px; font-size:14px; letter-spacing:.13em; text-transform:uppercase}
.step p{margin:0 0 16px; color:var(--muted); font-size:15.5px}

/* ⭐⭐ ONE REAL SCREENSHOT PER STEP — MSC W11 / HOMEPAGE_GRAPHICS_v8 G5.
   ⛔ §3: REAL SCREENS, NOT MOCK-UPS, and cropped to the content — no phone
   bezels, no browser chrome. tools/shoot_how_it_works.mjs takes an ELEMENT
   screenshot of the running app and REFUSES to write a file if it could not
   drive itself to the right screen, which is why there are three or none.
   ⚠️⚠️ NO FORCED ASPECT, AND THAT IS THE THIRD ANSWER TO ONE QUESTION.
   The three surfaces are genuinely different shapes — MEASURED at 2194x930,
   1716x1720 and 1292x540, so 2.36 : 1.00 : 2.39. A shared 16:10 box with
   `cover` cuts Tiger and his question off LEARN and the action row off PLAY;
   the same box with `contain` puts a small square in a wide frame and gives
   every card black bars. ⛔ Both trade the pictures for the grid, and the
   pictures are the reason the row exists.
   ⭐ So each keeps its own shape and `margin-top:auto` pushes it to the foot
   of its step: the grid already stretches the three cards to a common height,
   so the images share a BOTTOM edge. That reads as deliberate, which unequal
   tops did not — LEARN's sentence is one line, PLAY's two and PROVE's three,
   and the first cut had the pictures starting at three different heights. */
.step .shot{margin:0 0 4px; margin-top:auto}
.step .shot img{display:block; width:100%; height:auto;
  border-radius:12px; border:1px solid var(--rule); background:#0b1a17}
/* ⭐ D519: the PROVE card -- the cropped teeth picture on top, Eric's sentence as
   live text beneath, ONE card. The picture's own edge and ground are continued
   by the caption (colours sampled from how-prove.png); the picture loses its
   bottom border and radius so the two read as one. 18px floor on the text. */
.step .sb-card{border:1px solid rgb(27,27,25); border-radius:12px; background:rgb(10,9,8); overflow:hidden}
.step .sb-card img{border:0; border-radius:0; background:rgb(10,9,8)}
.sb-card-say{margin:0; padding:.25rem 6.5% 1.4rem; color:rgb(138,148,144);
  font-family:var(--font-body); font-size:clamp(18px,1.6cqw,26px); line-height:1.45}

/* ---------- without this ------------------------------------------------- */
/* ⛔ FOUR LINES MAXIMUM. §5: "this section can turn nasty if it runs long." */
/* ⛔ `.without` went with its section (Eric, 3 Sep — the third copy of the
   StoryBrand stakes device). Dead CSS is drift with a longer fuse. */

/* ---------- the ocean bands ---------------------------------------------- */
.band{position:relative; min-height:clamp(330px,44vw,450px); display:flex;
  align-items:flex-end; overflow:hidden}
.band::before{content:''; position:absolute; inset:0;
  background-image:var(--band-bg); background-size:cover; background-position:center}
.band::after{content:''; position:absolute; inset:0;
  background:linear-gradient(180deg,rgba(10,10,10,.55) 0%,rgba(10,10,10,.18) 38%,rgba(10,10,10,.93) 100%)}
.band .wrap{position:relative; z-index:2; padding-bottom:clamp(26px,4vw,50px);
  padding-top:clamp(50px,7vw,90px)}
.band h3{margin:0 0 8px; font-size:clamp(22px,3vw,32px); letter-spacing:-.01em}
.band .lv{margin:0 0 10px; font-size:13px; letter-spacing:.16em;
  text-transform:uppercase; color:var(--accent); font-weight:700}
.band p{margin:0; max-width:46ch; color:#D5DBDD}

/* ---------- founding story ----------------------------------------------- */
.founder{margin:0 0 34px; padding:0 0 0 22px; border-left:3px solid var(--accent);
  max-width:52ch}
.founder p{margin:0 0 14px; font-size:clamp(19px,2.3vw,23px); line-height:1.6;
  letter-spacing:-.01em}
.founder cite{display:block; margin-top:4px; font-style:normal; font-size:15px;
  color:var(--muted)}
/* ⭐⭐ §6 — the PHILOSOPHICAL problem, the strongest and previously unused
   angle. It gives the visitor something to AGREE with, and agreement is
   stickier than persuasion. */
.philosophy{max-width:54ch}
.philosophy p{margin:0 0 12px; font-size:clamp(18px,2.2vw,22px); line-height:1.6}
.philosophy strong{color:var(--accent)}

/* ---------- closing + footer --------------------------------------------- */
.closing{padding:clamp(64px,8.5vw,110px) 0; text-align:center;
  background:linear-gradient(180deg,#0B1418,#0A0A0A)}
.closing .lede{margin:0 auto 30px; text-align:center}
.closing .cta-row{justify-content:center}
footer{background:#080A0B; border-top:1px solid var(--rule);
  padding:clamp(46px,6vw,70px) 0 40px; font-size:15px}
.fcols{display:grid; grid-template-columns:1.4fr repeat(3,1fr); gap:34px; margin-bottom:38px}
.fcols h4{margin:0 0 14px; font-size:12.5px; letter-spacing:.16em;
  text-transform:uppercase; color:var(--muted)}
.fcols ul{list-style:none; margin:0; padding:0; display:grid; gap:9px}
.fcols a{color:#C3CBCE; text-decoration:none}
.fcols a:hover{color:var(--paper)}
.legal{color:var(--muted); font-size:14px; max-width:70ch; margin:0 0 14px}
.copy{color:var(--muted); font-size:14px; margin:0}

@media (max-width:860px){
  /* ⛔ `.hero{padding:102px 0 54px}` WAS HERE AND COULD NOT APPLY — 2026-10-02.
     It cleared the fixed header for the OLD hero. The new hero's own rule is
     declared later in this stylesheet at equal specificity, so document order
     decided and this one lost: MEASURED computed `padding-top: 0px` at 1440x900
     AND at 390x844. Header clearance is `--hdr-h` now, in one place.
     ⚠️ A declaration that can never take effect reads exactly like a working
     one — ninth member of that family in CLAUDE.md. */
  /* ⛔ the phone scrim went with the desktop one — see the note at `.hero` */
  .nav{display:none}
  .fcols{grid-template-columns:1fr 1fr; gap:26px}
  .cta-row .btn{flex:1 1 100%}
}

/* ==========================================================================
   ⛔ NO ORPHANS — Eric, 2026-08-25: "do an audit for ALL orphans and eliminate
   them."

   An orphan is a single word stranded on the last line of a paragraph. It
   reads as a mistake, and on a sales page it reads as a careless one.

   ⭐ TWO DIFFERENT PROPERTIES, AND THEY ARE NOT INTERCHANGEABLE:
     · `balance` evens out the lines of SHORT text — right for headings, and
       every engine caps it at a few lines, so on a paragraph it quietly does
       nothing at all.
     · `pretty` reflows the LAST few lines specifically to avoid an orphan —
       that is the one this is about, and it is right for body copy.

   Both degrade to ordinary wrapping where unsupported, so the worst case is
   the behaviour we already had.
   ========================================================================== */
h1, h2, h3, h4, .eyebrow, .player h3, .step h3, blockquote {
  text-wrap: balance;
}
p, li, .lede, figcaption, .sub, .hint, .tcoach, .wbw-tiger, dd {
  text-wrap: pretty;
}

/* ⚠️ `pretty` IS NOT ENOUGH IN A NARROW COLUMN, AND THESE ARE NARROW.
   The "Confused" card on the home page is 210px wide. text-wrap:pretty
   reflows the last few lines to avoid an orphan, but with only three or four
   words per line it has almost nothing to trade, and the paragraph still
   ended on a line reading just "hand." at 1440 and 1280.

   ⛔ A NON-BREAKING SPACE DOES NOT FIX IT EITHER, and that is worth
   recording because it is the obvious move. Measured: with U+00A0 between
   "second-best" and "hand." (verified as char code 160 in the DOM) Chrome
   still broke the line there in a 210px box. `balance` fixed it in the same
   measurement -- last line came back as "second-best hand.".

   ⭐ balance over pretty for SHORT blocks in NARROW boxes: it evens the
   lines out across the whole paragraph rather than only reflowing the tail. */
blockquote.founder p,
.lk-cost {
  text-wrap: balance;
}

/* ⭐⭐ D497 (ii): ON A PHONE, A HEADING FILLS ITS LINE — the same rule as
   typography.css (this page carries its own copy of those rules and does not load
   that file). MEASURED 15 Oct at 390: "Your next leak isn't going to fix itself."
   balanced to 230 / 213px in a 350px box (14.1ch) and the founder's "For 25
   years…" to 179 / 210px (18.8ch), against check_text_measure's 20ch floor.
   `pretty` keeps the no-lone-last-word point of `balance`. A px query on purpose: a
   rem query would move with the reader's text size. */
@media (max-width: 480px) {
  h1, h2, h3, h4, .eyebrow, .player h3, .step h3, blockquote, .eyes > h3,
  blockquote.founder p, .lk-cost, .tn-said, .limp-table .lt-cap {
    text-wrap: pretty;
  }
}



  /* ---- the ten leaks, as a map ---------------------------------------- */
  /* ===== THE TEN, GROUPED BY STREET — TEN_LEAKS_VISUAL_v8 ===============
     ⭐ Part 2: "the ten are ordered by street, so draw them as a journey
     through a hand." Each group gets a heading rule; the cards are three
     across with the picture on top.
     ⛔ Part 5: nothing flips, expands or scrolls sideways — they see all ten
     at once. */
  .streets { margin:26px 0 30px; }
  /* ⛔ THE FOUR STREET HEADINGS ARE GONE, AND THE STREET IS ON EACH CARD.
     Eric, 2026-09-01: "do the strict 1-2 / 3-4 pairing." Four separate grids
     could not produce it -- preflop held three leaks, so leak 3 sat alone and
     leak 4 started a new grid. One grid of ten in numeric order gives the
     pairing he asked for.
     ⚠️ TEN_LEAKS_VISUAL_v8 Part 1 says the ten are ordered BY STREET, "a
     journey through a hand", and that is not lost: the street is a tag on
     every card, read from leaks.js rather than typed, so a reader still sees
     preflop-preflop-preflop-flop as they go down. What changes is that the
     descent is carried by the cards instead of by four headings. */
  .lk-st { display:block; margin-bottom:6px; font-style:normal;
    font-family:var(--font-display,system-ui); font-size:14px;
    letter-spacing:.14em; text-transform:uppercase; color:#8FB8AF; }
  /* ⛔ TWO ACROSS, NOT THREE. Eric, 2026-08-31: "these scenarios have cards
     that are TOO SMALL. Too much green space, not enough CARDs... If you need
     to do 2 across to make them bigger, that's fine."
     Three columns showed each table at 346px; two shows it at 580px, and the
     stills were re-shot at 1160 wide so that is still 2x on a retina screen.
     ⚠️ THE STREET GROUPING STAYS. TEN_LEAKS_VISUAL_v8 Part 1 is that the ten
     are ordered BY STREET -- "draw them as a journey through a hand" -- so
     preflop keeps 1-2-3 together rather than splitting 3 away from its
     street to make an even pair. The rows that hold three leaks run 2 then 1,
     which is what .lk-pad already exists for. */
  .lks { display:grid; grid-template-columns:repeat(2,1fr); gap:18px; }
  .lk { position:relative; margin:0; border-radius:12px; overflow:hidden;
    background:#0E1A17; border:1px solid rgba(255,255,255,.10); }
  /* the draft pads a short row with an empty, borderless cell */
  .lk-pad { background:transparent; border:0; }
  /* ⚠️ 720/521 IS THE CAPTURE’S OWN SHAPE, not a design choice.
     This was 16/10 with object-fit:cover, which is fine while the export
     is 16/10 and silently CROPS the moment it is not — and what it
     crops off a photograph of a poker table is the seats. The stills are
     shot from play/pup-tank-layout.html now (tools/shoot_leaks_puptank.mjs)
     and come out 2180x1578. Re-measure this if the shooter’s viewport
     changes; check_scenarios asserts the files exist, not their shape. */
  .lk img { display:block; width:100%; height:auto; aspect-ratio:720/521;
    object-fit:cover; }
  /* ⭐⭐ Part 3: "PEOPLE WILL COUNT THEM. Make it effortless." 44px, brass,
     display face, and the numeral sits ON the picture — not beside the text,
     not grey, not 14px. */
  .lk-n { position:absolute; left:14px; top:10px;
    font-family:var(--font-display,system-ui); font-weight:700;
    font-size:44px; line-height:1; color:#C9A84C;
    font-variant-numeric:tabular-nums;
    text-shadow:0 2px 10px rgba(0,0,0,.75); pointer-events:none; }
  .lk-t { padding:14px 16px 16px; }
  /* ⛔ the label is one line, never wrapped (Part 3) */
  .lk-t b { display:block; font-family:var(--font-display,system-ui);
    font-size:17px; line-height:1.2; color:var(--paper,#F4F6F5);
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  /* the consequence is the second line, smaller and grey */
  .lk-t span { display:block; margin-top:5px; font-size:15px; line-height:1.4;
    color:var(--muted,#8A9490); }
  @media (max-width:820px){ .lk-pad { display:none; } .lk-n { font-size:38px; } }
  @media (max-width:520px){ .lks { grid-template-columns:1fr; } }
  .leak-note { max-width:44rem; color:var(--muted,#8A9490); font-size:16px;
    line-height:1.65; border-left:2px solid rgba(255,255,255,.14);
    padding-left:16px; margin:0 0 22px; }
  .leak-note strong { color:var(--paper,#F4F6F5); }

  /* ---- who made this --------------------------------------------------- */
  .who-pull { font-size:clamp(22px,2.6vw,30px) !important; line-height:1.35; margin:18px 0;
    color:var(--paper,#F4F6F5); max-width:38rem; }
  .who-pull em { font-style:italic; }
  .who-regs { margin-top:30px; padding:20px 22px; border-radius:10px;
    background:rgba(255,255,255,.035); border:1px solid rgba(255,255,255,.09);
    max-width:46rem; }
  .who-regs p { margin:0 0 12px; line-height:1.65; color:var(--muted,#8A9490); }
  .who-regs p:last-child { margin-bottom:0; }
  .who-regs strong { color:var(--paper,#F4F6F5); }

  /* ---- price ----------------------------------------------------------- */
  .price-row { display:grid; gap:14px; margin:26px 0 20px;
    grid-template-columns:repeat(auto-fit,minmax(230px,1fr)); }
  .price-card { padding:20px; border-radius:12px;
    border:1px solid rgba(255,255,255,.11); background:rgba(255,255,255,.03); }
  .price-name { margin:0 0 10px; font-size:13px; letter-spacing:.1em;
    text-transform:uppercase; color:var(--muted,#8A9490); }
  /* ⭐ THE PRICE ON THE BAND — Chatty via Eric, 2026-09-08:
     ⛔ AND IT IS NOT `.price-fig`. That class is in legibility-floor.css's
     `!important` list, where the rule is `font-size: max(18px, 1em)` -- a
     MINIMUM. With 1em inheriting 18px the max resolves to 18px and clamped
     the price to the floor: measured 18px where the rule said 28.
     ⚠️ The floor is doing its job; the mistake was reusing a class that opts
     into it for type that is deliberately larger.  the numbers moved
     off a separate section onto the three level cards, where the reader is
     already looking at the thing being priced.
     ⚠️ IT LIVES HERE, NOT IN css/home.css. index.html carries its own
     <style id="ss-home-css"> and does not link that file -- I appended the
     rule there first and measured the prices still at 18px, the legibility
     floor, with the rule sitting in a stylesheet the page never loads. */
  .band .band-price { margin:0 0 10px; font-size:28px !important; font-weight:700;
    line-height:1; color:var(--paper); }
  /* ⭐ 18px, NOT 15 — Eric, 2026-10-04: *"'once' and the year label both go to
     18px. No exemption applies to either."* Measured at 15px before: under the
     floor, at contrast 6.09:1, which is ABOVE the 4.5 bar — so it was a SIZE
     defect and not a contrast one, and raising the size is the whole fix.
     ⚠️ The parent `<p>` was already clamped to 18 by `legibility-floor.css`;
     a `<span>` inside it is not a `body p`, which is why this one sat under
     the floor while the paragraph around it did not. */
  .band .band-price span { font-size:18px; font-weight:400; color:var(--muted); }
  /* ⛔⛔ `.band-year` IS GONE — Eric, 2026-10-04, ruling 5: *"REMOVE the year
     label from both homepage bands. It returns on the paywall when the paywall
     is real and something can be bought."* ⭐ The MECHANISM stays built:
     `var YEAR` in js/pricing-copy.js and its `[data-price-year]` painter are
     untouched, so the label has one home and no surface. P8b is BUILT BUT
     UNPLACED — see D233.
     ⚠️ THE MEASUREMENT BEHIND THE RULING: the year rendered on exactly two
     surfaces, both of them bands that say "Being built now. Not on sale yet."
     and where `canEnter(3)` returns `sellable:false` — and it was ABSENT from
     `play/paywall.html`, the surface P8b ruled it for. Inverted from the
     ruling.
     ⛔ The rule is REMOVED rather than left unused, which is the precedent the
     `.band-vat` note below sets: a selector nothing matches is the next
     person's evidence that a thing is still policy. */
  /* ⛔ `.band-vat` IS GONE — Eric, 2026-10-03 20:08, withdrawing the qualifier
     itself. The rule is removed rather than left unused: a selector nothing
     matches is the next person's evidence that a thing is still policy. */
  .price-fig { margin:0 0 12px; font-size:34px; font-weight:700; line-height:1;
    color:var(--paper,#F4F6F5); font-variant-numeric:tabular-nums; }
  .price-fig span { font-size:15px; font-weight:400; color:var(--muted,#8A9490); }
  .price-what { margin:0; font-size:15px; line-height:1.6;
    color:var(--muted,#8A9490); }
  .price-note { max-width:44rem; }

  /* ⭐⭐⭐ THE TRANSACTION-TRUTH BLOCK — 210 PART 00B, ERIC 3 Oct, overruling
     his own earlier placement: *"BUILD IT NOW. It does not wait on Part 00.
     Part 00 defers the PAYWALL build. This block is homepage information with
     no destination, which is ruled option (b), and every remaining row is true
     today."*
     ⛔ THREE ROWS. "Do not add a fourth. The paywall version gets more rows
     later." ⚠️ The fourth row was `What you pay today ………… $197` and Eric
     dropped it himself: nothing in #levels is purchasable, both paid bands say
     "Not on sale yet", and `canEnter(3)` returns `sellable:false`, so it was
     false. *"The headline carries 2027 PRICE: $197 as a LISTED price, which is
     true of something not yet for sale."*
     ⛔⛔ STATIC MARKUP: a disclosure that disappears when a script fails is
     worse than one a guard keeps in step. `js/pricing-copy.js` holds the
     authority as `TRANSACTION_TRUTH` and `check_transaction_truth` asserts
     these rows against it, label and value, in order — so there is one home and
     a guard between it and this copy.
     ⚠️ THE VAT ROW IS THE ONE VAT SENTENCE THAT SURVIVED 3 Oct 20:08. Eric
     withdrew the ex-VAT qualifier from the priced bands and kept this: "That is
     not a price qualifier, it is a statement of mechanism, and it says exactly
     what Eric said." So this row must not be read as the qualifier returning.
     ⭐ THE LEADER IS DRAWN, NOT TYPED. Eric's "…………" is a visual rule; as
     characters a screen reader announces three ellipses per row, and a `<dl>`
     already pairs a term with its value without them. It is a dotted border on
     `dt::after`, which has no text content to announce.
     ⚠️ `<div>` wrapping each `dt`/`dd` pair is valid inside `<dl>` and is what
     lets a row be one flex line. */
  .truth { margin:0 0 26px; max-width:44rem; font-size:18px; line-height:1.6; }
  .truth > div { display:flex; align-items:baseline; gap:10px; padding:5px 0; }
  .truth dt { flex:1 1 auto; display:flex; align-items:baseline; gap:12px;
    margin:0; color:var(--muted); min-width:0; }
  .truth dt::after { content:""; flex:1 1 auto;
    border-bottom:2px dotted var(--rule); position:relative; top:-.3em; }
  .truth dd { flex:0 0 auto; margin:0; color:var(--paper); font-weight:700;
    font-variant-numeric:tabular-nums; }

  /* the band is an SVG that scales; the figure just gives it room */
  /* ⭐ THE SHARKSENSE MARK — Eric, 29 Aug. Replaces a typed eyebrow with the
     official artwork; the byline is part of the mark. */
  /* ⛔⛔ THE AIR GOES ABOVE THE MARK, NOT BELOW IT. Eric, 4 Sep: "the space
     under SharkSense should move ABOVE SharkSense so there is SPACE under the
     words 'Four of them have a habit...'".
     ⭐ Measured at 1280 first: margin-top was 0, so the mark sat straight
     under the paragraph above it, while the 88px beneath it was the H2's own
     margin-top — the "2-3 lines before a major heading" rule Eric set. That
     88px is not the mark's to give back.
     ⚠️ What the mark owns is its 18px bottom, redundant beside an 88px
     heading gap. So it gives that up and takes room above instead. */
  /* ⚠️ ZERO ABOVE, BECAUSE THE EYEBROW NOW SUPPLIES IT. The mark briefly
     carried clamp(32px,4.5vw,64px) when nothing sat above it; with "The tools
     that help you" and its 20px below, keeping both would stack ~78px between
     a label and the thing it labels. ⭐ Same reasoning as the sheet's own
     `.eyebrow + h2 { margin-top:0 }`. */
  .ss-mark{margin:0}
  .ss-mark img{display:block; width:min(620px, 88%); height:auto;
    max-width:100%}
  @media (max-width:700px){ .ss-mark img{width:88%} }
  #sharksense .ss-figure { margin:28px 0 22px; }
  /* ⭐ THREE FRAMES — the Murk widening and then closing. Stacked, because
     the argument is a sequence and a row of three would be read as three
     options rather than three moments. */
  #sharksense /* ⛔⛔ THE CAPTION READ AS A HEADING FOR THE BAND BELOW IT.
     Eric, 2026-09-02: "this is out of order!" The markup was already right --
     each <figure> holds its own level, band and caption -- but MEASURED, the
     caption sat 10px under its own band and only 22px above the NEXT level
     label, and both are small, uppercase and letter-spaced. At a glance it
     looked like the heading of what followed.
     ⭐ Two changes, and the second matters more than the first: 48px between
     figures so the group is unambiguous, and the caption is no longer
     uppercase, so it cannot be mistaken for a label. A group is only a group
     when the space inside it is smaller than the space around it AND the
     parts do not look alike. */
  .ss-frames { display:grid; gap:48px; margin:24px 0 22px;
    max-width:860px; }
  /* ⭐ §1e.3 SPLITS THE THREE FRAMES 1 + 2 so the surprise can sit between
     them. ⚠️ The margins collapse toward the claim rather than sitting
     symmetrically around it: the Level 1 frame belongs to what came before,
     the claim introduces the two that follow. Equal space would make the
     claim read as a caption for whichever frame the eye lands on — the same
     defect §1e.4 describes for the eyebrows. */
  .ss-frames-one { margin-bottom:34px; }
  .ss-frames-two { margin-top:14px; }
  /* ⭐ THE SIZE OF `.lede`, WHICH IS THE SENTENCE DIRECTLY BELOW IT —
     Eric: "larger text like the next sentence". Not a new size invented for
     one caption. ⚠️ The margin moves to the BOTTOM now that the caption sits
     above the band it describes. */
  #sharksense .ss-frames figcaption { text-transform:none; letter-spacing:0;
    font-size:18px; line-height:1.5; margin:0 0 12px; color:#9FB3AE; }
  #sharksense .ss-frames .ss-figure { margin:0; }
  /* ⭐ TWO SIZES LARGER — Eric: "the LEVEL x fonts ... are hard to see."
     ⚠️ 12px of brass letter-spaced uppercase on near-black is under the
     comfortable floor for the reader ACCESSIBILITY_v8 keeps naming: an
     85-year-old on a five-year-old phone. */
  #sharksense .ss-lv { margin:0 0 8px; font-family:var(--font-display,system-ui);
    font-size:16px; letter-spacing:.15em; text-transform:uppercase;
    color:#C9A84C; }
  /* ⭐ THE ANTI-RÉSUMÉ. ⚠️ ACCESSIBILITY_v8: this is a table of numbers, so
     tabular figures and an 18px floor. ⛔ Same typeface both columns. */
  /* ===== THE ANTI-RÉSUMÉ — ANTI_RESUME_BUILD_v8 =========================
     ⭐ Part 0: show the object, put the number on it. The old version was a
     table of labels and numerals, which is a spreadsheet.
     ⭐ Part 2: the mug is the hinge of the joke and sits between the columns. */
  /* ⛔ THE MIDDLE COLUMN NEEDS A FLOOR. It was `auto`, so the two 1fr columns
     took the room and crushed it: measured 71px at 932x430, which renders the
     mug's caption ELEVEN CHARACTERS wide. TEXT_WRAP_AUDIT_v8 sets a 20ch floor
     on any run of prose, and _screen-walk gates on it.
     ⭐ 150px at the caption's 12.5px is about 24ch, and the 1fr columns absorb
     the difference because that is what fr columns are for. */
  .brag { display:grid; grid-template-columns:1fr minmax(150px,auto) 1fr;
    gap:clamp(20px,3vw,44px); align-items:start; margin:26px 0 18px; }
  .brag-col h3 { margin:0 0 14px; font-family:var(--font-display,system-ui);
    font-size:.82rem; letter-spacing:.16em; text-transform:uppercase;
    color:var(--teal,#22ddbb); }
  /* ⛔⛔ `1fr` IS `minmax(auto, 1fr)`, AND THAT IS THE WHOLE DEFECT.
     Eric, README Part 2, as two findings: "the five zeros — numerals sit at
     different heights" and "labels wrap to different line counts". They are
     ONE bug. `auto` as the minimum means a column cannot be narrower than
     its longest unbreakable content, so TOURNAMENT EARNINGS pushed its own
     column wider than CELEBRITY STATUS's — and `.bo-img` is `width:100%` of
     that column with `aspect-ratio:1/1`, so a wider column draws a TALLER
     square and pushes its numeral further down.
     ⭐ MEASURED at 1440: image boxes 73 · 90 · 77 · 69 · 99 px, and the five
     numerals spread over 29.7px of vertical.
     ⚠️ Same family as `--fs-nav-w` and the dealer's `max()` floor: a
     constraint whose default quietly defeats the value beside it.
     ⭐ minmax(0,1fr) makes the five columns actually equal, which lands the
     images, the numerals AND the captions on one line each. */
  /* ⛔⛔ NOT FIVE ACROSS — THE WORDS DO NOT FIT, AND IT WAS ALL FIVE.
     Measured at 1440: the container is 395px, so five columns plus four gaps
     leave 71px each, while the labels measure 77 · 80 · 81 · 102 · 116px.
     The SHORTEST of them already overflows, centred text spills both ways,
     and the neighbours collide — Eric photographed TOURNAMENT running into
     FOLLOWERS.
     ⚠️ The `minmax(0,1fr)` above me is what exposed this. `minmax(auto,1fr)`
     made the columns unequal (the numeral-height bug); equal columns are
     71px, which is narrower than any label. One defect traded for another.
     ⛔ The words do not change — see the caption rule below, they are five
     specific true claims. ⛔ And the type does not shrink: Sponsorships would
     need ~7px to fit 71, far under the legibility floor.
     ⭐ So the LAYOUT yields. auto-fit at a 112px floor gives three columns of
     ~125px here — wider than the longest word — and the five fall 3 + 2. */
  .bo-row { display:grid; gap:10px 14px;
    grid-template-columns:repeat(auto-fit,minmax(112px,1fr)); }
  .bo { margin:0; text-align:center; }
  .bo-img { display:block; width:100%; height:auto; aspect-ratio:1/1;
    object-fit:contain; border-radius:8px; background:#080C0B; }
  /* ⭐⭐ Part 1: "the zeros are the BIGGEST TYPE in the section." Brass,
     display face. ⛔ NOT greyed out and NOT crossed through — they are not
     sad, they are the joke. */
  .bo-n { display:block; margin:8px 0 2px; font-family:var(--font-display,system-ui);
    font-weight:700; font-size:clamp(34px,4.4vw,54px); line-height:1;
    color:#C9A84C; font-variant-numeric:tabular-nums; }
  /* ⚠️ AND THE LABELS STILL WRAP TO ONE LINE OR TWO — "Followers" against
     "Tournament earnings" — so the five figures ended at a ragged bottom.
     ⛔ THE WORDS ARE NOT THE THING TO CHANGE: they are five specific true
     claims about the founder, and shortening one to make a row line up
     would be typography editing the content. ⭐ Reserve two lines and the
     row is level whichever way each label falls. */
  .bo figcaption { font-size:11.5px; letter-spacing:.07em; text-transform:uppercase;
    color:var(--muted,#8A9490); line-height:1.3; min-height:2.6em; }
  /* the mug, on its own, between them */
  .brag-mug { margin:0; max-width:200px; text-align:center; }
  .mug-img { display:block; width:100%; height:auto; border-radius:10px; }
  .brag-mug figcaption { margin-top:8px; font-size:12.5px; line-height:1.4;
    color:var(--muted,#8A9490); }
  /* ⭐ Part 3: ICONS here, objects on the left — the right side is time and
     people, which cannot be photographed. Brass numerals at the same scale
     as the zeros, so the two columns feel equal in weight. */
  .bh-row { display:grid; gap:14px; }
  .bh { display:grid; grid-template-columns:34px auto 1fr; align-items:center;
    column-gap:14px; }
  .bh-i { width:30px; height:30px; }
  .bh .bo-n { margin:0; font-size:clamp(30px,3.6vw,44px); }
  .bh span { font-size:13px; letter-spacing:.05em; text-transform:uppercase;
    color:var(--muted,#8A9490); line-height:1.3; }
  .brag-punch { font-size:18px; line-height:1.6; color:#9fb3ae; max-width:44rem; }
  .brag-punch strong { color:var(--paper,#F4F6F5); }
  @media (max-width:900px){
    .brag { grid-template-columns:1fr; }
    .brag-mug { max-width:170px; margin:0 auto; }
    .bo-row { grid-template-columns:repeat(5,1fr); gap:6px; }
    .bo figcaption { font-size:10px; }
  }
  @media (max-width:520px){ .bo-row { grid-template-columns:repeat(3,1fr); } }
  #sharksense .ss-band { max-width:860px; }
  /* ⭐ the official art, sized by its own aspect so it never boxes-in */
  #sharksense .ss-band-art { display:block; width:100%; max-width:860px;
    height:auto; margin:0 auto; }
  #sharksense .ss-band svg { display:block; width:100%; height:auto; }
  #sharksense figcaption { margin-top:10px; font-size:14px; letter-spacing:.06em;
    text-transform:uppercase; color:var(--muted,#8A9490); }
  /* ⚠️ A LEGEND, NOT A SECOND INSTRUMENT. At the width of a text column
     the Level 5 band has zones too narrow to carry readable words, and the
     art module correctly drops them rather than printing 7px type. That is
     the right call inside the product and the wrong picture for somebody
     meeting the thing for the first time, so the names go UNDERNEATH —
     where they cannot be squeezed — and the colours tie them to the zones.
     ⛔ The swatch colours come from the module, never re-typed here. */
  #sharksense .ss-key { display:flex; flex-wrap:wrap; gap:6px 22px;
    text-transform:none; letter-spacing:.02em; }
  #sharksense .ss-key span { display:inline-flex; align-items:center; gap:8px; }
  #sharksense .ss-key i { width:14px; height:14px; border-radius:3px;
    flex:0 0 auto; }
  /* ⚠️ the trademark is a mark, not a shout — §10.2 */
  #sharksense .eyebrow { letter-spacing:.12em; }


/* ⭐ SHARK BAIT on the homepage. Brass and vermillion only -- amber is THE
   MURK, and a colour means one thing. */
.sb-web-demo{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));
  gap:24px;margin:26px 0 24px}
.sb-web-one{background:rgba(0,0,0,.32);border:1px solid rgba(201,168,76,.22);
  border-radius:12px;padding:18px 18px 14px}
.sb-web-cap{margin:.7rem 0 0;font-size:.92rem;color:#8A9490;line-height:1.65}
.sb-web-rules{margin:0 0 22px;padding-left:1.1rem;max-width:64ch;line-height:1.7}
.sb-web-rules li{margin-bottom:.5rem}
.sb-web-rules strong{color:#E8F2F0}
/* ⚠️ TOP MARGIN IS LOAD-BEARING HERE. This was `margin:0 0 18px`, so the mark
   sat directly under the previous block's CTA — Eric: "need at least 2-3 blank
   spaces here to separate the green button from the SharkBAIT heading."
   ⭐ 2–3 lines at this size is 56–72px. Same defect the SharkSense mark had
   in the same pass: a block opening with artwork and no air above it. */
.sb-mark{display:block;width:min(420px,78vw);height:auto;
  margin:clamp(56px,6vw,76px) 0 18px}
    /* ⭐ the hero's second line, HOMEPAGE_COPY_v8 Part 1 */
  .h1-sub { display:block; font-size:.62em; font-weight:600; color:var(--muted,#8A9490); }
  /* ⛔ Part 6 rule 1 — the sentence that survives every edit. It is set apart
     so an editor can see it is doing a different job from the paragraph under
     it, and it is never moved below the fold. */
  .sub.protect { font-size:1.12rem; color:var(--paper,#F4F6F5); max-width:40rem; }
  .sub.protect em { font-style:normal; }
  /* ⭐⭐ TWO DOORS — equal columns, and nothing that reads as primary. */
  .doors { display:grid; grid-template-columns:1fr 1fr; gap:20px; }
  .door { padding:22px 24px; border-radius:14px;
    border:1px solid rgba(255,255,255,.12); background:rgba(255,255,255,.03); }
  .door h3 { margin:0 0 12px; font-family:var(--font-display,system-ui);
    font-size:1.15rem; color:var(--paper,#F4F6F5); }
  /* ⚠️ 18px, NOT 16. _typography-audit floors BODY text at 18 and these are
     two paragraphs of reading, not a caption -- APP_STATES_AND_STYLE_v8
     Part 0, our reader is seventy-eight. 16 put the count one over its
     baseline the moment the section landed. */
  .door p { margin:0 0 12px; font-size:18px; line-height:1.6;
    color:var(--muted,#8A9490); }
  .door p:last-child { margin-bottom:0; }
  .door strong { color:var(--paper,#F4F6F5); }
  @media (max-width:720px){ .doors { grid-template-columns:1fr; } }
    /* ⭐ NONE OF THIS IS SECRET / THE STAKES / SUCCESS — three short sections
     that are nothing but sentences, so they are set larger than body copy and
     given room. No card, no border: the words are the whole design. */
  .secret-line, .stakes-line, .success-line {
    max-width:46rem; margin:0 0 16px; font-size:20px; line-height:1.6;
    color:var(--muted,#8A9490); }
  .secret-line strong, .success-line strong { color:var(--paper,#F4F6F5); }
  .stakes-line.em { color:var(--paper,#F4F6F5); font-weight:600; }
  #success .btn { margin-top:10px; }
    /* ⚠️ BALANCE, NOT A NON-BREAKING SPACE. At 390px "knowing what you are
     doing." wrapped and left "doing." alone on its own line -- _orphan-audit
     caught it. A U+00A0 does NOT stop Chrome breaking there (measured on this
     project once already, char code 160 verified in the DOM and the line
     broke anyway); text-wrap:balance does, and it is what headings get. */
  .h2-em { font-style:italic; color:var(--teal,#22ddbb); display:block;
    text-wrap:balance; }
  .players-cta { margin-top:34px; text-align:center; }
  .players-cta .note { margin:14px auto 0; }
    /* ⭐ the six cards: a POSITION on the path, then their own words. §2.0 --
     the photographs provide the demographics, the words provide the poker
     identity. */
  .players figcaption b { display:block; font-family:var(--font-display,system-ui);
    font-size:18px; color:var(--paper,#F4F6F5); margin-bottom:8px; }
  .players .said { margin:0; font-size:18px; line-height:1.6;
    color:var(--muted,#8A9490); }
  .bridge { margin:34px auto 0; max-width:34rem; text-align:center;
    font-size:20px; line-height:1.6; color:var(--paper,#F4F6F5);
    text-wrap:balance; }

/* ===================================================================
   3 · THE PROBLEM — 00_HOMEPAGE_ORDER_FINAL_v8 §2.2
   =================================================================== */
.problem-list{font-size:clamp(26px,4.2vw,44px); line-height:1.22;
  letter-spacing:-.01em; margin:0 0 18px; max-width:20ch}
/* ⚠️ AN UNCLASSED PARAGRAPH INHERITS THE COLUMN, NOT THE MEASURE.
   .lede carries max-width:58ch and .problem-close carries 62ch, so the one
   plain <p> between them ran the full 1072px — ~119ch, against item 60's
   68ch rule. _typography-audit caught it as the fourth over-wide line on
   the site, one past its recorded baseline of three. */
#problem .wrap > p:not(.lede){max-width:62ch}
.problem-close{margin-top:30px; padding-top:26px;
  border-top:1px solid var(--rule); max-width:62ch}
.problem-close p{margin:0 0 10px; font-size:17.5px; line-height:1.7;
  color:#D5DBDD}
.problem-close strong{color:var(--paper)}

/* ===================================================================
   4 · THE PLAN — the two doors lead it (HOMEPAGE_COPY_v8 §8)
   =================================================================== */
.plan-h{margin:0 0 26px}
/* ⚠️ NOT .eyebrow. The routing line sits BELOW two equal doors, and an
   eyebrow above a heading reads as a label for what follows; here it is a
   hand-off into the leak story. Same size, different job. */
.plan-sub{margin:34px 0 10px; font-size:13px; letter-spacing:.16em;
  text-transform:uppercase; color:var(--muted); font-family:var(--font-display)}

/* ===================================================================
   5 · THE BANNER LINE — VILLAIN_LINEUP_v8 Part 4
   =================================================================== */
.banner-line{margin:0 0 6px; max-width:70ch; font-size:clamp(17px,2.1vw,21px);
  line-height:1.6; color:#D5DBDD}
.banner-line b{color:var(--paper); font-weight:600}

/* ===================================================================
   6 · YOUR TRAINING PARTNERS — FELT_SHARK_VILLAIN_LINEUP_v8
   ⛔ NO COLOUR DISTINGUISHES TUNA. Brass #C9A84C already means "leak
      marker" and TEN_LEAKS_MAP_v8 §5.4 calls that colour load-bearing —
      not amber, not violet. A fifth meaning for a fourth colour is how a
      palette stops carrying information. Tuna is set apart by the words
      "The one you're trying to become", which is the point anyway.
   =================================================================== */
#villains{background:#0B1F1A}          /* ⛔ the palette, not the comp's navy */
.vils{list-style:none; margin:34px 0 0; padding:0; display:grid;
  grid-template-columns:repeat(5,1fr); gap:clamp(14px,2vw,26px)}
.vils{grid-template-rows:auto auto auto auto}
.vil{text-align:center; min-width:0;
  display:grid; grid-row:span 4; grid-template-rows:subgrid; gap:0}
.vil-face{display:block; width:100%; max-width:168px; height:auto;
  aspect-ratio:1; margin:0 auto 14px; border-radius:50%; object-fit:cover;
  background:#0F2620; border:1px solid var(--rule)}
.vil h3{margin:0 0 8px; font-family:var(--font-display); font-size:15px;
  letter-spacing:.14em; text-transform:uppercase; color:var(--paper)}
.vil blockquote{margin:0 0 12px; font-size:15.5px; line-height:1.55;
  font-style:italic; color:#D5DBDD; text-wrap:balance}
.vil-lines p{margin:0 0 4px; font-size:14.5px; line-height:1.6;
  color:var(--muted); text-wrap:balance}
.vils-foot{margin:32px 0 0; font-size:17px; color:#D5DBDD; max-width:56ch}

/* ⚠️ FIVE ACROSS NEEDS 5 x 168px + gaps. Below that the row does not shrink
   gracefully — it makes five 90px faces, and at 90px a fish is a blob (the
   same argument APP_STATES_AND_STYLE_v8 Part 0 makes for the 96pt avatar).
   Three, then two, keeping every face large enough to read. */
@media (max-width:1000px){
  .vils{grid-template-columns:repeat(3,1fr); gap:26px 20px}
}
@media (max-width:600px){
  .vils{grid-template-columns:repeat(2,1fr); gap:26px 16px}
  .vil-face{max-width:132px}
}


/* ===================================================================
   4 · THE TEN LEAKS — 00_LEAK_ART_FINAL_v8 §2.5
   ⛔⛔ THE TEN ROWS ARE STRUCK. Eric, 2 Sep: "THE LIST OF LEAKS IS
      GRAPHICAL. NOBODY READS TEN PARAGRAPHS ON A HOMEPAGE." The
      explanations live on /the-ten-leaks, behind a disclosure (§2.6).
   ⭐⭐ ONE COMPONENT, ONE DATA SOURCE, TWO SHAPES. Above 900px the pins
      sit on the artwork; below it the artwork drops and the SAME pins
      lay out as a plain stack — number, nickname, plain name.
      ⚠️ That stack is not the struck section coming back. It is the
      graphic, rendered for a phone.
   ⛔ The pins are no longer aria-hidden: with the <ol> gone there is
      nothing left to duplicate, and they are what a reader who cannot
      see the picture gets.
   =================================================================== */
/* ⭐⭐ ERIC'S LINE, BETWEEN THE HEADING AND THE PICTURE — 4 Sep: "One line
   above the ten, not inside the artwork." It states the free/paid split in
   words; the faint rule inside the artwork draws the same boundary. */
.lkart-free{margin:0 0 14px; font-size:16px; line-height:1.6; color:#C9D6D1;
  max-width:64ch}
.lkart-free::first-line{color:#EAF2EF}
.lkart{margin:30px 0 8px; max-width:1160px; position:relative}
/* ⭐ THE FREE/PAID RULE. Reddish and faint — Eric: "faint but noticeable".
   ⛔ It FADES at both ends: a hard line butting into the frame edges reads as
   a rendering fault, a fading one reads as a boundary in the picture.
   ⚠️ Its `top` is generated from the measured midpoint of teeth 3 and 4, so
   it moves with the art and with the curriculum. */
.has-art .lkart-freeline{position:absolute; left:0; right:0; height:1px;
  pointer-events:none; z-index:1;
  background:linear-gradient(90deg,
    rgba(214,88,74,0) 0%, rgba(214,88,74,.55) 18%,
    rgba(214,88,74,.55) 82%, rgba(214,88,74,0) 100%)}
/* ⛔ no rule without the artwork — the phone stack is a plain list and a
   floating red line in it would mean nothing. */
.lkart:not(.has-art) .lkart-freeline{display:none}
.lkart picture{display:none}          /* ⭐ the phone shape: no artwork */
.lkart-pins{list-style:none; margin:0; padding:0;
  display:flex; flex-direction:column; gap:18px}
/* ⭐ ERIC'S 2px, AND IT IS AN OPTICAL CHOICE, NOT A MEASUREMENT.
   "Center it vertically on the tooth and then drop it 2px lower. It will look
   better." The teeth taper to a point at the bottom, so a shape's visual
   centre sits a little below its bounding box's centre -- the kind of thing a
   box measurement cannot see and an eye can.
   ⛔ It applies to every pin, so the row stays even; the per-tooth correction
   for a short measurement lives in gen_leak_rows.py, where the measurement
   does. */
.lkart-pin{ margin-top: 2px; }
.lkart-pin{display:grid; grid-template-columns:auto 1fr; gap:0 16px;
  align-items:start; padding-left:16px; border-left:2px solid transparent}
/* ⭐ leaks 1-3 carry a brass edge: the free tier, shown without a word.
   ⚠️ Brass is the LEAK colour (TEN_LEAKS_MAP §5.4). */
.lkart-pin:nth-child(-n+3){border-left-color:#C9A84C}
.lkart-n{font-family:var(--font-display); font-weight:700; line-height:1;
  font-size:clamp(24px,6vw,34px); color:#C9A84C;
  font-variant-numeric:tabular-nums; min-width:1.6ch; text-align:right}
.lkart-t{display:block; min-width:0}
.lkart-t b{display:block; font-family:var(--font-display); font-size:15px;
  letter-spacing:.14em; text-transform:uppercase; color:var(--paper)}
.lkart-p{display:block; margin-top:4px; font-size:16px; line-height:1.5;
  color:#8FA5A0}
.lkr-close{margin:34px 0 0; max-width:64ch; font-size:17px; line-height:1.7;
  color:var(--muted)}

/* ⛔⛔ THE ARTWORK SHAPE IS GATED ON `.has-art`, WHICH THE GENERATOR
   EMITS ONLY WHEN THE MEASURED POSITIONS BELONG TO THE ART WE SHIP.
   §2.2b killed all ten positions by changing the frame, and pinning
   ten labels to dead coordinates is how they collided in the first
   place. ⭐ Without it the ten render as the plain stack at every
   width: same component, same data, no picture. */
/* ⭐⭐ 980px, AND IT IS MEASURED — tools/_tmp_fit.mjs, 4 Sep. It was 900.
   ⛔⛔ At 900 leak 2's label — "THE WRONG SEAT — Playing the same hands from
   every position", the longest of the ten — does not fit on EITHER side of
   its own tooth: 21px too long left and right both. So the generator had no
   good answer, took the roomier side, and the edge clamp then pushed the
   words 11-14px INTO the tooth at every width. Eric's floor is 5-7px of
   clearance, and no placement at 900 can meet it.
     900 -> leak 2 short by 21px
     940 -> short by 4px
     980 -> all ten fit          <- the breakpoint
   ⭐ Below it the section is the plain stacked list, which is what
   `LEAK_POSTER_v8` §3.2 requires it to work as anyway: the art is an
   enhancement and never the content. ⚠️ Widening the picture's floor is the
   honest fix; shortening leak 2's plain name is content, and Eric's. */
@media (min-width:980px){
  /* ⭐ THE ARTWORK SHAPE. Every word and number is live HTML over a
     background, so a reorder in leaks.js carries and nothing is regenerated. */
  .lkart.has-art{position:relative}
  .lkart.has-art picture{display:block}
  .has-art .lkart-img{display:block; width:100%; height:auto; border-radius:14px}
  .has-art .lkart-pins{position:absolute; inset:0; display:block; pointer-events:none}

  /* ⛔⛔ ONE LINE PER LEAK, AND THE OPEN WATER IS THERE TO BE USED.
     Eric, 2026-09-03: "most of the real estate is NOT USED... 10 should read
     THE LAST CARD - paying off - or missing value - on the river. This should
     all be in ONE LINE and a little bigger font. Not three lines!!!"
     ⚠️ The eighth pass was drawn with open water on the right precisely so
     the labels could run; stacking them in three narrow lines wasted the
     frame it was regenerated to provide. */
  /* ⭐⭐ `--lk-nudge` PULLS THE LABEL TOWARD THE MIDDLE — Eric, 4 Sep.
     ⛔ It is per-pin and MEASURED (tools/gen_leak_nudges.mjs), because a
     uniform shift breaks the labels that had room: the teeth run bottom-right
     to top-left, so leak 2 ran 151px off the LEFT while leak 10 had 247px of
     slack on the right. Shifting them all equally would have taken leak 10
     off the picture in the other direction.
     ⚠️ THE NUMERAL DOES NOT MOVE. The pin carries the nudge and the numeral
     cancels it, so the numeral stays centred on its tooth -- which is the
     thing that was asked for first -- and only the words slide. */
  /* ⭐⭐ THE SIDE IS DATA ON THIS ONE RULE -- never a second rule.
     ⛔⛔ It used to be per-`nth-child` declarations in the generated block,
     which outrank the `.lk-left` class the generator toggles to measure with.
     So a pin could never be moved back to the right: toggling the class off
     left the nth-child transform in place, pass 2 measured a layout that was
     no longer assigned, and leak 3 shipped a 451px slide that put its label
     326px off the picture -- with a dash on both sides, because the stale
     `::after` also survived.
     ⭐ Values, not rules: an inline style beats a stylesheet, so the
     generator can now apply a side, reflow, and measure what ships. */
  .has-art .lkart-pin{--lk-nudge:0px; --lk-dir:row; --lk-pre:"— ";
    --lk-post:""; --lk-anchor:0px;
    position:absolute;
    transform:translate(calc(var(--lk-anchor) + var(--lk-nudge)),-50%);
    display:flex; flex-direction:var(--lk-dir); align-items:center; gap:10px;
    white-space:nowrap; padding-left:0; border-left:0}
  .has-art .lkart-pin:nth-child(-n+3){border-left-color:transparent}

  /* ⛔ THE NUMERAL SITS ON THE TOOTH — Eric: "the numbers should go directly
     on the teeth without a circle." The pin is anchored on the tooth centre
     and the numeral is the child at that anchor, so removing the disc is all
     it takes. ⚠️ It needs its own shadow to hold against a lit tooth, since
     the plate that used to carry it is gone. */
  .has-art .lkart-n{font-family:var(--font-display); font-weight:700;
    font-size:clamp(17px,1.7vw,26px); color:#0A1418; background:none;
    border-radius:0; width:auto; height:auto; min-width:0; display:inline-block;
    place-items:unset; flex:0 0 auto; font-variant-numeric:tabular-nums;
    /* ⭐ CENTRED ON THE TOOTH. The pin is anchored with the numeral's LEFT
       edge on the tooth centre, so the numeral sat entirely to the right of
       it. A percentage in `transform` resolves against the element's OWN
       width -- unlike `left`, which resolves against the containing block --
       so this centres at any font size with no width written down.
       ⚠️ `display:inline` cannot be transformed; it is inline-block now. */
    /* ⚠️ IT CANCELS WHATEVER THE PIN APPLIED, so one expression covers
       both sides: subtract the pin's anchor and its nudge, then centre. */
    /* ⛔⛔ NEVER CANCEL THE PIN'S ANCHOR HERE. This used to be
       `-50% - var(--lk-anchor) - var(--lk-nudge)`, and for a left-reading pin
       the anchor is `calc(-100% + 16px)` — 100% of the PIN. A percentage in
       `translateX` resolves against THE ELEMENT'S OWN WIDTH, so the numeral
       subtracted 100% of a 20px glyph instead. Exact for right pins (anchor
       0px, no percentage), nonsense for 1, 2 and 3.
       ⭐ Each side now says where the numeral sits in the numeral's own
       units, and nothing refers to the pin's width. */
    transform:translateX(var(--lk-n-tx, calc(-50% - var(--lk-nudge,0px))));
    text-shadow:0 1px 0 rgba(255,255,255,.55), 0 0 6px rgba(255,255,255,.75)}
  /* ⛔ THE FOUR DEEPEST TEETH ARE RED, AND A NEAR-BLACK NUMERAL DISAPPEARS ON
     THEM. Eric, 4 Sep: "4,3,2,1 should be white font, black is hard to see."
     ⚠️ The glow inverts with it — a white halo behind white type is invisible
     and would leave the numeral unreadable where the tooth is palest. */
  .has-art .lkart-pin:nth-child(-n+4) .lkart-n{ color:#FFFFFF;
    text-shadow:0 1px 0 rgba(0,0,0,.55), 0 0 7px rgba(0,0,0,.85) }

  /* ⭐ NICKNAME AND PLAIN NAME ON ONE ROW, with the dash between them. */
  .has-art .lkart-t{display:flex; flex-direction:var(--lk-dir); align-items:baseline;
    gap:.55em; line-height:1.2;
    text-shadow:0 1px 3px rgba(0,0,0,.9), 0 0 14px rgba(0,0,0,.7)}
  /* ⭐ TWO SIZES LARGER — Eric, 4 Sep: "there is room". The eighth pass
     was drawn with open water precisely so the labels could run. */
  /* ⛔⛔ 17px IS THE CEILING, AND IT IS MEASURED — tools/_find_leak_size.mjs.
     Eric asked for two sizes larger AND for 5-7px of clearance from every
     tooth. Those two cannot both hold: the binding label is leak 2, "THE
     WRONG SEAT — Playing the same hands from every position", the longest of
     the ten, and it must fit between the frame edge and its own tooth.
       23px  -> 182px too long
       21px  -> 119px too long
       19px  ->  56px too long   <- the size BEFORE the increase
       17px  ->  fits, every leak, on its roomier side
     ⚠️ SO THE OVERLAP PREDATES THE FONT CHANGE. At 19px leak 2 was already
     56px into its tooth, which is what "part of the text runs into the teeth"
     was describing. The clearance is the hard constraint -- it is the one
     stated with a number -- so the size yields to it.
     ⭐ To go bigger, leak 2's plain name has to get shorter. That is content,
     and it is Eric's. */
  .has-art .lkart-t b{font-size:clamp(13px,1.12vw,17px); letter-spacing:.1em;
    color:#FFF}
  .has-art .lkart-p{display:inline; font-size:clamp(12px,1.02vw,15px);
    line-height:1.2; color:#CFE0DC; white-space:nowrap; max-width:none}
  /* ⭐ THE DASH SITS BETWEEN THE TWO NAMES WHICHEVER WAY THE ROW READS.
     ⛔ One before and one after, both driven by the same data, so a pin can
     never render a dash on both sides -- which leaks 3, 4 and 5 did. */
  .has-art .lkart-p::before{content:var(--lk-pre); color:#8FA5A0}
  .has-art .lkart-p::after{content:var(--lk-post); color:#8FA5A0}

  /* ⛔⛔ A THIRD COPY OF THE SIDE ASSIGNMENT LIVED HERE, and it is why
     leaks 3, 4 and 5 rendered a dash on BOTH sides of their plain name. It
     was `nth-child(-n+5)`, hand-tuned from three to four to five by somebody
     looking at one width -- and it outranked both the generated values and
     the class the generator measures with, so the deepest five could not be
     moved back to the right at all.
     ⚠️⚠️ THE GENERATED BLOCK BELOW ALREADY SAID "the hand-tuned side rules
     are gone". They were forty lines above it. *A comment asserting a
     feature*, one more time -- and the third copy of one truth in this one
     figure. ⭐ The generator is the only writer of a side now. */
  /* ⚠️ MEASURED: leak 2's label is the longest of the leftward three at
     554px, and anchored flush to its tooth it ran 5px past the LEFT EDGE of
     the artwork — text off the picture. ⭐ Sliding the group 16px back toward
     the middle clears it with room at every width, and it puts the numeral a
     little further onto its tooth, which is where Eric asked for it anyway. */
  /* ⭐ AND THE LEFTWARD NUMERAL CENTRES THE OTHER WAY. Its RIGHT edge sits at
     tooth + 16px, so half its own width right, less that 16px, puts its centre
     exactly on the tooth -- and the label does not move, because a transform
     does not affect layout. */


  /* ⭐ `.lk-left` IS THE MEASURING INSTRUMENT AND THE SHIPPING STATE --
     one and the same now. It sets the four values the rules above read, so
     the generator applying it produces exactly the layout it then measures.
     ⛔ It declares no transform and no flex-direction of its own: a second
     declaration is what made the previous arrangement unmeasurable. */
  .has-art .lkart-pin.lk-left{--lk-dir:row-reverse; --lk-pre:""; --lk-post:" —";
    --lk-anchor:calc(-100% + 16px);
    /* ⭐ numeral is LAST here, its RIGHT edge landing at origin + 16px */
    --lk-n-tx:calc(50% - 16px - var(--lk-nudge,0px))}

  /* ⛔⛔ THE HAND-TUNED SIDE RULES ARE GONE. There used to be a block here
     saying "the deepest three read leftward", then four, then five — retuned
     three times, each time by somebody looking at one width, and each retune
     put a different label into a tooth.
     ⭐ tools/gen_leak_nudges.mjs decides the side per leak from the room its
     own tooth actually has, and writes it into the generated block below.
     ⚠️ A threshold is a guess about geometry. The geometry is measurable. */
  /* BEGIN GENERATED leak-nudges */
  /* ⭐ GENERATED by tools/gen_leak_nudges.mjs — MEASURED, never typed.
     Each value slides that label clear of its own tooth by 14px and
     keeps it 14px inside the artwork. ⚠️ Re-run when the art,
     the font sizes or the leak order change: a stale nudge puts a label in
     the wrong place, which is worse than one sitting at the edge. */
  .has-art .lkart-pins > .lkart-pin:nth-child(1){--lk-dir:row-reverse;--lk-pre:"";--lk-post:" —";--lk-anchor:calc(-100% + 16px);--lk-n-tx:calc(50% - 16px - var(--lk-nudge,0px));--lk-nudge:-26px}
  .has-art .lkart-pins > .lkart-pin:nth-child(2){--lk-dir:row-reverse;--lk-pre:"";--lk-post:" —";--lk-anchor:calc(-100% + 16px);--lk-n-tx:calc(50% - 16px - var(--lk-nudge,0px));--lk-nudge:-27px}
  .has-art .lkart-pins > .lkart-pin:nth-child(3){--lk-dir:row-reverse;--lk-pre:"";--lk-post:" —";--lk-anchor:calc(-100% + 16px);--lk-n-tx:calc(50% - 16px - var(--lk-nudge,0px));--lk-nudge:-27px}
  .has-art .lkart-pins > .lkart-pin:nth-child(4){--lk-dir:row;--lk-pre:"— ";--lk-post:"";--lk-anchor:0px;--lk-n-tx:calc(-50% - var(--lk-nudge,0px));--lk-nudge:11px}
  .has-art .lkart-pins > .lkart-pin:nth-child(5){--lk-dir:row;--lk-pre:"— ";--lk-post:"";--lk-anchor:0px;--lk-n-tx:calc(-50% - var(--lk-nudge,0px));--lk-nudge:10px}
  .has-art .lkart-pins > .lkart-pin:nth-child(6){--lk-dir:row;--lk-pre:"— ";--lk-post:"";--lk-anchor:0px;--lk-n-tx:calc(-50% - var(--lk-nudge,0px));--lk-nudge:10px}
  .has-art .lkart-pins > .lkart-pin:nth-child(7){--lk-dir:row;--lk-pre:"— ";--lk-post:"";--lk-anchor:0px;--lk-n-tx:calc(-50% - var(--lk-nudge,0px));--lk-nudge:10px}
  .has-art .lkart-pins > .lkart-pin:nth-child(8){--lk-dir:row;--lk-pre:"— ";--lk-post:"";--lk-anchor:0px;--lk-n-tx:calc(-50% - var(--lk-nudge,0px));--lk-nudge:9px}
  .has-art .lkart-pins > .lkart-pin:nth-child(9){--lk-dir:row;--lk-pre:"— ";--lk-post:"";--lk-anchor:0px;--lk-n-tx:calc(-50% - var(--lk-nudge,0px));--lk-nudge:9px}
  .has-art .lkart-pins > .lkart-pin:nth-child(10){--lk-dir:row;--lk-pre:"— ";--lk-post:"";--lk-anchor:0px;--lk-n-tx:calc(-50% - var(--lk-nudge,0px))}
  /* END GENERATED leak-nudges */
}

/* ⚠️ THE SEAM WHERE TWO SECTIONS BECAME ONE. ORDER_FINAL Part 5 item 4
   merged THE STORY and WHO MADE THIS into #founder, and the join had no
   breathing room: "So we built the other thing." ran straight into the
   WHO MADE THIS eyebrow, so empathy and authority read as one paragraph
   when the whole point of the order is that they are two beats.
   ⭐ Eric, 2026-09-02: "need a larger page space before WHO MADE THIS." */
/* ⛔⛔ THIS WAS A HAND-TYPED 64px, and it was the last green header out of
   step: measured 64 where every other reads 88. Eric set the standard on
   4 Sep by pointing at THE PLAN — "make them all the same as the area pointed
   to by the lower red arrow."
   ⚠️ A number typed beside the one that governs is the defect this repo keeps
   recording; it drifts the moment the governing number moves. It reads the
   variable now. */
#founder .philosophy + .eyebrow,
#founder .philosophy ~ .eyebrow { margin-top: var(--eyebrow-above); }
@media (max-width: 700px) {
  #founder .philosophy ~ .eyebrow { margin-top: 44px; }
}

/* ==================================================================
   ⭐⭐⭐ THE BREATHING RULE, LAST — so nothing later can undo it.
   Eric, 4 September, three times in one sitting: "at least 2 spaces of
   blank space need to be there before a major heading", "2-3 lines of
   blank space please", "need 3 lines of blank space here".

   ⛔⛔ AND IT HAD TO MOVE TO THE END OF THE SHEET. The earlier cut set
   `.eyebrow:has(+ h2){margin-top:...}` at line ~292, and `.eyebrow{margin:
   var(--eyebrow-above) 0 var(--eyebrow-below)}` at line 325 is a SHORTHAND
   that writes margin-top again — later, so it won. Measured: four of five
   eyebrow+heading pairs came back at 0px.
   ⚠️ That is the third shorthand-beats-longhand defect on this page today,
   after `.sec{padding:X 0}` clearing the page indent. ⭐ A shorthand writes
   every side; when two rules disagree, the later one wins, and specificity
   does not enter into it.

   ⭐ THE UNIT IS WHATEVER SITS ABOVE THE HEADING. A reader does not see an
   eyebrow, a logo and an h2 — they see one heading block. So the space goes
   above whichever of them comes first, and the rest keep their small binding
   gaps. */
/* ⛔⛔ THIS WAS A THIRD NUMBER. It set clamp(72px,8vw,104px) — 104 at desktop
   — while `--eyebrow-above` said 88 and an earlier floor said clamp(56,7vw,88).
   Three rules, three answers, and which one a header got depended on whether
   an h2 followed it: measured, THE PROBLEM read 88 and WHO MADE THIS read 104.
   ⭐ Eric settled the number on 4 Sep by pointing at THE PLAN — "make them all
   the same" — so all three read the one variable now. */
.eyebrow:has(+ h2) { margin-top: var(--eyebrow-above) }
.eyebrow + h2 { margin-top: 0 }

/* ⭐ THREE LINES ABOVE A BRAND MARK THAT INTRODUCES A HEADING — the
   SharkSense and SHARKBAIT wordmarks. They are bigger than an eyebrow and
   read as artwork, so they need more air above them, not less. */
p:has(> img) + h2, picture + h2, figure + h2 { margin-top: 0 }
p:has(+ h2):has(img), picture:has(+ h2), figure:has(+ h2) {
  margin-top: clamp(104px,11vw,148px) }

/* ⚠️ AND A HEADING THAT OPENS ITS SECTION STILL TAKES NOTHING EXTRA: the
   section's own padding is already there, and stacking on it opens a hole. */
section > .wrap > h2:first-child,
section > .wrap > .eyebrow:first-child:not(:has(+ h2)) { margin-top: 0 }
  
/* ==========================================================================
   ⛔⛔ 18px IS THE FLOOR HERE TOO — Eric, 2026-09-05: "18 px minimum must be
   met on all home page and app pages. Period. Fix them all."

   This page does not link css/legibility-floor.css (see the note above at
   .lede) so it never had one. Measured before this rule: eight body-text
   nodes between 14.0px and 17.0px, `.legal` the worst at 14px.

   ⚠️ `!important` because several of these are set inside media queries and
   clamps that would otherwise win on the small screens where it matters
   most. A floor is not a design opinion competing on specificity.
   ⛔ Captions and the legal line are NOT exempt any more. Our reader is
   seventy-eight; a 14px legal line is one they cannot read at all.
   ========================================================================== */
/* ⛔⛔ `body p`, `body li` AND `body .lede` CAME OFF THIS LIST — Eric,
   2026-09-08: "18px is NOT a ceiling. It is a MIN only."
   `max(18px, 1em)` reads the INHERITED size, so once a parent is 18px the
   expression can never return anything else; with `!important` on a selector
   as broad as `body p` that clamped EVERY paragraph on the page to exactly
   18px -- all 63 of them, with .band-price designed 28, .who-pull 30 and
   .sub 21.
   ⚠️ AND THIS WAS THE SECOND COPY. css/legibility-floor.css carries the same
   rule; I fixed that one first and measured no change, because this one was
   still winning. Two copies of one truth, in the rule that enforces
   legibility.
   ⭐ The floor is the inherited base now (`body { font-size:18px }` in
   legibility-floor.css). The deliberately-small classes below stay clamped by
   name, because each was MEASURED under 18 and each is single-purpose. */
/* ⭐⭐ THE FLOOR IS ABSOLUTE AND `p`/`li` ARE BACK ON IT.
   ⚠️ I took them off to stop it capping the headline sizes, and THIRTY-SIX
   body-text paragraphs fell under 18px across twenty pages. Most are bare
   <p> with no class, so there was nothing to name an exemption after.
   ⭐ The exemption goes the other way instead: the six elements the design
   deliberately sets ABOVE 18 carry `!important` in their OWN rule, where the
   number already lives. No size is restated here. */
body p, body li,
body .legal, body .price-what, body .vils-foot,
body .sb-web-cap, body .sb-cap, body .lkart-free, body .lkr-close,
body .lk, body .key, body .nobody {
  font-size: max(18px, 1em) !important;
  line-height: 1.6;
  /* ⭐ AND THE FLOOR OWNS THE WRAPPING IT CHANGED. Raising type re-wraps
     every line, and _orphan-audit immediately found two: the homepage footer
     at 390px stranded "info@feltshark.com" alone once .legal went 14px -> 18px.
     `text-wrap: pretty` is the mechanism for exactly this -- it pulls a word
     down from the line above. ⛔ NOT `balance`, which CLAUDE.md records as
     not reaching a long paragraph (Chrome stops balancing past a few lines),
     and ⛔ not a non-breaking space, which that same entry proves does not
     stop a line break at all. */
  text-wrap: pretty;
}

/* ⛔⛔ THE FOOTER LINE DOES NOT FIT ON A PHONE, AND text-wrap DID NOT FIX IT.
   Measured at 390px after the 18px floor: `.copy` is a 350px box (390 less
   the page's 20px gutters) holding 366px of content -- "© 2026 Felt Shark
   LLC. ·" is 200px and "info@feltshark.com" is an unbreakable 166px token.
   Sixteen pixels over, so it MUST take two lines.
   ⚠️ `text-wrap: pretty` is applied here (verified: computed value is
   "pretty") and cannot help -- there is exactly one break opportunity in the
   line and it is in front of the address. This was never an orphan of
   typography; it is a box sized for 14px text now holding 18px text.
   ⭐ So the second line is DELIBERATE rather than accidental. A copyright and
   a contact address are two facts, and on a phone they belong on two lines --
   which also makes the address its own flow rather than a stranded last line,
   the same distinction CLAUDE.md draws for `.fs-desk .who`.
   ⛔ The type does not shrink to fit. That is the trade the floor exists to
   refuse. */
@media (max-width: 460px) {
  .copy a { display: block; margin-top: 4px; }
}
/* ===================== THE HERO ============================================
   ⭐⭐⭐ `140_HERO_AND_SITE_ORDER_SPEC_1oct (2).md` PART 2, measured off the
   shipping plate. ⚠️ That file is not in the repo; cited by name and date so the
   reference is traceable and its absence declared.

   ⛔ EVERY LIVE-TYPE POSITION IS A % OF THE PLATE, IN ONE BLOCK. PART 2:
   "Re-plating is editing these numbers — never rebuilding the layout."

   ⛔⛔ `--sig-*` IS BACK, AND THE SENTENCE THAT EXPLAINED ITS ABSENCE WENT FALSE
   THE MOMENT IT RETURNED. It read: *"NO `--sig-*` AND NO NAME BASELINE,
   DELIBERATELY. PART 2 measured both and two rulings retired them: V1 moved the
   signature OUT of the illustration into body text, and 'faces, no names'
   removed the strip's name row."*
   ⭐ Eric reversed V1 on 2026-10-03: *"the bottom-right text is back … 140
   already has it measured against the plate we are keeping."* Rule 39 — a
   comment recording why something is absent is a comment that must move when it
   returns, which is why this paragraph is a correction rather than a deletion.
   ⚠️ THE NAME BASELINE IS STILL ABSENT and still correctly so: the four bus
   names were measured on 3 Oct and STOPPED on legibility, not on placement.
   ⛔⛔ AND THESE ARE `140`'s NUMBERS, NOT `250`'s REGION F. Eric: *"DO NOT use
   250's Region F coordinates (x 50% / y 86% / w 44% / h 9%). Those were measured
   for the new plate and 250 is parked."* ⭐ The difference is load-bearing: the
   strip's own zone reaches y 90.2%, so a block starting at 86% overlaps it BY
   DECLARATION — which is exactly what the earlier Region F build measured as a
   23-74px collision from 1200 down. Starting at 91.4% clears it, and there is
   no `h`, so there is no zone height to overflow either.

   ⛔⛔⛔ THIS BLOCK DECLARES NO FONT TOKEN. PART 4 counts 25 declarations of
   `--font-display` already and a twenty-sixth is not acceptable from the file
   that recorded the defect. It CONSUMES the two this page already declares.

   ⭐ TYPE SCALES IN `cqw`, so it tracks the plate exactly as the zones do. A
   fixed px size would hold still while its zone shrank, which is the
   `max()`-floor family: a rule that cannot fit reads like one that works. */
.hero{
  --sign-x:51.8%;  --sign-y:10.6%;  --sign-w:31.4%;  --sign-h:14.4%;
  --cave-x:79.0%;  --cave-y:42.5%;  --cave-w:18.6%;  --cave-h:12.2%;
  --strip-x:1.8%;  --strip-y:72.0%; --strip-w:62.9%; --strip-h:18.2%;
  /* ⛔⛔⛔ `--cta-y` STAYS AT 90.6% AND ERIC'S "+3%" CANNOT BE APPLIED AS A
     MOVE — 2026-10-04. He is RIGHT that it is touching: the strip's painted
     panel ends at 90.12% and the pill begins at 90.45%, a gap of 0.33% = 2.4px
     at his width. ⚠️ BUT THE BUTTON IS NOT WHAT PUTS IT THERE.
     ⭐⭐ MEASURED off `hero-plate.png`: the pill is PAINTED, at y 90.45%..95.34%
     and x 2.44%..25.81%, and these four tokens match that painting to within
     0.15% — they were measured FROM it. So the 2.4px is in the ARTWORK, and
     the live button is sitting exactly where it should.
     ⛔ The +3% was built, measured and REVERTED: it takes the gap from 2.9px to
     24.3px and in the same move drops the button's gold coverage from 98.47%
     to 37.71% — two thirds of it hanging off its own painted pill, with a 3%
     band of exposed gold above it and bare reef below. That is the ON BOARD
     portraits-and-rings defect of 2026-10-03 in a second costume: a DOM element
     pinned to a painted feature cannot be nudged without taking the painting
     with it.
     ⭐ So the three ways to close it are a PLATE edit, a strip move (also
     painted, so the same trap), or accepting 2.4px — and all three are Eric's.
     ⚠️ DO NOT "FIX" THIS BY MOVING THE BUTTON DOWN. That number is not wrong.

     ⭐⭐⭐ BUT SOMETHING ELSE WAS, AND IT IS WHAT HE WAS SEEING — 2026-10-04,
     after he reported it a second time as "too high". THE BUTTON WAS NOT
     TOUCHING THE PANEL; ITS GREEN HALO WAS. `.hz-cta` carried
     `box-shadow:0 0 0 .35cqw var(--accent)`, a SOLID ring of the same green on
     all four sides, added deliberately to cover the sliver of gold the zone
     left showing.
     ⛔⛔ AND A `cqw` SPREAD IS A WIDTH UNIT APPLIED IN FOUR DIRECTIONS ON A
     1.777 PLATE, so vertically it is 1.78x the size it is horizontally. 0.35cqw
     is 4.50px: 0.35% of plate WIDTH and 0.62% of plate HEIGHT.
     ⚠️ MEASURED, the gold it had to cover is 0.16% left, 0.01% right, 0.15%
     top, 0.04% bottom — so it over-covered the top by 0.47% and the bottom by
     0.58%, and the green reached 89.98%, which is 0.14% ABOVE the panel's
     painted bottom at 90.12%. ⭐ The halo genuinely overlapped the strip. The
     button never did.
     ⭐⭐ SO THE ZONE IS NOW THE PAINTING, MEASURED, AND THE HALO IS DELETED.
     A spread that has to cover four different margins cannot be one number;
     matching the zone to the pill makes every margin zero and needs no ring.
     This is the ring-centre discipline applied to the pill: derive it from the
     plate rather than nudge it against the plate.
     ⛔ Re-measure with the walk in `tools/_sign_arc.py`'s sibling if the plate
     is ever re-cut; these four are READ OFF `hero-plate.png`, not chosen. */
  /* ⭐⭐ RULED 9 Oct (D304, §22): "THE CTA GROWS DOWNWARD FROM ITS CURRENT TOP. It
     does not move." x, y and w stay READ OFF the painting; only the height grows,
     by +20% (4.89% → 5.87%), the larger of the two growths `_cta_options.mjs` §2
     measured. Both left the gold at 3 / 5 / 1 / 0 px, because the residue is at
     the fixed TOP, and left 29.7 / 26.7 / 21.3 / 15.8 px of room below to the
     plate's edge (1440 / 1287 / 1024 / 761). The words centre ~0.27cqw lower:
     Eric's "a little lower", without the move that uncovers 353–670 px of gold. */
  --cta-x:2.44%;   --cta-y:90.45%;  --cta-w:23.37%;  --cta-h:5.87%;
  /* ⭐ 140 PART 2's measured signature zone, restored 2026-10-03. ⛔ No `h`:
     140 does not give one, and a fixed fraction of plate height under type with
     an 18px floor is precisely what made the 250 Region F build overflow. */
  --sig-x:57%;     --sig-y:91.4%;   --sig-w:40%;
  /* ⭐⭐⭐ TWO SIGN TYPE TOKENS · ERIC, 2026-10-02 23:08: "TWO SIZES ACROSS BOTH
     SIGNS... BUILD IT AS TWO TOKENS, declared once, consumed by every sign
     class. Not four values that agree today."
     ⭐ TIER 1 is every NAME and every CALL TO ACTION -- SOLID POKER AHEAD ·
     WHEN READY (D433, 12 Oct, deleted THE MAIN CURRENT and THE DEEP).
     ⚠️ `WHEN READY` WAS `ENTER WHEN READY` UNTIL ERIC'S 2026-10-03 22:02
     RULING, and the word is why that ruling exists: it was the longest tier-1
     line AND it sat on the narrower board, so it alone set the size of the
     whole tier. Dropping it returned tier 1 from 18.56px to 25.09px at a 1434
     plate and saved an edit to the painted plate. ⛔ So this is not four
     interchangeable strings: a line added to the CAVE sign re-sets tier 1 for
     all four, and `tools/_sign_parity.mjs` is what measures it.
     ⭐ TIER 2 is every LIST -- the three fundamentals, the three solver words.
     ⛔ MEASURED BEFORE TOKENISING: the six sign classes carried TWELVE
     font-size declarations, not four -- six here in `cqw` and six more in the
     phone block in fixed `px`, which is the half a count of the desktop rules
     alone would have missed. The phone block now overrides the TOKENS rather
     than restating six sizes, so there are two NAMES and four value sites.
     ⚠️ The values are the ones already shipping -- tier 1 adopts `.sign-head`'s
     1.75cqw and tier 2 adopts `.sign-list`'s 1.05cqw -- so the consequence Eric
     asked to be measured comes from the GROUPING and not from a size I chose. */
  --sign-t1:1.75cqw;
  --sign-t2:1.05cqw;
  /* ⛔⛔ `--head-y` 11.4% -> 5%. ERIC, 2026-10-02: "the main top left text is
     too low", and his reference image puts the headline ~4.8% down. MEASURED:
     at 11.4% the h1 sat 92px into the plate at 1440 and 123px at 1920; at 5%
     it is 41px and 54px, which is the reference.
     ⚠️ THIS IS A ZONE CHANGE AND 140 MUST FOLLOW IT, or the spec and the page
     disagree about where the headline is -- the recurring defect with a
     stylesheet on it. Flagged to the relay in the same breath as the edit.
     ⭐ AND THERE WAS NO IN-ZONE FIX: the h1 sits 0px below its own `.hz-head`
     zone top at both widths, so there is no slack to reclaim and raising it
     cannot be done inside the zone.
     ⛔ D213 STILL HOLDS, checked rather than assumed: at 5% the headline
     clears the 130px fixed header by 41px at 1440 and 54px at 1920.
     ⭐⭐ 5% -> 2%. ERIC, 2026-10-03: "the top left part of the hero image (text)
     needs to move up 3% more. the bottom is running into the top of the
     luggage." ⚠️ So the constraint is the BOTTOM of the block against a painted
     object, which no zone number describes and only a render shows — the zone
     is a box and the luggage is in the picture.
     ⛔ D213 RE-CHECKED RATHER THAN ASSUMED, and the arithmetic was wrong before
     the render corrected it: 3% of the capped plate is ~24px, so 41 - 24 "is"
     17 — and it MEASURES 16px at 1440 and 1920, 14px at 1280 and 12px at 1024.
     The narrow widths are the ones a prediction misses, because the plate
     shrinks with the viewport while the 130px header does not.
     ⚠️⚠️ SO THE CLEARANCE IS 12px AT ITS WORST AND THAT IS THIN. ⛔ The next
     request to raise this is the one that needs the HEADER looked at rather
     than the zone — `--hdr-h` is 130px and declared once — and that is a
     composition decision rather than a number.
     ⭐ The headline's BOTTOM lands at 24.2% of the plate (was 27.2%), which is
     the measurement Eric's report is actually about: the zone is a box and the
     luggage is painted, so only a render says whether they touch. */
  --head-x:3.2%;   --head-y:2%;  --head-w:44%;
  --cream:#F4F6F5;
  /* ⛔ THE PLATE CLEARS THE FIXED HEADER. Without this the hero starts at y=0
     under a 130px fixed header at z-index 50, and the wordmark lands on the
     headline — measured, and found by `check_seat_occlusion --hero`, not by
     reading. The value is `--hdr-h`, declared once on `:root`. */
  padding:var(--hdr-h) 0 0; margin:0; background:#060C10;
}
.hero-plate{
  position:relative; width:100%; margin:0 auto;
  container-type:inline-size; container-name:plate;
  aspect-ratio:1672/941;      /* ⭐ PART 1's exact aspect, so every % lands */
  /* ⛔⛔ THE FOLD, AND `62vh` WAS REJECTED BY MEASUREMENT RATHER THAN APPLIED.
     The relay asked for `height:62vh` as "the mildest that works". It is not
     mild: the aspect above exists so every zone % lands, and the painting is
     `object-fit:cover`, so forcing a height takes the box from aspect 1.777 to
     2.58/2.87 and DISCARDS 31.1% of the painting at 1440 and 38.1% at 1920 --
     including the arch the signs are positioned against. It clears the CTA by
     destroying a third of the plate.
     ⭐ CAPPING THE WIDTH CLEARS IT WITH ZERO EXTRA CROP, because the aspect is
     kept and the plate simply gets smaller: 1434px puts the CTA at 899 against
     both a 900 and a 1080 fold, crop unchanged at 0.1% / 0%.
     ⚠️ ITS COST IS STATED RATHER THAN HIDDEN: above 1434px the hero stops being
     full-bleed and letterboxes -- 243px of page either side at 1920. That is a
     visible composition change and Eric sees it before it ships.
     ⛔⛔ AND IT DOES NOT FIX THE FOUR BUDGET SHAPES. Below 761px (the floor when
     this was measured; 853 since D489) the hero STACKS
     and the CTA is 675-957px down at every plate value measured; there the
     painting is already cropped 69-72% by the phone block. No plate value
     solves those -- something else has to leave the hero, which is Eric's. */
  max-width:1434px;
}
.hero-plate > picture > img{ display:block; width:100%; height:100%; object-fit:cover; }

/* ⭐⭐ THE NINTH COMPOSITED ELEMENT — TIGER (TIG-008) OVER THE PAINTED BUS DRIVER.
   D240: TIG-007 is the canonical character and the painted driver a poor
   rendition, covered rather than repainted — the plate is untouched (3 Oct).
   D246: TIG-008 at scale 0.300 of its opaque crop, plate px (1415, 698), 365x303
   — chosen by Eric from `docs/v9/tiger-tuna-grid-6oct.png`, panel 2. Measured
   there: 0px of the painted driver visible; part of the Tuna's mouth covered
   (437 of 730px), which no placement avoids without showing the painted fin.
   ⛔ THESE FOUR NUMBERS ARE READ, NOT CHOSEN: `tools/gen_hero_driver.py` derives
   them into `assets/website/hero-driver/_hero-driver.json`, and
   `tools/_hero_driver_check.mjs` fails if the rendered element leaves them.
   ⚠️ Percentages of the PLATE, like every zone, so he scales with the painting.
   D246 condition 2: hidden in the stacked band, <=760px when ruled, <=852px since
   D489 (the rule lives in that block, so it moved with it; MEASURED 15 Oct:
   display:none at 390-852, shown from 853). */
.hero-driver{ position:absolute; left:44.219%; top:38.756%; width:11.406%; height:16.824%;
              display:block; pointer-events:none; }

/* every live-type surface is pinned to its measured zone */
.hz{ position:absolute; margin:0; }
.hz-head { left:var(--head-x);  top:var(--head-y);  width:var(--head-w); }
.hz-sign { left:var(--sign-x);  top:var(--sign-y);  width:var(--sign-w); height:var(--sign-h);
           display:flex; flex-direction:column; align-items:center; justify-content:center;
           text-align:center; }
.hz-cave { left:var(--cave-x);  top:var(--cave-y);  width:var(--cave-w); height:var(--cave-h);
           display:flex; flex-direction:column; align-items:center; justify-content:center;
           text-align:center; }
.hz-strip{ left:var(--strip-x); top:var(--strip-y); width:var(--strip-w); height:var(--strip-h);
           display:flex; align-items:center; }
.hz-cta  { left:var(--cta-x);   top:var(--cta-y);   width:var(--cta-w);  height:var(--cta-h);
           display:flex; align-items:center; justify-content:center; }
/* ⭐ THE SIGNATURE — 140 PART 2's zone, and NO HEIGHT by design (see the token
   block). It is the only `.hz` that sizes itself from its own content. */
.hz-sig  { left:var(--sig-x);   top:var(--sig-y);   width:var(--sig-w); }
/* ⛔⛔ AND 140's ZONE CAN ONLY HOLD THIS COPY ABOVE ~1360. MEASURED at eleven
   widths: the block fits the plate at 1920/1680/1434/1360 and runs past the
   bottom of the painting by 17px at 1280, rising to 61px at 762 — at 1280 the
   last line is visibly cut off by the plate edge.
   ⭐ THE CAUSE IS THE ONE `index.html` ALREADY RECORDED FOR THE EARLIER REGION F
   BUILD, and it is structural rather than tunable: the zone is a FRACTION of a
   plate that shrinks with the viewport, while the type has a FIXED 18px FLOOR.
   Below ~1300 the content stops shrinking and the zone does not.
   ⛔ 250 PART 5's exemption does NOT rescue it — that covers hero SIGN
   lettering, and Eric drew the line himself: a label is not a sign, and neither
   is a signature.
   ⭐⭐ SO BELOW 1360 IT RETURNS TO WHERE V1 PUT IT — body text under the
   painting. ⚠️ That is deliberately NOT a new design: it is the placement that
   shipped this morning, kept for the widths where Eric's zone cannot hold the
   block. The alternatives all need a ruling — widen `--sig-w`, raise
   `--sig-y`, or shorten 140 PART 3's copy. */
/* ⛔⛔⛔ AND THE FALLBACK RESERVED 30px FOR A BLOCK THAT MEASURES 75 — ERIC
   FOUND IT BY LOOKING, 2026-10-04: *"the bottom left is covered up by the next
   page."* ⭐ The zone is `position:absolute` at `top:100%`, so it CANNOT push
   the hero; the hero has to reserve its height, and `30px` was never measured.
   ⚠️ MEASURED at Eric's own width (1287, inferred from a 1931px screenshot at
   dpr 1.5) before the fix: zone 73.6px tall against 30px reserved, so 43.5px
   hung past `.hero`'s own bottom and `overflow:hidden` cut it in half — which
   is why he read it as the next section covering the hero rather than as the
   signature overflowing.
   ⭐⭐ 100px IS A MEASUREMENT, NOT A ROUND NUMBER. The zone's height across the
   whole supported range below the breakpoint is remarkably flat, because both
   <p>s are at the 18px floor and the block is full-width here:
       761px -> 71.9    1000 -> 71.9    1200 -> 72.3
       1287  -> 73.8    1359 -> 75.1    (worst case 75.1)
   100 = 75.1 worst + ~25 of gap below the text, which answers the 20px the
   zone already sets ABOVE it. ⛔ It is not `--sig-h`: 140 gives no height, and
   the token block above records why a fixed fraction of plate height under
   18px-floored type is exactly what made the Region F build overflow.
   ⚠️ RE-MEASURE THIS IF THE SIGNATURE COPY CHANGES. Two lines of 140 PART 3
   drive it, and a third line would overflow again in silence — the clipping
   throws nothing and `overflow:hidden` hides the evidence. */
/* ⛔ D516 (Eric, 18 Oct, on a 1238px window, arrow at the plate's bottom-right
   beside the strip): "this should go here!" -- THE SIGNATURE STAYS ON THE WATER
   AT EVERY PLATE WIDTH. The V1 fallback below the painting now applies only
   where there is no plate (the phone flow stack, <=852px). */
@media (max-width:852px){
  .hz-sig{ left:0; top:100%; width:100%; padding:20px var(--pad) 0; }
  .hero{ padding-bottom:100px; }
}
/* ⭐ D516 · 853-1359: the zone is the WATER RIGHT OF THE STRIP. ⛔ The strip's
   BOX ends at 64.7% but its painted panel does not: the Tiger group overflows to
   69.1% (union of its elements, tools/_sig_on_plate.mjs) and the panel's border
   to ~72% in the 1238 screenshot. A first cut at 66.5% sat ON "TIGER COACH" while
   the box test said clear (Rule 58). So the block starts at 74.5% and runs to
   98%, anchored to the plate's BOTTOM
   (not a top %), because its height is its content: the 18px floor wraps it to
   more lines as the plate narrows, and a top % is what ran it off the painting
   (the 4 Oct measurement above). Its height and fit are re-measured in D516. */
@media (min-width:853px) and (max-width:1359px){
  .hz-sig{ left:74.5%; width:23.5%; top:auto; bottom:2.2%; }
}
/* ⭐⭐ D471.5 · THE STAKE, IN THE BAND DIRECTLY BELOW THE PLATE. `.hz-foot` is
   `display:contents` at 1360+ (the stake alone is below the painting; the
   signature stays on it) and on a phone (both join the flow stack, stake
   first). Between 761 and 1359 it is the ONE absolute box at `top:100%`, so the
   stake and the signature stack inside it instead of landing on each other.
   ⛔ `.hero` is `overflow:hidden` and an absolute box cannot push it, so the
   hero RESERVES the band's height -- the same trap the 100px above records.
   The reserves below are MEASURED (`tools/_hero_ceiling.mjs` prints the band
   height at every width), not chosen; re-measure if the stake copy changes. */
.hz-foot{ display:contents; }
.hero-stake{
  position:absolute; top:100%; left:0; width:100%; margin:0;
  padding:20px var(--pad) 0; box-sizing:border-box;
  font-family:var(--font-body); font-weight:500; line-height:1.45;
  font-size:clamp(18px,1.3cqw,20px) !important; color:var(--cream);
  /* ⭐ D497 (ii): the measure is capped. MEASURED 15 Oct: across the plate's full
     width the stake read 71.6ch at 1024 and 1440, over check_text_measure's 68ch
     ceiling (M2, baseline 0). The cap is on the TEXT, so the side padding is added
     back. */
  max-width:calc(66ch + 2 * var(--pad));
}
@media (min-width:1360px){ .hero{ padding-bottom:var(--stake-reserve-wide); } }
/* D484 + D489 (Eric, 15 Oct): the plate is a container from 853 now, not 761 */
/* ⭐ D516: the signature is back on the plate at 853-1359, so `.hz-foot` stays
   `display:contents` there too and the stake is alone below the painting, as it
   is at 1360+. The band now holds the stake only, so its reserve is re-measured
   (`--stake-reserve-mid`, below). */
@media (min-width:853px) and (max-width:1359px){
  .hero{ padding-bottom:var(--stake-reserve-mid); }
}
/* D497 (ii), RE-MEASURED 16 Oct: capping the stake's measure at 66ch wraps it at
   1440, and `check_hero_ceiling` read the band below the plate at 74px against the
   70px reserve (clipped) at 100/150/200%. The reserve follows that measurement. */
/* D516, RE-MEASURED 18 Oct: with the signature back on the plate the mid band
   holds the stake alone and reads 72px at 853-1359 (`_hero_ceiling.mjs`, every
   zoom); 160px reserved it with the signature stacked under it. 74 = 72 + 2. */
:root{ --stake-reserve-wide:74px; --stake-reserve-mid:74px; }

/* ---- the headline block · PART 2: it must END BY 37% ---------------------- */
/* ⛔⛔ `!important` IS LOAD-BEARING HERE AND IT IS NOT A STYLE CHOICE. This
   page's legibility floor is `body p,… {font-size:max(18px,1em) !important}`,
   and CLAUDE.md #43 records that `1em` is the INHERITED size, so once a parent
   is clamped the floor can never return anything else — a FLOOR acting as a
   CEILING. Measured here before fixing: every one of the hero's `<p>` surfaces
   computed to exactly 18px, including sizes meant to be larger.
   ⭐ #43's recorded remedy is the one followed: the elements the design
   deliberately sets ABOVE 18 carry `!important` in their OWN rule, where the
   number already lives. The floor is not weakened and no size is restated in it.
   ⛔ AND NOTHING HERE IS PUSHED BELOW 18. Anything whose natural size would fall
   under the floor is LEFT to the floor — Eric: "18 px minimum must be met on all
   home page and app pages. Period." An `!important` there would quietly buy
   layout with legibility, which is the trade this project refuses. */
.hero-h1{
  font-family:var(--font-display); font-weight:700; line-height:1.05;
  /* ⚠️ 2.7cqw, not 3.5. At 3.5 the headline block ended at 36.5% against PART
     2's 37% ceiling -- inside it, but by four pixels, which is not a margin.
     The relay's reference render puts the bus luggage at ~30%, so the block is
     sized to clear THAT rather than to squeak past the stated limit. */
  font-size:2.7cqw !important; letter-spacing:-.01em; color:var(--cream); margin:0;
}
.hero-h1 .gold{ color:var(--gold,#C9A84C); }
.hero-sub{
  font-family:var(--font-body); font-size:1.45cqw; line-height:1.45;
  color:var(--cream); opacity:.93; margin:.7cqw 0 0;
}
/* ⛔ THE PROTECTED SENTENCE — never cut, never below the fold. */
.hero-protect{
  /* 1.6: body text keeps the floor Eric set (item 60, "1.6 is a low bar") */
  font-family:var(--font-body); font-size:1.3cqw; line-height:1.6;
  color:var(--cream); opacity:.82; margin:.55cqw 0 0; max-width:92%;
}
/* ⭐⭐ D467.2 (Eric, 14 Oct): "THE WORDS MUST WIN THE FIRST SECOND." A reviewer:
   "I remember the bus journey before I remember that Felt Shark is a coaching
   app." The headline block sat at 82-93% opacity over textured water. Now:
   full opacity, weight 500 on the sub, hook and stake, and a dark halo
   (text-shadow) that separates every glyph from the water behind it. The
   WORDS are unchanged. Contrast is measured against the pixels actually
   behind each line (`tools/_hero_contrast.mjs`). */
/* ⭐ D468: THE KICKER, "A POKER COACHING APP" -- small caps (the text is
   written in sentence case and set in CAPITALS by CSS, so a screen reader
   reads words, not letters), one line, at the 18px floor. */
.hero-kicker{
  font-family:var(--font-display); font-weight:700; font-size:max(18px,1.15cqw);
  letter-spacing:.14em; text-transform:uppercase; color:var(--cream);
  margin:0 0 .45cqw; white-space:nowrap;
}
.hero-kicker, .hero-h1, .hero-sub, .hero-protect{
  opacity:1;
  text-shadow:0 1px 2px rgba(0,0,0,.9), 0 0 10px rgba(0,0,0,.7), 0 0 22px rgba(0,0,0,.45);
}
.hero-sub, .hero-protect{ font-weight:500; }

/* ---- the two signs ------------------------------------------------------- */
/* ⛔⛔ EVERY TIER-1 RULE CARRIES `!important`, AND IT IS LOAD-BEARING RATHER THAN
   TIDY. `legibility-floor` writes `max(18px, 1em) !important`, which beats a
   plain design rule -- so without it `.sign-top` and `.cave-cta` clamp to 18px,
   the token reads 25.1px, and the ruling is INERT while looking applied. That is
   the `max()`-floor family, and #174 counts nine of them. Tier 2 deliberately
   does NOT declare it: 1.05cqw is 15.1px on a capped plate, so the floor is
   right to lift it to 18 and the hierarchy is 25.1 against 18. */
.sign-top{ font-family:var(--font-display); font-weight:700; font-size:var(--sign-t1) !important;
           letter-spacing:.14em; color:var(--cream); opacity:.88; margin:0; }
.sign-list{ font-family:var(--font-body); font-size:var(--sign-t2); letter-spacing:.02em;
            color:var(--cream); opacity:.80; margin:.35cqw 0 .3cqw; }
.sign-head{ font-family:var(--font-display); font-weight:700; font-size:var(--sign-t1) !important;
            letter-spacing:.06em; margin:0; }
.cave-head{ font-family:var(--font-display); font-weight:700; font-size:var(--sign-t1) !important;
            letter-spacing:.1em; color:var(--cream); opacity:.9; margin:0; }
/* ⚠️ `.2cqw`, not `.3`. MEASURED: at .3 the third line overflowed the cave zone
   by 1.3px. The gap yields rather than the type, because the type is already AT
   the 18px floor and shaving it would buy 1.3px of layout with legibility. */
.cave-list{ font-family:var(--font-body); font-size:var(--sign-t2); letter-spacing:.02em;
            color:var(--cream); opacity:.72; margin:.2cqw 0; }
.cave-cta{ font-family:var(--font-display); font-weight:700; font-size:var(--sign-t1) !important;
           letter-spacing:.06em; margin:0; }
/* ⭐ GOLD IS SPENT ONCE PER SURFACE. */
.hz .gold{ color:var(--gold,#C9A84C); }

/* ---- the ON BOARD strip · PART 2's internal fractions --------------------- */
.strip-label{
  flex:0 0 16.3%;                      /* PART 2, exactly */
  font-family:var(--font-display); font-weight:700; font-size:1.15cqw;
  /* ⭐ .10em, NOT .16 — Eric, 2026-10-04 ruling 3: *"ON BOARD: tracking .16em
     -> .10em. Do NOT exempt it from the 18px floor; it is a label and the
     floor holds."* ⚠️ MEASURED why it was needed: `1.15cqw` is 14.63px at
     1287 and the floor clamps it UP to 18, so the ink grew past the painted
     box it was tracked for. At .16em the ink spans 8.59% of the plate against
     a painted interior of 8.07% — over on both sides. ⛔ The fix is the
     tracking and never the size: the floor is not negotiable here. */
  letter-spacing:.10em; color:var(--cream); opacity:.9; margin:0; text-align:center;
  /* ⛔⛔ AND IT IS CENTRED ON ITS PAINTED FRAME, NOT ON THE STRIP BOX — Eric,
     2026-10-04: *"on board is not centered vertically."*
     ⭐⭐ MEASURED off `hero-plate.png`: the ON BOARD frame is four painted
     strokes — verticals at x 2.66-2.81% and 10.88-11.00%, horizontals at
     y 73.79-74.07% and 82.23-82.45% — so its interior is y 74.07..82.23%,
     centre 78.15%. The live ink sat at 79.39..82.56%, centre 80.98%: 2.83% of
     plate LOW, which is 20.5px at 1287, and its bottom actually CROSSED the
     frame's bottom stroke.
     ⚠️ THE CAUSE IS NOT THIS ELEMENT. `.hz-strip` is `align-items:center` and
     the strip box is 72..90.2%, so centring in it put the label at 81.1% —
     correctly centred on the BOX. The box is taller than the painted content
     because it was sized to the painted PANEL (71.96..90.12%), and the panel
     includes the slot of the CUT NAME ROW. ⛔ The rings have the same problem
     and it is NOT fixed here: moving the portraits off their painted rings is
     the 2026-10-03 defect. See `000-OPEN-FOR-ERIC-2026-10-04.md`.
     ⭐ -15.5% of the strip's own height is -2.82% of plate, which lands the
     ink centre on the frame centre. DERIVED, not nudged: re-measure the four
     strokes if the plate is ever re-cut.
     ⭐ And -0.13% of the strip's width horizontally, for the same reason one
     axis up: `text-align:center` centres the ink in the FLEX ITEM, which
     spans 1.8..12.05% of plate while the painted frame spans 2.81..10.88% —
     two different boxes whose centres are 0.08% of plate apart. Without it
     the 0.14% of slack sits entirely on the left and the ink's right edge
     lands exactly on the stroke. */
  position:relative; top:-15.5%; left:-0.13%;
}
/* ⛔⛔ BELOW A 1368px PLATE, "ON BOARD" STACKS ON TWO LINES — Eric, 7 Oct: *"ON
   BOARD does not fit into the black box"* (his screenshot, at his width).
   ⭐ MEASURED (headless Chrome, canvas ink at the computed font): the ink is
   **98.4px at every width**, because the 18px floor holds the size, while the
   painted interior is 8.07% of the plate (the strokes above): 115.7px at a 1434
   plate, 110.2 at 1366, 103.3 at 1280, **96.8 at 1200 — over**. Edge to edge by
   ~1280, outside the frame below ~1219.
   ⛔ BOTH LEVERS ARE RULED: the size is the floor ("Do NOT exempt it") and the
   tracking is .10em (ruling 3). So the words stack instead: "BOARD" alone is about
   five-eighths of the ink and fits the interior down to the phone band's 761.
   The 1368 is the plate where a single line keeps ≥6px each side (interior ≥
   98.4 + 12). ⚠️ Re-derive it if the font, the floor or the tracking moves.
   ⭐ IN WINDOW WIDTH (D279, scrollbar named): plate = window − the page's vertical
   scrollbar, 15px on Windows Chrome (stated, not measured here; 0 on phones and in
   headless Chrome). So the words stack below a **~1383px window** on a desktop
   with a scrollbar, and below 1368 where there is none.
   Below 761 the plate stops being the container, so this does not apply to the
   phone band's own label rule. */
/* ⭐ AND .11em DOWN: `top:-15.5%` above centres ONE line's ink on the frame. Two
   lines at line-height 1 put the ink 2.0px high (ink gap top vs bottom: 11.4/15.4
   at 1280, 9.5/13.6 at 1200, 7.2/11.3 at 1100, measured off canvas font metrics),
   and 2px is .11em of 18.
   ⛔ A LIMIT, NOT FIXED, FOR ERIC: below a ~900px plate (a ~915px window with the
   15px scrollbar, D279), "BOARD" alone at the
   18px floor clears the frame by under 2px (1.0px at 866; ink −1.6px past the
   left stroke at 800). Only the size or the tracking can fix that, and both are
   his rulings. Guard: tools/_on_board_fit.mjs (plates ≥900, 2px clearance, with
   a planted single-line control). */
@container plate (max-width:1367px){
  .strip-label .sl-in{ display:inline-block; width:min-content; line-height:1;
                       position:relative; top:.11em; }
}
.strip-riders{
  flex:1 1 83.7%;                      /* the eight share the remainder */
  list-style:none; margin:0; padding:0;
  display:flex; align-items:center; justify-content:space-around; height:100%;
}
/* ⭐⭐ PART 2 TRANSLATES DIRECTLY, WITH NO ARITHMETIC. The strip already has
   `height:var(--strip-h)`, so a percentage on a child resolves against the
   STRIP's own height — "size 54% of strip height" and "centre 30% down the
   strip" are literally those two numbers.
   ⛔ A first cut computed the size in `cqw` from the aspect ratio and the strip
   fraction. It was unreadable, it put a second copy of 1672:941 in a width, and
   a reader could not have checked it against the spec. ⚠️ And a MARGIN would not
   work here even though it looks like it should: a percentage margin resolves
   against WIDTH, not height. */
/* ⭐⭐⭐ EACH PORTRAIT SITS ON ITS OWN PAINTED CIRCLE — Eric, 2026-10-03,
   "Centre the avatars", and the measurement is what turned that into a number.
   ⛔⛔ THE ON BOARD PANEL IS PAINTED INTO THE PLATE, INCLUDING EIGHT CIRCLE
   SLOTS. Measured off `assets/website/hero-plate.png`: eight rings, identical
   to two decimals, centred at these plate percentages —
       14.61  21.07  27.52  33.98  40.45  46.90  53.36  59.83   (pitch 6.46%)
   and every one spanning y 73.01% - 82.84%, centre 77.93%, height 9.83%.
   ⚠️ THE FLEX CELLS DID NOT AGREE WITH THEM. Eight equal cells across the
   riders box give a pitch of 6.58%, so the error ACCUMULATED left to right:
   +0.74% at the first slot and +1.58% at the eighth, which is 29% of a
   portrait's own width. The painted rings showed through above and to the LEFT
   of every face, by more each time.
   ⭐⭐ AND THE SIZE WAS ALREADY EXACT — the portrait measures 9.83% of plate
   height and so does the ring, to two decimals. PART 2's `height:54%` is
   untouched; only the CENTRES move. "Not centred" was the whole of it.
   ⚠️⚠️ THE FRACTIONS BELOW RESOLVE AGAINST `.hz-strip`, NOT AGAINST THE RIDERS
   BOX, AND THAT IS DELIBERATE RATHER THAN ACCIDENTAL — though it was found by
   accident. `.strip-riders` declares no `position`, so an absolutely positioned
   `li` resolves against the nearest positioned ancestor, which is the zone. A
   first cut wrote riders-box fractions and the portraits landed on the ON BOARD
   label. ⭐ The zone is the BETTER anchor: it depends on `--strip-x` and
   `--strip-w` only, and NOT on the label's 16.3% — one fewer layer between a
   measured number and where the glyph lands.
   ⛔ They are still coupled to those two variables, so `tools/_strip_rings.mjs`
   drives the rendered page and reports any portrait that has left its painted
   ring; that is what makes the coupling safe rather than hopeful. */
.strip-riders li{
  position:absolute; top:0; bottom:0; width:12%;
  transform:translateX(-50%);
}
/* ⭐⭐⭐ D477 (Eric, 14 Oct): THREE GROUPS, FOUR EQUAL GAPS — and the strip changes
   in POSITION ONLY. Removing ON BOARD left 145px of dead panel at the left with
   the nine rings bunched right of it. Groups left to right: the four people,
   the four fish, Tiger. Gaps: panel edge → group 1 → group 2 → group 3 → edge,
   all X, where X = (inner width − nine rings − six in-group gaps) / 4.
   ⛔ THE EIGHT RINGS WERE PAINTED (spec 140 says the plate's surfaces are drawn
   EMPTY; the strip is the exception — rings and the ON BOARD frame are in the
   picture). So `.strip-ring-cover` hides the painted eight in the panel's own
   fill (MEASURED flat: 69,349 px, rgb(4,24,36), sd 0.00) and each portrait's
   ring is drawn by `li::before`, below — the PAINTED rim reproduced, not Tiger's.
   ⭐ EVERY NUMBER BELOW IS A MEASUREMENT OFF `hero-plate.png` (3200 px wide),
   in plate px, and the positions are DERIVED from them by calc(), never typed:
     --pl  55      the panel's inner left edge (luminance scan, mid-height)
     --pr  2303.4  `.strip-ext`'s inner right edge (72.075% x 3200, less its 3px rim)
     --ring 177    a painted ring's diameter (9.83% of plate height)
     --pitch 206.7 ring to ring inside a group (6.46% x 3200, the painted pitch)
     --tig 194.7   Tiger's circle, 1.10 x the ring (D258, D335)
     --zx/--zw     the strip zone's own left and width (1.8% and 62.9% of 3200),
                   the frame every `left` below resolves against. */
.hz-strip{
  --pl:55; --pr:2303.4; --ring:177; --pitch:206.7; --tig:194.7; --zx:57.6; --zw:2012.8;
  --gx:calc((var(--pr) - var(--pl) - 8 * var(--ring) - var(--tig) - 6 * (var(--pitch) - var(--ring))) / 4);
  --g1:calc(var(--pl) + var(--gx) + var(--ring) / 2);                                  /* ring 1's centre */
  --g2:calc(var(--g1) + 3 * var(--pitch) + var(--ring) + var(--gx));                   /* ring 5's centre */
  --g3:calc(var(--g2) + 3 * var(--pitch) + var(--ring) / 2 + var(--gx) + var(--tig) / 2); /* Tiger's centre */
}
.strip-riders li:nth-child(1){ left:calc((var(--g1) - var(--zx)) / var(--zw) * 100%); }
.strip-riders li:nth-child(2){ left:calc((var(--g1) + 1 * var(--pitch) - var(--zx)) / var(--zw) * 100%); }
.strip-riders li:nth-child(3){ left:calc((var(--g1) + 2 * var(--pitch) - var(--zx)) / var(--zw) * 100%); }
.strip-riders li:nth-child(4){ left:calc((var(--g1) + 3 * var(--pitch) - var(--zx)) / var(--zw) * 100%); }
.strip-riders li:nth-child(5){ left:calc((var(--g2) - var(--zx)) / var(--zw) * 100%); }
.strip-riders li:nth-child(6){ left:calc((var(--g2) + 1 * var(--pitch) - var(--zx)) / var(--zw) * 100%); }
.strip-riders li:nth-child(7){ left:calc((var(--g2) + 2 * var(--pitch) - var(--zx)) / var(--zw) * 100%); }
.strip-riders li:nth-child(8){ left:calc((var(--g2) + 3 * var(--pitch) - var(--zx)) / var(--zw) * 100%); }
/* ⭐ THE PAINTED RING, DRAWN. MEASURED: a radial profile through all eight
   painted rings at 16 angles each (median), by offset d from the ring's edge
   (88.5 plate px): the dark disc inside (d -8..-6), a dark line (d -5..-4), the
   3px bright stroke (d -2..0), a dark shadow outside (d +1..+2), a faint light
   line (d +4), then flat panel from d +5. Each stop below IS one measured offset,
   as a fraction of the drawn radius 93.5 (88.5 + 5). `closest-side` makes 100%
   that radius, so the profile scales with the plate exactly as the painting did. */
.strip-riders li:not(.strip-coach)::before{
  content:''; position:absolute; left:50%; top:32.6%; transform:translate(-50%,-50%);
  height:calc(54% * 93.5 / 88.5); aspect-ratio:1; border-radius:50%; pointer-events:none;
  /* ⚠️ Every stop sits 1 plate px INSIDE its nominal offset (−1.07% of 93.5),
     FITTED by measurement at 1x, old against new, ring 6 (a transparent
     portrait), summed |Δ luminance| across the rim (offsets −2 to +0.5 CSS px):
     unshifted 261.8 · 0.5 px 160.1 · ⭐ 1 px 145.7. The peak lands at the painted
     offset (187 vs 192); what is left is the painting's half-pixel downscale blur
     on the stroke's outer edge, which a crisp gradient does not reproduce. */
  background:radial-gradient(closest-side,
    rgb(2,15,23) 85.03%, rgb(6,20,28) 86.10%, rgb(6,18,27) 87.17%, rgb(0,0,0) 88.24%,
    rgb(5,12,19) 89.30%, rgb(80,87,94) 90.37%, rgb(204,216,217) 91.44%,
    rgb(216,228,229) 92.51%, rgb(149,161,168) 93.58%, rgb(2,15,27) 94.65%,
    rgb(0,7,20) 95.72%, rgb(4,24,35) 96.79%, rgb(7,29,40) 97.86%, rgb(4,24,36) 98.93%);
}
/* ⭐⭐ TIGER, THE NINTH RIDER — D257/D258, 6 Oct. Eric: at the right end, his circle
   10% larger than the eight, TIGER / COACH under him. No painted ring exists for
   him, so the panel is CONTINUED (`.strip-ext`, below) and his ring is drawn.
   ⭐ DERIVED FROM THE PAINTING (`tools/_tiger_strip_render.mjs`): ring 8 spans plate
   x 1826-2003 (177px); the painted gap between rings is 29.7px. Tiger's circle is
   1.10 x 177 = 194.7px, one painted gap right of ring 8 — centre x 2130.05 — on
   the rings' own centre line, so `top:32.6%` is unchanged. In strip-zone terms:
   (2130.05 - 57.6) / 2012.8 = 102.964%; height 54% x 1.10 = 59.4%.
   ⚠️ He sits OUTSIDE the zone's box (>100%), on purpose: the zone is the painted
   panel's, and he is on its continuation. */
/* D477: Tiger's centre is --g3 (was a typed 102.964%, plate 66.564%) */
.strip-riders li.strip-coach{ left:calc((var(--g3) - var(--zx)) / var(--zw) * 100%); }
.strip-riders li.strip-coach img{ height:59.4%;
  box-shadow:0 0 0 max(1px,.094cqw) rgb(155,186,193); }   /* the painted rim, 3 plate px */
/* ⭐ THE PANEL, CONTINUED. Measured off `hero-plate.png`: fill rgb(4,24,36); rim
   3px rgb(155,186,193), top 1292-1295, bottom 1625-1628; a back card offset 29px
   right, y 1324-1553, rim rgb(93,118,130). The extension starts at x 2012 (clear
   of ring 8's rim at 2003), so it covers the painted right end and its back card,
   and ends the painted margin (79px) past Tiger's circle: x 2306.4.
   ⚠️ Plate percentages, like every zone. Hidden in the phone band. */
.strip-ext, .strip-ext-card{ position:absolute; pointer-events:none; box-sizing:border-box; }
.strip-ext{ left:62.875%; top:71.738%; width:9.200%; height:18.712%;
  background:rgb(4,24,36); border:max(1px,.094cqw) solid rgb(155,186,193); border-left:0;
  border-radius:0 1.25cqw 1.25cqw 0; }
.strip-ext-card{ left:67.700%; top:73.515%; width:5.281%; height:12.715%;
  background:rgb(4,23,36); border:max(1px,.0625cqw) solid rgb(93,118,130);
  border-radius:1.25cqw; }
/* ⭐ D469/D471 · THE "ON BOARD" FRAME GOES WITH ITS LABEL. The frame is PAINTED
   into `hero-plate.png`, so removing the label left an empty box on the panel.
   This covers it with the panel's own fill, the same technique as `.strip-ext`.
   MEASURED off the plate (luminance profiles through the frame's centre lines):
   stroke plus dark halo x 83-355 and y 1327-1488 of 3200 x 1801; flat panel
   rgb(4,24,36) on every side (std-dev 0); ring 1's halo begins at x 375. The
   cover is x 76-362, y 1322-1493 (a ~6 plate-px margin, ~2.7 CSS px at 1440),
   clear of the panel rim (x 50-55, y 1292-1295) and of ring 1. */
/* ⭐ D477 · THE EIGHT PAINTED RINGS GO UNDER THE PANEL'S OWN FILL, so the drawn
   rings (li::before) can sit anywhere. MEASURED off the plate: the painted rings
   span x 374-2008 and y 1310-1497 with their outer shadow (centres 14.61-59.83%,
   radius 88.5 + 5); the ground around them is flat rgb(4,24,36), sd 0.00 over
   69,349 px. Cover: x 340-2012 (where `.strip-ext` begins), y 1304-1503. It
   overlaps `.strip-frame-cover` on 340-362, which is the same fill. */
.strip-ring-cover{ position:absolute; pointer-events:none;
  left:10.625%; top:72.404%; width:52.25%; height:11.049%; background:rgb(4,24,36); }
.strip-frame-cover{ position:absolute; pointer-events:none;
  left:2.375%; top:73.404%; width:8.938%; height:9.495%; background:rgb(4,24,36); }
.strip-riders img{
  /* ⛔⛔ `top:30%` AND `height:54%` WERE PART 2's FRACTIONS, AND THE 30% EXISTED
     TO LEAVE ROOM FOR NAMES THAT WERE NEVER BUILT. Under the FACES-NO-NAMES
     ruling nothing ever occupied the lower 70%, so the circles sat in the top
     third of the row -- MEASURED at 1920: the image centre was 39px ABOVE the
     cell centre and filled 54% of its height. That is Eric's "not centred and
     not big enough", and it is the IMAGE inside its cell rather than a zone
     variable, so it is fixable here.
     ⚠️ NAMES ARE NOW RULED AND THIS WILL HAVE TO MOVE AGAIN. When a name line
     lands the circles go back above it -- but the fraction must then be set
     against a `--strip-h` that HOLDS both, which is the solve the relay has
     and has not ruled on. Centring is right for the page as it ships today.
     ⭐ ONLY THE CENTRING MOVED. `height:54%` is PART 2's and is untouched: Eric's
     "bigger" was about the HUMANS and he withdrew half of it, and the villain
     crops are already centred WITHIN their own files -- measured, dx/dy <= 4px
     on all four -- so the cell offset was the whole defect. */
  /* ⭐ `top:32.6%`, NOT 50%. The painted ring's centre is at 77.93% of the
     PLATE and the strip zone runs 72% to 90.2%, so the ring sits
     (77.93 - 72) / 18.2 = 32.6% down the strip. At 50% the portrait centred at
     81.09% — 3.17% of plate height BELOW its own ring, which is the other half
     of "centre the avatars". */
  position:absolute; left:50%; top:32.6%;
  transform:translate(-50%,-50%);
  height:54%; width:auto; aspect-ratio:1;
  border-radius:50%; object-fit:cover; display:block;
}

/* ⭐⭐ THE NAMES UNDER THE CIRCLES — D247, D250, D253-D256, 6 Oct.
   The painted panel keeps a band under its rings that was always meant for names
   (D247: Eric's fourteen "not centred" reports were the empty band). Two
   ALTERNATING rows, each name under its own circle (D250), the eight from `140`'s
   row with "The" dropped (D253) — written by `tools/gen_strip_names.py`, never
   typed here.
   ⭐ SHOWN ON A PLATE >= 1075px (D270, 7 Oct; D256 had 1287). D256's reason — "no
   leading fits two readable 18px rows" below 1287 — was a leading rule (1.24 put the
   second row on the edge at 1080); measured by INK, these rows stay 4.5px apart
   and exactly centred down to 1075, where the 12px same-row gap stops them. Below
   1075 the eight show no names (D254's compromise band, now 761-1074).
   ⭐ A CONTAINER query on `.hero-plate` (already `container-name:plate`) measures the
   PLATE, which is ~15px narrower than the WINDOW when a desktop scrollbar shows:
   1075 here is a ~1090px window.
   ⭐ GEOMETRY, DERIVED FROM THE PAINTING (D247): the band is 132 plate px, the gap
   above the rings 19. Rows of (132-19)/2 = 56.5 plate px = 1.766cqw leave 19
   below, so the strip is EXACTLY centred at every width this shows (22.7px of
   leading at 1287 = 1.26 x the type; 25.3px = 1.41 at 1434). Row 1 starts at the
   portrait's bottom — 32.6% + 54%/2 = 59.6% of the strip, the painted ring's
   bottom edge. `tools/_strip_vertical_balance.mjs` (BOT 6) holds both branches. */
/* ⭐ STYLED ONCE, SHOWN BY WIDTH: the look is set here and only `display` varies
   by the container queries below, so the two widths cannot drift apart. */
.strip-name{
  display:none; position:absolute; left:50%; top:59.6%; transform:translateX(-50%);
  white-space:nowrap; pointer-events:none;
  font-family:var(--font-display); font-weight:700; font-size:18px;
  letter-spacing:.10em; text-transform:uppercase; color:var(--cream);
  line-height:1.766cqw;
}
.strip-riders li:nth-child(even) .strip-name{ top:calc(59.6% + 1.766cqw); }
/* ⭐⭐ TIGER / COACH, PLACED BY THEIR INK — D261, D262 (Rule 58: the box is not
   the shape). The space under his circle is the panel's inner bottom (plate y
   1625) less the circle's bottom: 1.10x circle bottom 1500.93 -> 124.07 plate px =
   3.877cqw, the circle's bottom at 62.3% of the strip. Each word is 14px of ink at
   18px (13 ascent + 1 descent; content box 23px: ink runs 5px..19px down a 23px
   line). Three equal gaps, g = (free - 28px) / 3: above TIGER, between, below COACH.
     TIGER line top = circle bottom + g - 5px
     COACH line top = circle bottom + 2g + 9px      (= g + 14px + g, less the 5px)
   g is ~9px at 1440, ~1.1px at an 807px plate. Below 807 two lines do not fit at
   readable spacing, so TIGER stands alone there (D263, below); the circle is the
   eight's size there (D262), so his line sits under 59.6%. */
.strip-riders li.strip-coach .strip-name{ line-height:23px;
  top:calc(62.3% + (3.877cqw - 28px) / 3 - 5px); }
/* ⭐⭐ D469/D471 · THE TWO GROUP HEADINGS, in the band the eight names used.
   ⭐ DERIVED, NOT NUDGED:
   · horizontally, each is centred on its group: the mean of its first and
     fourth ring's `left` above (rings are pinned at their centres), so
     (20.366 + 51.160) / 2 = 35.763% and (61.446 + 92.258) / 2 = 76.852% of the
     strip zone;
   · vertically, ONE row centred in the band the names' TWO rows filled
     (2 x 1.766cqw from the ring's bottom at 59.6%), so the panel's vertical
     balance (19 plate px above the rings, 19 below the type) is unchanged;
   · the names' exact type: Space Grotesk 700, 18px (the floor), .10em.
   ⭐ The ruled fallback: "COMPUTER OPPONENTS" below a 1004px plate does not
   clear its group's span with 8px a side (measured: 234px of ink against a
   span of 255px at a 1024 plate, scaling with the plate while the type holds
   at 18px), so "THE COMPUTER" shows there. Re-measure if the type moves. */
.strip-group{
  /* ⭐ ON THE OLD SECOND NAME ROW'S LINE: its box ends 113 plate px under the
     rings (2 x 1.766cqw from 59.6%), so the strip's content ends 19 plate px
     above the panel's inner bottom, as it starts 19 below the top (D247).
     ⛔ A first cut centred the one row in the band (59.6% + .883cqw) and
     `check_strip_balance` failed it at every width: 7px above vs 17px below. */
  /* ⭐⭐ AND ANCHORED BY ITS BOTTOM, not its top: below an ~900px plate the 18px
     type is TALLER than a 1.766cqw row, so a top-anchored box grows downward
     into the rim (1.3px at 807, 0.2px at 761, measured). The gap under the ink
     is set equal to the gap over the rings -- the ring's top is 32.6% - 54%/2 =
     5.6% of the strip -- plus .115em, MEASURED: anchoring at 5.6% - .19em
     left the gap under the heading exactly 5.5px short of the gap over the
     rings at EVERY width (1440, 1287, 1024, 807, 761), a constant that is a
     property of the 18px line box, so it is written in em and holds everywhere. */
  position:absolute; top:auto; bottom:calc(5.6% + .115em); line-height:1; margin:0;
  transform:translateX(-50%); white-space:nowrap; pointer-events:none;
  font-family:var(--font-display); font-weight:700; font-size:18px;
  letter-spacing:.10em; text-transform:uppercase; color:var(--cream);
}
/* D477: each heading centred on its own group's span (ring 1 to ring 4's centre
   midpoint = g + 1.5 pitches), derived, so it moves with the group */
.strip-group--people{ left:calc((var(--g1) + 1.5 * var(--pitch) - var(--zx)) / var(--zw) * 100%); }
.strip-group--computer{ left:calc((var(--g2) + 1.5 * var(--pitch) - var(--zx)) / var(--zw) * 100%); }
.strip-group .sg-short{ display:none; }
@container plate (max-width:1003.98px){
  .strip-group .sg-long{ display:none; }
  .strip-group .sg-short{ display:inline; }
}
.strip-riders li.strip-coach .strip-role{
  top:calc(62.3% + (3.877cqw - 28px) * 2 / 3 + 9px); }
/* ⛔ D335 (Eric, 9 Oct): "RESTORE TIGER'S CIRCLE TO 1.10x below an 807px plate"
   (supersedes D262). The 54% override that made him the eight's size below 807
   is removed: D262's reason was the two lines, and D263 put TIGER alone there.
   check_strip_balance asserts 1.10x at every width, with 1px of ink clear. */
/* ⭐ D261 as amended by D263: TIGER over COACH wherever two lines fit at readable
   spacing — a plate >= 807px — and TIGER alone on 761–806; below 1287 he is the
   only one named. The lines are placed by their ink (above), and
   `_strip_vertical_balance.mjs` fails if any ink gap is under 1px.
   ⚠️ The phone band makes the plate a non-size container, so neither query
   matches there and no name shows. */
@container plate (max-width:1286.98px){
  .strip-riders li.strip-coach .strip-name{ display:block; }
}
/* ⭐⭐ D270 (7 Oct): THE NAMES SHOW FROM A 1075px PLATE — a ~1090px WINDOW, allowing
   ~15px for a desktop scrollbar — with D256's exactly-centred rows unchanged.
   MEASURED by `tools/_strip_names_floor.mjs`: the rows that centre the strip at 1287
   stay exactly centred all the way down (error -0.3px, the guard allows 2), and
   what stops them is horizontal — Tuna's name beside Tiger's COACH reaches D250's
   12px same-row gap at a 1075px plate. The ink-placed alternative (b) stops at the
   SAME plate and costs 4-5px of centring, so it was not built. */
@container plate (min-width:1075px){
  .strip-name{ display:block; }
}
/* ⭐ D263 (Eric, §18e, amending D261): on a 761–806px plate two lines cannot sit at
   readable spacing (1.2px of ink between them), so TIGER stands ALONE there, one
   line, centred by ink in the space under the circle: g = (4.154cqw - 14px) / 2.
   ⚠️ After the <=1286 query on purpose — same specificity, so source order hides
   COACH here. */
@container plate (max-width:806.98px){
  .strip-riders li.strip-coach .strip-role{ display:none; }
  .strip-riders li.strip-coach .strip-name{ top:calc(59.6% + (4.154cqw - 14px) / 2 - 5px); }
}

/* ---- the CTA pill -------------------------------------------------------- */
.hz-cta{
  /* ⭐ D484 (Eric, 15 Oct, CTA18): D303's 18px floor on the primary action. It
     was 1.3cqw alone, so it fell to 9.89px at a 761 plate and stayed under 18
     up to 1384 (MEASURED). The plate starts at 853 now (D489), where 18px fits
     the painted pill on one line. */
  font-family:var(--font-display); font-weight:700; font-size:max(18px,1.3cqw);
  letter-spacing:.02em; text-decoration:none;
  /* ⛔⛔ NOT `999px` — THE PAINTED PLAQUE IS ASYMMETRIC, 6 Oct. Nearly square at
     the TOP, round at the BOTTOM (the 5 Oct handoff §4.1: top inset ~10-13% of its
     height, bottom ~half). A fully round pill left its upper corners showing —
     Eric, on the live page: "gold behind green CTA". MEASURED by
     `tools/_cta_gold_residue.mjs`: 209 / 142 / 83 / 53 gold px at 1440 / 1287 /
     1024 / 761 with `999px`; 63 / 24 / 14 / 14 with this. ⭐ `.32cqw` is ~12% of
     the pill's height (`--cta-h` is 2.75cqw) and was FITTED by those pixels, not
     typed from the note. The bottom is `1.38cqw`, half the height: fully round.
     ⛔⛔ NEVER `999px` BESIDE A SMALL RADIUS. CSS scales ALL FOUR radii down by
     one factor whenever two on a side exceed the box, so `.32cqw ... 999px`
     squared the bottom corners too — 412px of gold at 1440 instead of 63. The
     guard's transition test caught it before commit.
     ⚠️ What remains is a sub-pixel hairline where the painted edge sits ~1px
     outside the zone; a spread to cover it crossed into the strip (4 Oct, below).
     `check_painted_cover.py` (BOT 6) holds this. */
  /* 9 Oct (D304): the bottom stays fully round at the new height, 3.30cqw → half = 1.65cqw */
  border-radius:.32cqw .32cqw 1.65cqw 1.65cqw;
  /* ⛔⛔ THE GOLD PILL IS PAINTED INTO THE PLATE, NOT DRAWN HERE -- measured:
     at 1920 this element's own background is `rgba(0,0,0,0)` and 98% of the
     plate pixels inside the CTA zone are gold. The live control has only ever
     been transparent text sitting on a painting, which is why the hero CTA
     never matched the site's buttons.
     ⭐ SO GREEN IS A LIVE PILL DRAWN OVER THE PAINTED ONE, and it CONSUMES the
     tokens the page already declares rather than typing a second hex --
     `.btn-primary` uses exactly these two.
     ⛔⛔ THE SPREAD IS GONE — 2026-10-04, and it was the thing Eric kept
     reading as "too high". It existed to cover the gold the zone left showing,
     and `box-shadow:0 0 0 .35cqw` is a WIDTH unit applied in four directions
     on a 1.777 plate: 0.35% of width is 0.62% of HEIGHT, against gold margins
     measured at 0.16 left / 0.01 right / 0.15 top / 0.04 bottom. So it
     over-covered vertically by roughly 0.5% each way and the green crossed
     into the strip panel's painted bottom edge.
     ⭐ The zone is now READ OFF the plate instead, so every margin is zero and
     there is nothing left to cover. A single spread cannot cover four
     different margins; the fix is the geometry, not a smaller ring.
     ⛔⛔ AND A RIM STILL SHOWED — Eric, 6 Oct night (D267): "there is still gold
     behind the green CTA". Measured: the fitted radius left 63 / 24 / 14 / 14 gold
     px (1440 / 1287 / 1024 / 761), ALL just outside the button. ⭐ So the spread
     returns WITHOUT its old fault: `0 1.5px 0 1.5px` grows the green 1.5px left,
     right and 3px down, and its TOP stays exactly where it was (offset 1.5 cancels
     spread 1.5), so it cannot cross into the strip. Gold: 3 / 5 / 1 / 0 px — the
     residue is at the very top, which only crossing the strip could cover.
     FITTED by `CTA_SHADOW=... node tools/_cta_gold_residue.mjs`, not typed.
     ⭐⭐ D384 (Eric, 9 Oct): "FIX THE GOLD … Do not accept the clip." The 3 / 5 / 1
     / 0 px left were ONE ROW, directly above the top edge, in the top-left corner
     (MEASURED: crop y = pad−1, x 3–7 px in). Green there is the 4 Oct bleed. So a
     second layer, BELOW the green, paints that one row in `--panel`, the strip
     rim's own dark: `0 -1px 0 0`. MEASURED: gold 0 / 0 / 0 / 0. The diff against
     the shipped render changes exactly that row (332 / 298 / 236 / 176 px), and
     every changed pixel got DARKER (0 lighter), so no green reaches the panel. */
  background:var(--accent); color:var(--accent-ink);
  box-shadow:0 1.5px 0 1.5px var(--accent), 0 -1px 0 0 var(--panel);
}
.hz-cta:hover{ filter:brightness(1.06); }

/* ---- V1 · the signature is BODY TEXT below the CTA, not on the plate ------ */
/* ⛔⛔ REGION F WAS BUILT HERE AND REVERTED, AND THE REASON IS GEOMETRY RATHER
   THAN TASTE. The respec puts this block on the plate at x 50% · y 86% ·
   w 44% · h 9%. MEASURED at eleven widths after building it exactly as ruled:
   it fits at 1434 (10px spare), 1360 (8px) and 1280 (5px), and from 1200 down
   to the phone band at 761 it OVERFLOWS ITS ZONE AND COLLIDES WITH THE RIDER
   STRIP -- by 23px at 1200, 28px at 1100, 61px at 1024 and 74px at 762.
   ⭐ THE CAUSE IS STRUCTURAL AND CANNOT BE TUNED AWAY: `h:9%` is a fixed
   FRACTION of plate height while the type has a fixed FLOOR of 18px, which
   Part 5 exempts for hero SIGN lettering and explicitly for "nothing else".
   Below ~1250 the content stops shrinking and the zone does not. The strip's
   own declared zone already reaches y 90.2%, so F's 86% start overlaps it by
   4.2% of plate height BY DECLARATION -- at 1434 the riders happen not to fill
   the bottom of their zone, which is why it looks clean on a desktop.
   ⛔ The brief's own instruction is why this is reported rather than shipped:
   "If any of it conflicts with what you measure tonight, YOUR MEASUREMENT WINS
   -- stop and report the conflict rather than following the instruction."
   ⚠️ And the fix is Eric's either way, because every route touches something
   that is his: his y/h numbers, his strip placement, or a second layout for
   one component below 1280. */
.hero-below{ padding:26px 0 34px; }
/* ⭐ ON THE PLATE NOW, so the type scales with it in `cqw` like every other
   live surface rather than with the VIEWPORT in `vw`. ⚠️ A `vw` size inside a
   plate that is capped at 1434px keeps growing after the plate stops, which is
   the mismatch that put the earlier Region F build through its own zone.
   ⛔ The 18px floor still applies — 250 PART 5 exempts hero SIGN lettering and
   this is not a sign, it is the signature. */
/* ⛔⛔ `!important`, AND IT IS NOT DECORATION — WITHOUT IT THIS CLAMP HAS NEVER
   ONCE TAKEN EFFECT. `legibility-floor.css` sets `body p { font-size:
   max(18px,1em) !important }`, and both these lines are `<p>`, so the floor has
   been beating the design at every width since the signature was written: it
   has rendered at 18px and never at its 30px display size, measured.
   ⭐ #43 is the ruling: the blanket floor stays exactly as it is, and the few
   elements the design deliberately sets ABOVE 18 carry `!important` in their
   OWN rule, where the number already lives. The four sign classes already do
   this; the signature was the one that did not. */
.hero-signature{
  font-family:var(--font-display); font-weight:700;
  /* ⛔⛔ THE CEILING IS 22px AND IT IS A MEASUREMENT, NOT A TASTE. 140 gives
     `--sig-w: 40%` and `--sig-y: 91.4%`, which at 1434 is a 574px zone with
     69px of plate beneath it. Swept: at 24px and above the first line WRAPS and
     the block becomes 86-100px — past the bottom of the painting. At 22px it
     holds one line and the block is 56px. ⭐ The whole overflow was that one
     wrap; the sub-line was never the problem.
     ⚠️ So the design's 30px display size is not available in 140's zone. Widening
     the zone or shortening the line are the only ways to get it back, and both
     are Eric's — the zone is his number and the copy is 140 PART 3's. */
  font-size:clamp(18px,1.53cqw,22px) !important;
  letter-spacing:.02em; color:var(--cream); margin:0; line-height:1.15;
}
/* ⛔ ITALIC, AND NOT GOLD — 140 PART 3, and it had been exactly the wrong way
   round. Gold is spent once per surface and the signature is not where it gets
   spent. */
.hero-signature em{ font-style:italic; }
.hero-signature-sub{
  font-family:var(--font-body); font-size:clamp(18px,1.2cqw,21px) !important;
  line-height:1.4;
  color:var(--cream); opacity:.82; margin:6px 0 0; max-width:62ch;
}

/* ===== PART 6 · THE PHONE ==================================================
   ⛔⛔ EVERY DESKTOP PIN IS EXPLICITLY UNDONE. PART 6 records a version that
   "piled eight names on top of each other because the absolute positioning
   survived the media query" — so `position:static` is set on `.hz` itself
   rather than relying on each zone, and the plate stops being a container.
   ⭐ Below the plate floor (760px when written; ≤852 since D489) the scene is a
   BACKDROP and the type stacks, in PART 6's own
   order: nav, headline, destination sign as a panel, cave sign as a panel,
   ON BOARD as a 4+4 grid, CTA, signature. */
/* ⭐⭐ D484 + D489 (Eric, 15 Oct, CTA18): THE STACK NOW RUNS TO 852px, up from 760.
   Eric: "below [the floor] the painted pill has no room, so that band takes the
   stacked layout." ⛔ D484 set the floor at 849 because 198.4px, which was the
   PILL's width at 849, was carried forward as the LABEL's width. The label is
   199.1px on one line (a Range rect, MEASURED 15 Oct) and needs 199.3px of pill,
   which first occurs at 853. At 849-852 it WRAPPED to two lines and spilled out
   of the pill; `check_home_occlusion` found it at the derived plate floor. Eric
   ruled (a): stack to ≤852, plate from 853 (D489). ⛔ The CTA's letter-spacing is
   NOT tightened to make 849 fit: "Start learning for free" is Eric's ruled label,
   and its appearance is not traded for 0.7px.
   ⚠️ The short-landscape block below (D319/D474, ruled as ≤760 x ≤500) moves
   WITH it, to ≤852 x ≤500, on a measurement: see that block's own comment. */
@media (max-width:852px){
  /* ⭐ NO HEADER CLEARANCE HERE, AND IT IS A CONDITION RATHER THAN A GUESS. The
     phone stack leads with the backdrop illustration, so the only thing under the
     fixed header is artwork — MEASURED: 13 readable surfaces at 390x844, none
     occluded. 130px of empty space above a banner would be a third of the first
     screen spent on nothing.
     ⚠️ If PART 6's order ever puts the headline first, this becomes the 1440
     defect on a phone — and `check_seat_occlusion --hero` fires at 390 and names
     it. The condition is enforced, not assumed. */
  .hero{ padding-top:0 }
  .hero-plate{ container-type:normal; aspect-ratio:auto; display:flex;
               flex-direction:column; gap:18px; padding:16px 16px 22px;
               background:#060C10; }
  .hero-plate > picture > img{ height:auto; aspect-ratio:1672/941;
                               border-radius:10px; opacity:.55; }
  /* ⛔ D246 CONDITION 2: NO TIGER OVERLAY DOWN HERE. The plate is a dimmed (opacity .55) flow
     image in a padded column, so nothing on it reads as a character at this size
     — the painted driver included — and the overlay's plate percentages would no
     longer land on him anyway. Hidden, not re-pinned. */
  .hero-driver{ display:none; }
  /* ⛔ the undo, stated once and applying to every zone */
  .hz{ position:static; left:auto; top:auto; width:auto; height:auto;
       max-width:none; transform:none; }
  .hz-head, .hz-sign, .hz-cave, .hz-strip, .hz-cta, .hz-sig{
       left:auto; top:auto; width:auto; height:auto; }
  /* ⭐ the signature joins the stack as flow text down here, after the CTA */
  .hz-sig{ order:5; margin-top:14px; }
  /* D471.5: the stake joins the stack too, immediately before the signature */
  .hero-stake{ position:static; order:5; width:auto; padding:0; margin-top:14px;
               font-size:18px !important; }
  .hz-sign, .hz-cave{ align-items:flex-start; text-align:left;
       border:1px solid rgba(244,246,245,.18); border-radius:12px; padding:14px 16px; }
  /* ⛔⛔ `!important`, AND IT IS THE ONE PLACE THE PAGE NEEDS IT. The desktop rule
     is `font-size:2.7cqw !important`, and an important declaration beats any
     ordinary one — so this clamp LOST from 2 Oct (`875280c4`) to 7 Oct, and with no
     size container down here `cqw` resolved against the viewport: the headline
     rendered at 10.1px on a 375px phone, smaller than its own body copy, under
     Eric's 18px floor. Important against important, the later rule wins.
     ⚠️ THE 30-42px VALUE IS NOT DERIVED FROM THE FLOOR AND NOTHING RULED IT. It is
     this rule's own clamp, written in the same 2 Oct rebuild (`875280c4`) and never
     rendered until now: 8vw is 30px at 375 and 31.2px at 390, 42px from 525 up.
     Making it win was CC's choice (7 Oct) — restoring the rebuild's stated phone
     intent rather than picking a new size. `tools/_heading_floor.mjs` reports any
     h1 under 18px (report-only pending open row §25). */
  .hero-h1{ font-size:clamp(30px,8vw,42px) !important; }
  .hero-sub{ font-size:19px; margin-top:10px; }
  .hero-protect{ font-size:18px; margin-top:10px; max-width:none; }
  /* ⭐ THE PHONE BAND OVERRIDES THE TWO TOKENS, NOT SIX FONT SIZES. The values
     are fixed px here because the plate stops being the container below 761px,
     so `cqw` has nothing to resolve against -- that is a responsive override of
     one rule, not a second copy of it. Tier 1 adopts the 22px `.sign-head`
     already shipped; tier 2 adopts 18px, Eric's floor. */
  .hero{ --sign-t1:22px; --sign-t2:18px; }
  .strip-label{ flex:none; font-size:18px; text-align:left; margin-bottom:10px; }
  .hz-strip{ flex-direction:column; align-items:flex-start; }
  .strip-riders{ display:grid; grid-template-columns:repeat(4,1fr); gap:12px;
                 width:100%; height:auto; }
  /* ⛔⛔⛔ PART 6'S OWN RECORDED DEFECT, AND I SHIPPED IT: "the absolute
     positioning survived the media query". The `.hz` undo above reaches the five
     ZONES; it does not reach a descendant with its own pin, and `.strip-riders
     img` carries `position:absolute; left:50%; top:30%; height:54%`.
     ⚠️ MEASURED at 390x844 before the fix: `li` 0px tall, img `cssH:0px`, the
     whole `ul` collapsed to 12px, 8 of 8 riders under 4px — so the eight faces
     were ABSENT, and the occlusion probe had silently dropped them from its
     corpus because a size filter cannot tell hidden from broken.
     ⭐ EVERY DESKTOP PIN UNDONE BY NAME: position, both offsets, the percentage
     height and the centring transform. A percentage height against an `auto`
     parent is the half that produced the zero. */
  /* ⛔ THE PAINTED RINGS DO NOT EXIST DOWN HERE. Below the plate breakpoint the
     strip is a 4-column grid of flow items, so every desktop pin is undone by
     name — the same discipline the img rule below already follows. */
  .strip-riders li{ height:auto; position:static; left:auto; width:auto;
                    transform:none; }
  .strip-riders img{ position:static; left:auto; top:auto; transform:none;
                     width:100%; height:auto; }
  /* D258: Tiger's desktop pins undone by name too; no panel to continue here */
  .strip-riders li.strip-coach{ left:auto; }
  .strip-riders li.strip-coach img{ height:auto; }
  .strip-ext, .strip-ext-card, .strip-frame-cover, .strip-ring-cover{ display:none; }
  /* ⭐ D485 (Eric, 15 Oct): THE ON BOARD FRAME IS COVERED ON PHONES TOO, the same
     percentage-of-plate box as `.strip-frame-cover`, here as the picture's own
     ::after because the stack makes the plate a flow image. Its fill is the
     panel as it RENDERS here: the image sits at opacity .55 over #060C10, so
     .55 x rgb(4,24,36) + .45 x rgb(6,12,16) = rgb(5,19,27). Only the frame: the
     painted rings stay, because the phone grid draws no rings of its own. */
  .hero-plate > picture{ position:relative; display:block; }
  .hero-plate > picture::after{ content:''; position:absolute; pointer-events:none;
    left:2.375%; top:73.404%; width:8.938%; height:9.495%; background:rgb(5,19,27); }
  /* D477: the drawn rings belong to the plate's strip; the phone grid has none */
  .strip-riders li::before{ display:none; }
  /* ⭐ D469/D471 ON A PHONE: each heading sits ABOVE its own row of four. The
     list becomes `display:contents`, so its items and the two headings are
     siblings in one 4-column grid and `order` interleaves them -- the DOM, and
     every nth-child ring rule above, is untouched. */
  .hz-strip{ display:grid; grid-template-columns:repeat(4,1fr); gap:12px; width:100%; }
  .strip-riders{ display:contents; }
  .strip-group{ position:static; transform:none; grid-column:1 / -1; line-height:1.3;
                margin:4px 0 0; white-space:normal; }
  .strip-group--people{ order:1; }
  .strip-riders li:nth-child(-n+4){ order:2; }
  .strip-group--computer{ order:3; }
  .strip-riders li:nth-child(n+5):not(.strip-coach){ order:4; }
  .strip-riders li.strip-coach{ order:5; }
  /* a full-width row fits the preferred label, so the fallback is not used here
     (the plate container query above would otherwise pick it) */
  .strip-group .sg-long{ display:inline; }
  .strip-group .sg-short{ display:none; }
  /* ⭐ the phone band drew its own GOLD pill -- the one place the CTA colour
     was live rather than painted. It follows the desktop one to the site's
     accent, so the hero CTA is one colour at every width. */
  /* ⭐⭐ PART 7 / option 1b, Eric 2026-10-02 22:08: on phone the CTA comes
     BEFORE the strip. "Headline -> sub-line -> START FREE -> then the strip.
     Nothing leaves the page; the order changes."
     ⛔⛔ AND THE OTHER HALF OF THAT RULING IS NOT APPLIED, BECAUSE ITS PREMISE
     DOES NOT HOLD. It says the two signs "do not render at phone width -- their
     content lives as live text further down the page". MEASURED: it does not.
     `Fundamentals` occurs ONCE in this file and it is the sign; `GTO` occurs
     twice and the second is a COMMENT; `Charts` at :2045 is a different
     sentence in the sources section. So hiding them would DELETE the hero's
     two-paths argument from every phone rather than relocating it.
     ⭐ The signs therefore keep rendering and follow the strip, which preserves
     his stated sequence verbatim and adds only where the un-deleted content
     lands. Flex `order` on a column plate; nothing moves above 760px. */
  .hz-cta  { order:1; }
  .hz-strip{ order:2; }
  .hz-sign { order:3; }
  .hz-cave { order:4; }
  .hz-cta{ font-size:19px; padding:14px 22px; align-self:flex-start;
           background:var(--accent); color:var(--accent-ink); box-shadow:none; }
  .hero-below{ padding:4px 16px 26px; }
}
/* ⭐⭐ D319 (Eric): "THE LANDSCAPE-PHONE HERO MUST SHOW THE CTA WITHOUT SCROLLING."
   MEASURED 10 Oct at the four shapes `check_cta_fold` asserts (548×411, 633×356,
   699×323, 708×318): START FREE sat 182–365px below the fold. The fixed header
   was 130px (its `min-height`, against a 54px wordmark and 44px buttons) and the
   dimmed plate image (290–380px) came BEFORE the headline.
   ⭐ EVERY RULING HELD, nothing traded:
     · Eric's 2 Oct order: "Headline -> sub-line -> START FREE -> then the strip.
       Nothing leaves the page; the order changes." The image does not leave; it
       moves to AFTER the strip (order 3), and the ruled sequence is untouched.
     · the 18px floor: the h1 takes its own clamp's minimum (30px); the smallest
       text in the block stays 18px.
     · D384/D396: 1440×900 is not in this band and nothing here moves its button.
   Short landscape only (≤760 wide AND ≤500 tall); portrait phones are unchanged.
   MEASURED in memory before writing: the CTA's bottom at 309px on all four shapes,
   9px clear of the shortest (318). */
/* ⭐ D484 + D489 (Eric, 15 Oct): THIS BLOCK'S WIDTH BOUND MOVES WITH THE STACK'S,
   760 -> 852 (848 under D484, then 852 under D489), and it carries D319's
   reordering AND D474's spacing together. MEASURED
   before the move: 761x420, 800x450, 824x480 and 848x500, newly stacked by
   ruling 2, put the CTA 325 / 317 / 301 / 265px BELOW the fold (the dimmed
   picture first, the 130px header, no D474 margins). Eric's condition: "the fix
   applies wherever the stacked layout and the kicker meet a short viewport." */
@media (max-width:852px) and (max-height:500px){
  .hdr, .hdr.stuck{ min-height:64px; }
  .hero-plate{ padding-top:72px; gap:12px; }
  .hero-plate > picture{ order:3; }
  .hero-h1{ font-size:30px !important; }
  /* ⭐ D468's kicker added 32px here (a 28.8px line + 3.2px margin) and put the
     CTA 18px / 23px below the fold at 699x323 / 708x318 -- `check_cta_fold`
     caught it. MEASURED HEAD vs worktree: CTA bottom 309 -> 341. Every RULED
     thing holds (the kicker, the hook above the fold, the 18px floor, D319's
     order). ⭐ D474 (Eric, 14 Oct) ruled the collision with D319's fitted values,
     BOUNDED: gaps and margins only, no font-size (or other type) change, this
     band only. Before -> after: the kicker's bottom margin .45cqw (3.2px) -> 0;
     the sub's and the hook's top margins 10 -> 2px each; the plate's flex gap
     12 -> 4px (the gap above the CTA). Re-measure with `check_cta_fold`. */
  .hero-plate{ gap:4px; }
  .hero-kicker{ margin-bottom:0; }
  .hero-sub, .hero-protect{ margin-top:2px; }
}
