/* ============================================================
   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. */

  /* ---- 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;

  /* ---- 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;
}

/* ============================================================
   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);
}
