/* ---- tokens.css ---- */
:root {
  --bg:         #0a0d14;
  --surface:    #10141c;
  --surface-hi: #161b26;
  --border:     rgba(var(--overlay-rgb),0.08);
  --border-hi:  rgba(var(--accent-rgb),0.28);
  --bullish:    #34d399;
  --bearish:    #fb7185;
  /* Direct-on-background TEXT variants of bullish/bearish (candlestick
     crosshair readout, the error toast) — kept separately from the pill/
     badge shades above rather than reusing them, since a text color and
     a fill color don't need the same value even in one theme, and
     definitely don't in both (see :root[data-theme="light"] below,
     where these get meaningfully darker for real contrast on a white
     page, while --bullish/--bearish themselves barely need to move). */
  --bullish-text: #2fbf87;
  --bearish-text: #fda4af;
  --neutral:    #fbbf24;
  /* Two-tone brand system: amber is primary (buttons, active market tab,
     focus/highlight states — the Binance-gold CTA role); teal is
     secondary (active timeframe pills, the pulse-mark's ring). Never
     used for bullish/bearish — those stay green/red regardless of
     brand accent. */
  --accent:           #f3ba2f;
  --accent-hover:     #f6c957;
  --accent-secondary: #2fb8a6;
  --btc:        #f7931a;
  /* Asset-allocation categorical set (donut/pie charts — Portfolio,
     Demo Trading) — a deliberate 5-hue arc (25°→173°→215°→258°→300°)
     rather than one vivid color next to four washed-out pastels, which
     read as unconsidered when first tried. Every stop stays clear of
     --bullish (~155°) and --bearish (~355°) so an allocation color is
     never mistaken for a gain/loss signal, and holds consistent
     saturation/lightness so no single wedge dominates by default.
     Confirmed to hold enough contrast on the light theme's white
     surface too — no [data-theme="light"] override needed. */
  --alloc-1: var(--btc);
  --alloc-2: #2fb8a6;
  --alloc-3: #4a90f5;
  --alloc-4: #8b5cf6;
  --alloc-5: #c026d3;
  --text:       #eef2ff;
  --muted:      #7d8598;
  --muted-2:    #a8b0c2;
  /* The base color every "subtle overlay tint" rgba() in this app is
     built from (hover backgrounds, separator lines, faint borders) —
     ONE token instead of ~26 separate rgba(255,255,255,0.0X) literals
     scattered across every CSS file, each of which would otherwise need
     manually flipping to a dark-on-light tint for :root[data-theme="light"]
     below. Every one of those call sites now reads rgba(var(--overlay-rgb), 0.0X)
     instead — same opacity, theme-aware color. */
  --overlay-rgb: 255,255,255;
  /* Same "one token instead of dozens of literals" reasoning as
     --overlay-rgb above, but for the five semantic colors themselves —
     every "tinted border/background" (e.g. a pill's
     border-color: rgba(251,113,133,0.35)) used the color's OWN raw RGB
     triple directly instead of deriving it from --bearish/--bullish/etc.
     (58 call sites, found by grepping for these exact triples). Since
     :root[data-theme="light"] below gives several of those variables a
     genuinely different value for text-contrast reasons, any call site
     still hardcoding the dark theme's own RGB triple would silently
     stay dark-mode-colored in light mode — these five tokens are what
     every one of those call sites now derives from instead. */
  --bearish-rgb:          251,113,133;
  --bullish-rgb:          52,211,153;
  --neutral-rgb:          251,191,36;
  --accent-rgb:           243,186,47;
  --accent-secondary-rgb: 47,184,166;
  --radius:     8px;
  --radius-sm:  6px;
  --shadow:     0 2px 8px rgba(0,0,0,0.4);
  --font-body:  'Inter', ui-sans-serif, system-ui, sans-serif;
  --font-disp:  'Space Grotesk', 'Inter', sans-serif;
  --font-mono:  'JetBrains Mono', ui-monospace, monospace;
}

/* ---------- Light theme ----------
   Pulsar was dark-only for its first two months; this is the first
   light palette. Deliberately NOT a naive value-by-value invert of the
   block above — every token here was picked for its own job on a light
   ground rather than mechanically flipped, in particular the four
   semantic colors (accent/accent-secondary/bullish-text/bearish-text)
   that get used as small TEXT: the dark theme's own values for those
   (bright amber/teal/green/pink) fail contrast on a light background
   badly enough to be genuinely hard to read, so light mode uses
   noticeably deeper/richer variants of the same hues instead — still
   unmistakably "the same brand," just legible here. Applied via
   data-theme="light" on <html> (see settings.js's applyTheme) rather
   than only prefers-color-scheme, so a user's explicit Settings ->
   Preferences choice always wins over their OS-level default; "System"
   in that picker resolves to one or the other in JS before paint
   instead of relying on a CSS media query at all (see the inline
   pre-paint script in index.html's <head> for how the flash of the
   wrong theme on load is avoided). */
:root[data-theme="light"] {
  --bg:         #f4f5f8;
  --surface:    #ffffff;
  --surface-hi: #eef0f4;
  --border:     rgba(10,14,20,0.1);
  --border-hi:  rgba(var(--accent-rgb),0.4);
  --bullish:    #10b981;
  --bearish:    #f43f5e;
  --bullish-text: #047857;
  --bearish-text: #be123c;
  --neutral:    #b45309;
  --accent:           #f3ba2f;
  --accent-hover:     #f6c957;
  --accent-secondary: #14806f;
  --text:       #14161d;
  --muted:      #6b7280;
  --muted-2:    #454b58;
  --overlay-rgb: 10,14,20;
  /* Matching RGB triples for the retuned colors above — see the dark
     theme's own --bearish-rgb etc. for why these exist at all. */
  --bearish-rgb:          244,63,94;
  --bullish-rgb:          16,185,129;
  --neutral-rgb:          180,83,9;
  --accent-rgb:           243,186,47;
  --accent-secondary-rgb: 20,128,111;
  --shadow:     0 2px 10px rgba(20,22,30,0.1);
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html {
  scroll-behavior: smooth;
  /* Without this, native form controls (select dropdown popups,
     checkboxes, scrollbars) render using the WRONG light/dark chrome
     regardless of our own CSS, since nothing else here tells the
     browser which one the page itself actually is right now. */
  color-scheme: dark;
}
html[data-theme="light"] { color-scheme: light; }
html {
  /* Kills the native rubber-band bounce past the top/bottom edge (and the
     pull-to-refresh gesture it triggers on Android Chrome) — an installed
     app-like PWA reads as more "locked down"/native without it. */
  overscroll-behavior-y: none;
}
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  min-height: 100vh;
  padding: 32px 24px 56px;
  overflow-x: hidden;
  overscroll-behavior-y: none;
  -webkit-font-smoothing: antialiased;
}

/* ---------- Backdrop ---------- */
/* A faint chart-style grid, not decoration — reads as a terminal/data
   surface rather than a marketing-page backdrop. No blurred floating
   orbs, no drift animation: those were the single biggest "vibe-coded"
   tell in the original design (see the redesign plan for the full
   before/after rationale). */
.backdrop { position: fixed; inset: 0; z-index: -2; overflow: hidden; }
.gridlines {
  position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background-image:
    linear-gradient(rgba(148,197,255,0.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(148,197,255,0.045) 1px, transparent 1px);
  background-size: 56px 56px;
  mask-image: radial-gradient(ellipse 90% 60% at 50% 0%, black 30%, transparent 78%);
  -webkit-mask-image: radial-gradient(ellipse 90% 60% at 50% 0%, black 30%, transparent 78%);
}

.container { max-width: 1120px; margin: 0 auto; }

@keyframes rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ---------- Shared component base classes ---------- */
/* Every panel across the app (Analyze, Watchlist, Portfolio, Alerts,
   Signals, Compare, News) previously copy-pasted the same translucent
   blur+glow recipe; every primary button copy-pasted the same hardcoded
   blue->purple gradient. One definition each here, reused everywhere. */
.panel-base {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.btn-primary {
  background: var(--accent);
  border: none;
  border-radius: var(--radius-sm);
  color: #04121c;
  font-family: var(--font-body);
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s, opacity 0.15s;
}
.btn-primary:hover:not(:disabled) { background: var(--accent-hover); }
.btn-primary:disabled { opacity: 0.5; cursor: default; }

.btn-secondary {
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--muted-2);
  font-family: var(--font-body);
  font-weight: 600;
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s;
}
.btn-secondary:hover:not(:disabled) { border-color: var(--border-hi); color: var(--text); }
.btn-secondary:disabled { opacity: 0.5; cursor: default; }

.pill {
  display: inline-flex; align-items: center;
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase;
  padding: 4px 10px; border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--muted-2);
  background: transparent;
}
.pill-bullish { color: var(--bullish); border-color: rgba(var(--bullish-rgb),0.35); }
.pill-bearish { color: var(--bearish); border-color: rgba(var(--bearish-rgb),0.35); }
.pill-neutral { color: var(--neutral); border-color: rgba(var(--neutral-rgb),0.35); }
.pill-accent  { color: var(--accent);  border-color: rgba(var(--accent-rgb),0.35); }
.pill-secondary { color: var(--accent-secondary); border-color: rgba(var(--accent-secondary-rgb),0.35); }

.field {
  background: var(--surface-hi);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 13px;
  padding: 9px 12px;
  outline: none;
  transition: border-color 0.15s;
}
.field:focus { border-color: var(--accent); }

/* ---------- Allocation donut + ROI histogram (charts.js: mountAllocationDonut,
   mountROIHistogram) — shared between Portfolio's Real Exchange Account
   section and Demo Trading, so styled once here rather than duplicated
   into both portfolio.css and demo.css. ---------- */
.alloc-donut-wrap { position: relative; width: 260px; height: 260px; margin: 8px auto 0; }
.alloc-donut-wrap canvas { cursor: pointer; }
.alloc-donut-center {
  position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center;
  justify-content: center; pointer-events: none; text-align: center; padding: 0 30px;
}
.alloc-donut-center .val { font-family: var(--font-mono); font-weight: 700; font-size: 24px; font-variant-numeric: tabular-nums; }
.alloc-donut-center .lbl { font-size: 10px; color: var(--muted); letter-spacing: 0.08em; text-transform: uppercase; margin-top: 4px; }
.alloc-donut-center .asset-name { font-family: var(--font-disp); font-weight: 700; font-size: 15px; margin-top: 2px; }
.alloc-donut-center .back-hint { font-size: 9.5px; color: var(--muted); margin-top: 8px; letter-spacing: 0.03em; }

.alloc-legend { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; margin-top: 18px; }
.alloc-legend button {
  display: inline-flex; align-items: center; gap: 6px; font-size: 11px; font-family: var(--font-body);
  font-weight: 600; color: var(--muted-2); background: var(--surface-hi); border: 1px solid var(--border);
  border-radius: 999px; padding: 5px 11px 5px 8px; cursor: pointer; transition: border-color 0.15s, background 0.15s, color 0.15s;
}
.alloc-legend button .dot { width: 8px; height: 8px; border-radius: 2px; flex: none; }
.alloc-legend button:hover { border-color: var(--accent); color: var(--text); }
.alloc-legend button.active { background: var(--surface-hi); border-color: var(--accent); color: var(--text); box-shadow: inset 0 0 0 1px var(--accent); }

.roi-hist-canvas-wrap canvas { width: 100%; height: auto; display: block; cursor: pointer; }
.roi-hist-detail {
  margin-top: 16px; padding: 0 16px; border-radius: var(--radius-sm); background: var(--surface-hi);
  border: 1px solid var(--border); overflow: hidden;
  max-height: 0; opacity: 0; transition: max-height 0.32s cubic-bezier(0.16,1,0.3,1), opacity 0.25s, padding 0.32s;
}
.roi-hist-detail.open { max-height: 200px; opacity: 1; padding-top: 14px; padding-bottom: 14px; }
.roi-hist-detail .detail-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.roi-hist-detail .detail-title { font-family: var(--font-mono); font-weight: 700; font-size: 13.5px; }
.roi-hist-detail .detail-count { font-size: 11px; color: var(--muted); }
.roi-hist-detail .detail-close { background: none; border: none; color: var(--muted); cursor: pointer; font-size: 11px; font-family: var(--font-body); font-weight: 600; padding: 2px 6px; }
.roi-hist-detail .detail-close:hover { color: var(--text); }
.roi-hist-detail .pos-pills { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.pos-pill {
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 700; padding: 4px 9px; border-radius: 999px;
  border: 1px solid var(--border);
}
.pos-pill.up { color: var(--bullish); border-color: rgba(var(--bullish-rgb),0.35); }
.pos-pill.down { color: var(--bearish); border-color: rgba(var(--bearish-rgb),0.35); }

/* ---- intro.css ---- */
/* ---------- Intro overlay ---------- */
/* Deliberately brief and plain: pick a market, get into the app. The
   previous version had a hand-animated pixel-art runner sprinting down a
   drawn road toward a bursting "portal," ~3s of choreography for a single
   selection. Cut per the redesign — this keeps only what's purposeful. */
.no-intro #intro { display: none; }
#intro {
  position: fixed; inset: 0; z-index: 100;
  background: var(--bg);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 34px;
  transition: opacity 0.35s ease;
}
#intro.leaving { opacity: 0; pointer-events: none; }

.intro-mark {
  width: 64px; height: 64px;
  opacity: 0; animation: rise 0.5s cubic-bezier(0.22,1,0.36,1) forwards;
}
.intro-word { display: flex; gap: 4px; }
.intro-word span {
  font-family: var(--font-disp); font-weight: 700;
  font-size: clamp(2.4rem, 6vw, 3.6rem); letter-spacing: 0.12em; line-height: 1;
  color: var(--text);
  opacity: 0; transform: translateY(14px);
  animation: rise 0.5s cubic-bezier(0.22,1,0.36,1) forwards;
}

.intro-signpost { display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; }
.sign {
  display: flex; align-items: center; gap: 9px;
  font-family: var(--font-body); font-weight: 600;
  font-size: 13px; letter-spacing: 0.06em;
  color: var(--muted-2); cursor: pointer;
  padding: 12px 22px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  transition: border-color 0.15s, color 0.15s;
}
.sign[data-market="crypto"] { --sc: #f7931a; }
.sign[data-market="forex"]  { --sc: #38bdf8; }
.sign[data-market="stocks"] { --sc: #34d399; }
.sign[data-market="commodities"] { --sc: #d4a72c; }
.sign .ic { color: var(--sc); font-size: 14px; }
.sign:hover, .sign:focus-visible { border-color: var(--sc); color: var(--text); }
.sign.picked { border-color: var(--sc); color: var(--text); }

.intro-hint {
  font-size: 12px; color: var(--muted); letter-spacing: 0.16em; text-transform: uppercase;
}
.intro-skip {
  position: absolute; bottom: 30px; right: 34px;
  background: none; border: none; cursor: pointer;
  color: var(--muted); font-size: 12px; font-family: var(--font-body);
  letter-spacing: 0.08em; transition: color 0.25s;
}
.intro-skip:hover { color: var(--muted-2); }

/* pause main-page entrance animations while the intro is up */
.pre header, .pre .panel-base, .pre .empty-state, .pre .ticker-bar { animation-play-state: paused !important; }

/* ---- layout.css ---- */
/* ---------- Header ---------- */
header {
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px; flex-wrap: wrap; margin-bottom: 18px;
  animation: rise 0.8s cubic-bezier(0.22,1,0.36,1) both;
  /* the account dropdown menu is absolutely positioned inside here and
     must paint above the ticker tape below it — the ticker's own
     will-change:transform (for its infinite scroll animation) creates a
     stacking context that would otherwise win on DOM/paint order alone */
  position: relative; z-index: 10;
}
.brand { display: flex; align-items: center; gap: 16px; }
.header-actions { display: flex; align-items: center; gap: 10px; }

/* ---------- Hamburger nav ---------- */
.nav-menu-wrap { position: relative; }
.hamburger-btn {
  display: flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; flex-shrink: 0;
  font-size: 16px; color: var(--muted-2); cursor: pointer;
  background: rgba(var(--overlay-rgb),0.03);
  border: 1px solid var(--border);
  border-radius: 11px;
  transition: all 0.22s cubic-bezier(0.22,1,0.36,1);
}
.hamburger-btn:hover { color: var(--accent); border-color: rgba(var(--accent-rgb),0.4); }
/* position:fixed, not absolute — #nav-menu lives as a top-level sibling
   near the end of <body> (see index.html's own comment there for why:
   header's entrance animation permanently leaves it a non-"none"
   transform, which would otherwise silently hijack this into being
   positioned relative to header instead of the viewport). Its top/left
   are computed in JS (nav.js's positionNavMenuDesktop) from the trigger
   button's live position each time it opens, since there's no longer a
   positioned ancestor to anchor a static top/left against. */
.nav-menu {
  position: fixed; z-index: 70;
  min-width: 180px; padding: 6px;
  background: var(--surface-hi);
  border: 1px solid var(--border-hi);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow);
}
.nav-menu-item {
  display: block; width: 100%; text-align: left;
  background: none; border: none; cursor: pointer;
  font: inherit; font-family: var(--font-body); font-size: 12.5px; font-weight: 600;
  color: var(--muted-2); padding: 9px 12px; border-radius: 8px;
  transition: background 0.2s, color 0.2s;
}
.nav-menu-item:hover { background: rgba(var(--overlay-rgb),0.06); color: var(--text); }
.nav-menu-item.active { color: var(--accent); background: rgba(var(--accent-rgb),0.08); }

/* ---------- View switching ---------- */
.app-view { animation: rise 0.5s cubic-bezier(0.22,1,0.36,1) both; }
.view-back {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: none; cursor: pointer;
  font: inherit; font-family: var(--font-body); font-size: 12.5px; font-weight: 600;
  color: var(--muted); margin-bottom: 16px;
  transition: color 0.2s;
}
.view-back:hover { color: var(--accent); }

/* ---------- Gated ("log in to use this") empty state ---------- */
/* Shared by Watchlist/Portfolio/Alerts/Signals/Demo — see
   main.js::gatedEmptyState for why this replaced five copies of a bare
   line of muted italic text with no button and no sense of what's
   behind the login wall. */
.gate-empty {
  text-align: center; padding: 56px 20px 40px;
  animation: rise 0.6s cubic-bezier(0.22,1,0.36,1) both;
}
.gate-empty-icon {
  width: 30px; height: 30px; margin: 0 auto 16px; display: block;
  color: var(--muted); opacity: 0.9;
}
.gate-empty-title {
  font-family: var(--font-disp); font-size: 17px; font-weight: 700;
  margin-bottom: 8px;
}
.gate-empty-msg {
  font-size: 13px; color: var(--muted); line-height: 1.6;
  max-width: 340px; margin: 0 auto 22px;
}
.gate-empty-cta { padding: 10px 22px; font-size: 13.5px; }
/* The Market Pulse mark — the app's one brand identity, used identically
   here, in every favicon/app icon, and standalone assets (see
   frontend/*.png). Previously an animated dot+ring; replaced with this
   static price-spike glyph so the header and every icon file show the
   same mark instead of two different ones. */
.pulse-mark { width: 40px; height: 40px; flex-shrink: 0; }
h1 {
  font-family: var(--font-disp);
  font-size: clamp(2.1rem, 3.4vw, 2.9rem);
  font-weight: 700; letter-spacing: -0.045em; line-height: 1;
  color: var(--text);
}
.tagline { color: var(--muted); font-size: 13.5px; margin-top: 7px; letter-spacing: 0.01em; }
.tagline b { color: var(--muted-2); font-weight: 600; }

@keyframes breathe { 50% { opacity: 0.45; } }

/* ---------- Live ticker tape ---------- */
.ticker-bar {
  overflow: hidden; margin: 0 0 20px;
  border-top: 1px solid rgba(var(--overlay-rgb),0.05);
  border-bottom: 1px solid rgba(var(--overlay-rgb),0.05);
  padding: 10px 0;
  mask-image: linear-gradient(90deg, transparent, black 6%, black 94%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, black 6%, black 94%, transparent);
  animation: rise 0.8s 0.05s cubic-bezier(0.22,1,0.36,1) both;
}
.ticker-track { display: inline-flex; white-space: nowrap; animation: tickerScroll 55s linear infinite; will-change: transform; }
.ticker-bar:hover .ticker-track { animation-play-state: paused; }
@keyframes tickerScroll { to { transform: translateX(-50%); } }
.ticker-half { display: inline-flex; gap: 38px; padding-right: 38px; }
.tick {
  display: inline-flex; align-items: baseline; gap: 8px;
  font-family: var(--font-mono); font-size: 12px; cursor: pointer;
  transition: transform 0.2s;
}
.tick:hover { transform: translateY(-1px); }
.tick:hover .tick-sym { color: var(--accent); }
.tick-sym { font-weight: 700; color: var(--muted-2); transition: color 0.2s; }
/* Fixed min-widths matter here, not just cosmetics: the scroll animation
   below targets translateX(-50%), a percentage the browser recomputes
   against the track's live width — live price/change text (updated up to
   ~1/sec per symbol over the WebSocket) changing width mid-scroll was
   making that target shift continuously, which read as the tape
   stuttering/jumping backward. Pinning these widths keeps the track's
   total width stable so the animation has a fixed target again. */
.tick-price { color: var(--text); display: inline-block; min-width: 9ch; text-align: right; }
.tick-chg { font-size: 11px; font-weight: 600; display: inline-block; min-width: 7ch; text-align: right; }
.tick-chg.up { color: var(--bullish); }
.tick-chg.down { color: var(--bearish); }

/* ---------- Command panel ---------- */
.panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 24px 26px;
  margin: 0 0 24px;
  box-shadow: var(--shadow);
  animation: rise 0.8s 0.08s cubic-bezier(0.22,1,0.36,1) both;
}
.form-row { display: flex; gap: 26px; align-items: flex-end; flex-wrap: wrap; }
.form-group { display: flex; flex-direction: column; gap: 10px; }
label.field-label {
  font-size: 10.5px; color: var(--muted); font-weight: 700;
  letter-spacing: 0.18em; text-transform: uppercase;
}
input[type="text"] {
  background: var(--surface-hi);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 15px; font-weight: 600;
  padding: 13px 15px;
  width: 210px;
  outline: none;
  transition: border-color 0.15s;
}
input[type="text"]:focus { border-color: var(--accent); }
.chips { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.chip {
  font-family: var(--font-mono); font-size: 11px; font-weight: 600;
  color: var(--muted-2); cursor: pointer;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 999px; padding: 5px 11px;
  transition: border-color 0.15s, color 0.15s;
}
.chip:hover { color: var(--accent); border-color: var(--accent); }

.tf-group { display: flex; gap: 8px; flex-wrap: wrap; }
.tf-pill {
  position: relative; cursor: pointer;
  font-family: var(--font-mono); font-size: 13px; font-weight: 600;
  color: var(--muted-2);
  padding: 11px 18px;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  transition: border-color 0.15s, color 0.15s;
  user-select: none;
}
.tf-pill input { position: absolute; opacity: 0; pointer-events: none; }
.tf-pill:hover { border-color: var(--border-hi); }
/* Secondary (teal), not primary amber — market selection is the primary
   choice (.market-tab.active below), timeframe is a secondary refinement
   of it, so the two-tone system keeps that hierarchy visible at a glance. */
.tf-pill.active { color: var(--accent-secondary); border-color: var(--accent-secondary); background: var(--surface-hi); }

.market-tabs { display: flex; gap: 8px; margin-bottom: 18px; flex-wrap: wrap; }
.market-tab {
  font: inherit; outline: none; cursor: pointer;
  font-family: var(--font-body); font-size: 12px; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--muted-2);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 9px 18px;
  transition: border-color 0.15s, color 0.15s;
}
.market-tab:hover { color: var(--text); border-color: var(--border-hi); }
.market-tab.active { color: var(--accent); border-color: var(--accent); background: var(--surface-hi); }

button#analyze-btn {
  background: var(--accent);
  border: none; border-radius: var(--radius-sm);
  color: #04121c; cursor: pointer;
  font-family: var(--font-body);
  font-size: 14px; font-weight: 700; letter-spacing: 0.01em;
  padding: 14px 34px;
  transition: background 0.15s, opacity 0.15s;
}
button#analyze-btn:hover:not(:disabled) { background: var(--accent-hover); }
button#analyze-btn:disabled { opacity: 0.5; cursor: wait; }
.scan-dots::after { content: ""; animation: dots 1.4s steps(4, end) infinite; }
@keyframes dots { 0% { content: ""; } 25% { content: "."; } 50% { content: ".."; } 75% { content: "..."; } }

/* ---------- Error toast ---------- */
.error-box {
  display: none;
  background: rgba(var(--bearish-rgb),0.09);
  border: 1px solid rgba(var(--bearish-rgb),0.35);
  border-radius: var(--radius-sm);
  color: var(--bearish-text);
  padding: 14px 18px;
  font-size: 13px; line-height: 1.6;
  margin-bottom: 20px;
  animation: shake 0.5s cubic-bezier(0.36,0.07,0.19,0.97) both;
}
@keyframes shake {
  10%, 90% { transform: translateX(-1px); }
  20%, 80% { transform: translateX(2px); }
  30%, 50%, 70% { transform: translateX(-4px); }
  40%, 60% { transform: translateX(4px); }
}

/* ---------- Consensus banner ---------- */
.consensus {
  display: none;
  align-items: center; justify-content: space-between; gap: 18px; flex-wrap: wrap;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px 26px;
  margin-bottom: 20px;
  box-shadow: var(--shadow);
  animation: rise 0.7s cubic-bezier(0.22,1,0.36,1) both;
}
.consensus-label { font-size: 11px; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase; color: var(--muted); margin-bottom: 6px; }
.consensus-verdict {
  font-family: var(--font-disp); font-size: clamp(1.5rem, 2.6vw, 2rem);
  font-weight: 700; letter-spacing: -0.02em; line-height: 1;
}
.consensus-verdict.bull { color: var(--bullish); }
.consensus-verdict.bear { color: var(--bearish); }
.consensus-verdict.neut { color: var(--neutral); }
.consensus-meta { font-size: 12.5px; color: var(--muted); margin-top: 7px; }
.consensus-meta b { color: var(--muted-2); font-family: var(--font-mono); }
.consensus-right { text-align: right; }
.consensus-sym { font-family: var(--font-mono); font-size: 14px; font-weight: 700; color: var(--muted-2); }
.consensus-time { font-size: 11.5px; color: var(--muted); margin-top: 5px; }

/* ---------- Footer ---------- */
footer {
  margin-top: 34px; font-size: 11.5px; color: var(--muted);
  line-height: 1.7; text-align: center; opacity: 0.8;
}
footer b { color: var(--neutral); font-weight: 600; }
.footer-links {
  margin-top: 10px; display: flex; justify-content: center; gap: 16px;
  font-family: var(--font-mono); font-size: 11px;
}
.footer-links a { color: var(--muted); text-decoration: none; }
.footer-links a:hover { color: var(--accent); }

.footer-apps {
  margin-top: 16px;
  display: flex; align-items: center; justify-content: center; gap: 10px;
}
.footer-apps-label {
  font-family: var(--font-mono); font-size: 10.5px;
  letter-spacing: 0.04em; text-transform: uppercase; color: var(--muted);
}
.footer-app-icon {
  display: flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 50%;
  border: 1px solid var(--border);
  color: var(--muted-2);
  transition: border-color 0.15s, color 0.15s;
  /* Mono-font uppercase labels sit visually high in their own line box
     (little descender space) — centering the icon circle against that
     box alone makes it look a few px too high next to the label's actual
     glyphs, so nudge it down slightly for the optical match. */
  margin-top: 3px;
}
.footer-app-icon svg { width: 16px; height: 16px; }
.footer-app-icon:hover { border-color: var(--border-hi); color: var(--accent); }
.footer-app-icon--android { color: #3ddc84; border-color: rgba(61,220,132,0.3); }
.footer-app-icon--android:hover { border-color: #3ddc84; color: #3ddc84; }

/* ---- nav.css ---- */
/* ---------- Bottom tab bar (phones only) ---------- */
/* Hidden on desktop by default — the hamburger menu already works fine
   there and a fixed bottom bar is a mobile-app idiom, not a desktop one.
   Shown at the same 620px breakpoint the rest of the app treats as
   "phone" (see responsive.css). */
.bottom-tab-bar {
  display: none;
}

@media (max-width: 620px) {
  .bottom-tab-bar {
    display: flex;
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 55; /* above normal content, below modals (60) and Tars (50 is fine — Tars sits higher up, see its own safe-area offset below) */
    background: var(--surface-hi);
    border-top: 1px solid var(--border);
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  .bottom-tab-item {
    flex: 1;
    display: flex; flex-direction: column; align-items: center; gap: 3px;
    background: none; border: none;
    color: var(--muted);
    cursor: pointer;
    padding: 8px 0 3px;
    font-family: var(--font-body);
    transition: color 0.15s;
  }
  .bottom-tab-item.active { color: var(--accent); }
  .bottom-tab-icon { width: 21px; height: 21px; }
  .bottom-tab-label { font-size: 10px; font-weight: 600; letter-spacing: 0.02em; }

  /* body's own bottom padding at this breakpoint is set in responsive.css
     (loads after this file — a plain padding-bottom here would be
     silently overwritten by its shorthand `padding` rule) — see that
     file for the actual clearance added for this bar's real height. */

  /* "More" (bottom-tab-more) now does everything the hamburger trigger
     did — no need for both on screen at once. */
  #nav-menu-trigger { display: none; }

  /* #nav-menu (index.html: a top-level element, not nested under
     <header> — see the comment there) is positioned by JS on desktop
     (nav.js's positionNavMenuDesktop, anchored under the trigger
     button) but that never runs here since the trigger itself is
     hidden above — pin it above the bottom tab bar instead. */
  #nav-menu {
    top: auto;
    left: 14px; right: 14px; bottom: calc(70px + env(safe-area-inset-bottom, 0px));
    width: auto;
    max-height: 60vh;
    overflow-y: auto;
    z-index: 71; /* above the backdrop below */
  }

  /* Without this, the sheet above just floats over whatever's still
     showing on the rest of the page (e.g. the Timeframes row's own
     pill outlines were visible poking out above the sheet's top edge)
     — first-time-visitor testing found that reads as an overlap glitch,
     not an intentional panel taking over the screen. Toggled by nav.js
     alongside #nav-menu's own hidden state; clicking it closes the
     menu via the same outside-click handler every other click target
     outside #nav-menu already falls through to. */
  #nav-menu-backdrop {
    position: fixed; inset: 0; z-index: 56; /* above bottom-tab-bar (55), below the sheet (71) */
    background: rgba(4,6,12,0.6);
  }

  /* Demo Trading, Alerts, and Learn already sit one tap away on the
     bottom tab bar directly beneath this sheet (see
     BOTTOM_TAB_VIEWS in nav.js) — showing them again here was pure
     duplication with no reason for either copy to exist over the
     other. Desktop keeps all of them: the hamburger menu is the ONLY
     way to reach these views there, since there's no bottom tab bar. */
  .nav-menu-item[data-view="demo"],
  .nav-menu-item[data-view="alerts"],
  .nav-menu-item[data-view="learn"] {
    display: none;
  }
}

/* ---- results.css ---- */
/* ---------- Results grid & cards ---------- */
.results-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  align-items: start; /* expanding one card must not stretch its neighbors */
  gap: 18px;
  margin-bottom: 20px;
}
.tf-card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 24px;
  box-shadow: var(--shadow);
  opacity: 0;
  transform: translateY(28px);
  filter: blur(6px);
  transition:
    opacity 0.65s cubic-bezier(0.22,1,0.36,1),
    transform 0.65s cubic-bezier(0.22,1,0.36,1),
    filter 0.65s cubic-bezier(0.22,1,0.36,1),
    border-color 0.3s;
  overflow: hidden;
}
.tf-card.visible { opacity: 1; transform: translateY(0); filter: blur(0); }
.tf-card.settled { transition: transform 0.16s ease-out, border-color 0.3s; will-change: transform; }
.tf-card:hover { border-color: var(--border-hi); }
.tf-card::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  background: radial-gradient(480px circle at var(--mx, 50%) var(--my, 0%), rgba(120,180,255,0.08), transparent 42%);
  opacity: 0; transition: opacity 0.35s; pointer-events: none;
}
.tf-card:hover::before { opacity: 1; }

.tf-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px; }
.tf-label-text { font-family: var(--font-disp); font-size: 21px; font-weight: 700; letter-spacing: -0.02em; }
.badge {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.1em;
  padding: 6px 12px; border-radius: 999px; text-transform: uppercase;
  border: 1px solid transparent;
}
.badge-BULLISH { background: transparent; color: var(--bullish); border-color: rgba(var(--bullish-rgb),0.35); }
.badge-BEARISH { background: transparent; color: var(--bearish); border-color: rgba(var(--bearish-rgb),0.35); }
.badge-NEUTRAL { background: transparent; color: var(--neutral); border-color: rgba(var(--neutral-rgb),0.3); }

.price-row { display: flex; align-items: baseline; gap: 10px; margin-bottom: 12px; }
.price { font-family: var(--font-mono); font-size: 15px; font-weight: 700; color: var(--muted-2); }
.change { font-family: var(--font-mono); font-size: 12px; font-weight: 600; }
.change.up   { color: var(--bullish); }
.change.down { color: var(--bearish); }

/* sparkline + crosshair */
.spark-wrap { position: relative; margin: 2px 0 16px; height: 58px; cursor: crosshair; }
.spark-line { fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.spark-area { opacity: 0; transition: opacity 0.9s ease 0.5s; }
.spark-wrap.go .spark-area { opacity: 1; }
.spark-line { stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset 1.3s cubic-bezier(0.22,1,0.36,1) 0.15s; }
.spark-wrap.go .spark-line { stroke-dashoffset: 0; }
.cross-x {
  position: absolute; top: 0; bottom: 0; width: 1px;
  background: rgba(148,197,255,0.35); opacity: 0; pointer-events: none;
  transition: opacity 0.2s;
}
.cross-dot {
  position: absolute; width: 8px; height: 8px; border-radius: 50%;
  background: var(--text);
  margin: -4px 0 0 -4px; opacity: 0; pointer-events: none;
  transition: opacity 0.2s;
}
.cross-tip {
  position: absolute; top: -26px; transform: translateX(-50%);
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 700;
  /* Fixed light-on-dark, not var(--text) — the background here is a
     deliberately theme-invariant dark tooltip (same reasoning as every
     other scrim/tooltip in this app), but the text color was still
     following the theme, which went near-black in light mode and landed
     on a dark background: unreadable. */
  color: #eef2ff; background: rgba(10,14,24,0.92);
  border: 1px solid var(--border-hi); border-radius: 7px;
  padding: 3px 8px; white-space: nowrap; opacity: 0; pointer-events: none;
  transition: opacity 0.2s;
}
.spark-wrap.tracking .cross-x, .spark-wrap.tracking .cross-dot, .spark-wrap.tracking .cross-tip { opacity: 1; }

/* candlestick variant — needs more vertical room than the sparkline for
   wicks/bodies to read clearly */
.spark-wrap.candles { height: 80px; }
.candle-svg { opacity: 0; transition: opacity 0.7s ease 0.15s; }
.spark-wrap.candles.go .candle-svg { opacity: 1; }

/* bipolar score bar */
.score-block { margin-bottom: 16px; }
.score-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 8px; }
.score-title { font-size: 10px; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: var(--muted); }
.score-val { font-family: var(--font-mono); font-size: 14px; font-weight: 700; }
.bar-wrap { position: relative; height: 8px; background: rgba(var(--overlay-rgb),0.05); border-radius: 999px; overflow: visible; }
.bar-center { position: absolute; left: 50%; top: -3px; bottom: -3px; width: 1.5px; background: rgba(var(--overlay-rgb),0.18); }
.bar-fill {
  position: absolute; top: 0; height: 100%; border-radius: 999px;
  width: 0; transition: width 0.9s cubic-bezier(0.22,1,0.36,1) 0.35s, left 0.9s cubic-bezier(0.22,1,0.36,1) 0.35s;
}
.bar-fill.up   { background: var(--bullish); }
.bar-fill.down { background: var(--bearish); }

/* accuracy ring row */
.stats-row {
  display: flex; align-items: center; gap: 16px;
  padding: 14px 0; margin-bottom: 14px;
  border-top: 1px solid rgba(var(--overlay-rgb),0.06);
  border-bottom: 1px solid rgba(var(--overlay-rgb),0.06);
}
.ring-wrap { position: relative; width: 62px; height: 62px; flex-shrink: 0; }
.ring-wrap svg { transform: rotate(-90deg); }
.ring-bg  { fill: none; stroke: rgba(var(--overlay-rgb),0.07); stroke-width: 5; }
.ring-fg  {
  fill: none; stroke-width: 5; stroke-linecap: round;
  stroke-dasharray: 100; stroke-dashoffset: 100;
  transition: stroke-dashoffset 1.2s cubic-bezier(0.22,1,0.36,1) 0.4s;
}
.ring-num {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-family: var(--font-mono); font-size: 13px; font-weight: 700;
}
.stats-text { flex: 1; }
.stats-title { font-size: 12.5px; font-weight: 600; color: var(--muted-2); display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.stats-meta  { font-size: 11.5px; color: var(--muted); margin-top: 4px; line-height: 1.5; }
.stats-meta b { color: var(--muted-2); font-family: var(--font-mono); font-weight: 600; }

/* reasons — collapsed by default, expand on tap */
.votes-toggle {
  width: 100%; display: flex; align-items: center; gap: 10px;
  background: none; border: none; cursor: pointer; padding: 6px 0;
  font-family: var(--font-body); -webkit-tap-highlight-color: transparent;
}
.votes-title {
  font-size: 10px; font-weight: 700; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--muted); transition: color 0.25s;
}
.votes-toggle:hover .votes-title { color: var(--muted-2); }
.votes-counts { margin-left: auto; font-family: var(--font-mono); font-size: 11px; font-weight: 600; display: inline-flex; gap: 9px; }
.votes-counts .up { color: var(--bullish); }
.votes-counts .down { color: var(--bearish); }
.votes-counts .flat { color: var(--muted); }
.chev { color: var(--muted); font-size: 11px; transition: transform 0.35s cubic-bezier(0.22,1,0.36,1); }
.votes-toggle.open .chev { transform: rotate(180deg); }
.votes-body {
  overflow: hidden; max-height: 0;
  transition: max-height 0.5s cubic-bezier(0.22,1,0.36,1);
}
.reasons { list-style: none; display: flex; flex-direction: column; gap: 8px; padding-top: 10px; }
.reasons li {
  font-size: 12.5px; color: var(--muted-2); display: flex; gap: 9px; line-height: 1.55;
  opacity: 0; transform: translateX(-10px);
}
.votes-body.open .reasons li { animation: slideIn 0.5s cubic-bezier(0.22,1,0.36,1) forwards; }
@keyframes slideIn { to { opacity: 1; transform: translateX(0); } }
.vote { flex-shrink: 0; font-size: 11px; width: 14px; text-align: center; margin-top: 2px; font-weight: 700; }
.vote.up   { color: var(--bullish); }
.vote.down { color: var(--bearish); }
.vote.flat { color: var(--muted); }
.tf-error { font-size: 12.5px; color: var(--bearish); line-height: 1.6; }

/* ---------- Indicator contribution chart (diverging bars) ---------- */
.contrib-list { display: flex; flex-direction: column; gap: 11px; padding-top: 10px; }
.contrib-row {
  opacity: 0; transform: translateX(-10px);
}
.votes-body.open .contrib-row { animation: slideIn 0.5s cubic-bezier(0.22,1,0.36,1) forwards; }
.contrib-top { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.contrib-label {
  flex-shrink: 0; width: 72px; font-family: var(--font-mono); font-size: 10.5px;
  font-weight: 700; letter-spacing: 0.03em; color: var(--muted-2);
  text-transform: uppercase; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.contrib-bar-wrap { position: relative; flex: 1; height: 8px; }
.contrib-bar-track { position: absolute; inset: 0; top: 3px; height: 2px; background: rgba(var(--overlay-rgb),0.06); border-radius: 999px; }
.contrib-bar-zero { position: absolute; left: 50%; top: -3px; bottom: -3px; width: 1.5px; background: rgba(var(--overlay-rgb),0.18); }
.contrib-bar-fill {
  position: absolute; top: 0; height: 8px; border-radius: 999px;
}
.contrib-bar-fill.up   { background: var(--bullish); }
.contrib-bar-fill.down { background: var(--bearish); }
.contrib-value {
  flex-shrink: 0; width: 44px; text-align: right;
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 700; color: var(--muted-2);
}
.contrib-icon { display: inline-block; margin-right: 3px; }
.contrib-icon.up   { color: var(--bullish); }
.contrib-icon.down { color: var(--bearish); }
.contrib-icon.flat { color: var(--muted); }
.contrib-reason { font-size: 11.5px; color: var(--muted); line-height: 1.5; padding-left: 80px; }
.contrib-learn { padding-left: 80px; margin-top: 6px; }

/* ---------- Analysis scanner (loading state) ---------- */
.scanner {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px 24px 18px;
  box-shadow: var(--shadow);
  overflow: hidden;
  animation: rise 0.5s cubic-bezier(0.22,1,0.36,1) both;
}
.scanner::before { /* faint chart grid */
  content: ""; position: absolute; inset: 58px 24px 36px;
  background-image:
    linear-gradient(rgba(148,197,255,0.05) 1px, transparent 1px);
  background-size: 100% 34px;
  pointer-events: none;
}
.scanner-head {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 14px; flex-wrap: wrap; margin-bottom: 12px;
}
.scan-status {
  font-size: 13.5px; font-weight: 600; color: var(--muted-2);
  display: inline-flex; align-items: center; gap: 10px;
}
.scan-status::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%;
  background: var(--mkc, var(--accent));
  box-shadow: 0 0 12px var(--mkc, var(--accent));
  animation: breathe 1.6s ease-in-out infinite;
}
.scan-phase { transition: opacity 0.35s, transform 0.35s; }
.scan-phase.swap { opacity: 0; transform: translateY(7px); }
.scan-note { font-family: var(--font-mono); font-size: 11px; color: var(--muted); }
.scan-chart {
  position: relative; height: 170px; overflow: hidden;
  border-bottom: 1px solid rgba(148,197,255,0.14);
  mask-image: linear-gradient(90deg, transparent, black 7%, black 93%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, black 7%, black 93%, transparent);
}
.candle-track {
  position: absolute; inset: 0;
  display: flex; align-items: flex-end; gap: 6px; padding: 0 2px;
  will-change: transform;
}
.candle {
  position: relative; flex: 0 0 14px; border-radius: 3px;
  background: currentColor;
  animation: candleIn 0.4s cubic-bezier(0.22,1,0.36,1) both;
}
.candle.up   { color: var(--bullish-text); }
.candle.down { color: var(--bearish-text); }
.candle::before { /* wick */
  content: ""; position: absolute; left: 50%; width: 2px;
  transform: translateX(-50%);
  top: calc(-1 * var(--wt, 6px)); bottom: calc(-1 * var(--wb, 6px));
  background: currentColor; opacity: 0.65; border-radius: 2px;
}
@keyframes candleIn { from { transform: scaleY(0); opacity: 0; } }
.scan-beam {
  position: absolute; top: 0; bottom: 0; width: 70px; left: -10%;
  background: linear-gradient(90deg, transparent,
    color-mix(in srgb, var(--mkc, #38bdf8) 20%, transparent), transparent);
  animation: beamSweep 2.6s ease-in-out infinite alternate;
  pointer-events: none;
}
.scan-beam::after {
  content: ""; position: absolute; left: 50%; top: 0; bottom: 0; width: 1.5px;
  background: var(--mkc, #38bdf8); opacity: 0.85;
  box-shadow: 0 0 16px var(--mkc, #38bdf8);
}
@keyframes beamSweep { from { left: -4%; } to { left: calc(100% - 66px); } }
.scanner .runner {
  position: absolute; bottom: 3px; left: 30px;
  transform: scale(0.5); transform-origin: bottom left;
  animation: none; opacity: 0.95; z-index: 2;
}
.scan-floater {
  position: absolute; bottom: 16px;
  font-family: var(--font-mono); font-size: 10px; font-weight: 700;
  opacity: 0; pointer-events: none;
  animation: floatUp 2.8s linear forwards;
}
@keyframes floatUp {
  12%  { opacity: 0.75; }
  100% { transform: translateY(-130px); opacity: 0; }
}
.scan-progress {
  position: relative; height: 3px; margin-top: 14px;
  border-radius: 999px; background: rgba(var(--overlay-rgb),0.06); overflow: hidden;
}
.scan-progress::after {
  content: ""; position: absolute; top: 0; bottom: 0; width: 38%;
  border-radius: 999px;
  background: linear-gradient(90deg, transparent, var(--mkc, #38bdf8), transparent);
  animation: indet 1.5s ease-in-out infinite;
}
@keyframes indet { from { left: -38%; } to { left: 100%; } }

/* ---------- Empty state ---------- */
.empty-state {
  text-align: center; padding: 70px 20px 50px;
  animation: rise 0.8s 0.18s cubic-bezier(0.22,1,0.36,1) both;
}
.empty-icon { width: 34px; height: 34px; margin: 0 auto 16px; display: block; opacity: 0.9; }
.empty-title { font-family: var(--font-disp); font-size: 19px; font-weight: 700; margin-bottom: 8px; }
.empty-sub { font-size: 13px; color: var(--muted); line-height: 1.7; max-width: 420px; margin: 0 auto; }

/* ---- news.css ---- */
/* ---------- News panel ---------- */
.news-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 24px 26px;
  margin-bottom: 20px;
  box-shadow: var(--shadow);
  opacity: 0; transform: translateY(24px);
  animation: rise 0.7s cubic-bezier(0.22,1,0.36,1) 0.25s forwards;
}
.news-header { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
.news-title-text { font-family: var(--font-body); font-size: 15px; font-weight: 600; }
.more-headlines {
  margin-top: 12px; background: none; cursor: pointer;
  border: 1px solid var(--border); border-radius: 999px;
  color: var(--muted-2); font-size: 11.5px; font-weight: 600;
  padding: 7px 16px; font-family: var(--font-body);
  transition: all 0.22s; -webkit-tap-highlight-color: transparent;
}
.more-headlines:hover { color: var(--accent); border-color: rgba(var(--accent-rgb),0.5); }
.news-summary { font-size: 13.5px; color: var(--muted-2); line-height: 1.8; margin-bottom: 14px; }
.news-headlines { list-style: none; display: flex; flex-direction: column; gap: 8px; }
.news-headlines li {
  font-size: 12.5px; color: var(--muted); padding: 4px 0 4px 14px;
  border-left: 2px solid rgba(var(--accent-rgb),0.3); line-height: 1.6;
  opacity: 0; transform: translateX(-10px);
  animation: slideIn 0.5s cubic-bezier(0.22,1,0.36,1) forwards;
  transition: color 0.25s, border-color 0.25s, transform 0.25s;
}
.news-headlines li.linked { cursor: pointer; }
.news-headlines li.linked:hover { color: var(--text); border-color: var(--accent); transform: translateX(4px) !important; }
.news-headlines li.linked::after { content: " ↗"; color: var(--accent); font-size: 10px; opacity: 0; transition: opacity 0.25s; }
.news-headlines li.linked:hover::after { opacity: 1; }
.no-news { font-size: 13px; color: var(--muted); font-style: italic; line-height: 1.7; }
.no-news code { font-family: var(--font-mono); font-size: 11.5px; color: var(--accent); background: rgba(var(--accent-rgb),0.08); padding: 2px 6px; border-radius: 6px; font-style: normal; }

/* ---------- Article modal ---------- */
.modal-backdrop {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(3,5,10,0.7); backdrop-filter: blur(8px);
  display: grid; place-items: center; padding: 24px;
  opacity: 0; pointer-events: none; transition: opacity 0.3s;
}
.modal-backdrop.open { opacity: 1; pointer-events: auto; }
.modal {
  width: min(620px, 100%); max-height: 78vh; overflow-y: auto;
  background: var(--surface-hi);
  border: 1px solid var(--border-hi);
  border-radius: var(--radius);
  padding: 26px 28px;
  box-shadow: 0 20px 50px rgba(0,0,0,0.5);
  transform: translateY(20px) scale(0.95);
  transition: transform 0.35s cubic-bezier(0.22,1,0.36,1);
}
.modal-backdrop.open .modal { transform: translateY(0) scale(1); }
.modal-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 14px; margin-bottom: 16px; }
.modal-title { font-family: var(--font-disp); font-size: 16px; font-weight: 700; line-height: 1.45; }
.modal-close {
  background: rgba(var(--overlay-rgb),0.05); border: 1px solid var(--border);
  color: var(--muted-2); border-radius: 10px; cursor: pointer;
  width: 32px; height: 32px; font-size: 13px; flex-shrink: 0;
  transition: all 0.2s;
}
.modal-close:hover { color: var(--text); border-color: var(--border-hi); transform: rotate(90deg); }
.modal-body { font-size: 13.5px; color: var(--muted-2); line-height: 1.85; white-space: pre-line; margin-bottom: 18px; }
.modal-loader { display: flex; gap: 6px; padding: 18px 0; }
.modal-loader span {
  width: 8px; height: 8px; border-radius: 50%; background: var(--accent);
  animation: bounceDot 1.1s ease-in-out infinite;
}
.modal-loader span:nth-child(2) { animation-delay: 0.15s; }
.modal-loader span:nth-child(3) { animation-delay: 0.3s; }
@keyframes bounceDot { 40% { transform: translateY(-8px); opacity: 0.5; } }
.modal-link {
  font-size: 12.5px; font-weight: 600; color: var(--accent);
  text-decoration: none; border-bottom: 1px dashed rgba(var(--accent-rgb),0.4);
  transition: border-color 0.2s;
}
.modal-link:hover { border-bottom-style: solid; }

/* ---- auth.css ---- */
/* ---------- User chip ---------- */
.user-chip {
  display: inline-flex; align-items: center; gap: 10px;
  font-size: 12px; color: var(--muted-2);
}
.user-action {
  font: inherit; font-family: var(--font-body); font-size: 12px; font-weight: 600;
  color: var(--accent); background: rgba(var(--accent-rgb),0.08);
  border: 1px solid rgba(var(--accent-rgb),0.3); border-radius: 999px;
  padding: 7px 14px; cursor: pointer; transition: all 0.22s;
}
.user-action:hover { border-color: rgba(var(--accent-rgb),0.6); background: rgba(var(--accent-rgb),0.14); }

/* ---------- Account dropdown ---------- */
.user-menu-wrap { position: relative; }
.user-menu-caret { font-size: 9px; color: var(--muted); margin-left: 2px; }
.user-menu {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 70;
  min-width: 180px; padding: 6px;
  background: var(--surface-hi);
  border: 1px solid var(--border-hi);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow);
}
.user-menu-item {
  display: block; width: 100%; text-align: left;
  background: none; border: none; cursor: pointer;
  font: inherit; font-family: var(--font-body); font-size: 12.5px; font-weight: 600;
  color: var(--muted-2); padding: 9px 12px; border-radius: 8px;
  transition: background 0.2s, color 0.2s;
}
.user-menu-item:hover { background: rgba(var(--overlay-rgb),0.06); color: var(--text); }
.user-menu-item.danger { color: var(--bearish); }
.user-menu-item.danger:hover { background: rgba(var(--bearish-rgb),0.1); }
.user-menu-sep { height: 1px; background: rgba(var(--overlay-rgb),0.08); margin: 4px 6px; }

/* ---------- Profile modal ---------- */
.profile-modal { width: min(460px, 100%); }
.profile-section { padding: 18px 0; border-top: 1px solid rgba(var(--overlay-rgb),0.07); }
.profile-section:first-of-type { padding-top: 4px; border-top: none; }
.profile-section-title {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 12px;
}
.profile-current-value {
  font-family: var(--font-mono); font-size: 13px; color: var(--muted-2);
  margin-bottom: 10px;
}

/* ---------- Auth modal ---------- */
.auth-form { display: flex; flex-direction: column; gap: 14px; margin-top: 4px; }
.auth-form input[type="text"], .auth-form input[type="password"] {
  background: var(--surface-hi);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 14px;
  padding: 12px 14px;
  width: 100%;
  outline: none;
  transition: border-color 0.15s;
}
.auth-form input:focus { border-color: var(--accent); }

/* ---------- Boxed OTP entry ---------- */
.otp-boxes { display: flex; gap: 8px; justify-content: space-between; }
.otp-box {
  width: 100%; aspect-ratio: 1; min-width: 0;
  background: var(--surface-hi);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-family: var(--font-mono); font-size: 22px; font-weight: 700;
  text-align: center; outline: none;
  transition: border-color 0.15s, background 0.15s;
}
.otp-box:focus { border-color: var(--accent); background: var(--surface); }

.pw-field { position: relative; }
.pw-field input { padding-right: 42px; }
.pw-toggle {
  position: absolute; top: 50%; right: 4px; transform: translateY(-50%);
  display: flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: var(--radius-sm);
  background: none; border: none; color: var(--muted); cursor: pointer;
  transition: color 0.15s;
}
.pw-toggle:hover { color: var(--text); }
.pw-toggle svg { width: 18px; height: 18px; }
.auth-error {
  font-size: 12.5px; color: var(--bearish);
  background: rgba(var(--bearish-rgb),0.09);
  border: 1px solid rgba(var(--bearish-rgb),0.3);
  border-radius: var(--radius-sm); padding: 10px 12px;
}
.auth-submit {
  background: var(--accent);
  border: none; border-radius: var(--radius-sm);
  color: #04121c; cursor: pointer;
  font-family: var(--font-body);
  font-size: 14px; font-weight: 700;
  padding: 12px 20px;
  transition: background 0.15s, opacity 0.15s;
}
.auth-submit:hover:not(:disabled) { background: var(--accent-hover); }
.auth-submit:disabled { opacity: 0.5; cursor: default; }
.auth-switch {
  display: block; width: 100%; margin-top: 14px;
  background: none; border: none; cursor: pointer;
  color: var(--muted); font-size: 12px; text-align: center;
  transition: color 0.2s;
}
.auth-switch:hover { color: var(--accent); }
.auth-forgot {
  display: block; width: 100%; margin-top: 10px;
  background: none; border: none; cursor: pointer;
  color: var(--accent); font-size: 12px; text-align: center;
  transition: color 0.2s;
}
.auth-forgot:hover { color: var(--muted-2); }
.auth-info {
  font-size: 12.5px; color: var(--muted-2); line-height: 1.6;
  background: rgba(var(--accent-rgb),0.06);
  border: 1px solid rgba(var(--accent-rgb),0.25);
  border-radius: 10px; padding: 10px 12px;
  margin-top: 4px; margin-bottom: 4px;
}

/* Google Sign-In — the button itself is Google's (rendered by their
   library into .auth-google-btn, dark theme to sit on our surface), so
   the only styling here is the wrapper and the "or" rule between it and
   the password form. Hidden until /auth/google/config says it's on. */
.auth-google { display: flex; flex-direction: column; gap: 16px; margin-bottom: 18px; }
/* A class setting display beats the UA stylesheet's [hidden] rule, so
   without this the wrapper could never actually hide — the divider
   stayed drawn above an empty slot whenever the button was blocked. */
.auth-google[hidden] { display: none; }
.auth-google-btn { display: flex; justify-content: center; min-height: 44px; }
.auth-google-btn > div { width: 100%; max-width: 400px; }
/* The click lands focus on the <iframe> element in OUR document, and the
   browser draws its default focus ring around it — the white box seen on
   click. Google's button inside the iframe carries its own focus style,
   so the outer ring is pure duplication. */
.auth-google-btn iframe, .auth-google-btn iframe:focus, .auth-google-btn div:focus {
  outline: none !important; box-shadow: none !important; border: 0 !important;
}
/* The page is color-scheme:dark (tokens.css) but Google's button document
   is light-scheme. When those disagree on a cross-origin iframe, Chrome
   paints an opaque white canvas behind the iframe — the white rectangle
   that showed around the rounded pill once GIS reloaded the iframe on
   click. Matching the iframe ELEMENT's scheme to the document inside it
   keeps the iframe transparent. */
.auth-google-btn iframe { color-scheme: light; background: transparent !important; }
.auth-google-blocked {
  width: 100%; max-width: 400px;
  padding: 12px 14px;
  background: var(--surface); border: 1px solid var(--border);
  border-left: 3px solid var(--bearish); border-radius: var(--radius-sm);
  font-size: 13px; line-height: 1.55; color: var(--muted-2);
}
.auth-google-blocked strong { color: var(--text); }
.auth-divider {
  display: flex; align-items: center; gap: 12px;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--muted);
}
.auth-divider::before, .auth-divider::after {
  content: ''; flex: 1; height: 1px; background: var(--border);
}

/* Copy shown in place of a password field for Google-only accounts, on
   the profile forms and the Settings delete confirm. */
.profile-reauth-hint {
  font-size: 13px; line-height: 1.55; color: var(--muted-2); margin: 0 0 4px;
}
.settings-google-confirm {
  display: flex; flex-direction: column; gap: 12px;
  margin-top: 12px; padding: 16px;
  background: var(--surface); border: 1px solid var(--border);
  border-left: 3px solid var(--bearish); border-radius: var(--radius-sm);
}
.settings-google-confirm p { margin: 0; font-size: 13.5px; line-height: 1.55; color: var(--muted-2); }
.settings-google-confirm .auth-google-btn { justify-content: flex-start; }
.settings-google-confirm .btn-secondary { align-self: flex-start; }

/* ---- watchlist.css ---- */
/* ---------- Watchlist star button ---------- */
.star-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 48px; height: 48px; flex-shrink: 0;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--muted);
  font-size: 19px; cursor: pointer;
  transition: color 0.15s, border-color 0.15s;
}
.star-btn:hover { color: var(--neutral); border-color: rgba(var(--neutral-rgb),0.4); }
.star-btn.active { color: var(--neutral); background: rgba(var(--neutral-rgb),0.1); border-color: rgba(var(--neutral-rgb),0.45); }

/* ---------- Watchlist panel ---------- */
.watchlist-section { margin-bottom: 20px; }
.watchlist-section-title {
  font-size: 10.5px; color: var(--muted); font-weight: 700;
  letter-spacing: 0.18em; text-transform: uppercase; margin-bottom: 10px;
}
.watchlist-panel { display: flex; gap: 8px; flex-wrap: wrap; }
.watchlist-empty { font-size: 12.5px; color: var(--muted); font-style: italic; }
.watchlist-empty-learn-link { margin-top: 10px; }
.watchlist-chip { display: inline-flex; align-items: center; gap: 8px; }
.watchlist-remove {
  background: none; border: none; cursor: pointer;
  color: var(--muted); font-size: 10px; padding: 0;
  transition: color 0.2s;
}
.watchlist-remove:hover { color: var(--bearish); }

/* ---- portfolio.css ---- */
/* ---------- Portfolio ---------- */
.portfolio-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 24px 26px;
  margin-bottom: 20px;
  box-shadow: var(--shadow);
}
.portfolio-header { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 16px; }
.portfolio-title { font-family: var(--font-body); font-size: 15px; font-weight: 600; }
.portfolio-total { font-family: var(--font-mono); font-size: 14px; font-weight: 700; }
.portfolio-total.up { color: var(--bullish); }
.portfolio-total.down { color: var(--bearish); }

.portfolio-form { display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end; margin-bottom: 18px; }
.portfolio-form .form-group { gap: 6px; }
.portfolio-form select, .portfolio-form input[type="text"], .portfolio-form input[type="number"] {
  background: var(--surface-hi);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 13px; font-weight: 600;
  padding: 10px 12px;
  width: 130px;
  outline: none;
}
/* See alerts.css for why this is needed — the dropdown popup doesn't
   composite with the page, so it needs its own opaque dark background. */
.portfolio-form select option {
  background: var(--surface-hi);
  color: var(--text);
}
.portfolio-add-btn {
  background: var(--accent);
  border: none; border-radius: var(--radius-sm);
  color: #04121c; cursor: pointer;
  font-family: var(--font-body); font-size: 13px; font-weight: 700;
  padding: 10px 20px;
  transition: background 0.15s, opacity 0.15s;
}
.portfolio-add-btn:hover:not(:disabled) { background: var(--accent-hover); }
.portfolio-add-btn:disabled { opacity: 0.5; cursor: default; }

.portfolio-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.portfolio-table th {
  text-align: left; font-size: 10px; font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--muted); padding: 8px 10px;
  border-bottom: 1px solid rgba(var(--overlay-rgb),0.08);
}
.portfolio-table td { padding: 10px; border-bottom: 1px solid rgba(var(--overlay-rgb),0.05); font-family: var(--font-mono); color: var(--muted-2); }
.portfolio-table td.up { color: var(--bullish); }
.portfolio-table td.down { color: var(--bearish); }
.portfolio-remove { background: none; border: none; cursor: pointer; color: var(--muted); font-size: 11px; }
.portfolio-remove:hover { color: var(--bearish); }
.portfolio-empty { font-size: 13px; color: var(--muted); font-style: italic; }

/* ---------- Asset Allocation (donut) ---------- */
.portfolio-allocation-section:empty { display: none; }
.portfolio-allocation-section { margin-top: 24px; padding-top: 20px; border-top: 1px solid var(--border); }
.portfolio-allocation-title { font-family: var(--font-disp); font-size: 15px; font-weight: 700; margin-bottom: 4px; }
.portfolio-allocation-sub { font-size: 12.5px; color: var(--muted); line-height: 1.6; margin-bottom: 4px; }
.portfolio-allocation-learn-link { margin-top: 14px; text-align: center; }

/* ---------- Real Exchange Account (read-only Binance link) ---------- */
.exchange-account-section { margin-top: 24px; padding-top: 20px; border-top: 1px solid var(--border); }
.exchange-account-title { font-family: var(--font-disp); font-size: 15px; font-weight: 700; margin-bottom: 4px; }
.exchange-account-sub { font-size: 12.5px; color: var(--muted); line-height: 1.6; margin-bottom: 16px; }

.exchange-security-note {
  background: rgba(var(--accent-rgb),0.07); border: 1px solid rgba(var(--accent-rgb),0.25);
  border-radius: var(--radius-sm); padding: 12px 14px; font-size: 12px; color: var(--muted-2);
  line-height: 1.6; margin-bottom: 16px; display: flex; gap: 10px;
}
.exchange-security-note svg { flex: none; width: 16px; height: 16px; color: var(--accent); margin-top: 1px; }
.exchange-security-note b { color: var(--text); }

.exchange-link-form { display: flex; flex-direction: column; gap: 6px; max-width: 420px; }
.exchange-link-form .field-label {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--muted); margin-top: 6px;
}
.exchange-link-form .field-label:first-child { margin-top: 0; }
.exchange-link-form .field {
  background: var(--surface-hi); border: 1px solid var(--border); border-radius: var(--radius-sm);
  color: var(--text); font-family: var(--font-mono); font-size: 13px; padding: 10px 12px; outline: none;
}
.exchange-link-form .field:focus { border-color: var(--accent); }
.exchange-link-form .portfolio-add-btn { margin-top: 10px; width: 100%; text-align: center; }
.exchange-link-error { color: var(--bearish); font-size: 12px; }
.exchange-link-hint { font-size: 11px; color: var(--muted); margin-top: 8px; max-width: 420px; }

.exchange-connected-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 16px; }
.exchange-connected-id { display: flex; align-items: center; gap: 10px; }
.exchange-connected-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--bullish); box-shadow: 0 0 8px rgba(var(--bullish-rgb),0.6); flex: none; }
.exchange-connected-dot.warn { background: var(--bearish); box-shadow: 0 0 8px rgba(var(--bearish-rgb),0.5); }
.exchange-connected-key { font-family: var(--font-mono); font-size: 13px; font-weight: 700; }
.exchange-verified-pill {
  font-family: var(--font-mono); font-size: 9.5px; font-weight: 700; padding: 3px 8px; border-radius: 999px;
  background: rgba(var(--bullish-rgb),0.14); color: var(--bullish); letter-spacing: 0.04em;
}
.exchange-connected-actions { display: flex; gap: 8px; }
.exchange-unlink-btn {
  background: none; border: 1px solid var(--border); color: var(--bearish);
  font-family: var(--font-body); font-size: 11.5px; font-weight: 700; padding: 7px 14px;
  border-radius: var(--radius-sm); cursor: pointer; transition: border-color 0.15s;
}
.exchange-unlink-btn:hover { border-color: var(--bearish); }

.exchange-warning-note {
  background: rgba(var(--bearish-rgb),0.08); border: 1px solid rgba(var(--bearish-rgb),0.3);
  border-radius: var(--radius-sm); padding: 10px 12px; font-size: 11.5px; color: var(--muted-2);
  line-height: 1.6; margin-bottom: 16px;
}
.exchange-warning-note b { color: var(--bearish); }

.exchange-subsection-title {
  font-size: 11px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--muted); margin: 20px 0 10px;
}
.exchange-subsection-title:first-child { margin-top: 0; }

.exchange-balance-row {
  display: flex; align-items: center; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--border);
}
.exchange-balance-row:last-child { border-bottom: none; }
.exchange-balance-info { flex: 1; min-width: 0; }
.exchange-balance-symbol { font-family: var(--font-mono); font-size: 12.5px; font-weight: 700; color: var(--text); }
.exchange-balance-sub { font-size: 10.5px; color: var(--muted); margin-top: 1px; }
.exchange-balance-total { font-family: var(--font-mono); font-size: 13px; font-weight: 700; }

.exchange-position-card {
  background: var(--surface-hi); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 16px; margin-bottom: 10px;
}
.exchange-position-card:last-child { margin-bottom: 0; }
.exchange-position-top { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; flex-wrap: wrap; }
.exchange-position-top b { font-size: 13px; }
.exchange-live-badge {
  margin-left: auto; font-family: var(--font-mono); font-size: 9px; font-weight: 700; letter-spacing: 0.06em;
  color: var(--bullish); border: 1px solid rgba(var(--bullish-rgb),0.35); padding: 3px 7px; border-radius: 5px;
}
.exchange-position-pnl { font-family: var(--font-mono); font-weight: 800; font-size: 22px; line-height: 1; margin-bottom: 2px; }
.exchange-position-pnl.up { color: var(--bullish); }
.exchange-position-pnl.down { color: var(--bearish); }
.exchange-position-pnl-sub { font-size: 11px; color: var(--muted); margin-bottom: 14px; }
.exchange-position-rows { display: flex; flex-direction: column; gap: 8px; }
.exchange-position-row { display: flex; justify-content: space-between; font-size: 11.5px; gap: 12px; }
.exchange-position-row span:first-child { color: var(--muted); flex-shrink: 0; }
.exchange-position-row span:last-child { font-family: var(--font-mono); font-weight: 700; color: var(--text); text-align: right; }

/* ---------- Trade History (diffed position snapshots) ---------- */
.exchange-history-title-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.exchange-history-note {
  font-size: 11px; color: var(--muted); line-height: 1.5; margin-bottom: 12px; font-style: italic;
}
.exchange-closed-badge {
  margin-left: auto; font-family: var(--font-mono); font-size: 9px; font-weight: 700; letter-spacing: 0.06em;
  color: var(--muted); border: 1px solid var(--border); padding: 3px 7px; border-radius: 5px;
}
.exchange-trade-card .exchange-position-top .exchange-closed-badge { margin-left: auto; }

.exchange-report-btn { font-size: 11px; padding: 6px 12px; }

/* ---------- Trade history report (modal) ---------- */
.exchange-report-modal { max-width: 640px; width: 92vw; max-height: 86vh; overflow-y: auto; }
.exchange-report-modal-head { align-items: center; }
.exchange-report-modal-actions { display: flex; align-items: center; gap: 10px; }
.exchange-report-print-btn { font-size: 11px; padding: 6px 12px; }
.exchange-report-empty { font-size: 13px; color: var(--muted); font-style: italic; padding: 20px 0; }
.exchange-report-note {
  font-size: 11.5px; color: var(--muted); line-height: 1.6; margin-bottom: 18px; font-style: italic;
}
.exchange-report-print-title { display: none; }
.exchange-report-print-sub { display: none; }

.exchange-report-stat-grid {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; margin-bottom: 24px;
}
.exchange-report-stat {
  background: var(--surface-hi); border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 12px 14px; display: flex; flex-direction: column; gap: 4px;
}
.exchange-report-stat-label {
  font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted);
}
.exchange-report-stat-val { font-family: var(--font-mono); font-size: 16px; font-weight: 700; color: var(--text); }
.exchange-report-stat-val.up { color: var(--bullish); }
.exchange-report-stat-val.down { color: var(--bearish); }

.exchange-report-chart-title {
  font-size: 11px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 10px;
}
#exchange-report-equity-chart canvas { width: 100%; display: block; }

/* Everything else on the page (nav, bottom tabs, the rest of Portfolio,
   the modal's own buttons) is hidden on print — only the report content
   itself should end up on paper. window.print() is the entire "PDF
   export" feature (see portfolio.js's openBinanceHistoryReport comment
   for why no PDF library was added): the browser's own "Save as PDF"
   print destination does the job for free. A light background is forced
   here specifically, even though the app stays dark everywhere else on
   screen, since printing this page's near-black background would waste
   ink and look bad on actual paper. */
@media print {
  /* The dark app background sits on html/body and every wrapper, and that
     paints onto EVERY printed page, not just the first. Forcing the whole
     document white (not just the report) is what stops the blank black page. */
  html, body, body * { background: #fff !important; }
  html, body { height: auto !important; min-height: 0 !important; overflow: visible !important; }
  body * { visibility: hidden; }
  #exchange-report-modal-backdrop,
  #exchange-report-modal-backdrop * { visibility: visible; }
  #exchange-report-modal-backdrop {
    position: static !important; inset: auto !important; height: auto !important;
    background: #fff !important; display: block;
    padding: 0; margin: 0;
  }
  .exchange-report-modal {
    position: static; max-width: none; width: auto; max-height: none; overflow: visible;
    background: #fff !important; border: none; box-shadow: none; padding: 0; margin: 0;
  }
  .exchange-report-modal-head, .modal-close, .exchange-report-print-btn { display: none !important; }
  .exchange-report-print-title, .exchange-report-print-sub { display: block !important; }
  .exchange-report-print-title { font-size: 20px; font-weight: 800; color: #111; margin: 0 0 4px; }
  .exchange-report-print-sub { font-size: 11px; color: #555; margin: 0 0 20px; }
  .exchange-report-print-area { padding: 24px; color: #111; }
  .exchange-report-note { color: #555; }
  .exchange-report-stat {
    background: #f4f5f7 !important; border: 1px solid #ddd; break-inside: avoid;
  }
  .exchange-report-stat-label { color: #666; }
  .exchange-report-stat-val { color: #111; }
  .exchange-report-stat-val.up { color: #0a7a4f; }
  .exchange-report-stat-val.down { color: #b3273f; }
  .exchange-report-chart-title { color: #444; break-before: avoid; }
  #exchange-report-equity-chart { break-inside: avoid; }
}

.exchange-history-actions { display: inline-flex; gap: 8px; }

.perf-section { background: var(--surface); border: 1px solid var(--surface-hi); border-radius: 12px; padding: 14px; margin: 10px 0 14px; }
.perf-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.perf-tab { font: inherit; font-size: 11.5px; padding: 6px 10px; border-radius: 999px; border: 1px solid var(--surface-hi); background: transparent; color: var(--muted); cursor: pointer; }
.perf-tab.active { background: var(--text); color: var(--bg); border-color: var(--text); }
.perf-tab:focus-visible { outline: 2px solid var(--bullish); outline-offset: 2px; }
.perf-panel[hidden] { display: none; }
.perf-kicker { font-size: 11px; color: var(--muted); letter-spacing: 0.06em; text-transform: uppercase; }
.perf-gap { margin-top: 16px; }
.perf-big { font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 34px; font-weight: 700; margin-top: 4px; }
.perf-big-sm { font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 22px; font-weight: 700; margin-top: 4px; }
.perf-note { font-size: 12.5px; color: var(--muted); line-height: 1.5; margin: 12px 0 0; }
.perf-curve { width: 100%; height: 90px; display: block; margin-top: 12px; }
.perf-panel-curve .perf-curve { height: 180px; }
.perf-tiles3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-top: 12px; }
.perf-tiles2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.perf-tile { background: var(--bg); border-radius: 10px; padding: 10px; display: flex; flex-direction: column; gap: 4px; }
.perf-tile-val { font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 15px; font-weight: 700; }
.perf-row { display: flex; justify-content: space-between; align-items: center; padding: 10px 0; border-bottom: 1px solid var(--surface-hi); }
.perf-row:last-child { border-bottom: 0; }
.perf-row-sym { font-weight: 600; font-size: 14px; }
.perf-row-sub { font-size: 11px; color: var(--muted); margin-top: 2px; }
.perf-row-pnl { font-family: 'JetBrains Mono', ui-monospace, monospace; font-weight: 700; }
.perf-sheet { background: var(--bg); border-radius: 14px 14px 0 0; margin-top: 14px; padding: 8px 12px 4px; border-top: 1px solid var(--surface-hi); }
.perf-sheet-grab { width: 36px; height: 4px; border-radius: 999px; background: var(--surface-hi); margin: 0 auto 8px; }
.perf-ledger-head, .perf-ledger-row { display: grid; grid-template-columns: 1.6fr 0.8fr 0.6fr 1fr; gap: 6px; font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 12px; padding: 8px 4px; }
.perf-ledger-head { font-size: 10px; color: var(--muted); border-bottom: 1px solid var(--surface-hi); }
.perf-ledger-row { border-bottom: 1px solid var(--surface-hi); }
.perf-ledger-day { font-size: 10px; color: var(--muted); letter-spacing: 0.06em; padding: 12px 4px 4px; }
.perf-serif-kicker, .perf-serif-label { font-size: 12px; color: var(--muted); }
.perf-serif-big, .perf-serif-num { font-family: Georgia, 'Times New Roman', serif; line-height: 1; }
.perf-serif-big { font-size: 56px; margin-top: 8px; }
.perf-serif-num { font-size: 30px; margin-top: 4px; }
.perf-serif-lede { font-size: 14px; color: var(--muted); line-height: 1.6; margin: 12px 0 0; }
.perf-serif-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px 16px; margin-top: 18px; }
.perf-heat { display: grid; grid-template-rows: 14px repeat(7, auto); gap: 3px; margin-top: 12px; align-items: center; }
.perf-cell { border-radius: 3px; background: var(--surface-hi); aspect-ratio: 1; min-width: 0; padding: 0; border: 0; }
.perf-month { font-size: 10px; color: var(--muted); align-self: end; white-space: nowrap; }
.perf-weekday { font-size: 10px; color: var(--muted); }
.perf-heat-foot { display: flex; justify-content: space-between; align-items: center; font-size: 11px; color: var(--muted); margin-top: 10px; }
.perf-legend { display: inline-flex; align-items: center; gap: 4px; }
.perf-legend i { display: inline-block; width: 9px; height: 9px; border-radius: 2px; margin-left: 6px; }
.perf-ring-wrap { display: flex; align-items: center; gap: 18px; }
.perf-ring { flex-shrink: 0; }
.perf-ring-val { font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 22px; font-weight: 700; fill: var(--text); }
.perf-ring-lbl { font-size: 10px; fill: var(--muted); }
.perf-bar-row { display: flex; align-items: center; gap: 10px; margin-top: 10px; }
.perf-bar-sym { width: 80px; font-size: 13px; font-weight: 600; }
.perf-bar-track { flex: 1; height: 8px; background: var(--bg); border-radius: 999px; overflow: hidden; }
.perf-bar-fill { height: 100%; border-radius: 999px; background: var(--muted); }
.perf-bar-fill.up { background: var(--bullish); }
.perf-bar-fill.down { background: var(--bearish); }
.perf-bar-val { width: 70px; text-align: right; font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 12px; font-weight: 700; }
.perf-statement-head { display: flex; justify-content: space-between; font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 11px; color: var(--muted); padding-bottom: 8px; border-bottom: 1px dashed var(--surface-hi); }
.perf-statement-cols { display: grid; grid-template-columns: 1.1fr 1fr 0.9fr; font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 10px; color: var(--muted); margin-top: 16px; padding-bottom: 6px; border-bottom: 1px solid var(--surface-hi); }
.perf-statement-row { display: grid; grid-template-columns: 1.1fr 1fr 0.9fr; gap: 6px; align-items: center; padding: 10px 0; border-bottom: 1px dashed var(--surface-hi); font-size: 12px; }
.perf-mono-sm { font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 10.5px; color: var(--muted); }
.perf-statement-sym { font-family: Inter, sans-serif; font-size: 13px; color: var(--text); }
.perf-statement-pos { color: var(--muted); font-size: 11.5px; line-height: 1.5; }
.perf-statement-amt { text-align: right; font-family: 'JetBrains Mono', ui-monospace, monospace; font-weight: 700; }
.perf-split { display: flex; height: 10px; border-radius: 999px; overflow: hidden; gap: 2px; margin-top: 8px; }
.perf-split-win { background: var(--bullish); }
.perf-split-loss { background: var(--bearish); }
.perf-light { background: #f5f6f8; color: #0d1117; border-radius: 14px; padding: 16px; }
.perf-light-kicker { font-size: 11px; color: #5b6472; }
.perf-light-big { font-family: Georgia, 'Times New Roman', serif; font-size: 44px; line-height: 1; margin-top: 6px; color: #0d1117; }
.perf-light-big.up { color: #0f7a4f; }
.perf-light-big.down { color: #b42318; }
.perf-light-lede { font-size: 12.5px; color: #5b6472; line-height: 1.5; margin: 10px 0 0; }
.perf-light-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 14px; }
.perf-light .perf-tile { background: #ffffff; border: 1px solid #dfe3ea; }
.perf-light .perf-tile .perf-kicker { color: #5b6472; }
.perf-light .perf-tile-val .down { color: #b42318; }
.perf-light-list { background: #ffffff; border: 1px solid #dfe3ea; border-radius: 10px; margin-top: 12px; padding: 0 12px; }
.perf-light .perf-row, .perf-light .perf-row-sub { border-color: #eef0f4; color: #5b6472; }
.perf-light .perf-row-sym { color: #0d1117; }
.perf-light .up { color: #0f7a4f; }
.perf-light .down { color: #b42318; }

.perf-tabs { flex-wrap: wrap; }
.perf-tab { min-height: 36px; padding: 8px 14px; flex-shrink: 0; transition: transform .15s ease, background .2s ease, color .2s ease; -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
.perf-tab:active { transform: scale(.95); }
.perf-curve-wrap { position: relative; touch-action: pan-y; user-select: none; -webkit-user-select: none; }
.perf-curve-cursor { position: absolute; top: 0; bottom: 0; width: 1px; background: var(--muted); transform: translateX(-50%); pointer-events: none; opacity: .7; }
.perf-curve-tip { position: absolute; top: 4px; transform: translateX(-50%); display: flex; flex-direction: column; gap: 2px; background: var(--surface-hi); border-radius: 8px; padding: 6px 9px; font-size: 11px; color: var(--muted); white-space: nowrap; pointer-events: none; box-shadow: 0 6px 18px rgba(0,0,0,0.25); }
.perf-curve-tip b { font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 13px; color: var(--text); }
.perf-curve-tip b.up { color: var(--bullish); }
.perf-curve-tip b.down { color: var(--bearish); }
.perf-curve-cursor[hidden], .perf-curve-tip[hidden], .perf-detail[hidden], .perf-day[hidden] { display: none; }
.perf-draw { stroke-dasharray: 1; stroke-dashoffset: 0; animation: perfDraw 1.1s cubic-bezier(.3,.6,.2,1) both; }
.perf-curve-area { animation: perfFade .9s .25s both; }
.perf-panel:not([hidden]) > * { animation: perfRise .5s cubic-bezier(.2,.7,.2,1) both; }
.perf-panel:not([hidden]) > :nth-child(2) { animation-delay: .06s; }
.perf-panel:not([hidden]) > :nth-child(3) { animation-delay: .12s; }
.perf-panel:not([hidden]) > :nth-child(4) { animation-delay: .18s; }
.perf-panel:not([hidden]) > :nth-child(5) { animation-delay: .24s; }
.perf-panel:not([hidden]) > :nth-child(6) { animation-delay: .3s; }
.perf-panel:not([hidden]) > :nth-child(7) { animation-delay: .36s; }
.perf-panel:not([hidden]) > :nth-child(8) { animation-delay: .42s; }
.perf-ring-arc { stroke-dasharray: 352; animation: perfRing 1.2s cubic-bezier(.2,.7,.2,1) .15s both; }
.perf-bar-fill { transform-origin: left center; animation: perfGrow .9s cubic-bezier(.2,.7,.2,1) .2s both; }
.perf-split-win, .perf-split-loss { transform-origin: left center; animation: perfGrow .9s cubic-bezier(.2,.7,.2,1) .15s both; }
.perf-split-loss { animation-delay: .3s; }
.perf-cell { animation: perfPop .4s cubic-bezier(.2,.8,.2,1) var(--d, 0ms) both; transition: transform .15s ease, box-shadow .2s ease; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.perf-cell-empty { background: var(--surface-hi); cursor: default; }
.perf-cell:not(.perf-cell-empty):active { transform: scale(.85); }
.perf-cell.is-selected { box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--text); }
.perf-cell:focus-visible { outline: 2px solid var(--bullish); outline-offset: 2px; }
.perf-day { min-height: 48px; margin-top: 12px; padding: 10px 12px; background: var(--bg); border-radius: 10px; }
.perf-day-date { font-size: 12px; color: var(--muted); }
.perf-day-main { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; margin-top: 4px; flex-wrap: wrap; }
.perf-day-pnl { font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 20px; font-weight: 700; }
.perf-day-meta { font-size: 11.5px; color: var(--muted); }
.perf-day-empty { font-size: 12px; color: var(--muted); }
[data-perf-trade] { cursor: pointer; transition: background .2s ease, transform .15s ease; -webkit-tap-highlight-color: transparent; border-radius: 8px; }
[data-perf-trade]:active { background: var(--surface-hi); transform: scale(.985); }
[data-perf-trade].is-selected { background: var(--surface-hi); }
[data-perf-trade]:focus-visible { outline: 2px solid var(--bullish); outline-offset: 2px; }
.perf-detail { margin-top: 14px; padding: 14px; background: var(--bg); border: 1px solid var(--surface-hi); border-radius: 12px; }
.perf-detail-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 15px; }
.perf-detail-pnl { font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 28px; font-weight: 700; margin-top: 8px; }
.perf-detail-grid { display: grid; grid-template-columns: auto 1fr; gap: 8px 16px; margin-top: 12px; font-size: 12.5px; }
.perf-detail-grid span { color: var(--muted); }
.perf-detail-grid b { text-align: right; font-family: 'JetBrains Mono', ui-monospace, monospace; font-weight: 600; }
.perf-detail.show, .perf-day.show { animation: perfSlide .35s cubic-bezier(.2,.7,.2,1) both; }

@keyframes perfRise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes perfPop { from { opacity: 0; transform: scale(.4); } to { opacity: 1; transform: none; } }
@keyframes perfGrow { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes perfRing { from { stroke-dashoffset: 352; } to { stroke-dashoffset: var(--off); } }
@keyframes perfDraw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes perfFade { from { opacity: 0; } to { opacity: 1; } }
@keyframes perfSlide { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  .perf-section, .perf-section * { animation: none !important; transition: none !important; }
}
.exchange-report-print-brand { display: none; }
@media print {
  .exchange-report-print-brand { display: flex !important; align-items: center; gap: 10px; margin-bottom: 14px; font-family: 'Space Grotesk', Arial, sans-serif; font-size: 18px; font-weight: 700; color: #111; }
}

/* ---- demo.css ---- */
/* ---------- Demo Trading ---------- */
/* A trading-terminal layout: live-priced asset browser on one side, a
   Binance/Groww-style buy/sell order ticket on the other. Positions and
   history below reuse .portfolio-table (see portfolio.css) so the two
   features still share one visual language for tabular data. */

.demo-topbar {
  display: flex; align-items: center; flex-wrap: wrap; gap: 14px;
  margin-bottom: 6px;
}
.demo-title { font-family: var(--font-body); font-size: 15px; font-weight: 600; }
.demo-topbar-stats { display: flex; gap: 10px; flex-wrap: wrap; margin-left: auto; }
.demo-stat {
  background: var(--surface-hi);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 6px 12px;
  display: flex; flex-direction: column; gap: 2px;
  min-width: 92px;
}
.demo-stat-label { font-size: 9px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
.demo-stat-value { font-family: var(--font-mono); font-size: 13px; font-weight: 700; }
.demo-stat-value.up { color: var(--bullish); }
.demo-stat-value.down { color: var(--bearish); }

.demo-reset-btn {
  background: none;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--muted);
  cursor: pointer;
  font-family: var(--font-body); font-size: 12px; font-weight: 600;
  padding: 7px 14px;
  transition: border-color 0.15s, color 0.15s;
}
.demo-reset-btn:hover:not(:disabled) { border-color: var(--bearish); color: var(--bearish); }
.demo-reset-btn:disabled { opacity: 0.5; cursor: default; }

/* ---------- Terminal: asset browser + order ticket ---------- */
.demo-terminal {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 16px;
  margin: 16px 0 26px;
  align-items: start;
}

.demo-browser {
  background: var(--surface-hi);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px;
}
/* Same component as .market-tab (layout.css, the Analyze page's own
   market row) — same shape and active-state treatment, so the two
   don't read as two different design languages within the same app. */
.demo-market-tabs { display: flex; gap: 8px; margin-bottom: 10px; flex-wrap: wrap; }
.demo-market-tab {
  font: inherit; outline: none; cursor: pointer;
  font-family: var(--font-body); font-size: 12px; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--muted-2);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 9px 18px;
  transition: border-color 0.15s, color 0.15s;
}
.demo-market-tab:hover { color: var(--text); border-color: var(--border-hi); }
.demo-market-tab.active { color: var(--accent); border-color: var(--accent); background: var(--surface-hi); }

.demo-search {
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-family: var(--font-mono); font-size: 13px;
  padding: 10px 12px;
  margin-bottom: 10px;
  outline: none;
  box-sizing: border-box;
}
.demo-search:focus { border-color: var(--accent); }

.demo-asset-list {
  max-height: 420px;
  overflow-y: auto;
  display: flex; flex-direction: column; gap: 2px;
}
.demo-asset-row {
  display: flex; align-items: center; gap: 10px;
  width: 100%;
  background: none; border: 1px solid transparent; border-radius: var(--radius-sm);
  cursor: pointer;
  padding: 8px 10px;
  text-align: left;
  transition: background 0.12s, border-color 0.12s;
}
.demo-asset-row:hover { background: var(--surface); }
.demo-asset-row.selected { background: rgba(var(--accent-rgb),0.1); border-color: var(--accent); }
.demo-asset-row-custom { border-style: dashed; border-color: var(--border); }
.demo-asset-row-custom:hover { border-color: var(--muted-2); }
.demo-asset-row-custom .demo-asset-name { font-style: italic; }

.demo-avatar {
  flex: none;
  width: 30px; height: 30px;
  border-radius: 50%;
  border: 1px solid;
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-body); font-size: 11px; font-weight: 700;
}
.demo-asset-info { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.demo-asset-symbol { font-family: var(--font-mono); font-size: 12.5px; font-weight: 700; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.demo-asset-name { font-size: 10.5px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.demo-asset-price-col { display: flex; flex-direction: column; align-items: flex-end; gap: 1px; flex: none; }
.demo-asset-price { font-family: var(--font-mono); font-size: 12.5px; font-weight: 700; color: var(--text); }
.demo-asset-chg { font-family: var(--font-mono); font-size: 10.5px; font-weight: 600; }
.demo-asset-chg.up { color: var(--bullish); }
.demo-asset-chg.down { color: var(--bearish); }

/* ---------- Order ticket ---------- */
.demo-ticket {
  background: var(--surface-hi);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px;
  position: sticky;
  top: 16px;
}
.demo-ticket-head { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; }
.demo-ticket-symbol { font-family: var(--font-mono); font-size: 15px; font-weight: 700; }
.demo-ticket-price { font-family: var(--font-mono); font-size: 12px; color: var(--muted); }

.demo-side-toggle { display: flex; gap: 6px; margin-bottom: 12px; }
.demo-side-btn {
  flex: 1;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--muted-2);
  cursor: pointer;
  font-family: var(--font-body); font-size: 13px; font-weight: 700;
  padding: 10px 0;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.demo-side-btn.demo-side-buy.active { background: rgba(var(--bullish-rgb),0.16); border-color: var(--bullish); color: var(--bullish); }
.demo-side-btn.demo-side-sell.active { background: rgba(var(--bearish-rgb),0.16); border-color: var(--bearish); color: var(--bearish); }

.demo-avail-row, .demo-est-row {
  display: flex; justify-content: space-between; align-items: center;
  font-size: 12px; color: var(--muted);
  margin-bottom: 6px;
}
.demo-est-row { margin-top: 10px; font-weight: 600; color: var(--muted-2); }
.demo-est-row span:last-child { font-family: var(--font-mono); color: var(--text); }

.demo-ticket .field-label { margin-top: 4px; }
.demo-qty-label-row { display: flex; justify-content: space-between; align-items: center; margin-top: 4px; }
.demo-qty-label-row .field-label { margin-top: 0; }
.demo-qty-mode-toggle { display: flex; gap: 4px; }
.demo-qty-mode-btn {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--muted-2);
  cursor: pointer;
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 700;
  padding: 3px 9px;
  transition: border-color 0.15s, color 0.15s;
}
.demo-qty-mode-btn.active { border-color: var(--accent); color: var(--accent); }
.demo-qty-input {
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-family: var(--font-mono); font-size: 15px; font-weight: 600;
  padding: 10px 12px;
  margin: 6px 0 8px;
  outline: none;
  box-sizing: border-box;
}
.demo-qty-input:focus { border-color: var(--accent); }

.demo-qty-pct { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; margin-bottom: 8px; }
.demo-pct-btn {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--muted-2);
  cursor: pointer;
  font-family: var(--font-mono); font-size: 11px; font-weight: 700;
  padding: 6px 0;
  transition: border-color 0.15s, color 0.15s;
}
.demo-pct-btn:hover { border-color: var(--accent); color: var(--text); }

.demo-ticket-error { color: var(--bearish); font-size: 12px; margin-bottom: 8px; }

.demo-place-btn {
  width: 100%;
  border: none; border-radius: var(--radius-sm);
  cursor: pointer;
  font-family: var(--font-body); font-size: 14px; font-weight: 700;
  padding: 13px 0;
  transition: filter 0.15s, opacity 0.15s;
}
.demo-place-btn:disabled { opacity: 0.5; cursor: default; }
.demo-place-buy { background: var(--bullish); color: #05261c; }
.demo-place-buy:hover:not(:disabled) { filter: brightness(1.08); }
.demo-place-sell { background: var(--bearish); color: #2a0a10; }
.demo-place-sell:hover:not(:disabled) { filter: brightness(1.08); }

/* ---------- Positions / history ---------- */
.demo-positions-title, .demo-history-title {
  font-family: var(--font-body); font-size: 13px; font-weight: 600;
  color: var(--muted); margin: 22px 0 10px;
}
.demo-sell-btn {
  background: none;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--bearish);
  cursor: pointer;
  font-family: var(--font-body); font-size: 11px; font-weight: 700;
  padding: 4px 10px;
}
.demo-sell-btn:hover { border-color: var(--bearish); }

@media (max-width: 760px) {
  .demo-terminal { grid-template-columns: 1fr; }
  .demo-ticket { position: static; }
  .demo-asset-list { max-height: 320px; }
}
@media (max-width: 620px) {
  .demo-topbar-stats { width: 100%; margin-left: 0; }
  .demo-stat { flex: 1; min-width: 0; }
}

/* ---------- Spot / Futures mode toggle ---------- */
.demo-mode-toggle {
  display: inline-flex; background: var(--surface-hi); border: 1px solid var(--border);
  border-radius: 999px; padding: 3px; margin: 4px 0 14px; gap: 2px;
}
.demo-mode-btn {
  font-family: var(--font-mono); font-size: 11.5px; font-weight: 700; letter-spacing: 0.02em;
  padding: 8px 18px; border-radius: 999px; border: none; background: none; color: var(--muted);
  cursor: pointer; transition: background 0.15s, color 0.15s;
}
.demo-mode-btn.active { background: var(--accent); color: #04121c; }

/* ---------- Futures: open-position form ----------
 * Same terminal shell as Spot's own .demo-terminal (left form, right
 * content) — a plain single-column stack instead: the form's own fields
 * (leverage/margin sliders especially) need full width to be usable,
 * and positions render as EITHER a table or hero cards below (see the
 * responsive split further down), neither of which wants to share a
 * cramped side-by-side row with the form on a laptop-width screen. */
.futures-terminal { margin: 4px 0 8px; }
.futures-form {
  background: var(--surface-hi); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 16px; max-width: 420px; margin: 0 auto; display: flex; flex-direction: column; gap: 14px;
}
.futures-field { display: flex; flex-direction: column; gap: 6px; }
.futures-field-label {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted);
}
.futures-select {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm);
  color: var(--text); font-family: var(--font-mono); font-size: 14px; font-weight: 600;
  padding: 10px 12px; outline: none; width: 100%;
}
.futures-select:focus { border-color: var(--accent); }
.futures-price-preview { font-family: var(--font-mono); font-size: 12px; color: var(--muted); margin-top: -8px; }

/* ---------- Symbol search ("all coins", not just the ticker tape) ---------- */
.futures-symbol-picker { position: relative; }
.futures-symbol-dropdown {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 5;
  max-height: 240px; overflow-y: auto; padding: 4px;
  background: var(--surface-hi); border: 1px solid var(--border-hi); border-radius: var(--radius-sm);
  box-shadow: var(--shadow);
}
.futures-symbol-option {
  display: flex; align-items: baseline; gap: 8px; width: 100%; text-align: left;
  background: none; border: none; cursor: pointer; border-radius: 6px;
  padding: 8px 10px; font-family: var(--font-body);
}
.futures-symbol-option:hover { background: rgba(var(--overlay-rgb),0.06); }
.futures-symbol-option-sym { font-family: var(--font-mono); font-size: 13px; font-weight: 700; color: var(--text); }
.futures-symbol-option-name { font-size: 11px; color: var(--muted); }
.futures-symbol-empty { padding: 10px; font-size: 12px; color: var(--muted); text-align: center; }

.futures-side-toggle { display: flex; gap: 6px; }
.futures-side-btn, .futures-mode-btn {
  flex: 1; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm);
  color: var(--muted-2); cursor: pointer; font-family: var(--font-body); font-size: 13px; font-weight: 700;
  padding: 10px 0; transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.futures-side-btn.long.active { background: rgba(var(--bullish-rgb),0.16); border-color: var(--bullish); color: var(--bullish); }
.futures-side-btn.short.active { background: rgba(var(--bearish-rgb),0.16); border-color: var(--bearish); color: var(--bearish); }
.futures-mode-btn.active { background: rgba(var(--accent-secondary-rgb),0.16); border-color: var(--accent-secondary); color: var(--accent-secondary); }
.futures-hedge-note { font-size: 10.5px; color: var(--muted); line-height: 1.4; margin-top: 2px; }

.futures-lev-row { display: flex; align-items: center; gap: 12px; }
.futures-lev-val { font-family: var(--font-mono); font-weight: 700; font-size: 14px; min-width: 42px; text-align: right; }

/* ---------- Direct margin entry ---------- */
.futures-margin-input-row { display: flex; gap: 6px; }
.futures-margin-input {
  flex: 1; min-width: 0; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm);
  color: var(--text); font-family: var(--font-mono); font-size: 14px; font-weight: 600;
  padding: 10px 12px; outline: none;
}
.futures-margin-input:focus { border-color: var(--accent); }
.futures-unit-toggle { display: flex; border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden; flex-shrink: 0; }
.futures-unit-btn {
  background: var(--surface); border: none; border-left: 1px solid var(--border); color: var(--muted);
  cursor: pointer; font-family: var(--font-mono); font-size: 11.5px; font-weight: 700;
  padding: 0 12px; transition: background 0.15s, color 0.15s;
}
.futures-unit-btn:first-child { border-left: none; }
.futures-unit-btn.active { background: rgba(var(--accent-rgb),0.14); color: var(--accent); }
.futures-margin-avail { font-size: 11px; font-weight: 500; color: var(--muted); margin-top: -2px; }

/* ---------- Sliders (leverage + margin) ----------
   A native <input type=range> — real keyboard/touch drag support for
   free instead of hand-rolling pointer tracking, which a full re-render
   on every drag tick would fight with anyway (see demo.js's
   futuresUpdatePreview for why that's surgical). Styled to match the
   reference: a thin neutral track, a colored "filled so far" segment
   driven by the --fill custom property (see demo.js's
   futuresSetSliderFill), and a diamond thumb (a square rotated 45°) —
   Binance's own margin/size slider uses the same shape. */
.futures-range {
  --fill: 0%;
  -webkit-appearance: none; appearance: none; width: 100%; height: 3px; border-radius: 2px;
  background: linear-gradient(to right, var(--accent) var(--fill), rgba(var(--overlay-rgb),0.14) var(--fill));
  outline: none; cursor: pointer; margin: 9px 0 5px;
}
.futures-range::-webkit-slider-thumb {
  -webkit-appearance: none; width: 13px; height: 13px; border-radius: 3px;
  background: var(--text); transform: rotate(45deg); cursor: pointer;
  box-shadow: 0 1px 4px rgba(0,0,0,0.35);
}
.futures-range::-moz-range-thumb {
  width: 13px; height: 13px; border-radius: 3px; background: var(--text); border: none;
  transform: rotate(45deg); cursor: pointer; box-shadow: 0 1px 4px rgba(0,0,0,0.35);
}
.futures-range-ticked {
  /* Small dots at 0/25/50/75/100%, layered on top of the fill gradient
     above (multiple backgrounds stack; this one is listed first so it
     paints over it) — same idea as the reference's dotted track. Must be
     the `background` shorthand, not `background-image` — per-layer
     position/size/repeat (the "0% center / 4px 4px no-repeat" part) is
     only valid there; written as background-image the whole declaration
     is invalid and the browser drops it, silently rendering `none` (this
     is why the margin slider — the only one with this class — showed no
     fill color at all despite --fill being set correctly). */
  background:
    radial-gradient(circle, rgba(var(--overlay-rgb),0.5) 1.5px, transparent 1.6px) 0% center / 4px 4px no-repeat,
    radial-gradient(circle, rgba(var(--overlay-rgb),0.5) 1.5px, transparent 1.6px) 25% center / 4px 4px no-repeat,
    radial-gradient(circle, rgba(var(--overlay-rgb),0.5) 1.5px, transparent 1.6px) 50% center / 4px 4px no-repeat,
    radial-gradient(circle, rgba(var(--overlay-rgb),0.5) 1.5px, transparent 1.6px) 75% center / 4px 4px no-repeat,
    radial-gradient(circle, rgba(var(--overlay-rgb),0.5) 1.5px, transparent 1.6px) 100% center / 4px 4px no-repeat,
    linear-gradient(to right, var(--accent) var(--fill), rgba(var(--overlay-rgb),0.14) var(--fill));
}
.futures-slider-labels {
  display: flex; justify-content: space-between; font-family: var(--font-mono);
  font-size: 9.5px; color: var(--muted); margin-top: -2px;
}
.futures-margin-learn-link { margin-top: 10px; }
#futures-leverage-learn-link:empty { display: none; }
#futures-leverage-learn-link:not(:empty) { margin-top: 10px; }

.futures-preview {
  font-size: 11.5px; color: var(--muted); display: flex; flex-direction: column; gap: 4px;
  padding: 10px 12px; background: rgba(var(--overlay-rgb),0.03); border-radius: var(--radius-sm);
}
.futures-preview b { color: var(--muted-2); font-family: var(--font-mono); }
.futures-ticket-error { color: var(--bearish); font-size: 12px; }

.futures-submit {
  width: 100%; border: none; border-radius: var(--radius-sm); cursor: pointer;
  font-family: var(--font-body); font-size: 14px; font-weight: 700; padding: 13px 0;
  transition: filter 0.15s, opacity 0.15s;
}
.futures-submit:disabled { opacity: 0.5; cursor: default; }
.futures-submit.long { background: var(--bullish); color: #05261c; }
.futures-submit.short { background: var(--bearish); color: #2a0a10; }
.futures-submit:hover:not(:disabled) { filter: brightness(1.08); }

/* ---------- Futures badges (shared by table + hero cards) ---------- */
.futures-badge {
  font-family: var(--font-mono); font-size: 10px; font-weight: 700; padding: 3px 8px; border-radius: 5px;
}
.futures-badge-long { background: rgba(var(--bullish-rgb),0.16); color: var(--bullish); }
.futures-badge-short { background: rgba(var(--bearish-rgb),0.16); color: var(--bearish); }
.futures-badge-lev { background: rgba(var(--overlay-rgb),0.07); color: var(--muted-2); }

.futures-close-btn {
  background: none; border: 1px solid var(--border); border-radius: var(--radius-sm);
  color: var(--bearish); cursor: pointer; font-family: var(--font-body); font-size: 11px; font-weight: 700;
  padding: 6px 12px; transition: background-color 0.15s, border-color 0.15s, color 0.15s;
}
.futures-close-btn:hover { border-color: var(--bearish); }
/* Inline "click again to confirm" state (see wireFuturesEvents) — no
   native confirm() popup, and no separate modal either; the button
   itself becomes the confirmation. */
.futures-close-btn.confirming, .futures-close-btn-lg.confirming {
  background: var(--bearish); border-color: var(--bearish); color: #fff;
}
.futures-share-btn, .futures-share-btn-lg {
  background: none; border: 1px solid var(--border); border-radius: var(--radius-sm);
  color: var(--muted-2); cursor: pointer; transition: border-color 0.15s, color 0.15s;
  display: inline-flex; align-items: center; justify-content: center;
}
.futures-share-btn:hover, .futures-share-btn-lg:hover { border-color: var(--accent-secondary); color: var(--accent-secondary); }
.futures-share-btn:disabled, .futures-share-btn-lg:disabled { opacity: 0.5; cursor: default; }
.futures-share-btn { width: 30px; height: 30px; }
.futures-share-btn svg, .futures-share-btn-lg svg { width: 15px; height: 15px; }

/* ---------- Desktop: dense table ----------
 * Genuinely a different arrangement from the mobile hero cards below,
 * not a CSS reflow of the same markup — both get rendered by demo.js
 * and this media query decides which one is actually visible, matching
 * the two designs picked from the layout options (table for desktop,
 * one full card per position for mobile). */
.futures-positions-cards { display: none; }
.futures-table .futures-sym-cell { display: flex; align-items: center; gap: 8px; font-weight: 700; color: var(--text); }
.futures-actions-cell { display: flex; gap: 6px; justify-content: flex-end; }

/* ---------- Mobile: one hero card per position ---------- */
.futures-hero-card {
  position: relative; overflow: hidden;
  background: var(--surface-hi); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 22px; margin-bottom: 16px;
}
/* Small and tucked into the corner, not a centerpiece — it's a mood
   indicator sitting behind the numbers, not the point of the card. */
.futures-hero-rocket {
  position: absolute; right: 4%; top: 6%; width: 17%; opacity: 0.4; pointer-events: none;
}
.futures-rocket-svg { width: 100%; height: auto; display: block; transition: transform 0.5s ease; }
.futures-rocket-profit { animation: futuresRocketBob 2.6s ease-in-out infinite; }
.futures-rocket-loss { transform: rotate(150deg) translate(8%, -6%); }
@keyframes futuresRocketBob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-6px); }
}
.futures-hero-top { display: flex; align-items: center; gap: 8px; margin-bottom: 18px; position: relative; z-index: 1; }
.futures-hero-top b { font-size: 14px; }
.futures-hero-pnl { font-family: var(--font-mono); font-weight: 800; font-size: 32px; line-height: 1; margin-bottom: 6px; position: relative; z-index: 1; }
.futures-hero-pnl.up { color: var(--bullish); }
.futures-hero-pnl.down { color: var(--bearish); }
.futures-hero-pnl-sub { font-size: 11.5px; color: var(--muted); margin-bottom: 22px; position: relative; z-index: 1; }
.futures-hero-rows { display: flex; flex-direction: column; gap: 12px; margin-bottom: 20px; position: relative; z-index: 1; }
.futures-hero-row { display: flex; justify-content: space-between; align-items: baseline; font-size: 12px; gap: 12px; }
.futures-hero-row span:first-child { color: var(--muted); flex-shrink: 0; }
.futures-hero-row span:last-child { font-family: var(--font-mono); font-weight: 700; color: var(--text); text-align: right; }
.futures-hero-btns { display: flex; gap: 10px; position: relative; z-index: 1; }
.futures-close-btn-lg { flex: 1; padding: 11px; text-align: center; }
.futures-share-btn-lg { flex: 1; gap: 6px; padding: 11px; font-family: var(--font-body); font-size: 11.5px; font-weight: 700; }

@media (max-width: 620px) {
  .futures-form { max-width: none; }
  .futures-positions-table-wrap { display: none; }
  .futures-positions-cards { display: block; }
  /* Extra breathing room specifically on phone, on top of the base
     card spacing above — a tight card reads very differently stacked
     full-width on a phone than sitting narrow among other cards on a
     wide desktop grid, even at the same padding. */
  .futures-hero-card { padding: 24px 20px; margin-bottom: 18px; }
  .futures-hero-rocket { width: 15%; }
  .futures-hero-pnl { font-size: 36px; }
}

/* ---------- Share sheet ----------
 * Reuses the app's shared .modal-backdrop/.modal/.modal-close chrome
 * (news.css) so it looks native to the rest of the app, adding only
 * the share-specific content below the header. */
.futures-share-modal { width: min(360px, 100%); max-height: 90vh; }
.futures-share-amount { display: inline-flex; background: var(--surface-hi); border-radius: 999px; padding: 3px; margin-bottom: 10px; align-self: center; }
.futures-share-amount-btn { font: inherit; font-size: 12px; font-weight: 600; padding: 6px 14px; border: 0; border-radius: 999px; background: transparent; color: var(--muted); cursor: pointer; transition: background .2s ease, color .2s ease; min-height: 32px; }
.futures-share-amount-btn.active { background: var(--surface); color: var(--text); box-shadow: 0 1px 4px rgba(0,0,0,0.2); }
.futures-share-amount-btn:disabled { opacity: .6; cursor: progress; }
.futures-share-preview {
  width: 100%; border-radius: var(--radius-sm); border: 1px solid var(--border);
  margin-bottom: 16px; display: block; background: #0b0d14;
}
.futures-share-platforms { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-bottom: 12px; }
.futures-share-platform-btn {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  background: rgba(var(--overlay-rgb),0.04); border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 10px 4px; cursor: pointer; color: var(--muted-2);
  font-family: var(--font-body); font-size: 10.5px; font-weight: 600;
  transition: border-color 0.15s, color 0.15s, transform 0.15s;
}
.futures-share-platform-btn:hover { transform: translateY(-2px); }
.futures-share-platform-btn svg { width: 22px; height: 22px; }
.futures-share-platform-btn.wa { color: #25d366; }
.futures-share-platform-btn.wa:hover { border-color: #25d366; }
.futures-share-platform-btn.tg { color: #229ed9; }
.futures-share-platform-btn.tg:hover { border-color: #229ed9; }
.futures-share-platform-btn.x { color: var(--text); }
.futures-share-platform-btn.x:hover { border-color: var(--text); }
.futures-share-platform-btn.copy:hover, .futures-share-platform-btn.more:hover { border-color: var(--accent-secondary); color: var(--accent-secondary); }
.futures-share-save-btn {
  width: 100%; display: flex; align-items: center; justify-content: center; gap: 8px;
  background: var(--accent-secondary); color: #06251f; border: none; border-radius: var(--radius-sm);
  padding: 13px; font-family: var(--font-body); font-size: 13px; font-weight: 700; cursor: pointer;
  transition: filter 0.15s;
}
.futures-share-save-btn:hover { filter: brightness(1.08); }
.futures-share-save-btn svg { width: 17px; height: 17px; }
.futures-share-toast {
  margin-top: 12px; text-align: center; font-size: 11.5px; color: var(--muted-2);
  background: rgba(var(--overlay-rgb),0.05); border-radius: var(--radius-sm); padding: 8px;
}

/* ---- alerts.css ---- */
/* ---------- Alerts ---------- */
.alerts-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 24px 26px;
  margin-bottom: 20px;
  box-shadow: var(--shadow);
}
.alerts-header { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 16px; }
.alerts-title { font-family: var(--font-body); font-size: 15px; font-weight: 600; }
.telegram-connect-btn {
  font-size: 12px; font-weight: 600; color: var(--accent);
  background: rgba(var(--accent-rgb),0.08); border: 1px solid rgba(var(--accent-rgb),0.3);
  border-radius: 999px; padding: 7px 14px; cursor: pointer; transition: all 0.22s;
}
.telegram-connect-btn:hover { border-color: rgba(var(--accent-rgb),0.6); background: rgba(var(--accent-rgb),0.14); }
.telegram-connect-btn.linked { color: var(--bullish); background: rgba(var(--bullish-rgb),0.08); border-color: rgba(var(--bullish-rgb),0.35); cursor: default; }

.telegram-link-info { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 16px; }
.telegram-link-info a { color: var(--accent); font-weight: 600; }
.telegram-link-info code {
  font-family: var(--font-mono); font-size: 12.5px; font-weight: 700; color: var(--accent);
  background: rgba(var(--accent-rgb),0.1); padding: 3px 9px; border-radius: 6px;
}
.telegram-link-expiry { font-size: 11px; color: var(--muted); }

.alert-form { display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end; margin-bottom: 18px; }
.alert-form select, .alert-form input[type="text"], .alert-form input[type="number"] {
  background: var(--surface-hi);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 13px; font-weight: 600;
  padding: 10px 12px;
  width: 120px;
  outline: none;
}
/* The dropdown *popup* is a separate native surface that doesn't composite
   with the page — a translucent background there shows through as
   whatever the browser's own default popup color is (usually white), so
   the options need an explicit opaque dark background of their own.
   color-scheme:dark (see tokens.css) handles most browsers already; this
   is the fallback for the ones that still show light option rows. */
.alert-form select option {
  background: var(--surface-hi);
  color: var(--text);
}
.alert-form label.checkbox-label {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--muted-2); cursor: pointer;
}
.alert-add-btn {
  background: var(--accent);
  border: none; border-radius: var(--radius-sm);
  color: #04121c; cursor: pointer;
  font-family: var(--font-body); font-size: 13px; font-weight: 700;
  padding: 10px 20px;
  transition: background 0.15s, opacity 0.15s;
}
.alert-add-btn:hover:not(:disabled) { background: var(--accent-hover); }
.alert-add-btn:disabled { opacity: 0.5; cursor: default; }

.alert-list { display: flex; flex-direction: column; gap: 10px; }
.alert-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 10px 14px; background: var(--surface-hi);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  font-size: 12.5px; flex-wrap: wrap;
}
.alert-row-desc { color: var(--muted-2); font-family: var(--font-mono); }
.alert-row-meta { color: var(--muted); font-size: 11px; }
.alert-remove { background: none; border: none; cursor: pointer; color: var(--muted); font-size: 11px; }
.alert-remove:hover { color: var(--bearish); }
.alerts-empty { font-size: 13px; color: var(--muted); font-style: italic; }
.alerts-empty-learn-link { margin-top: 10px; }

/* ---- signals.css ---- */
/* ---------- Signals ---------- */
.signals-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 24px 26px;
  margin-bottom: 20px;
  box-shadow: var(--shadow);
}

.signals-optin {
  display: flex; flex-direction: column; align-items: flex-start; gap: 10px;
  padding: 8px 0 4px;
}
.signals-optin-title { font-family: var(--font-body); font-size: 15px; font-weight: 600; }
.signals-optin-body { font-size: 13px; color: var(--muted-2); line-height: 1.6; max-width: 60ch; }
.signals-telegram-hint { font-size: 11px; color: var(--muted); }
.signals-optin-learn-link { margin: 4px 0 14px; }

.signals-stats {
  display: flex; flex-wrap: wrap; gap: 22px;
  margin-bottom: 18px; padding-bottom: 18px;
  border-bottom: 1px solid rgba(var(--overlay-rgb),0.07);
}
.signals-stat { display: flex; flex-direction: column; gap: 2px; }
.signals-stat-value { font-family: var(--font-disp); font-size: 20px; font-weight: 700; }
.signals-stat-label { font-size: 11px; color: var(--muted); }

.signals-settings {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin-bottom: 18px; font-size: 12px;
}
.signals-settings-label { color: var(--muted-2); font-weight: 600; }

.near-misses {
  display: flex; flex-direction: column; gap: 8px;
  padding: 12px 14px; margin-bottom: 16px;
  background: var(--surface-hi);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.near-misses-title { font-size: 11px; font-weight: 600; color: var(--muted-2); letter-spacing: 0.02em; }
.near-miss-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  font-size: 12px;
}
.near-miss-badge { padding: 2px 7px; font-size: 10px; }
.near-miss-symbol { font-family: var(--font-mono); font-weight: 700; color: var(--text); }
.near-miss-reason { color: var(--muted); }

.signal-list { display: flex; flex-direction: column; gap: 12px; }
.signal-card {
  padding: 14px 16px;
  background: var(--surface-hi);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.signal-card-top { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; flex-wrap: wrap; }
.signal-symbol { font-family: var(--font-mono); font-size: 13px; font-weight: 700; }
.signal-badge {
  font-size: 11px; font-weight: 700; letter-spacing: 0.04em;
  padding: 3px 9px; border-radius: 999px;
}
.signal-badge-long { color: var(--bullish); background: rgba(var(--bullish-rgb),0.1); border: 1px solid rgba(var(--bullish-rgb),0.3); }
.signal-badge-short { color: var(--bearish); background: rgba(var(--bearish-rgb),0.1); border: 1px solid rgba(var(--bearish-rgb),0.3); }
.signal-chip {
  font-size: 10px; font-weight: 700; letter-spacing: 0.05em;
  padding: 3px 8px; border-radius: 999px; margin-left: auto;
}
.signal-chip-open { color: var(--accent); background: rgba(var(--accent-rgb),0.1); border: 1px solid rgba(var(--accent-rgb),0.3); }
.signal-chip-win { color: var(--bullish); background: rgba(var(--bullish-rgb),0.1); border: 1px solid rgba(var(--bullish-rgb),0.3); }
.signal-chip-loss { color: var(--bearish); background: rgba(var(--bearish-rgb),0.1); border: 1px solid rgba(var(--bearish-rgb),0.3); }
.signal-card-levels {
  display: flex; flex-wrap: wrap; gap: 16px;
  font-family: var(--font-mono); font-size: 12.5px; color: var(--muted-2);
  margin-bottom: 8px;
}
.signal-card-levels b { color: var(--text); }
.signal-card-meta {
  display: flex; justify-content: space-between; flex-wrap: wrap; gap: 8px;
  font-size: 11px; color: var(--muted);
}

/* ---- compare.css ---- */
/* ---------- Multi-symbol comparison ---------- */
.compare-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 24px 26px;
  margin-bottom: 20px;
  box-shadow: var(--shadow);
}
.compare-header { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 16px; }
.compare-title { font-family: var(--font-body); font-size: 15px; font-weight: 600; }
.compare-hint { font-size: 11.5px; color: var(--muted); }

.compare-form { display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end; margin-bottom: 16px; }
.compare-form input[type="text"] {
  background: var(--surface-hi);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 13px; font-weight: 600;
  padding: 10px 12px;
  width: 280px;
  outline: none;
}
.compare-btn {
  background: var(--accent);
  border: none; border-radius: var(--radius-sm);
  color: #04121c; cursor: pointer;
  font-family: var(--font-body); font-size: 13px; font-weight: 700;
  padding: 10px 20px;
  transition: background 0.15s, opacity 0.15s;
}
.compare-btn:hover:not(:disabled) { background: var(--accent-hover); }
.compare-btn:disabled { opacity: 0.5; cursor: default; }

.compare-table-wrap { overflow-x: auto; }
.compare-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.compare-table th {
  text-align: left; font-size: 10px; font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--muted); padding: 8px 10px;
  border-bottom: 1px solid rgba(var(--overlay-rgb),0.08); white-space: nowrap;
}
.compare-table td { padding: 10px; border-bottom: 1px solid rgba(var(--overlay-rgb),0.05); vertical-align: top; }
.compare-symbol { font-family: var(--font-mono); font-weight: 700; color: var(--text); cursor: pointer; }
.compare-symbol:hover { color: var(--accent); }
.compare-cell { display: flex; flex-direction: column; gap: 3px; }
.compare-badge {
  display: inline-block; font-size: 9.5px; font-weight: 700; letter-spacing: 0.08em;
  padding: 3px 8px; border-radius: 999px; text-transform: uppercase; width: fit-content;
}
.compare-score { font-family: var(--font-mono); font-size: 11px; color: var(--muted-2); }
.compare-acc { font-family: var(--font-mono); font-size: 10.5px; color: var(--muted); }
.compare-error { color: var(--bearish); font-size: 11.5px; }
.compare-empty { font-size: 13px; color: var(--muted); font-style: italic; }

/* ---- symbol-search.css ---- */
/* ---------- Symbol search combobox ---------- */
.symbol-combobox { position: relative; }
.symbol-suggestions {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 20;
  max-height: 280px; overflow-y: auto;
  background: var(--surface-hi);
  border: 1px solid var(--border-hi);
  border-radius: var(--radius-sm);
  padding: 6px;
  box-shadow: var(--shadow);
}
.symbol-suggestion {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  padding: 9px 12px; border-radius: var(--radius-sm); cursor: pointer;
  transition: background 0.15s;
}
.symbol-suggestion:hover, .symbol-suggestion.highlighted { background: rgba(var(--accent-rgb),0.1); }
.symbol-suggestion-sym {
  font-family: var(--font-mono); font-size: 13px; font-weight: 700; color: var(--text);
  white-space: nowrap;
}
.symbol-suggestion-name {
  font-size: 11.5px; color: var(--muted); overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; text-align: right;
}

/* ---- tars.css ---- */
/* ================= Ask Tars widget ================= */
/* Global, persistent floating widget — NOT an .app-view, stays visible
   across every page/section since it isn't tied to nav.js's showView(). */

#tars-widget {
  position: fixed;
  /* env(safe-area-inset-*) is 0 on browsers/devices that don't need it,
     so this degrades to the plain 22px everywhere except phones with a
     rounded-corner screen, notch, or gesture bar overlapping this
     corner — where it keeps the button clear of that hardware instead
     of sitting flush against (or visually clipped by) the true edge.
     Needs viewport-fit=cover on the <meta viewport> tag to report real
     values on iOS Safari; harmless no-op without it. */
  right: calc(22px + env(safe-area-inset-right, 0px));
  bottom: calc(22px + env(safe-area-inset-bottom, 0px));
  /* Below .modal-backdrop's z-index:60 (news.css, shared by the auth/
     profile/article modals) on purpose — confirmed live this was a real
     bug at 70 (same as .nav-menu/.user-menu dropdowns): the fixed-
     position widget rendered ON TOP of an open modal, and its FAB
     button could sit over/intercept clicks meant for a login field
     underneath. At 50 it stays above normal page content (header is
     10, suggestions dropdowns are 20) but a modal's own backdrop
     (solid, full-viewport) fully covers and hides it while open. */
  z-index: 50;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 12px;
  /* The real root cause of "clicking things near here does nothing":
     .tars-panel keeps its full min(360px,...) x min(520px,...) layout
     footprint even while CLOSED (opacity:0, not display:none) — its
     own pointer-events:none lets clicks pass through IT, but this flex
     PARENT has no such rule and defaults to auto, so its own invisible
     bounding box (sized to contain that footprint) was itself a valid
     hit-test target, silently swallowing clicks meant for whatever
     page content happens to render underneath — independent of
     z-index entirely. pointer-events:none here, re-enabled explicitly
     on just the always-visible .tars-fab below (.tars-panel.open
     already re-enables itself the same way). */
  pointer-events: none;
}

/* Bare icon, no circle backing — currentColor applied to TARS_ICON_SVG's
   own fill/stroke. Teal (secondary), not amber — it was sitting right
   next to the Analyze button and reading as the same color/thing. */
.tars-fab {
  width: 56px; height: 56px;
  background: none;
  border: none;
  color: var(--accent-secondary);
  display: grid; place-items: center;
  cursor: pointer;
  filter: drop-shadow(0 4px 10px rgba(0,0,0,0.45));
  transition: transform 0.25s cubic-bezier(0.22,1,0.36,1);
  position: relative;
  pointer-events: auto;
}
.tars-fab:hover { transform: translateY(-2px) scale(1.06); }
.tars-fab:active { transform: translateY(0) scale(0.95); }
.tars-fab svg { width: 36px; height: 36px; }

.tars-fab-ring {
  position: absolute; inset: -6px;
  border-radius: 50%;
  border: 1.5px solid rgba(var(--accent-secondary-rgb),0.5);
  opacity: 0;
  animation: tarsPulseRing 2.6s ease-out infinite;
  pointer-events: none;
}
#tars-widget.tars-unread .tars-fab-ring { animation-play-state: running; }
#tars-widget:not(.tars-unread) .tars-fab-ring { animation-play-state: paused; opacity: 0; }
@keyframes tarsPulseRing {
  0%   { transform: scale(0.85); opacity: 0.55; }
  70%  { transform: scale(1.35); opacity: 0; }
  100% { transform: scale(1.35); opacity: 0; }
}

.tars-badge {
  position: absolute; top: -3px; right: -3px;
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--bearish);
  border: 2px solid var(--bg);
  display: none;
}
#tars-widget.tars-unread .tars-badge { display: block; }

.tars-panel {
  width: min(360px, calc(100vw - 32px));
  height: min(520px, calc(100vh - 110px));
  background: var(--surface-hi);
  border: 1px solid var(--border-hi);
  border-radius: var(--radius);
  box-shadow: 0 20px 50px rgba(0,0,0,0.5);
  display: flex; flex-direction: column;
  overflow: hidden;
  transform-origin: bottom right;
  transform: translateY(16px) scale(0.96);
  opacity: 0;
  pointer-events: none;
  transition: transform 0.28s cubic-bezier(0.22,1,0.36,1), opacity 0.22s;
}
.tars-panel.open { transform: translateY(0) scale(1); opacity: 1; pointer-events: auto; }

.tars-header {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border);
  background: rgba(var(--accent-secondary-rgb),0.06);
  flex-shrink: 0;
}
.tars-header-icon {
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--accent-secondary);
  color: #04121c;
  display: grid; place-items: center; flex-shrink: 0;
}
.tars-header-icon svg { width: 17px; height: 17px; }
.tars-header-text { flex: 1; min-width: 0; }
.tars-header-title { font-family: var(--font-disp); font-size: 14px; font-weight: 700; }
.tars-header-sub { font-size: 11px; color: var(--muted); }
.tars-close {
  background: rgba(var(--overlay-rgb),0.05); border: 1px solid var(--border);
  color: var(--muted-2); border-radius: 8px; cursor: pointer;
  width: 26px; height: 26px; font-size: 12px; flex-shrink: 0;
  transition: all 0.2s;
}
.tars-close:hover { color: var(--text); border-color: var(--border-hi); transform: rotate(90deg); }

.tars-messages {
  flex: 1; overflow-y: auto;
  padding: 14px 14px 6px;
  display: flex; flex-direction: column; gap: 10px;
}
.tars-msg { display: flex; }
.tars-msg-bot { justify-content: flex-start; }
.tars-msg-user { justify-content: flex-end; }
.tars-bubble {
  max-width: 84%;
  padding: 9px 12px;
  border-radius: 12px;
  font-size: 13px;
  line-height: 1.55;
  white-space: pre-wrap;
  word-break: break-word;
}
.tars-msg-bot .tars-bubble {
  background: rgba(var(--overlay-rgb),0.05);
  border: 1px solid var(--border);
  color: var(--text);
  border-bottom-left-radius: 4px;
}
.tars-msg-user .tars-bubble {
  background: var(--accent-secondary);
  color: #04121c;
  font-weight: 500;
  border-bottom-right-radius: 4px;
}
.tars-msg-error .tars-bubble {
  background: rgba(var(--bearish-rgb),0.12);
  border: 1px solid rgba(var(--bearish-rgb),0.35);
  color: var(--bearish);
}

/* Shown once under the welcome bubble on first open — see
   tars.js::tarsAddSuggestions for why (fills what was otherwise dead
   space on the very first open, before any real conversation exists). */
.tars-suggestions { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }
.tars-suggestion {
  font-family: var(--font-body); font-size: 12.5px; text-align: left;
  padding: 8px 12px; border-radius: 12px; border-bottom-left-radius: 4px;
  background: transparent; border: 1px solid var(--border-hi);
  color: var(--accent-secondary); cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.tars-suggestion:hover { background: rgba(var(--accent-secondary-rgb),0.1); color: var(--text); }

.tars-typing { display: flex; gap: 5px; padding: 4px 2px; }
.tars-typing span {
  width: 6px; height: 6px; border-radius: 50%; background: var(--accent-secondary);
  animation: tarsBounceDot 1.1s ease-in-out infinite;
}
.tars-typing span:nth-child(2) { animation-delay: 0.15s; }
.tars-typing span:nth-child(3) { animation-delay: 0.3s; }
@keyframes tarsBounceDot { 40% { transform: translateY(-6px); opacity: 0.5; } }

.tars-input-row {
  display: flex; gap: 8px;
  padding: 12px;
  border-top: 1px solid var(--border);
  flex-shrink: 0;
}
.tars-input {
  flex: 1;
  background: rgba(var(--overlay-rgb),0.04);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 13px;
  padding: 9px 11px;
  resize: none;
  max-height: 90px;
  transition: border-color 0.2s;
}
.tars-input:focus { outline: none; border-color: var(--border-hi); }
.tars-send {
  background: var(--accent-secondary);
  color: #04121c;
  border: none;
  border-radius: var(--radius-sm);
  width: 38px; flex-shrink: 0;
  cursor: pointer;
  display: grid; place-items: center;
  transition: opacity 0.2s, transform 0.15s;
}
.tars-send:hover:not(:disabled) { transform: translateY(-1px); }
.tars-send:disabled { opacity: 0.45; cursor: default; }
.tars-send svg { width: 16px; height: 16px; }

/* The bottom tab bar (nav.css) appears at the same 620px breakpoint and
   is ~62px tall — clear it here rather than in nav.css so this file
   stays the single source of truth for where the widget sits. */
@media (max-width: 620px) {
  /* Just enough to clear the ~53px bottom tab bar with a little
     breathing room — pushing this HIGHER moves the FAB toward the
     Analyze button (which sits above, not below), making that
     collision worse, not better; confirmed by measuring both rects
     directly rather than guessing again. */
  #tars-widget { bottom: calc(66px + env(safe-area-inset-bottom, 0px)); }
}

@media (max-width: 480px) {
  #tars-widget {
    right: calc(14px + env(safe-area-inset-right, 0px));
  }
  /* 100vw can exceed the true visible width on some mobile browsers
     (scrollbar gutters, or any incidental horizontal overflow elsewhere
     on the page) — 100% of the (non-scrolling) body avoids inheriting
     that, so the open panel can't render wider than the actual screen. */
  .tars-panel { width: min(calc(100vw - 28px), calc(100% - 28px)); }
}

/* ---- learn.css ---- */
/* ================= Learn ================= */
.learn-sub-back {
  background: transparent;
  border: none;
  color: var(--accent);
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  padding: 0 0 14px;
  display: block;
}
.learn-sub-back:hover { text-decoration: underline; }

.learn-module-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 12px;
  margin-top: 16px;
}
.learn-module-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px 16px;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.2s, transform 0.2s;
}
.learn-module-card:hover { border-color: var(--border-hi); transform: translateY(-2px); }
.learn-module-card-title { font-family: var(--font-disp); font-weight: 700; font-size: 15px; margin-bottom: 6px; }
.learn-module-card-count { font-size: 12px; color: var(--muted); }

.learn-lesson-list { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }
.learn-lesson-row {
  display: flex; align-items: center; gap: 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  cursor: pointer;
  text-align: left;
  transition: border-color 0.2s;
}
.learn-lesson-row:hover { border-color: var(--border-hi); }
.learn-lesson-row-num {
  width: 26px; height: 26px; border-radius: 50%;
  background: rgba(var(--accent-rgb),0.12); color: var(--accent);
  display: grid; place-items: center;
  font-size: 12px; font-weight: 700; flex-shrink: 0;
}
.learn-lesson-row-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.learn-lesson-row-title { font-weight: 600; font-size: 13.5px; }
.learn-lesson-row-module { font-size: 10.5px; color: var(--accent); text-transform: uppercase; letter-spacing: 0.03em; }
.learn-lesson-row-summary { font-size: 12px; color: var(--muted); }

.learn-search-row { display: flex; align-items: center; gap: 8px; margin-top: 16px; position: relative; }
.learn-search-input {
  flex: 1;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 13px;
  padding: 10px 36px 10px 12px;
}
.learn-search-input:focus { border-color: var(--accent); outline: none; }
.learn-search-clear {
  position: absolute;
  right: 8px;
  background: none;
  border: none;
  color: var(--muted);
  font-size: 14px;
  cursor: pointer;
  padding: 4px;
}
.learn-search-clear:hover { color: var(--text); }
.learn-search-results { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; }
.learn-search-empty { color: var(--muted); font-size: 13px; margin-top: 14px; }

.learn-bookmarks-toggle {
  margin-top: 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
  padding: 7px 14px;
  cursor: pointer;
  transition: border-color 0.2s, color 0.2s;
}
.learn-bookmarks-toggle:hover { border-color: var(--border-hi); }
.learn-bookmarks-toggle.active { border-color: var(--accent); color: var(--accent); background: rgba(var(--accent-rgb), 0.08); }

.learn-lesson-view { margin-top: 4px; }
.learn-lesson-title-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; margin-bottom: 16px; }
.learn-lesson-title { font-family: var(--font-disp); font-size: 21px; font-weight: 700; }
.learn-bookmark-btn {
  flex-shrink: 0;
  background: none;
  border: none;
  color: var(--muted);
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
  padding: 2px 4px;
  transition: color 0.2s, transform 0.15s;
}
.learn-bookmark-btn:hover { transform: scale(1.1); }
.learn-bookmark-btn.active { color: var(--accent); }
.learn-lesson-body { font-size: 14px; line-height: 1.85; color: var(--muted-2); }
.learn-lesson-body p { margin-bottom: 14px; }
.learn-lesson-body p:last-child { margin-bottom: 0; }

.learn-diagram {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px;
  margin-bottom: 18px;
  display: flex; justify-content: center;
}
.learn-diagram-svg { width: 100%; max-width: 380px; height: auto; }
.learn-diagram-label { font-size: 11px; fill: var(--muted-2); font-family: var(--font-body); }
.learn-diagram-caption { font-size: 12px; fill: var(--text); font-weight: 600; font-family: var(--font-body); }
.learn-diagram-sub { font-size: 10px; fill: var(--muted); font-family: var(--font-body); }

.learn-chart {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  margin-bottom: 18px;
  line-height: 0;
}
.learn-chart img { width: 100%; height: auto; display: block; }

.learn-quiz {
  margin-top: 26px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
}
.learn-quiz-title { font-family: var(--font-disp); font-weight: 700; font-size: 14px; margin-bottom: 14px; }
.learn-quiz-q { margin-bottom: 20px; }
.learn-quiz-q:last-child { margin-bottom: 0; }
.learn-quiz-question { font-size: 13.5px; font-weight: 600; margin-bottom: 10px; }
.learn-quiz-choices { display: flex; flex-direction: column; gap: 8px; }
.learn-quiz-choice {
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 13px;
  padding: 10px 12px;
  cursor: pointer;
  transition: border-color 0.2s, background 0.2s;
}
.learn-quiz-choice:hover:not(:disabled) { border-color: var(--border-hi); }
.learn-quiz-choice:disabled { cursor: default; }
.learn-quiz-choice-correct { border-color: var(--bullish); background: rgba(var(--bullish-rgb),0.1); }
.learn-quiz-choice-wrong { border-color: var(--bearish); background: rgba(var(--bearish-rgb),0.1); }
.learn-quiz-feedback {
  margin-top: 10px;
  font-size: 12.5px;
  line-height: 1.6;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
}
.learn-quiz-feedback-correct { background: rgba(var(--bullish-rgb),0.08); color: var(--bullish); }
.learn-quiz-feedback-wrong { background: rgba(var(--bearish-rgb),0.08); color: var(--bearish); }

.learn-activity {
  margin: 18px 0 24px;
  padding: 16px;
  background: rgba(var(--accent-rgb), 0.06);
  border: 1px solid rgba(var(--accent-rgb), 0.3);
  border-radius: var(--radius-sm);
}
.learn-activity-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--accent); margin-bottom: 8px; }
.learn-activity-prompt { font-size: 14px; font-weight: 600; margin-bottom: 12px; line-height: 1.5; }
.learn-activity-reveal {
  margin-top: 10px;
  font-size: 12.5px;
  line-height: 1.6;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
}
.learn-activity-reveal-correct { background: rgba(var(--bullish-rgb),0.08); color: var(--bullish); }
.learn-activity-reveal-wrong { background: rgba(var(--bearish-rgb),0.08); color: var(--bearish); }

/* predict: single guess-before-reading multiple choice */
.learn-predict-options { display: flex; flex-direction: column; gap: 8px; }
.learn-predict-option {
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 13px;
  padding: 10px 12px;
  cursor: pointer;
  transition: border-color 0.2s, background 0.2s;
}
.learn-predict-option:hover:not(:disabled) { border-color: var(--border-hi); }
.learn-predict-option:disabled { cursor: default; }
.learn-predict-option-correct { border-color: var(--bullish); background: rgba(var(--bullish-rgb),0.1); }
.learn-predict-option-wrong { border-color: var(--bearish); background: rgba(var(--bearish-rgb),0.1); }

/* sequence: tap items back into the correct order */
.learn-sequence-list { display: flex; flex-direction: column; gap: 8px; }
.learn-sequence-item {
  display: flex;
  align-items: center;
  gap: 10px;
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 13px;
  padding: 10px 12px;
  cursor: pointer;
  transition: border-color 0.2s, background 0.2s;
}
.learn-sequence-item:hover:not(:disabled) { border-color: var(--border-hi); }
.learn-sequence-item:disabled { cursor: default; }
.learn-sequence-num {
  flex-shrink: 0;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--border);
  color: var(--bg);
  font-size: 11px;
  font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}
.learn-sequence-item-picked .learn-sequence-num { background: var(--accent); }
.learn-sequence-item-correct { border-color: var(--bullish); background: rgba(var(--bullish-rgb),0.1); }
.learn-sequence-item-wrong { border-color: var(--bearish); background: rgba(var(--bearish-rgb),0.1); }

/* estimate: numeric slider guess against a real figure */
.learn-estimate-row { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.learn-estimate-slider { flex: 1; accent-color: var(--accent); }
.learn-estimate-value { font-family: var(--font-mono); font-weight: 700; font-size: 14px; min-width: 60px; text-align: right; }
.learn-estimate-lock {
  width: 100%;
  background: var(--accent);
  color: var(--bg);
  border: none;
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}
.learn-estimate-lock:disabled { opacity: 0.6; cursor: default; }

/* classify: sort short scenarios into one of two buckets */
.learn-classify-list { display: flex; flex-direction: column; gap: 14px; }
.learn-classify-item { padding-bottom: 4px; }
.learn-classify-text { font-size: 13px; margin-bottom: 8px; line-height: 1.5; }
.learn-classify-buttons { display: flex; gap: 8px; }
.learn-classify-btn {
  flex: 1;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 12.5px;
  font-weight: 600;
  padding: 9px 10px;
  cursor: pointer;
  transition: border-color 0.2s, background 0.2s;
}
.learn-classify-btn:hover:not(:disabled) { border-color: var(--border-hi); }
.learn-classify-btn:disabled { cursor: default; }
.learn-classify-btn-correct { border-color: var(--bullish); background: rgba(var(--bullish-rgb),0.1); }
.learn-classify-btn-wrong { border-color: var(--bearish); background: rgba(var(--bearish-rgb),0.1); }

.learn-ask-tars-pill {
  display: block;
  width: 100%;
  margin-top: 22px;
  padding: 11px 14px;
  background: var(--surface);
  border: 1px dashed var(--border-hi);
  border-radius: var(--radius-sm);
  color: var(--muted);
  font-size: 12.5px;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
  transition: border-color 0.2s, color 0.2s;
}
.learn-ask-tars-pill:hover { border-color: var(--accent); color: var(--accent); }

.learn-related { margin-top: 22px; }
.learn-related-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); margin-bottom: 10px; }
.learn-related-pills { display: flex; flex-wrap: wrap; gap: 8px; }
.learn-related-pill {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--accent);
  font-size: 12px;
  font-weight: 600;
  padding: 7px 14px;
  cursor: pointer;
  transition: border-color 0.2s;
}
.learn-related-pill:hover { border-color: var(--accent); }

.learn-lesson-row-exercise {
  flex-shrink: 0;
  font-size: 15px;
  color: var(--muted);
  opacity: 0.6;
}
.learn-lesson-row-exercise.done { color: var(--accent); opacity: 1; }

/* ---- Interactive tap exercise (support-and-resistance) ---- */
.learn-exercise-mount { margin-bottom: 8px; }
.learn-exercise-loading {
  padding: 40px 16px;
  text-align: center;
  color: var(--muted);
  font-size: 13px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.learn-exercise-wrap {
  position: relative;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface);
  cursor: crosshair;
}
/* candleChart()'s SVG defaults to opacity:0 (results.css's .candle-svg) —
   a fade-in Analyze itself triggers by adding .go to its OWN wrapper
   class (.spark-wrap.candles.go) after its render animation settles.
   This exercise doesn't use that wrapper class or that animation
   sequence at all, so without this override the chart renders correctly
   into the DOM (confirmed — real candles, real coordinates) and is
   simply invisible forever: found via an actual screenshot, not just a
   "no JS error" check, which is exactly why it wasn't caught by syntax
   validation alone. */
.learn-exercise-wrap svg.candle-svg { display: block; opacity: 1; }
.learn-exercise-line {
  position: absolute;
  left: 0; right: 0;
  height: 2px;
  pointer-events: none;
  transform: translateY(-1px);
}
.learn-exercise-line-tap {
  background: var(--accent);
  box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.18);
}
.learn-exercise-line-answer {
  background: var(--text);
  border-top: 2px dashed var(--bg);
}
.learn-exercise-wrap.learn-exercise-correct .learn-exercise-line-answer,
.learn-exercise-wrap.learn-exercise-correct .learn-exercise-line-tap {
  background: var(--bullish);
}
.learn-exercise-wrap.learn-exercise-wrong .learn-exercise-line-tap { background: var(--bearish); }
.learn-exercise-wrap.learn-exercise-wrong .learn-exercise-line-answer { background: var(--text); }
.learn-exercise-hint {
  font-size: 12px;
  color: var(--muted);
  margin: 8px 0 0;
  text-align: center;
}

/* ---- Shared result/status strip, used by both exercise kinds ---- */
.learn-exercise-result {
  margin-top: 10px;
  font-size: 12.5px;
  line-height: 1.6;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--muted-2);
}
.learn-exercise-result-correct { background: rgba(var(--bullish-rgb),0.08); border-color: transparent; color: var(--bullish); }
.learn-exercise-result-wrong { background: rgba(var(--bearish-rgb),0.08); border-color: transparent; color: var(--bearish); }
.learn-exercise-result-error { background: rgba(var(--bearish-rgb),0.08); border-color: transparent; color: var(--bearish); }

/* ---- Action exercises (Demo Trading — position-sizing, leverage, ...) ---- */
.learn-exercise-action {
  margin-top: 26px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
}
.learn-exercise-check-btn {
  background: var(--accent);
  color: var(--bg);
  border: none;
  border-radius: var(--radius-sm);
  padding: 11px 18px;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  transition: opacity 0.2s;
}
.learn-exercise-check-btn:hover:not(:disabled) { opacity: 0.88; }
.learn-exercise-check-btn:disabled { cursor: default; opacity: 0.6; }
.learn-exercise-action-done {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  color: var(--bullish);
  font-weight: 600;
}
.learn-exercise-action-check { font-size: 16px; }

/* ---- Learn-link pill — reused verbatim wherever another view points
   back at a specific lesson (Analyze's indicator votes, Demo Trading's
   leverage field, Portfolio's allocation section, and the empty/intro
   states on Watchlist, Alerts, Signals, Gamma). Kept here rather than in
   each of those views' own CSS files since it's one shared component,
   not styling specific to any of them. ---- */
.learn-link-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: rgba(var(--accent-rgb), 0.1);
  color: var(--accent);
  border: 1px solid rgba(var(--accent-rgb), 0.3);
  border-radius: 999px;
  padding: 4px 11px 4px 9px;
  font-size: 11.5px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.2s, border-color 0.2s;
}
.learn-link-pill:hover { background: rgba(var(--accent-rgb), 0.18); border-color: rgba(var(--accent-rgb), 0.5); }
.learn-link-pill-icon { font-size: 12px; }

/* ---- Course flow: overall/per-module progress, resume, prev/next ---- */
.learn-overall-progress { margin: 16px 0 0; }
.learn-overall-progress-text { font-size: 12px; color: var(--muted); margin-bottom: 6px; }
.learn-overall-progress-bar, .learn-module-card-bar {
  height: 5px;
  border-radius: 3px;
  background: var(--surface);
  border: 1px solid var(--border);
  overflow: hidden;
}
.learn-overall-progress-fill, .learn-module-card-bar-fill {
  height: 100%;
  background: var(--accent);
  border-radius: 3px;
  transition: width 0.4s ease;
}
.learn-module-card-bar { margin-top: 8px; height: 4px; }

.learn-continue-banner {
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 100%;
  text-align: left;
  background: rgba(var(--accent-rgb), 0.08);
  border: 1px solid rgba(var(--accent-rgb), 0.3);
  border-radius: var(--radius);
  padding: 12px 16px;
  margin-top: 14px;
  cursor: pointer;
  transition: background 0.2s;
}
.learn-continue-banner:hover { background: rgba(var(--accent-rgb), 0.14); }
.learn-continue-label { font-size: 11px; font-weight: 700; color: var(--accent); text-transform: uppercase; letter-spacing: 0.04em; }
.learn-continue-title { font-size: 14px; font-weight: 600; color: var(--text); }

.learn-module-progress-line { font-size: 12px; color: var(--muted); margin: -4px 0 12px; }

.learn-lesson-position {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--muted);
  letter-spacing: 0.03em;
  margin-bottom: 6px;
}

.learn-course-nav {
  display: flex;
  align-items: stretch;
  gap: 10px;
  margin-top: 28px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
}
.learn-nav-btn {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  cursor: pointer;
  text-align: left;
  min-width: 0;
  transition: border-color 0.2s;
}
.learn-nav-btn:hover { border-color: var(--border-hi); }
.learn-nav-next { justify-content: flex-end; text-align: right; }
.learn-nav-arrow { font-size: 16px; color: var(--accent); flex-shrink: 0; }
.learn-nav-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; overflow: hidden; }
.learn-nav-next .learn-nav-text { align-items: flex-end; }
.learn-nav-label { font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
.learn-nav-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  max-width: 100%;
  line-height: 1.3;
  /* Two lines instead of one truncated line — a single-line ellipsis
     left long titles like "Candlestick Patterns 101" reduced to
     "Candlestick Pat..." on phone-width screens, which read as broken
     rather than intentionally shortened. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: normal;
}
.learn-nav-spacer { flex: 1; }

.learn-course-complete {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  text-align: center;
}
.learn-course-complete-title { font-family: var(--font-disp); font-size: 15px; font-weight: 700; }
.learn-recap { display: flex; gap: 18px; }
.learn-recap-stat { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.learn-recap-num { font-family: var(--font-mono); font-weight: 700; font-size: 16px; color: var(--accent); }
.learn-recap-label { font-size: 10.5px; color: var(--muted); }

@media (max-width: 480px) {
  .learn-module-grid { grid-template-columns: 1fr; }
  .learn-nav-text { max-width: 110px; }
}

/* ---- settings.css ---- */
/* ================= Settings & rich profile ================= */

/* ---------- Avatar (shared: header chip + Settings' own Profile section) ---------- */
.avatar-img, .avatar-fallback {
  border-radius: 50%; flex-shrink: 0; object-fit: cover;
}
.avatar-fallback {
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-weight: 700; font-family: var(--font-disp);
}
.user-action-with-avatar { display: inline-flex; align-items: center; gap: 8px; }

.settings-panel { display: flex; flex-direction: column; gap: 18px; max-width: 1120px; }

.settings-head {
  position: sticky; top: 0; z-index: 4;
  display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  padding: 10px 0; background: var(--bg);
}
.settings-title { font-family: var(--font-disp); font-size: 24px; font-weight: 700; margin: 0; }
.settings-nav { display: flex; gap: 4px; overflow-x: auto; scrollbar-width: none; max-width: 100%; }
.settings-nav::-webkit-scrollbar { display: none; }
.settings-nav-btn {
  flex-shrink: 0; font: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer;
  padding: 8px 13px; border-radius: 999px; border: 1px solid transparent;
  background: transparent; color: var(--muted); min-height: 36px;
  transition: background .2s ease, color .2s ease, border-color .2s ease;
}
.settings-nav-btn:hover { color: var(--text); }
.settings-nav-btn.active { background: var(--surface-hi); color: var(--text); border-color: var(--border); }
.settings-nav-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

#settings-panel [id^="settings-sec-"] { scroll-margin-top: 72px; }

.settings-grid { display: grid; gap: 16px; align-items: start; }
.settings-grid-top { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); }
.settings-grid-main { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); }
.settings-col { display: flex; flex-direction: column; gap: 16px; min-width: 0; }

.settings-section {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 20px; min-width: 0;
  animation: rise .35s cubic-bezier(0.22,1,0.36,1) both;
}
.settings-section-title {
  font-family: var(--font-disp); font-size: 15px; font-weight: 700;
  margin-bottom: 16px;
}
.settings-block-title {
  font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 10px;
}

.settings-profile-hero { display: flex; align-items: center; gap: 18px; margin-bottom: 18px; }
.settings-profile-id { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; min-width: 0; }
.settings-profile-name { font-family: var(--font-disp); font-size: 20px; font-weight: 700; overflow-wrap: anywhere; }
.settings-profile-email { font-size: 13px; color: var(--muted); overflow-wrap: anywhere; }
.settings-pill {
  display: inline-flex; align-items: center; font-size: 11px; font-weight: 700;
  padding: 4px 9px; border-radius: 999px;
  background: rgba(var(--overlay-rgb),0.08); color: var(--muted-2);
}
.settings-pill.ok { background: rgba(var(--bullish-rgb),0.14); color: var(--bullish); }

.settings-avatar-row { display: flex; align-items: center; gap: 16px; }

/* ---------- Avatar edit menu ----------
   WhatsApp/Telegram-style: the avatar itself is the only thing shown up
   front, with a small camera badge on its corner as the sole affordance
   — clicking either one reveals every actual option (upload, built-in
   presets, remove) inside a tucked-away dropdown instead of a permanent
   row of buttons competing with the rest of the Profile section. Visual
   language (surface-hi panel, border-hi, item hover/danger states)
   deliberately matches auth.css's own .user-menu dropdown so this reads
   as the same family of control, not a one-off. */
.avatar-edit-wrap { position: relative; }
.avatar-view-btn {
  position: relative; background: none; border: none; padding: 0; cursor: pointer;
  display: block; border-radius: 50%;
  transition: transform .2s ease, box-shadow .2s ease;
}
.avatar-view-btn.has-photo { cursor: zoom-in; }
.avatar-view-btn.has-photo:hover { transform: scale(1.03); box-shadow: 0 0 0 3px rgba(var(--accent-rgb),0.35); }
.avatar-view-btn:focus-visible, .avatar-edit-badge:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.avatar-edit-badge {
  position: absolute; right: -2px; bottom: -2px; z-index: 1;
  width: 30px; height: 30px; border-radius: 50%; padding: 0; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent-secondary); color: #04121c;
  border: 2px solid var(--surface);
  transition: transform 0.15s;
}
.avatar-edit-badge svg { width: 15px; height: 15px; }
.avatar-edit-badge:hover { transform: scale(1.08); }

/* ---------- Full-size photo viewer ---------- */
.avatar-viewer {
  position: fixed; inset: 0; z-index: 80;
  display: flex; flex-direction: column;
  background: rgba(4,6,10,0.97); opacity: 0;
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  transition: opacity .2s ease;
}
.avatar-viewer.open { opacity: 1; }
.avatar-viewer-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: calc(12px + env(safe-area-inset-top)) 16px 12px; color: #eef2ff;
}
.avatar-viewer-name { font-family: var(--font-disp); font-weight: 700; font-size: 15px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.avatar-viewer-close {
  flex-shrink: 0; width: 44px; height: 44px; border-radius: 50%; border: none; cursor: pointer;
  background: rgba(255,255,255,0.1); color: #fff; font-size: 16px;
}
.avatar-viewer-close:hover { background: rgba(255,255,255,0.18); }
.avatar-viewer-stage {
  flex: 1; min-height: 0; position: relative;
  display: flex; align-items: center; justify-content: center;
  padding: 8px 16px calc(24px + env(safe-area-inset-bottom));
}
.avatar-viewer-img {
  max-width: 100%; max-height: 100%; object-fit: contain; border-radius: 12px;
  opacity: 0; transform: scale(.96);
  transition: opacity .25s ease, transform .3s cubic-bezier(.2,.8,.2,1);
}
.avatar-viewer.loaded .avatar-viewer-img { opacity: 1; transform: none; }
.avatar-viewer-spinner {
  position: absolute; width: 32px; height: 32px; border-radius: 50%;
  border: 3px solid rgba(255,255,255,0.15); border-top-color: #fff;
  animation: avatarViewerSpin .8s linear infinite;
}
.avatar-viewer.loaded .avatar-viewer-spinner { display: none; }
@keyframes avatarViewerSpin { to { transform: rotate(360deg); } }
body.avatar-viewer-open { overflow: hidden; }

.avatar-edit-menu {
  position: absolute; top: calc(100% + 10px); left: 0; z-index: 5;
  width: min(280px, calc(100vw - 64px)); padding: 6px;
  background: var(--surface-hi);
  border: 1px solid var(--border-hi);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  animation: rise 0.16s cubic-bezier(0.22,1,0.36,1) both;
}
.avatar-edit-menu-item {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  background: none; border: none; cursor: pointer;
  font: inherit; font-family: var(--font-body); font-size: 12.5px; font-weight: 600;
  color: var(--muted-2); padding: 9px 10px; border-radius: 8px;
  transition: background 0.15s, color 0.15s;
}
.avatar-edit-menu-item svg { width: 16px; height: 16px; flex-shrink: 0; }
.avatar-edit-menu-item:hover { background: rgba(var(--overlay-rgb),0.06); color: var(--text); }
.avatar-edit-menu-item-danger { color: var(--bearish); }
.avatar-edit-menu-item-danger:hover { background: rgba(var(--bearish-rgb),0.1); }
.avatar-edit-menu-sep { height: 1px; background: rgba(var(--overlay-rgb),0.08); margin: 4px 6px; }
.avatar-edit-menu-label {
  font-size: 10px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--muted); padding: 8px 10px 4px;
}

/* ---------- Built-in animated avatars ----------
   Pure CSS + emoji, no image asset — see settings.js's AVATAR_PRESETS
   and main.py's _AVATAR_PRESETS for the id list. Each is a fixed
   colorful gradient fill (deliberately theme-invariant, same reasoning
   as avatarColorFor's HSL initials-avatar fallback right above: a
   small colorful badge with content on top reads fine as a fill on
   either a light or dark page, so it never needed a light-theme
   variant). Animations are grouped into a few shared families so 9
   presets don't need 9 bespoke keyframes; prefers-reduced-motion /
   the in-app Reduce Motion toggle already freezes all of these via the
   blanket html.reduce-motion rule further down this file. */
.avatar-preset {
  border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  line-height: 1;
}
@keyframes apBounce {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50%      { transform: translateY(-3px) rotate(-6deg); }
}
@keyframes apSway {
  0%, 100% { transform: rotate(-8deg); }
  50%      { transform: rotate(8deg); }
}
@keyframes apGlow {
  0%, 100% { transform: scale(1); filter: brightness(1); }
  50%      { transform: scale(1.08); filter: brightness(1.3); }
}
@keyframes apFlicker {
  0%, 100% { opacity: 1; transform: scale(1); }
  45%      { opacity: 0.75; transform: scale(0.94); }
  55%      { opacity: 1; transform: scale(1.05); }
}
@keyframes apSpin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
.ap-rocket     { background: linear-gradient(135deg, #1a1f3d, #ff6b35); animation: apBounce 1.8s ease-in-out infinite; }
.ap-bull       { background: linear-gradient(135deg, #0d3320, #34d399); animation: apBounce 1.6s ease-in-out 0.4s infinite; }
.ap-bear       { background: linear-gradient(135deg, #3d0d17, #fb7185); animation: apSway 2.2s ease-in-out infinite; }
.ap-moon       { background: linear-gradient(135deg, #1e1b4b, #818cf8); animation: apGlow 3s ease-in-out infinite; }
.ap-lightning  { background: linear-gradient(135deg, #4d3800, #f3ba2f); animation: apFlicker 1.4s ease-in-out infinite; }
.ap-fire       { background: linear-gradient(135deg, #3d0f00, #ff7a1a); animation: apFlicker 1.1s ease-in-out 0.3s infinite; }
.ap-gem        { background: linear-gradient(135deg, #003d3a, #2fb8a6); animation: apSpin 3.5s linear infinite; }
.ap-satellite  { background: linear-gradient(135deg, #1e2a3d, #60a5fa); animation: apSpin 4.5s linear 1s infinite; }
.ap-star       { background: linear-gradient(135deg, #2d0a3d, #c084fc); animation: apGlow 2.4s ease-in-out 0.8s infinite; }

.avatar-preset-picker {
  display: grid; grid-template-columns: repeat(5, 1fr);
  gap: 4px; padding: 2px 6px 6px;
}
.avatar-preset-option {
  background: none; border: 2px solid transparent; border-radius: 50%;
  padding: 2px; cursor: pointer; display: flex; align-items: center; justify-content: center;
  transition: border-color 0.15s, transform 0.15s;
}
.avatar-preset-option:hover:not(:disabled) { transform: scale(1.08); }
.avatar-preset-option.selected { border-color: var(--accent); }
.avatar-preset-option:disabled { opacity: 0.55; cursor: default; }

.settings-form { display: flex; flex-direction: column; gap: 14px; }
.settings-field { display: flex; flex-direction: column; gap: 6px; }
.settings-field > span {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: 10.5px; color: var(--muted); font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase;
}
.settings-count { font-style: normal; font-family: var(--font-mono); letter-spacing: 0; text-transform: none; }
.settings-field-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }

.settings-switch-list { display: flex; flex-direction: column; gap: 4px; }
.settings-switch-row {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 8px 0; cursor: pointer; min-height: 44px;
}
.settings-switch-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.settings-switch-title { font-size: 13.5px; color: var(--text); }
.settings-switch-sub { font-size: 12px; color: var(--muted); line-height: 1.5; }
.settings-switch { position: relative; flex-shrink: 0; width: 42px; height: 24px; }
.settings-switch input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; z-index: 1; }
.settings-switch-track {
  position: absolute; inset: 0; border-radius: 999px;
  background: var(--surface-hi); border: 1px solid var(--border);
  transition: background .2s ease, border-color .2s ease;
}
.settings-switch-track::after {
  content: ''; position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%;
  background: var(--muted); transition: transform .22s cubic-bezier(.2,.8,.2,1), background .2s ease;
}
.settings-switch input:checked + .settings-switch-track { background: var(--bullish); border-color: var(--bullish); }
.settings-switch input:checked + .settings-switch-track::after { transform: translateX(18px); background: #fff; }
.settings-switch input:focus-visible + .settings-switch-track { outline: 2px solid var(--accent); outline-offset: 2px; }
.settings-switch input:disabled + .settings-switch-track { opacity: .5; }

.settings-form-foot { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.settings-dirty { display: none; font-size: 12px; color: var(--accent); }
.settings-dirty::before { content: '● '; }
.settings-form.is-dirty .settings-dirty { display: inline; }

.settings-learn { margin-top: 16px; padding: 12px 14px; border-radius: var(--radius-sm); background: var(--surface-hi); }
.settings-learn-head { display: flex; justify-content: space-between; font-size: 12.5px; color: var(--muted-2); }
.settings-learn-head b { font-family: var(--font-mono); color: var(--text); }
.settings-learn-bar { height: 6px; border-radius: 999px; background: rgba(var(--overlay-rgb),0.08); margin-top: 8px; overflow: hidden; }
.settings-learn-bar span { display: block; height: 100%; border-radius: 999px; background: var(--accent); transform-origin: left; animation: settingsGrow .8s cubic-bezier(.2,.7,.2,1) .15s both; }
@keyframes settingsGrow { from { transform: scaleX(0); } to { transform: scaleX(1); } }
.settings-link-btn {
  margin-top: 10px; padding: 6px 0; background: none; border: none; cursor: pointer;
  font: inherit; font-size: 12.5px; font-weight: 600; color: var(--accent);
}
.settings-link-btn:hover { text-decoration: underline; }

.settings-conn-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }
.settings-conn-card {
  display: flex; flex-direction: column; gap: 8px; padding: 16px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  transition: border-color .2s ease, transform .2s ease;
}
.settings-conn-card:hover { transform: translateY(-2px); }
.settings-conn-card.is-linked { border-color: rgba(var(--accent-rgb),0.35); }
.settings-conn-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; font-size: 15px; }
.settings-conn-card p { margin: 0; font-size: 12.5px; color: var(--muted); line-height: 1.55; overflow-wrap: anywhere; flex: 1; }
.settings-conn-btn { align-self: flex-start; padding: 8px 14px; font-size: 12.5px; }

.settings-account-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }
.settings-account-card {
  display: flex; flex-direction: column; gap: 6px; align-items: flex-start;
  padding: 16px; border-radius: var(--radius-sm); background: var(--surface-hi);
}
.settings-account-card b { font-size: 14px; }
.settings-account-card p { margin: 0 0 6px; font-size: 12.5px; color: var(--muted); line-height: 1.5; flex: 1; }
.settings-account-card .btn-secondary { padding: 8px 14px; font-size: 12.5px; text-decoration: none; white-space: nowrap; margin-top: auto; }
.settings-account-delete b { color: var(--bearish); }
.settings-delete-confirm, .settings-google-confirm {
  margin-top: 14px; padding: 16px; border-radius: var(--radius-sm);
  border: 1px solid rgba(var(--bearish-rgb),0.35); background: rgba(var(--bearish-rgb),0.05);
  display: flex; flex-direction: column; gap: 12px;
  animation: rise .25s cubic-bezier(0.22,1,0.36,1) both;
}
.settings-delete-confirm[hidden], .settings-google-confirm[hidden] { display: none; }
.settings-delete-confirm input[type="password"] {
  background: var(--surface-hi); border: 1px solid var(--border); border-radius: var(--radius-sm);
  color: var(--text); font-family: var(--font-body); font-size: 13.5px; padding: 9px 12px; outline: none; width: 100%; max-width: 360px;
}
.settings-delete-confirm input[type="password"]:focus { border-color: var(--bearish); }
.settings-delete-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.settings-delete-confirm-btn {
  font: inherit; font-size: 13px; font-weight: 700; cursor: pointer;
  padding: 9px 16px; border-radius: var(--radius-sm); border: none;
  background: var(--bearish); color: #fff;
}
.settings-google-confirm p { margin: 0; font-size: 13px; color: var(--muted-2); }

@media (max-width: 900px) {
  .settings-grid-top, .settings-grid-main { grid-template-columns: minmax(0, 1fr); }
  .settings-conn-grid, .settings-account-grid { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 620px) {
  .settings-head { flex-direction: column; align-items: stretch; gap: 8px; }
  .settings-title { font-size: 22px; }
  .settings-section { padding: 16px; }
  .settings-field-grid { grid-template-columns: minmax(0, 1fr); }
  .settings-profile-hero { gap: 14px; }
  .settings-account-card .btn-secondary, .settings-conn-btn { align-self: stretch; text-align: center; min-height: 44px; }
}
.settings-field input[type="text"],
.settings-field input[type="number"],
.settings-field textarea,
.settings-field select {
  background: var(--surface-hi); border: 1px solid var(--border); border-radius: var(--radius-sm);
  color: var(--text); font-family: var(--font-body); font-size: 13.5px;
  padding: 9px 12px; outline: none; transition: border-color 0.15s; resize: vertical;
  width: 100%;
}
.settings-field input[type="text"]:focus,
.settings-field input[type="number"]:focus,
.settings-field textarea:focus,
.settings-field select:focus { border-color: var(--accent); }

.settings-tf-pills { display: flex; gap: 8px; flex-wrap: wrap; }

.settings-toggle-field {
  display: flex; align-items: center; gap: 10px; cursor: pointer;
  font-size: 13.5px; color: var(--text);
}
.settings-toggle-field input { width: 16px; height: 16px; accent-color: var(--accent); cursor: pointer; }

.settings-form .btn-primary { align-self: flex-start; padding: 9px 20px; font-size: 13px; margin-top: 2px; }

.settings-stats-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-bottom: 16px;
}
.settings-stat {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  background: var(--surface-hi); border-radius: var(--radius-sm); padding: 12px 6px;
}
.settings-stat-val { font-family: var(--font-mono); font-size: 17px; font-weight: 700; color: var(--accent-secondary); }
.settings-stat-label { font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; }
@media (max-width: 480px) { .settings-stats-grid { grid-template-columns: repeat(2, 1fr); } }

.settings-badges { display: flex; flex-wrap: wrap; gap: 8px; }
.settings-badge {
  font-family: var(--font-mono); font-size: 11px; font-weight: 700;
  padding: 5px 12px; border-radius: 999px;
  background: rgba(var(--accent-rgb),0.1); border: 1px solid rgba(var(--accent-rgb),0.35); color: var(--accent);
}
.settings-empty-note { font-size: 12.5px; color: var(--muted); font-style: italic; }

.settings-danger { border-color: rgba(var(--bearish-rgb),0.3); }
.settings-danger .settings-section-title { color: var(--bearish); }
.settings-delete-btn { color: var(--bearish); border-color: rgba(var(--bearish-rgb),0.35); white-space: nowrap; padding: 8px 16px; font-size: 12.5px; }
.settings-delete-btn:hover { border-color: var(--bearish); background: rgba(var(--bearish-rgb),0.08); }

.settings-toast {
  position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%); z-index: 70;
  max-width: calc(100vw - 32px); padding: 11px 16px; border-radius: var(--radius-sm);
  font-size: 13px; font-weight: 600; background: var(--surface-hi); border: 1px solid rgba(var(--accent-secondary-rgb),0.45);
  color: var(--accent-secondary); box-shadow: var(--shadow);
  animation: settingsToastIn .3s cubic-bezier(0.22,1,0.36,1) both;
}
.settings-toast-error { border-color: rgba(var(--bearish-rgb),0.45); color: var(--bearish); }
@keyframes settingsToastIn { from { opacity: 0; transform: translate(-50%, 10px); } to { opacity: 1; transform: translate(-50%, 0); } }
@media (max-width: 620px) {
  .settings-toast { bottom: calc(76px + env(safe-area-inset-bottom)); }
}

/* ---------- Reduce-motion preference (Settings -> Preferences) ----------
   Same intent as the OS-level prefers-reduced-motion media query already
   respected elsewhere (e.g. tour.css) — this is the in-app override for
   someone who can't easily change that OS setting (a shared/work
   computer, a locked-down device). Blunt on purpose: kill every
   transition/animation duration app-wide via one high-specificity rule
   rather than hunting down each animated selector individually. */
html.reduce-motion *, html.reduce-motion *::before, html.reduce-motion *::after {
  animation-duration: 0.001ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.001ms !important;
  scroll-behavior: auto !important;
}

/* ---- tour.css ---- */
/* ================= First-run guided tour =================
 * See tour.js for the step list and control flow. Three layered
 * pieces: a full-viewport click-blocker (keeps the rest of the page
 * inert while the tour is active), a spotlight highlight (a
 * transparent box whose huge box-shadow dims everything OUTSIDE it —
 * the standard "punch a hole" technique, no separate dim layer
 * needed), and the tooltip card itself with its own arrow pointing
 * back at whatever's highlighted. z-index sits above every other
 * fixed-position layer in the app (nav-menu's 70/71, modals' 60,
 * bottom-tab-bar's 55) since the tour needs to spotlight controls
 * living inside all of them. */

.tour-blocker {
  position: fixed; inset: 0; z-index: 198;
  background: transparent;
}

.tour-highlight {
  position: fixed; z-index: 199;
  border-radius: 12px;
  pointer-events: none;
  box-shadow:
    0 0 0 9999px rgba(4,6,12,0.82),
    0 0 0 2px var(--accent),
    0 0 22px rgba(var(--accent-rgb),0.4);
  transition: top 0.32s cubic-bezier(0.22,1,0.36,1), left 0.32s cubic-bezier(0.22,1,0.36,1),
              width 0.32s cubic-bezier(0.22,1,0.36,1), height 0.32s cubic-bezier(0.22,1,0.36,1);
}
@media (prefers-reduced-motion: reduce) {
  .tour-highlight { transition: none; }
}

.tour-tooltip {
  position: fixed; z-index: 200;
  width: min(300px, calc(100vw - 24px));
  background: var(--surface-hi);
  border: 1px solid var(--border-hi);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 18px 18px 16px;
  opacity: 0; transform: translateY(6px);
  transition: opacity 0.2s, transform 0.2s, top 0.32s cubic-bezier(0.22,1,0.36,1), left 0.32s cubic-bezier(0.22,1,0.36,1);
}
.tour-open .tour-tooltip { opacity: 1; transform: translateY(0); }

/* Arrow pointing back at the highlighted target — a rotated square,
   positioned horizontally via --tour-arrow-left (set in tour.js to
   line up with the target's own center, clamped to stay on the card). */
.tour-tooltip::before {
  content: "";
  position: absolute;
  width: 12px; height: 12px;
  background: var(--surface-hi);
  border: 1px solid var(--border-hi);
  transform: rotate(45deg);
  left: var(--tour-arrow-left, 24px);
  margin-left: -6px;
}
.tour-tooltip[data-placement="bottom"]::before {
  top: -7px; border-right: none; border-bottom: none;
}
.tour-tooltip[data-placement="top"]::before {
  bottom: -7px; border-left: none; border-top: none;
}

.tour-skip {
  position: absolute; top: 10px; right: 10px;
  width: 24px; height: 24px;
  display: flex; align-items: center; justify-content: center;
  background: none; border: none; cursor: pointer;
  color: var(--muted); font-size: 13px;
  border-radius: 6px;
  transition: color 0.15s, background 0.15s;
}
.tour-skip:hover { color: var(--text); background: rgba(var(--overlay-rgb),0.06); }

.tour-step-count {
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--accent-secondary);
  margin-bottom: 8px;
}
.tour-title {
  font-family: var(--font-disp); font-size: 16px; font-weight: 700;
  margin-bottom: 6px; padding-right: 20px;
}
.tour-body { font-size: 13px; color: var(--muted-2); line-height: 1.55; margin-bottom: 16px; }

.tour-actions { display: flex; justify-content: flex-end; gap: 8px; }
.tour-back, .tour-next { padding: 8px 16px; font-size: 12.5px; }
.tour-back:disabled { opacity: 0; pointer-events: none; }

/* Reuses .hamburger-btn's own sizing/border/hover treatment (layout.css)
   so it reads as the same family of header icon-trigger as the
   hamburger menu right next to it — accent-colored teal (rather than
   .hamburger-btn's own amber hover) is the only override, so the two
   never look identical at a glance. */
#tour-relaunch:hover { color: var(--accent-secondary); border-color: rgba(var(--accent-secondary-rgb),0.4); }

#tour-widget.tour-leaving .tour-tooltip { opacity: 0; transform: translateY(6px); }
#tour-widget.tour-leaving .tour-highlight { box-shadow: 0 0 0 9999px rgba(4,6,12,0); }

/* ---- responsive.css ---- */
@media (max-width: 620px) {
  /* Bottom value clears the fixed bottom tab bar (nav.css, real measured
     height ~53px) that overlaps this same breakpoint, plus a small gap
     so footer text doesn't sit flush against it — without this the
     footer/last content on every page renders partly hidden underneath
     it. Previously 62px+40px (a 49px measured dead gap above the bar,
     reported as "blank space that doesn't reach the bottom") — the 40px
     was meant as a small buffer, not that much empty space. */
  body { padding: 20px 14px calc(53px + 16px + env(safe-area-inset-bottom, 0px)); }
  .panel { padding: 18px 16px; }
  /* Desktop's 70px/50px breathing room pushes this whole block below the
     fold on phone-height viewports, where it lands under the fixed bottom
     tab bar and the heading reads as cut in half. Tightened here only —
     the desktop spacing is fine at that size. */
  .empty-state { padding: 24px 20px 28px; }
  .form-row { gap: 18px; }
  input[type="text"] { width: 100%; }
  .form-group { width: 100%; }
  button#analyze-btn { width: 100%; padding: 15px 34px; }
  .consensus { padding: 18px; }
  .consensus-right { text-align: left; }
  .tf-card { padding: 18px; }
  .tf-pill { padding: 10px 15px; font-size: 12px; }
  .stats-row { gap: 13px; }
  .ticker-half { gap: 26px; padding-right: 26px; }
  .tick { font-size: 11px; }
  .brand { gap: 12px; }
  .scan-chart { height: 128px; }
  .scanner { padding: 16px 16px 14px; }
  .sign { font-size: 12px; padding: 10px 16px; letter-spacing: 0.05em; }
  .market-tab, .demo-market-tab { font-size: 11px; padding: 8px 14px; letter-spacing: 0.04em; }
  .intro-signpost { gap: 9px; }
  .intro-skip { bottom: 22px; right: 22px; }
  .modal { padding: 20px 18px; max-height: 84vh; }
  /* .user-menu-wrap sits on the header's right on desktop (where the
     trigger has room to its left), so the dropdown anchors via `right: 0`
     and grows leftward. Below this width the header wraps and the trigger
     lands on the left instead — the same anchor then pushes the menu off
     the left edge of the screen. Flip the anchor so it grows rightward. */
  .user-menu { left: 0; right: auto; }
}
/* touch devices: no hover — keep cards flat, rely on tap interactions */
@media (hover: none) {
  .tf-card::before { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
