/* ═══════════════════════════════════════════════════════════════════════════════
 * pitch.css — /sports/  ·  "functionSPACE for sports trading infrastructure"
 * ═══════════════════════════════════════════════════════════════════════════════
 * ⚠ THIS IS A RE-SKIN TARGET, NOT THE DESIGN SYSTEM.
 *
 * The page REPRODUCES the converged functionSPACE look at the state it stood on
 * 2026-07-28. It does NOT import the design-system architecture: `tokens.css`,
 * `home/_build/components.css` and `home/_build/replica/system.css` are
 * deliberately NOT referenced, linked or copied as files — that scaffolding is
 * still being finalised on `brand-reconstruction` and must not be enshrined on
 * main. What follows is a POUR: the decisions, re-expressed locally, so the page
 * can be lifted and re-run through the published system with nothing to unpick.
 * See NOTE-reskin-target.md next to this file.
 *
 * REFERENCE PAGE: `home/_build/replica/research.html` — an article with an index
 * scroller, a masthead and in-track figures. This page is the same shape; the
 * structure is copied, not invented.
 *
 * READ ORDER OF THE SOURCES (read-only, at 2026-07-28):
 *   1 _context/plan/design-ledger.md        decisions canon — the ledger wins
 *   2 _context/plan/data-layout-STATE.md    layout/component lane truth
 *   3 assets/tokens.css                     §1–5 colour · §6b type · §7 geometry
 *   4 home/_build/components.css            the components, on our tokens
 *   5 home/_build/replica/system.css        page layout · chrome
 *   6 home/_build/replica/research.html     the reference shape
 *
 * THE LAWS THIS FILE OBEYS
 *   TIERS      display 67/64 is ONCE PER PAGE and reserved for the homepage hero.
 *              An article masthead takes HEADING (52/64 serif). SECTION titles take
 *              HEADING. In-article BLOCK headings take SUBHEAD (720 25/32 Geist) —
 *              distinguished by WEIGHT, not size. The serif is display + heading
 *              ONLY; Geist for everything below.
 *   ⚠ SERIF    CM Function v1 carries tracking, word-space and kerning IN THE FONT.
 *              There is NO letter-spacing or word-spacing on any serif tier in this
 *              file. Re-declaring them double-applies and the words collide.
 *   NO BREAKOUTS  figures, tables, charts and notes are the SAME WIDTH as prose,
 *              enforced structurally by sharing the content TRACK — never by
 *              per-element widths. There is no "wide" track on this page.
 *   GRID       W7: cell 24 · column 72 · gutter 24 · edge-air 72 · frame 1272.
 *              Article = 8b: | air 72 | index 3 | spare | content 8 | air 72 |.
 *   RHYTHM     --v-line 32 is the atomic unit. Structural spacing between BLOCKS is
 *              a whole multiple of it. Half-units are legal INSIDE a component only.
 *   COLOUR     accent #4169EE for links / selection / focus / data — NEVER buttons,
 *              never status, never furniture. Buttons are neutral: the ink is the
 *              brand. Elevation = tint + border, no shadows.
 *
 * LOAD ORDER: this file is now the ONLY stylesheet the page loads. As of
 * 2026-07-29 it also carries the CHROME — the rebuilt nav and footer, poured in
 * §3 — because the rebuilt versions live on `brand-reconstruction`, the new
 * `site.css` @imports tokens.css and components.css, and `/assets/brand/` (which
 * the new logomark and wordmark mask from) does not exist on main. See §3.
 * The token block stays on `:root, :root[data-theme]` so it applies both WITH the
 * attribute and WITHOUT it, which is what makes `system` theme work.
 * ═══════════════════════════════════════════════════════════════════════════════ */

/* ── FACES ─────────────────────────────────────────────────────────────────────
 * Page-local so the page is self-contained and deploys from main today. Same
 * binaries the design system uses: serif = assets/fonts/cm-function.woff2 ·
 * mono = assets/fonts/geist-mono-VF.woff2 · Geist = assets/wordmark/Geist-VF.ttf
 * (NOT in assets/fonts/), re-emitted TTF→woff2 — a lossless container change, no
 * glyph, metric or table edits. Licences travel with them: see fonts/LICENSES.txt.
 * `New CM Book` is named in the stack as the coverage fallback only; it is not
 * shipped here because this page needs no glyph outside CM Function's subset.  */
@font-face{ font-family:'CM Function'; src:url('fonts/cm-function.woff2') format('woff2');
  font-weight:400; font-style:normal; font-display:swap; }
@font-face{ font-family:'Geist'; src:url('fonts/geist-VF.woff2') format('woff2');
  font-weight:100 900; font-style:normal; font-display:swap; }
@font-face{ font-family:'Geist Mono'; src:url('fonts/geist-mono-VF.woff2') format('woff2');
  font-weight:100 900; font-style:normal; font-display:swap; }

/* ═══ 1 · TOKENS — poured from assets/tokens.css @ 2026-07-28 ══════════════════ */
:root, :root[data-theme]{
  color-scheme: light dark;

  /* §1 the neutral instrument */
  --color-bg:          light-dark(#FBFBFB, #030304);
  --color-surface:     light-dark(#FFFFFF, #101215);
  --color-surface-alt: light-dark(#EEEFF0, #1C1E22);
  --color-border:      light-dark(#C7C9CD, #2F3238);   /* the HAIRLINE/divider rung, 1.6:1 */
  --color-wireframe:   light-dark(#BABCC2, #44474E);   /* the STRUCTURAL line rung — control edges */

  /* §2 the text ladder — 18:1 / 11.6:1 / 7.5:1, + quarantined disabled 3.5:1 */
  --color-text:           light-dark(#111316, #EFEFF1);
  --color-text-secondary: light-dark(#34363C, #C0C2C7);
  --color-text-tertiary:  light-dark(#4F525A, #999CA3);
  --color-text-disabled:  light-dark(#83868E, #61646C);
  --color-strong:         light-dark(#111316, #EFEFF1);

  /* §3 identity — one hue, universal; links/selection/focus/data only */
  --color-accent:          #4169EE;
  --color-accent-subtle:   rgba(65,105,238,.12);
  --color-accent-hover-bg: rgba(65,105,238,.20);
  --color-accent-bdr:      rgba(65,105,238,.40);
  --color-accent-hover:    light-dark(#2B4EEB, #5A81F0);

  /* §4 functional signals */
  --color-positive:      #3AB885;
  --color-positive-sub:  rgba(58,184,133,.12);
  --color-positive-text: #288861;
  --color-caution:       #F4AE3E;
  --color-caution-text:  #976B23;
  --color-negative:      #EE3533;
  --color-negative-text: #CF2D2B;

  /* §5 data encoding — accent + opacity ladder is the default; grey is "other" */
  --color-data-loss:   rgba(65,105,238,.06);
  --color-data-profit: rgba(65,105,238,.17);
  --color-data-line:   var(--color-accent);
  --color-data-other:  var(--color-text-tertiary);

  /* §6 faces */
  --font-heading:'CM Function','New CM Book','Computer Modern',Georgia,serif;
  --font-sans:'Geist','Inter',-apple-system,BlinkMacSystemFont,sans-serif;
  --font-mono:'Geist Mono','JetBrains Mono','SF Mono',monospace;

  /* §6b scale — √φ off body 20; line-heights ABSOLUTE px, whole 8-multiples */
  --text-display: 400 67px/64px var(--font-heading);   /* NOT USED HERE — homepage hero only */
  --text-heading: 400 52px/64px var(--font-heading);   /* masthead + SECTION titles */
  --text-subhead: 720 25px/32px var(--font-sans);      /* in-article BLOCK titles */
  --text-lede:    430 20px/32px var(--font-sans);
  --text-body:    460 20px/32px var(--font-sans);
  --text-small:   486 16px/24px var(--font-sans);
  --text-micro:   506 12px/16px var(--font-sans);
  /* the Geist tiers still track in CSS; the SERIF tiers do NOT — baked into the cut */
  --track-small: .018em;
  --track-micro: .036em;

  /* §7 geometry — W7 frozen constants */
  --cell: 24px;
  --paper-cell: 48px;
  --u: 8px;
  --v-line: calc(4 * var(--u));          /* 32 — THE atomic vertical unit */
  --space-1: calc(.5 * var(--u));
  --space-2: var(--u);
  --space-3: calc(1.5 * var(--u));
  --space-4: calc(2 * var(--u));
  --space-5: calc(3 * var(--u));
  --space-6: calc(2 * var(--v-line));    /* BLOCK gap = 2 units */
  --space-7: calc(2 * var(--v-line));    /* SECTION pad per side = 2 units */

  --radius-sm: 4px; --radius-md: 8px; --radius-lg: 12px; --radius-full: 9999px;
  --corner-shape: superellipse(2.5);

  --frame-max: 1272px;
  --frame-pad: clamp(16px, 4vw, 40px);
  --nav-height: calc(2 * var(--v-line));  /* 64 = 2 units */
  --edge-air: 72px;
  --col: 72px;
  --col-gutter: 24px;

  /* the ARTICLE tracks — 8b: index 3 | spare 1 | content 8.
     ⚠ THERE IS NO WIDE TRACK. Everything in the article — prose, figures, charts,
     tables, cards — shares --sp-content. That is the NO-BREAKOUTS law, and it is
     enforced structurally by the grid, not by per-element widths. */
  --sp-side:    calc(3 * var(--col) + 2 * var(--col-gutter));    /* 264 */
  --sp-spare:   var(--col);                                      /*  72 */
  --sp-content: calc(8 * var(--col) + 7 * var(--col-gutter));    /* 744 */
  --sp-canvas:  calc(12 * var(--col) + 11 * var(--col-gutter));  /* 1128 — masthead only */
  --container:  min(var(--frame-max), calc(100% - 2 * var(--frame-pad)));
  --sec-pad-y:  var(--space-7);

  /* chart surface vars (consumed by payoff-core's .pcfig-* classes) — poured onto
     the colour tokens: the curve is the accent, the fills are the accent opacity
     ladder, structure sits on the wireframe rung. */
  --pf-curve: var(--color-accent);
  --pf-premium-line:  light-dark(#9AA9DA, #38477A);
  --pf-premium-label: light-dark(#5A6B9E, #7E8DBE);
  --pf-axis: var(--color-wireframe);
  --pf-dist: var(--color-text-tertiary);
  --pc-hair: 1.1px; --pc-curve: 2.1px; --pc-premium: 1.2px; --pc-knob-stroke: 2.2px;

  /* categorical extension, DERIVED ON TAP (colour-STATE: there is no standing
     multi-hue ramp). Three identity colours + one derived accent step + neutral. */
  --cat-point: var(--color-positive);
  --cat-range: var(--color-caution);
  --cat-ou:    var(--color-accent);
  --cat-duel:  color-mix(in srgb, var(--color-accent) 58%, transparent);
  --cat-other: var(--color-data-other);
}
@media (max-width:599px){ :root, :root[data-theme]{ --space-7: var(--v-line); } }

:root[data-theme="dark"]  { color-scheme: dark; }
:root[data-theme="light"] { color-scheme: light; }

/* SELECTION INVERTS — an ink block with paper text, site-wide.
   ⚠ light-dark() does NOT resolve inside ::selection (Chromium), so these are
   literal per-theme values that MIRROR --color-text / --color-bg. */
:root                    { --sel-bg:#111316; --sel-fg:#FBFBFB; }
:root[data-theme="dark"] { --sel-bg:#EFEFF1; --sel-fg:#030304; }
@media (prefers-color-scheme: dark){
  :root:not([data-theme]) { --sel-bg:#EFEFF1; --sel-fg:#030304; }
}
::selection{ background-color:var(--sel-bg); color:var(--sel-fg); }

/* ═══ 2 · THE GROUND + THE FRAME ══════════════════════════════════════════════ */
*,*::before,*::after{ box-sizing:border-box; }
html{ position:relative; scroll-behavior:smooth;
  scroll-padding-top:calc(var(--nav-height) + var(--v-line)); }
@media (prefers-reduced-motion: reduce){ html{ scroll-behavior:auto; } }
body{
  margin:0; overflow-x:clip;
  background:var(--color-bg); color:var(--color-text);
  font:var(--text-body);
  -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
  padding-top:var(--nav-height);   /* the first SECTION begins BELOW the fixed nav */
}
img{ max-width:100%; }
h1,h2,h3,h4,p,figure,ul,ol,dl,dd,blockquote,table{ margin:0; padding:0; }
ul,ol{ list-style:none; }
/* ⚠ `text-decoration:none` IS LOAD-BEARING and was NOT here before 2026-07-29.
   It came from `site.css`'s base (`a{ color:inherit; text-decoration:none }`),
   which this page relied on without owning. The moment the chrome was poured and
   site.css stopped being linked, 26 links across the nav dropdowns, the drawer
   and the social icons picked up the UA underline. Nothing else regressed —
   every link in the CONTENT is already covered by a page rule. The page's own
   underlines (prose links, .meta-row on hover) re-add it deliberately below. */
a{ color:inherit; text-decoration:none; }

/* RAILS and PAPER are SEPARATE CONCERNS: paper is TEXTURE at .6; rails are
   STRUCTURE at full opacity (a rail drawn inside the .6 panel inherits the alpha).
   LINE·DUO paper: strong MAJORS (cols 48 · rows 32) over faint MINORS (24 · 16). */
html::before, html::after{
  content:""; position:absolute; top:0; bottom:0; pointer-events:none; opacity:.6; z-index:0;
  background-size:var(--paper-cell) var(--v-line), var(--paper-cell) var(--v-line),
                  calc(var(--paper-cell)/2) calc(var(--v-line)/2), calc(var(--paper-cell)/2) calc(var(--v-line)/2);
}
html::before{ left:0; right:calc(50% + var(--container)/2);
  background-image:
    linear-gradient(to left, var(--color-border) 1px, transparent 1px),
    linear-gradient(to bottom, var(--color-border) 1px, transparent 1px),
    linear-gradient(to left, color-mix(in srgb, var(--color-border) 40%, transparent) 1px, transparent 1px),
    linear-gradient(to bottom, color-mix(in srgb, var(--color-border) 40%, transparent) 1px, transparent 1px);
  background-position:right -1px; }
html::after{ left:calc(50% + var(--container)/2); right:0;
  background-image:
    linear-gradient(to right, var(--color-border) 1px, transparent 1px),
    linear-gradient(to bottom, var(--color-border) 1px, transparent 1px),
    linear-gradient(to right, color-mix(in srgb, var(--color-border) 40%, transparent) 1px, transparent 1px),
    linear-gradient(to bottom, color-mix(in srgb, var(--color-border) 40%, transparent) 1px, transparent 1px);
  background-position:left -1px; }
body::before, body::after{ content:""; position:absolute; top:0; bottom:0; width:1px;
  background:var(--color-border); pointer-events:none; z-index:0; }
body::before{ left:calc(50% - var(--container)/2 - 1px); }
body::after { left:calc(50% + var(--container)/2); }
@media (max-width:1320px){ html::before, html::after{ display:none; } }

/* ═══ 3 · CHROME — POURED IN FULL from assets/site.css @ 2026-07-29 ═══════════
 * ⭐ REBASED 2026-07-29 (Tom: "the only one I'm interested in you rebasing off
 *    and pulling into your working page is the Nav bar and Footer").
 *
 * ⚠ THIS SECTION CHANGED SHAPE. It used to be a PARITY OVERRIDE layer: the page
 * linked `/assets/site.css`, which shipped the chrome AND theme-scoped rules that
 * outranked plain selectors, so every decision we own had to be re-asserted here
 * at matched specificity. That is over. The chrome is now POURED — the whole nav
 * and footer, ours, in this file — and the page no longer links `site.css` or
 * `site-chrome.js` at all. Three things forced it, in order of finality:
 *   1. The rebuilt chrome lives on `brand-reconstruction`, and nothing merges.
 *      Linking the shared files gives the page main's OLD chrome, not this one.
 *   2. The new `site.css` opens with `@import tokens.css` and `@import
 *      components.css`. Linking it would drag the entire WIP architecture onto
 *      the page, which is the one thing this page's brief forbids outright.
 *   3. `/assets/brand/` DOES NOT EXIST ON MAIN. The rebuilt logomark and wordmark
 *      are CSS masks reading the two SVGs there; on main today both are 404
 *      and the nav would render with no logo and no wordmark at all.
 * So the two vectors are shipped page-local in `brand/` beside index.html, the
 * same treatment the faces already get, and for the same reason.
 *
 * WHAT THE REBASE ACTUALLY BROUGHT (the diff against what this page had):
 *   · logomark + wordmark are ONE masked element inked by `currentColor`,
 *     replacing a hand-inlined SVG that had drifted from the real mark and a
 *     two-<img> display-swap keyed on [data-theme] (which shipped the superseded
 *     pre-Geist wordmark, downloaded both files always, and could not follow an
 *     OS theme).
 *   · a THREE-way theme switch (system · light · dark) on `gc-themeswitch`,
 *     replacing two ☀/☾ text buttons. `system` = the attribute REMOVED.
 *   · every `[data-theme="light"]` chrome override DELETED at source; the nav,
 *     dropdown, drawer and scrim now derive from the tokens via color-mix(), so
 *     they follow the OS in system mode instead of desyncing from the ground.
 *   · the theme cross-fade DELETED — it half-flipped the page on theme change.
 *   · the dropdown trigger aligner promoted into the chrome itself.
 *
 * OUR OWN DECISIONS still sit below the poured rules and still win, but they no
 * longer need `[data-theme="light"]` twins, because there is nothing left to
 * out-shout. That is why this section got SHORTER as it got more complete.
 * LOCKED (unchanged): band = 2 units (64) · dropdown is a full-bleed OPAQUE
 * surface growing downward with no panel line · sub-links descend one drawn
 * square (48) · the rest of the page dims (scrim 62%) · sub-items align to THEIR
 * OWN TRIGGER's left edge · the menu block starts on column 3 with a uniform 24px
 * gap · nav CTAs are gc-btn.
 * ⛔ SWEEP: delete this whole section, `brand/`, the head seed, the static markup
 *    and pitch.js §0, and go back to linking the shared pair. */

/* ── the two aliases the poured chrome expects, mapped onto our own tokens.
      Both are aliases in tokens.css too, with these exact definitions. */
:root, :root[data-theme]{
  --gutter: var(--frame-pad);                          /* ONE outside pad */
  --color-text-muted: var(--color-text-disabled);      /* old name, faint tier */
}

/* ── NAV (poured) ───────────────────────────────────────────────────────────── */
.nav{
  position:fixed; top:0; left:0; right:0; z-index:100;
  display:flex; align-items:center; justify-content:space-between; gap:16px;
  padding:14px var(--gutter);
  /* the nav IS the page, thinned — so it tracks --color-bg in ANY theme rather
     than two hard-coded rgba()s keyed on [data-theme]. That attribute-keying is
     what broke OS/system theme: the ground followed the OS, the chrome did not. */
  background:color-mix(in srgb, var(--color-bg) 72%, transparent);
  backdrop-filter:blur(12px); -webkit-backdrop-filter:blur(12px);
  border-bottom:1px solid var(--color-border);
}
.nav-left{ display:flex; align-items:center; gap:20px; }
.nav-logo{ display:flex; align-items:center; gap:10px; text-decoration:none;
  color:var(--color-text); }
/* THE LOGOMARK and THE WORDMARK — one element each, inked by `currentColor`,
   MASKED from the canonical vector, so they are theme-following by construction
   and a re-export propagates for free. Aspects are the vectors' own:
   364.79:227.63 = 1.6026 · 69.9338:10.923 = 6.402. */
.nav-logomark{ display:block; height:25px; width:calc(25px * 1.6026);
  background-color:currentColor;
  -webkit-mask:url('brand/logomark.svg') no-repeat center / contain;
          mask:url('brand/logomark.svg') no-repeat center / contain; }
.nav-wordmark{ display:block; height:22px; width:calc(22px * 6.402);
  background-color:currentColor;
  -webkit-mask:url('brand/wordmark.svg') no-repeat center / contain;
          mask:url('brand/wordmark.svg') no-repeat center / contain; }
.nav-links{ display:flex; gap:4px; align-items:center; }
.nav-link{ display:inline-flex; align-items:center; gap:4px;
  font-family:var(--font-sans); font-size:13px; color:var(--color-text-tertiary);
  text-decoration:none; padding:6px 10px; border-radius:var(--radius-sm);
  transition:color .2s; cursor:pointer; background:none; border:0; }
.nav-link:hover, .nav-link.active{ color:var(--color-text); }
.nav-dropdown.active > .nav-link{ color:var(--color-text); }
.nav-dropdown > .nav-link svg{ transition:transform .2s; }
.nav-dropdown:hover > .nav-link svg,
.nav-dropdown.open > .nav-link svg{ transform:rotate(180deg); }
.nav-dropdown-menu{
  position:absolute; top:100%; left:0; margin-top:8px; min-width:160px;
  background:color-mix(in srgb, var(--color-surface) 96%, transparent);
  backdrop-filter:blur(12px); -webkit-backdrop-filter:blur(12px);
  border:1px solid var(--color-border); border-radius:var(--radius-md); padding:6px;
  opacity:0; visibility:hidden; transform:translateY(-4px);
  transition:opacity .15s, transform .15s, visibility .15s; }
.nav-dropdown:hover .nav-dropdown-menu,
.nav-dropdown.open .nav-dropdown-menu{ opacity:1; visibility:visible; transform:translateY(0); }
.nav-dropdown-menu a{ display:block; padding:8px 12px; font-size:13px;
  color:var(--color-text-tertiary); border-radius:var(--radius-sm); white-space:nowrap; }
.nav-dropdown-menu a:hover{ color:var(--color-text); background:var(--color-surface-alt); }
.nav-right{ display:flex; align-items:center; gap:10px; }
.nav-icon{ display:inline-flex; align-items:center; justify-content:center;
  width:30px; height:30px; color:var(--color-text-tertiary); transition:color .2s; }
.nav-icon:hover{ color:var(--color-text); }
.nav-mobile-toggle{ display:none; width:44px; height:44px; background:transparent;
  border:1px solid var(--color-border); border-radius:var(--radius-sm);
  color:var(--color-text); cursor:pointer; align-items:center; justify-content:center;
  padding:0; transition:border-color .15s; }
.nav-mobile-toggle:hover{ border-color:var(--color-wireframe); }
.nav-drawer{ position:fixed; top:var(--nav-height); left:0; right:0;
  max-height:calc(100dvh - var(--nav-height)); overflow-y:auto;
  background:color-mix(in srgb, var(--color-bg) 98%, transparent);
  backdrop-filter:blur(12px); -webkit-backdrop-filter:blur(12px);
  border-bottom:1px solid var(--color-border); z-index:99;
  transform:translateY(-8px); opacity:0; visibility:hidden;
  transition:transform .2s cubic-bezier(.4,0,.2,1), opacity .2s, visibility .2s;
  padding:12px 24px 24px; display:flex; flex-direction:column; }
.nav-drawer.open{ transform:translateY(0); opacity:1; visibility:visible; }
.nav-drawer a{ display:flex; align-items:center; gap:8px; padding:13px 8px;
  font-size:15px; font-weight:500; color:var(--color-text);
  border-bottom:1px solid var(--color-border); }
.nav-drawer a.nav-drawer-sub{ padding-left:20px; font-size:14px;
  color:var(--color-text-secondary); font-weight:400; }
.nav-drawer-label{ padding:14px 8px 6px; font-family:var(--font-mono);
  font-size:10px; font-weight:700; letter-spacing:.12em; text-transform:uppercase;
  color:var(--color-text-muted); }
.nav-drawer .nav-cta{ margin-top:14px; justify-content:center;
  font-size:14px; padding:12px 18px; border-bottom:none; }
@media (max-width:860px){
  .nav-mobile-toggle{ display:inline-flex; }
  .nav-links{ display:none; }
  .nav-pill{ display:none; }
}
@media (max-width:540px){
  .nav{ padding:12px 16px; }
  .nav-icon{ display:none; }
  .nav .nav-right > .nav-cta{ display:none; }
}

/* ── FOOTER (poured) ────────────────────────────────────────────────────────── */
footer.site-footer{ display:flex; align-items:center; justify-content:space-between;
  flex-wrap:wrap; gap:16px 24px; padding:28px var(--gutter);
  border-top:1px solid var(--color-border); color:var(--color-text-muted);
  font-size:13px; }
.footer-brand{ display:inline-flex; align-items:center; gap:12px;
  color:var(--color-text-tertiary); }
.footer-links{ display:flex; align-items:center; flex-wrap:wrap; gap:14px 32px; }
.footer-links > a{ display:inline-flex; align-items:center; gap:4px;
  color:var(--color-text-secondary); text-decoration:none; transition:color .2s; }
.footer-links > a:hover{ color:var(--color-text); }
.footer-social{ display:inline-flex; align-items:center; gap:8px;
  padding-left:18px; margin-left:6px; border-left:1px solid var(--color-border); }
@media (max-width:640px){
  footer.site-footer{ justify-content:flex-start; }
  .footer-links{ order:3; width:100%; }
  .footer-social{ border-left:none; padding-left:0; margin-left:auto; }
}
.footer-wordmark{ display:inline-block; height:16px; width:calc(16px * 6.402);
  background-color:currentColor;
  -webkit-mask:url('brand/wordmark.svg') no-repeat center / contain;
          mask:url('brand/wordmark.svg') no-repeat center / contain; }

/* ── THE THEME SWITCH (poured from components.css § gc-themeswitch) ──────────
   A 1-unit pill of 1-unit circles, real Geist glyphs as masks, and SELECTED is a
   PURE CIRCLE LINE with full ink — no fill, drawn INSIDE so it costs no layout
   and each segment stays exactly one unit. Both `.active` and `aria-pressed` are
   matched, so it works whichever the markup sets. */
.gc-themeswitch{ display:inline-flex; align-items:center; box-sizing:border-box;
  height:var(--v-line); padding:0; gap:0; border:0;
  border-radius:var(--radius-full); box-shadow:none; }
.gc-themeswitch-opt{ display:inline-flex; align-items:center; justify-content:center;
  box-sizing:border-box; width:var(--v-line); height:var(--v-line); flex:none;
  padding:0; border:0; background:none; cursor:pointer;
  border-radius:var(--radius-full);
  font-size:0;                       /* hides any text label; the icon is the mask */
  color:var(--color-text-disabled); }/* the DISABLED rung — an inactive control */
.gc-themeswitch-opt::before{ content:""; width:16px; height:16px;
  background:currentColor;
  -webkit-mask:var(--ts-icon) center/16px no-repeat;
          mask:var(--ts-icon) center/16px no-repeat; }
.gc-themeswitch-opt:hover{ color:var(--color-text); }
.gc-themeswitch-opt.active, .gc-themeswitch-opt[aria-pressed="true"]{
  background:none; color:var(--color-text);
  box-shadow:inset 0 0 0 1px var(--color-wireframe); }
.gc-themeswitch-opt:focus-visible{ outline:2px solid var(--color-accent-bdr);
  outline-offset:2px; }
.gc-themeswitch-opt[data-theme-set="light"]{ --ts-icon:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path fill='black' d='M8.75.75V0h-1.5v2h1.5V.75M3.26 4.32l-.53-.53-.35-.35-.53-.53L2.9 1.85l.53.53.35.35.53.53zm8.42-1.06.53-.53.35-.35.53-.53 1.06 1.06-.53.53-.35.35-.53.53zM8 11.25a3.25 3.25 0 1 0 0-6.5 3.25 3.25 0 0 0 0 6.5m0 1.5a4.75 4.75 0 1 0 0-9.5 4.75 4.75 0 0 0 0 9.5m6-5.5h2v1.5h-2zm-13.25 0H0v1.5h2v-1.5H.75m1.62 5.32-.53.53 1.06 1.06.53-.53.35-.35.53-.53-1.06-1.06-.53.53zm10.2 1.06.53.53 1.06-1.06-.53-.53-.35-.35-.53-.53-1.06 1.06.53.53zM8.75 14v2h-1.5v-2z'/></svg>"); }
.gc-themeswitch-opt[data-theme-set="dark"]{ --ts-icon:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path fill='black' d='M1.5 8a6 6 0 0 1 3.62-5.51 7 7 0 0 0 7.08 9.25A5.99 5.99 0 0 1 1.5 8M6.42.58a7.5 7.5 0 1 0 7.96 10.41l-.92-1.01a5.5 5.5 0 0 1-6.3-8.25zm6.83.42v1.75H15v1.5h-1.75V6h-1.5V4.25H10v-1.5h1.75V1z'/></svg>"); }
.gc-themeswitch-opt[data-theme-set="system"]{ --ts-icon:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path fill='black' d='M1 3.25C1 1.45 2.46 0 4.25 0h7.5C13.55 0 15 1.46 15 3.25V16H1V3.25M4.25 1.5c-.97 0-1.75.78-1.75 1.75V14.5h11V3.25c0-.97-.78-1.75-1.75-1.75zM4 4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v6H4zm5 9h3v-1.5H9z'/></svg>"); }

/* ── OUR DECISIONS, over the poured chrome ──────────────────────────────────── */
/* ⛔ `body[data-page] main.frame{ padding-top:0 }` IS DELETED (2026-07-29). It
   existed to cancel `site.css`'s `body:not([data-page="home"]) main{ padding-top
   :var(--nav-height) }`, which applied the nav offset a SECOND time on top of the
   one §2 sets on BODY — the hero opened 128px below the nav instead of 64, and it
   hid because 64 is itself a whole 2 units so every rhythm check still passed.
   With site.css no longer linked there is only one offset, on body, and nothing
   to cancel. If the shared sheet is ever re-linked, this rule comes back. */
.nav{
  padding-left:max(var(--frame-pad), calc((100% - var(--frame-max))/2));
  padding-right:max(var(--frame-pad), calc((100% - var(--frame-max))/2));
  height:var(--nav-height); min-height:var(--nav-height); box-sizing:border-box;
  padding-top:0; padding-bottom:0; align-items:center;
  background:color-mix(in srgb, var(--color-bg) 88%, transparent);
  backdrop-filter:blur(20px); -webkit-backdrop-filter:blur(20px);
  /* the rule is drawn INSIDE so the content box stays the full 64 and the 48 button
     centres exactly 8/8 (with border-bottom it ate a pixel and rendered 8/9). */
  border-bottom:0; box-shadow:inset 0 -1px 0 var(--color-border);
}
/* with a dropdown open the band goes fully OPAQUE and its rule disappears — the
   panel and the band read as ONE surface growing downward. */
.nav:has(.nav-dropdown:hover, .nav-dropdown.open){
  border-bottom-color:transparent; background:var(--color-bg); box-shadow:none; }
/* THE SCRIM — the rest of the page dims behind an open dropdown. */
.nav::after{ content:""; position:fixed; top:0; left:0; width:100vw; height:100vh;
  z-index:-1; pointer-events:none;
  background:color-mix(in srgb, var(--color-bg) 62%, transparent);
  opacity:0; visibility:hidden; transition:opacity .15s ease, visibility .15s ease; }
.nav:has(.nav-dropdown:hover, .nav-dropdown.open)::after{ opacity:1; visibility:visible; }
/* TYPE + ALIGNMENT — the persistent chrome speaks the SYSTEMIC-LABEL register
   (micro, uppercase, tracked, tertiary); opening a dropdown SHIFTS to the CONTENT
   register (sentence-case, small, primary ink). The register change IS the design. */
.nav .nav-link{
  font:var(--text-micro); font-family:var(--font-sans); font-weight:500;
  text-transform:uppercase; letter-spacing:.08em; color:var(--color-text-tertiary);
  display:inline-flex; align-items:center; gap:5px;
  appearance:none; -webkit-appearance:none; margin:0; vertical-align:middle;
  line-height:16px; align-self:center; padding-inline:0; }
.nav .nav-link:hover, .nav .nav-dropdown.active > .nav-link, .nav .nav-link.active{
  color:var(--color-text); }
.nav-dropdown{ position:static; display:inline-flex; align-items:center; }
/* the logo holds the col-1/2 zone; the nav-links block starts on COLUMN 3 */
.nav .nav-left{ display:grid; align-items:center; justify-items:start; column-gap:0;
  grid-template-columns: calc(var(--edge-air) + 2 * (var(--col) + var(--col-gutter))) auto; }
.nav .nav-links{ gap:var(--col-gutter); }   /* uniform gap = ONE column gutter */
.nav-dropdown-menu{
  position:fixed; top:var(--nav-height); left:0; right:0; margin:0; min-width:0;
  display:flex; flex-direction:column; gap:0;
  padding:0 0 0 calc(max(var(--frame-pad), (100% - var(--frame-max))/2) + var(--edge-air) + 2 * (var(--col) + var(--col-gutter)));
  background:var(--color-bg); border:0; border-bottom:1px solid var(--color-border);
  border-radius:0; box-shadow:none; transform:none;
  transition:opacity .12s ease, visibility .12s ease; }
.nav-dropdown-menu::before, .nav-dropdown-menu::after{ display:none; }
/* sub-links descend ONE DRAWN SQUARE each (48 = 2 logic cells) */
.nav-dropdown-menu a{ display:flex; align-items:center; white-space:nowrap;
  height:var(--paper-cell); padding:0 .3em 0 0; align-self:flex-start;
  border-radius:0; background:none; font:var(--text-small); font-weight:500;
  letter-spacing:0; text-transform:none; color:var(--color-text); }
/* the invert highlight, hugging the word + one trailing space */
.nav-dropdown-menu a:hover{ color:var(--sel-fg);
  background:linear-gradient(var(--sel-bg), var(--sel-bg)) no-repeat 0 center / 100% 1.5em; }
.nav-cta svg, .nav-pill svg{ display:none; }      /* NO GLYPHS IN CTAs */
.nav-pill, .nav-cta, .theme-toggle{ corner-shape:var(--corner-shape); }
/* the footer's TOP boundary IS the last section's rule, so it draws none of its own */
footer.site-footer{ max-width:var(--frame-max); margin:0 auto; position:relative;
  border-top:0; padding:var(--paper-cell) var(--frame-pad); }
footer.site-footer::before, footer.site-footer::after{ display:none; }

/* ═══ 4 · THE FRAME + SECTION RHYTHM — the homepage's grammar ════════════════
 * `<main class="frame">` sits at container width and holds a stack of
 * `<section class="sec">` bands. A section FILLS the frame — it never
 * re-constrains — and its INNER content caps at the usable 12 columns
 * (--sp-canvas 1128) and centres. That is what delivers the 72px edge-air
 * structurally on every row, instead of as a padding strip.
 *
 * SECTION RHYTHM, one mechanism for every band: SYMMETRIC --sec-pad-y top and
 * bottom + a 1px rule at the BOTTOM with ⬦ at the rails. The 1px is absorbed out
 * of the bottom padding so the box stays whole-unit and the next section lands on
 * a major paper stroke. No first/last special-casing: the first section's top
 * boundary is the nav's own rule, the last section's bottom rule is the footer
 * boundary. Add a section and it inherits the rhythm for free. */
.frame{ max-width:var(--container); margin-inline:auto; position:relative; z-index:1; }
.sec{
  box-sizing:border-box; position:relative;
  max-width:100%; padding:var(--sec-pad-y) 0 calc(var(--sec-pad-y) - 1px);
  border-top:0; border-bottom:1px solid var(--color-border); margin-bottom:0;
}
.sec::before, .sec::after{
  content:""; position:absolute; bottom:-4px; width:7px; height:7px;
  background:var(--color-bg); border:1px solid var(--color-wireframe);
  transform:rotate(45deg); pointer-events:none;
}
.sec::before{ left:-4px; }
.sec::after { right:-4px; }
/* THE CANVAS — every section's payload, centred inside the frame. */
.sec-inner{ max-width:var(--sp-canvas); margin-inline:auto; }

/* ═══ 5 · HERO ═══════════════════════════════════════════════════════════════
 * A HERO, not an article masthead — so the headline takes the DISPLAY tier
 * (67/64), once on this page and nowhere else, exactly as `.hero-headline` does
 * on the homepage. The sub is body-size at 430, secondary; never a bigger tier.
 *
 * ⛔ THE TOPLINE (back-link + "Partner brief" badge) IS DELETED — 2026-07-28, Tom.
 * It was an ARTICLE's furniture, carried over from the shape this page was rebased
 * off, and it pushed the headline 3 units down the band. The headline is now the
 * section's first child, so the rhythm is exactly the homepage's and needs no
 * special-casing: 64 nav · 64 --sec-pad-y · then the 2-unit display box at
 * offset 0. Display 67/64 is grid-true, so the title's box opens 2 units below the
 * nav's rule and closes on the next major line. */
/* ⭐ THE HERO TITLE TAKES SIX COLUMNS, NOT TEN (2026-07-29, Tom). Every other
   title on the page runs the span-10 title track (936); this one is capped at
   552 = 6 cols + 5 gutters. Two reasons, and the first is measured rather than
   eyeballed: at display 67 "Markets your book" is 516 wide and adding "can't"
   takes it to 664, so ANY cap between those two forces the break the copy wants
      Markets your book
      can't list today.
   and 552 is the only whole-column value in that window. The second is that a
   headline running the full title track leaves no top-right air for the hero
   imagery this page is getting next; six columns hands back six.
   ⚠ It is a MAX, and it relaxes below the paper regime — under 1240 the canvas is
   viewport-bound and a hard 552 would strand the title mid-column. */
:root{ --sp-hero-title: calc(6*var(--col) + 5*var(--col-gutter)); }   /* 552 */
.hero-headline{ font:var(--text-display); color:var(--color-text);
  margin:0 0 var(--v-line); max-width:min(var(--sp-hero-title), 100%); }
.hero-sub{ font:var(--text-lede); color:var(--color-text-secondary);
  max-width:var(--sp-content); margin:0; }
/* ⭐ THE HERO CTA replaced `.meta-row` (2026-07-29, Tom). The row was two grey
   status spans and a micro link; the link is now a real button and the spans are
   gone (both facts still live in §02, where they are load-bearing).
   ⚠ TWO-CLASS SELECTOR, DELIBERATELY — the same trap `.row-b` and `.proof-link`
   fell into. `.hero-cta` is a `p` inside `.sec-inner`, so the §7 text firewall
   (0,1,1) sets `margin:0 0 var(--v-line)` on it and a plain `.hero-cta` (0,1,0)
   would lose its top margin AND gain a phantom bottom one. `.hero-inner
   .hero-cta` is (0,2,0) and wins.
   ONE UNIT above, zero below: the button's own 48 box plus one unit of air is a
   whole 2.5 units off the sub, and the hero band's --sec-pad-y closes the rest. */
.hero-inner .hero-cta{ display:flex; margin:var(--v-line) 0 0; }

/* ═══ THE HERO ART — the construction loop ════════════════════════════════════
 * (2026-07-29, Tom: "a nice visual flourish… aligned to the right and vertically
 * centred between the combined Hero/lede text… at least one column" of gap.)
 *
 * THE LANE GEOMETRY IS THE PROOF ROW'S, REUSED: 744 · 120 · 264. The page already
 * makes exactly this move in §02 (copy on the content track, a declared lane, an
 * aside), so the hero inherits a proportion the reader meets again 800px later
 * rather than inventing a second one. The lane is 120 = 1 column + 2 gutters,
 * which is Tom's "at least one column" measured the way this grid measures things.
 * The art gets the remaining 264 = 3 cols + 2 gutters, and it is SQUARE — the
 * Illustration lane's one hard constraint, because a square box is what makes the
 * stroke rule (√2% of the fitted extent) give every object the same line weight.
 *
 * VERTICAL CENTRING is on `.hero-lead` (headline + lede) alone, NOT the column:
 * the shape row and the CTA sit below it, and centring against those would drag
 * the mark down past the text it belongs to. One grid row, `align-self:center`,
 * no magic numbers, and it re-centres for free when the copy re-wraps.
 *
 * ⚠ 1080 IS THE PAIR/PROOF BREAKPOINT, deliberately the same one. Below it the
 *   art has nowhere to go: 264 + 120 would eat the lede's measure. */
.hero-art{ display:block; aspect-ratio:1; color:var(--color-text-tertiary); }
/* THE JS-OFF FALLBACK — the loop's END STATE, as a mask of the canonical mark.
   With no JS the slot would otherwise be a 264px hole in the hero. Same file and
   same mechanism the nav's logomark uses, so it is one vector, not a copy.
   `.is-live` is added by art.js only AFTER a successful mount, so a throw in the
   engine leaves the static mark showing rather than clearing to nothing. */
.hero-art{
  -webkit-mask:url('brand/logomark.svg') no-repeat center / contain;
          mask:url('brand/logomark.svg') no-repeat center / contain;
  background-color:currentColor; }
.hero-art.is-live{ -webkit-mask:none; mask:none; background-color:transparent; }
.hero-art svg{ display:block; width:100%; height:auto; }

@media (min-width:1080px){
  .hero-inner{
    --hero-lane: calc(1*var(--col) + 2*var(--col-gutter));    /* 120 */
    --hero-art:  calc(3*var(--col) + 2*var(--col-gutter));    /* 264 */
    display:grid; align-items:start;
    /* ⚠ THE ART IS THE FIXED COLUMN AND THE TEXT FLEXES, not the other way round.
       Written `744 · 120 · 1fr` first, which is right at 1440 and WRONG below it:
       the canvas is viewport-bound under the paper regime, so at a 1100 viewport
       the 744 and the 120 ate everything and the art was handed 108px — SMALLER
       than its own 112 mobile size, and squeezed between two fixed columns.
       Fixed art + flexible text holds the object at 264 and the gap at exactly
       one column all the way down to the breakpoint; the lede simply takes a
       narrower measure, which it is already built to do (it caps at 744, it does
       not demand it). */
    grid-template-columns:minmax(0,1fr) var(--hero-lane) var(--hero-art);
    grid-template-rows:auto auto auto; }
  .hero-inner > .hero-lead { grid-area:1/1; }
  .hero-inner > .shape-row { grid-area:2/1; }
  .hero-inner > .hero-cta  { grid-area:3/1; }
  .hero-inner > .hero-art  { grid-area:1/3; align-self:center; width:100%; }
}
/* MOBILE — ABOVE the text (Tom), and the soccer ball's mobile size (3.5 units =
   112) so the page's two marks agree at phone width. LEFT-SET, not centred: it
   opens a left-set stack (headline, lede, chips, button all begin on the same
   line), and a centred mark over left-set type reads as a stray. The ball is
   centred because it sits over a full-width CARD, which is a different problem. */
@media (max-width:1079.98px){
  .hero-art{ width:calc(3.5 * var(--v-line)); margin:0 0 var(--v-line); }
}

/* THE SHAPE ROW — what a ticket can be. LABELS, not controls: no hover, no
   selection, no accent except the open-ended one. */
.shape-row{ display:flex; flex-wrap:wrap; gap:var(--space-2);
  margin:var(--space-6) 0 0; }
.shape{ display:inline-flex; align-items:center; height:var(--v-line);
  padding:0 var(--space-3); font:var(--text-small); font-family:var(--font-mono);
  letter-spacing:var(--track-small); color:var(--color-text-secondary);
  border-radius:var(--radius-sm); corner-shape:var(--corner-shape);
  box-shadow:inset 0 0 0 1px var(--color-border); }
.shape.is-open{ color:var(--color-accent);
  box-shadow:inset 0 0 0 1px var(--color-accent-bdr); }

/* ═══ 6 · SECTION HEADS ══════════════════════════════════════════════════════
 * Each beat is now its own SECTION, so its title takes the serif HEADING tier —
 * not the subhead an in-article block would take. Three separate jobs, three
 * tracks: the head GROUP shares the canvas origin, the TITLE takes the span-10
 * title track (at the serif tier a span-8 track breaks titles far too eagerly),
 * and the LEDE keeps the span-8 content track because it is reading text.
 *
 * ⛔ THE EYEBROWS ARE DELETED — 2026-07-29, Tom. Every section wore a mono accent
 * kicker ("The idea", "The data", …). They were a hangover from the deck's slide
 * titles, they spent the accent on furniture nine times over, and a ½-unit gap
 * under each one was the only sub-unit step in the page's structural rhythm. A
 * section head is now exactly two registers — title, then lede — and the head
 * group's own 2-unit gap to the payload is the only spacing decision in it. */
:root{ --sp-title: calc(10*var(--col) + 9*var(--col-gutter)); }   /* 936 */
.sec-head{ max-width:var(--sp-canvas); margin:0 0 var(--space-6); }
.sec-head > h2{ font:var(--text-heading); color:var(--color-text);
  max-width:var(--sp-title); margin:0 0 var(--v-line); }
/* ⭐ THE ELEVEN-COLUMN TITLE (2026-07-29, Tom: §03's header "should span more
   columns, so it doesn't break line"). MEASURED, not guessed: at the heading tier
   (CM Function 52/64) that title sets 946.1px on one line and the standard title
   track is 936, so it was breaking by TEN PIXELS. Eleven columns = 1032 clears it
   with 86 to spare, and is still a WHOLE COLUMN COUNT rather than an invented cap,
   so the title's right edge lands on a real grid line. Twelve (1128) would be the
   full canvas and would leave the title no air at all against the figures below.
   ⚠ This is a CAP, not a width: below the paper regime the h2 wraps as normal. If
   you re-cut this title, re-measure. A title that fits in 936 does not need it. */
.sec-head.is-wide > h2{ max-width:calc(11*var(--col) + 10*var(--col-gutter)); }
.sec-head > h2:last-child{ margin-bottom:0; }
.sec-lead{ font:var(--text-lede); color:var(--color-text-secondary);
  max-width:var(--sp-content); margin:0; }

/* ═══ 7 · TEXT + PLACEMENT ═══════════════════════════════════════════════════
 * ⚑ THE COMPONENT FIREWALL (ledger law (b): a component's internals are
 * AUTHORITATIVE — page/section rules must not reach inside one). `:where()`
 * carries ZERO specificity, so each selector keeps exactly the weight it had; it
 * simply stops reaching where it shouldn't. Without it, a section blanket (0,1,1)
 * out-specifies a component's own `p` rule (0,1,0) and silently repaints it —
 * measured three times on this page: `.venue-k`; `.pan-lbl` rendering at body
 * 20/32 inside a phone; and `.pf-duo-cap` ("Interface") doing the same inside a
 * figure. THE UX PANELS AND THE PAYOFF FIGURES ARE BOTH IN THE GUARD for that
 * reason — each is a housing with its own internal type scale. */
:is(.sec-inner p, .prose p):not(:where([class*="gc-"], [class*="gc-"] *, .pan, .pan *, .pf, .pf *, .sec-head p, .hero-cta)){
  font:var(--text-body); color:var(--color-text-secondary);
  max-width:var(--sp-content); margin:0 0 var(--v-line); }
:is(.sec-inner strong, .prose strong):not(:where([class*="gc-"], [class*="gc-"] *, .pan, .pan *, .pf, .pf *)){
  color:var(--color-text); font-weight:620; }
/* EMPHASIS IS WEIGHT, NOT ITALIC (the serif has no italic; the sans ladder is
   rest 460 · medium 540 · semibold 620). */
:is(.sec-inner em, .prose em):not(:where([class*="gc-"], [class*="gc-"] *, .pan, .pan *, .pf, .pf *)){
  color:var(--color-text); font-style:normal; font-weight:540; }
/* ⚠ THE GUARD MUST NAME THE COMPONENT ITSELF, NOT ONLY ITS DESCENDANTS. Measured
   2026-07-28: `a.gc-btn` (the mailto CTA) IS a component root, and the old guard
   only excluded `[class*="gc-"] *`, so this rule (0,2,0) beat `.gc-btn` (0,1,0)
   and painted the button's LABEL accent-blue on a dark fill. Every guard in this
   block now lists the root and the subtree — the same pair the `p` rule above has
   carried since the first firewall fix. */
:is(.sec-inner a, .prose a):not(:where([class*="gc-"], [class*="gc-"] *, .pan, .pan *, .pf, .pf *, .hero-cta a)){
  color:var(--color-accent); text-decoration:none; }
:is(.sec-inner a, .prose a):not(:where([class*="gc-"], [class*="gc-"] *, .pan, .pan *, .pf, .pf *)):hover{ text-decoration:underline; }

/* COMPONENT PLACEMENT — a component ships MARGIN-LESS; the SECTION places it.
   1 unit above a figure; the caption owns the ½-unit hug under it and a clean
   1-unit gap below (its other ½ is the caption's own padding). */
.sec-inner > .pf,
.sec-inner > .pair,
.sec-inner > .share,
.sec-inner > .gc-table-scroll{ margin:var(--v-line) 0 0; }
.sec-inner > .gc-caption{ margin:calc(var(--v-line)/2) 0 var(--v-line); }
.sec-inner > p.gc-result{ margin:var(--v-line) 0 0; }
.sec-inner > :first-child{ margin-top:0; }
.sec-inner > :last-child{ margin-bottom:0; }

/* ═══ 8 · COMPONENTS — poured from home/_build/components.css @ 2026-07-28 ═════
 * Only the components this page adopts. Values are VERBATIM; the comments are
 * compressed to the load-bearing reasoning. Any divergence is marked ⚠ PAGE.
 * ───────────────────────────────────────────────────────────────────────────── */

/* ⛔ THE PAGE LINK COMPONENT IS NOT USED HERE (2026-07-28). It carried the
   hero's "← Back to functionSPACE" topline, which was deleted with the rest of
   the article furniture. The whole rule set went with it rather than sitting
   here dark — dead CSS is how a page-local sheet drifts from what it renders.
   If this page ever needs one, adopt `gc-pagelink` from components.css.
   The BADGE below is still live: the venue cards use it. */

/* ── BADGE — only the gray/subtle variant is adopted. 24 tall (¾ unit) so it sits
   cleanly on a 1-unit row; surface-alt fill + primary ink, no accent (the accent
   is never a status). Its one remaining use is the venue cards' category marker;
   the league cards took their league as a card TITLE instead (2026-07-28, Tom) —
   a badge marks status, and a league is the card's subject. */
.gc-badge{ box-sizing:border-box; display:inline-flex; align-items:center; justify-content:center;
  height:24px; padding:2px 12px; border-radius:var(--radius-full); corner-shape:var(--corner-shape);
  font:var(--text-micro); font-family:var(--font-sans);
  text-transform:capitalize; white-space:nowrap; }
.gc-badge.b-gray.sub, .gc-badge.sub{ background:var(--color-surface-alt); color:var(--color-text); }

/* ── RESULT — unboxed: a mono kicker + primary ink. The mathcore register:
   differentiate by structure, not by a box. Element-qualified so it beats the
   page's blanket section `p` rule. */
p.gc-result{ margin:0; font:var(--text-body); color:var(--color-text); }
.gc-result .res-label{ font:var(--text-micro); font-family:var(--font-mono);
  text-transform:uppercase; letter-spacing:var(--track-micro);
  color:var(--color-text-tertiary); margin-right:.7em; }
.gc-result strong{ color:var(--color-text); font-weight:620; }

/* ── CAPTION — ⭐ THE LEADING LAW: a text component is grid-true at EVERY line
   count only if its LEADING IS THE VERTICAL UNIT (box = 2·pad + L·leading must be
   ≡0 mod 32 for all L ⇒ leading | 32). So the SIZE drops a tier and the LEADING
   stays the unit. Plus ONE UNIT OF CHROME: ½ above (the hug, placed by the block)
   + ½ below (this padding, internal). */
.gc-caption, .gc-table caption{ margin:0; font:var(--text-small);
  line-height:var(--v-line); color:var(--color-text-tertiary); text-align:left;
  padding-bottom:calc(var(--v-line)/2); }
.gc-caption strong, .gc-table caption strong{ color:var(--color-text-secondary); font-weight:600; }

/* ── TABLE — ONE rule (under the header), drawn INSIDE so its 1px costs no layout.
   Header distinguished by WEIGHT, not by shouting or by size. Unit leading on
   every cell ⇒ a 1-line row is exactly 1 unit and rows cannot drift, so vertical
   padding is ZERO. Horizontal padding is a GUTTER only, so column 1 sits flush
   with the prose measure and the last column ends flush with it. */
.gc-table-scroll{ overflow-x:auto; }
.gc-table{ width:100%; border-collapse:collapse; font-variant-numeric:tabular-nums;
  font:var(--text-small); line-height:var(--v-line); }
.gc-table th, .gc-table td{ padding:0 var(--space-5) 0 0; text-align:left; vertical-align:top; }
.gc-table th:last-child, .gc-table td:last-child{ padding-right:0; }
.gc-table thead tr{ box-shadow:inset 0 -1px 0 var(--color-border); }
.gc-table th{ font-weight:620; color:var(--color-text); }
.gc-table td{ color:var(--color-text-secondary); }
.gc-table caption{ caption-side:bottom; padding-top:calc(var(--v-line)/2); }
/* ⚠ PAGE DIVERGENCE — `.is-keyed`: A KEYED TABLE, NOT A DATA TABLE (2026-07-29,
   Tom: "put subtle horizontal lines in the table — this is too hard to read right
   now. Also the table is spaced too wide for its content").
   Both symptoms have one cause. The component's `width:100%` + a header rule is
   built for a DATA table: several columns, a thead to anchor the eye, cells the
   reader scans DOWN. This is a two-column key/value list with NO header row — so
   the component gave it no rule at all, and stretching two short columns across
   744 opened a ~290px void between the key and its value. The eye has to travel
   that gap with nothing to hold, four times.
   The fix is the component's own logic applied to this shape: the ONE rule exists
   to separate the reading unit, and with no header the reading unit is the ROW.
   So the rule moves to the row, at the DIVIDER rung and dashed — the same weight
   the finding rows use — and the table shrinks to its content with the columns a
   gutter apart. It is still one rule per reading unit, still drawn INSIDE, still
   whole-unit rows. ⚠ Do NOT generalise this to `gc-table`: a real data table on
   this page would take the component unchanged. */
.gc-table.is-keyed{ width:auto; }
.gc-table.is-keyed th{ white-space:nowrap; padding-right:var(--space-6); }
.gc-table.is-keyed td{ padding-right:0; }
.gc-table.is-keyed tbody tr{ box-shadow:inset 0 -1px 0 var(--color-border); }
.gc-table.is-keyed tbody tr:first-child{
  box-shadow:inset 0 1px 0 var(--color-border), inset 0 -1px 0 var(--color-border); }

/* ── CARD — chrome is 1 unit (½ padding top + ½ bottom), border drawn INSIDE so
   the card stays whole-unit, elevation = tint + border (never a shadow, never a
   lift). Hover = the invert highlight at card scale.
   ⚠ PAGE DIVERGENCE: `.is-static`. The invert is a LINK affordance — "choose this
   one among a set". This page's venue and league cards are not links, so hovering
   them must not promise a target. `.is-static` neutralises it; everything else
   about the component is untouched. */
.gc-card{ display:flex; flex-direction:column; box-sizing:border-box;
  padding:calc(var(--v-line)/2) var(--space-5);
  border-radius:var(--radius-md); corner-shape:var(--corner-shape);
  box-shadow:inset 0 0 0 1px var(--color-border);
  background:var(--color-surface); color:inherit; text-decoration:none; }
.gc-card > *{ margin:0; }
.gc-card > .gc-badge{ align-self:start; margin-block:calc((var(--v-line) - 24px)/2); }
.gc-card-top{ display:flex; align-items:center; gap:var(--space-3); height:var(--v-line); }
.gc-card-top > svg{ flex:none; color:var(--color-text-tertiary); }
.gc-card{ --card-title-lines:2; --card-desc-lines:3; }
.gc-card-title, .gc-card-desc{ display:-webkit-box; -webkit-box-orient:vertical; overflow:hidden;
  -webkit-line-clamp:var(--lines); line-clamp:var(--lines);
  min-height:calc(var(--lines) * var(--v-line)); }
.gc-card-title{ --lines:var(--card-title-lines);
  font:var(--text-subhead); color:var(--color-text); margin-top:calc(var(--v-line)/2); }
.gc-card-desc{ --lines:var(--card-desc-lines);
  font:var(--text-small); line-height:var(--v-line);
  color:var(--color-text-secondary); margin-top:calc(var(--v-line)/2); }
.gc-card-meta{ font:var(--text-micro); font-family:var(--font-mono);
  text-transform:uppercase; letter-spacing:var(--track-micro); color:var(--color-text-tertiary);
  margin-top:auto; padding-top:var(--v-line); padding-bottom:calc(var(--v-line)/2); }
.gc-card:hover{ background:var(--sel-bg); box-shadow:inset 0 0 0 1px var(--sel-bg); }
.gc-card:hover :is(.gc-card-title, .gc-card-desc, .gc-card-meta){ color:var(--sel-fg); }
.gc-card:hover .gc-badge{ background:color-mix(in srgb, var(--sel-fg) 16%, transparent); color:var(--sel-fg); }
.gc-card.is-static:hover{ background:var(--color-surface);
  box-shadow:inset 0 0 0 1px var(--color-border); }        /* ⚠ PAGE — see above */
.gc-card.is-static:hover :is(.gc-card-title, .gc-card-desc, .gc-card-meta){ color:inherit; }
.gc-card.is-static:hover .gc-badge{ background:var(--color-surface-alt); color:var(--color-text); }

/* ── BUTTON — height 48 = 1½ units, centring exactly in the 2-unit nav band with
   8px each side, and the 32 line-box centring inside it with 8px each side.
   Buttons are NEUTRAL (the ink is the brand); the accent is never a button.
   Secondary takes a BORDER, not a shadow, and it sits on --color-wireframe (the
   STRUCTURAL rung) not --color-border (the divider rung) — a control's edge is
   structure, which is why it read weak at the divider value.
   ⛔ NO INVERT ON CONTROLS: on a control pair, fill-vs-outline IS the hierarchy,
   so swapping it inverts the meaning. A button's hover must INTENSIFY. */
.gc-btn{ display:inline-flex; align-items:center; justify-content:center; box-sizing:border-box;
  height:calc(1.5 * var(--v-line)); padding:0 var(--space-4);
  font:var(--text-small); font-weight:540; line-height:var(--v-line);
  border:0; border-radius:var(--radius-md); corner-shape:var(--corner-shape);
  text-decoration:none; white-space:nowrap; cursor:pointer;
  background:var(--color-strong); color:var(--color-bg); }
.gc-btn:hover{ background:var(--color-strong-hover, light-dark(#030304, #FBFBFB)); }
.gc-btn.is-secondary{ background:transparent; color:var(--color-text-secondary);
  box-shadow:inset 0 0 0 1px var(--color-wireframe); }
.gc-btn.is-secondary:hover{ background:transparent; color:var(--color-text);
  box-shadow:inset 0 0 0 1px var(--color-strong); }

/* ── TABS — height 32 = 1 unit, gap 24 = one gutter. Selected vs not is INK + a
   1px rule beneath (the same mechanism as the index's active state), nothing
   more: no pill, no radius, no accent fill. The icon slot carries the
   payoff-shape glyph — category IS shape. */
.gc-tabs{ display:flex; align-items:stretch; gap:var(--col-gutter); flex-wrap:wrap;
  min-height:var(--v-line); }
.gc-tab{ display:inline-flex; align-items:center; gap:var(--space-2); box-sizing:border-box;
  height:var(--v-line); padding:0; background:none; border:0; border-radius:0; cursor:pointer;
  font:var(--text-small); font-weight:540; line-height:var(--v-line);
  color:var(--color-text-tertiary); white-space:nowrap; }
.gc-tab > svg{ flex:none; color:var(--color-accent); opacity:.55; }
.gc-tab:hover{ color:var(--color-text-secondary); }
.gc-tab:hover > svg{ opacity:.8; }
.gc-tab.is-active, .gc-tab.is-on{ color:var(--color-text);
  background:linear-gradient(var(--color-text), var(--color-text)) no-repeat left bottom / 100% 1px; }
.gc-tab.is-active > svg, .gc-tab.is-on > svg{ opacity:1; }
.gc-tab:focus-visible{ outline:2px solid var(--color-accent-bdr); outline-offset:2px; }
/* ⭐ A TRUE 2×2 GRID AT PHONE WIDTHS (2026-07-29, Tom: "the toggles are weirdly
   aligned and should be made more neat"). They were, and it is what flex-wrap
   does with items of unequal width: measured at 390, row 1 was Binary(81) and
   Range(80) starting at x 40 and 133, row 2 was Long/Short(127) and Custom(91)
   starting at x 40 and 179 — so the second column did not line up with itself and
   the block read as four labels dropped on the floor rather than one control.
   A 2-column grid puts every tab on one of two axes at every combination of
   label widths, including the longer "Dynamic" wording if these ever inherit it.
   `justify-content:start` on the tab keeps the glyph beside its word rather than
   stretching the pair across the cell. */
@media (max-width:720px){
  .gc-tabs{ display:grid; grid-template-columns:repeat(2, minmax(0,1fr));
    gap:calc(var(--v-line)/4) var(--col-gutter); }
  .gc-tab{ justify-content:flex-start; }
}

/* ── WINDOW — poured 2026-07-29. ⚠ It was dropped on 2026-07-28 and is BACK for a
   different job. It was dropped as a frame around the PHONE panels — a browser
   shell around a phone bezel is two chromes deep for one screenshot, and that
   reasoning still stands; the phones have no window. It returns as the housing for
   the four PAYOFF FIGURES, which is the job it is actually for: a live surface.
   The whole frame is 7 units — bar 2 (64) + body 5 — and inside the bar ½ unit of
   padding + a 1-unit control row + ½ unit, so a light (12) or a `gc-tab` (32)
   centres with no magic number. The bar's rule is drawn INSIDE, so the 1px costs
   no layout and the bar stays exactly 2 units.
   ⚠ THE TRAFFIC LIGHTS ARE NEUTRAL, NOT RED/AMBER/GREEN — the component's one
   visible deviation from Geist, and it is a colour-law decision: those three hues
   are the FUNCTIONAL signal set (positive · caution · negative), which this system
   spends on meaning and never on decoration. Geometry kept exactly (12×12, gap 8),
   ink moved to the hairline rung. */
/* ⚠ PAGE DIVERGENCE 1 — THE FRAME'S OUTLINE IS DRAWN ON AN OVERLAY, so it encloses
   the WHOLE component. The component paints its 1px on `.gc-window` itself, and the
   BAR then paints its own opaque background over the top 2 units of that box — so
   the outline visually wraps the body only and the chrome sits outside its own
   frame. Reproduced from the shipped `components.css` + `tokens.css` at rendered
   pixels, so it is the component's behaviour and not this page's pour. An
   `::after` at `inset:0` with `pointer-events:none` paints ABOVE both children,
   costs no layout, and keeps the border on the same inset mechanism.
   ⚠ PAGE DIVERGENCE 2 — THE TWO TONES ARE THE OTHER WAY UP. Shipped: bar =
   `--color-surface`, body = `--color-surface-alt`, which is Geist's relationship
   (chrome lighter than the well). In light that is a WHITE bar over a GREY body —
   the content reads recessed and slightly dirty, which is the wrong way round when
   the body holds the page's primary instrument. Here the CONTENT takes the card
   rung and the CHROME takes the tint rung: light → grey bar, white body; dark →
   the bar lifts a step off a darker body. Same contrast, opposite polarity, and it
   restores the ground the payoff figures were originally drawn against (`.pf` was
   `--color-surface` before the window adoption).
   ⚠ FOR THE SWEEP: both of these are corrections to `gc-window`, not to this page.
   If they are right, they belong in `components.css` and these two rules should be
   deleted rather than carried. */
.gc-window{ box-sizing:border-box; overflow:hidden; position:relative;
  border-radius:var(--radius-md); corner-shape:var(--corner-shape);
  background:var(--color-surface); }
.gc-window::after{ content:""; position:absolute; inset:0; pointer-events:none;
  border-radius:inherit; corner-shape:var(--corner-shape);
  box-shadow:inset 0 0 0 1px var(--color-border); }
.gc-window-bar{ box-sizing:border-box; display:flex; align-items:center;
  justify-content:space-between; gap:var(--col-gutter);
  height:calc(2 * var(--v-line)); padding:0 var(--space-5);
  background:var(--color-surface-alt);
  box-shadow:inset 0 -1px 0 var(--color-border); }
.gc-window-lights{ display:flex; align-items:center; gap:var(--space-2); flex:none; }
.gc-window-lights i{ width:12px; height:12px; border-radius:var(--radius-full);
  background:var(--color-border); transition:background .22s ease; }
/* ⚠ PAGE DIVERGENCE 3 — THE LIGHTS COME ON WHEN YOU TOUCH THE WINDOW (Tom's
   flourish, 2026-07-29). The component keeps them NEUTRAL at rest, and that rule
   is untouched and still right: three coloured dots sitting permanently on an
   otherwise monochrome page would be the loudest colour on it, and would read as
   a STATUS. On hover they are not a status — they are the window acknowledging a
   pointer, on a surface that really is live, and they go out again the moment you
   leave. The hues are OUR functional signal set (negative · caution · positive)
   in Geist's own left-to-right order, so the reference is legible without
   borrowing anyone's hexes.
   Cheap to revert: delete this one rule and the component is back. */
.pf:hover .gc-window-lights i:nth-child(1),
.gc-window:hover .gc-window-lights i:nth-child(1){ background:var(--color-negative); }
.pf:hover .gc-window-lights i:nth-child(2),
.gc-window:hover .gc-window-lights i:nth-child(2){ background:var(--color-caution); }
.pf:hover .gc-window-lights i:nth-child(3),
.gc-window:hover .gc-window-lights i:nth-child(3){ background:var(--color-positive); }
@media (prefers-reduced-motion: reduce){ .gc-window-lights i{ transition:none; } }
.gc-window-body{ box-sizing:border-box;
  padding:calc(var(--v-line)/2) var(--space-5); }

/* ⛔ PEER RECEDE IS NOT USED HERE (2026-07-28, Tom: "the cards … don't need the
   hover/dim effect — they aren't clickable"). `gc-peers` dims the rest of a set
   while one is highlighted, and that is the other half of the INVERT: together
   they say "choose one of these". Both halves belong to a set of LINKS. This
   page's venue and league cards are static, so the page was making a promise it
   could not keep — the invert was already neutralised by `.is-static`, and the
   dim was the half still firing. Both grids dropped the class; the rule went with
   it rather than sitting here dark. Adopt `gc-peers` from components.css if a
   clickable set ever lands on this page. */

/* ═══ 9 · PAGE-LOCAL BLOCKS ═══════════════════════════════════════════════════
 * Things with no component ancestor yet. Each is authored on the same laws, so
 * the sweep can map or replace them cleanly. */

/* FINDING ROWS — three numbered claims. Ruled, unboxed (mathcore: differentiate by
   structure, not by a box), on the LEADING LAW so each row is a whole number of
   units at any line count. The number is furniture; the claim is a subhead; the
   evidence is small at unit leading. */
.rows{ margin:0; }
.row{ display:grid; grid-template-columns:var(--space-6) minmax(0,1fr); gap:var(--space-5);
  padding:var(--v-line) 0 calc(var(--v-line) - 1px);
  border-top:1px dashed var(--color-border); }
/* THE LAST ROW CARRIES TWO BORDERS, so it needs TWO pixels of compensation, not
   one. It had `--v-line - 1px` like every other row and came out 1px over, which
   put the whole three-row block 1px off and left the housing snap to absorb it.
   Correct at the source instead: the snap should be catching sub-pixel font
   metrics, not a known off-by-one. */
.row:last-child{ border-bottom:1px dashed var(--color-border);
  padding-bottom:calc(var(--v-line) - 2px); }
.row-n{ font:var(--text-micro); font-family:var(--font-mono);
  letter-spacing:var(--track-micro); color:var(--color-text-tertiary);
  line-height:var(--v-line); }
/* ONE UNIT under the claim (2026-07-29, Tom: "there doesn't seem like there's
   enough gap"). It was zero — the subhead's line box sat straight on the body's —
   and 1 unit is the system's own head→body step everywhere else (`system.css`:
   "every other head→body relationship in the system is exactly 1 unit"). A half
   unit would have read better in isolation and put the row on a half. */
.row-h{ font:var(--text-subhead); color:var(--color-text); margin:0 0 var(--v-line);
  max-width:var(--sp-content); }
.row-b{ font:var(--text-small); line-height:var(--v-line);
  color:var(--color-text-secondary); margin:0; }
.row-b strong{ color:var(--color-text); font-weight:620; }
/* THE ATTRIBUTION — furniture, so micro/mono/tertiary, the same register the row
   NUMBER already uses.
   ⚠ TWO-CLASS SELECTORS, DELIBERATELY. The §7 text firewall is
   `:is(.sec-inner p, .prose p):not(:where(…))` at (0,1,1) and it sets
   `margin:0 0 var(--v-line)` on every unguarded p in a section. `.row-b` is such a
   p, so its own `margin:0` at (0,1,0) LOST, and every row carried a phantom unit
   of margin below its last line: 32 of air at the top of a row against 63 at the
   bottom. It landed on whole units, so no rhythm check ever caught it; it just
   read bottom-heavy. `.row .row-b` is (0,2,0) and wins cleanly, which is a better
   fix than widening the firewall's exclusion list for two page-local classes.
   The gap to the attribution is a FULL unit, the system's own head→body step,
   which is what keeps the row content whole: 32 + 32 + body + 32 + 32 is always a
   multiple of 32, so the row's air is symmetric at every line count. A half unit
   read better in isolation and put the row on a half. */
.row .row-b{ max-width:var(--sp-content); margin:0; }
.row .row-by{ font:var(--text-micro); font-family:var(--font-mono);
  letter-spacing:var(--track-micro); text-transform:uppercase;
  color:var(--color-text-tertiary); line-height:var(--v-line);
  max-width:var(--sp-content); margin:var(--v-line) 0 0; }
@media (max-width:640px){ .row{ grid-template-columns:1fr; gap:var(--space-2); } }

/* STAT FIGURES — a hero number is DATA, so it is Geist Mono and tabular, not the
   serif. It takes the HEADING SIZE (52) on the heading LINE (64 = 2 units) so it
   sits at a defined step of the scale rather than an invented one; the label
   beneath is the furniture register. Row = 3 units. */
/* ⭐ THE STAT AND ITS LABEL SIT ON ONE BASELINE (2026-07-29, Tom: "rather than
 * vertically stacked do them horizontally, tastefully… think about how you use
 * the columns"). Two decisions, both structural:
 *  · THE PAIRS ARE BASELINE-ALIGNED, not stacked. A 52px numeral and a 12px cap
 *    share a baseline, so the label reads as a unit OF the number rather than a
 *    caption under it, and the row stays exactly 2 units tall.
 *  · THE ROW IS THREE COLUMNS OF THE CONTENT TRACK, not a flex row with a made-up
 *    gap. 744 in three = 232 a cell, which is close enough that the three read as
 *    one row and wide enough that the longest label ("Polysights") clears the
 *    numeral. It also lines the stats up with the sentence underneath, which is
 *    what they are evidence for. */
.figures{ display:grid; grid-template-columns:repeat(3, minmax(0,1fr));
  gap:var(--col-gutter); max-width:var(--sp-content);
  margin:var(--v-line) 0 0; }
.fig-stat{ display:flex; align-items:baseline; gap:var(--space-3);
  min-width:0; position:relative; }
/* THE DIVIDER sits in the GUTTER, not on the cell edge — half a gutter to the left
   of each cell after the first, so it reads as the rule BETWEEN two figures rather
   than as a border belonging to one of them. Full row height (2 units), on the
   divider rung. */
.fig-stat + .fig-stat::before{ content:""; position:absolute;
  left:calc(var(--col-gutter) / -2); top:0; bottom:0; width:1px;
  background:var(--color-border); }
/* THE STRIP'S CAPTION — the sentence that reads the numbers. It was plain body
   copy, which put it in the same register as the section's argument and floated it
   free of the figures it explains; as a caption it drops a tier, hugs the row at ½
   unit, and its lead-in carries the unit the three numbers are IN. */
.fig-note{ max-width:var(--sp-content); margin:calc(var(--v-line)/2) 0 0; }
@media (max-width:720px){
  .figures{ grid-template-columns:1fr; }
  .fig-stat + .fig-stat::before{ display:none; }   /* stacked, a vertical rule between rows means nothing */
}
.fig-stat b{ font-family:var(--font-mono); font-size:52px; line-height:64px;
  font-weight:600; color:var(--color-text); font-variant-numeric:tabular-nums;
  letter-spacing:-.02em; }
.fig-stat span{ font:var(--text-micro); font-family:var(--font-mono);
  text-transform:uppercase; letter-spacing:var(--track-micro);
  color:var(--color-text-tertiary); line-height:var(--v-line); }

/* THE TRADE-TYPE SHARE CHART — rebuilt fluid (the deck's was a baked-pixel SVG).
   Housed like every other surface: inset border, no shadow. Rows are whole units. */
.share{ border-radius:var(--radius-md); corner-shape:var(--corner-shape);
  background:var(--color-surface); overflow:hidden;
  box-shadow:inset 0 0 0 1px var(--color-border); }
.share-head{ display:flex; align-items:center; justify-content:space-between;
  flex-wrap:wrap; gap:var(--space-2) var(--space-3);
  padding:0 var(--space-5); min-height:calc(2 * var(--v-line));
  box-shadow:inset 0 -1px 0 var(--color-border); }
.share-head .k{ font:var(--text-micro); font-family:var(--font-mono);
  text-transform:uppercase; letter-spacing:var(--track-micro); color:var(--color-text-secondary); }
.legend{ display:flex; flex-wrap:wrap; gap:var(--space-3); }
.legend span{ display:inline-flex; align-items:center; gap:var(--space-1);
  font:var(--text-micro); font-family:var(--font-mono); letter-spacing:var(--track-micro);
  color:var(--color-text-tertiary); }
.legend i{ width:9px; height:9px; flex:none; }
.share-body{ padding:var(--space-4) var(--space-5);
  display:flex; flex-direction:column; gap:var(--space-4); }
.share-row{ display:grid; grid-template-columns:96px minmax(0,1fr); gap:var(--space-4);
  align-items:center; }
.share-row .app{ font:var(--text-small); font-weight:620; color:var(--color-text);
  line-height:var(--v-line); text-align:right; }
.share-bar{ display:flex; height:var(--v-line); border-radius:var(--radius-sm);
  corner-shape:var(--corner-shape); overflow:hidden; background:var(--color-surface-alt); }
.share-seg{ display:flex; align-items:center; justify-content:center; min-width:0;
  font:var(--text-micro); font-family:var(--font-mono); font-weight:600;
  letter-spacing:var(--track-micro); color:#FBFBFB; font-variant-numeric:tabular-nums; }
.share-seg[data-c="point"]{ background:var(--cat-point); }
.share-seg[data-c="range"]{ background:var(--cat-range); }
.share-seg[data-c="ou"]   { background:var(--cat-ou); }
.share-seg[data-c="duel"] { background:var(--cat-duel); }
.share-seg[data-c="other"]{ background:var(--cat-other); }
.legend i[data-c="point"]{ background:var(--cat-point); }
.legend i[data-c="range"]{ background:var(--cat-range); }
.legend i[data-c="ou"]   { background:var(--cat-ou); }
.legend i[data-c="duel"] { background:var(--cat-duel); }
.legend i[data-c="other"]{ background:var(--cat-other); }
@media (max-width:640px){
  .share-row{ grid-template-columns:1fr; gap:var(--space-2); }
  .share-row .app{ text-align:left; }
}

/* VENUE + LEAGUE CARD GRIDS — on the canvas since the rebase, so the venues run
   4-up (one per column-triple) and the leagues 3-up. Neither set is clickable, so
   neither carries `gc-peers`; see the ⛔ note in §8. */
.venues{ display:grid; grid-template-columns:repeat(4, minmax(0,1fr));
  grid-template-rows:auto auto; gap:var(--col-gutter);
  align-items:stretch; margin:var(--v-line) 0 0; }
@media (max-width:1100px){ .venues{ grid-template-columns:repeat(2, minmax(0,1fr));
  grid-template-rows:auto auto auto auto; } }
@media (max-width:720px){ .venues{ grid-template-rows:none; } }

/* ⭐ THE DUOCHROME VENUE CARD (2026-07-29, Tom) ───────────────────────────────
 * The card answers two different questions — "you ship" and "it gets you" — and
 * they were reading as one paragraph split by a dashed line. So the card is two
 * BANDS now: the top stays as it was, and the lower half INVERTS.
 * The invert is not a new colour. `--sel-bg` / `--sel-fg` are the system's
 * existing invert pair — the same two values `::selection` uses and the same two
 * the card's own hover uses — so in light the band is near-black on paper and in
 * dark it is paper on near-black, with no per-theme override to keep in step.
 * ⚠ THE SPLIT LINE IS THE SAME HEIGHT ON ALL FOUR CARDS, via `subgrid`: the row
 * grid lives on `.venues` and each card adopts it, so the top bands are sized by
 * the TALLEST top rather than each card sizing itself. Without it a 2-line and a
 * 3-line "you ship" put the four inversions at four different heights and the row
 * reads as ragged. `margin-top:auto` on the lower band is the fallback where
 * subgrid is unavailable — the inversion still bottoms out, just unaligned.
 * The dashed divider is gone: the colour change IS the divider now, and drawing
 * both would be saying the same thing twice. */
.venue{ overflow:hidden; padding:0; grid-row:span 2;
  display:grid; grid-template-rows:subgrid; }
@media (max-width:720px){ .venue{ grid-row:auto; grid-template-rows:auto auto; } }
.venue-top{ padding:calc(var(--v-line)/2) var(--space-5); }
.venue-gets{ margin-top:auto;
  padding:calc(var(--v-line)/2) var(--space-5);
  background:var(--sel-bg); color:var(--sel-fg); }
/* ⚠ WITH SUBGRID THE BAND MUST STRETCH, NOT BOTTOM OUT. `margin-top:auto` is the
   no-subgrid fallback and it is actively WRONG once the shared row exists: inside
   a row sized by the tallest band it pushes each shorter band to the row's floor,
   so the four inversions end up bottom-aligned and top-ragged — the exact fault
   subgrid was added to fix (measured: tops at 104/136/136/168). Letting each band
   fill its row aligns both edges and makes the four inverted areas identical. */
@supports (grid-template-rows: subgrid){ .venue-gets{ margin-top:0; } }
/* the inverted band re-states the card's OWN ink ramp against its new ground —
   the page tokens are all solved against the page background and would be wrong
   here, so the two rungs are mixed out of the band's own foreground. */
.venue-gets .venue-dl dt{ color:color-mix(in srgb, var(--sel-fg) 62%, transparent); }
.venue-gets .venue-dl dd{ color:var(--sel-fg); }
.venue-gets .venue-dl dd strong{ color:var(--sel-fg); }
.leagues{ display:grid; grid-template-columns:repeat(3, minmax(0,1fr));
  gap:var(--col-gutter); align-items:stretch; margin:var(--v-line) 0 0; }
/* THE LEAGUE CARD — glyph row, then the league at SUBHEAD, then the line of copy.
   The clamp counts are set to what these cards actually hold (1-line titles,
   2-line copy) so the reserved min-heights are the real heights and the three
   cards agree without a stretch hack. The glyph is FURNITURE: tertiary ink, never
   the accent, and monochrome line art at the same 1.5 stroke as the venue art. */
.leagues .gc-card{ --card-title-lines:1; --card-desc-lines:2; }
.leagues .gc-card-top{ color:var(--color-text-tertiary); }
.leagues .gc-card-top > svg{ display:block; }
.venue-art{ color:var(--color-accent); height:var(--space-6);
  margin:calc(var(--v-line)/2) 0 0; }
.venue-art svg{ display:block; width:100%; height:100%; }
.venue-dl{ margin:calc(var(--v-line)/2) 0 0; }
.venue-gets .venue-dl{ margin:0; }
.venue-dl dt{ font:var(--text-micro); font-family:var(--font-mono); text-transform:uppercase;
  letter-spacing:var(--track-micro); color:var(--color-text-tertiary); line-height:var(--v-line); }
.venue-dl dd{ font:var(--text-small); line-height:var(--v-line);
  color:var(--color-text); margin:0; }
/* ⭐ A TWO-COLUMN REGIME FOR THE LEAGUE CARDS (2026-07-29). Six cards now, and
   three columns held all the way down to 720, which left each card 192px at the
   834 tablet width. At 192 the descriptions need three lines, the clamp reserves
   two, and FIVE OF THE SIX CARDS SILENTLY LOST THEIR LAST LINE. That was true of
   the original three as well, so this is a pre-existing clip the second row simply
   made obvious. Two columns hands each card ~300px, which is two lines again.
   960 rather than 1100 (where `.venues` steps down) because these cards hold one
   short sentence where a venue card holds two definition lists, so they stay
   comfortable in three columns for longer. */
@media (max-width:960px){ .leagues{ grid-template-columns:repeat(2, minmax(0,1fr)); } }
@media (max-width:720px){ .venues, .leagues{ grid-template-columns:1fr; } }

/* ── THE PROOF ROW — prose + table on the content track, takeaway right-set ────
   The takeaway was a `gc-result` running the full track under the table: a mono
   kicker and a sentence, structurally identical to the prose above it and easy to
   read straight past. As a CARD beside the copy it is a different object at a
   glance, and the row reads as claim + evidence. (2026-07-29, Tom.) */
.proof-row{ display:grid; grid-template-columns:1fr; gap:var(--v-line); }
@media (min-width:1080px){
  .proof-row{
    --proof-lane: calc(1*var(--col) + 2*var(--col-gutter));   /* 120 */
    grid-template-columns:var(--sp-content) var(--proof-lane) minmax(0,1fr);
    gap:0; align-items:start;                                  /* 744 · 120 · 264 */
  }
  .proof-row > .proof-copy{ grid-column:1; }
  .proof-row > .proof-aside{ grid-column:3; }
}
/* THE ASIDE — the sphere, then the takeaway card. The mark's box opens on the
   row's top line, which is the lede's first line, so the two columns start
   together and the mark reads as belonging to the paragraph beside it rather than
   floating above the card. 5 units square + 1 unit to the card = 6 whole units.
   INK: the tertiary rung. The wireframe rung (which the pun wanted) is a hairline
   value and the mark vanished at this size; full ink would out-shout the 52px
   serif two lines away. Not the accent — a brand mark is not a link, a selection,
   a focus ring or a data mark, which is the whole of the accent's licence. */
/* ⭐ CENTRED ON THE CARD (2026-07-29, Tom: "horizontally centred with the card
   'Why it matters' below it"). It was RIGHT-set — `margin-left:auto` landed the
   ball's right edge on the card's — which read as one stack only if you were
   reading the right edge. Centred, the ball sits on the card's own axis and the
   two are unmistakably one object. `margin-inline:auto` centres it in the aside,
   and the card fills the aside, so the two centres coincide by construction
   rather than by a number that would need re-deriving at every width.
   MOBILE: 3.5 units instead of 5 (112 against 160 = 30% smaller, Tom). At full
   size the ball was a third of a 390 screen wide and read as an illustration
   demanding attention rather than a mark introducing the card under it. */
.proof-mark{ width:calc(5 * var(--v-line)); margin:0 auto var(--v-line);
  color:var(--color-text-tertiary); }
.proof-mark svg{ display:block; width:100%; height:auto; }
@media (max-width:720px){
  .proof-mark{ width:calc(3.5 * var(--v-line)); }
}
.proof-copy > :last-child{ margin-bottom:0; }
/* ⚠ TWO-CLASS SELECTOR, DELIBERATELY. This is the THIRD instance of the same
   trap (see `.row .row-b` and `.hero-inner .hero-cta`): the §7 text firewall is
   `:is(.sec-inner p, .prose p):not(…)` at (0,1,1) and sets `margin:0 0
   var(--v-line)`. A plain `.proof-link{ margin-top:var(--v-line) }` is (0,1,0)
   and LOST — measured 2026-07-29, the gap between the table and this paragraph
   was ZERO (Tom: "there is not spacing after the table"). The bottom margin is
   killed too, because `.proof-copy > :last-child` already closes the block and
   the firewall's trailing unit would push the card's column out of step. */
.proof-copy .proof-link{ margin:var(--v-line) 0 0; }
/* ⚠ THE CLAMP COMES OFF for this one card. `gc-card` reserves a fixed number of
   description lines so a ROW of cards agrees without a stretch hack — that is the
   whole reason the clamp exists. This card has no peers, so the clamp has nothing
   to align to and was doing the one thing a clamp must never do on a page like
   this: truncating a sentence ("…trading shapes no…"). */
.proof-card .gc-card-desc{ -webkit-line-clamp:none; line-clamp:none;
  display:block; min-height:0; }

/* THE ACTION ROW */
/* THE ACTION ROW — centred (2026-07-29, Tom). It is the page's last gesture and
   it sits under a 3-up card row rather than under a paragraph, so a left-set pair
   read as orphaned off the first card instead of as the section's close. */
.actions{ display:flex; flex-wrap:wrap; gap:var(--space-4); justify-content:center;
  min-height:calc(2 * var(--v-line)); align-items:center; margin:var(--v-line) 0 0; }
@media (max-width:520px){ .gc-btn{ width:100%; } }

/* ═══ 10 · THE PAYOFF INSTRUMENT (pf / pm / pcfig) ════════════════════════════
 * Structure carried over from the Case Study page so both stay in lockstep with
 * payoff-core's conventions; every VALUE re-poured onto the tokens above, and the
 * caption moved OUT of the box to a `gc-caption` beneath it (the figure/caption
 * model the reference page uses for all eleven of its figures). */
/* ⭐ EVERY FIGURE IS THE `window` COMPONENT NOW (2026-07-29, Tom). A payoff chart is
 * a live surface, not a picture, and the window is the shape this system already
 * uses to say "a live surface" — it is what the homepage's CTA terminal wears. So
 * `figure.pf` IS a `gc-window`: the same 2-unit bar with the three neutral lights,
 * the same `--color-surface` chrome over a `--color-surface-alt` well, the same
 * inset 1px border. Adopting it also retired `.pf-head`, `.pf-tag` and the "pick a
 * shape" label — the bar carries the title and the tabs below carry the invitation.
 * ⚠ PAGE DIVERGENCE — THE BAR IS A 3-COLUMN GRID, NOT SPACE-BETWEEN. The component
 * pairs the lights with a right-hand slot (Geist's address pill, our package tabs).
 * Here the bar carries a TITLE, and a title has to be centred on the WINDOW, not on
 * the space left over beside the lights — with `space-between` it drifts with the
 * title's own length. `1fr auto 1fr` centres it on the frame; the third track is
 * deliberately empty and is what makes the centring true. */
figure.pf{ margin:0; position:relative; overflow:hidden;
  border-radius:var(--radius-md); corner-shape:var(--corner-shape);
  background:var(--color-surface);
  overflow-anchor:none; }   /* the live SVG mutates — keep scroll-anchoring off it */
.pf::after{ content:""; position:absolute; inset:0; pointer-events:none; z-index:2;
  border-radius:inherit; corner-shape:var(--corner-shape);
  box-shadow:inset 0 0 0 1px var(--color-border); }
.pf-bar{ display:grid; grid-template-columns:1fr auto 1fr; align-items:center; }
.pf-bar .pf-label{ grid-column:2; text-align:center;
  font:var(--text-micro); font-family:var(--font-mono);
  text-transform:uppercase; letter-spacing:var(--track-micro); color:var(--color-text-secondary); }
/* ⭐ THE DRAG HINT LIVES IN THE BAR (2026-07-29, Tom: the three paired charts
   "have a bit of unnecessary height, particularly at the top below the top
   browser chrome… I could see a div class='ctl-row' that was creating space that
   wasn't actually being used").
   He is right, and it was worse than dead space. In those three figures the
   `.ctl-row` held NOTHING BUT the hint — no tabs — and it cost min-height 32 +
   margin 16 = 48px. The hint fades to `opacity:0` permanently on first touch but
   KEEPS ITS BOX, so for the entire rest of the session those three charts carried
   a unit and a half of guaranteed-empty space between the window bar and the plot.
   The fix costs ZERO layout: the bar is already `1fr auto 1fr` with the label
   centred in column 2 and column 3 EMPTY, and it is already 2 units tall. The
   hint goes in column 3, right-set. It is the same micro/mono/tertiary register
   the bar's own label uses, so the bar reads as one strip rather than two, and
   the affordance now sits in the window chrome — which is where a browser puts
   affordances anyway.
   ⚠ THE HERO FIGURE KEEPS ITS `.ctl-row`. Its row holds the four shape TABS, is
   genuinely used, and must not be swept with these. Its hint stays beside them. */
.pf-bar .hint{ grid-column:3; justify-self:end; }
@media (max-width:720px){
  /* at phone widths the centred label already fills the bar; a third text would
     collide, so the hint drops. The halo on the handle still says "drag me". */
  .pf-bar .hint{ display:none; }
}
.pf-body{ padding:calc(var(--v-line)/2) var(--space-5); }

/* ── THE CODE STRIP ──────────────────────────────────────────────────────────
 * The ticket on screen, written as the call that builds it. Two lines and three
 * units, and every value in it is the homepage CTA terminal's — mono at the small
 * tier on UNIT leading, a ½-unit + inset rule + ½-unit separator, tertiary ink.
 * It sits INSIDE the window on purpose (Tom): it is the same instrument described
 * a second way, not a note about the instrument, so it belongs in the housing.
 * ⚠ ONE INK, ONE ACCENT. The homepage's rule is explicit — "syntax-colouring an
 * illustrative import with our single brand hue is decoration" — and there the one
 * accent goes on the package, because the package is the subject. Here the subject
 * is the reader's own numbers, which are DATA and are the thing they just dragged.
 * Nothing else in the line is coloured: no keywords, no strings, no function names.
 * ⚠ THE API IS NOT INVENTED. `generateRange`, `generateTriangle` and `execute` are
 * verbatim from the published case study's snippets; `design` is verbatim from the
 * homepage CTA. `...cfg` stands for the case study's own
 * `numBuckets, lowerBound, upperBound` destructure, shortened so the line holds. */
.pf-code{ margin:0 var(--space-5) calc(var(--v-line)/2);
  padding-top:calc(var(--v-line)/2);
  box-shadow:inset 0 1px 0 var(--color-border); }
.pf-code-cm, .pf-code-l{ display:block;
  font:var(--text-small); font-family:var(--font-mono); line-height:var(--v-line);
  color:var(--color-text-tertiary);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.pf-code-l{ color:var(--color-text-secondary); }
.pf-code-n{ color:var(--color-accent); font-variant-numeric:tabular-nums; }
@media (max-width:600px){
  .pf-code-cm, .pf-code-l{ white-space:normal; overflow-wrap:anywhere; }
}

/* THE DUO STACKS. The instrument and its ticket both belong to the CONTENT track
   (no breakouts), and splitting 744 two ways leaves a ~400 chart beside a ~272
   ticket that wraps on almost every line — measured. So the chart takes the full
   track and the ticket reads beneath it as a wide strip: the shape still answers
   the ticket, and both get room. */
/* THE DUO IS SIDE BY SIDE AGAIN. On the 744 prose track a split left a ~400 chart
   beside a ~272 ticket that wrapped on almost every line, so it had to stack. On
   the CANVAS the shape sits beside the ticket where it belongs — that adjacency IS
   the figure's argument: change the shape, read the ticket. */
/* ⚠ THE LANE IS A DECLARED TRACK HERE TOO (2026-07-29, Tom: "a bit more padding/
   space between the chart here and the UX, if necessary just shrink the chart").
   Same arithmetic as the section pairs, one column narrower because this lattice
   sits INSIDE a window's 24px padding rather than on the canvas:
      chart 552 (6 cols + 5 gutters) · lane 120 (1 col + 2 gutters) · ticket 360
   = 1032, and the canvas less the window's two 24s is exactly 1080, so the chart
   track absorbs the remainder as `minmax(0,1fr)` and the ticket stays at the 360
   the card was designed for. WAS `minmax(0,1fr) 360px` on one 24px gutter. */
.pf-duo{ display:grid; grid-template-columns:1fr; gap:var(--v-line); }
@media (min-width:900px){
  .pf-duo{
    --duo-lane: calc(1*var(--col) + 2*var(--col-gutter));   /* 120 */
    grid-template-columns:minmax(0,1fr) var(--duo-lane) 360px;
    gap:0; align-items:stretch;
  }
  .pf-duo-l{ grid-column:1; }
  .pf-duo-r{ grid-column:3; }
}
.pf-duo-l, .pf-duo-r{ min-width:0; display:flex; flex-direction:column; }
/* ⭐ THE TICKET IS BOTTOM-ALIGNED ON THE CHART'S X-AXIS (Tom). The two columns open
   on the same row — the chart's tab row and the ticket's "Interface" caption are
   both 1 unit — and from there the ticket is pushed to the FOOT of the column, so
   its base sits on the plot's baseline rather than floating in the middle of it.
   `margin-top:auto` on the card does it; the column is already a flex column and
   already stretches to the row's height. */
@media (min-width:900px){
  .pf-duo-r{ justify-content:flex-end; padding-bottom:var(--duo-foot, 0px); }
}
/* THE TICKET'S LABEL sits directly ON the card, not at the top of the column. The
   column is tall (the chart owns its height) and a label stranded at the top would
   be labelling 170px of air; travelling down WITH the card, it labels the thing it
   names and the slack collects in one place above both. */
.pf-duo-cap{ font:var(--text-micro); font-family:var(--font-mono);
  text-transform:uppercase; letter-spacing:var(--track-micro);
  color:var(--color-text-tertiary); line-height:var(--v-line);
  min-height:var(--v-line); margin:0 0 calc(var(--v-line)/2); flex:none; }

/* the chart's own control row — one whole unit, tabs left, hint right */
.ctl-row{ display:flex; align-items:center; justify-content:space-between;
  flex-wrap:wrap; gap:var(--space-3); min-height:var(--v-line);
  margin:0 0 calc(var(--v-line)/2); }

/* the "as a product" card
   ⚠ NO OFFSET FILL (2026-07-29, Tom: "this doesn't need to be offset with a
   different colour background, just make it the same"). It sat on
   `--color-surface-alt` — which since the window adoption is the WELL's own
   colour, so the card was a same-colour rectangle outlined against its own
   background: two containments, no information. It keeps its border, which is
   what says "this is one ticket", and drops the fill. */
.pm{ display:flex; flex-direction:column; min-height:0;
  background:transparent; border-radius:var(--radius-md);
  corner-shape:var(--corner-shape); box-shadow:inset 0 0 0 1px var(--color-border);
  padding:calc(var(--v-line)/2) var(--space-5); }
.pm[hidden]{ display:none; }
.pm-top{ display:flex; justify-content:space-between; align-items:center;
  gap:var(--space-3); min-height:var(--v-line); }
/* ⭐ THE CARD BREATHES AT PHONE WIDTHS (2026-07-29, Tom: "the interface card is a
   bit too cramped"). Two separate squeezes, both fixed here:
   1. The card's own side padding was `--space-5` (24) against a 310px card, so
      24/310 = 15% of the width was gutter and every line inside broke early. At
      the paper regime 24 is right; on a phone it is a tax. 16 gives the content
      32 more pixels, which is where "Will Yamal beat 6.0 FP?" stops wrapping.
   2. `.pm-top` is a `space-between` ROW — the ticker on the left, the settlement
      meta on the right. On a phone that meta ("the Final · settled 19 Jul") is
      longer than the space left over, so it wrapped to two lines INSIDE the row
      while the ticker stayed on one, which is what made the header look broken.
      It stacks instead: ticker, then meta under it, both left-set. */
@media (max-width:720px){
  .pm{ padding:calc(var(--v-line)/2) var(--space-4); }
  .pm-top{ flex-direction:column; align-items:flex-start;
    gap:calc(var(--v-line)/4); min-height:0; }
  .pm-meta{ line-height:var(--v-line); }
}
.pm-tkr{ display:inline-flex; align-items:center; gap:var(--space-2);
  font:var(--text-small); font-weight:620; color:var(--color-text); }
.pm-dot{ width:7px; height:7px; border-radius:50%; background:var(--color-accent); }
.pm-meta{ font:var(--text-micro); font-family:var(--font-mono);
  letter-spacing:var(--track-micro); color:var(--color-text-tertiary); }
.pm-q{ font:var(--text-body); font-weight:540; color:var(--color-text);
  line-height:var(--v-line); margin:0; }
.pm-val{ font-family:var(--font-mono); font-weight:600; color:var(--color-accent);
  font-variant-numeric:tabular-nums; background:var(--color-accent-subtle);
  border-radius:var(--radius-sm); padding:1px 6px; white-space:nowrap;
  box-shadow:inset 0 0 0 1px var(--color-accent-bdr); }
.pm-mid{ display:flex; flex-direction:column; gap:var(--space-4);
  padding-top:calc(var(--v-line)/2); }
/* ⛔ The wide-strip overrides that lived here are GONE (2026-07-28). They existed
   while the ticket ran the full 744 track beneath its chart; on the canvas the
   ticket sits BESIDE the chart at 360, which is the width the card was designed
   for — so it goes back to its own stacked rhythm. A viewport media query was the
   wrong instrument anyway: the card's layout depends on the CARD's width, not the
   window's. */
.pm-spec{ font:var(--text-micro); font-family:var(--font-mono);
  letter-spacing:var(--track-micro); color:var(--color-text-tertiary);
  line-height:var(--v-line); margin-top:calc(var(--v-line)/2);
  box-shadow:inset 0 1px 0 var(--color-border); padding-top:calc(var(--v-line)/2); }
.pm-spec b{ color:var(--color-text-secondary); font-weight:540; }

.pm-opts, .pm-pays{ display:grid; grid-template-columns:1fr 1fr; gap:var(--space-2); }
.pm-opt{ display:flex; align-items:center; justify-content:space-between;
  height:calc(1.5 * var(--v-line)); padding:0 var(--space-3);
  border-radius:var(--radius-md); corner-shape:var(--corner-shape);
  box-shadow:inset 0 0 0 1px var(--color-border);
  background:var(--color-surface); cursor:pointer; }
.pm-opt-l{ font:var(--text-small); font-weight:620; color:var(--color-text); }
.pm-opt-p{ font-family:var(--font-mono); font-size:14px; color:var(--color-text-tertiary);
  font-variant-numeric:tabular-nums; }
.pm-opt.is-sel{ box-shadow:inset 0 0 0 1px var(--color-accent-bdr);
  background:var(--color-accent-subtle); }
.pm-opt.is-sel .pm-opt-l{ color:var(--color-accent); }
.pm-opt:not(.is-sel):hover{ box-shadow:inset 0 0 0 1px var(--color-wireframe); }
.pm-pay{ display:flex; flex-direction:column; align-items:center; }
.pm-pay-l, .pm-stat-l, .pm-range-lbl, .pm-step-l{ font:var(--text-micro);
  font-family:var(--font-mono); text-transform:uppercase; letter-spacing:var(--track-micro);
  color:var(--color-text-tertiary); white-space:nowrap; line-height:var(--v-line); }
.pm-pay-v, .pm-stat-v{ font-family:var(--font-mono); font-size:16px;
  line-height:var(--v-line); font-weight:600; color:var(--color-text);
  font-variant-numeric:tabular-nums; }

.pm-range-ctl{ display:flex; align-items:center; justify-content:space-between;
  gap:var(--space-3); flex-wrap:wrap; min-height:var(--v-line); }
.pm-step{ display:inline-flex; align-items:center; gap:var(--space-2); }
.pm-step-btn{ display:inline-flex; align-items:center; justify-content:center;
  width:24px; height:24px; font-family:var(--font-mono); font-size:15px; line-height:1;
  color:var(--color-text-tertiary); background:var(--color-surface);
  box-shadow:inset 0 0 0 1px var(--color-border); border:0;
  border-radius:var(--radius-sm); corner-shape:var(--corner-shape); cursor:pointer; }
.pm-step-btn:hover:not(:disabled){ color:var(--color-text);
  box-shadow:inset 0 0 0 1px var(--color-wireframe); }
.pm-step-btn:disabled{ color:var(--color-text-disabled); cursor:default; }
.pm-step-n{ font-family:var(--font-mono); font-size:14px; font-weight:600;
  color:var(--color-text); min-width:1.2ch; text-align:center; font-variant-numeric:tabular-nums; }
.pm-bkts{ display:grid; grid-template-columns:repeat(2, minmax(0,1fr)); gap:var(--space-1); }
.pm-bkt{ display:flex; align-items:center; justify-content:center; text-align:center;
  height:var(--v-line); padding:0 3px; border:0;
  border-radius:var(--radius-md); corner-shape:var(--corner-shape);
  box-shadow:inset 0 0 0 1px var(--color-border);
  background:var(--color-surface); cursor:pointer; }
.pm-bkt[hidden]{ display:none; }
.pm-bkt:hover{ box-shadow:inset 0 0 0 1px var(--color-wireframe); }
.pm-bkt.is-on{ box-shadow:inset 0 0 0 1px var(--color-accent-bdr);
  background:var(--color-accent-subtle); }
.pm-bkt-r{ font-family:var(--font-mono); font-size:12px; font-variant-numeric:tabular-nums;
  white-space:nowrap; color:var(--color-text-tertiary); }
.pm-bkt.is-on .pm-bkt-r{ color:var(--color-accent); }
.pm-bkts[data-n="8"] .pm-bkt-r{ font-size:10.5px; }

.pm-lin-row{ display:flex; align-items:center; gap:var(--space-3); flex-wrap:wrap;
  min-height:var(--v-line); font:var(--text-small); line-height:var(--v-line);
  color:var(--color-text-secondary); }
.pm-lin-prep{ color:var(--color-text-tertiary); }
.pm-stats{ display:grid; grid-template-columns:1fr 1fr; gap:0 var(--space-4); }
.pm-stat{ display:flex; flex-direction:column; }
.pm-dist-stats{ grid-template-columns:repeat(3, minmax(0,1fr)); }
.pm-cust-ctl{ display:flex; min-height:var(--v-line); }
/* ⚠ PAGE: inside a figure's control row the tabs run at a HALF gutter. At a full
   gutter four labels plus the hint break onto three lines on the content track.
   The component's own gap is untouched everywhere it has room. */
.pf .gc-tabs, .pm .gc-tabs{ gap:var(--space-3); }
#pm-cust-presets{ display:flex; flex-direction:column; gap:calc(var(--v-line)/2); }
#pm-cust-presets[hidden]{ display:none; }
.pm-cons{ display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:var(--space-1); }
.pm-con{ display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:4px; height:var(--space-6); border:0;
  border-radius:var(--radius-md); corner-shape:var(--corner-shape);
  box-shadow:inset 0 0 0 1px var(--color-border);
  background:var(--color-surface); cursor:pointer; }
.pm-con:hover{ box-shadow:inset 0 0 0 1px var(--color-wireframe); }
.pm-con.is-on{ box-shadow:inset 0 0 0 1px var(--color-accent-bdr);
  background:var(--color-accent-subtle); }
.pm-con svg{ color:var(--color-accent); opacity:.7; }
.pm-con.is-on svg{ opacity:1; }
.pm-con span{ font:var(--text-micro); font-family:var(--font-sans); letter-spacing:0;
  text-transform:none; color:var(--color-text-tertiary); white-space:nowrap; }
.pm-con.is-on span{ color:var(--color-text); }
.pm-fx-edit{ display:flex; align-items:center; gap:var(--space-2);
  height:calc(1.5 * var(--v-line)); padding:0 var(--space-3); cursor:text;
  border-radius:var(--radius-md); corner-shape:var(--corner-shape);
  box-shadow:inset 0 0 0 1px var(--color-accent-bdr); background:var(--color-accent-subtle); }
.pm-fx-edit:hover, .pm-fx-edit:focus-within{ box-shadow:inset 0 0 0 1px var(--color-accent); }
.pm-fx-pen{ flex:0 0 auto; color:var(--color-accent); opacity:.6; }
.pm-fx-edit:hover .pm-fx-pen, .pm-fx-edit:focus-within .pm-fx-pen{ opacity:1; }
.pm-fx-prefix{ font-family:var(--font-mono); font-size:15px; color:var(--color-accent); white-space:nowrap; }
.pm-fx-input{ flex:1; min-width:0; border:0; outline:none; background:transparent;
  padding:0; margin:0; font-family:var(--font-mono); font-size:15px;
  color:var(--color-text); caret-color:var(--color-accent); }
.pm-fx-dot{ flex:0 0 auto; width:9px; height:9px; border-radius:50%; background:var(--color-positive); }
.pm-fx-dot.is-err{ background:var(--color-negative); }
.pm-fx-err{ font:var(--text-micro); font-family:var(--font-mono); letter-spacing:var(--track-micro);
  color:var(--color-negative-text); line-height:var(--v-line); }
.pm-fx-pal{ display:flex; flex-wrap:wrap; gap:var(--space-1); }
.pm-fx-key{ font-family:var(--font-mono); font-size:12px; color:var(--color-text-tertiary);
  background:var(--color-surface); border:0;
  box-shadow:inset 0 0 0 1px var(--color-border);
  border-radius:var(--radius-sm); corner-shape:var(--corner-shape);
  padding:var(--space-1) var(--space-2); cursor:pointer; }
.pm-fx-key:hover{ color:var(--color-text); box-shadow:inset 0 0 0 1px var(--color-wireframe); }

/* the live chart mount — NO horizontal padding: the mount is MEASURED for the SVG
   viewBox, so its width must equal the SVG's rendered width. */
.pf-plot{ position:relative; width:100%; }
.pcfig-charthd{ display:flex; align-items:center; justify-content:space-between;
  min-height:var(--v-line); user-select:none; -webkit-user-select:none; }
.pcfig-chart-cap{ font:var(--text-micro); font-family:var(--font-mono);
  letter-spacing:var(--track-micro); color:var(--color-text-tertiary); }
.pcfig-probtoggle{ display:inline-flex; align-items:center; gap:var(--space-2);
  background:none; border:0; cursor:pointer; padding:0;
  font:var(--text-micro); font-family:var(--font-mono); letter-spacing:var(--track-micro);
  color:var(--color-text-tertiary); }
.pcfig-probtoggle:hover{ color:var(--color-text); }
.pcfig-probtoggle-tr{ position:relative; width:30px; height:17px; border-radius:9px; flex:0 0 auto;
  background:var(--color-surface-alt); box-shadow:inset 0 0 0 1px var(--color-border);
  transition:background .15s; }
.pcfig-probtoggle-kn{ position:absolute; top:3px; left:3px; width:11px; height:11px;
  border-radius:50%; background:var(--color-wireframe); transition:transform .18s, background .18s; }
.pcfig-probtoggle[aria-checked="true"]{ color:var(--color-text-secondary); }
.pcfig-probtoggle[aria-checked="true"] .pcfig-probtoggle-tr{
  background:color-mix(in srgb, var(--pf-dist) 18%, transparent);
  box-shadow:inset 0 0 0 1px var(--pf-dist); }
.pcfig-probtoggle[aria-checked="true"] .pcfig-probtoggle-kn{ transform:translateX(13px); background:var(--pf-dist); }
.pcfig-svg{ display:block; width:100%; height:auto; overflow:visible;
  -webkit-user-select:none; user-select:none; -webkit-touch-callout:none; }
.pcfig-dragging, .pcfig-dragging *{ cursor:grabbing !important;
  user-select:none !important; -webkit-user-select:none !important; }
.pcfig-line, .pcfig-gridline, .pcfig-axis, .pcfig-premium, .pcfig-prob-line,
.pcfig-handle-knob, .pcfig-xh{ vector-effect:non-scaling-stroke; }
.pcfig-prob-fill{ fill:var(--pf-dist); fill-opacity:.07; }
.pcfig-prob-line{ fill:none; stroke:var(--pf-dist); stroke-width:1.6px; stroke-dasharray:5 3.6; stroke-opacity:.75; }
.pcfig-gridline{ stroke:var(--color-accent); stroke-opacity:.34; stroke-width:var(--pc-hair); }
.pcfig-axis{ stroke:var(--pf-axis); stroke-opacity:.9; stroke-width:var(--pc-hair); }
.pcfig-grid-wrap-dim{ opacity:.56; transition:opacity .35s ease; pointer-events:none; }
.pcfig-live .pcfig-grid-wrap-dim{ opacity:1; transition:opacity .13s cubic-bezier(0,0,.2,1); }
.pcfig-loss{ fill:var(--color-accent); fill-opacity:.06; }
.pcfig-profit{ fill:var(--color-accent); fill-opacity:.17; }
.pcfig-line{ fill:none; stroke:var(--pf-curve); stroke-width:var(--pc-curve);
  stroke-linejoin:round; stroke-linecap:round; }
.pcfig-premium{ stroke:var(--pf-premium-line); stroke-width:var(--pc-premium); stroke-dasharray:5 5; }
.pcfig-premium-tx{ font-family:var(--font-mono); font-size:11px; fill:var(--pf-premium-label); }
.pcfig-end{ font-family:var(--font-mono); font-size:11px; font-weight:500; fill:var(--color-text-tertiary); }
.pcfig-end-c{ fill:var(--color-text-disabled); font-size:10px; letter-spacing:.05em; }
.pcfig-xh{ stroke:var(--color-accent); stroke-width:var(--pc-hair); stroke-dasharray:3 3; stroke-opacity:.55; }
.pcfig-xh-lbl{ font-family:var(--font-mono); font-size:11.5px; fill:var(--color-accent);
  font-variant-numeric:tabular-nums; }
.pcfig-handle{ cursor:grab; touch-action:none; }
.pcfig-handle-hit{ fill:transparent; }
.pcfig-handle-halo{ fill:var(--color-accent); opacity:.15; }
.pcfig-handle-knob{ fill:var(--color-bg); stroke:var(--color-accent); stroke-width:var(--pc-knob-stroke); }

/* ── THE DRAG AFFORDANCE. Every payoff figure on this page is an instrument, so
 * each beckons until the reader touches it, then goes quiet for good. The halo
 * BREATHES (it is already the accent — a data mark, which is a legitimate accent
 * role) and a one-line hint sits with the controls in the FURNITURE register,
 * tertiary, because a hint is furniture and the accent is not spent on it. */
@keyframes pcfig-beckon{
  0%,100%{ opacity:.15; transform:scale(1); }
  50%    { opacity:.34; transform:scale(1.35); }
}
.pf.is-untouched .pcfig-handle-halo{
  animation:pcfig-beckon 2.4s ease-in-out infinite; transform-box:fill-box; transform-origin:center; }
@media (prefers-reduced-motion: reduce){
  .pf.is-untouched .pcfig-handle-halo{ animation:none; opacity:.32; }
}
.hint{ display:inline-flex; align-items:center; gap:var(--space-2);
  font:var(--text-micro); font-family:var(--font-mono); text-transform:uppercase;
  letter-spacing:var(--track-micro); color:var(--color-text-tertiary);
  line-height:var(--v-line); transition:opacity .3s ease; }
.hint::before{ content:"\2194"; font-size:14px; line-height:1; color:var(--color-accent); }
.pf:not(.is-untouched) .hint{ opacity:0; pointer-events:none; }

/* ═══ 11 · SCREEN + CHART PAIRS ═══════════════════════════════════════════════
 * A phone on the left, the payoff it buys on the right, and a declared LANE
 * between them. The panel keeps its partner's identity — it is CONTENT, not
 * chrome, so it does not theme — and it is live: working the app moves the chart
 * and vice versa (panels.js).
 *
 * ⭐ THE GAP IS A TRACK, NOT A `gap:` — the Crux's mechanism, copied deliberately.
 * Declaring the lane as a column is what lets the tie arrow sit dead-centre in it
 * with no magic number, and it is why every value here is column arithmetic:
 *      LEFT  3 cols + 2 gutters = 264   the phone
 *      LANE  1 col  + 2 gutters = 120   the tie's home — a FULL column of air
 *      RIGHT 8 cols + 7 gutters = 744   the chart (= the content track exactly)
 *                                 1128  the canvas
 * The right track is `minmax(0,1fr)` rather than a fixed 744 so the pair still
 * fits between the 900 and 1240 breakpoints, where the canvas is viewport-bound;
 * at full width it resolves to 744 on the nose.
 * ⚠ WAS 320 + one 24 gutter + 784 (2026-07-28 rebase). Tom: cramped and blown up.
 * The lane went 24 → 120 and the phone 320 → 264. */
/* ⭐ FOUR CHILDREN, TWO ROWS — the caption is a SIBLING of the chart, not a child
 * of a right-hand column. That is what makes the tie's alignment structural: row 1
 * holds the two INSTRUMENTS and nothing else, so `align-self:center` in the lane
 * puts the arrow on their shared midline with no magic number; row 2 carries the
 * caption under the chart, in the chart's own column, where Tom asked for it.
 * ⚠ WAS a `.pair-r` flex column holding chart + caption. With the caption inside
 * the row, the row's midline sat 64px below both instruments' centres and the tie
 * pointed at the caption. Deleting the wrapper fixed the alignment structurally. */
.pair{ display:grid; grid-template-columns:1fr; gap:0; }
.pair > .pan{ margin-bottom:var(--v-line); }             /* stacked: phone → chart */
.pair > .gc-caption{ margin:calc(var(--v-line)/2) 0 0; } /* the caption's ½-unit hug */
/* ⚠ THE TWO-COLUMN REGIME STARTS AT 1080, NOT 900. The lane is 120px of the row's
   width, so the old 900 threshold left the chart on 433px — cramped again, one
   breakpoint down. 1080 is the narrowest viewport at which the chart still clears
   the 9-column mark (648) with the phone and its lane in place; below it the pair
   stacks, which is the honest answer at that width. */
@media (min-width:1080px){
  .pair{
    --pair-left: calc(3*var(--col) + 2*var(--col-gutter));   /* 264 */
    --pair-lane: calc(1*var(--col) + 2*var(--col-gutter));   /* 120 */
    grid-template-columns:var(--pair-left) var(--pair-lane) minmax(0,1fr);
    grid-template-rows:auto auto;
    gap:0; align-items:start;
  }
  .pair > .pan       { grid-area:1 / 1; margin-bottom:0; }
  .pair > .pair-tie  { grid-area:1 / 2; align-self:center; justify-self:center; }
  .pair > .pf        { grid-area:1 / 3; }
  .pair > .gc-caption{ grid-area:2 / 3; }

  /* ⭐ `.is-flipped` — THE MIDDLE BEAT MIRRORS (2026-07-29, Tom: three of these in
     a row read "a bit same-same"). The wide track moves to column 1 and the phone
     to column 3, so the page alternates app→chart, chart←app, app→chart down the
     three UX beats.
     ⚠ IT IS A PURELY VISUAL MIRROR. The DOM order does not change — phone, tie,
     chart, caption — so the stacked layout below 1080 and the reading order for a
     screen reader are identical in all three sections. Only the grid placement
     moves, which is the whole reason the pair was built on declared TRACKS rather
     than on source order.
     The tie is mirrored with it: an arrow that still pointed right would be
     pointing away from the thing it ties to. */
  .pair.is-flipped{ grid-template-columns:minmax(0,1fr) var(--pair-lane) var(--pair-left); }
  .pair.is-flipped > .pan       { grid-area:1 / 3; }
  .pair.is-flipped > .pf        { grid-area:1 / 1; }
  .pair.is-flipped > .gc-caption{ grid-area:2 / 1; }
  .pair.is-flipped > .pair-tie  { transform:scaleX(-1); }
}

/* THE TIE — a real grid child occupying the lane. Same treatment as the homepage's
   Crux tie: accent at .4, decorative, never a target. It is the only accent in the
   pair, and it is carrying meaning (this screen IS this shape), not decorating a
   divider. Below the two-column regime the pair stacks and the arrow would point at
   nothing, so it is not rendered. */
.pair-tie{ display:flex; color:var(--color-accent); opacity:.4; pointer-events:none; }
@media (max-width:1079.98px){ .pair-tie{ display:none; } }
@media (prefers-reduced-motion: no-preference){
  .pair-tie{ transition:opacity .2s ease; }
  .pair:hover .pair-tie{ opacity:.62; }
}

/* ═══ 12 · RESPONSIVE — the essence survives, the expression steps down ═══════
 * There is no lattice to collapse any more: a section fills the frame and its
 * payload centres inside the canvas, so below the paper regime the canvas simply
 * becomes the frame and everything keeps its order. */
@media (max-width:1240px){
  :root, :root[data-theme]{ --edge-air:var(--col-gutter); }
  .sec-inner{ max-width:100%; padding-inline:var(--col-gutter); }
}
@media (max-width:860px){
  .sec-inner{ padding-inline:0; }
  body::before, body::after{ display:none; }
}
@media (max-width:600px){
  /* the SERIF tiers step down together; the Geist tiers are unchanged, so the
     reading register is identical — only the display register relaxes. */
  :root, :root[data-theme]{ --text-display: 400 40px/48px var(--font-heading);
                            --text-heading: 400 34px/40px var(--font-heading); }
  .fig-stat b{ font-size:34px; line-height:40px; }
}
@media (pointer:coarse){ .gc-btn, .gc-tab{ min-height:44px; } }
@media print{ .nav, .site-footer{ display:none; } }

/* ═══ 13 · THE UX PANELS ══════════════════════════════════════════════════════
 * Rebuilt as native DOM (panels.js explains why). Three rules govern this block:
 *
 *  1 THE HOUSING IS THE BASELINE `phone` COMPONENT, not a box I drew. Measured
 *    off the extraction in `component-bench.html#c-phone`: an inline-size
 *    container, a frame at 2.5% padding with `border-radius:15cqw` and a 2px
 *    #333 outline, a screen at **aspect-ratio 9/19.5** with
 *    `radius:calc(15cqw − 6px)`, a 30%×4% notch at top 2.5%, a 34%×0.6% home
 *    indicator at bottom 3%, and four side buttons at 15/23.4/32.4% left and
 *    28.2% right. Because every value is a container-query unit or a percentage,
 *    the device is correct at ANY width.
 *    ⛔ The component's floating back / URL / menu pill row is NOT adopted — those
 *    are a BROWSER's controls and this is an app, the same reason `gc-window`
 *    drops Geist's nav icons.
 *  2 A PANEL IS CONTENT, NOT CHROME. It is a picture of somebody else's product,
 *    so it carries the PARTNER's palette and type scale, not our §6b tiers.
 *    Palettes are lifted from the screens' own `:root`. Every custom property is
 *    `--pp-*` and scoped to `.pan`, so nothing leaks out.
 *  3 IT STILL OBEYS OUR STRUCTURAL LAWS: elevation is tint + border, never a drop
 *    shadow (the one exception is the device's own outline, which is the
 *    component's anatomy). */
/* ⭐ THE PHONE IS AUTHORED AT 320 AND RENDERED AT 264 (2026-07-28, Tom: "the mobile
 * just needs to be smaller overall"). `zoom` — not a smaller max-width — because a
 * phone screen is a FIXED-PIXEL design: its type, its 44px CTA, its 32px avatar and
 * its 9px status bar are the partner's real values, and narrowing the box would
 * have re-wrapped that copy and overflowed the 9:19.5 screen (measured: Trepa's
 * panel had 79px of slack at 320, and 264 costs 115). Zooming scales the whole
 * device — layout included, so the box really is 264 wide and the grid track is
 * honest — and every internal proportion survives untouched.
 * 264/320 = .825, and 264 is the pair's 3-column track, so the device fills it
 * exactly. Keep the two in step if either changes. */
.pan{ margin:0; zoom:.825; }
/* [hidden] has to beat a panel part's own `display` (a `.pan-dial` is flex, and the
   UA's [hidden]{display:none} loses to any class rule — measured). */
.pan [hidden]{ display:none; }

/* the partner palettes, verbatim from the screens' own :root */
.pan[data-brand="ps"]{        /* WC26 — navy / gold, light. Verbatim from
                                 scrPropLine.html / scrDuel.html :root. */
  --pp-paper:#FBFAF7; --pp-surf:#FFFFFF; --pp-surf-2:#F4F1E9; --pp-track:#EFEDE5;
  --pp-bd:#E7E2D6; --pp-bd-2:#D8D2C2;
  --pp-ink:#0E1B33; --pp-ink-2:#42506B; --pp-ink-3:#8A93A6;
  --pp-accent:#11224D; --pp-on-accent:#FFFFFF;
  --pp-gold:#C9A227; --pp-gold-2:#E3C463; --pp-gold-ink:#A8861D; --pp-on-gold:#11224D;
  --pp-pos:#1B7A4B; --pp-neg:#C0392B; --pp-pos-mid:#D98A1F; --pp-on-pos:#FFFFFF;
  --pp-alloc-2:#3A56A8; --pp-def:#2B6CB0; --pp-shadow:#0E1B33;
  --pp-glow-a:rgba(201,162,39,.10); --pp-glow-b:rgba(17,34,77,.06); }
.pan[data-brand="trepa"]{     /* Trepa — near-black + lime. Verbatim from
                                 scrTrepa.html :root. */
  --pp-paper:#060804; --pp-surf:#131313; --pp-surf-2:#1E1E1E; --pp-track:#1E1E1E;
  --pp-bd:#2A2A2A; --pp-bd-2:#3A3A3A;
  --pp-ink:#FDFDFD; --pp-ink-2:#D7D7D2; --pp-ink-3:#B4B4B4;
  --pp-accent:#BCE67A; --pp-on-accent:#16210A;
  --pp-gold:#BCE67A; --pp-gold-2:#D4ED9E; --pp-gold-ink:#BCE67A; --pp-on-gold:#16210A;
  --pp-pos:#2BA162; --pp-neg:#FF538C; --pp-pos-mid:#E8B45A; --pp-on-pos:#0B0B0B;
  --pp-alloc-2:#3A3A3A; --pp-def:#5B8DEF; --pp-shadow:#000000;
  --pp-glow-a:rgba(188,230,122,.08); --pp-glow-b:rgba(188,230,122,.04); }

/* ── THE DEVICE (baseline `phone`) ─────────────────────────────────────────── */
.pan-device{ container-type:inline-size; width:100%; max-width:320px; margin-inline:auto; }
.pan-frame{ position:relative; width:100%; padding:2.5%;
  background:#000; outline:2px solid #333; border-radius:15cqw; }
.pan-screen{ position:relative; aspect-ratio:9/19.5; overflow:hidden;
  border-radius:calc(15cqw - 6px);
  display:flex; flex-direction:column;
  color:var(--pp-ink); font-family:var(--font-sans);
  /* ⭐ THE TWO CORNER GLOWS, verbatim from the mockups' `.screen`. They are most
     of why the source screens read as lit products and the old flat-fill panels
     read as wireframes: a brand glow top-left, a cooler one bottom-right. */
  background:
    radial-gradient(ellipse 70% 50% at 18% 6%,  var(--pp-glow-a) 0%, transparent 55%),
    radial-gradient(ellipse 80% 60% at 88% 98%, var(--pp-glow-b) 0%, transparent 60%),
    var(--pp-paper); }
.pan-notch{ position:absolute; top:2.5%; left:50%; transform:translateX(-50%);
  width:30%; height:4%; background:#000; border-radius:var(--radius-full); }
.pan-home{ position:absolute; bottom:3%; left:50%; transform:translateX(-50%);
  width:34%; height:.6%; background:#fff; border-radius:var(--radius-full); opacity:.55; }
.pan-side{ position:absolute; width:2px; background:#333; }
.pan-side.s1{ left:-4px; top:15%;   height:3.5%; border-radius:9px 0 0 9px; }
.pan-side.s2{ left:-4px; top:23.4%; height:7.1%; border-radius:9px 0 0 9px; }
.pan-side.s3{ left:-4px; top:32.4%; height:7.1%; border-radius:9px 0 0 9px; }
.pan-side.s4{ right:-4px; top:28.2%; height:11%; border-radius:0 9px 9px 0; }

/* ⛔ THE OS STATUS BAR IS GONE (2026-07-29, Tom). A clock and a battery are the
   PHONE's chrome, not the partner's product, and at this scale they were three
   grey dots nobody reads. Same reasoning that dropped the browser window's
   back/forward/refresh icons: the frame is anatomy, the OS furniture is not.
   (The notch and the home indicator stay — they are the device, not the OS.) */

/* ⭐ ONE SCALE FACTOR, NOT A HUNDRED GUESSES ────────────────────────────────
 * ⚠ REBUILT 2026-07-29 (Tom: "the UX styling/colours don't really match well
 * close enough with the source HTML — these need to be much closer").
 * They didn't match because every value below was hand-picked to look right at
 * this size, so the panels were a SKETCH of the partner screens rather than a
 * reduction of them: right idea, wrong weights, wrong radii, wrong ratios.
 * Now there is exactly one number to trust. The source mockups draw a 430px-wide
 * screen; ours is 95% of a 320px device, so
 *      1 source px  =  (0.95 × 320 / 430) px  =  (95 / 430) cqw  =  0.22093cqw
 * and every value in this block is `calc(<the source's own number> * --pp-u)`.
 * That makes each declaration self-documenting (the literal IS the source value,
 * so it can be diffed against the mockup) and it makes the panel correct at ANY
 * device width, because cqw tracks the container.
 * The one thing NOT scaled is the type FAMILY: the source uses LT Superior and
 * JetBrains Mono, which are not ours to serve, so `--font-sans` / `--font-mono`
 * stand in. Everything else — size, weight, tracking, colour, radius, border,
 * padding, gap — is the source's.
 *
 * ⚠ SHADOWS ARE PERMITTED INSIDE `.pan`, AND ONLY INSIDE IT. Our elevation law is
 * tint + inset border, shadows avoid-first — and it governs OUR surfaces. A panel
 * is a picture of somebody else's product (§13 rule 2), and these partners lift
 * their cards on drop shadows. Removing them is what made the panels read as our
 * components wearing a partner palette instead of as their apps. Every shadow
 * here is copied from the mockup and every one is inside a `.pan`. */
.pan{ --pp-u: 0.22093cqw; }

/* ⚠ THE APP BAR CARRIES THE SAFE AREA NOW. The status bar used to hold the notch
   off the content (its own 18px of top padding did the work); with it gone the
   wordmark ran straight under the cutout. 40 source px is the height the status
   row occupied, so the app bar simply inherits the clearance rather than the page
   inventing one. */
.pan-appbar{ display:flex; align-items:center; justify-content:space-between;
  gap:calc(8 * var(--pp-u)); flex:none;
  padding:calc(40 * var(--pp-u)) calc(24 * var(--pp-u)) 0; }
.pan-wm{ display:inline-flex; align-items:center; gap:calc(9 * var(--pp-u));
  font:900 calc(19 * var(--pp-u))/1 var(--font-sans);
  letter-spacing:-.03em; color:var(--pp-ink); }
.pan-wm i{ font-style:normal; color:var(--pp-gold); }
/* Trepa's lockup is a lime hexagon + the wordmark at +0.14em — the mark is drawn,
   not an image, exactly as the source draws it (clip-path on a filled square). */
.pan-hex{ width:calc(20 * var(--pp-u)); height:calc(20 * var(--pp-u)); flex:none;
  background:var(--pp-accent);
  clip-path:polygon(50% 0%, 93% 25%, 93% 75%, 50% 100%, 7% 75%, 7% 25%); }
.pan[data-brand="trepa"] .pan-wm{ letter-spacing:.14em; }
.pan-chip{ font:700 calc(8.5 * var(--pp-u))/1 var(--font-mono);
  letter-spacing:.08em; text-transform:uppercase;
  padding:calc(4 * var(--pp-u)) calc(8 * var(--pp-u));
  border-radius:calc(7 * var(--pp-u)); }
/* propSPACE: gold ink on the navy; Trepa: lime on the feature grey with a hairline */
.pan[data-brand="ps"] .pan-chip{ color:var(--pp-gold-2); background:var(--pp-accent); }
.pan[data-brand="trepa"] .pan-chip{ color:var(--pp-accent); background:var(--pp-surf-2);
  box-shadow:inset 0 0 0 1px var(--pp-bd); }

/* the app's scroll surface — a real phone screen scrolls, and this is also the
   safety valve if a panel's content ever outgrows the 9:19.5 box. */
.pan-content{ flex:1 1 auto; min-height:0; overflow-y:auto; scrollbar-width:none;
  display:flex; flex-direction:column; gap:calc(14 * var(--pp-u));
  padding:calc(14 * var(--pp-u)) calc(22 * var(--pp-u)) calc(10 * var(--pp-u)); }
.pan-content::-webkit-scrollbar{ display:none; }
/* the last block sits just above the CTA — the app pattern, and it turns a ragged
   tail of leftover space into one deliberate gap when the content is short. */
/* ⛔ NO `margin-top:auto` ON THE LAST BLOCK (2026-07-29). It pinned the stake row
   to the foot and parked all the leftover height as a hole in the MIDDLE of the
   screen. The source screens are a plain top-aligned flex column — the slack
   collects at the bottom, above the pinned CTA, which is what a half-filled app
   screen actually looks like. */
.pan-foot{ flex:none; background:var(--pp-paper);
  padding:calc(16 * var(--pp-u)) calc(22 * var(--pp-u)) calc(30 * var(--pp-u));
  box-shadow:inset 0 1px 0 var(--pp-bd); }
.pan-cta{ width:100%; height:calc(58 * var(--pp-u)); border:0;
  border-radius:calc(18 * var(--pp-u));
  background:var(--pp-gold); color:var(--pp-on-gold);
  font:800 calc(17 * var(--pp-u))/1 var(--font-sans); letter-spacing:-.01em;
  box-shadow:0 calc(16 * var(--pp-u)) calc(32 * var(--pp-u)) calc(-14 * var(--pp-u))
             color-mix(in srgb, var(--pp-gold) 70%, transparent);
  opacity:.45; cursor:not-allowed; }

/* ── APP PARTS ─────────────────────────────────────────────────────────────── */
.pan-ph, .pan-matchstrip{ display:flex; align-items:center;
  gap:calc(13 * var(--pp-u)); flex:none; }
/* the avatar is a TINTED TILE with the partner's ink on it — not a filled accent
   block. That inversion was the single loudest mismatch in the old panels. */
.pan-av{ display:inline-flex; align-items:center; justify-content:center;
  width:calc(46 * var(--pp-u)); height:calc(46 * var(--pp-u)); flex:none;
  border-radius:calc(14 * var(--pp-u));
  background:linear-gradient(150deg, color-mix(in srgb, var(--pp-accent) 16%, transparent), var(--pp-surf));
  box-shadow:inset 0 0 0 1px var(--pp-bd);
  color:var(--pp-ink); font:900 calc(18 * var(--pp-u))/1 var(--font-sans);
  letter-spacing:-.02em; }
/* the duel's paired heads: 34px circles with a gold rim, overlapped by 14 */
.pan-av.sm{ width:calc(34 * var(--pp-u)); height:calc(34 * var(--pp-u));
  border-radius:50%; font:700 calc(11 * var(--pp-u))/1 var(--font-mono);
  background:linear-gradient(150deg,#e8ecf6,#cdd6ea); color:var(--pp-accent);
  box-shadow:inset 0 0 0 2px var(--pp-gold); }
.pan-av.alt{ margin-left:calc(-14 * var(--pp-u)); }
.pan-ph-main{ display:flex; flex-direction:column;
  gap:calc(6 * var(--pp-u)); min-width:0; flex:1; }
/* first name light, surname heavy — the source's `.ph-name .first` split */
.pan-name{ font:500 calc(22 * var(--pp-u))/1 var(--font-sans);
  letter-spacing:-.035em; color:var(--pp-ink-2); }
.pan-name b{ font-weight:900; color:var(--pp-ink); }
.pan-name i{ font-style:normal; color:var(--pp-gold); }
.pan-matchstrip .pan-name{ flex:1; font-weight:800; font-size:calc(15 * var(--pp-u));
  letter-spacing:normal; color:var(--pp-ink); }
.pan-tags{ display:flex; align-items:center; gap:calc(7 * var(--pp-u));
  font:400 calc(10 * var(--pp-u))/1 var(--font-mono); letter-spacing:.04em;
  color:var(--pp-ink-3); }
/* the position pill is the SIGNAL set, per position — MID is amber in both apps */
.pan-pos{ font-style:normal; font:700 calc(9 * var(--pp-u))/1 var(--font-mono);
  letter-spacing:.08em; text-transform:uppercase;
  padding:calc(3 * var(--pp-u)) calc(7 * var(--pp-u));
  border-radius:calc(6 * var(--pp-u));
  background:var(--pp-pos-mid); color:var(--pp-on-pos); }
.pan-pos[data-pos="fwd"]{ background:var(--pp-neg); }
.pan-pos[data-pos="def"]{ background:var(--pp-def); }
.pan-free{ margin-left:auto; display:inline-flex; align-items:center;
  font:700 calc(10 * var(--pp-u))/1 var(--font-mono); letter-spacing:.08em;
  text-transform:uppercase; color:var(--pp-accent);
  background:linear-gradient(180deg, var(--pp-gold-2), var(--pp-gold));
  padding:calc(5 * var(--pp-u)) calc(10 * var(--pp-u));
  border-radius:calc(8 * var(--pp-u));
  box-shadow:0 calc(6 * var(--pp-u)) calc(16 * var(--pp-u)) calc(-8 * var(--pp-u))
             color-mix(in srgb, var(--pp-gold) 70%, transparent); }
/* the match strip is a CARD in the duel screen, not a bare row */
.pan-matchstrip{ padding:calc(11 * var(--pp-u)) calc(12 * var(--pp-u));
  border-radius:calc(14 * var(--pp-u)); background:var(--pp-surf);
  box-shadow:inset 0 0 0 1px var(--pp-bd); gap:calc(10 * var(--pp-u)); }

/* every card in these apps is introduced by the same two-part label: a tracked
   mono cap on the left, a coloured aside on the right */
.pan-lbl{ display:flex; align-items:baseline; justify-content:space-between;
  gap:calc(8 * var(--pp-u)); margin:0 0 calc(8 * var(--pp-u));
  font:700 calc(10 * var(--pp-u))/1 var(--font-mono); letter-spacing:.18em;
  text-transform:uppercase; color:var(--pp-ink-3); }
.pan-lbl .q{ font-weight:700; font-size:calc(9 * var(--pp-u)); letter-spacing:.04em;
  text-transform:none; color:var(--pp-gold-ink); }

/* recent form */
.pan-form{ display:flex; gap:calc(7 * var(--pp-u)); }
.pan-form > span{ flex:1; display:flex; flex-direction:column; align-items:center;
  padding:calc(9 * var(--pp-u)) calc(6 * var(--pp-u));
  border-radius:calc(12 * var(--pp-u)); background:var(--pp-surf);
  box-shadow:inset 0 0 0 1px var(--pp-bd); }
.pan-form b{ font:700 calc(15 * var(--pp-u))/1 var(--font-mono); color:var(--pp-accent);
  font-variant-numeric:tabular-nums; }
.pan-form i{ font-style:normal; font:400 calc(8 * var(--pp-u))/1 var(--font-mono);
  letter-spacing:.06em; text-transform:uppercase; color:var(--pp-ink-3);
  margin-top:calc(3 * var(--pp-u)); }
.pan-form .hi{ background:color-mix(in srgb, var(--pp-pos) 6%, var(--pp-surf));
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--pp-pos) 40%, transparent); }
.pan-form .hi b{ color:var(--pp-pos); }

/* ⭐ THE MODE TOGGLE IS A SEGMENTED CONTROL ON A GROOVE, not two buttons.
   The source draws a `--track` trough at r14 with 5px of padding, and the ACTIVE
   segment is a raised white pill: background → surface, ink → the brand, plus a
   soft lift. Exactly three properties change. The old build inverted this — it
   filled the active segment with the accent — which read as a chip row, not as
   an iOS-style switch, and was the second loudest mismatch. */
.pan-modes{ display:flex; gap:calc(7 * var(--pp-u)); flex:none;
  background:var(--pp-track); border-radius:calc(14 * var(--pp-u));
  padding:calc(5 * var(--pp-u)); }
.pan-mode{ flex:1; border:0; cursor:pointer; background:transparent;
  display:flex; align-items:center; justify-content:center;
  padding:calc(11 * var(--pp-u)) calc(6 * var(--pp-u));
  border-radius:calc(10 * var(--pp-u));
  font:800 calc(14 * var(--pp-u))/1 var(--font-sans); letter-spacing:-.01em;
  color:var(--pp-ink-3);
  transition:background .18s ease, color .18s ease, box-shadow .18s ease; }
.pan-modes.three .pan-mode{ font-size:calc(13 * var(--pp-u)); }
.pan-mode:hover{ color:var(--pp-ink-2); }
.pan-mode.is-on{ background:var(--pp-surf); color:var(--pp-accent);
  box-shadow:0 calc(3 * var(--pp-u)) calc(8 * var(--pp-u))
             color-mix(in srgb, var(--pp-shadow) 10%, transparent); }

/* THE DIAL — a lifted card carrying a 52px numeral. The numeral is the screen's
   focal point in all three apps and it was rendering at half that. */
.pan-dial{ display:flex; flex-direction:column;
  padding:calc(14 * var(--pp-u)); border-radius:calc(20 * var(--pp-u));
  background:var(--pp-surf); box-shadow:inset 0 0 0 1px var(--pp-bd),
    0 calc(10 * var(--pp-u)) calc(26 * var(--pp-u)) calc(-16 * var(--pp-u))
    color-mix(in srgb, var(--pp-shadow) 25%, transparent); }
.pan-dialrow{ display:flex; align-items:center; justify-content:center;
  gap:calc(12 * var(--pp-u)); }
.pan-dial.is-dim{ opacity:.4; }
.pan-step{ display:inline-flex; align-items:center; justify-content:center; flex:none;
  width:calc(48 * var(--pp-u)); height:calc(48 * var(--pp-u));
  border:0; cursor:pointer; border-radius:50%;
  background:var(--pp-paper); color:var(--pp-accent);
  box-shadow:inset 0 0 0 1px var(--pp-bd);
  font:500 calc(22 * var(--pp-u))/1 var(--font-mono);
  transition:transform .12s ease, background .18s ease, color .18s ease; }
.pan-step:hover{ background:var(--pp-gold); color:var(--pp-on-gold); box-shadow:none; }
.pan-step:active{ background:var(--pp-gold); color:var(--pp-on-gold);
  box-shadow:none; transform:scale(.9); }
.pan-step.sm{ width:calc(34 * var(--pp-u)); height:calc(34 * var(--pp-u));
  font-size:calc(16 * var(--pp-u)); }
.pan-dialmid{ display:flex; flex-direction:column; align-items:center;
  min-width:0; flex:1; }
.pan-val{ font:700 calc(52 * var(--pp-u))/.9 var(--font-mono); color:var(--pp-accent);
  font-variant-numeric:tabular-nums; letter-spacing:-.03em; }
.pan-dial .pan-val{ min-width:calc(110 * var(--pp-u)); text-align:center; }
.pan-who{ font:700 calc(10 * var(--pp-u))/1 var(--font-mono); letter-spacing:.14em;
  text-transform:uppercase; color:var(--pp-gold-ink); }
.pan-unit{ font:700 calc(11 * var(--pp-u))/1 var(--font-mono); letter-spacing:.16em;
  text-transform:uppercase; color:var(--pp-ink-3);
  margin-top:calc(6 * var(--pp-u)); text-align:center; }
.pan-note{ font:400 calc(11.5 * var(--pp-u))/1.45 var(--font-sans);
  color:var(--pp-ink-3); text-align:center; margin:calc(9 * var(--pp-u)) 0 0; }
.pan-note b{ color:var(--pp-ink-2); font-weight:600; }

/* the crowd scale under the dial */
.pan-scale{ position:relative; height:calc(36 * var(--pp-u));
  margin-top:calc(16 * var(--pp-u)); }
.pan-scale::before{ content:""; position:absolute; left:0; right:0;
  top:calc(22 * var(--pp-u)); height:calc(4 * var(--pp-u));
  border-radius:var(--radius-full);
  background:linear-gradient(90deg, var(--pp-bd), var(--pp-gold) 50%, var(--pp-bd)); }
.pan-scale-crowd{ position:absolute; top:calc(15 * var(--pp-u)); left:50%;
  width:calc(2 * var(--pp-u)); height:calc(18 * var(--pp-u));
  transform:translateX(-50%); background:var(--pp-gold); }
.pan-scale-you{ position:absolute; top:calc(24 * var(--pp-u));
  width:calc(22 * var(--pp-u)); height:calc(22 * var(--pp-u)); border-radius:50%;
  transform:translate(-50%,-50%); background:var(--pp-accent);
  border:calc(3 * var(--pp-u)) solid #fff;
  box-shadow:0 calc(2 * var(--pp-u)) calc(8 * var(--pp-u))
             color-mix(in srgb, var(--pp-shadow) 40%, transparent);
  transition:left .18s ease; }

/* PICK A SIDE — outline cards, big mono multiplier, ink-3 caps. The source has no
   selected state at all (both sides sit unselected while the CTA reads "Pick a
   side"); ours needs one because the reader really does pick, so the selection is
   the app's own gold, applied the way the duel's face-off card applies it. */
.pan-picks{ display:flex; gap:calc(10 * var(--pp-u)); }
.pan-pick{ flex:1; display:flex; flex-direction:column; align-items:center;
  border:0; cursor:pointer; text-align:center;
  padding:calc(15 * var(--pp-u)) calc(14 * var(--pp-u));
  border-radius:calc(16 * var(--pp-u)); background:var(--pp-surf);
  box-shadow:inset 0 0 0 1.5px var(--pp-bd);
  transition:background .18s ease, box-shadow .18s ease; }
.pan-pick:hover{ box-shadow:inset 0 0 0 1.5px var(--pp-bd-2); }
.pan-pick .d{ font:800 calc(13 * var(--pp-u))/1 var(--font-sans); letter-spacing:-.01em;
  text-transform:uppercase; color:var(--pp-ink-3); }
.pan-pick .l{ font:400 calc(11 * var(--pp-u))/1 var(--font-mono); color:var(--pp-ink-3);
  margin:calc(2 * var(--pp-u)) 0 calc(7 * var(--pp-u));
  font-variant-numeric:tabular-nums; }
.pan-pick .m{ font:700 calc(26 * var(--pp-u))/1 var(--font-mono); color:var(--pp-accent);
  font-variant-numeric:tabular-nums; }
.pan-pick.is-on{ background:var(--pp-gold); box-shadow:inset 0 0 0 1.5px var(--pp-gold),
  0 calc(16 * var(--pp-u)) calc(30 * var(--pp-u)) calc(-14 * var(--pp-u))
  color-mix(in srgb, var(--pp-shadow) 45%, transparent); }
.pan-pick.is-on :is(.d,.m){ color:var(--pp-on-gold); }
.pan-pick.is-on .l{ color:var(--pp-on-gold); opacity:.72; }

/* the in/out pair of range steppers reuses the pick card's shell */
.pan-range{ display:flex; gap:calc(10 * var(--pp-u)); }
.pan-rcol{ flex:1; display:flex; flex-direction:column; align-items:center;
  gap:calc(4 * var(--pp-u));
  padding:calc(12 * var(--pp-u)) calc(8 * var(--pp-u));
  border-radius:calc(16 * var(--pp-u)); background:var(--pp-surf);
  box-shadow:inset 0 0 0 1.5px var(--pp-bd); }
.pan-runit{ font:700 calc(9 * var(--pp-u))/1 var(--font-mono); letter-spacing:.14em;
  text-transform:uppercase; color:var(--pp-ink-3); }
.pan-rrow{ display:inline-flex; align-items:center; gap:calc(8 * var(--pp-u)); }
.pan-rval{ min-width:1.6ch; text-align:center; letter-spacing:-.03em;
  font:700 calc(26 * var(--pp-u))/1 var(--font-mono); color:var(--pp-accent);
  font-variant-numeric:tabular-nums; }

/* ── TREPA'S CALL CURVE ────────────────────────────────────────────────────────
 * The belief curve Trepa actually showed traders. The engine prices a TRIANGLE;
 * users saw a smooth bell. Kept on purpose (Tom) — and it maps to the triangle
 * exactly: same centre, same ± edges, redrawn from the same two numbers. */
.pan-graph{ border-radius:calc(18 * var(--pp-u)); background:var(--pp-surf);
  box-shadow:inset 0 0 0 1px var(--pp-bd);
  padding:calc(13 * var(--pp-u)) calc(14 * var(--pp-u)) calc(8 * var(--pp-u)); }
.pan-graph-sub{ margin:0 0 calc(2 * var(--pp-u));
  font:400 calc(10.5 * var(--pp-u))/1.4 var(--font-mono);
  color:var(--pp-ink-3); letter-spacing:.02em; }
.pan-graph-sub b{ color:var(--pp-ink-2); font-weight:700; }
.pan-graph svg{ display:block; width:100%; height:calc(118 * var(--pp-u)); }
.pan-graph .g-band{ fill:var(--pp-accent); opacity:.12; }
.pan-graph .g-fill{ fill:var(--pp-accent); opacity:.18; }
.pan-graph .g-line{ fill:none; stroke:var(--pp-accent); stroke-width:2.2;
  vector-effect:non-scaling-stroke; }
.pan-graph .g-call{ stroke:var(--pp-accent); stroke-width:1.3; stroke-dasharray:4 4;
  opacity:.85; vector-effect:non-scaling-stroke; }
.pan-graph .g-axis{ stroke:var(--pp-bd-2); stroke-width:1; vector-effect:non-scaling-stroke; }
.pan-graph-ax{ display:flex; justify-content:space-between;
  margin-top:calc(2 * var(--pp-u)); }
.pan-graph-ax i{ font-style:normal; font:400 calc(9 * var(--pp-u))/1 var(--font-mono);
  color:var(--pp-ink-3); }

/* Trepa's confidence slider — the rail is the track colour, the FILL is a lime
   gradient with a glow, and the handle is lime with a 3px white ring. The glow
   and the ring are what make it read as Trepa's control rather than a range input
   with the accent painted on. */
.pan-conf{ display:flex; flex-direction:column; gap:calc(6 * var(--pp-u));
  padding:calc(12 * var(--pp-u)) calc(15 * var(--pp-u)) calc(10 * var(--pp-u));
  border-radius:calc(16 * var(--pp-u)); background:var(--pp-surf-2);
  box-shadow:inset 0 0 0 1px var(--pp-bd); }
.pan-conf .pan-lbl{ margin:0; letter-spacing:.16em; }
.pan-conf .pan-lbl .q{ color:var(--pp-accent); font-weight:700;
  font-size:calc(12 * var(--pp-u)); letter-spacing:normal;
  font-variant-numeric:tabular-nums; }
.pan-slider{ -webkit-appearance:none; appearance:none; width:100%;
  height:calc(24 * var(--pp-u)); background:transparent; cursor:pointer; margin:0; }
.pan-slider{ --pp-fill:50%; }
.pan-slider::-webkit-slider-runnable-track{ height:calc(6 * var(--pp-u));
  border-radius:calc(3 * var(--pp-u));
  background:linear-gradient(90deg, var(--pp-gold-2), var(--pp-accent) var(--pp-fill),
                             var(--pp-track) var(--pp-fill));
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--pp-shadow) 12%, transparent); }
.pan-slider::-moz-range-track{ height:calc(6 * var(--pp-u));
  border-radius:calc(3 * var(--pp-u));
  background:linear-gradient(90deg, var(--pp-gold-2), var(--pp-accent) var(--pp-fill),
                             var(--pp-track) var(--pp-fill)); }
.pan-slider::-webkit-slider-thumb{ -webkit-appearance:none; appearance:none;
  width:calc(22 * var(--pp-u)); height:calc(22 * var(--pp-u));
  margin-top:calc(-8 * var(--pp-u)); border-radius:50%;
  background:var(--pp-accent); border:calc(3 * var(--pp-u)) solid #fff;
  box-shadow:0 0 calc(12 * var(--pp-u)) color-mix(in srgb, var(--pp-accent) 45%, transparent); }
.pan-slider::-moz-range-thumb{ width:calc(22 * var(--pp-u)); height:calc(22 * var(--pp-u));
  border:calc(3 * var(--pp-u)) solid #fff; border-radius:50%; background:var(--pp-accent);
  box-shadow:0 0 calc(12 * var(--pp-u)) color-mix(in srgb, var(--pp-accent) 45%, transparent); }
.pan-slider:focus-visible{ outline:2px solid var(--pp-accent); outline-offset:3px; }
.pan-ends{ display:flex; justify-content:space-between; margin:0;
  font:400 calc(9 * var(--pp-u))/1 var(--font-mono); letter-spacing:.06em;
  text-transform:uppercase; color:var(--pp-ink-3); }

/* the payout readout — a green-tinted card, the headline figure in the positive
   signal and the bullseye in the brand */
.pan-payout{ display:flex; align-items:center; justify-content:space-between;
  gap:calc(14 * var(--pp-u));
  padding:calc(13 * var(--pp-u)) calc(16 * var(--pp-u));
  border-radius:calc(16 * var(--pp-u));
  background:color-mix(in srgb, var(--pp-pos) 10%, transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--pp-pos) 30%, transparent); }
.pan-payout-l, .pan-payout-r{ display:flex; flex-direction:column;
  gap:calc(3 * var(--pp-u)); min-width:0; }
.pan-payout-r{ text-align:right; }
.pan-payout .k{ font:700 calc(9 * var(--pp-u))/1 var(--font-mono); letter-spacing:.14em;
  text-transform:uppercase; color:var(--pp-ink-3); }
.pan-payout .v{ font:700 calc(24 * var(--pp-u))/1 var(--font-mono); color:var(--pp-pos);
  font-variant-numeric:tabular-nums; }
.pan-payout-r .v{ font-size:calc(10 * var(--pp-u)); color:var(--pp-ink-3); }
.pan-payout-r .v b{ color:var(--pp-accent); font-weight:700; }

/* the duel's face-off — two big pick cards with a gold VS medallion between them */
.pan-faceoff{ display:grid; grid-template-columns:1fr 1fr;
  gap:calc(10 * var(--pp-u)); position:relative; }
.pan-fo{ display:flex; flex-direction:column; align-items:center;
  border:0; cursor:pointer; text-align:center;
  padding:calc(17 * var(--pp-u)) calc(12 * var(--pp-u)) calc(15 * var(--pp-u));
  border-radius:calc(18 * var(--pp-u)); background:var(--pp-surf);
  box-shadow:inset 0 0 0 1.5px var(--pp-bd);
  transition:background .18s ease, box-shadow .18s ease; }
.pan-fo:hover{ box-shadow:inset 0 0 0 1.5px var(--pp-bd-2); }
.pan-fo .av{ display:inline-flex; align-items:center; justify-content:center;
  width:calc(60 * var(--pp-u)); height:calc(60 * var(--pp-u)); border-radius:50%;
  margin:0 0 calc(8 * var(--pp-u));
  background:linear-gradient(150deg,#16295a,#0b1734); color:#fff;
  border:calc(2.5 * var(--pp-u)) solid rgba(255,255,255,.7);
  font:900 calc(18 * var(--pp-u))/1 var(--font-sans); }
.pan-fo .n{ font:900 calc(16 * var(--pp-u))/1 var(--font-sans); color:var(--pp-accent); }
.pan-fo .p{ font:400 calc(10.5 * var(--pp-u))/1 var(--font-mono); color:var(--pp-ink-3);
  margin:calc(3 * var(--pp-u)) 0 calc(7 * var(--pp-u)); }
.pan-fo .m{ font:700 calc(25 * var(--pp-u))/1 var(--font-mono); color:var(--pp-accent);
  font-variant-numeric:tabular-nums; }
.pan-fo.is-on{ background:var(--pp-gold); box-shadow:inset 0 0 0 1.5px var(--pp-gold),
  0 calc(16 * var(--pp-u)) calc(30 * var(--pp-u)) calc(-14 * var(--pp-u))
  color-mix(in srgb, var(--pp-shadow) 45%, transparent); }
.pan-fo.is-on :is(.n,.m){ color:var(--pp-on-gold); }
.pan-fo.is-on .p{ color:var(--pp-on-gold); opacity:.72; }
.pan-vs{ position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  z-index:2; pointer-events:none;
  display:inline-flex; align-items:center; justify-content:center;
  width:calc(36 * var(--pp-u)); height:calc(36 * var(--pp-u)); border-radius:50%;
  background:var(--pp-gold); color:var(--pp-on-gold);
  border:calc(3 * var(--pp-u)) solid #fff;
  font:900 calc(12 * var(--pp-u))/1 var(--font-sans); letter-spacing:0;
  box-shadow:0 calc(8 * var(--pp-u)) calc(20 * var(--pp-u))
             color-mix(in srgb, var(--pp-shadow) 30%, transparent); }

/* the settlement axis — red on the left, green on the right, the live window in
   gold. It is the panel's own picture of "the differential IS the axis". */
.pan-axis{ border-radius:calc(16 * var(--pp-u)); background:var(--pp-surf);
  box-shadow:inset 0 0 0 1px var(--pp-bd);
  padding:calc(13 * var(--pp-u)) calc(14 * var(--pp-u)) calc(11 * var(--pp-u)); }
.pan-axis .pan-lbl{ letter-spacing:.14em; font-size:calc(9 * var(--pp-u));
  margin-bottom:calc(10 * var(--pp-u)); }
.pan-axis-bar{ position:relative; display:block; height:calc(22 * var(--pp-u)); }
.pan-axis-bar::before{ content:""; position:absolute; left:0; right:0;
  top:calc(9 * var(--pp-u)); height:calc(5 * var(--pp-u));
  border-radius:var(--radius-full);
  background:linear-gradient(90deg,
    color-mix(in srgb, var(--pp-neg) 30%, transparent),
    var(--pp-track) 50%,
    color-mix(in srgb, var(--pp-pos) 30%, transparent)); }
.pan-axis-bar i{ position:absolute; left:50%; top:calc(2 * var(--pp-u));
  width:calc(2 * var(--pp-u)); height:calc(19 * var(--pp-u));
  margin-left:calc(-1 * var(--pp-u)); background:var(--pp-bd-2); }
.pan-axis-bar b{ position:absolute; top:calc(8 * var(--pp-u));
  height:calc(7 * var(--pp-u)); border-radius:var(--radius-full);
  background:linear-gradient(90deg, var(--pp-gold-2), var(--pp-gold));
  box-shadow:0 0 calc(12 * var(--pp-u)) color-mix(in srgb, var(--pp-gold) 50%, transparent);
  transition:left .18s ease, width .18s ease; }
.pan-axis-ends{ display:flex; justify-content:space-between;
  margin-top:calc(4 * var(--pp-u));
  font:400 calc(9 * var(--pp-u))/1 var(--font-mono); letter-spacing:.04em;
  color:var(--pp-ink-3); }

/* the stake row — a gold-ringed field beside a "use remaining" button, over the
   allocation bar. This is the block that says "a real account, mid-session". */
.pan-stake{ display:flex; gap:calc(8 * var(--pp-u));
  margin-bottom:calc(10 * var(--pp-u)); }
.pan-stake-in{ flex:1; display:flex; align-items:center; gap:calc(6 * var(--pp-u));
  padding:calc(12 * var(--pp-u)) calc(14 * var(--pp-u));
  border-radius:calc(12 * var(--pp-u)); background:var(--pp-surf);
  font:700 calc(22 * var(--pp-u))/1 var(--font-mono); color:var(--pp-accent);
  font-variant-numeric:tabular-nums;
  box-shadow:inset 0 0 0 1.5px var(--pp-gold),
             0 0 0 calc(3 * var(--pp-u)) color-mix(in srgb, var(--pp-gold) 12%, transparent); }
.pan-stake-in i{ font-style:normal; font-size:calc(16 * var(--pp-u)); color:var(--pp-ink-3); }
.pan-stake-max{ display:flex; flex-direction:column; justify-content:center;
  padding:0 calc(14 * var(--pp-u)); border-radius:calc(12 * var(--pp-u));
  background:var(--pp-surf); box-shadow:inset 0 0 0 1px var(--pp-bd);
  font:700 calc(9 * var(--pp-u))/1.5 var(--font-mono); letter-spacing:.06em;
  text-transform:uppercase; color:var(--pp-accent); }
.pan-stake-max i{ font-style:normal; color:var(--pp-ink-3); }
.pan-alloc{ display:flex; height:calc(9 * var(--pp-u)); overflow:hidden;
  border-radius:var(--radius-full); background:var(--pp-track); }
.pan-alloc i, .pan-alloc b{ height:100%; }
.pan-alloc i{ background:var(--pp-accent); }
.pan-alloc i + i{ background:var(--pp-alloc-2); }
.pan-alloc b{ background:var(--pp-gold); }

/* ── THE TOUCH CUE ─────────────────────────────────────────────────────────────
 * ⚠ REBUILT 2026-07-29 (Tom: "you seemed to have applied static effects like
 * shadows on the UX as the affordance, when the effect here just looks like weird
 * UX treatment — what I'd envision is more of an overlay subtly animating").
 * That is the right correction and the earlier attempt had the wrong shape: it
 * DECORATED the controls — a glow on this button, a ring on that card — so the
 * partner's own UI looked altered, which is the one thing a panel must never do
 * (§13 rule 2: a panel is a picture of somebody else's product). Painting four
 * things at once also says "everything here is special", which is not a cue, it
 * is noise.
 *
 * So the cue is now ONE OVERLAY that touches nothing. A soft touch-pointer rides
 * above the screen, travels between two of the screen's real controls and taps
 * each one — the universal "this is interactive" gesture, and the same thing a
 * person would do if they were showing you the app over their shoulder. The
 * controls underneath are rendered exactly as the partner ships them.
 *
 * · It is a SIBLING of the app content inside `.pan-screen`, at `pointer-events:
 *   none`, so it can never intercept the click it is advertising.
 * · Its two anchor points are MEASURED from the real controls by pitch.js and
 *   published as `--cue-a-*` / `--cue-b-*` in the panel's own local pixels, so
 *   the cue cannot drift from what it is pointing at when the layout moves.
 * · It retires permanently on first touch, like every other affordance here.
 * · The ink is the PARTNER's, not ours — `--pp-ink` at low alpha reads as a
 *   fingertip on a light screen and as a soft white disc on a dark one. */
.pan-cue{ position:absolute; left:0; top:0; z-index:6; pointer-events:none;
  width:calc(40 * var(--pp-u)); height:calc(40 * var(--pp-u));
  margin:calc(-20 * var(--pp-u)) 0 0 calc(-20 * var(--pp-u));
  translate:var(--cue-a-x, 50%) var(--cue-a-y, 50%);
  animation:pan-cue-travel 6.4s cubic-bezier(.65,0,.2,1) infinite; }
.pan:not(.is-untouched) .pan-cue{ display:none; }
/* the pointer itself — a disc with a hairline rim, pressing on each tap */
.pan-cue::before{ content:""; position:absolute; inset:0; border-radius:50%;
  background:color-mix(in srgb, var(--pp-ink) 26%, transparent);
  box-shadow:inset 0 0 0 1.5px color-mix(in srgb, var(--pp-ink) 60%, transparent),
             0 0 0 calc(3 * var(--pp-u)) color-mix(in srgb, var(--pp-paper) 55%, transparent);
  animation:pan-cue-press 6.4s ease-out infinite; }
/* the tap — one ring expanding out of the pointer at each stop */
.pan-cue::after{ content:""; position:absolute; inset:0; border-radius:50%;
  box-shadow:0 0 0 1.5px color-mix(in srgb, var(--pp-ink) 62%, transparent);
  animation:pan-cue-tap 6.4s ease-out infinite; }

/* A → dwell → B → dwell → back. The travel is the slow part and the dwell is
   where the tap happens, so the eye is always led to a control and then shown
   what to do with it. */
@keyframes pan-cue-travel{
  0%,   40%  { translate:var(--cue-a-x, 50%) var(--cue-a-y, 50%); }
  54%,  92%  { translate:var(--cue-b-x, 50%) var(--cue-b-y, 50%); }
  100%       { translate:var(--cue-a-x, 50%) var(--cue-a-y, 50%); }
}
@keyframes pan-cue-press{
  0%, 8%   { scale:1; opacity:.85; }
  13%      { scale:.74; opacity:1; }
  22%, 60% { scale:1; opacity:.85; }
  65%      { scale:.74; opacity:1; }
  74%,100% { scale:1; opacity:.85; }
}
@keyframes pan-cue-tap{
  0%,  9%     { transform:scale(.5); opacity:0; }
  14%         { transform:scale(.6); opacity:.9; }
  30%         { transform:scale(2.1); opacity:0; }
  30.01%, 61% { transform:scale(.5); opacity:0; }
  66%         { transform:scale(.6); opacity:.9; }
  82%         { transform:scale(2.1); opacity:0; }
  100%        { transform:scale(.5); opacity:0; }
}

@media (prefers-reduced-motion: reduce){
  .pan-scale-you, .pan-axis-bar b, .pan-mode, .pan-step, .pan-pick, .pan-fo{ transition:none; }
  .pan-step:active{ transform:none; }
  /* reduced motion keeps the STATEMENT and drops the movement: the pointer parks
     on the first control and stops, so the affordance is still legible to a reader
     who has asked for stillness. */
  .pan-cue, .pan-cue::before, .pan-cue::after{ animation:none; }
  .pan-cue::after{ opacity:0; }
}
