/* ============================================================================
 * S8 Insights — Public light/dark theme layer
 * ============================================================================
 * The six inline-token marketing pages (home, how-it-works, methodology,
 * pricing, intelligence, about) and the record page declare their DARK palette
 * inline in a per-page :root (--bg, --s1..--s3, --text, --text2, --dim, the
 * --gold* family, --red/--green/--blue). Dark is the default and is untouched.
 *
 * This file adds the LIGHT theme by re-mapping the same token names under
 * :root[data-theme="light"]. It also defines --ink, the foreground-ink RGB
 * triple used by every rgba(var(--ink,255,255,255),a) surface hairline/overlay
 * so those flip with the theme instead of staying white.
 *
 * It used to describe itself as "a faithful inversion", and it was one: the
 * navy stack flipped onto warm cream (#FAF8F2 / #F3EFE5 / #ECE7DA, hue 89-91deg
 * in OKLCH against the dark identity's 267deg), which is a different brand
 * rather than the same brand in daylight. Rebuilt 2026-08-11 onto the shared
 * daylight stack: same hue family as the navy, same elevation direction, and a
 * gold that keeps enough chroma to still read as gold. The values here mirror
 * brand-colors.css in the --bg/--s1../--gold vocabulary the marketing pages
 * use; keep the two in step.
 *
 * Applied before first paint by the per-page inline theme script, which sets
 * data-theme on <html> from localStorage('s8-theme') or, absent a stored choice,
 * from prefers-color-scheme. Manual choice via the nav toggle overrides the OS.
 *
 * Colour governance: light values are AA-checked against the surfaces they sit
 * on. Do not hard-code light colours in a page; extend the map here.
 * ============================================================================ */

:root {
  color-scheme: dark;
  /* Foreground ink for hairlines/overlays. Dark default; the var() fallback in
     each usage covers pages that never load this file. */
  --ink: 255, 255, 255;
  /* Gold-ink: the token behind inline-styled gold text so it can flip in light.
     Dark = the page gold; light now resolves it to the light gold ink, not to
     a substitute colour (see the light block). */
  --gi: var(--gold);
  /* Filled controls have their own gold role. In dark these resolve to the
     existing shipped gradient exactly; in light they DEEPEN, because a gold
     luminous enough to read as gold cannot also clear the 3:1 boundary
     contrast a control needs against paper. */
  --gold-fill-start: #9a7d33;
  --gold-fill: var(--gold);
  /* Hover-strength gold ring: pages that step a border UP on hover route it
     here so the step stays a step in light (the dark alpha would read weaker
     than the resting --gold-ring on cream). */
  --gold-ring-strong: rgba(201, 168, 76, 0.35);
}

:root[data-theme="light"] {
  color-scheme: light;
  --ink: 10, 22, 40;

  /* Surfaces — the daylight stack: the navy's own hue lightened, base lightest
     and raised surfaces progressively deeper. Mirrors --s8-navy..-4. */
  --bg: #FBFCFE;
  --s1: #F1F4FA;
  --s2: #E7EBF3;
  --s3: #D9DFEB;

  /* Text — brand navy as ink */
  --text:  #0A1628;
  --text2: #42506A;
  --dim:   #4F5B70;

  /* Gold, INK role. Kept as chromatic as AA allows (92% of the dark gold's
     OKLCH chroma against the retired #7E5F16's 81%), which is what stops a
     darkened gold sliding into olive. Filled controls are --gold-fill*. */
  --gold:      #886000;
  --gold-lt:   #8C6300;
  --gold-dim:  #9A7A2E;
  --gold-glow: rgba(136, 96, 0, 0.12);
  --gold-ring: rgba(136, 96, 0, 0.30);
  --gold-ring-strong: rgba(136, 96, 0, 0.45);
  --gold-fill-start: #A47800;
  --gold-fill: #AC7D00;

  /* Status — hues preserved, darkened to clear AA on light surfaces.
     AA is checked against the DEEPEST small-text surface (--s2 #E7EBF3, the
     raised card stack), not just --bg: green 5.18:1, red 5.23:1, blue 5.31:1. */
  --red:   #B23125;
  --green: #0F7038;
  --blue:  #1F5BBF;

  /* Gold text and filled controls stay separate roles, but --gi is now the
     gold ink rather than a substitute colour: it measures 4.72:1 on --s2 and
     5.50:1 on --bg, so small gold text is legible as gold. */
  --gi: #886000;
}

/* ----------------------------------------------------------------------------
 * Light-mode gold text (colour only; dark theme untouched)
 * ----------------------------------------------------------------------------
 * This block used to be the gold-text SPLIT: on cream the olive gold read
 * muddy, so small gold text became brand navy #1A3B8C and hero italics a
 * warmer display gold. Both substitutions are retired. The selectors stay,
 * because these elements take their colour from a page-level rule that assumes
 * a dark ground, but they now resolve to the gold token, so an eyebrow is the
 * same gold in both themes.
 * -------------------------------------------------------------------------- */
:root[data-theme="light"] .eyebrow,
:root[data-theme="light"] .consent-section-title,
:root[data-theme="light"] .rg-footer .label,
:root[data-theme="light"] .rg-footer a,
:root[data-theme="light"] .s8nav-link[aria-current="page"],
:root[data-theme="light"] .s8foot-rg .s8foot-rg-label,
:root[data-theme="light"] .s8foot-rg a { color: var(--gold); }

/* ── Body scroll lock behind a blocking overlay ──────────────────────────────
 * THE SOURCE OF THIS RULE. shared/public-theme.css carries a byte-identical
 * copy, for the same reason as the zoom floor below: the seven marketing pages
 * load that sheet and never this one.
 *
 * WHAT IT FIXES. Measured across the overlay lifecycle pass: the page scrolled
 * 300px behind EVERY blocking overlay on the site — the bankroll modals, all
 * three tracker modals, the match-intel bottom sheet (1141px behind it), and
 * the 18+ AGE GATE, which is compliance furniture a visitor could simply
 * scroll past and read the site behind. Exactly one surface in the codebase
 * locked scroll (the run takeover, in JS); every other one never implemented it.
 *
 * WHY :has() AND NOT JAVASCRIPT. A JS lock means editing the open/close path of
 * five separate modal implementations that share no code, and each would then
 * own its own scroll-restoration bug. This is one declarative rule that keys on
 * the state the markup already sets. :has() has been baseline since 2023.
 *
 * WHY overflow:hidden AND NOT position:fixed. The position:fixed technique has
 * to store and restore scrollY by hand, and getting that wrong is what jumps
 * the reader to the top on close — a defect this pass also measured. Leaving
 * the document where it is means there is nothing to restore.
 *
 * ADDING AN OVERLAY: give it [data-s8-lock-scroll] rather than extending this
 * list. The named selectors are the surfaces that predate the convention. */
html:has(.modal-overlay.open),
html:has(.br-modal-overlay.open),
html:has(#ageOverlay:not(.hidden)),
html:has([data-s8-lock-scroll]),
body:has(.modal-overlay.open),
body:has(.br-modal-overlay.open),
body:has(#ageOverlay:not(.hidden)),
body:has([data-s8-lock-scroll]) {
  overflow: hidden;
  /* iOS momentum scrolling can still carry the document under a locked body;
     touch-action stops the gesture reaching it at all. */
  touch-action: none;
}


/* The match-intel date picker is a bottom SHEET only below 640px; above that
   it is a small popover anchored to its trigger, and locking the page behind a
   popover strands a desktop reader — measured as a Critical when this selector
   was unconditional. The breakpoint is the component's own (match-intel.css:503). */
@media (max-width: 639.98px) {
  html:has(.mi-datepop:not([hidden])),
  body:has(.mi-datepop:not([hidden])) { overflow: hidden; touch-action: none; }
}

/* ── iOS text-entry zoom floor ───────────────────────────────────────────────
 * THE SOURCE OF THIS RULE. shared/public-theme.css carries a byte-identical
 * copy because the two sheets are the site's two independent roots — the seven
 * marketing pages load public-theme.css and never this file. Keep them in step;
 * netlify/tests/input-zoom-guard.test.mjs asserts they are identical, and the
 * responsive harness re-measures every focusable control at runtime.
 *
 * WHAT IT FIXES. iOS Safari zooms the page when a focused text control renders
 * below 16px, and does not zoom back. Guards for this already existed in four
 * places (app-shell.css:64, intelligence.html, record.html, pricing.html), all
 * written as the bare type selector `input, textarea, select` — specificity
 * (0,0,1). EVERY input rule in this codebase is a class, (0,1,0) or higher, so
 * those guards lost the cascade in every place that mattered and had never
 * done anything. Sign in, sign up, password reset, the /record filters, the
 * Elite+ waitlist field, the whole personal tracker, the bankroll modals, the
 * stake calculator, the intelligence scope selects and the engine-run player
 * search and sort were all zooming.
 *
 * HOW IT WINS WITHOUT !important. `:root:root` is (0,2,0), so with the element
 * this rule is (0,2,1) — above every offending rule in the repo, the most
 * specific of which is (0,1,1). Specificity beats source order, so it does not
 * matter which sheet loads last. The exclusion list is wrapped in :where(),
 * which contributes ZERO specificity, so the list can grow without the rule
 * silently getting stronger.
 *
 * WHY (pointer: coarse) AND NOT A WIDTH. The zoom is a property of the input
 * method, not the viewport: a width query would miss a touch laptop and would
 * change desktop for no reason. Under a fine pointer nothing here applies and
 * desktop stays pixel-identical.
 *
 * The excluded types either cannot receive typed text or are buttons whose
 * label size is a deliberate design choice. */
@media (pointer: coarse) {
  :root:root input:not(:where(
    [type="checkbox"], [type="radio"], [type="range"], [type="color"],
    [type="file"], [type="submit"], [type="button"], [type="image"], [type="hidden"]
  )),
  :root:root select,
  :root:root textarea {
    font-size: var(--s8-fs-base, 16px);
  }
}
