/* ============================================================================
   Scalp Engine — "Deep Signal" design system
   One import, every page. Tokens, primitives, and the motion library.

   THEMES.  Every colour in the app resolves through a token defined in the
   :root / [data-theme="..."] blocks below and NOWHERE else.  A raw hex or
   rgba() literal outside those blocks is a bug: it would survive a theme
   switch and leave a stray accent behind.  The gate is

       grep -oE "#[0-9a-fA-F]{3,8}|rgba?\(" static/css/*.css

   -- every match must sit inside a :root or [data-theme] block.

   Three themes ship: emerald (default), slate, amber.  Each is a dark ground
   plus a two-stop brand gradient; the semantic long/short/hold trio is tuned
   per theme so it never collides with the brand.  Every ink step clears WCAG
   AA against the surfaces it actually lands on (4.5:1 body, 3:1 large/UI).

   Motion rule: animate transform/opacity only; everything respects
   prefers-reduced-motion at the bottom of this file.
   ========================================================================= */

/* ============================================================================
   THEME 1 — EMERALD (default)
   Dark green ground, emerald -> teal brand gradient.
   ========================================================================= */
:root,
[data-theme="emerald"]{
  color-scheme:dark;

  /* ground */
  --void:#0a0e0c;
  --deep:#0e1412;
  --slab:#131b18;
  --slab-2:#182220;

  /* brand — cooler than --long on purpose: emerald into teal, so a brand
     surface never reads as a BUY card. */
  --beam:#10b981;
  --beam-mid:#14b8a6;
  --beam-2:#2dd4bf;

  /* semantic — --long is the brighter, more yellow-green of the two greens */
  --long:#4ade80;
  --short:#fb7185;
  --hold:#fbbf24;

  /* ink ramp.  Tuned so --ink-3 clears 4.5:1 (AA body) and --ink-4 clears
     3:1 (AA large/UI) on every surface they actually land on, glass cards
     included.  Nudging these two is a legibility fix, not a palette change. */
  --ink:#dfe7e3;
  --ink-2:#9aaaa3;
  --ink-3:#83938c;
  --ink-4:#67756f;

  /* ink that sits ON a filled brand / long / short surface */
  --on-beam:#04140e;
  --on-long:#04160c;
  --on-short:#20060f;
}

/* ============================================================================
   THEME 2 — SLATE
   Neutral blue-grey. The lowest-saturation, most sober of the three.
   ========================================================================= */
[data-theme="slate"]{
  color-scheme:dark;

  --void:#0d1117;
  --deep:#111820;
  --slab:#161e28;
  --slab-2:#1b2531;

  --beam:#3b82f6;
  --beam-mid:#0ea5e9;
  --beam-2:#38bdf8;

  --long:#4ade80;
  --short:#f87171;
  --hold:#fbbf24;

  --ink:#e2e8f0;
  --ink-2:#9aa7b8;
  --ink-3:#8893a3;
  --ink-4:#6b7586;

  --on-beam:#05101c;
  --on-long:#04160c;
  --on-short:#1d0808;
}

/* ============================================================================
   THEME 3 — AMBER
   Warm ground, amber brand. The easiest of the three at night.
   ========================================================================= */
[data-theme="amber"]{
  color-scheme:dark;

  --void:#0f0d0a;
  --deep:#14110d;
  --slab:#1a1611;
  --slab-2:#221d16;

  --beam:#f59e0b;
  --beam-mid:#f8b21a;
  --beam-2:#fbbf24;

  --long:#86efac;
  --short:#fb7185;
  --hold:#fcd34d;

  --ink:#ece5db;
  --ink-2:#b0a596;
  --ink-3:#988f83;
  --ink-4:#7b7266;

  --on-beam:#1a1004;
  --on-long:#05170d;
  --on-short:#20060f;
}

/* ============================================================================
   DERIVED TOKENS — one definition, every theme.
   Everything below is a function of the base hues above, so a theme only ever
   restates the ~16 literals it owns.  color-mix keeps the alpha variants
   honest instead of hand-rolling a dozen rgba() triples per theme and
   re-deriving them by hand every time a hue moves.
   ========================================================================= */
:root{
  /* ---- neutral films: lift a surface off the ground ---- */
  --glass:rgba(255,255,255,.028);
  --glass-2:rgba(255,255,255,.048);
  --glass-3:rgba(255,255,255,.085);
  --film:rgba(255,255,255,.02);
  --edge:rgba(255,255,255,.08);
  --edge-2:rgba(255,255,255,.15);
  --edge-3:rgba(255,255,255,.23);
  --edge-soft:rgba(255,255,255,.05);
  --row-hover:rgba(255,255,255,.035);
  --sheen:rgba(255,255,255,.42);
  --scan-line:rgba(255,255,255,.055);
  --mark-glow:rgba(255,255,255,.5);
  --skel-a:rgba(255,255,255,.045);
  --skel-b:rgba(255,255,255,.1);
  --rail-track:rgba(255,255,255,.07);
  --ring-track:rgba(255,255,255,.09);
  --spin-track:rgba(255,255,255,.26);
  --track-mid:rgba(255,255,255,.06);
  --grid-line:rgba(255,255,255,.013);

  /* ---- wells: darken a patch of a card for inputs and readouts ---- */
  --well:rgba(0,0,0,.24);
  --well-2:rgba(0,0,0,.28);
  --well-3:rgba(0,0,0,.36);
  --well-4:rgba(0,0,0,.5);

  /* ---- cast shadows ---- */
  --cast:rgba(0,0,0,.5);
  --cast-2:rgba(0,0,0,.6);
  --cast-3:rgba(0,0,0,.75);
  --scrim:rgba(0,0,0,.74);
  --shadow:0 1px 2px var(--cast),0 12px 40px -12px var(--cast-2);
  --shadow-lift:0 2px 6px var(--cast),0 24px 70px -20px var(--cast-3);

  /* ---- translucent grounds (sticky bars, toasts, hero fade) ---- */
  --veil:color-mix(in srgb,var(--void) 74%,transparent);
  --veil-2:color-mix(in srgb,var(--void) 55%,transparent);
  --toast-bg:color-mix(in srgb,var(--slab) 94%,transparent);

  /* ---- semantic tints ---- */
  --long-dim:color-mix(in srgb,var(--long) 13%,transparent);
  --long-wash:color-mix(in srgb,var(--long) 4%,transparent);
  --long-edge:color-mix(in srgb,var(--long) 42%,transparent);
  --long-edge-soft:color-mix(in srgb,var(--long) 32%,transparent);
  --long-edge-strong:color-mix(in srgb,var(--long) 50%,transparent);
  --long-glow:color-mix(in srgb,var(--long) 34%,transparent);
  --long-beacon:color-mix(in srgb,var(--long) 55%,transparent);
  --long-sweep:color-mix(in srgb,var(--long) 50%,transparent);

  --short-dim:color-mix(in srgb,var(--short) 13%,transparent);
  --short-wash:color-mix(in srgb,var(--short) 4%,transparent);
  --short-edge:color-mix(in srgb,var(--short) 42%,transparent);
  --short-edge-soft:color-mix(in srgb,var(--short) 32%,transparent);
  --short-edge-strong:color-mix(in srgb,var(--short) 50%,transparent);
  --short-edge-faint:color-mix(in srgb,var(--short) 16%,transparent);
  --short-glow:color-mix(in srgb,var(--short) 34%,transparent);
  --short-beacon:color-mix(in srgb,var(--short) 55%,transparent);

  --hold-dim:color-mix(in srgb,var(--hold) 13%,transparent);
  --hold-edge:color-mix(in srgb,var(--hold) 42%,transparent);
  --hold-beacon:color-mix(in srgb,var(--hold) 55%,transparent);

  /* ---- brand tints ---- */
  --beam-dim:color-mix(in srgb,var(--beam) 14%,transparent);
  --beam-edge:color-mix(in srgb,var(--beam) 32%,transparent);
  --beam-edge-2:color-mix(in srgb,var(--beam) 50%,transparent);
  --beam-cast:color-mix(in srgb,var(--beam) 62%,transparent);
  --beam-cast-2:color-mix(in srgb,var(--beam) 88%,transparent);
  --beam-2-dim:color-mix(in srgb,var(--beam-2) 10%,transparent);
  --beam-2-edge:color-mix(in srgb,var(--beam-2) 42%,transparent);
  --select:color-mix(in srgb,var(--beam) 34%,transparent);

  /* ---- gradients ---- */
  /* The mid stop sits early so the brand reads TEAL across most of its
     length. --long is a brighter, yellower green; keeping the brand cool
     is what stops a primary button reading as a BUY card. */
  --sweep:linear-gradient(115deg,var(--beam) 0%,var(--beam-mid) 26%,var(--beam-2) 100%);
  --sweep-long:linear-gradient(115deg,var(--long) 0%,var(--beam-2) 100%);
  --lit-line:linear-gradient(90deg,transparent,
              color-mix(in srgb,var(--beam) 85%,transparent),
              color-mix(in srgb,var(--beam-2) 85%,transparent),transparent);
  --sheen-sweep:linear-gradient(110deg,transparent 25%,var(--sheen) 50%,transparent 75%);
  /* The blobs are a DEEP tint of the brand, not the brand itself: a vivid
     short-wavelength field drifting in the periphery is the single biggest
     contributor to the fatigue this palette exists to fix, and at full
     chroma the blob core lifts the ground enough to push --ink-3 under
     4.5:1 on the cards that float over it. */
  --aurora-a:radial-gradient(circle,color-mix(in srgb,var(--beam) 26%,var(--void)) 0%,transparent 68%);
  --aurora-b:radial-gradient(circle,color-mix(in srgb,var(--beam-2) 26%,var(--void)) 0%,transparent 68%);
  --skel-sweep:linear-gradient(90deg,var(--skel-a) 25%,var(--skel-b) 50%,var(--skel-a) 75%);

  /* ---- theme-picker swatches: each has to show its OWN palette whatever is
     active, so these three literals genuinely belong here. brand -> ground. */
  --sw-emerald:linear-gradient(135deg,#10b981 0 50%,#0a0e0c 50% 100%);
  --sw-slate:linear-gradient(135deg,#3b82f6 0 50%,#0d1117 50% 100%);
  --sw-amber:linear-gradient(135deg,#f59e0b 0 50%,#0f0d0a 50% 100%);

  /* ---- type ----
     No CDN and no bundled webfont, so these are the best faces actually
     present on Windows 11 with a system-ui ladder behind them.  Segoe UI
     Variable ships Text (small optical size, looser spacing) and Display
     (tight, for headline sizes) as separate families. */
  /* Bahnschrift is a DIN-derived technical face — instrument-panel lineage,
     lining digits, slightly narrow, which suits dense tabular data. It ships
     with Windows 10+. The fallbacks keep the page sane elsewhere. */
  --sans:"Bahnschrift","DIN Next","Segoe UI Variable Text","Segoe UI",system-ui,-apple-system,Roboto,sans-serif;
  --display:"Bahnschrift","DIN Next","Segoe UI Variable Display","Segoe UI",system-ui,sans-serif;
  --mono:"Cascadia Code","Cascadia Mono",ui-monospace,Consolas,"SF Mono",monospace;

  /* opaque stop for mask gradients — a mask reads alpha, not hue, but the
     literal still has to live inside :root */
  --mask:#000;

  --r-xs:6px; --r-sm:10px; --r:14px; --r-lg:20px; --r-xl:28px; --r-pill:999px;
  --maxw:1220px;
  --nav-h:64px;

  --ease:cubic-bezier(.22,1,.36,1);
  --ease-in-out:cubic-bezier(.65,0,.35,1);
}

*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{
  background:var(--void);color:var(--ink);
  font:15px/1.6 var(--sans);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overflow-x:hidden;
  min-height:100vh;
}
a{color:inherit;text-decoration:none}
button,input,select,textarea{font:inherit;color:inherit}
button{background:none;border:none;cursor:pointer}
img,svg,canvas{display:block;max-width:100%}
::selection{background:var(--select)}
:focus-visible{outline:2px solid var(--beam-2);outline-offset:3px;border-radius:4px}

/* screen-reader-only text (live regions, labels). Defined here so every page
   has it, auth.html included. */
.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;
}

/* The brand mark is inline SVG carrying a hardcoded gradient in the markup.
   A CSS declaration beats a presentation attribute, so the mark follows the
   theme without the markup having to change. */
.mark-glyph linearGradient stop,
.mark-ring linearGradient stop,
.brand-mark linearGradient stop{stop-color:var(--beam)}
.mark-glyph linearGradient stop+stop,
.mark-ring linearGradient stop+stop,
.brand-mark linearGradient stop+stop{stop-color:var(--beam-2)}
.mark-glyph svg circle[fill]:not([fill^="url"]),
.mark-ring svg circle[fill]:not([fill^="url"]),
.brand-mark svg circle[fill]:not([fill^="url"]){fill:var(--beam-2)}
/* .brand-mark is itself a filled brand chip, so the rules above would paint
   the glyph brand-on-brand and it would vanish. Inside that chip the mark
   takes the ink that sits on a brand fill instead. */
.brand-mark linearGradient stop,
.brand-mark linearGradient stop+stop{stop-color:var(--on-beam)}
.brand-mark svg circle[fill]:not([fill^="url"]){fill:var(--on-beam)}

/* ============================================================================
   AURORA BACKGROUND — two drifting blobs + a fine grid. Fixed, behind all.
   Deliberately quiet: a low-contrast field moving in the periphery is a real
   source of eye fatigue, so the blobs are dim (.16) and the drift is slow
   enough (70s / 85s) to read as still unless you stare straight at it.
   ========================================================================= */
.aurora{position:fixed;inset:0;z-index:-2;overflow:hidden;background:var(--void);pointer-events:none}
.aurora::before,.aurora::after{
  content:"";position:absolute;width:70vw;height:70vw;border-radius:50%;
  filter:blur(120px);opacity:.16;will-change:transform;
}
.aurora::before{
  background:var(--aurora-a);
  top:-24vw;left:-14vw;animation:drift-a 70s var(--ease-in-out) infinite;
}
.aurora::after{
  background:var(--aurora-b);
  bottom:-30vw;right:-16vw;animation:drift-b 85s var(--ease-in-out) infinite;
}
.aurora-grid{
  position:fixed;inset:0;z-index:-1;pointer-events:none;
  background-image:linear-gradient(var(--grid-line) 1px,transparent 1px),
                   linear-gradient(90deg,var(--grid-line) 1px,transparent 1px);
  background-size:64px 64px;
  mask-image:radial-gradient(ellipse 90% 55% at 50% 0%,var(--mask) 24%,transparent 72%);
  -webkit-mask-image:radial-gradient(ellipse 90% 55% at 50% 0%,var(--mask) 24%,transparent 72%);
}
@keyframes drift-a{
  0%,100%{transform:translate3d(0,0,0) scale(1)}
  33%{transform:translate3d(10vw,6vh,0) scale(1.1)}
  66%{transform:translate3d(-5vw,11vh,0) scale(.95)}
}
@keyframes drift-b{
  0%,100%{transform:translate3d(0,0,0) scale(1)}
  40%{transform:translate3d(-11vw,-8vh,0) scale(1.12)}
  75%{transform:translate3d(6vw,-3vh,0) scale(.93)}
}

/* ============================================================================
   TYPE
   ========================================================================= */
/* Bahnschrift sets tighter than Segoe UI at text sizes; give body copy a
   little air back so 13-15px paragraphs stay comfortable. */
body{letter-spacing:.008em}
.lede,p,li,td,dd{letter-spacing:.006em}

.num{font-family:var(--mono);font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.eyebrow{
  font-family:var(--mono);font-size:11px;letter-spacing:2.2px;text-transform:uppercase;
  color:var(--ink-3);font-weight:600;
}
/* Display optical size for headline text. Segoe UI Variable Display sets a
   touch wider than Inter did, so the clamps below are pulled in slightly. */
h1,h2{font-family:var(--display)}
h1{font-size:clamp(36px,5.7vw,66px);line-height:1.05;letter-spacing:-.034em;font-weight:800}
h2{font-size:clamp(25px,3.5vw,39px);line-height:1.12;letter-spacing:-.026em;font-weight:750}
h3{font-size:19px;line-height:1.3;letter-spacing:-.014em;font-weight:680}
h4{font-size:15px;line-height:1.35;letter-spacing:-.008em;font-weight:650}
.lede{font-size:17px;line-height:1.66;color:var(--ink-2);max-width:58ch}
.muted{color:var(--ink-3)}
.small{font-size:13px}
.tiny{font-size:11.5px;line-height:1.5}
.gradient-text{
  background:var(--sweep);-webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent;
}

/* ============================================================================
   LAYOUT
   ========================================================================= */
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 24px;width:100%}
.wrap-narrow{max-width:820px;margin:0 auto;padding:0 24px;width:100%}
section{padding:96px 0;position:relative}
@media(max-width:720px){section{padding:60px 0}}
.stack>*+*{margin-top:16px}
.row{display:flex;align-items:center;gap:12px}
.row-wrap{flex-wrap:wrap}
.spread{display:flex;justify-content:space-between;align-items:center;gap:14px}
.grid{display:grid;gap:16px}
.g2{grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}
.g3{grid-template-columns:repeat(auto-fit,minmax(268px,1fr))}
.g4{grid-template-columns:repeat(auto-fit,minmax(190px,1fr))}
.center{text-align:center}
.right{text-align:right}
.nowrap{white-space:nowrap}
.hidden{display:none!important}
.scroll-x{overflow-x:auto;-webkit-overflow-scrolling:touch}
.mono{font-family:var(--mono)}

/* ============================================================================
   SURFACES — glass
   ========================================================================= */
.glass{
  background:var(--glass);border:1px solid var(--edge);border-radius:var(--r-lg);
  backdrop-filter:blur(18px) saturate(140%);-webkit-backdrop-filter:blur(18px) saturate(140%);
  box-shadow:var(--shadow);
}
.glass-sm{
  background:var(--glass);border:1px solid var(--edge);border-radius:var(--r);
  backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
}
.slab{background:var(--slab);border:1px solid var(--edge);border-radius:var(--r-lg)}
.pad{padding:22px}
.pad-sm{padding:15px}
/* color:inherit is not cosmetic. Chrome's UA sheet gives <hr> a hardcoded grey
   `color`, which survives every theme switch and would be handed to anything
   inside that resolves currentColor. The visible rule is --edge; this keeps the
   inherited colour on a token too, so the audit gate has nothing to find. */
.hr{height:1px;background:var(--edge);border:0;margin:0;color:inherit}

/* a hairline gradient top-edge, for hero-level cards */
.lit{position:relative;overflow:hidden}
.lit::before{
  content:"";position:absolute;top:0;left:12%;right:12%;height:1px;
  background:var(--lit-line);
}

/* ============================================================================
   BUTTONS
   ========================================================================= */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:9px;
  padding:12px 22px;border-radius:var(--r-pill);border:1px solid var(--edge-2);
  background:var(--glass-2);font-weight:600;font-size:14.5px;letter-spacing:-.01em;
  transition:transform .16s var(--ease),background .2s,border-color .2s,box-shadow .25s;
  position:relative;overflow:hidden;white-space:nowrap;
}
.btn:hover{background:var(--glass-3);border-color:var(--edge-3);transform:translateY(-1px)}
.btn:active{transform:translateY(0)}
.btn:disabled{opacity:.4;cursor:not-allowed;transform:none}
.btn-primary{
  background:var(--sweep);border-color:transparent;color:var(--on-beam);font-weight:700;
  box-shadow:0 6px 26px -8px var(--beam-cast);
}
.btn-primary:hover{box-shadow:0 10px 34px -8px var(--beam-cast-2)}
.btn-long{background:var(--long);border-color:transparent;color:var(--on-long);font-weight:700}
.btn-short{background:var(--short);border-color:transparent;color:var(--on-short);font-weight:700}
.btn-ghost{background:transparent}
.btn-sm{padding:8px 15px;font-size:13px}
.btn-lg{padding:15px 30px;font-size:16px}
.btn-block{width:100%}

/* sheen sweep on primary hover */
.btn-primary::after{
  content:"";position:absolute;inset:0;
  background:var(--sheen-sweep);
  transform:translateX(-110%);
}
.btn-primary:hover::after{animation:sheen 1s var(--ease)}
@keyframes sheen{to{transform:translateX(110%)}}

/* ============================================================================
   FORM
   ========================================================================= */
.field{display:block}
.field>span,.label{
  display:block;font-size:12px;color:var(--ink-3);margin-bottom:7px;
  font-weight:600;letter-spacing:.3px;
}
.input{
  width:100%;padding:13px 15px;background:var(--well-3);
  border:1px solid var(--edge);border-radius:var(--r-sm);outline:none;
  transition:border-color .18s,box-shadow .18s,background .18s;
}
.input:hover{border-color:var(--edge-2)}
.input:focus{border-color:var(--beam);box-shadow:0 0 0 4px var(--beam-dim);background:var(--well-4)}
/* `.input` zeroes the outline above, which also swallows the global
   :focus-visible ring at equal specificity. Put it back for keyboard focus. */
.input:focus-visible{outline:2px solid var(--beam-2);outline-offset:2px}
/* a placeholder is text: --ink-4 is the 3:1 step, so the ramp's body-text
   step is the floor here */
.input::placeholder{color:var(--ink-3)}
.input[aria-invalid="true"]{border-color:var(--short);box-shadow:0 0 0 4px var(--short-dim)}
select.input{cursor:pointer;appearance:none;-webkit-appearance:none;
  background-repeat:no-repeat;background-position:right 14px center;padding-right:36px}
.err-text{color:var(--short);font-size:12.5px;margin-top:6px}

/* ============================================================================
   PILLS / CHIPS / DOTS
   ========================================================================= */
.pill{
  display:inline-flex;align-items:center;gap:7px;font-family:var(--mono);
  font-size:11px;letter-spacing:.8px;padding:5px 12px;border-radius:var(--r-pill);
  border:1px solid var(--edge);color:var(--ink-3);background:var(--glass);font-weight:600;
}
.pill.long{color:var(--long);border-color:var(--long-edge);background:var(--long-dim)}
.pill.short{color:var(--short);border-color:var(--short-edge);background:var(--short-dim)}
.pill.hold{color:var(--hold);border-color:var(--hold-edge);background:var(--hold-dim)}
.pill.beam{color:var(--beam-2);border-color:var(--beam-2-edge);background:var(--beam-2-dim)}

.dot{width:7px;height:7px;border-radius:50%;display:inline-block;flex:none;background:var(--ink-4)}
.dot.live{background:var(--long);color:var(--long-beacon);animation:beacon 2.2s infinite}
.dot.warn{background:var(--hold);color:var(--hold-beacon);animation:beacon 2.2s infinite}
@keyframes beacon{
  0%{box-shadow:0 0 0 0 currentColor;opacity:1}
  70%{box-shadow:0 0 0 7px transparent;opacity:.75}
  100%{box-shadow:0 0 0 0 transparent;opacity:1}
}

/* ============================================================================
   THEME PICKER — theme.js mounts this into #themePicker when that element is
   present. A radiogroup, not a select: three options, all worth showing, and
   arrow keys move between them.
   ========================================================================= */
.theme-pick{
  display:inline-flex;align-items:center;gap:3px;padding:3px;
  border-radius:var(--r-pill);background:var(--well);border:1px solid var(--edge);
}
.theme-opt{
  display:inline-flex;align-items:center;gap:7px;
  padding:6px 12px;border-radius:var(--r-pill);
  font-size:12.5px;font-weight:650;letter-spacing:-.005em;color:var(--ink-3);
  transition:color .18s,background .18s;white-space:nowrap;
}
.theme-opt:hover{color:var(--ink)}
.theme-opt[aria-checked="true"]{background:var(--glass-2);color:var(--ink)}
.theme-opt:focus-visible{outline-offset:-1px}
.theme-swatch{
  width:13px;height:13px;border-radius:50%;flex:none;
  border:1px solid var(--edge-2);background:var(--sweep);
}
.theme-opt[data-theme-opt="emerald"] .theme-swatch{background:var(--sw-emerald)}
.theme-opt[data-theme-opt="slate"] .theme-swatch{background:var(--sw-slate)}
.theme-opt[data-theme-opt="amber"] .theme-swatch{background:var(--sw-amber)}
/* Compact form: swatches only. The picker is ~107px with labels and ~84px
   without, so it fits a footer, a card or a rail -- but NOT the home nav at
   380px, where the mark + two CTAs already fill the row exactly. */
@media(max-width:640px){
  .theme-opt{padding:6px 8px}
  .theme-name{display:none}
}
@media(max-width:420px){
  .theme-pick{gap:2px;padding:2px}
  .theme-opt{padding:6px 7px}
}

/* ============================================================================
   TABLES
   ========================================================================= */
table{width:100%;border-collapse:collapse;font-size:13.5px}
th{
  /* a column header is content, not chrome -- it needs body-text contrast */
  font-family:var(--mono);font-size:10.5px;letter-spacing:1.3px;color:var(--ink-3);
  text-align:left;padding:10px 12px;font-weight:600;white-space:nowrap;
  border-bottom:1px solid var(--edge);
}
td{padding:11px 12px;border-bottom:1px solid var(--edge-soft);color:var(--ink-2)}
tbody tr{transition:background .15s}
tbody tr:hover td{background:var(--row-hover)}
tbody tr:last-child td{border-bottom:0}
.t-long{color:var(--long);font-weight:650}
.t-short{color:var(--short);font-weight:650}
.t-hold{color:var(--hold);font-weight:650}

/* ============================================================================
   MOTION LIBRARY
   ========================================================================= */

/* entrance — add .fx-rise, optionally with --d delay */
.fx-rise{animation:rise .7s var(--ease) both;animation-delay:var(--d,0s)}
@keyframes rise{from{opacity:0;transform:translateY(18px)}to{opacity:1;transform:none}}

.fx-fade{animation:fade .5s var(--ease) both;animation-delay:var(--d,0s)}
@keyframes fade{from{opacity:0}to{opacity:1}}

.fx-pop{animation:pop .5s var(--ease) both}
@keyframes pop{0%{opacity:0;transform:scale(.94)}60%{transform:scale(1.015)}100%{opacity:1;transform:scale(1)}}

/* reveal on scroll — JS toggles .in */
.reveal{opacity:0;transform:translateY(26px);transition:opacity .8s var(--ease),transform .8s var(--ease)}
.reveal.in{opacity:1;transform:none}

/* SIGNAL FIRES — the card slams in and glows once */
.fx-signal{animation:signal-fire .85s var(--ease) both}
@keyframes signal-fire{
  0%{opacity:0;transform:scale(.96) translateY(14px);box-shadow:0 0 0 0 transparent}
  45%{opacity:1;transform:scale(1.008) translateY(0);box-shadow:0 0 60px -10px var(--long-glow)}
  100%{opacity:1;transform:scale(1);box-shadow:var(--shadow)}
}
.fx-signal.is-short{animation-name:signal-fire-s}
@keyframes signal-fire-s{
  0%{opacity:0;transform:scale(.96) translateY(14px)}
  45%{opacity:1;transform:scale(1.008);box-shadow:0 0 60px -10px var(--short-glow)}
  100%{opacity:1;transform:scale(1);box-shadow:var(--shadow)}
}

/* LIVE pulse ring — wrap an element, ring expands out of it */
.pulse-host{position:relative}
.pulse-host::after{
  content:"";position:absolute;inset:-2px;border-radius:inherit;
  border:1.5px solid var(--long);opacity:0;animation:pulse-ring 2.4s var(--ease-in-out) infinite;
  pointer-events:none;
}
.pulse-host.is-short::after{border-color:var(--short)}
@keyframes pulse-ring{
  0%{opacity:.65;transform:scale(1)}
  70%{opacity:0;transform:scale(1.045)}
  100%{opacity:0;transform:scale(1.045)}
}

/* TARGET HIT — a light sweeps across, card flashes green */
.fx-hit{position:relative;animation:hit-flash 1.5s var(--ease) both}
.fx-hit::after{
  content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  background:linear-gradient(105deg,transparent 30%,var(--long-sweep) 50%,transparent 70%);
  transform:translateX(-100%);animation:hit-sweep 1.1s var(--ease) both;
}
@keyframes hit-flash{
  0%{box-shadow:0 0 0 0 transparent}
  25%{box-shadow:0 0 70px -6px var(--long-glow)}
  100%{box-shadow:var(--shadow)}
}
@keyframes hit-sweep{0%{transform:translateX(-100%)}100%{transform:translateX(100%)}}

/* STOP HIT — a short shake and a red wash */
.fx-stopped{animation:stopped 1.4s var(--ease) both}
@keyframes stopped{
  0%{transform:translateX(0);box-shadow:0 0 0 0 transparent}
  8%{transform:translateX(-7px)}
  16%{transform:translateX(6px)}
  24%{transform:translateX(-4px)}
  32%{transform:translateX(3px);box-shadow:0 0 60px -8px var(--short-glow)}
  40%{transform:translateX(0)}
  100%{box-shadow:var(--shadow)}
}

/* price tick flash */
.tick-up{animation:tick-up .7s var(--ease)}
.tick-down{animation:tick-down .7s var(--ease)}
@keyframes tick-up{0%{color:var(--long);text-shadow:0 0 18px var(--long-glow)}100%{color:inherit}}
@keyframes tick-down{0%{color:var(--short);text-shadow:0 0 18px var(--short-glow)}100%{color:inherit}}

/* progress track: spot travelling between stop and target */
.track{
  position:relative;height:6px;border-radius:var(--r-pill);
  background:linear-gradient(90deg,var(--short-dim),var(--track-mid),var(--long-dim));
  border:1px solid var(--edge);
}
.track-mark{
  position:absolute;top:50%;width:12px;height:12px;border-radius:50%;
  background:var(--ink);border:2px solid var(--void);
  transform:translate(-50%,-50%);transition:left .8s var(--ease);
  box-shadow:0 0 14px var(--mark-glow);
}
.track-fill{
  position:absolute;top:0;bottom:0;border-radius:var(--r-pill);
  background:var(--sweep-long);opacity:.5;transition:width .8s var(--ease),left .8s var(--ease);
}

/* countdown ring (SVG stroke-dashoffset driven from JS) */
.ring{transform:rotate(-90deg)}
.ring circle{fill:none;stroke-linecap:round}
.ring .bg{stroke:var(--ring-track)}
.ring .fg{stroke:var(--beam-2);transition:stroke-dashoffset .9s linear}

/* SVG path draw-on */
.draw{stroke-dasharray:var(--len,1000);stroke-dashoffset:var(--len,1000);animation:draw 2s var(--ease) forwards}
@keyframes draw{to{stroke-dashoffset:0}}

/* radar mark — the sweep rotates about the dial centre (12,12 in a 24 viewBox) */
.radar-sweep{transform-origin:50% 50%;animation:radar-spin 3.6s linear infinite}
@keyframes radar-spin{to{transform:rotate(360deg)}}

/* marquee ticker */
.ticker{overflow:hidden;position:relative;
  mask-image:linear-gradient(90deg,transparent,var(--mask) 6%,var(--mask) 94%,transparent);
  -webkit-mask-image:linear-gradient(90deg,transparent,var(--mask) 6%,var(--mask) 94%,transparent)}
.ticker-track{display:flex;gap:34px;width:max-content;animation:marquee 46s linear infinite}
.ticker:hover .ticker-track{animation-play-state:paused}
@keyframes marquee{from{transform:translateX(0)}to{transform:translateX(-50%)}}

/* shimmer skeleton */
.skel{
  background:var(--skel-sweep);
  background-size:200% 100%;animation:shimmer 1.5s infinite;border-radius:var(--r-xs);color:transparent!important;
}
@keyframes shimmer{to{background-position:-200% 0}}

/* floating idle bob */
.fx-float{animation:float 7s var(--ease-in-out) infinite}
@keyframes float{0%,100%{transform:translateY(0)}50%{transform:translateY(-9px)}}

/* ============================================================================
   TOASTS
   ========================================================================= */
#toasts{position:fixed;right:20px;bottom:20px;display:flex;flex-direction:column;
  gap:10px;z-index:200;max-width:370px}
.toast{
  border-radius:var(--r);padding:13px 17px;font-size:13.5px;
  background:var(--toast-bg);border:1px solid var(--edge-2);border-left-width:3px;
  backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);
  box-shadow:var(--shadow-lift);animation:toast-in .35s var(--ease);
}
.toast.ok{border-left-color:var(--long)}
.toast.err{border-left-color:var(--short)}
.toast.info{border-left-color:var(--beam-2)}
.toast.warn{border-left-color:var(--hold)}
@keyframes toast-in{from{opacity:0;transform:translateX(24px) scale(.97)}to{opacity:1;transform:none}}

/* ============================================================================
   MODAL
   ========================================================================= */
.scrim{
  position:fixed;inset:0;background:var(--scrim);backdrop-filter:blur(6px);
  -webkit-backdrop-filter:blur(6px);z-index:150;display:grid;place-items:center;padding:20px;
  animation:fade .25s var(--ease);
}
.modal{
  width:min(520px,100%);border-radius:var(--r-lg);background:var(--slab);
  border:1px solid var(--edge-2);box-shadow:var(--shadow-lift);
  animation:pop .35s var(--ease);max-height:90vh;overflow:auto;
}

/* ============================================================================
   REDUCED MOTION — kill everything decorative
   ========================================================================= */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important;scroll-behavior:auto!important;
  }
  .reveal{opacity:1;transform:none}
  .aurora::before,.aurora::after{animation:none}
  .ticker-track{animation:none}
}
