/* VENDORED from the Jagga product repo -- do not edit.
 *
 * source:  design/themes/ethereal/tokens.css
 * pack:    ethereal   (design/themes/active.json)
 * sha256:  20c09cf80f8238f4211359cc63bdc3b1a7487393fcfce17d918f817f31d0b77a
 * copied:  2026-09-08
 *
 * This file is a COPY, and a copy nobody checks goes stale. Verify with
 *   python3 tools/vendor_theme.py --check
 * and refresh with the same command minus --check.
 *
 * Rule for every other stylesheet here: name a ROLE (--bg-surface,
 * --text-primary, --accent), never a primitive (--surface-container-high,
 * --primary) and never a literal colour. tools/check.py enforces it.
 */

/* ============================================================
   ETHEREAL — TOKENS
   "Ethereal Analytics Light" + "GEOINT Command Nocturnal" (dark)
   Source: claude.ai/design · Jagga Design System
           db109a7e-eef6-476a-a998-407df6185cc0

   Same two layers as every pack:
     1. PRIMITIVES — the source palette, Material 3 names, verbatim
     2. ROLES      — the contract in design/themes/ROLE-CONTRACT.md

   Ethereal is a tonal-surface system: depth comes from stacked blue-tinted
   surface containers and a soft violet-tinted ambient shadow, not from hard
   borders. Where Graphite reaches for a rule, this reaches for a tint.

   Re-derived in Ethereal's own idiom rather than transposed from Graphite:
   the shadow ramp is violet-ambient, radii are the source's 4/8/12 ladder,
   spacing follows the source's 8px rhythm, and headline tracking is negative.
   What is NOT re-derived is the DERIVATION STYLE — the accent identity is
   still computed off --accent with color-mix(in srgb, …), because whitelabel
   tenant accents and scripts/check-contrast.mjs both depend on that shape.
   ============================================================ */

:root {
  /* ===========================================================
     1 · PRIMITIVES — Material 3 roles, verbatim from the source kit.
     Pack-private: nothing outside this file may reference them.
     =========================================================== */

  /* Surfaces (tonal layers, lightest to deepest) */
  --background:                #f8f9ff;
  --surface:                   #f8f9ff;
  --surface-container-lowest:  #ffffff;
  --surface-container-low:     #eff4ff;
  --surface-container:         #e5eeff;
  --surface-container-high:    #dce9ff;
  --surface-container-highest: #d3e4fe;
  --surface-variant:           #d3e4fe;
  --surface-dim:               #cbdbf5;
  --inverse-surface:           #213145;
  --inverse-on-surface:        #eaf1ff;

  /* Ink */
  --on-surface:         #0b1c30;
  --on-surface-variant: #4a4455;

  /* Outlines */
  --outline:         #7b7487;
  --outline-variant: #ccc3d8;

  /* Primary (violet) */
  --primary:                    #630ed4;
  --on-primary:                 #ffffff;
  --primary-container:          #7c3aed;
  --surface-tint:               #732ee4;
  --primary-fixed:              #eaddff;
  --primary-fixed-dim:          #d2bbff;
  --on-primary-fixed-variant:   #5a00c6;
  --inverse-primary:            #842bd2;

  /* Tertiary (cyan) */
  --tertiary:            #00566b;
  --tertiary-container:  #00708a;
  --tertiary-fixed:      #b7eaff;
  --tertiary-fixed-dim:  #6cd3f7;

  /* Error */
  --error:               #ba1a1a;
  --error-container:     #ffdad6;
  --on-error-container:  #93000a;

  /* EXTENSION — success and warning. Material 3 ships primary/secondary/
     tertiary/error and nothing else, and Ethereal's own status language is
     Optimal / Maintenance / Critical mapped to violet / cyan / red
     (guidelines/color-status.card.html). Jagga needs green and amber for
     workflow states and finance, so these two ramps are a DELIBERATE
     ADDITION — recorded under `extensions` in theme.json, not a silent
     invention. Hues are pulled toward the kit's cool cast (the green sits
     next to the cyan tertiary rather than reading as a stock #16a34a) and
     every pair clears 4.5:1; check-contrast.mjs is the arbiter. */
  --success:            #0d6b4a;
  --success-container:  #c9f0dd;
  --on-success-container: #054a32;
  --success-dim:        #56d7a4;

  --warning:            #8a5a00;
  --warning-container:  #ffe8c2;
  --on-warning-container: #6b4400;
  --warning-dim:        #f2c46b;

  /* Dark-surface primitives — "GEOINT Command Nocturnal" */
  --d-background:                #0b1326;
  --d-surface-container-lowest:  #060e20;
  --d-surface-container-low:     #131b2e;
  --d-surface-container:         #171f33;
  --d-surface-container-high:    #222a3d;
  --d-surface-container-highest: #2d3449;
  --d-surface-bright:            #31394d;
  --d-inverse-surface:           #dae2fd;
  --d-inverse-on-surface:        #283044;
  --d-on-surface:         #dae2fd;
  --d-on-surface-variant: #cfc2d6;
  --d-outline:            #988d9f;
  --d-outline-variant:    #4d4354;
  --d-primary:            #ddb7ff;
  --d-secondary:          #c4c1fb;
  --d-secondary-container:#444173;
  --d-tertiary:           #2fd9f4;
  --d-error:              #ffb4ab;

  --white: #ffffff;

  /* ===========================================================
     2 · ROLES — LIGHT (default)
     =========================================================== */

  /* Depth is tonal: each step up the container ladder, not a shadow + rule. */
  --bg-app:        var(--background);
  --bg-surface:    var(--surface-container-lowest);
  --bg-raised:     var(--surface-container-low);
  --bg-sunken:     var(--surface-container);
  --bg-well:       var(--surface-container-highest);
  --bg-inverse:    var(--inverse-surface);
  --bg-shell:      var(--surface-container-low);
  /* Overlay ink. Dark in BOTH themes by construction — a scrim that flipped
     would stop reading as "behind". Built from the inverse surface so it
     carries the kit's navy cast rather than neutral black. */
  --scrim:         color-mix(in srgb, var(--inverse-surface) 55%, transparent);
  /* Light theme carries depth in the tonal ladder, so no top-light needed. */
  --surface-lift:  none;
  --field-bg:      var(--surface-container-lowest);
  --row-hover:     var(--surface-container-low);
  /* Glassmorphism is load-bearing here: the sticky header composites over
     scrolling content, so the alpha and --blur-glass work as a pair. */
  --topbar-bg:     rgba(248, 249, 255, 0.7);

  --border:        var(--outline-variant);
  /* --outline is the source's own interactive boundary and clears 3:1 on all
     four light surfaces — asserted by check-contrast.mjs. */
  --border-strong: var(--outline);

  --text-primary:   var(--on-surface);
  --text-secondary: var(--on-surface-variant);
  /* No M3 role sits between on-surface-variant and outline, so tertiary is
     derived: the supporting ink lightened toward the page. Decorative /
     large-only, and the gate warns rather than fails below 4.5:1. */
  --text-tertiary:  color-mix(in srgb, var(--on-surface-variant) 84%, var(--background));
  --text-inverse:   var(--inverse-on-surface);
  --text-link:      var(--primary);

  --accent:        var(--primary);
  --accent-hover:  var(--surface-tint);

  /* Accent-derived identity — the same color-mix shape Graphite uses, and for
     the same two reasons: a tenant overrides --accent and the whole identity
     recolors (apps/api/src/tenants/wcag.util.ts gates the override), and
     check-contrast.mjs resolves these exactly as a browser does. Hardcoding
     any of them passes the build and quietly breaks whitelabel. */
  --accent-deep:   color-mix(in srgb, var(--accent) 72%, var(--on-surface) 28%);
  --accent-glow:   color-mix(in srgb, var(--accent) 32%, transparent);
  --grad-accent:   linear-gradient(135deg, var(--accent) 0%, var(--accent-deep) 100%);
  --grad-hero:     linear-gradient(150deg, var(--accent-deep) 0%, var(--inverse-surface) 100%);
  --grad-surface:  linear-gradient(180deg, color-mix(in srgb, var(--accent) 5%, var(--bg-surface)) 0%, var(--bg-surface) 60%);
  --grad-stat:     linear-gradient(150deg, var(--accent-deep) 0%, color-mix(in srgb, var(--accent) 52%, var(--inverse-surface) 48%) 96%);
  --on-accent-muted: color-mix(in srgb, var(--white) 85%, var(--accent) 15%);
  --on-hero-strong: rgba(255, 255, 255, 0.92);
  --on-hero-muted:  rgba(255, 255, 255, 0.82);
  --on-hero-faint:  rgba(255, 255, 255, 0.18);

  /* Focus. --focus-ring is the solid band that carries the 3:1 on its own;
     --focus-halo is decorative. Components reference only --focus-shadow. */
  --focus-ring:    var(--accent);
  --focus-halo:    color-mix(in srgb, var(--focus-ring) 30%, transparent);
  --focus-shadow:  0 0 0 2px var(--focus-ring), 0 0 0 6px var(--focus-halo);

  --avatar-bg:     var(--on-primary-fixed-variant);

  /* Soft (tinted) status pairs. Ethereal's status language is Optimal /
     Maintenance / Critical = violet / cyan / red, so `blue` maps to the violet
     primary (the informational/in-progress tone) rather than being invented. */
  --soft-primary-bg:  var(--primary-fixed);      --soft-primary-fg:  var(--on-primary-fixed-variant);
  --soft-tertiary-bg: var(--tertiary-fixed);     --soft-tertiary-fg: var(--tertiary);
  --soft-success-bg:  var(--success-container);  --soft-success-fg:  var(--on-success-container);
  --soft-warning-bg:  var(--warning-container);  --soft-warning-fg:  var(--on-warning-container);
  --soft-error-bg:    var(--error-container);    --soft-error-fg:    var(--on-error-container);
  --soft-neutral-bg:  var(--surface-container);  --soft-neutral-fg:  var(--on-surface-variant);

  /* Solid (saturated) status tones — the filled counterpart. --solid-primary is
     the violet status tone, deliberately distinct from --accent: a whitelabel
     repaint must recolour the primary button and must not recolour a status
     dot. They coincide by value here; both are still declared. */
  --solid-primary: var(--primary);  --solid-tertiary: var(--tertiary);
  --solid-success: var(--success);  --solid-warning:  var(--warning);
  --solid-error:   var(--error);    --solid-neutral:  var(--outline);
  --on-solid:      var(--white);

  /* Identity tints — the five-step ramp a surface cycles when it has to give a
     CATEGORY its own colour and then put text on it: avatar initials, owner
     discs, per-type marks. Distinct from --solid-* by construction: those three
     of six are fills only (check-contrast asserts --on-solid on primary,
     success and error, deliberately not on warning, tertiary or neutral), so a
     text-bearing tint had nowhere in the contract to live and one shipped as
     frozen Graphite hexes with unverified white initials (jagga-a719).

     Every step carries --on-tint at 4.5:1 — asserted, all five, in both themes.
     Theme-stable on purpose, like the service tints: a category mark that
     changed colour on a theme flip would stop being the same mark. */
  --tint-1: var(--primary);          /* violet  8.25:1 */
  --tint-2: var(--tertiary-container); /* cyan   5.70:1 */
  --tint-3: var(--warning);          /* amber   5.93:1 */
  --tint-4: var(--success);          /* green   6.52:1 */
  --tint-5: var(--inverse-surface);  /* navy   13.21:1 */
  --on-tint: var(--white);

  /* ---------- Typography ---------- */
  /* Ethereal ships ONE typeface, Plus Jakarta Sans, for both display and body
     — the display/sans distinction is carried by weight and tracking, not by a
     second family. It specifies no monospace at all; JetBrains Mono is a pack
     decision (recorded in theme.json) chosen for its geometric, near-circular
     bowls, which sit with Jakarta's construction. */
  --font-display: "Plus Jakarta Sans", ui-sans-serif, system-ui, sans-serif;
  --font-sans: "Plus Jakarta Sans", ui-sans-serif, system-ui, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, monospace;

  /* Source steps: headline-xl 48 / lg 32 (24 mobile) / md 24, body-lg 18,
     body-md 16, label-md 14, label-sm 12. display and h1 are made fluid so
     hero type reflows at 320px; the lg mobile step (24) is the clamp floor.
     h3 has no source step and is derived to sit between h2 and body-lg. */
  --fs-display: clamp(32px, 3vw + 22px, 48px); --fs-h1: clamp(24px, 1.4vw + 20px, 32px);
  --fs-h2: 24px; --fs-h3: 20px;
  --fs-body-lg: 18px; --fs-body: 16px; --fs-sm: 14px; --fs-xs: 12px; --fs-mono: 13px;
  --fw-regular: 400; --fw-medium: 500; --fw-semibold: 600; --fw-bold: 700; --fw-extra: 800;
  --lh-tight: 1.2; --lh-snug: 1.25; --lh-normal: 1.5; --lh-relaxed: 1.6;
  --ls-display: -0.02em; --ls-tight: -0.01em;

  /* ---------- Spacing (8px rhythm) ---------- */
  /* The source names six steps (xs 4 · base 8 · sm 12 · md 24 · lg 48 ·
     xl 80); the ladder below fills the gaps on the same rhythm. Thirteen
     steps, as the contract requires — a pack retunes values, never the count. */
  --sp-0: 0; --sp-1: 2px; --sp-2: 4px; --sp-3: 8px; --sp-4: 12px; --sp-5: 16px;
  --sp-6: 24px; --sp-7: 32px; --sp-8: 40px; --sp-9: 48px; --sp-10: 64px; --sp-11: 80px; --sp-12: 96px;

  /* ---------- Radius ---------- */
  /* Source ladder: 4 tags/cells · 8 buttons/inputs/nav · 12 cards · full.
     xs/md/lg land on those three; sm/xl/2xl fill the contract's seven steps.
     The RN port runs sm/md/lg one step rounder for touch (ROLE-CONTRACT
     § Radius) — it inherits that adaptation automatically. */
  --r-xs: 4px; --r-sm: 6px; --r-md: 8px; --r-lg: 12px; --r-xl: 16px; --r-2xl: 20px; --r-full: 9999px;

  /* ---------- Elevation ---------- */
  /* The signature move: a wide, soft, VIOLET-tinted ambient shadow rather than
     a neutral drop — 0 8px 30px rgba(124,58,237,0.08) is the card shadow the
     source names. xs/sm stay neutral navy (they read as hairlines at that
     size); md upward carry the violet cast, paired with a tight key layer for
     direction. */
  --shadow-xs: 0 1px 2px rgba(11, 28, 48, 0.06);
  --shadow-sm: 0 1px 2px rgba(11, 28, 48, 0.06), 0 1px 1px rgba(11, 28, 48, 0.04);
  --shadow-md: 0 2px 6px -2px rgba(11, 28, 48, 0.06), 0 8px 30px rgba(124, 58, 237, 0.08);
  --shadow-lg: 0 6px 14px -8px rgba(11, 28, 48, 0.10), 0 12px 40px rgba(124, 58, 237, 0.12);
  --shadow-xl: 0 12px 28px -12px rgba(11, 28, 48, 0.14), 0 24px 64px rgba(124, 58, 237, 0.18);
  --shadow-accent: 0 2px 8px -2px color-mix(in srgb, var(--accent) 20%, transparent),
                   0 8px 24px -8px var(--accent-glow);
  --ring-hairline: 0 0 0 1px var(--border);
  /* Glass is a real surface treatment here, not a flourish — --topbar-bg's
     alpha is tuned against this blur. */
  --blur-glass: 12px;

  /* ---------- Motion ---------- */
  /* NOT specified by the source kit (recorded in theme.json under knownGaps).
     Carried over unchanged so motion.ts's presets and theme.parity.test.ts
     keep their meaning across the swap — a design that wants different timing
     should state it, and until then changing it would be invention. */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --dur-fast: 120ms; --dur-base: 200ms; --dur-slow: 320ms; --dur-slower: 480ms;
  --stagger: 40ms;

  /* ---------- Texture ---------- */
  /* Ethereal's surface language is glass and tonal wash, not grain. The
     contract allows a pack to opt out; mobile's pre-rendered noise.png is the
     port of Graphite's grain and is unused under this pack. */
  --texture-noise: none;

  /* ---------- Layout ---------- */
  --container: 1200px; --grid-cols: 12; --grid-gutter: 24px;
}

/* ===========================================================
   2 · ROLES — DARK  ("GEOINT Command Nocturnal")
   =========================================================== */
[data-theme="dark"] {
  --bg-app:        var(--d-background);
  --bg-surface:    var(--d-surface-container-low);
  --bg-raised:     var(--d-surface-container-high);
  --bg-sunken:     var(--d-surface-container-lowest);
  /* Deepest inset — below the lowest container, so it is derived rather than
     named by the source. */
  --bg-well:       color-mix(in srgb, var(--d-surface-container-lowest) 72%, #000000);
  --bg-inverse:    var(--d-inverse-surface);
  --bg-shell:      var(--d-surface-container);
  /* Faint top-light so raised cards separate without a border, the way the
     tonal ladder does that job in light. */
  --surface-lift:  linear-gradient(180deg, rgba(255, 255, 255, 0.045) 0%, rgba(255, 255, 255, 0) 120px);
  --field-bg:      var(--d-surface-container-lowest);
  --row-hover:     rgba(221, 183, 255, 0.10);
  --topbar-bg:     rgba(23, 31, 51, 0.7);

  --border:        var(--d-outline-variant);
  --border-strong: var(--d-outline);

  --text-primary:   var(--d-on-surface);
  --text-secondary: var(--d-on-surface-variant);
  --text-tertiary:  color-mix(in srgb, var(--d-on-surface-variant) 74%, var(--d-background));
  --text-inverse:   var(--d-inverse-on-surface);
  /* The lavender the source uses as its dark primary. It is far too light to
     carry white text, so it serves as link/soft ink here while --accent stays
     the violet fill that --on-solid sits on in both themes. */
  --text-link:      var(--d-primary);

  /* Raw --accent is too dark against the navy surfaces to clear 3:1 as a focus
     indicator, so the ring is a lightened accent mix — still derived, so a
     tenant override recolors it. */
  --focus-ring:    color-mix(in srgb, var(--accent) 55%, var(--d-primary) 45%);

  --avatar-bg:      var(--d-secondary-container);

  --soft-primary-bg:  rgba(221, 183, 255, 0.18); --soft-primary-fg:  var(--d-primary);
  --soft-tertiary-bg: rgba(47, 217, 244, 0.16);  --soft-tertiary-fg: var(--d-tertiary);
  --soft-success-bg:  rgba(13, 107, 74, 0.28);   --soft-success-fg:  var(--success-dim);
  --soft-warning-bg:  rgba(138, 90, 0, 0.28);    --soft-warning-fg:  var(--warning-dim);
  --soft-error-bg:    rgba(186, 26, 26, 0.26);   --soft-error-fg:    var(--d-error);
  --soft-neutral-bg:  rgba(218, 226, 253, 0.08); --soft-neutral-fg:  #b9c2dd;

  /* Light-theme shadows are invisible on dark surfaces; the violet cast is
     kept in the ambient layer so the identity survives the flip. */
  --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.40);
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.45), 0 1px 1px rgba(0, 0, 0, 0.30);
  --shadow-md: 0 2px 6px -2px rgba(0, 0, 0, 0.45), 0 8px 30px rgba(99, 14, 212, 0.22);
  --shadow-lg: 0 6px 14px -8px rgba(0, 0, 0, 0.50), 0 12px 40px rgba(99, 14, 212, 0.28);
  --shadow-xl: 0 12px 28px -12px rgba(0, 0, 0, 0.60), 0 24px 64px rgba(99, 14, 212, 0.34);
}
