/* ============================================================
   NOVA — Design Tokens (monochrome, Notion/Apple-clean)
   Neutral Radix-gray ramp · Inter · hairline borders · small radii.
   Theme via [data-theme="light"|"dark"] on <html>.
   Accent = near-black ink (light) / near-white (dark), overridable
   per-instance via --brand-accent (white-label).
   Legacy gold/ink tokens are ALIASED to neutrals at the
   bottom so the 14 existing views keep rendering while migrating.
   ============================================================ */

:root {
  /* ---- Typography ---- */
  --font-display: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-mono: "Geist Mono", "JetBrains Mono", ui-monospace, "SF Mono", monospace;

  /* ---- THE TYPE SCALE ----
     Eight rungs. Nothing else ships. Every one of them is a token, and the
     bottom rung IS the floor — there is no rung below it any more.

       --fs-display  33-38px  the one number on a hero
       --fs-h1       22.4px   page title
       --fs-h2       18.4px   section title
       --fs-h3       16px     card / panel title
       --fs-body     15px     prose, list rows, anything you read
       --fs-sm       13.5px   dense rows, buttons, controls
       --fs-xs       12.5px   labels, captions, meta
       --fs-2xs      12px     THE FLOOR — smallest text that ships, full stop

     THE 12px FLOOR (teardown 01 §6.2, Findings F10). A live measurement on
     2026-08-01 counted 2,254 text nodes under 12px across the three products —
     8.5px, 9px, 9.5px, 10px and 11px — with Calendar contributing 110 per
     screen. Small print is where the product does most of its talking: nav
     group headers, counts, hints, stats, keycaps, weekday letters, hour
     labels. None of it may sit below 12px.

     --fs-micro USED to be the documented exception at 11px, "glyphs and digits
     only". It did not hold: 702 of the 2,254 offenders were --fs-micro, and
     they included the word "esc" on a keycap and two-digit unread counts. An
     exception that big is not an exception, it is a second floor. The token
     stays (call sites keep working) and now resolves to the real floor, so
     there is exactly ONE number to remember. */
  --fs-display: clamp(1.7rem, 2.4vw, 2.05rem);
  --fs-h1: 1.4rem;
  --fs-h2: 1.15rem;
  --fs-h3: 1.0rem;
  --fs-body: 0.9375rem;
  --fs-sm: 0.8438rem;   /* 13.5px */
  --fs-xs: 0.78rem;     /* 12.5px */
  --fs-2xs: 0.75rem;    /* 12px — THE FLOOR. Nothing renders smaller. */
  --fs-micro: var(--fs-2xs);  /* retired alias — was 11px. Do not reintroduce. */

  /* A PLATFORM THRESHOLD, NOT A TYPE CHOICE.
     iOS zooms the whole page when a form field under 16px takes focus, and
     leaves it zoomed — the app looks broken and there is no way back except a
     pinch. Every field on a phone is held at this size (phone.css, FIELDS).
     It is a token because the ship gate rightly refuses literal font sizes, and
     it is its own token rather than --fs-body because the two mean different
     things: --fs-body is what reads well, this is what Safari will tolerate.
     They happen to both be 16px on a phone today. Do not merge them. */
  --fs-ios-nozoom: 16px;

  /* ---- Spacing scale ---- */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px;
  --sp-5: 20px; --sp-6: 24px; --sp-7: 32px; --sp-8: 40px;
  --sp-9: 48px; --sp-10: 64px; --sp-12: 80px;

  /* ---- Tap targets (teardown 01 §6.3 / WCAG 2.2 SC 2.5.8) ----
     WCAG 2.2 sets a hard 24×24 CSS-px floor for any pointer target. Apple HIG
     says 44×44, Material says 48×48, and Hoober's field research puts the
     rage-tap threshold at ~42px at the top of a phone screen and ~46px at the
     bottom. 44 is the design target; 24 is the number you are not allowed to
     go below, ever.
     Two ways to reach it, in order of preference:
       1. make the control actually 44px tall (rail rows, list rows, nav);
       2. where the visual design genuinely needs a smaller chip, keep the
          paint small and grow the HIT AREA with `.u-tap44`/`.u-tap-v` below
          (base.css) — SC 2.5.8 measures the target region, not the ink. */
  --tap-min: 44px;
  --tap-min-mobile: 48px;
  /* The PAD is 2px bigger than the floor, on purpose. A transparent ::before
     of exactly 44px centred on a control gives a region that is 44px WIDE but
     only reaches 21px either side of the centre pixel — so a centre-out
     measurement (which is how `verify-a11y-tokens.mjs` and, more importantly,
     a thumb, work) sees 43. Sub-pixel layout positions shave another fraction
     off. 46 makes the guarantee actually hold at 44 rather than round down
     through it. Overhang stays inside the gap between neighbouring controls:
     7px each side on a 32px chip, and the tightest gap in the product (the
     topbar's 8px) still clears. */
  --tap-pad: 46px;
  /* The same trick at the NORMATIVE floor. SC 2.5.8 (AA, WCAG 2.2) is 24×24;
     the 44 above is SC 2.5.5, which is AAA. Dense grids — a 7-column mini
     calendar, a task row's 14px checkbox — have no room for 44 and a pad that
     big lands on the neighbouring control, which is a worse bug than a small
     target. Those take `.u-tap24` and clear 24 with 2px to spare. */
  --tap-pad-sm: 26px;

  /* ---- CONTROL HEIGHTS (P1-03) ----
     A live probe over 9 Nova OS routes measured 9–16 distinct button heights
     PER ROUTE. There are three, and a fourth for text fields:

       --ctl-h-sm  32px  dense toolbars, row actions, chips-as-buttons
       --ctl-h-md  38px  the default button
       --ctl-h-lg  44px  primary CTAs, mobile, anything standing alone

     All three carry a 44px HIT REGION via the `::before` pad in
     components.css — the paint is the designer's, the target is WCAG's.
     NEVER reach 44 with `min-height` on an element whose height someone
     designed: that is what broke the app-shell brand lockup (Findings F7).

     Fields are their own rung, and that is deliberate: `::before` does not
     render on a replaced element, so an <input> has no hit pad and its real
     height is the only lever there is. It was 40 — four short of the floor,
     for no reason other than that nobody had finished the thought — and every
     `.input` in the product measured 40 or 41 against a 44 promise. It is 44
     now, which is the ONE place raising a real height is the correct fix
     rather than the banned one: nothing here is faking a target with
     `min-height`, the field genuinely IS 44 tall. */
  --ctl-h-sm: 32px;
  --ctl-h-md: 38px;
  --ctl-h-lg: 44px;
  --ctl-h-fld: 44px;

  /* ============================================================
     MOTION SCALE (--mo-*) — P5-05.
     Four durations, two easings, two springs. Lives HERE rather than in
     motion.css because components.css / forms.css use these tokens and are
     loaded by pages that never load motion.css (login.html, affiliate.html):
     an undefined custom property inside a `transition` shorthand invalidates
     the whole declaration, so a token defined "somewhere else" is a token
     that silently switches motion off on those pages.
     ============================================================ */

  /* ---- Duration scale (short by design) ---------------------------- */
  --mo-dur-1: 120ms;  /* micro:   hover tint, icon color, tap feedback   */
  --mo-dur-2: 200ms;  /* base:    most interactions, focus ring          */
  --mo-dur-3: 320ms;  /* entrance:card/list reveals, drawer/panel        */
  --mo-dur-4: 480ms;  /* overlay: modal/backdrop, large emphasis moments */
  --mo-stagger-step: 42ms; /* per-item offset for .mo-stagger cascades   */
  --mo-delay-tip: 350ms;   /* hover dwell before a tooltip appears        */

  /* ---- Named easings ----------------------------------------------- */
  /* Standard: quick, symmetric-ish ease for micro-interactions.        */
  --mo-ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
  /* Emphasized / decelerate: enters fast, settles slow — for content
     arriving on screen (the house --ease-smooth, kept in sync).        */
  --mo-ease-emphasized: cubic-bezier(0.22, 1, 0.36, 1);

  /* ---- linear() SPRING curves (generated, damped oscillator) -------- */
  /* SMOOTH spring — critically damped (ζ≈1.0, ω≈7), NO overshoot.
     Use for overlay/content entrances that should feel alive but calm. */
  --mo-spring-smooth: linear(
    0, 0.0487, 0.1558, 0.2826, 0.4082, 0.5221, 0.6204, 0.7023,
    0.7689, 0.8222, 0.8641, 0.8968, 0.922, 0.9414, 0.9561, 0.9672,
    0.9756, 0.9819, 0.9866, 0.9901, 1
  );
  /* SUBTLY BOUNCY spring — underdamped (ζ≈0.72, ω≈8), ~3.8% overshoot.
     Tasteful settle, not cartoonish. Use for pops / affirmative moments.*/
  --mo-spring-bouncy: linear(
    0, 0.0472, 0.1597, 0.3028, 0.4523, 0.5927, 0.7152, 0.8159,
    0.8943, 0.9521, 0.992, 1.0174, 1.0316, 1.0376, 1.0381, 1.035,
    1.0301, 1.0244, 1.0187, 1.0136, 1.0092, 1.0057, 1.003, 1.0011, 1
  );

  /* ---- Radii (soft, Notion/ClickUp/Apple) ----
     Five rungs and a pill. `--r-2xl` and `--r-xs` were merged into their
     neighbours in the P1-03 pass: the same probe measured 5–8 distinct radii
     per route, and two of the rungs differed from the one next to them by 2px
     — a difference nobody can see and everybody has to choose between.
     A circle is `--r-pill`, not `50%`: they paint identically on a square box
     and one of them is not on the scale. */
  --r-xs: 7px; --r-sm: 9px; --r-md: 11px; --r-lg: 14px;
  --r-xl: 18px; --r-2xl: var(--r-xl); --r-pill: 999px;
  /* The button radius. One value for every button, every size, everywhere —
     `.btn` was --r-sm and `.btn-sm` was --r-xs, which is two radii for one
     component and the single easiest radius to delete. */
  --r-btn: var(--r-sm);

  /* ---- Layout dimensions ---- */
  --rail-w: 248px;
  --rail-w-collapsed: 64px;
  --topbar-h: 54px;
  --aidock-w: 380px;

  /* ---- Safe areas ----------------------------------------------------
     The notch, the Dynamic Island and the home indicator, as tokens rather
     than as env() spelled out at each call site. Every entry page carries
     `viewport-fit=cover`, so these are LIVE on a phone and exactly 0 on a
     desktop browser — which is why they can be used unconditionally and do
     not need a `.native-app` guard.

     They exist as tokens because the native app taught us the call sites are
     not where you expect: the bottom bar had handled its inset since Nova
     Home shipped (homenav.css), and the TOP had never been handled anywhere
     at all, so `.topbar` rendered underneath the clock and the Dynamic Island
     on every one of Nova Home's 29 routes. Anything that pins itself to an
     edge — a bar, a sheet, a drawer, a full-screen takeover — reads these. */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);

  /* ---- Motion (house curves — never the browser default `ease`) ---- */
  --ease-smooth: cubic-bezier(0.22, 1, 0.36, 1);   /* default for almost everything */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);       /* alias (decorative entrances) */
  --ease-spring: cubic-bezier(0.35, 1.55, 0.65, 1); /* badges, pops, overshoot */
  --ease-in-out: cubic-bezier(0.66, 0, 0.34, 1);    /* symmetric moves */
  --t-fast: 150ms;
  --t-med: 200ms;
  --t-slow: 280ms;

  /* ---- z-index ----
     ONE ordered scale, low → high. Use the tokens, never raw magic numbers.
     Toast is deliberately the ceiling so a transient confirmation always wins
     over any menu/lightbox (WS-14 defect #4: content/wins lightboxes at raw
     200/220 used to render ON TOP of toasts — toast now clears them).

     THE RULES, not just the numbers (teardown 02 §S6 / 01 §6.5). The setup
     flow has its own five-rung sub-scale (`--z-su-*`, documented in
     setup.css); this is the app-wide parent it hangs off, and it obeys the
     same three rules:
       1. Nothing above --z-dock may cover a primary button. Chrome that
          floats (docks, orb, hype toasts) is corner-pinned, height-capped,
          and the surface underneath reserves its live height.
       2. Decorative and aria-hidden layers get `pointer-events: none`.
          Always. An invisible element that can be clicked is a bug with no
          symptom — `.nova-orb-grab`, an empty transparent aria-hidden 80×96
          div at a raw z-index of 89, is what ate the setup composer's Send
          button. 89 was not on any scale; that was the whole problem.
       3. ONE overlay at a time. Panels reflow the column; they do not float
          over the CTA they are describing.
     Anything that paints in a fixed/absolute layer must take its number from
     here BY NAME. If a new layer needs a rung that does not exist, add the
     rung here — do not invent a number at the call site. */
  --z-base: 0;                 /* the content plane */
  --z-sticky: 2;               /* sticky headers/action bars riding content */
  --z-topbar: 30;
  --z-rail: 40;
  --z-orb: 45;                 /* the AI orb + its drag pad (was a raw 89) */
  --z-dock: 50;                /* corner chrome: progress dock, hype toasts */
  --z-drawer: 90;
  --z-modal: 100;
  --z-palette: 120;
  --z-popover: 140; --z-menu: 140; --z-tooltip: 150; --z-lightbox: 220;
  --z-toast: 300;
  /* The arrival overlay (nova-boot.css) covers the whole app for one animation
     before anything else exists on screen, so it is the only rung above toast.
     It was a raw 9999, which is exactly the magic number this scale forbids. */
  --z-boot: 400;
}

/* ============================================================
   LIGHT THEME (default surface)
   ============================================================ */
:root,
[data-theme="light"] {
  color-scheme: light;

  /* Backgrounds & surfaces */
  --bg: #ffffff;
  --surface-0: #ffffff;
  --surface-1: #fafafa;
  --surface-2: #f4f4f5;
  --surface-3: #ececee;
  --surface-glass: rgba(255, 255, 255, 0.82);
  --raised: #ffffff;

  /* Text — every rung below is measured, not eyeballed.
     Ratios quoted against --bg / --surface-1 / --surface-2, the three
     backgrounds muted text actually sits on in this app.
     Teardown 02 §S5: light mode was measurably WORSE than dark (15 failures
     vs 8 on the same page) and --text-500 at 2.56:1 was the single most
     repeated AA failure in the product. */
  --text-100: #171717;  /* primary heading/body strong */
  --text-200: #2a2a2a;  /* body */
  --text-300: #52525b;  /* secondary            7.73 / 7.41 / 7.03 */
  --text-400: #5d5d65;  /* tertiary / muted     6.52 / 6.25 / 5.94  (was #71717a · 4.40 on surface-2) */
  --text-500: #696975;  /* faint but READ       5.41 / 5.19 / 4.93  (was #a1a1aa · 2.33 on surface-2) */
  /* The old --text-500. Genuinely decorative or genuinely disabled ONLY —
     WCAG 1.4.3 exempts inactive controls, and nothing else. If a person has
     to read it, it is --text-500, not this. */
  --text-faint: #a1a1aa;

  /* Borders */
  --border-soft: #f0f0f1;
  --border: #ececec;
  --border-strong: #dcdcdc;

  /* Accent: near-black ink (overridable per instance/product via theme.js) */
  --accent: var(--brand-accent, #18181b);
  --accent-hover: var(--brand-accent, #000000);
  --accent-fg: var(--brand-accent-fg, #ffffff);  /* text on accent fills */
  --accent-soft: var(--brand-accent-soft, rgba(24, 24, 27, 0.06));
  --accent-ring: var(--brand-accent-ring, rgba(24, 24, 27, 0.14));
  /* Text selection. NOT --accent-soft (6% ink): inside a field that reads as
     "nothing is selected" — reported as "you can't really see it fully". This is
     a deliberately visible brand-teal wash that still keeps near-black text
     legible on top of it. */
  --select-bg: rgba(63, 141, 134, 0.42);
  --select-fg: var(--text-100);

  /* Semantic status — desaturated, sparse.
     Darkened one step in LIGHT mode only: each of these doubles as text
     ("15d" stale, "$0 overdue") and as a fill under white text (count
     chips), and at the old values both failed — e.g. #b07d2a stale text was
     3.61:1 on white and white-on-#3f8d86 was 3.91:1. Same hue, deeper, so
     the palette still reads as itself. Dark mode already passed and is
     untouched. */
  --green-400: #317855;  --green-bg: rgba(63, 155, 110, 0.10);
  --red-400:   #b6473e;  --red-bg:   rgba(194, 85, 77, 0.10);
  /* SOLID danger fill — a red chip with WHITE text on it (the calendar "now"
     marker is the only one). --red-400 is tuned to be readable AS TEXT on the
     page background; white on top of it measured 2.57:1 light / 3.01:1 dark and
     was one of the last two contrast failures in the product. This rung is the
     same red, deepened until white actually reads: 8.0:1 light, 5.2:1 dark. */
  --red-solid: #8f2f2a;  --red-solid-fg: #ffffff;
  --amber-400: #8d6422;  --amber-bg: rgba(176, 125, 42, 0.11);
  /* Status aliases — used app-wide as var(--ok/--warn/--danger). Point them at the
     desaturated palette so the vivid emerald/amber/radix-red fallbacks never render.
     The var() indirection resolves per-theme automatically (green-400 etc. are themed). */
  --ok:     var(--green-400);
  --warn:   var(--amber-400);
  --danger: var(--red-400);
  --blue-400:  #4d6c9f;  --blue-bg:  rgba(79, 111, 163, 0.10);
  --violet-400:#6f5fa3;  --violet-bg:rgba(111, 95, 163, 0.10);
  --teal-400:  #357670;  --teal-bg:  rgba(63, 141, 134, 0.10);
  --pink-400:  #9c547a;  --pink-bg:  rgba(166, 90, 130, 0.10);

  /* Google brand — LOCKED VALUES, do not neutralize.
     Google's Sign-in branding guidelines mandate exact surface/text/border colors
     and forbid recoloring the G mark, so these are the one place in the system that
     is deliberately NOT tuned to our palette. Light theme surface per the spec. */
  --g-surface:        #ffffff;
  --g-surface-hover:  #f7f8f8;   /* spec: 8% #303030 state layer over white */
  --g-text:           #1f1f1f;
  --g-border:         #747775;
  --g-focus-ring:     rgba(66, 133, 244, 0.30);

  /* Pipeline / category accents (neutralized — used as small dots) */
  --c-venture:  #4f6fa3;
  --c-investor: #3f9b6e;
  --c-operator: #6f5fa3;
  --c-chrg:     #b07d2a;

  /* Shadows — restrained */
  --shadow-sm: 0 1px 1px rgba(0,0,0,0.04);
  --shadow-md: 0 1px 2px rgba(0,0,0,0.05), 0 1px 3px rgba(0,0,0,0.04);
  --shadow-lg: 0 4px 14px -4px rgba(0,0,0,0.10), 0 2px 6px rgba(0,0,0,0.05);
  --shadow-xl: 0 12px 36px -10px rgba(0,0,0,0.18), 0 4px 12px rgba(0,0,0,0.08);
  --shadow-inset: none;
  /* Layered depth: hairline ring (not a border) + tight contact + wide ambient, all faint. */
  --shadow-card: 0 1px 2px rgba(0,0,0,0.05), 0 2px 4px rgba(0,0,0,0.02), 0 0 0 0.5px rgba(0,0,0,0.08);
  --shadow-elevated: 0 4px 8px rgba(0,0,0,0.02), 0 8px 12px rgba(0,0,0,0.02), 0 2px 4px rgba(0,0,0,0.03), 0 1px 2px rgba(0,0,0,0.05), 0 0 0 0.5px rgba(0,0,0,0.10);
}

/* ============================================================
   DARK THEME
   ============================================================ */
[data-theme="dark"] {
  color-scheme: dark;

  --bg: #171717;
  --surface-0: #171717;
  --surface-1: #1e1e1e;
  --surface-2: #262626;
  --surface-3: #2f2f2f;
  --surface-glass: rgba(23, 23, 23, 0.82);
  --raised: #1e1e1e;

  --text-100: #ebebeb;
  --text-200: #d4d4d4;
  /* -300 lifted with -400 so the ramp still steps DOWN in three visible
     stages; at the old #a1a1a1 it would have sat below the new -400. */
  --text-300: #b5b5b5;  /* 8.74 / 8.13 / 7.38  (was #a1a1a1) */
  --text-400: #a2a2a2;  /* 7.02 / 6.53 / 5.93  (was #8a8a8a · 4.38 on surface-2) */
  --text-500: #939393;  /* 5.84 / 5.43 / 4.93  (was #6b6b6b · 2.84 on surface-2) */
  --text-faint: #6b6b6b;  /* decorative / disabled only — see the light block */

  --border-soft: #232323;
  --border: #2a2a2a;
  --border-strong: #3a3a3a;

  --accent: var(--brand-accent, #fafafa);
  --accent-hover: var(--brand-accent, #ffffff);
  --accent-fg: var(--brand-accent-fg, #171717);
  --accent-soft: var(--brand-accent-soft, rgba(255, 255, 255, 0.08));
  --accent-ring: var(--brand-accent-ring, rgba(255, 255, 255, 0.16));
  /* Selection on dark: a heavier teal wash so highlighted text still reads. */
  --select-bg: rgba(95, 179, 170, 0.40);
  --select-fg: #ffffff;

  --green-400: #5cba8a;  --green-bg: rgba(92, 186, 138, 0.12);
  --red-400:   #d97a72;  --red-bg:   rgba(217, 122, 114, 0.12);
  --red-solid: #a8544c;  --red-solid-fg: #ffffff;
  --amber-400: #d4a04a;  --amber-bg: rgba(212, 160, 74, 0.12);
  --blue-400:  #7d9bce;  --blue-bg:  rgba(125, 155, 206, 0.12);
  --violet-400:#9b8bd0;  --violet-bg:rgba(155, 139, 208, 0.12);
  --teal-400:  #5fb3aa;  --teal-bg:  rgba(95, 179, 170, 0.12);
  --pink-400:  #cc88aa;  --pink-bg:  rgba(204, 136, 170, 0.12);

  /* Google brand — dark-theme surface per the same guidelines (see light block). */
  --g-surface:        #131314;
  --g-surface-hover:  #1e1f20;   /* spec: 8% #e3e3e3 state layer over #131314 */
  --g-text:           #e3e3e3;
  --g-border:         #8e918f;
  --g-focus-ring:     rgba(138, 180, 248, 0.35);

  --c-venture:  #7d9bce;
  --c-investor: #5cba8a;
  --c-operator: #9b8bd0;
  --c-chrg:     #d4a04a;

  --shadow-sm: 0 1px 1px rgba(0,0,0,0.3);
  --shadow-md: 0 1px 2px rgba(0,0,0,0.4), 0 1px 3px rgba(0,0,0,0.3);
  --shadow-lg: 0 6px 20px -6px rgba(0,0,0,0.5), 0 2px 8px rgba(0,0,0,0.4);
  --shadow-xl: 0 16px 44px -12px rgba(0,0,0,0.6), 0 6px 16px rgba(0,0,0,0.45);
  --shadow-inset: none;
  /* Dark: the hairline ring is light, not dark. */
  --shadow-card: 0 1px 2px rgba(0,0,0,0.4), 0 2px 6px rgba(0,0,0,0.3), 0 0 0 0.5px rgba(255,255,255,0.06);
  --shadow-elevated: 0 8px 24px -6px rgba(0,0,0,0.55), 0 3px 8px rgba(0,0,0,0.4), 0 0 0 0.5px rgba(255,255,255,0.09);
}

/* ============================================================
   LEGACY ALIASES — keep the 14 existing views rendering.
   Every old gold/ink/glow token maps to a neutral so
   nothing breaks mid-migration. Cleaned per-surface later.
   ============================================================ */
:root, [data-theme] {
  /* ink ramp -> neutral surfaces/borders */
  --ink-900: var(--bg);
  --ink-850: var(--bg);
  --ink-800: var(--bg);
  --ink-750: var(--surface-1);
  --ink-700: var(--surface-1);
  --ink-650: var(--surface-2);
  --ink-600: var(--surface-2);
  --ink-550: var(--border-strong);
  --ink-500: var(--border);
  --ink-450: var(--text-500);

  /* gold ramp -> accent ink */
  --gold-50:  var(--accent-soft);
  --gold-100: var(--accent);
  --gold-200: var(--accent);
  --gold-300: var(--accent);
  --gold-400: var(--accent);
  --gold-500: var(--accent);
  --gold-600: var(--accent);
  --gold-700: var(--accent);
  --gold-glow: var(--accent-soft);
  --text-gold: var(--text-100);

  /* border aliases that referenced gold */
  --border-gold: var(--border-strong);

  /* surface alpha tokens used directly by some views */
  /* (already defined above as solid neutrals) */

  /* shadows that referenced gold -> neutral */
  --shadow-gold: var(--shadow-md);
}

/* ============================================================
   THE TOUCH SCALE LIVES IN assets/css/phone.css.

   There was a duplicate here for a few hours on 2026-09-03: two sessions
   reached for the same lever within an hour of each other, both raising these
   tokens rather than chasing components. It is gone, and this note is what is
   left of it, because "why is there no coarse-pointer block in the tokens file"
   is a reasonable question to ask before writing a third one.

   phone.css is the single statement of the phone scale — control heights, type,
   spacing, sheets, keyboard clearance. It is loaded by index.html for all four
   products and every rule is inside
   `@media (max-width: 900px) and (pointer: coarse)`, so it reaches a phone
   BROWSER as well as the three iOS shells and does not depend on a product
   having armed a bottom bar.

   That last part was the whole argument for merging the two: a scale belongs to
   the POINTER, not to whether a product has a tab bar. Nova Assistant has no
   bottom bar and should not get one — it ships five routes and its chat sidebar
   IS the chrome — so gating the type scale on the bar would have meant arming a
   tab bar on a chat app to inherit a font size.
   ============================================================ */
