/* ============================================================================
   TROXY DESIGN TOKENS
   Single source of truth for every colour, scale and curve in the dashboard.

   Rules of the road:
     - Nothing outside this file declares a colour. Reach for a token, never a
       hex, an rgba() or a bare px value.
     - The scales are deliberately short. Twelve radii and sixteen font sizes is
       what made the UI read as a pile of one-offs instead of one system; if a
       value you want isn't here, the answer is almost always the nearest token,
       not a new one.
     - Both themes define the same token names. A component never branches on
       theme; it asks for --surface and gets the right answer in both.
   ============================================================================ */

:root {
  --bg: #0d1117;
  --surface: #161b22;
  --surface2: #1c2333;
  --border: rgba(255,255,255,0.09);
  --teal: #0a9e88;
  --teal-dim: rgba(10,158,136,0.07);
  --teal-border: rgba(10,158,136,0.14);
  /* Teal for text sitting on the page background. On dark, --teal clears AA on
     its own (5.6:1), so this is just an alias. Light mode needs a darker stop:
     see the html.light override. Fills, borders and dots keep using --teal,
     which is about the brand colour, not about being readable as words. */
  --teal-text: var(--teal);
  --text: #e6edf3;
  /* Was #7d8590: 5.07:1 on the page and 4.64:1 on a card, but 4.21:1 on the
     agent chips inside a recommendation card (--surface2), which is exactly
     where it labels which agent a finding is about. Lightened until it clears
     AA on the lightest surface it actually sits on, not the darkest. */
  --muted: #868e99;
  --muted2: #484f58;
  /* Health, not decision. --green was the same #0a9e88 as --teal, so a "reached"
     checkpoint dot, a connected agent and the brand accent were all one colour
     and the status legend conveyed nothing. ALLOW keeps the teal of its donut
     segment via --action-allow; --green now means only "this is fine". */
  --green: #3fb950;
  --green-bg: rgba(63,185,80,0.10);
  --green-border: rgba(63,185,80,0.20);
  --amber: #d29922;
  --amber-bg: rgba(210,153,34,0.1);
  --amber-border: rgba(210,153,34,0.2);
  --red: #f85149;
  --red-bg: rgba(248,81,73,0.1);
  --red-border: rgba(248,81,73,0.2);
  /* Agent series palette, as TEXT. The fill palette lives in index.html and is
     tuned for bars, dots and chart series on a dark canvas; as small text on
     white those same hues measure 2.4:1 to 3.4:1.

     These are custom properties rather than a JS lookup on purpose. The colour
     is written into an HTML string at render time, so a JS branch on the
     current theme bakes in whichever theme was active when the row was built:
     toggling to dark left agent labels painted #7c5004, a light-mode brown on
     a near-black background, at 2.48:1. A var() re-resolves on toggle with no
     re-render, which is the same reason charts register a redraw. */
  --series-text-0: #0a9e88;
  --series-text-1: #d29922;
  --series-text-2: #6e8fd6;
  --series-text-3: #c76ea8;
  --series-text-4: #5bb974;
  --series-text-5: #d2724a;
  --series-text-6: #8f7fd8;
  --series-text-7: #4aa8c7;
  --sidebar-w: 220px;
  --rail-w: 64px;
  /* Semantic action colors, matched to donut chart palette */
  --action-allow:    #0a9e88;
  --action-allow-bg: rgba(36,158,141,0.13);
  --action-block:    #f85149;
  --action-block-bg: rgba(248,81,73,0.11);
  --action-escalate:    #d29922;
  --action-escalate-bg: rgba(210,153,34,0.12);
  --action-escalate-border: rgba(210,153,34,0.25);
  /* Escalate-amber for TEXT sitting on the page background, same split as
     --teal-text. --action-escalate is unchanged across both themes because it
     is mostly a fill (badges, dots, chart series) where the bright hue is
     correct. As small text on white it measures 2.52:1, well under AA, which
     made "high" severity labels and escalate counts the least readable things
     on the page. See the html.light override. */
  --action-escalate-text: var(--action-escalate);
  --action-notify:    #58a6ff;
  --action-notify-bg: rgba(88,166,255,0.12);
  /* Charge failed is a fifth decision state on the donut. It was living as a
     bare #b05050 in three places with no token behind it. */
  --action-failed:    #b05050;
  --action-failed-bg: rgba(176,80,80,0.12);
  /* The sidebar sits a shade below --surface on purpose. Was a magic #111820. */
  --sidebar-bg: #111820;
  /* Referenced by a var() fallback but never actually declared until now. */
  --surface3: rgba(255,255,255,0.06);
  /* AI accent. One hue for every Claude-powered affordance, kept clear of the
     four action colors so "this was generated" never reads as a decision. */
  --ai:        #a78bfa;
  --ai-bg:     rgba(167,139,250,0.12);
  --ai-border: rgba(167,139,250,0.22);
  /* Control domains. One hue per policy category, kept deliberately desaturated
     so a category chip can never be mistaken for a decision (allow/block/
     escalate/notify own the saturated end of the palette). Six of the nine
     domains had no colour at all and fell through to the base chip style, which
     is why a mixed list read as one undifferentiated colour. Every domain gets
     an entry here so adding a category is a token, not a special case. */
  --dom-payment:     #2dd4bf;
  --dom-comms:       #a78bfa;
  --dom-files:       #60a5fa;
  --dom-data:        #38bdf8;
  --dom-login:       #38bdf8;
  --dom-secrets:     #fbbf24;
  --dom-access:      #f472b6;
  --dom-model:       #818cf8;
  --dom-destructive: #f87171;
  /* Text that sits on a filled accent (teal button, colored badge). Hardcoded
     #fff broke in light mode; this stays white in both themes on purpose. */
  --text-on-accent: #ffffff;
  /* Third-party brand marks. Not ours to restyle, but still not a magic hex
     buried mid-stylesheet. */
  --brand-anthropic: #CC785C;
  /* A stronger hairline than --border, for edges that sit against an image or
     a screenshot rather than a surface. */
  --border-strong: rgba(255,255,255,0.16);
  /* One dimming layer for every overlay. Four different alphas had grown up for
     the same idea, so a drawer and a modal dimmed the page by different amounts. */
  --scrim: rgba(0,0,0,0.5);
  /* Elevation. Static depth only, never animated or blurred (no glow rule).
     These are the dark-theme values; html.light overrides them below. A second
     :root further down the stylesheet used to redefine all three, so the set
     declared up here was dead code and the layered set silently won. They are
     merged here now, which is the whole point of a single token file. */
  --shadow-xs:  0px 1px 2px rgba(0,0,0,0.4);
  --shadow-sm:  0px 1px 6px rgba(0,0,0,0.5);
  --shadow-md:  0px 4px 8px -2px rgba(0,0,0,0.5), 0px 2px 4px -2px rgba(0,0,0,0.4), 0 1px 0 rgba(255,255,255,0.04) inset;
  --shadow-lg:  0px 12px 16px -4px rgba(0,0,0,0.55), 0px 4px 6px -2px rgba(0,0,0,0.45), 0 1px 0 rgba(255,255,255,0.05) inset;

  /* ── SCALES (theme-independent) ───────────────────────────────
     Before this pass the file carried 12 distinct radii and 16 font sizes
     (including 12.5px and 14.5px). These caps are what make the UI read as
     one system instead of a pile of one-offs. Reach for a token, not a number. */
  --r-xs: 8px;
  --r-sm: 14px;
  --r-md: 16px;
  --r-lg: 20px;
  --r-xl: 24px;
  --r-full: 999px;

  --fs-2xs:  10px;
  --fs-xs:   11px;
  --fs-sm:   12px;
  --fs-base: 13px;
  --fs-md:   14px;
  --fs-lg:   16px;
  --fs-xl:   20px;
  --fs-2xl:  26px;
  --fs-3xl:  36px;

  /* Typography. Three faces, each with one job, so a component never picks a
     family — it picks a role. Instrument Serif is page titles only; using it
     anywhere else is what makes a serif look like a mistake rather than a
     decision. Numbers everywhere use tabular figures so columns line up and a
     counting animation doesn't make the row jitter. */
  --font-body:    'Wix Madefor Text', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-display: 'Instrument Serif', Georgia, 'Times New Roman', serif;
  --font-mono:    'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  --weight-normal:   400;
  --weight-medium:   500;
  --weight-semibold: 600;
  --weight-bold:     700;

  --leading-tight:   1.2;
  --leading-normal:  1.5;
  --leading-relaxed: 1.7;

  --tracking-tight: -0.02em;
  --tracking-wide:   0.05em;

  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;
  --sp-8: 32px;
  --sp-10: 40px;
  --sp-12: 48px;

  /* Control heights. One height for every primary control, one for every
     secondary control, so a row of inputs reads as a line, not a skyline. */
  --control-h: 42px;
  --control-h-sm: 32px;

  /* Motion. One decelerating curve for everything that moves, so the whole app
     feels like it shares a physics. Default `ease` is the main reason UI reads
     cheap. Durations are capped at three so nothing feels out of step. */
  --ease: cubic-bezier(0.32, 0.72, 0, 1);
  --dur-fast: 120ms;
  --dur-base: 180ms;
  --dur-slow: 280ms;
}
html.light {
  --bg: #ffffff;
  --surface: #ffffff;
  --surface2: #f4f6f9;
  --border: rgba(60,66,87,0.12);
  --teal: #0a9e88;
  --teal-dim: rgba(10,158,136,0.07);
  --teal-border: rgba(10,158,136,0.2);
  /* #0a9e88 on white is 3.36:1, under the 4.5:1 AA floor for body text. This
     darker stop clears it while staying the same hue. */
  --teal-text: #05756a;
  --text: #1a1f36;
  /* Was #697386, which is 4.78:1 on the page background but only 4.41:1 on a
     card, just under AA. Small muted labels inside cards are most of the
     secondary text in the product, so it failed in the places it is used most.
     Six units darker clears 4.81:1 on a card and 5.21:1 on the page. */
  --muted: #636d80;
  --muted2: #c0c8d5;
  --green: #1a7f37;
  --green-bg: rgba(26,127,55,0.07);
  --green-border: rgba(26,127,55,0.2);
  --amber: #7c5004;
  --amber-bg: rgba(124,80,4,0.07);
  --amber-border: rgba(124,80,4,0.18);
  --red: #b52b2b;
  --red-bg: rgba(181,43,43,0.06);
  --red-border: rgba(181,43,43,0.16);
  /* Light-mode action colors, matched to donut chart palette */
  --action-allow:    #0a9e88;
  --action-allow-bg: rgba(10,158,136,0.08);
  --action-block:    #f85149;
  --action-block-bg: rgba(248,81,73,0.07);
  --action-escalate:    #d29922;
  --action-escalate-bg: rgba(210,153,34,0.08);
  --action-escalate-border: rgba(210,153,34,0.20);
  /* 5.92:1 on white, 5.47:1 on a card. Same hue, enough of it to read. */
  --action-escalate-text: #8a5a06;
  /* Each darkened until it clears 4.5:1 on both the page and a card. */
  --series-text-0: #05756a;
  --series-text-1: #7c5004;
  --series-text-2: #3a5fa8;
  --series-text-3: #a03d7d;
  --series-text-4: #2f7a45;
  --series-text-5: #a1461f;
  --series-text-6: #5f4fb0;
  --series-text-7: #226f88;
  --action-notify:    #58a6ff;
  --action-notify-bg: rgba(88,166,255,0.08);
  --action-failed:    #b05050;
  --action-failed-bg: rgba(176,80,80,0.08);
  --sidebar-bg: #ffffff;
  --surface3: rgba(60,66,87,0.06);
  /* Deeper purple on white so the AI accent keeps its contrast ratio. */
  --ai:        #7c3aed;
  --ai-bg:     rgba(124,58,237,0.07);
  --ai-border: rgba(124,58,237,0.18);
  /* Same nine hues, darkened for contrast on white. The mapping is identical in
     both themes on purpose: a category must not change colour with the theme. */
  --dom-payment:     #0d9488;
  --dom-comms:       #7c3aed;
  --dom-files:       #2563eb;
  --dom-data:        #0284c7;
  --dom-login:       #0284c7;
  --dom-secrets:     #b45309;
  --dom-access:      #be185d;
  --dom-model:       #4f46e5;
  --dom-destructive: #dc2626;
  --text-on-accent: #ffffff;
  --border-strong: rgba(0,0,0,0.16);
  --scrim: rgba(15,23,42,0.35);
  /* Light-mode elevation: layered and barely-there. A card must read as lifted
     without a grey smudge under it. */
  --shadow-xs:  0px 1px 2px rgba(0,0,0,0.08);
  --shadow-sm:  0px 1px 6px rgba(0,0,0,0.10);
  --shadow-md:  0px 4px 8px -2px rgba(0,0,0,0.12), 0px 2px 4px -2px rgba(0,0,0,0.08);
  --shadow-lg:  0px 12px 16px -4px rgba(0,0,0,0.14), 0px 4px 6px -2px rgba(0,0,0,0.08);
}
