    *,*::before,*::after{margin:0;padding:0;box-sizing:border-box;}

    @keyframes alertSlideDown{from{transform:translateY(-100%);opacity:0;}to{transform:translateY(0);opacity:1;}}
    @keyframes alertFadeOut{from{opacity:1;transform:translateY(0);}to{opacity:0;transform:translateY(-100%);}}
    .alert-banner{animation:alertSlideDown .35s ease-out forwards;}
    .alert-banner.dismissing{animation:alertFadeOut .4s ease-in forwards;}

    :root{
      /* Surfaces, borders, accent, semantic — original palette */
      --bg-primary:    #09090b;
      --bg-secondary:  #0f0f12;
      --bg-tertiary:   #16161a;
      --bg-elevated:   #1c1c21;
      --bg-hover:      #22222a;
      --border-subtle: #1e1e26;
      --border-default:#2a2a35;

      --text-primary:  #f0f0f3;
      --text-secondary:#a1a1aa;
      --text-muted:    #71717a;

      --accent:        #6366f1;
      --accent-dim:    rgba(99,102,241,.12);
      --green:         #22c55e;
      --green-dim:     rgba(34,197,94,.10);
      --red:           #ef4444;
      --red-dim:       rgba(239,68,68,.10);
      --amber:         #f59e0b;

      /* Warm secondary accent — muted gold/tan. Used for "active but not
         primary" highlights (chart-type toggles, watchlist row in focus).
         Calm, distinct from the cream inversion used by 1D/5D/1W. */
      --accent-warm:     #d4b18a;
      --accent-warm-dim: rgba(212,177,138,0.10);

      /* Type — Space Grotesk (display/headings) + Inter (body/UI) + JetBrains Mono (data).
         IBM Plex stays as vendored offline fallback for all three. */
      --font-display:  'Space Grotesk', 'IBM Plex Sans', system-ui, sans-serif;
      --font-sans:     'Google Sans Flex', 'IBM Plex Sans', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
      --font-mono:     'JetBrains Mono', 'IBM Plex Mono', 'SF Mono', ui-monospace, monospace;

      /* Tracking — premium financial platform values.
         Tight negative tracking on headings = authority + trust (Bloomberg, Citadel-level). */
      --tr-display:    -0.04em;
      --tr-heading:    -0.03em;
      --tr-body:       -0.01em;
      --tr-caps:        0.10em;
      --tr-mono:        0.01em;

      /* Geometry — flat language: zero radius on chrome surfaces.
         Round corners now only appear where they're semantically required
         (true circles like the LIVE dot, scrollbar thumbs, brand video). */
      /* Sidebar — cap stays at 312px (27" full-screen). Steeper midband
         so smaller screens shrink properly:
           • 1280  → 170px (floor)
           • 1366 laptop  → 178px
           • 1500  → 195px
           • 1700  → 221px
           • 1920  → 250px
           • 2200  → 286px
           • 2400+ → 312px (cap)
         Laptops sit visibly smaller than the desk-monitor cap. */
      --sidebar-w:         clamp(170px, 13vw, 312px);
      --header-h:          56px;
      --radius:            0;
      --radius-sm:         0;

      /* Motion */
      --ease-out:      cubic-bezier(0.22, 0.8, 0.18, 1);
      --ease-in-out:   cubic-bezier(0.4, 0, 0.2, 1);
      --dur-fast:      140ms;
      --dur:           220ms;
      --dur-slow:      420ms;
      --dur-reveal:    560ms;
    }

    /* ─── Global typography rules ─── */
    h1,h2,h3,h4,h5,h6{font-family:var(--font-display);letter-spacing:var(--tr-heading);}
    h1{letter-spacing:var(--tr-display);}
    .font-mono,code,pre{font-variant-numeric:tabular-nums;}

    /* ─────────────── Mask-reveal utilities ─────────────── */
    @keyframes mask-in-up{
      from{clip-path:inset(100% 0 0 0);transform:translateY(6px);opacity:0;}
      to  {clip-path:inset(0 0 0 0);   transform:translateY(0);   opacity:1;}
    }
    @keyframes mask-in-x{
      from{clip-path:inset(0 100% 0 0);opacity:0;}
      to  {clip-path:inset(0 0 0 0);   opacity:1;}
    }
    @keyframes soft-fade{from{opacity:0;}to{opacity:1;}}
    .reveal{animation:mask-in-up var(--dur-reveal) var(--ease-out) both;}
    .reveal-x{animation:mask-in-x var(--dur-reveal) var(--ease-out) both;}
    .reveal-delay-1{animation-delay:60ms;}
    .reveal-delay-2{animation-delay:120ms;}
    .reveal-delay-3{animation-delay:180ms;}

    html,body{height:100%;overflow:hidden;}
    html{font-size:clamp(16px, calc(10px + 0.4vw), 24px);}
    body{
      font-family:var(--font-sans);
      letter-spacing:var(--tr-body);
      background:var(--bg-primary);
      color:var(--text-primary);
      display:flex;
      -webkit-font-smoothing:antialiased;
      text-rendering:optimizeLegibility;
    }

    /* ═══════════════════════════════════════════════════════════
       SIDEBAR
    ═══════════════════════════════════════════════════════════ */
    .sidebar{
      width:var(--sidebar-w);min-width:var(--sidebar-w);height:100vh;
      background:var(--bg-secondary);
      border-right:1px solid var(--border-subtle);
      display:flex;flex-direction:column;flex-shrink:0;
      transition:width .3s cubic-bezier(.4,0,.2,1),min-width .3s cubic-bezier(.4,0,.2,1);
      z-index:20;
    }
    .sidebar.collapsed{width:0;min-width:0;overflow:hidden;border-right:none;}

    /* Sidebar expand/collapse handle — soft pill on the screen edge.
       Larger hit target (28×64), subtle background that brightens on
       hover, generous SVG chevron with proper stroke. Visible against
       both the dark sidebar and the chart background. */
    .sb-toggle{
      position:fixed;top:50%;z-index:30;
      left:var(--sidebar-w);transform:translateY(-50%);
      width:24px;height:64px;
      background:var(--bg-elevated);
      border:1px solid var(--border-default);border-left:none;
      color:var(--text-secondary);
      cursor:pointer;display:flex;align-items:center;justify-content:center;
      padding:0;
      transition:left .3s cubic-bezier(.4,0,.2,1),
                 background .18s var(--ease-out),
                 color .18s var(--ease-out),
                 width .18s var(--ease-out);
    }
    .sb-toggle:hover{
      background:var(--bg-hover);
      color:var(--text-primary);
      width:28px;
    }
    .sb-toggle.collapsed{left:0;}
    /* SVG chevron sits inside the toggle — flips with the collapse state
       so the arrow always points "outward" (toward where the sidebar
       will go when clicked). */
    .sb-toggle svg{
      width:12px;height:12px;
      transition:transform .3s cubic-bezier(.4,0,.2,1);
    }
    .sb-toggle.collapsed svg{transform:rotate(180deg);}

    /* Sidebar brand — knight + "Cavalry" lockup. Hover the knight to
       play; mouse-out finishes the current loop then parks on frame 0.
       Click anywhere on the brand (logo or text) to return to the
       welcome hero — acts as the "Home" affordance. */
    /* Brand — TRULY dynamic scaling. Every dimension interpolates
       linearly between a laptop size at viewport 1366 and a monitor
       size at viewport 1920. Below 1366 it clamps to the laptop floor;
       above 1920 it clamps to the monitor cap.

       Anchor points (and what calc(K*vw - C) resolves to at each):
                 LAPTOP 1366   MONITOR 1920
         video:    38px          140px
         text:     12px           30px
         row:      56px          170px
         gap:       8px           18px

       The calc()s solve the linear formula between those two points.
       Because vw resolves continuously, the brand grows smoothly as
       the window resizes — no stepped breakpoints. */
    .sidebar-brand{
      /* Single source of truth for brand size.  Derived from the
         sidebar's own width (not the viewport) so the knight + wordmark
         are guaranteed to fit no matter how big the screen is.  The
         lockup width is roughly 11 × font + 10px gap, so dividing the
         available width (sidebar minus 32px padding) by 12 leaves a
         small safety margin at every size.  Capped at 20px so it
         doesn't get gigantic on ultra-wide displays. */
      --brand-font:clamp(8.5px, calc((var(--sidebar-w) - 32px) / 12), 20px);
      padding:12px 6px;
      border-bottom:1px solid var(--border-subtle);
      display:grid;
      place-items:center;
      text-align:center;
      min-height:calc(var(--brand-font) * 4.6 + 24px);
      cursor:pointer;
      overflow:hidden;
      transition:background .15s var(--ease-out);
    }
    .sidebar-brand:hover{
      background:var(--bg-hover);
    }
    /* Horizontal row. Sizes are driven by --brand-font on the parent;
       knight height = 4.6 × font so the ratio matches the user's
       original 4.67:1 preference exactly at every viewport. Cropping
       (aspect-ratio on the video) eliminates the WebM's 25.6/27%
       transparent padding, so a small positive gap reads correctly. */
    .sidebar-brand .brand-lockup{
      display:inline-flex;
      flex-direction:row;
      align-items:center;
      gap:clamp(8px, calc(0.361vw + 3.07px), 10px);
      /* The WebM has 25.6% transparent padding on the left of the
         visible knight. Grid place-items:center centers the lockup's
         bounding box (which includes that transparent padding), so
         visually the knight + CAVALRY appear pushed right. Shifting
         the lockup left by half the left transparent width re-centers
         the VISIBLE content (knight body to wordmark right edge) in
         the brand container. shift = 0.128 × video_w = 0.128 × 1.5 ×
         4.6 × font = 0.883 × font. */
      transform:translateX(calc(-0.883 * var(--brand-font)));
    }
    /* The knight WebM has 25.6% transparent padding on the left and
       27% on the right (verified by sampling the alpha channel of
       knight1.webm: 1176×784 natural, visible content x=301..859).
       Without cropping, the visible knight sits far from CAVALRY and
       far from the sidebar's left edge — neither end of the lockup
       reads as visually centered.
       Fix: aspect-ratio 558/784 = visible content's aspect ratio.
       Combined with object-fit:cover + object-position:center, the
       element box matches the visible knight exactly, and the WebM
       gets scaled+cropped so its visible portion fills that box. The
       bounding box now equals what the eye sees, so a normal positive
       gap and grid centering produce a visually-centered lockup. */
    .sidebar-brand video{
      height:calc(var(--brand-font) * 4.6);
      width:auto;
      cursor:pointer;
      display:block;
      flex-shrink:0;
      transition:transform .22s var(--ease-out);
    }
    .sidebar-brand:hover video{
      transform:scale(1.06);
    }
    .sidebar-brand .sb-text{
      font-family:var(--font-display);
      font-size:var(--brand-font);
      font-weight:700;
      letter-spacing:-0.02em;
      color:var(--text-primary);
      text-transform:uppercase;
      line-height:1;
      white-space:nowrap;
      flex-shrink:0;
    }
    /* Collapse label if the sidebar is cramped (<220px). */
    @media (max-width: 220px){ .sidebar-brand .sb-text{display:none;} }

    /* Sidebar nav — flush, magnetized to the sidebar edges. Each button
       fills its third of the row; vertical 1px dividers separate them.
       A horizontal line below the row separates the nav from Add Stock. */
    .sidebar-nav{
      display:flex;
      border-bottom:1px solid var(--border-subtle);
    }
    .sidebar-nav button{
      flex:1;padding:13px 0;
      border:none;border-right:1px solid var(--border-subtle);
      font-family:var(--font-display);font-size:0.75rem;font-weight:600;
      color:var(--text-muted);background:transparent;cursor:pointer;
      transition:background .15s var(--ease-out),color .15s var(--ease-out);
      letter-spacing:var(--tr-caps);text-transform:uppercase;
    }
    .sidebar-nav button:last-child{border-right:none;}
    .sidebar-nav button.active{background:var(--bg-elevated);color:var(--text-primary);}
    .sidebar-nav button:hover:not(.active){color:var(--text-secondary);background:var(--bg-hover);}
    .stg-btn{
      flex:1;padding:7px 0;border:1px solid var(--border-default);border-radius:var(--radius-sm);
      background:transparent;color:var(--text-muted);font-size:0.75rem;font-weight:700;
      cursor:pointer;transition:all .15s;font-family:var(--font-mono);
    }
    .stg-btn.selected{background:var(--accent);color:#fff;border-color:var(--accent);}
    .stg-btn:hover:not(.selected){border-color:var(--text-muted);color:var(--text-secondary);}
    .stg-select{
      width:100%;padding:8px 10px;border:1px solid var(--border-default);
      border-radius:var(--radius-sm);background:var(--bg-elevated);color:var(--text-primary);
      font-size:0.8125rem;font-family:var(--font-mono);font-weight:600;cursor:pointer;
      appearance:none;-webkit-appearance:none;
      background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 16 16' fill='none' stroke='%2399a4b8' stroke-width='1.6'><polyline points='4,6 8,10 12,6'/></svg>");
      background-repeat:no-repeat;background-position:right 10px center;padding-right:30px;
      transition:border-color .15s;
    }
    .stg-select:hover{border-color:var(--text-muted);}
    .stg-select:focus{outline:none;border-color:var(--accent);}

    /* ── Grok marker hover tooltip (over price chart) ───────── */
    .grok-tip{
      position:fixed;z-index:1000;pointer-events:none;
      min-width:240px;max-width:340px;
      padding:14px 16px;
      background:rgba(12,12,18,0.55);
      border:1px solid rgba(167,139,250,0.18);
      border-radius:8px;
      box-shadow:0 12px 32px rgba(0,0,0,0.55);
      backdrop-filter:blur(24px) saturate(145%);
      -webkit-backdrop-filter:blur(24px) saturate(145%);
      font-family:var(--font-sans);
      opacity:0;transform:translateY(4px);
      transition:opacity .14s ease,transform .14s ease;
    }
    .grok-tip.show{opacity:1;transform:translateY(0);}
    .grok-tip-head{
      display:flex;align-items:center;gap:10px;margin-bottom:10px;
      padding-bottom:9px;
      border-bottom:1px solid rgba(255,255,255,0.06);
    }
    .grok-tip-score{
      font-family:var(--font-mono);font-size:1.125rem;font-weight:700;
      letter-spacing:-0.5px;line-height:1;
    }
    .grok-tip-score.pos{color:#22c55e;}
    .grok-tip-score.neg{color:#ef4444;}
    .grok-tip-time{font-family:var(--font-mono);font-size:0.6875rem;color:#7a7a86;margin-left:auto;}
    .grok-tip-trigger{
      display:inline-block;font-size:0.5625rem;letter-spacing:1.6px;font-weight:700;text-transform:uppercase;
      padding:2px 8px;background:rgba(167,139,250,0.10);color:#a78bfa;
      border:1px solid rgba(167,139,250,0.20);
      margin-bottom:10px;
    }
    .grok-tip-themes{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px;}
    .grok-tip-theme{
      font-size:0.625rem;font-weight:600;padding:2px 8px;
      background:rgba(167,139,250,0.10);color:#c4b5fd;
      border:1px solid rgba(167,139,250,0.20);letter-spacing:0.2px;
    }
    .grok-tip-narrative{
      font-size:0.75rem;line-height:1.5;color:#c8c8d2;font-style:italic;
    }
    .grok-tip-hint{
      margin-top:10px;padding-top:9px;
      border-top:1px solid rgba(255,255,255,0.05);
      font-size:0.625rem;color:#5a5a66;letter-spacing:0.6px;text-transform:uppercase;font-weight:600;
    }

    /* Highlight a call card briefly when arriving from a chart marker click */
    @keyframes sxHighlight{
      0%   {background:linear-gradient(135deg,rgba(167,139,250,0.18),rgba(167,139,250,0.08));
            box-shadow:0 0 0 2px rgba(167,139,250,0.45),0 0 32px rgba(167,139,250,0.32);}
      40%  {background:linear-gradient(135deg,rgba(167,139,250,0.10),rgba(167,139,250,0.04));
            box-shadow:0 0 0 1px rgba(167,139,250,0.25),0 0 18px rgba(167,139,250,0.18);}
      100% {background:transparent;box-shadow:none;}
    }
    .sx-call.sx-highlight{
      animation:sxHighlight 2.4s cubic-bezier(.16,1,.3,1) both;
      padding:14px;margin:-14px;
    }

    /* ── Grok Sources view ───────────────────────────────────── */
    .sources-view{
      position:absolute;inset:0;display:flex;background:var(--bg-primary);
      font-family:var(--font-sans);
    }
    .sources-view.hidden{display:none;}

    /* Calm staggered entrance — every time the user opens Sources */
    @keyframes sxFadeUp{
      0%{opacity:0;transform:translateY(10px);}
      100%{opacity:1;transform:translateY(0);}
    }
    @keyframes sxFadeIn{
      0%{opacity:0;}
      100%{opacity:1;}
    }
    .sources-view.sx-enter .sx-left,
    .sources-view.sx-enter .sx-main,
    .sources-view.sx-enter .sx-right{
      animation:sxFadeIn 0.5s ease both;
    }
    .sources-view.sx-enter .sx-left{animation-delay:0s;}
    .sources-view.sx-enter .sx-main{animation-delay:0.08s;}
    .sources-view.sx-enter .sx-right{animation-delay:0.16s;}
    .sources-view.sx-enter .sx-aside-inner > *,
    .sources-view.sx-enter .sx-main-head,
    .sources-view.sx-enter .sx-feed > *{
      animation:sxFadeUp 0.65s cubic-bezier(.16,1,.3,1) both;
    }
    .sources-view.sx-enter .sx-aside-inner > *:nth-child(1){animation-delay:0.10s;}
    .sources-view.sx-enter .sx-aside-inner > *:nth-child(2){animation-delay:0.14s;}
    .sources-view.sx-enter .sx-aside-inner > *:nth-child(3){animation-delay:0.18s;}
    .sources-view.sx-enter .sx-aside-inner > *:nth-child(4){animation-delay:0.22s;}
    .sources-view.sx-enter .sx-aside-inner > *:nth-child(5){animation-delay:0.26s;}
    .sources-view.sx-enter .sx-aside-inner > *:nth-child(6){animation-delay:0.30s;}
    .sources-view.sx-enter .sx-aside-inner > *:nth-child(7){animation-delay:0.34s;}
    .sources-view.sx-enter .sx-aside-inner > *:nth-child(8){animation-delay:0.38s;}
    .sources-view.sx-enter .sx-aside-inner > *:nth-child(9){animation-delay:0.42s;}
    .sources-view.sx-enter .sx-main-head{animation-delay:0.18s;}
    .sources-view.sx-enter .sx-feed > *:nth-child(1){animation-delay:0.28s;}
    .sources-view.sx-enter .sx-feed > *:nth-child(2){animation-delay:0.34s;}
    .sources-view.sx-enter .sx-feed > *:nth-child(3){animation-delay:0.40s;}
    .sources-view.sx-enter .sx-feed > *:nth-child(n+4){animation-delay:0.46s;}

    /* Custom aesthetic scrollbars (only inside Sources view) */
    .sources-view *::-webkit-scrollbar{width:8px;height:8px;}
    .sources-view *::-webkit-scrollbar-track{background:transparent;}
    .sources-view *::-webkit-scrollbar-thumb{
      background:rgba(167,139,250,0.18);border-radius:4px;
      transition:background .18s ease;
    }
    .sources-view *::-webkit-scrollbar-thumb:hover{background:rgba(167,139,250,0.45);}
    .sources-view{scrollbar-width:thin;scrollbar-color:rgba(167,139,250,0.25) transparent;}

    /* Sticky asides */
    .sx-aside{
      flex-shrink:0;
      overflow-y:auto;
      position:relative;
    }
    .sx-left{
      width:340px;
      border-right:1px solid rgba(167,139,250,0.08);
      background:
        radial-gradient(ellipse at top left, rgba(167,139,250,0.04), transparent 50%),
        linear-gradient(180deg,#0d0d12 0%,#08080c 100%);
    }
    .sx-right{
      width:300px;
      border-left:1px solid rgba(167,139,250,0.08);
      background:
        radial-gradient(ellipse at top right, rgba(99,142,255,0.03), transparent 50%),
        linear-gradient(180deg,#0a0a0e 0%,#08080c 100%);
    }
    .sx-aside-inner{padding:42px 26px 36px;}
    .sx-right .sx-aside-inner{padding-top:78px;}
    .sx-eyebrow{
      display:flex;align-items:center;gap:9px;
      font-size:0.75rem;font-weight:700;letter-spacing:2.4px;
      color:#8b8b96;text-transform:uppercase;margin-bottom:18px;
    }
    .sx-eyebrow-pulse{
      width:6px;height:6px;border-radius:50%;
      background:#a78bfa;box-shadow:0 0 0 0 rgba(167,139,250,0.55);
      animation:sxPulse 2.4s ease-out infinite;
    }
    @keyframes sxPulse{
      0%{box-shadow:0 0 0 0 rgba(167,139,250,0.6);}
      70%{box-shadow:0 0 0 7px rgba(167,139,250,0);}
      100%{box-shadow:0 0 0 0 rgba(167,139,250,0);}
    }
    .sx-symbol{
      font-family:var(--font-mono);font-size:3rem;font-weight:700;
      letter-spacing:-1px;line-height:1;margin-bottom:36px;
      background:linear-gradient(180deg,#fff 0%,#a8a8b8 100%);
      -webkit-background-clip:text;-webkit-text-fill-color:transparent;
      background-clip:text;
    }
    .sx-divider{
      display:flex;align-items:center;gap:12px;margin:30px 0 16px;
    }
    .sx-divider span{
      font-size:0.6875rem;font-weight:700;letter-spacing:2.4px;color:#5a5a66;
      flex-shrink:0;
    }
    .sx-divider::after{
      content:'';flex:1;height:1px;
      background:linear-gradient(90deg,rgba(167,139,250,0.18),transparent);
    }

    /* Posture meter — refined gauge: thin track, subtle gradient, slim animated needle */
    .sx-meter{margin-bottom:24px;padding:0 4px;}
    .sx-meter-track{
      position:relative;height:5px;
      background:linear-gradient(90deg,rgba(239,68,68,0.10) 0%,rgba(255,255,255,0.03) 50%,rgba(34,197,94,0.10) 100%);
    }
    .sx-meter-mid{
      position:absolute;left:50%;top:-2px;bottom:-2px;width:1px;
      background:rgba(255,255,255,0.16);transform:translateX(-50%);pointer-events:none;
    }
    .sx-meter-fill{
      position:absolute;top:0;bottom:0;
      transition:left .55s cubic-bezier(.16,1,.3,1),width .55s cubic-bezier(.16,1,.3,1),background .35s ease;
    }
    .sx-meter-fill.pos{
      background:linear-gradient(90deg,rgba(34,197,94,0.15),#22c55e);
      box-shadow:0 0 18px rgba(34,197,94,0.32);
    }
    .sx-meter-fill.neg{
      background:linear-gradient(90deg,#ef4444,rgba(239,68,68,0.15));
      box-shadow:0 0 18px rgba(239,68,68,0.32);
    }
    .sx-meter-fill.neu{background:rgba(140,140,150,0.3);}
    .sx-meter-needle{
      position:absolute;top:-6px;width:2px;height:17px;
      background:#fff;
      box-shadow:0 0 14px rgba(255,255,255,0.7), 0 0 4px rgba(255,255,255,0.9);
      transform:translateX(-50%);
      transition:left .55s cubic-bezier(.16,1,.3,1);
      pointer-events:none;
    }
    .sx-meter-needle::before{
      content:'';position:absolute;top:-3px;left:50%;
      width:7px;height:7px;border-radius:50%;
      background:#fff;transform:translateX(-50%);
      box-shadow:0 0 12px rgba(255,255,255,0.6);
    }
    .sx-meter-scale{
      display:flex;justify-content:space-between;margin-top:14px;padding:0 2px;
      font-family:var(--font-mono);font-size:0.625rem;color:#4a4a54;letter-spacing:2px;
      font-weight:700;
    }
    .sx-meter-scale span:nth-child(2){color:#2e2e36;letter-spacing:1px;}

    @keyframes sxPostureIn{
      0%{opacity:0;transform:translateY(6px);}
      100%{opacity:1;transform:translateY(0);}
    }
    .sx-posture-row{
      display:flex;align-items:baseline;gap:14px;margin-bottom:0;
      padding-top:4px;
    }
    .sx-posture-num{
      font-family:var(--font-mono);font-size:2.875rem;font-weight:300;
      color:#e6e6ef;letter-spacing:-1.8px;line-height:1;
      animation:sxPostureIn .6s cubic-bezier(.16,1,.3,1) both;
      transition:color .35s ease,text-shadow .35s ease;
    }
    .sx-posture-num.pos{color:#22c55e;text-shadow:0 0 32px rgba(34,197,94,0.35),0 0 8px rgba(34,197,94,0.15);}
    .sx-posture-num.neg{color:#ef4444;text-shadow:0 0 32px rgba(239,68,68,0.35),0 0 8px rgba(239,68,68,0.15);}
    .sx-posture-label{
      font-size:0.6875rem;font-weight:600;color:#7a7a86;
      text-transform:uppercase;letter-spacing:2px;
      animation:sxPostureIn .6s cubic-bezier(.16,1,.3,1) both;
      animation-delay:.05s;
    }

    .sx-themes{display:flex;gap:6px;flex-wrap:wrap;}
    .sx-theme{
      font-size:0.75rem;font-weight:600;padding:6px 12px;border-radius:2px;
      background:linear-gradient(135deg,rgba(167,139,250,0.14),rgba(99,142,255,0.06));
      color:#d8c8ff;
      border:1px solid rgba(167,139,250,0.26);
      letter-spacing:0.3px;
      transition:transform .15s ease,border-color .15s ease;
    }
    .sx-theme:hover{transform:translateY(-1px);border-color:rgba(167,139,250,0.5);}

    .sx-quote{
      position:relative;margin:0;
      padding:22px 20px 20px 26px;
      font-size:0.9375rem;line-height:1.7;color:#d8d8df;
      font-style:italic;
      background:linear-gradient(135deg,rgba(167,139,250,0.04),rgba(255,255,255,0.012));
      border:1px solid rgba(167,139,250,0.12);
      border-left:3px solid rgba(167,139,250,0.55);
      border-radius:1px;
    }
    .sx-quote::before{
      content:'"';position:absolute;top:-4px;left:14px;
      font-family:Georgia,serif;font-size:2.875rem;color:rgba(167,139,250,0.22);
      line-height:1;font-style:normal;
    }

    .sx-meta{
      display:flex;flex-direction:column;gap:14px;
      margin-top:36px;padding-top:24px;
      border-top:1px solid rgba(167,139,250,0.08);
    }
    .sx-meta-row{
      display:flex;justify-content:space-between;align-items:center;
    }
    .sx-meta-row span{color:#6a6a76;letter-spacing:1.2px;text-transform:uppercase;font-weight:700;font-size:0.6875rem;}
    .sx-meta-row b{
      font-family:var(--font-mono);font-weight:600;color:#d0d0d8;font-size:0.8125rem;
    }

    /* Center column — tweet feed */
    .sx-main{flex:1;overflow-y:auto;min-width:0;}
    .sx-main-head{
      padding:42px 44px 20px;
      border-bottom:1px solid rgba(167,139,250,0.06);
      position:sticky;top:0;
      background:linear-gradient(180deg,rgba(9,9,11,0.96) 0%,rgba(9,9,11,0.92) 100%);
      backdrop-filter:blur(8px);
      z-index:2;
    }
    .sx-main-head-row{display:flex;align-items:baseline;gap:14px;margin-bottom:8px;}
    .sx-main-head h2{
      margin:0;font-size:1.375rem;font-weight:600;color:var(--text-primary);
      letter-spacing:-0.4px;
    }
    .sx-main-count{
      font-family:var(--font-mono);font-size:0.6875rem;font-weight:600;
      padding:3px 9px;border-radius:2px;
      background:rgba(167,139,250,0.12);color:#c4b5fd;
      border:1px solid rgba(167,139,250,0.22);letter-spacing:0.6px;
    }
    .sx-main-sub{font-size:0.8125rem;color:#7a7a86;}
    .sx-feed{padding:28px 44px 80px;display:flex;flex-direction:column;gap:36px;}
    .sx-empty{
      padding:80px 32px;text-align:center;font-size:0.875rem;color:#6a6a76;line-height:1.6;
    }

    /* Call group */
    .sx-call{display:flex;flex-direction:column;gap:14px;}
    .sx-call-bar{
      display:flex;align-items:center;gap:12px;
      font-size:0.75rem;color:#7a7a86;
    }
    .sx-call-dot{
      display:inline-block;width:8px;height:8px;border-radius:50%;
      background:rgba(140,140,150,0.5);
      box-shadow:0 0 0 4px rgba(140,140,150,0.08);
    }
    .sx-call-dot.pos{background:#22c55e;box-shadow:0 0 0 4px rgba(34,197,94,0.12);}
    .sx-call-dot.neg{background:#ef4444;box-shadow:0 0 0 4px rgba(239,68,68,0.12);}
    .sx-call-time{font-family:var(--font-mono);color:#a8a8b8;font-size:0.8125rem;}
    .sx-call-trigger{
      font-size:0.625rem;letter-spacing:1.6px;text-transform:uppercase;font-weight:700;
      padding:3px 9px;border-radius:1px;
      background:rgba(167,139,250,0.08);color:#a78bfa;
      border:1px solid rgba(167,139,250,0.18);
    }
    .sx-call-posture{
      margin-left:auto;font-family:var(--font-mono);font-weight:700;font-size:0.875rem;
    }
    .sx-call-posture.pos{color:#22c55e;}
    .sx-call-posture.neg{color:#ef4444;}
    .sx-call-posture.neu{color:#7a7a86;}

    /* Tweet cards — pinterest/twitter style with avatar */
    .sx-posts{display:flex;flex-direction:column;gap:10px;}
    .sx-post{
      position:relative;display:block;text-decoration:none;color:inherit;
      padding:20px 22px;
      background:linear-gradient(180deg,rgba(255,255,255,0.022),rgba(255,255,255,0.008));
      border:1px solid rgba(255,255,255,0.05);
      border-radius:2px;
      transition:transform .2s ease,background .2s ease,border-color .2s ease,box-shadow .2s ease;
    }
    .sx-post:hover{
      transform:translateY(-1px);
      background:linear-gradient(180deg,rgba(167,139,250,0.05),rgba(255,255,255,0.012));
      border-color:rgba(167,139,250,0.22);
      box-shadow:0 8px 28px rgba(0,0,0,0.28),0 0 0 1px rgba(167,139,250,0.08);
    }
    .sx-post-head{
      display:flex;align-items:center;gap:12px;margin-bottom:12px;
    }
    .sx-avatar{
      width:36px;height:36px;border-radius:50%;flex-shrink:0;
      display:flex;align-items:center;justify-content:center;
      font-family:var(--font-sans);font-size:0.875rem;font-weight:700;color:#fff;
      background:linear-gradient(135deg,#a78bfa,#638eff);
      letter-spacing:-0.3px;
    }
    .sx-post-id{display:flex;flex-direction:column;line-height:1.2;min-width:0;}
    .sx-post-author{
      font-weight:700;color:var(--text-primary);
      font-family:var(--font-sans);font-size:0.875rem;
      overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
    }
    .sx-post-handle{color:#7a7a86;font-size:0.75rem;}
    .sx-post-likes{
      margin-left:auto;display:inline-flex;align-items:center;gap:6px;
      font-family:var(--font-mono);font-size:0.8125rem;font-weight:600;color:#a8a8b8;
      padding:4px 10px;border-radius:2px;
      background:rgba(239,68,68,0.06);
      border:1px solid rgba(239,68,68,0.12);
    }
    .sx-post-likes svg{opacity:0.85;width:12px;height:12px;color:#ef4444;}
    .sx-post-likes svg{opacity:0.85;width:11px;height:11px;color:#ef4444;}
    .sx-post-text{
      font-size:0.875rem;line-height:1.6;color:#dadae3;
      white-space:pre-wrap;word-break:break-word;
    }
    .sx-post-foot{
      margin-top:14px;padding-top:12px;
      border-top:1px solid rgba(255,255,255,0.04);
      display:flex;align-items:center;gap:6px;
      font-size:0.6875rem;color:#6a6a76;letter-spacing:0.4px;font-weight:600;
      text-transform:uppercase;
      transition:color .18s ease;
    }
    .sx-post:hover .sx-post-foot{color:#a78bfa;}
    .sx-post-foot svg{opacity:0.7;width:11px;height:11px;}
    .sx-no-posts{
      padding:18px 20px;font-size:0.8125rem;color:#6a6a76;
      font-style:italic;
      background:rgba(255,255,255,0.012);
      border:1px dashed rgba(255,255,255,0.06);border-radius:1px;
    }

    /* Right column — sparkline + stats + theme bars */
    .sx-spark-wrap{
      margin-bottom:36px;padding:0;
      background:transparent;border:0;
    }
    .sx-spark{width:100%;height:96px;display:block;}
    .sx-spark-axis{
      display:flex;justify-content:space-between;margin-top:10px;
      font-family:var(--font-mono);font-size:0.625rem;color:#6a6a76;letter-spacing:1.4px;
      font-weight:600;
    }

    /* Stat list — clean column with internal dividers, no boxes */
    .sx-stat-grid{
      display:flex;flex-direction:column;
      border-top:1px solid rgba(167,139,250,0.08);
      border-bottom:1px solid rgba(167,139,250,0.08);
    }
    .sx-stat{
      display:flex;justify-content:space-between;align-items:baseline;
      padding:16px 0;
      border-bottom:1px solid rgba(167,139,250,0.05);
    }
    .sx-stat:last-child{border-bottom:0;}
    .sx-stat-label{
      font-size:0.6875rem;font-weight:700;color:#6a6a76;letter-spacing:1.4px;
      text-transform:uppercase;margin:0;
    }
    .sx-stat-val{
      font-family:var(--font-mono);font-size:1.375rem;font-weight:700;color:#e6e6ef;
      letter-spacing:-0.5px;line-height:1;
      white-space:nowrap;
    }
    .sx-stat-val.pos{color:#22c55e;}
    .sx-stat-val.neg{color:#ef4444;}
    /* "Range" shows two values + arrow — shrink so it fits the column */
    #sx-stat-range{font-size:0.875rem;font-weight:600;color:#c8c8d2;}

    .sx-theme-bars{display:flex;flex-direction:column;gap:14px;margin-top:10px;}
    .sx-theme-bar{
      display:flex;flex-direction:column;gap:6px;
    }
    .sx-theme-bar-row{
      display:flex;align-items:baseline;justify-content:space-between;gap:10px;
    }
    .sx-theme-bar-name{
      color:#c8c8d2;font-weight:600;letter-spacing:0.2px;font-size:0.8125rem;
      overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
    }
    .sx-theme-bar-count{
      font-family:var(--font-mono);font-size:0.6875rem;color:#6a6a76;font-weight:600;
    }
    .sx-theme-bar-track{
      width:100%;height:3px;
      background:rgba(255,255,255,0.04);overflow:hidden;
    }
    .sx-theme-bar-fill{
      height:100%;
      background:linear-gradient(90deg,rgba(167,139,250,0.4),#a78bfa);
      transition:width .55s cubic-bezier(.4,0,.2,1);
    }

    /* Add Stock — flush against the sidebar edges, no internal padding
       so the button itself spans the full width like a magnetic surface. */
    .add-row{padding:0;border-bottom:1px solid var(--border-subtle);}
    .add-row button{
      width:100%;
      background:transparent;border:none;
      color:var(--text-muted);font-family:var(--font-sans);font-size:0.8125rem;font-weight:600;
      padding:14px 18px;cursor:pointer;
      transition:background .15s var(--ease-out),color .15s var(--ease-out);
      display:flex;align-items:center;gap:10px;
      letter-spacing:.02em;
    }
    .add-row button:hover{background:var(--bg-hover);color:var(--text-primary);}
    .add-row button:hover svg{opacity:1;color:var(--accent);}
    .add-row button svg{opacity:.55;transition:opacity .15s var(--ease-out),color .15s var(--ease-out);}

    /* Symbol search modal */
    .search-overlay{
      position:fixed;inset:0;z-index:500;
      background:rgba(0,0,0,.6);
      backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);
      display:flex;align-items:flex-start;justify-content:center;
      padding-top:min(12vh,100px);
      opacity:0;pointer-events:none;
      transition:opacity .2s ease;
    }
    .search-overlay.open{opacity:1;pointer-events:auto;}
    .search-modal{
      width:min(560px,92vw);
      max-height:min(520px,75vh);
      background:var(--bg-secondary);
      border:1px solid var(--border-default);
      /* Tiny corner curve — the rest of the dashboard uses sharp
         corners by token, but the search modal floats over the page
         so a touch of radius softens the edges without making it
         feel like a bubble. */
      border-radius:5px;
      box-shadow:0 24px 80px rgba(0,0,0,.6);
      display:flex;flex-direction:column;
      transform:translateY(-8px) scale(.98);
      transition:transform .2s ease;
    }
    .search-overlay.open .search-modal{transform:translateY(0) scale(1);}
    .search-head{
      display:flex;align-items:center;gap:10px;
      padding:16px 20px;border-bottom:1px solid var(--border-subtle);
    }
    .search-head svg{color:var(--text-muted);flex-shrink:0;}
    .search-head input{
      flex:1;background:none;border:none;outline:none;
      color:var(--text-primary);font-family:var(--font-sans);font-size:1.0625rem;font-weight:500;
      caret-color:var(--accent);
    }
    .search-head input::placeholder{color:var(--text-muted);}
    .search-close{
      background:none;border:none;color:var(--text-muted);cursor:pointer;
      padding:4px;border-radius:4px;transition:all .15s;
      display:flex;align-items:center;
    }
    .search-close:hover{color:var(--text-primary);background:var(--bg-hover);}
    .search-results{
      flex:1;overflow-y:auto;padding:4px 0;
    }
    .search-results::-webkit-scrollbar{width:4px;}
    .search-results::-webkit-scrollbar-thumb{background:var(--border-default);border-radius:2px;}
    .sr-item{
      display:flex;align-items:center;gap:12px;
      padding:10px 20px;cursor:pointer;transition:background .1s;
    }
    .sr-item:hover,.sr-item.active{background:var(--bg-hover);}
    .sr-sym{font-family:var(--font-mono);font-size:0.875rem;font-weight:700;color:var(--text-primary);min-width:70px;}
    .sr-name{font-size:0.8125rem;color:var(--text-secondary);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
    .sr-meta{display:flex;align-items:center;gap:8px;flex-shrink:0;}
    .sr-type{font-family:var(--font-mono);font-size:0.75rem;color:var(--text-muted);padding:2px 6px;border:1px solid var(--border-subtle);border-radius:3px;}
    .sr-exch{font-family:var(--font-mono);font-size:0.75rem;color:var(--text-muted);}
    .sr-empty{padding:32px 20px;text-align:center;color:var(--text-muted);font-size:0.875rem;}
    .sr-hint{padding:16px 20px;text-align:center;color:var(--text-muted);font-size:0.8125rem;}

    .stock-list{flex:1;overflow-y:auto;padding:0;}
    .stock-list::-webkit-scrollbar{width:4px;}
    .stock-list::-webkit-scrollbar-track{background:transparent;}
    .stock-list::-webkit-scrollbar-thumb{background:var(--border-default);border-radius:2px;}

    /* ── Account chip (sidebar bottom) ───────────────────────────────────
       Pinned to the bottom of the sidebar via the flex layout (stock-list
       has flex:1, so this naturally sits after it). Click toggles the
       account-menu above it. */
    .account-chip{
      position:relative;
      display:flex;align-items:center;gap:10px;
      padding:10px 12px;
      border-top:1px solid var(--border-default);
      cursor:pointer;
      transition:background .12s ease;
      outline:none;
    }
    .account-chip:hover,.account-chip:focus-visible{background:var(--bg-hover);}
    .account-avatar{
      width:30px;height:30px;border-radius:50%;
      object-fit:cover;flex-shrink:0;
      background:var(--bg-elevated);
      border:1px solid var(--border-default);
    }
    .account-avatar-fallback{
      display:flex;align-items:center;justify-content:center;
      color:var(--text-secondary);font-weight:600;font-size:0.8125rem;
    }
    .account-meta{flex:1;min-width:0;}
    .account-name{
      font-size:0.8125rem;font-weight:500;color:var(--text-primary);
      white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
    }
    .account-email{
      font-size:0.6875rem;color:var(--text-muted);
      white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
    }
    .account-caret{color:var(--text-muted);flex-shrink:0;transition:transform .15s ease;}
    .account-chip[aria-expanded="true"] .account-caret{transform:rotate(180deg);}

    .account-menu{
      position:absolute;left:8px;right:8px;bottom:calc(100% + 6px);
      background:var(--bg-elevated);
      border:1px solid var(--border-default);
      border-radius:8px;
      padding:4px;
      box-shadow:0 8px 24px rgba(0,0,0,0.4);
      z-index:30;
    }
    .account-menu-item{
      display:flex;align-items:center;gap:10px;
      padding:8px 10px;
      border-radius:6px;
      color:var(--text-secondary);
      font-size:0.8125rem;font-weight:500;
      text-decoration:none;
      transition:background .12s ease,color .12s ease;
    }
    .account-menu-item:hover{background:var(--bg-hover);color:var(--text-primary);}
    .account-menu-item svg{color:var(--text-muted);}
    .account-menu-item:hover svg{color:var(--accent);}

    /* Collapsed sidebar — hide everything but the avatar */
    .sidebar.collapsed .account-meta,
    .sidebar.collapsed .account-caret{display:none;}
    .sidebar.collapsed .account-chip{justify-content:center;padding:10px 8px;}

    /* ── Home top-right account / auth pills ──────────────────────────── */
    .home-account{
      position:fixed;top:20px;right:24px;z-index:50;
      display:flex;align-items:center;gap:8px;
    }
    .home-auth-link{
      padding:8px 14px;
      color:rgba(212,177,138,0.70);
      font-family:'IBM Plex Sans',sans-serif;
      font-size:0.8125rem;font-weight:500;
      letter-spacing:0.01em;
      text-decoration:none;
      border-radius:8px;
      transition:color .18s ease,background .18s ease;
    }
    .home-auth-link:hover{
      color:#e7c9a3;
      background:rgba(212,177,138,0.07);
    }
    .home-auth-cta{
      padding:9px 20px;
      background:linear-gradient(180deg,
        rgba(212,177,138,0.26) 0%,
        rgba(212,177,138,0.11) 100%);
      -webkit-backdrop-filter:blur(12px) saturate(1.3);
      backdrop-filter:blur(12px) saturate(1.3);
      border:1px solid rgba(212,177,138,0.50);
      color:#e7c9a3;
      font-family:'IBM Plex Sans',sans-serif;
      font-size:0.8125rem;font-weight:600;
      letter-spacing:0.03em;
      border-radius:8px;
      text-decoration:none;
      box-shadow:
        inset 0 1px 0 rgba(255,220,170,0.14),
        0 4px 18px -6px rgba(212,140,70,0.28);
      transition:background .20s ease,border-color .20s ease,
                 box-shadow .20s ease,color .20s ease,transform .10s ease;
    }
    .home-auth-cta:hover{
      background:linear-gradient(180deg,
        rgba(212,177,138,0.38) 0%,
        rgba(212,177,138,0.20) 100%);
      border-color:rgba(212,177,138,0.72);
      color:#f5e0c0;
      box-shadow:
        inset 0 1px 0 rgba(255,220,170,0.20),
        0 6px 24px -6px rgba(212,140,70,0.48);
      transform:translateY(-1px);
    }
    .home-auth-cta:active{transform:translateY(0);}

    .home-account-chip{
      display:flex;align-items:center;gap:8px;
      padding:6px 12px 6px 6px;
      background:rgba(22,22,27,0.7);
      border:1px solid var(--border-default);
      border-radius:999px;
      backdrop-filter:blur(8px);
      text-decoration:none;color:var(--text-primary);
      font-family:'IBM Plex Sans',sans-serif;
      font-size:0.8125rem;font-weight:500;
      transition:border-color .12s ease,background .12s ease;
    }
    .home-account-chip:hover{border-color:var(--text-muted);background:rgba(29,29,36,0.85);}
    .home-account-chip img{
      width:24px;height:24px;border-radius:50%;object-fit:cover;
    }
    .home-account-fallback{
      width:24px;height:24px;border-radius:50%;
      background:var(--bg-elevated);
      display:inline-flex;align-items:center;justify-content:center;
      color:var(--text-secondary);font-weight:600;font-size:0.6875rem;
    }
    .home-account-name{
      max-width:160px;
      white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
    }
    .home-account-logout{
      display:inline-flex;align-items:center;justify-content:center;
      width:34px;height:34px;
      background:rgba(22,22,27,0.7);
      border:1px solid var(--border-default);
      border-radius:50%;
      color:var(--text-muted);
      backdrop-filter:blur(8px);
      transition:color .12s ease,border-color .12s ease;
    }
    .home-account-logout:hover{color:var(--text-primary);border-color:var(--text-muted);}

    /* Tickers — flush, full-width, separated by 1px lines. The active
       state uses a left accent bar (2px) instead of an outlined pill,
       so the row stays visually anchored to its row. */
    .stock-item{
      display:flex;align-items:center;gap:10px;
      padding:12px 18px;margin:0;
      cursor:pointer;
      border-bottom:1px solid var(--border-subtle);
      border-left:2px solid transparent;
      transition:background .12s var(--ease-out),border-color .12s var(--ease-out);
    }
    .stock-item:hover{background:var(--bg-hover);}
    .stock-item.active{
      background:var(--accent-warm-dim);
      border-left-color:var(--accent-warm);
    }

    .si-info{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1;}
    .si-sym{font-family:var(--font-sans);font-size:0.875rem;font-weight:700;letter-spacing:var(--tr-heading);color:var(--text-primary);}
    .si-name{font-size:0.75rem;font-weight:500;color:var(--text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;letter-spacing:0;}
    .si-meta{font-family:var(--font-mono);font-size:0.75rem;font-weight:600;color:var(--text-muted);font-variant-numeric:tabular-nums;letter-spacing:var(--tr-mono);}
    .si-rm{
      background:none;border:none;color:var(--text-muted);font-size:0.9375rem;
      cursor:pointer;padding:4px;border-radius:4px;line-height:1;flex-shrink:0;
      transition:all .12s;opacity:0;
    }
    .stock-item:hover .si-rm{opacity:1;}
    .si-rm:hover{color:var(--red);background:var(--red-dim);}

    .prog-wrap{width:100%;height:3px;background:var(--bg-primary);border-radius:2px;margin-top:4px;overflow:hidden;}
    .prog-bar{height:100%;background:var(--accent);border-radius:2px;transition:width .4s ease;}
    .prog-txt{font-size:0.6875rem;color:var(--accent);margin-top:3px;font-family:var(--font-mono);}

    /* ═══════════════════════════════════════════════════════════
       MAIN AREA
    ═══════════════════════════════════════════════════════════ */
    .main{flex:1;display:flex;flex-direction:column;overflow:hidden;min-width:0;position:relative;}

    /* ── Header strip ─────────────────────────────────────────
       Glass-material info bar: translucent base, top sheen and a
       fading bottom hairline (instead of a hard border) so it sits
       on the page like a pane of frosted glass rather than a flat
       toolbar.  Same language used elsewhere (watchlist, dropdowns). */
    .hdr{
      display:flex;align-items:center;gap:18px;
      padding:0 24px;height:var(--header-h);min-height:var(--header-h);
      position:relative;
      /* z-index needed above the chart panel below — backdrop-filter
         creates a stacking context that traps absolute children, so
         any dropdown opened from inside the header would otherwise
         render under the chart canvas (next sibling in the DOM). */
      z-index:10;
      background:
        linear-gradient(180deg,
          rgba(255,255,255,0.020) 0%,
          rgba(255,255,255,0.004) 55%,
          transparent 100%),
        rgba(15,15,21,0.55);
      backdrop-filter:blur(18px) saturate(140%);
      -webkit-backdrop-filter:blur(18px) saturate(140%);
      border-bottom:none;
      flex-shrink:0;
      box-shadow:inset 0 1px 0 rgba(255,255,255,0.045);
    }
    .hdr.hidden{display:none!important;}
    /* Bottom hairline — gradient that fades at the edges so it
       doesn't slam into the page corners. */
    .hdr::after{
      content:'';position:absolute;
      left:24px;right:24px;bottom:0;height:1px;
      background:linear-gradient(90deg,
        transparent 0%,
        rgba(255,255,255,0.10) 50%,
        transparent 100%);
      pointer-events:none;
    }
    /* Smooth reveal whenever the header is un-hidden (i.e. after a
       stock is selected). The .hidden class kills display:flex, so
       removing it re-runs the animation. */
    .hdr:not(.hidden){animation:strip-in .42s var(--ease-out) backwards;}

    .hdr-sym{
      font-family:var(--font-sans);font-size:1.375rem;font-weight:700;
      letter-spacing:var(--tr-heading);color:var(--text-primary);
    }
    .hdr-price{
      font-family:var(--font-mono);font-size:1.375rem;font-weight:600;
      letter-spacing:var(--tr-mono);font-variant-numeric:tabular-nums;
      transition:color .32s ease;
    }
    /* Change pill — rounded, glass-tinted, gentle border in the
       up/down color so it reads as a small information chip. */
    .hdr-chg{
      display:inline-flex;align-items:center;
      font-family:var(--font-mono);font-size:0.8125rem;font-weight:600;
      padding:4px 10px;
      border-radius:6px;
      border:1px solid transparent;
      letter-spacing:var(--tr-mono);
      font-variant-numeric:tabular-nums;
      transition:
        background-color .22s var(--ease-out),
        border-color .22s var(--ease-out),
        transform .22s var(--ease-out);
    }
    .up{color:var(--green);}
    .up.hdr-chg{
      background:rgba(34,197,94,0.10);
      border-color:rgba(34,197,94,0.22);
    }
    .down{color:var(--red);}
    .down.hdr-chg{
      background:rgba(239,68,68,0.10);
      border-color:rgba(239,68,68,0.22);
    }

    /* OHLC stats — tight cluster with vertical hairlines between
       each stat.  Each stat gently brightens on hover so the cursor
       has somewhere to "land". */
    .hdr-stats{display:flex;gap:0;margin-left:auto;align-items:center;}
    .hs{
      display:flex;flex-direction:column;align-items:flex-end;gap:2px;
      padding:0 16px;
      position:relative;
      transition:opacity .18s ease;
    }
    .hs + .hs::before{
      content:'';position:absolute;
      top:24%;bottom:24%;left:0;width:1px;
      background:linear-gradient(180deg,
        transparent 0%,
        rgba(255,255,255,0.10) 50%,
        transparent 100%);
      pointer-events:none;
    }
    .hs-l{
      font-size:0.625rem;color:var(--text-muted);
      text-transform:uppercase;letter-spacing:var(--tr-caps);font-weight:700;
    }
    .hs-v{
      font-family:var(--font-mono);font-size:0.8125rem;font-weight:600;
      color:var(--text-primary);font-variant-numeric:tabular-nums;
      letter-spacing:var(--tr-mono);
      transition:color .22s ease;
    }
    .hs:hover .hs-v{color:#fff;}

    /* Live indicator — small pill so the dot has a home, instead of
       floating untethered after the stats cluster. */
    .live-r{
      display:flex;align-items:center;gap:7px;
      margin-left:14px;
      padding:5px 11px 5px 10px;
      border-radius:6px;
      background:rgba(255,255,255,0.025);
      border:1px solid rgba(255,255,255,0.05);
    }
    .live-d{
      width:6px;height:6px;border-radius:50%;background:var(--green);
      animation:pulse 2s infinite;
    }
    .live-d.off{background:var(--text-muted);animation:none;}
    @keyframes pulse{0%,100%{opacity:1;}50%{opacity:.25;}}
    .live-t{
      font-family:var(--font-sans);font-size:0.6875rem;
      color:var(--text-muted);font-weight:700;
      letter-spacing:var(--tr-caps);text-transform:uppercase;
    }

    /* ── Sentiment / news stat strip ─────────────────────────
       Same glass material as the header above so the two rows
       read as one continuous frosted slab divided by a fading
       inner hairline. */
    .sent-bar{
      display:flex;align-items:center;gap:14px;
      /* wrap the chart-control cluster onto a 2nd row instead of
         overflowing (and clipping) on narrower viewports */
      flex-wrap:wrap;
      padding:0 24px;min-height:44px;
      position:relative;
      /* Same reason as .hdr: backdrop-filter creates a stacking
         context, so the timezone dropdown menu would otherwise render
         under the chart canvas.  Bump above .charts (auto) but below
         the floating view-toggle (z-index:50). */
      z-index:10;
      background:
        linear-gradient(180deg,
          rgba(255,255,255,0.012) 0%,
          transparent 100%),
        rgba(13,13,19,0.45);
      backdrop-filter:blur(14px) saturate(135%);
      -webkit-backdrop-filter:blur(14px) saturate(135%);
      border-bottom:none;
      flex-shrink:0;font-size:0.75rem;
    }
    .sent-bar.hidden{display:none!important;}
    .sent-bar::after{
      content:'';position:absolute;
      left:24px;right:24px;bottom:0;height:1px;
      background:linear-gradient(90deg,
        transparent 0%,
        rgba(255,255,255,0.07) 50%,
        transparent 100%);
      pointer-events:none;
    }
    .sent-bar:not(.hidden){animation:strip-in .42s var(--ease-out) 60ms backwards;}
    .sl{
      color:var(--text-muted);font-weight:700;
      font-size:0.625rem;letter-spacing:var(--tr-caps);
      text-transform:uppercase;
    }
    .sv{
      font-family:var(--font-mono);font-weight:700;font-size:0.8125rem;
      color:var(--text-primary);
      font-variant-numeric:tabular-nums;letter-spacing:var(--tr-mono);
    }
    .s-bull{color:var(--green);}

    @keyframes strip-in{
      from{opacity:0;transform:translateY(-6px);}
      to  {opacity:1;transform:translateY(0);}
    }

    /* Grok narrative badge — sticky header strip below the stats bar */
    .grok-badge{
      display:flex;align-items:center;gap:10px;
      padding:0 24px;height:32px;
      background:linear-gradient(180deg,var(--bg-secondary),var(--bg-primary));
      border-bottom:1px solid var(--border-subtle);
      flex-shrink:0;font-size:0.75rem;
      cursor:default;
      transition:background .2s ease;
    }
    .grok-badge{display:none!important;}
    .grok-badge.hidden{display:none!important;}
    .gb-emoji{font-size:0.9375rem;line-height:1;}
    .gb-score{
      font-family:var(--font-mono);font-weight:700;font-size:0.8125rem;
      padding:1px 8px;border-radius:3px;color:#fff;
      background:rgba(140,140,150,0.6);
      min-width:48px;text-align:center;
    }
    .gb-score.bullish{background:#16a34a;}
    .gb-score.cautious-bull{background:#65a30d;}
    .gb-score.neutral{background:#525252;}
    .gb-score.cautious-bear{background:#ea580c;}
    .gb-score.bearish{background:#dc2626;}
    .gb-themes{display:flex;gap:4px;flex-wrap:nowrap;overflow:hidden;}
    .gb-theme{
      font-size:0.75rem;padding:1px 7px;border-radius:10px;
      background:rgba(167,139,250,0.18);color:#c4b5fd;
      border:1px solid rgba(167,139,250,0.3);
      white-space:nowrap;
    }
    .gb-narrative{
      flex:1;font-style:italic;color:var(--text-muted);
      overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:0.75rem;
    }
    .gb-age{font-family:var(--font-mono);color:var(--text-muted);font-size:0.75rem;}
    .gb-age.stale{color:#dc2626;}

    /* Sidebar dot — coloured by current posture */
    /* Sidebar posture dot — disabled per design (kept selectors as no-op for safety) */
    .grok-dot{display:none!important;
      width:6px;height:6px;border-radius:50%;
      background:rgba(140,140,150,0.4);margin-left:6px;vertical-align:middle;
    }
    .grok-dot.bullish{background:#16a34a;box-shadow:0 0 4px rgba(22,163,74,0.6);}
    .grok-dot.cautious-bull{background:#65a30d;}
    .grok-dot.neutral{background:#a3a3a3;}
    .grok-dot.cautious-bear{background:#ea580c;}
    .grok-dot.bearish{background:#dc2626;box-shadow:0 0 4px rgba(220,38,38,0.6);}

    /* Toast — extreme events / new catalyst */
    .grok-toast{
      position:fixed;bottom:20px;right:20px;z-index:9999;
      max-width:340px;padding:10px 14px;
      background:var(--bg-secondary);
      border:1px solid var(--border-subtle);
      border-left:3px solid #a78bfa;
      border-radius:4px;font-size:0.8125rem;
      color:var(--text-primary);
      box-shadow:0 8px 24px rgba(0,0,0,0.5);
      transform:translateX(380px);opacity:0;
      transition:transform .25s ease,opacity .25s ease;
      pointer-events:auto;
    }
    .grok-toast.show{transform:translateX(0);opacity:1;}
    .grok-toast .gt-title{font-weight:700;margin-bottom:4px;font-size:0.75rem;letter-spacing:0.04em;text-transform:uppercase;}
    .grok-toast .gt-body{color:var(--text-muted);}
    .s-bear{color:var(--red);}
    .s-neut{color:var(--text-secondary);}

    /* Chart toolbar — inner cluster of .sent-bar. Floats to the right
       so the sentiment stats stay left-aligned and the chart controls
       sit "under Price" on the right. No rounded pills, no glass blur. */
    .time-controls{
      display:flex;align-items:center;gap:0;
      margin-left:auto;
    }
    .time-controls.hidden{display:none!important;}

    /* Time-range buttons (1D / 5D / 1W) — borderless, share a hover bg.
       Active state inverts to cream (text-primary on bg-primary). */
    .time-btn{
      padding:0 14px;height:32px;
      border:none;border-radius:0;
      background:transparent;color:var(--text-muted);
      font-family:var(--font-mono);font-size:0.75rem;font-weight:600;
      cursor:pointer;letter-spacing:.04em;
      display:inline-flex;align-items:center;justify-content:center;
      transition:background .14s var(--ease-out),color .14s var(--ease-out);
    }
    .time-btn:hover{color:var(--text-primary);background:var(--bg-hover);}
    .time-btn.active{background:var(--text-primary);color:var(--bg-primary);}

    /* Chart-type / mode buttons (line / candle / 5m / 1m / spikes / grok)
       — calm warm-accent treatment when active. Reads as "this is on"
       without competing with the cream inversion used by 1D/5D/1W. */
    .chart-type-btn{
      padding:0 12px;height:32px;
      border:none;border-radius:0;
      background:transparent;color:var(--text-muted);font-size:0.875rem;line-height:1;
      cursor:pointer;
      display:inline-flex;align-items:center;justify-content:center;
      font-family:var(--font-mono);font-weight:600;
      transition:background .14s var(--ease-out),color .14s var(--ease-out);
    }
    .chart-type-btn:hover{color:var(--text-primary);background:var(--bg-hover);}
    .chart-type-btn.active{background:var(--accent-warm-dim);color:var(--accent-warm);}

    /* Group separators — barely-visible vertical hairlines, matching
       the muted divider language used elsewhere on the page. */
    .chart-type-sep{width:1px;height:14px;background:rgba(255,255,255,0.04);margin:0 6px;}

    /* Interval picker — eight pill buttons in a row, with one dashed
       in-line separator after 30m. Below 30m: chart keeps overnight
       sentiment context. Above 30m: chart skips closed-market periods. */
    .interval-picker{display:inline-flex;align-items:center;gap:2px;}
    .interval-picker .iv-btn{padding:0 6px;min-width:30px;}
    .iv-sep{
      display:inline-block;width:0;height:14px;
      border-left:1px dashed rgba(255,255,255,0.18);
      margin:0 6px;
    }

    /* Timezone select — borderless, inline. Just text + a 14px chevron
       on a transparent surface. Hover lightens the bg subtly. NO box.
       Distinct from the Price trigger (which is a full-height magnetic
       block) and from every other toolbar button (which use icons or
       short labels). */
    /* Original .tz-select look — preserved exactly for the new
       .tz-trigger button so the user-visible button shape is unchanged. */
    .tz-select{
      margin-left:14px;
      padding:0 28px 0 8px;
      height:32px;line-height:32px;
      border:none;border-radius:0;
      background-color:transparent;
      color:var(--text-secondary);
      font-family:var(--font-mono);font-size:0.75rem;font-weight:600;
      cursor:pointer;outline:none;
      appearance:none;-webkit-appearance:none;
      background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 16 16' fill='none' stroke='%238b8b96' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'><polyline points='4,6 8,10 12,6'/></svg>");
      background-repeat:no-repeat;
      background-position:right 6px center;
      background-size:14px 14px;
      transition:background-color .14s var(--ease-out),color .14s var(--ease-out);
    }
    .tz-select:hover,.tz-select:focus,
    .tz-trigger[aria-expanded="true"]{background-color:var(--bg-hover);color:var(--text-primary);}

    /* Custom dropdown wrapper — relative anchor for the absolute menu. */
    .tz-dropdown{position:relative;display:inline-flex;align-items:center;}
    /* Native <select> kept as a value store + change-event source.
       Visually hidden but still focusable for assistive tech. */
    .tz-select-hidden{
      position:absolute;width:1px;height:1px;
      opacity:0;pointer-events:none;
      border:0;padding:0;margin:0;
      clip:rect(0 0 0 0);overflow:hidden;
    }
    /* Trigger button — inherits .tz-select styles above so the
       button shape is identical to the original native <select>. */
    .tz-trigger{
      display:inline-flex;align-items:center;
      text-align:left;
    }
    .tz-trigger > span{
      display:inline-block;
      white-space:nowrap;
    }

    /* Menu — same glass material as the view-toggle menu so the two
       dropdowns feel like the same component.  Stays in the DOM with
       pointer-events:none in the closed state so the close animation
       runs in both directions. */
    .tz-menu{
      position:absolute;
      top:calc(100% + 4px);
      right:0;
      min-width:180px;
      padding:5px;
      border:1px solid rgba(255,255,255,0.06);
      border-radius:0;
      background:rgba(18,18,24,0.70);
      backdrop-filter:blur(22px) saturate(145%);
      -webkit-backdrop-filter:blur(22px) saturate(145%);
      overflow:hidden;
      z-index:60;
      box-shadow:0 22px 44px -18px rgba(0,0,0,0.85);
      opacity:0;
      transform:translateY(-6px);
      transform-origin:top right;
      pointer-events:none;
      transition:
        opacity .22s var(--ease-out),
        transform .26s var(--ease-out);
    }
    .tz-menu[hidden]{display:none;}  /* honored only at first paint */
    .tz-dropdown.open .tz-menu{
      opacity:1;
      transform:translateY(0);
      pointer-events:auto;
    }
    .tz-opt{
      position:relative;
      display:block;width:100%;
      height:30px;line-height:30px;
      padding:0 12px;
      border:0;
      background:transparent;
      color:var(--text-secondary);
      font-family:var(--font-mono);font-size:0.75rem;font-weight:600;
      letter-spacing:var(--tr-mono);
      text-align:left;
      cursor:pointer;
      /* Keep each option on one line — "PT (Los Angeles)" was wrapping
         inside the fixed 30px row, splitting the label mid-word. */
      white-space:nowrap;
      overflow:hidden;
      text-overflow:ellipsis;
      transition:
        background .18s var(--ease-out),
        color .18s var(--ease-out),
        padding-left .22s var(--ease-out);
    }
    .tz-opt:hover{
      background:rgba(255,255,255,0.05);
      color:var(--text-primary);
      padding-left:16px;
    }
    .tz-opt.active{
      background:rgba(255,255,255,0.055);
      color:var(--text-primary);
      box-shadow:inset 2px 0 0 0 var(--accent);
    }

    /* ═══════════════════════════════════════════════════════════
       CHART PANELS
    ═══════════════════════════════════════════════════════════ */
    /* padding-bottom keeps the lowest panel (or the Modify-graphs toolbar
       when every panel is hidden) from sitting flush against the viewport
       edge. Same 14px feel as the toolbar's horizontal padding. */
    .charts{flex:1;display:flex;flex-direction:column;overflow:hidden;background:var(--bg-primary);padding-bottom:14px;}
    .charts.hidden{display:none!important;}

    /* ═══════════════════════════════════════════════════════════
       VIEW TOGGLE — IBM Carbon "Content Switcher" style
       Flat rectangular segmented control: solid fill on active,
       thin 1px divider between inactive segments, no gradients/blur.
       Position + size stay identical across both modes.
    ═══════════════════════════════════════════════════════════ */
    /* Hidden until a stock is selected (welcome overlay gets `.hidden` class on pick). */
    /* Trigger is magnetized to the header: flush right, flush top, full
       header height. No rounded corners. The single 1px border on the
       left is the only seam — it visually connects the button to the
       LIVE / stats area without floating above it. */
    /* Self-contained floating glass pill, inset from the top-right
       corner so it works identically across all four views:
         - Price view: floats over the header glass
         - Graph / Map / Sources views: floats over the chart area
       Same look, same shape in every context.  Subtle border + drop
       shadow give it real presence even when there's nothing behind
       it; the glass background keeps it visually quiet. */
    .view-toggle{
      position:absolute;top:10px;right:14px;z-index:50;
      display:block;
    }
    /* Multi-route world: app.html has no #welcome, so the legacy
       `body:has(#welcome.hidden) .view-toggle{display:block}` rule
       never matched and the toggle stayed hidden. Default is now
       `display:block`; suppress it only on the command center and
       during the knight loading overlay. */
    body:has(#command-center:not(.hidden)) .view-toggle{display:none!important;}
    body:has(.stock-loading:not(.hidden)) .view-toggle{display:none!important;}
    /* Flat glass with a quiet, low-contrast border.  On hover the
       border stays put — only the inside tint shifts, so the change
       feels like the surface itself lighting up rather than the
       outline glowing in. */
    .view-trigger{
      position:relative;
      display:flex;align-items:center;gap:12px;
      min-width:239px;
      height:36px;
      padding:0 16px;
      border:1px solid rgba(255,255,255,0.04);
      border-radius:5px;
      background:rgba(15,15,21,0.55);
      backdrop-filter:blur(20px) saturate(140%);
      -webkit-backdrop-filter:blur(20px) saturate(140%);
      color:var(--text-primary);
      font-family:var(--font-sans);font-size:0.8125rem;font-weight:600;letter-spacing:0;
      cursor:pointer;
      transition:
        background-color .38s cubic-bezier(0.22,0.8,0.18,1),
        color            .26s ease;
    }
    .view-trigger:hover{
      background-color:rgba(34,34,42,0.78);
    }
    .view-trigger:active{
      background-color:rgba(44,44,52,0.86);
    }
    .view-trigger:focus{outline:none;}
    .view-trigger-icon{display:inline-flex;align-items:center;color:var(--text-secondary);transition:color .18s ease;}
    .view-trigger-icon svg{opacity:.95;display:block;}
    .view-trigger:hover .view-trigger-icon,
    .view-trigger[aria-expanded="true"] .view-trigger-icon{color:var(--text-primary);}
    .view-trigger-label{flex:1;text-align:left;}
    .view-trigger-caret{
      margin-left:2px;opacity:.55;
      transition:transform .26s var(--ease-out),opacity .18s ease;
    }
    .view-trigger[aria-expanded="true"] .view-trigger-caret{transform:rotate(180deg);opacity:1;}
    /* Open state: same tint as :active so the press → open feedback
       is one continuous gesture.  Border stays put. */
    .view-trigger[aria-expanded="true"]{
      background-color:rgba(44,44,52,0.86);
    }

    /* Menu — same width, same corner radius, same calm border as the
       trigger.  Drops 6px below; sits flat (no drop shadow) to match
       the no-3D feel of the button. */
    .view-menu{
      position:absolute;top:calc(100% + 6px);right:0;
      min-width:239px;
      padding:5px;
      border:1px solid rgba(255,255,255,0.04);
      border-radius:5px;
      background:rgba(15,15,21,0.57);
      backdrop-filter:blur(24px) saturate(145%);
      -webkit-backdrop-filter:blur(24px) saturate(145%);
      overflow:hidden;
      opacity:0;
      transform:translateY(-6px);
      transform-origin:top right;
      pointer-events:none;
      transition:
        opacity .22s var(--ease-out),
        transform .26s var(--ease-out);
    }
    .view-menu[hidden]{display:none;}  /* honored only at first paint */
    .view-toggle.open .view-menu{
      opacity:1;
      transform:translateY(0);
      pointer-events:auto;
    }
    .view-opt{
      position:relative;
      display:flex;align-items:center;gap:10px;width:100%;
      height:38px;
      padding:0 12px;
      border:0;
      border-radius:6px;
      background:transparent;color:var(--text-secondary);
      font-family:var(--font-sans);font-size:0.8125rem;font-weight:600;letter-spacing:0;
      cursor:pointer;
      transition:
        background .18s var(--ease-out),
        color .18s var(--ease-out),
        padding-left .22s var(--ease-out);
    }
    .view-opt + .view-opt{margin-top:2px;}
    /* Grouping inside the view menu: a small caps label + a hairline divider. */
    .view-menu-section{
      padding:6px 12px 3px;
      font-size:0.5625rem;font-weight:700;letter-spacing:.1em;
      text-transform:uppercase;color:var(--text-muted);
      pointer-events:none;
    }
    .view-menu-sep{
      height:1px;margin:5px 8px;
      background:rgba(255,255,255,0.06);
    }
    .view-opt svg{
      opacity:.85;flex-shrink:0;
      transition:opacity .18s ease,transform .22s var(--ease-out);
    }
    .view-opt:hover{
      background:rgba(255,255,255,0.05);
      color:var(--text-primary);
      padding-left:14px;
    }
    .view-opt:hover svg{opacity:1;transform:translateX(2px);}

    /* Active option: accent rail + brighter foreground. */
    .view-toggle[data-mode="price"]     .view-opt[data-view="price"],
    .view-toggle[data-mode="signals"]   .view-opt[data-view="signals"],
    .view-toggle[data-mode="graph"]     .view-opt[data-view="graph"],
    .view-toggle[data-mode="map"]       .view-opt[data-view="map"],
    .view-toggle[data-mode="newsgraph"] .view-opt[data-view="newsgraph"],
    .view-toggle[data-mode="sources"]   .view-opt[data-view="sources"]{
      background:rgba(255,255,255,0.055);
      color:var(--text-primary);
      box-shadow:inset 2px 0 0 0 var(--accent);
    }
    .view-toggle[data-mode="price"]     .view-opt[data-view="price"]     svg,
    .view-toggle[data-mode="signals"]   .view-opt[data-view="signals"]   svg,
    .view-toggle[data-mode="graph"]     .view-opt[data-view="graph"]     svg,
    .view-toggle[data-mode="map"]       .view-opt[data-view="map"]       svg,
    .view-toggle[data-mode="newsgraph"] .view-opt[data-view="newsgraph"] svg,
    .view-toggle[data-mode="sources"]   .view-opt[data-view="sources"]   svg{opacity:1;}

    /* Reserve room on the header right edge so stats don't duck under the toggle */
    /* Reserve room for the floating dropdown pill — 239px trigger +
       14px right inset + 12px breathing room.  Reducing this lets the
       OHLC stats + LIVE pill flow further right alongside the
       narrower trigger instead of being parked at a fixed margin. */
    .hdr{padding-right:265px;}

    /* In graph/map modes: full-canvas content, header + toolbar + sentiment bar gone */
    .main.no-header-mode .hdr{display:none!important;}
    .main.no-header-mode .time-controls{display:none!important;}
    .main.no-header-mode .sent-bar{display:none!important;}
    .main.no-header-mode .grok-badge{display:none!important;}

    /* Partner graph view (iframes demo.html with ?ticker=...) */
    .graph-view{flex:1;display:flex;flex-direction:column;position:relative;background:var(--bg-primary);overflow:hidden;}
    .graph-view.hidden{display:none!important;}
    .graph-view iframe{flex:1;width:100%;height:100%;border:0;background:#09090b;}
    .graph-overlay{
      position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
      background:rgba(9,9,11,0.88);backdrop-filter:blur(4px);z-index:10;
    }
    .graph-overlay.hidden{display:none!important;}
    .graph-overlay-card{
      padding:28px 36px;border:1px solid var(--border-default);border-radius:var(--radius-md);
      background:var(--bg-elevated);text-align:center;max-width:400px;
    }
    .graph-overlay-spinner{
      width:36px;height:36px;margin:0 auto 14px;
      border:3px solid rgba(167,139,250,0.15);border-top-color:var(--accent);
      border-radius:50%;animation:spin 0.9s linear infinite;
    }
    .graph-overlay-spinner.hidden{display:none;}
    @keyframes spin{to{transform:rotate(360deg);}}
    .graph-overlay-title{font-size:1rem;font-weight:700;color:var(--text-primary);margin-bottom:6px;}
    .graph-overlay-sub{font-size:0.8125rem;color:var(--text-secondary);line-height:1.5;margin-bottom:16px;}
    .graph-progress-wrap{
      display:none;height:4px;width:100%;background:rgba(99,102,241,0.12);
      border-radius:2px;overflow:hidden;margin-top:6px;
    }
    .graph-progress-wrap.active{display:block;}
    .graph-progress-bar{
      height:100%;width:32%;background:linear-gradient(90deg,transparent,var(--accent) 40%,var(--accent) 60%,transparent);
      border-radius:2px;animation:progress-slide 1.6s ease-in-out infinite;
    }
    @keyframes progress-slide{
      0%{transform:translateX(-100%);}
      100%{transform:translateX(310%);}
    }
    .graph-progress-meta{
      margin-top:10px;font-size:0.75rem;font-family:var(--font-mono);
      color:var(--text-muted);letter-spacing:.03em;text-transform:uppercase;
      min-height:14px;
    }

    .cp{position:relative;overflow:hidden;}
    /* Price panel is the sole flex-grower in .charts — it absorbs ALL space
       not taken by the toolbar + the (content-sized) lower-panels wrapper. So
       as graphs are unchecked in the Modify-graphs modal, the wrapper shrinks
       and the price stretches to fill; with zero graphs it's the whole area.
       min-height keeps it from collapsing if every dot panel is expanded on a
       short viewport (the wrapper then shrinks + scrolls instead). */
    /* Price panel never shrinks below 40% of the viewport — when the
       lower panels need more room they scroll inside .charts-scroll
       instead of squeezing the price chart. */
    .cp.price{flex:1 1 auto;min-height:40vh;}
    /* Panel separators — barely-visible hairlines against the chart bg.
       --border-subtle (#1e1e26) reads too loud over #09090b; the same
       rgba(255,255,255,0.04) used by the toolbar separators feels
       calmer and matches the sidebar divider language. */
    .cp.sent{flex:1.7;border-top:1px solid rgba(255,255,255,0.04);}
    .cp.dots{flex:1.7;border-top:1px solid rgba(255,255,255,0.04);}
    .cp.sent-blend{flex:1.7;border-top:1px solid rgba(255,255,255,0.04);}
    .cp.dots-blend{flex:1.7;border-top:1px solid rgba(255,255,255,0.04);}
    .cp.newsent{flex:1.7;border-top:1px solid rgba(255,255,255,0.04);}
    .cp.news{flex:1.7;border-top:1px solid rgba(255,255,255,0.04);}
    .cp.tape{flex:1.7;border-top:1px solid rgba(255,255,255,0.04);}
    /* Lower-panels scroll wrapper — content-sized (flex:0 1 auto), so removing
       a graph via the modal shrinks it and the price panel grows to fill.
       --charts-scroll-max is the optional cap set by the drag handle: when the
       user drags the price panel taller, the wrapper is capped below its
       content height and scrolls. With no drag the cap is `none` → the wrapper
       equals its content, which is the price panel's smallest allowed state. */
    .charts-scroll{
      flex:0 1 auto;display:flex;flex-direction:column;overflow-y:auto;
      max-height:var(--charts-scroll-max,none);
      /* Always reserve 8px for the scrollbar so panes inside .charts-scroll
         keep a stable width regardless of whether the scrollbar is visible.
         The #cp-price margin below mirrors that gutter so the price panel's
         outer width matches the panes' container width and plot areas align. */
      scrollbar-gutter:stable;
    }
    /* margin-right (not padding) so the *outer* width drops by 8px — that's
       what LightweightCharts reads when sizing its widget. */
    .cp.price{ margin-right:8px; }
    /* Each lower panel is a FIXED 145px — graph panels never resize. The drag
       handle only changes how many fit before the wrapper scrolls. */
    .charts-scroll > .cp{flex:0 0 145px;min-height:80px;}
    .charts-scroll::-webkit-scrollbar{width:8px;}
    .charts-scroll::-webkit-scrollbar-track{background:transparent;}
    .charts-scroll::-webkit-scrollbar-thumb{background:var(--border-subtle);border-radius:4px;}
    .charts-scroll::-webkit-scrollbar-thumb:hover{background:var(--border-strong,#525252);}

    .cp-label{
      position:absolute;top:6px;left:10px;z-index:4;
      font-size:0.625rem;font-weight:700;color:var(--text-muted);
      text-transform:uppercase;letter-spacing:.08em;
      pointer-events:none;
      /* Tinted chip so the chart line behind doesn't bleed through the text.
         Background uses the page base color at 60% opacity + a small blur,
         so the chip fades whatever's behind rather than masking it. */
      padding:2px 7px;border-radius:3px;
      background:rgba(9,9,11,.62);
      -webkit-backdrop-filter:blur(4px);
              backdrop-filter:blur(4px);
    }

    /* Source-mode chip beside a panel label (e.g. tape pressure candles/live). */
    .cp-mode{
      display:inline-block;margin-left:8px;padding:2px 7px;
      font-size:0.5625rem;font-weight:600;letter-spacing:.08em;
      color:var(--text-muted);
      background:rgba(255,255,255,0.04);
      border:1px solid rgba(255,255,255,0.06);
      border-radius:8px;
      vertical-align:1px;
    }
    .cp-mode.live{color:#22c55e;border-color:rgba(34,197,94,0.25);background:rgba(34,197,94,0.08);}
    /* Right-aligned current-value badge in a panel header. Updated by the
       render functions after each frame; sits in the same row as cp-label
       so the panel header reads "TITLE         +0.34 ↑". */
    .cp-value{
      position:absolute;top:8px;right:10px;z-index:4;
      display:inline-flex;align-items:center;gap:6px;
      font-family:var(--font-mono);font-size:0.6875rem;font-weight:600;
      letter-spacing:.02em;color:var(--text-muted);
      padding:1px 8px;border-radius:6px;
      background:rgba(255,255,255,0.02);
      border:1px solid rgba(255,255,255,0.04);
      opacity:0;transition:opacity .25s ease, color .2s, border-color .2s, background .2s;
      pointer-events:none;
    }
    .cp-value.shown{opacity:.9;}
    .cp-value.pos{color:#22c55e;border-color:rgba(34,197,94,0.22);background:rgba(34,197,94,0.06);}
    .cp-value.neg{color:#ef4444;border-color:rgba(239,68,68,0.22);background:rgba(239,68,68,0.06);}
    .cp-value .cp-val-sub{color:var(--text-muted);font-weight:500;}

    /* Interval-mismatch hint inside tweet/news expansion panels. Tweet
       + news dots are 5-minute-scale; at higher TFs they show as a thin
       streak on the right edge. We surface a low-key hint so the user
       knows what to do, without nagging. Hidden by default, shown by
       JS when the panel is open AND INT_SEC > 1800. */
    .cp-iv-hint{
      position:absolute;top:50%;left:50%;
      transform:translate(-50%,-50%);
      z-index:5;
      display:none;
      padding:6px 12px;border-radius:4px;
      font-size:0.7rem;font-weight:600;color:var(--accent-warm,#e0a060);
      letter-spacing:.04em;
      background:rgba(9,9,11,.78);
      border:1px solid rgba(224,160,96,.35);
      -webkit-backdrop-filter:blur(6px);
              backdrop-filter:blur(6px);
      pointer-events:none;
      white-space:nowrap;
    }
    .cp-iv-hint.show{display:block;}

    /* At >30m intervals every sentiment / tweet / news panel hides
       entirely. The sentiment lines aggregate to a handful of points
       at those timeframes (≈260 at most) and the tweet/news dot panels
       only cover ~7 days, so they'd just sit blank under a multi-month
       price chart. The JS toggles `.coarse-interval` on #charts-scroll
       to opt every cp-panel out. */
    .charts-scroll.coarse-interval .cp.sent,
    .charts-scroll.coarse-interval .cp.dots,
    .charts-scroll.coarse-interval .cp.sent-blend,
    .charts-scroll.coarse-interval .cp.dots-blend,
    .charts-scroll.coarse-interval .cp.newsent,
    .charts-scroll.coarse-interval .cp.news,
    .charts-scroll.coarse-interval .cp.tape {
      display:none !important;
    }

    /* ── Collapsible dot panels — minimal expand/collapse ─────────
       One gesture, executed precisely. No traveling light, no glow
       trails, no multi-element choreography.
         1. Panel folds open
         2. The 1px top seam pulses very faintly in warm gold while
            data loads — the seam IS the loader
         3. Content fades in over ~500ms once data is ready
       That's the whole thing.
    */
    .cp.dots, .cp.dots-blend, .cp.news{
      transition:
        flex-grow .34s cubic-bezier(.22,.61,.36,1),
        flex-basis .34s cubic-bezier(.22,.61,.36,1),
        opacity .26s ease .06s;
    }
    .cp.cp-collapsed{
      flex-grow:0!important;
      flex-basis:0!important;
      min-height:0!important;
      opacity:0;
      pointer-events:none;
      transition:
        flex-grow .28s cubic-bezier(.5,0,.75,0),
        flex-basis .28s cubic-bezier(.5,0,.75,0),
        opacity .2s ease;
    }

    /* Simple opacity fade for content reveal — no clip-path, no mask. */
    .cp.dots .cp-reveal,
    .cp.dots-blend .cp-reveal,
    .cp.news .cp-reveal{
      clip-path:none !important;
      opacity:0;
    }
    .cp.dots .cp-reveal.revealed,
    .cp.dots-blend .cp-reveal.revealed,
    .cp.news .cp-reveal.revealed{
      opacity:1;
      transition:opacity .55s ease;
    }

    /* The top seam itself is the loader. While .cp-loading is on the
       panel, this 1px line breathes in warm gold; once the content
       reveals, it settles to a low static opacity. */
    .cp.dots::before, .cp.dots-blend::before, .cp.news::before{
      content:'';position:absolute;
      top:-1px;left:0;right:0;height:1px;
      background:var(--accent-warm);
      opacity:0;pointer-events:none;z-index:5;
      transition:opacity .4s ease;
    }
    .cp.cp-loading::before{
      opacity:.55;
      animation:cpSeamBreathe 1.6s cubic-bezier(.4,0,.6,1) infinite;
    }
    @keyframes cpSeamBreathe{
      0%, 100% {opacity:.18;}
      50%      {opacity:.6;}
    }

    /* Toggle button — color shift only, no click effect. */
    .cp-toggle{
      position:absolute;top:5px;right:12px;z-index:6;
      display:flex;align-items:center;gap:5px;
      font-family:inherit;font-size:0.5625rem;font-weight:700;
      text-transform:uppercase;letter-spacing:.07em;
      color:var(--text-muted);
      background:rgba(9,9,11,.62);
      -webkit-backdrop-filter:blur(4px);
              backdrop-filter:blur(4px);
      border:1px solid var(--border-subtle);
      border-radius:4px;padding:3px 7px;cursor:pointer;
      transition:color .18s ease,border-color .18s ease,background .18s ease;
    }
    .cp-toggle:hover{color:var(--accent-warm);border-color:rgba(212,177,138,.28);background:rgba(9,9,11,.7);}
    .cp-toggle.open{color:var(--accent-warm);border-color:rgba(212,177,138,.45);background:rgba(212,177,138,.08);}
    .cp-tg-caret{display:inline-block;font-size:0.6rem;transition:transform .32s cubic-bezier(.22,.61,.36,1);}
    .cp-toggle.open .cp-tg-caret{transform:rotate(180deg);}

    /* Hidden — kept as no-ops so the existing HTML/JS still works. */
    .cp-loader,.cp-loader-label{display:none;}

    @media (prefers-reduced-motion: reduce){
      .cp.dots, .cp.dots-blend, .cp.news,
      .cp.cp-collapsed,
      .cp.dots .cp-reveal,
      .cp.dots-blend .cp-reveal,
      .cp.news .cp-reveal{transition:none!important;}
      .cp.cp-loading::before{animation:none!important;}
    }

    /* ── Sentiment window slider ──────��──────────────────── */
    .sent-slider-wrap{
      /* Right-aligned, sits just to the left of the panel's toggle button
         (which is at right:12px and ~95-120px wide depending on label). With
         right:140px the slider clears every existing toggle ("Tweet Scores",
         "Self-Label", "Headlines") with a small gap. Left-of-the-label
         positioning broke once labels grew to "Stocktwits Sentiment Finetuned". */
      position:absolute;top:3px;right:140px;z-index:6;
      display:flex;align-items:center;gap:8px;
      pointer-events:auto;
      padding:3px 10px;border-radius:3px;
      background:rgba(9,9,11,.62);
      -webkit-backdrop-filter:blur(4px);
              backdrop-filter:blur(4px);
    }
    .sent-slider-label{
      font-family:var(--font-mono);font-size:0.75rem;font-weight:700;
      color:var(--text-muted);letter-spacing:.03em;
      min-width:36px;text-align:right;
      transition:color .15s;
    }
    .sent-slider-label.active{color:var(--accent);}
    .sent-slider{
      -webkit-appearance:none;appearance:none;
      width:120px;height:3px;
      background:var(--border-default);
      border-radius:2px;outline:none;cursor:pointer;
      transition:background .15s;
    }
    .sent-slider:hover{background:var(--border-default);}
    .sent-slider::-webkit-slider-thumb{
      -webkit-appearance:none;appearance:none;
      width:14px;height:14px;border-radius:50%;
      background:var(--accent);border:2px solid var(--bg-primary);
      cursor:pointer;transition:transform .15s, box-shadow .15s;
      box-shadow:0 0 0 0 rgba(99,102,241,0);
    }
    .sent-slider::-webkit-slider-thumb:hover{
      transform:scale(1.2);
      box-shadow:0 0 0 4px rgba(99,102,241,0.2);
    }
    .sent-slider:active::-webkit-slider-thumb{
      transform:scale(1.1);
      box-shadow:0 0 0 6px rgba(99,102,241,0.15);
    }
    .sent-slider::-moz-range-thumb{
      width:14px;height:14px;border-radius:50%;
      background:var(--accent);border:2px solid var(--bg-primary);
      cursor:pointer;
    }
    .sent-slider-ticks{
      display:flex;gap:0;position:relative;width:120px;
    }
    .sent-slider-tick{
      font-family:var(--font-mono);font-size:0.6875rem;color:var(--text-muted);
      opacity:.5;text-align:center;flex:1;
    }

    /* ── Loading skeleton ─────────────────────────────────── */
    .cp-skeleton{
      position:absolute;inset:0;z-index:10;
      background:var(--bg-primary);
      display:flex;align-items:center;justify-content:center;
      transition:opacity .4s ease;
    }
    .cp-skeleton.hide{opacity:0;pointer-events:none;}
    .cp-skeleton .skel-bar{
      width:60%;height:1px;
      background:linear-gradient(90deg,transparent,var(--border-default),transparent);
      position:relative;overflow:hidden;
    }
    .cp-skeleton .skel-bar::after{
      content:'';position:absolute;inset:0;
      background:linear-gradient(90deg,transparent 0%,rgba(99,102,241,.25) 50%,transparent 100%);
      animation:skelSweep 1.8s ease-in-out infinite;
    }
    @keyframes skelSweep{
      0%{transform:translateX(-100%);}
      100%{transform:translateX(100%);}
    }

    /* ── Left-to-right reveal wipe ────────────────────────── */
    .cp-reveal{
      clip-path:inset(0 100% 0 0);
    }
    .cp-reveal.revealed{
      clip-path:inset(0 0% 0 0);
      transition:clip-path .9s cubic-bezier(.25,.46,.45,.94);
    }
    /* Labels fade in instead of wipe */
    .cp-label.cp-reveal{
      clip-path:none;
      opacity:0;
      transition:opacity .5s ease;
    }
    .cp-label.cp-reveal.revealed{
      clip-path:none;
      opacity:1;
    }
    .dots-cv{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:3;}
    .grok-cv{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:4;}
    .price-bg-cv{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:0;}

    /* Hide lightweight-charts attribution + make chart bg transparent so price-bg-cv shows through */
    .chart-panel a{display:none!important;}
    .cp.price .tv-lightweight-charts{background:transparent!important;}

    /* ═══════════════════════════════════════════════════════════
       WELCOME STATE — editorial first impression.
       Thin hairline eyebrow, large IBM Plex Sans wordmark, muted tagline.
       Each line masks-in with a 80ms stagger.
    ═══════════════════════════════════════════════════════════ */
    .welcome{
      position:relative;
      flex:1;display:flex;align-items:flex-start;justify-content:flex-end;
      flex-direction:row;gap:0;
      color:var(--text-muted);
      /* Smaller right padding pushes the hero further into the
         right edge while keeping a comfortable gutter. */
      padding:0 clamp(32px, 5vw, 96px) 0 24px;
      overflow:hidden;
      /* 48px square grid behind the hero. Two 1px lines per axis,
         subtle ivory tint so it reads atmospheric, not decorative.
         Welcome state doesn't pan, so a fixed background-image is fine. */
      background-image:
        linear-gradient(rgba(255,255,255,0.035) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255,255,255,0.035) 1px, transparent 1px);
      background-size:48px 48px;
    }
    .welcome > *{position:relative;z-index:1;}

    /* ─────────────── Welcome content stack ───────────────
       Wraps eyebrow + wordmark + tagline + search and pins
       them to the right half of the welcome area so they
       don't collide with the autumn-tree backdrop on the
       left. Stays centered within its own column.
       ──────────────────────────────────────────────────── */
    .welcome-content{
      display:flex;flex-direction:column;
      align-items:center;justify-content:center;
      gap:0;
      max-width:min(680px, 48vw);
      width:100%;
      /* Pushed higher so the stack sits in the upper-right of the
         hero. Smaller wordmark below means we don't need as much
         top space to clear the autumn canopy. */
      margin-top:clamp(172px, 26vh, 300px);
      padding:8px 0;
    }

    /* New unified slide-fade transition for "the rest" (eyebrow,
       knight video, tagline, search). The CAVALRY letter cascade
       (.ch-text .ch-l → @keyframes ch-letter-in) is untouched. */
    @keyframes welcome-piece-in{
      0%   {opacity:0; transform:translateX(56px);}
      100% {opacity:1; transform:translateX(0);}
    }

    /* Hide the watchlist sidebar (and its toggle handle) while the
       welcome hero is on screen — the welcome is the "main page";
       the sidebar belongs to the tracking page. The CTA button
       below the search bar flips welcome → tracking. */
    body:has(#welcome:not(.hidden)) .sidebar,
    body:has(#welcome:not(.hidden)) #sb-toggle{
      display:none;
    }

    /* "Go to Tracking" CTA — warm pill sitting in the same row as
       the search bar. Matches the search field's height + drop
       shadow so the pair reads as a single composed control row.
       Warm-accent palette ties it to the chart-type chips and the
       autumn-tree palette. Slide-in is handled by the row's
       animation; no individual entrance here. */
    .welcome-cta{
      display:inline-flex;align-items:center;gap:10px;
      flex:0 0 auto;
      padding:15px 24px;
      background:linear-gradient(180deg,
        rgba(212,177,138,0.24) 0%,
        rgba(212,177,138,0.10) 100%);
      -webkit-backdrop-filter:blur(16px) saturate(1.3);
      backdrop-filter:blur(16px) saturate(1.3);
      border:1px solid rgba(212,177,138,0.40);
      color:#e7c9a3;
      font-family:var(--font-sans);
      font-size:0.8125rem;font-weight:600;
      letter-spacing:0.06em;
      text-transform:uppercase;
      cursor:pointer;
      border-radius:var(--radius-sm);
      box-shadow:
        inset 0 1px 0 rgba(255,220,170,0.18),
        0 12px 32px -12px rgba(212,140,70,0.38);
      transition:background .22s var(--ease-out),
                 border-color .22s var(--ease-out),
                 box-shadow   .22s var(--ease-out),
                 transform    .22s var(--ease-out),
                 color        .22s var(--ease-out);
    }
    .welcome-cta:hover{
      background:linear-gradient(180deg,
        rgba(212,177,138,0.36) 0%,
        rgba(212,177,138,0.18) 100%);
      border-color:rgba(212,177,138,0.68);
      color:#f5e0c0;
      box-shadow:
        inset 0 1px 0 rgba(255,220,170,0.24),
        0 16px 40px -10px rgba(212,140,70,0.55);
      transform:translateY(-2px);
    }
    .welcome-cta:active{
      transform:translateY(0);
      box-shadow:
        inset 0 1px 0 rgba(255,220,170,0.12),
        0 8px 22px -14px rgba(212,140,70,0.38);
    }
    .welcome-cta svg{display:block;opacity:.85;transition:transform .2s var(--ease-out), opacity .2s var(--ease-out);}
    .welcome-cta:hover svg{transform:translateX(2px);opacity:1;}

    /* ── Frame Button: futuristic corner-bracket CTA (Components 2) ──
       Four corner chevrons float outside the edges and spring outward
       on hover. Pure CSS, no JS. Base .fbtn + variants .fbtn--research
       (rose → Eva) and .fbtn--lancer (gold → tracking). */
    .fbtn-wrap{
      position:relative;
      display:inline-block;
      /* room for the corners to travel */
      padding:14px;
    }
    .fbtn{
      position:relative;
      display:inline-flex;
      align-items:center;
      justify-content:center;
      /* Fluid: full size only at ≥1920px effective viewport. Laptops with
         OS display scaling report 1280–1536px, so they land mid-curve and
         get a genuinely smaller button instead of the desktop cap. */
      padding:0 clamp(32px, 3.55vw, 68px);
      height:clamp(44px, 3.75vw, 72px);
      min-width:clamp(200px, 17.2vw, 330px);
      box-sizing:border-box;
      font-family:"Manrope", ui-sans-serif, system-ui, sans-serif;
      font-size:clamp(11px, 0.84vw, 16px);
      font-weight:600;
      letter-spacing:0.2em;
      text-transform:uppercase;
      text-decoration:none;
      /* 1px ring via inset box-shadow, NOT border — 1px rounded borders
         render as a bowtie X in headless screenshots */
      border:none;
      border-radius:2px;
      background:transparent;
      cursor:pointer;
      -webkit-tap-highlight-color:transparent;
      transition:background 0.45s ease, color 0.45s ease,
        box-shadow 0.55s ease, transform 0.3s cubic-bezier(.22,1,.36,1);
    }
    .fbtn:active{ transform:scale(0.965); }

    /* corner brackets: flush against the rectangle at rest, spring out on hover */
    .fbtn-corner{
      position:absolute;
      width:clamp(13px, 1.05vw, 20px);
      height:clamp(13px, 1.05vw, 20px);
      border:1.5px solid;
      pointer-events:none;
      transition:transform 0.45s cubic-bezier(.22,1,.36,1), border-color 0.45s ease,
        opacity 0.45s ease;
      opacity:0.85;
    }
    .fbtn-corner--tl{ top:11px;    left:11px;   border-right:none; border-bottom:none; }
    .fbtn-corner--tr{ top:11px;    right:11px;  border-left:none;  border-bottom:none; }
    .fbtn-corner--bl{ bottom:11px; left:11px;   border-right:none; border-top:none; }
    .fbtn-corner--br{ bottom:11px; right:11px;  border-left:none;  border-top:none; }

    .fbtn-wrap:hover .fbtn-corner{ opacity:1; }
    .fbtn-wrap:hover .fbtn-corner--tl{ transform:translate(-9px, -9px); }
    .fbtn-wrap:hover .fbtn-corner--tr{ transform:translate(9px, -9px); }
    .fbtn-wrap:hover .fbtn-corner--bl{ transform:translate(-9px, 9px); }
    .fbtn-wrap:hover .fbtn-corner--br{ transform:translate(9px, 9px); }
    /* corners settle back near the rectangle when pressed */
    .fbtn-wrap:active .fbtn-corner--tl{ transform:translate(-3px, -3px); }
    .fbtn-wrap:active .fbtn-corner--tr{ transform:translate(3px, -3px); }
    .fbtn-wrap:active .fbtn-corner--bl{ transform:translate(-3px, 3px); }
    .fbtn-wrap:active .fbtn-corner--br{ transform:translate(3px, 3px); }

    /* Research variant — rose on dark plum (Eva slide) */
    .fbtn--research{
      color:#f0a8c4;
      box-shadow:inset 0 0 0 1px rgba(240,168,196,0.38);
      background:rgba(38,15,27,0.35);
    }
    .fbtn--research ~ .fbtn-corner{ border-color:rgba(240,168,196,0.55); }
    .fbtn-wrap:hover .fbtn--research{
      color:#f7bcd3;
      background:rgba(56,20,36,0.4);
      box-shadow:inset 0 0 0 1px rgba(244,184,208,0.5), 0 0 12px rgba(231,124,165,0.1);
    }
    .fbtn-wrap:hover .fbtn--research ~ .fbtn-corner{ border-color:rgba(240,168,196,0.75); }

    /* Lancer variant — gold on dark amber (autumn-tree slide) */
    .fbtn--lancer{
      color:#d9b178;
      box-shadow:inset 0 0 0 1px rgba(217,177,120,0.36);
      background:rgba(36,24,12,0.35);
    }
    .fbtn--lancer ~ .fbtn-corner{ border-color:rgba(217,177,120,0.5); }
    .fbtn-wrap:hover .fbtn--lancer{
      color:#e6c490;
      background:rgba(46,30,15,0.4);
      box-shadow:inset 0 0 0 1px rgba(230,190,130,0.48), 0 0 12px rgba(224,131,47,0.09);
    }
    .fbtn-wrap:hover .fbtn--lancer ~ .fbtn-corner{ border-color:rgba(217,177,120,0.7); }

    /* ═══════════════════════════════════════════════════════════
       Autumn Tree backdrop — merged from /demo/index.html.
       Sits inside .welcome at z-index 0 so it paints behind the
       welcome content (eyebrow, wordmark, tagline, search) and
       above the welcome's 48px grid. All transitions preserved
       from the source demo: warm glow breathing in, tree rising
       from below with blur, falling leaves with sway+spin, and
       a soft vignette + lifting veil.
       ═══════════════════════════════════════════════════════════ */
    .welcome .tree-glow,
    .welcome .tree-stage,
    .welcome .tree-vignette,
    .welcome .tree-veil{
      position:absolute;
      z-index:0;
      pointer-events:none;
    }

    /* Warm radial glow that breathes in behind the canopy */
    .welcome .tree-glow{
      inset:0;
      background:
        radial-gradient(ellipse 60% 50% at 38% 42%,
          rgba(255, 138, 60, 0.22) 0%,
          rgba(220, 90, 40, 0.10) 30%,
          rgba(0, 0, 0, 0) 65%);
      opacity:0;
    }
    body.tree-ready .welcome .tree-glow{
      animation:tree-glow-in 1.1s cubic-bezier(0.22, 1, 0.36, 1) 0.15s forwards;
    }
    @keyframes tree-glow-in{
      0%   {opacity:0; transform:scale(0.94);}
      100% {opacity:1; transform:scale(1);}
    }

    /* Soft dark veil that lifts after the tree has settled */
    .welcome .tree-veil{
      inset:0;
      background:var(--bg-primary);
      z-index:3;
      opacity:1;
    }
    body.tree-ready .welcome .tree-veil{
      animation:tree-veil-lift 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0s forwards;
    }
    @keyframes tree-veil-lift{
      0%   {opacity:1;}
      100% {opacity:0;}
    }

    /* Subtle radial vignette that eases in last, for depth */
    .welcome .tree-vignette{
      inset:0;
      background:radial-gradient(ellipse at center, rgba(0,0,0,0) 50%, rgba(0,0,0,0.55) 100%);
      opacity:0;
      z-index:2;
    }
    body.tree-ready .welcome .tree-vignette{
      animation:tree-vignette-in 0.9s ease-out 0.7s forwards;
    }
    @keyframes tree-vignette-in{
      to{opacity:1;}
    }

    .welcome .tree-stage{
      inset:0;
      background-image:url("/static/autumn/tree.png");
      background-repeat:no-repeat;
      background-position:center bottom;
      /* auto 95%, not contain: tree.png is 1.5:1 so contain ≈ full stage
         height on widescreen — 95% shrinks the tree 5% on every screen.
         The vw term caps height so width (h × 1.5) never exceeds the
         stage box — otherwise tall (F11) viewports hard-clip the image
         at the element edge instead of showing its own soft edge. */
      background-size:auto min(95%, 66.6vw);
      transform:translate(-13.5vw, 5.15vh);
      opacity:0;
    }
    body.tree-ready .welcome .tree-stage{
      animation:tree-in 1.2s cubic-bezier(0.22, 1, 0.36, 1) 0.2s both;
    }
    @keyframes tree-in{
      0%{
        opacity:0;
        filter:blur(10px) brightness(0.5);
        transform:translate(-13.5vw, 20vh) scale(1);
      }
      25%{
        opacity:1;
        filter:blur(2px) brightness(0.9);
      }
      100%{
        opacity:1;
        filter:blur(0) brightness(1);
        transform:translate(-13.5vw, 5.15vh) scale(1);
      }
    }

    .welcome .tree-leaf{
      position:absolute;
      left:var(--x);
      top:var(--y);
      /* --size is in vh (calibrated: 1vh = 13px on a ~1300px-tall viewport,
         the 27" reference) so leaves scale with the tree, which is
         height-fit. The 20px floor stops dust-speck leaves in short windows. */
      width:calc(max(var(--size, 3.2vh), 20px) * 0.68);
      will-change:transform, opacity;
      opacity:0;
      pointer-events:none;
    }
    body.tree-ready .welcome .tree-leaf{
      animation:tree-leaf-fade-in 0.6s ease-out 1.2s both,
                tree-fall var(--dur, 14s) linear calc(var(--delay, 0s) + 1.2s) infinite;
    }
    @keyframes tree-leaf-fade-in{
      from{opacity:0;}
      to  {opacity:1;}
    }
    .welcome .tree-leaf .tree-sway{
      animation:tree-sway var(--sway-dur, 5s) ease-in-out var(--sway-delay, 0s) infinite alternate;
    }
    .welcome .tree-leaf img{
      display:block;
      width:100%;
      height:auto;
      animation:tree-spin var(--spin-dur, 9s) linear var(--spin-delay, 0s) infinite;
      transform-origin:50% 50%;
      filter:drop-shadow(0 4px 6px rgba(0,0,0,0.4));
    }
    @keyframes tree-fall{
      0%   {transform:translate3d(0, 0, 0);                                                opacity:0;}
      6%   {opacity:var(--peak, 0.95);}
      85%  {opacity:var(--peak, 0.95);}
      100% {transform:translate3d(calc(var(--wind, 9vw) * 1.3), var(--fall, 70vh), 0);     opacity:0;}
    }
    @keyframes tree-sway{
      from{transform:translateX(calc(var(--sway-amp, 28px) * -1));}
      to  {transform:translateX(var(--sway-amp, 28px));}
    }
    @keyframes tree-spin{
      from{transform:rotate(var(--rot-from, -12deg));}
      to  {transform:rotate(var(--rot-to, 348deg));}
    }

    /* ─────────────── Warm light wash ───────────────
       Big soft warm light originating from the bottom-right
       corner, fanning across the welcome area to illuminate
       the autumn tree on the left. Uses `mix-blend-mode:
       screen` so the light reads as additive — the orange
       canopy glows where the wash reaches it, the dark
       background stays dark in the cold corners.
       Color matches --accent-warm and the foliage tones.
       ───────────────────────────────────────────────── */
    .welcome .welcome-light{
      position:absolute;
      inset:0;
      z-index:1;
      background:radial-gradient(ellipse 140% 130% at 96% 102%,
        rgba(255, 210, 140, 0.527) 0%,
        rgba(255, 180, 100, 0.408) 12%,
        rgba(255, 150, 70,  0.272) 26%,
        rgba(255, 120, 50,  0.170) 42%,
        rgba(255,  95, 35,  0.085) 60%,
        rgba(255,  80, 25,  0.034) 76%,
        rgba(0, 0, 0, 0)            90%);
      mix-blend-mode:screen;
      pointer-events:none;
      opacity:0;
    }
    body.tree-ready .welcome .welcome-light{
      animation:
        welcome-light-in      0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.3s forwards,
        welcome-light-breathe 7.4s ease-in-out 1.5s infinite;
    }
    @keyframes welcome-light-in{
      from{opacity:0;}
      to  {opacity:1;}
    }
    @keyframes welcome-light-breathe{
      0%,100%{opacity:1;    transform:scale(1);   }
      50%    {opacity:0.88; transform:scale(1.02);}
    }
    .welcome.hidden{display:none;}
    .welcome-eyebrow{
      font-family:var(--font-sans);
      font-size:0.6875rem;font-weight:700;letter-spacing:0.10em;
      color:rgba(232,200,158,0.90);text-transform:uppercase;
      margin-bottom:28px;
      padding:6px 16px;
      border:1px solid rgba(212,177,138,0.30);
      border-radius:999px;
      background:rgba(18,13,9,0.45);
      -webkit-backdrop-filter:blur(12px) saturate(1.3);
      backdrop-filter:blur(12px) saturate(1.3);
      box-shadow:inset 0 1px 0 rgba(255,210,160,0.10);
      opacity:0;
      animation:welcome-piece-in 720ms cubic-bezier(0.22, 1, 0.36, 1) 60ms forwards;
    }
    /* ═══════════════════════════════════════════════════════════
       Welcome wordmark — "CAVALRY[knight]"
         • Each letter rises through a mask reveal, staggered.
         • The knight is aligned with the cap height of the text and
           fades + rises in after the last letter — same rhythm as the
           tagline, no rotation gimmicks.
         • Hover the logo → plays on loop. Mouse out → current loop
           finishes, then the video pauses on its first frame again.
       ═══════════════════════════════════════════════════════════ */
    .welcome-wordmark{
      display:flex;align-items:center;justify-content:center;
      gap:0;
      margin-bottom:22px;
      max-width:100%;
    }
    .ch-text{
      display:inline-flex;
      flex-shrink:0;
      font-family:var(--font-display);
      /* Trimmed ~20% from the previous clamp(40px, 5.8vw, 88px).
         Smaller wordmark sits more comfortably in the upper-right
         pocket above the autumn canopy. */
      font-size:clamp(34px, 4.8vw, 72px);
      font-weight:700;
      letter-spacing:-0.045em;
      line-height:0.9;
      color:var(--text-primary);
      text-transform:uppercase;
      overflow:hidden;           /* clips each letter while it slides up */
      padding-bottom:0.08em;     /* descenders get a sliver of room */
      /* Lift above the knight in the stacking order so the letters
         always paint on top if the video's negative margin overlaps. */
      position:relative;
      z-index:2;
    }
    .ch-l{
      display:inline-block;
      transform:translateY(110%);
      opacity:0;
      animation:ch-letter-in 720ms cubic-bezier(0.22, 0.8, 0.18, 1) forwards;
      animation-delay:calc(var(--i) * 55ms + 140ms);
    }
    @keyframes ch-letter-in{
      0%  {transform:translateY(110%);opacity:0;}
      60% {opacity:1;}
      100%{transform:translateY(0);    opacity:1;}
    }
    .welcome-wordmark video{
      /* Sized ~1.6× the cap height of CAVALRY so the knight feels
         "tall" next to the letters. Floor and cap stepped down to
         match the trimmed wordmark size. */
      height:clamp(60px, 7.8vw, 124px);
      width:auto;max-width:30vw;
      flex-shrink:0;
      cursor:pointer;
      display:block;
      /* Knight sits tight against CAVALRY. The WebM has ~25.6%
         transparent left padding; the negative margin shaves part
         of that away so the visible knight body stays close to the
         text. Plain fade-in after the Y settles — no transform, so
         the later hover scale doesn't fight an animated transform. */
      margin-left:clamp(-32px, -1.4vw, -8px);
      position:relative;
      z-index:1;
      opacity:0;
      animation:knight-fade-in 600ms ease-out 580ms forwards;
    }
    @keyframes knight-fade-in{
      0%  {opacity:0;}
      100%{opacity:1;}
    }
    /* After the intro animation settles, hover gets its own transition.
       Scale triggers on hovering the whole lockup (CAVALRY + knight),
       not just the video — matches the loop-on-whole-row behavior. */
    .welcome-wordmark video.lit{
      transition:transform .3s var(--ease-out);
    }
    .welcome-wordmark:hover video.lit{
      transform:scale(1.05);
    }
    @keyframes ch-logo-in{
      0%  {transform:translateY(24px);opacity:0;}
      100%{transform:translateY(0);    opacity:1;}
    }
    .welcome-wordmark em{display:none;}
    .welcome-tagline{
      font-family:var(--font-sans);
      font-size:0.9rem;font-weight:500;letter-spacing:0;line-height:1.6;
      /* 500px keeps both taglines to two lines on desktop */
      color:var(--text-secondary);max-width:500px;text-align:center;
      margin-bottom:22px;
      opacity:0;
      animation:welcome-piece-in 720ms cubic-bezier(0.22, 1, 0.36, 1) 260ms forwards;
    }
    .welcome-hint{
      font-family:var(--font-sans);
      font-size:0.75rem;font-weight:600;letter-spacing:var(--tr-caps);
      color:var(--text-muted);text-transform:uppercase;
      display:flex;align-items:center;gap:10px;
      animation:mask-in-up var(--dur-reveal) var(--ease-out) 240ms both;
    }
    .welcome-hint::before,
    .welcome-hint::after{
      content:'';height:1px;width:32px;background:var(--border-strong);
    }

    /* Welcome hero "Track Stock" — inline search + "Go to Tracking"
       CTA, in the same row. Both controls share the same height and
       a polished aesthetic: gradient surfaces, soft drop shadow,
       refined borders, smooth focus/hover.  Results dropdown still
       anchors directly below the input. */
    .track-stock-row{
      display:flex;
      gap:12px;
      width:min(540px, 88vw);
      align-items:stretch;
      opacity:0;
      animation:welcome-piece-in 720ms cubic-bezier(0.22, 1, 0.36, 1) 460ms forwards;
    }
    .track-stock-wrap{
      position:relative;
      flex:1 1 auto;
      min-width:0;
    }
    .track-stock-field{
      display:flex;align-items:center;gap:10px;
      padding:15px 20px;
      background:rgba(18,13,9,0.52);
      -webkit-backdrop-filter:blur(20px) saturate(1.4);
      backdrop-filter:blur(20px) saturate(1.4);
      border:1px solid rgba(212,177,138,0.22);
      border-radius:var(--radius-sm);
      cursor:text;
      box-shadow:
        inset 0 1px 0 rgba(255,210,160,0.07),
        0 10px 40px -14px rgba(0,0,0,0.55);
      transition:border-color .22s var(--ease-out),
                 background   .22s var(--ease-out),
                 box-shadow   .22s var(--ease-out);
    }
    .track-stock-field:hover{
      border-color:rgba(212,177,138,0.48);
      background:rgba(20,15,10,0.58);
      box-shadow:
        inset 0 1px 0 rgba(255,210,160,0.10),
        0 12px 44px -12px rgba(0,0,0,0.60);
    }
    .track-stock-field:focus-within{
      border-color:var(--accent-warm);
      background:rgba(22,16,10,0.62);
      box-shadow:
        inset 0 1px 0 rgba(255,210,160,0.12),
        0 0 0 3px rgba(212,177,138,0.16),
        0 14px 44px -10px rgba(212,140,70,0.22);
    }
    .track-stock-field svg{
      opacity:.5;flex-shrink:0;color:var(--text-muted);
      transition:opacity .15s var(--ease-out),color .15s var(--ease-out);
    }
    .track-stock-field:focus-within svg{opacity:1;color:var(--text-secondary);}
    .track-stock-field input{
      flex:1;
      background:none;border:none;outline:none;
      font-family:var(--font-sans);font-size:0.875rem;font-weight:600;letter-spacing:0;
      color:var(--text-primary);
      caret-color:var(--accent-warm);
      min-width:0;       /* needed for flex shrink in narrow viewports */
    }
    .track-stock-field input::placeholder{
      color:var(--text-muted);font-weight:400;
    }

    /* Inline results dropdown — pinned directly under the input. */
    .track-stock-results{
      position:absolute;top:calc(100% + 6px);left:0;right:0;
      background:var(--bg-secondary);
      border:1px solid var(--border-default);
      border-radius:var(--radius-sm);
      box-shadow:0 16px 40px rgba(0,0,0,.55);
      max-height:min(360px, 50vh);overflow-y:auto;
      z-index:60;
      padding:4px 0;
    }
    .track-stock-results.hidden{display:none;}
    .track-stock-results::-webkit-scrollbar{width:4px;}
    .track-stock-results::-webkit-scrollbar-thumb{background:var(--border-default);border-radius:2px;}
    /* Reuse the same .sr-item / .sr-sym / .sr-name / .sr-meta classes the
       modal uses — the only override is a slightly tighter padding so the
       dropdown doesn't feel wider than the input itself. */
    .track-stock-results .sr-item{padding:10px 16px;}

    /* ═══════════════════════════════════════════════════════════
       Stock-loading overlay — fills the chart area while data is
       fetching or a new stock is mid-backfill. Pipeline:
         knight1 plays once (intro) → knight2 loops until done →
         overlay fades out, videos pause.
       Covers .charts, .graph-view, and .map-view; sits below the
       view-toggle (z:50) so the Price/Graph/Map switcher stays
       clickable while loading.
       ═══════════════════════════════════════════════════════════ */
    .stock-loading{
      position:absolute;inset:0;z-index:45;
      display:flex;flex-direction:column;align-items:center;justify-content:center;
      gap:22px;
      background:rgba(9,9,11,0.88);
      backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
      background-image:
        linear-gradient(rgba(255,255,255,0.035) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255,255,255,0.035) 1px, transparent 1px);
      background-size:48px 48px;
      opacity:1;
      transition:opacity .42s var(--ease-out);
      pointer-events:auto;
    }
    .stock-loading.hidden{
      opacity:0;
      pointer-events:none;
    }
    .stock-loading .ld-video{
      height:clamp(160px, 22vh, 280px);
      width:auto;max-width:60vw;
      display:block;
    }
    .stock-loading .ld-video.hidden{display:none;}
    .stock-loading .ld-caption{
      font-family:var(--font-sans);
      font-size:0.75rem;font-weight:700;letter-spacing:var(--tr-caps);
      color:var(--text-muted);text-transform:uppercase;
      animation:ld-pulse 1.8s ease-in-out infinite;
    }
    @keyframes ld-pulse{
      0%,100%{opacity:0.55;}
      50%    {opacity:1;}
    }
    /* Legacy fallback refs — keep so the initial HTML still renders if the
       welcome block template was not regenerated. */
    .welcome-icon{display:none;}
    .welcome-sub{font-size:0.8125rem;color:var(--text-muted);opacity:.6;}

    /* ═══════════════════════════════════════════════════════════
       TOAST
    ═══════════════════════════════════════════════════════════ */
    .toast{
      position:fixed;bottom:24px;left:50%;
      transform:translateX(-50%) translateY(80px);
      background:var(--red);color:#fff;
      padding:10px 20px;border-radius:var(--radius);
      font-size:0.8125rem;font-weight:600;
      opacity:0;transition:transform .3s cubic-bezier(.4,0,.2,1),opacity .3s;
      z-index:200;box-shadow:0 8px 32px rgba(0,0,0,.4);
    }
    .toast.show{transform:translateX(-50%) translateY(0);opacity:1;}

    /* Tweet hover tooltip */
    .tweet-tip{
      position:fixed;
      pointer-events:none;
      z-index:300;
      max-width:320px;
      padding:12px 14px;
      background:rgba(22,22,26,0.55);
      backdrop-filter:blur(24px) saturate(145%);
      -webkit-backdrop-filter:blur(24px) saturate(145%);
      border:1px solid rgba(255,255,255,0.06);
      border-radius:8px;
      box-shadow:0 8px 32px rgba(0,0,0,.5);
      font-size:0.8125rem;
      line-height:1.5;
      color:var(--text-primary);
      opacity:0;
      transform:translateY(4px);
      transition:opacity .15s ease, transform .15s ease;
    }
    .tweet-tip.visible{
      opacity:1;
      transform:translateY(0);
    }
    .tweet-tip .tt-user{
      font-family:var(--font-mono);
      font-size:0.75rem;
      font-weight:700;
      color:var(--accent);
      margin-bottom:4px;
    }
    .tweet-tip .tt-body{
      color:var(--text-primary);
      word-wrap:break-word;
      margin-bottom:6px;
    }
    .tweet-tip .tt-meta{
      display:flex;
      gap:10px;
      font-family:var(--font-mono);
      font-size:0.75rem;
      color:var(--text-muted);
    }
    .tweet-tip .tt-score{font-weight:700;}
    .tweet-tip .tt-score.bull{color:var(--green);}
    .tweet-tip .tt-score.bear{color:var(--red);}
    .tweet-tip .tt-score.neut{color:var(--text-secondary);}

    /* ═══════════════════════════════════════════════════════════
       VOLUME SPIKE MARKERS
    ═══════════════════════════════════════════════════════════ */
    .spike-canvas{
      position:absolute;top:0;left:0;width:100%;height:100%;
      pointer-events:none;z-index:2;
      transition:opacity .35s cubic-bezier(.4,0,.2,1);
    }
    .spike-canvas.fading{opacity:0;}

    /* ── Spike tooltip ── */
    .spike-tip{
      position:fixed;pointer-events:none;z-index:300;
      padding:0;
      background:rgba(14,14,18,0.55);
      backdrop-filter:blur(24px) saturate(145%);
      -webkit-backdrop-filter:blur(24px) saturate(145%);
      border:1px solid rgba(255,255,255,0.06);
      border-radius:8px;
      box-shadow:0 12px 40px rgba(0,0,0,.55);
      font-size:0.8125rem;line-height:1.5;color:var(--text-primary);
      opacity:0;transform:translateY(6px) scale(0.97);
      transition:opacity .18s ease, transform .18s cubic-bezier(.4,0,.2,1);
      max-width:260px;
      overflow:hidden;
    }
    .spike-tip.visible{opacity:1;transform:translateY(0) scale(1);}
    .spike-tip .st-header{
      display:flex;align-items:center;gap:8px;
      padding:10px 14px 8px;
      border-bottom:1px solid rgba(255,255,255,0.04);
    }
    .spike-tip .st-icon{
      width:22px;height:22px;border-radius:5px;
      display:flex;align-items:center;justify-content:center;
      font-size:0.75rem;flex-shrink:0;
    }
    .spike-tip .st-icon.buy{background:rgba(34,197,94,0.12);color:#22c55e;}
    .spike-tip .st-icon.sell{background:rgba(239,68,68,0.12);color:#ef4444;}
    .spike-tip .st-title{
      font-family:var(--font-sans);font-size:0.8125rem;font-weight:700;
      color:var(--text-primary);letter-spacing:-.01em;
    }
    .spike-tip .st-mag{
      margin-left:auto;
      font-family:var(--font-mono);font-size:0.75rem;font-weight:700;
      padding:2px 7px;border-radius:4px;
    }
    .spike-tip .st-mag.buy{background:rgba(34,197,94,0.1);color:#22c55e;}
    .spike-tip .st-mag.sell{background:rgba(239,68,68,0.1);color:#ef4444;}
    .spike-tip .st-body{padding:8px 14px 10px;}
    .spike-tip .st-row{
      display:flex;justify-content:space-between;align-items:center;
      padding:2px 0;
      font-family:var(--font-mono);font-size:0.75rem;color:var(--text-muted);
    }
    .spike-tip .st-val{color:var(--text-secondary);font-weight:600;}
    .spike-tip .st-bar{
      height:3px;border-radius:2px;margin-top:8px;
      background:rgba(255,255,255,0.04);overflow:hidden;
    }
    .spike-tip .st-bar-fill{
      height:100%;border-radius:2px;
      transition:width .3s ease;
    }
    .spike-tip .st-bar-fill.buy{background:linear-gradient(90deg,rgba(34,197,94,0.15),rgba(34,197,94,0.6));}
    .spike-tip .st-bar-fill.sell{background:linear-gradient(90deg,rgba(239,68,68,0.15),rgba(239,68,68,0.6));}

    /* ═══════════════════════════════════════════════════════════
       COMMAND CENTER — empty-state for the tracking page when no
       stock is selected. Three-section vertical layout:
         1. Pulse bar — top strip with watchlist-wide stats
         2. Card grid — one rich card per tracked stock
         3. Activity  — combined newest-first headline stream
       Cards are the focal point. Click → selectStock().
    ═══════════════════════════════════════════════════════════ */
    .command-center{
      flex:1;display:flex;flex-direction:column;
      position:relative;overflow:hidden;
      /* Tighten the tracking page: scale pulse bar + watchlist + activity
         to 90% of their natural size in one place. zoom (not transform:scale)
         keeps layout reflow, click targets, and scrollbars accurate. */
      zoom:0.9;
      background:var(--bg-primary);
      /* Line grid — same texture used on the welcome page. Two
         orthogonal linear-gradients laid on a 48px × 48px tile so
         the surface has the same trading-desk character throughout
         the whole product. */
      background-image:
        linear-gradient(rgba(255,255,255,0.035) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255,255,255,0.035) 1px, transparent 1px);
      background-size:48px 48px;
      opacity:0;
      transition:opacity 420ms var(--ease-out);
    }
    .command-center.visible{opacity:1;}
    .command-center.hidden{display:none!important;}

    /* Warm glow anchored to the bottom-right. Mirrors the welcome
       page's --welcome-light pattern but a touch less saturated so
       it sits behind data rather than competing with it. Range now
       covers roughly the bottom-right two-thirds of the surface. */
    .cc-light{
      position:absolute;inset:0;
      z-index:1;pointer-events:none;
      background:radial-gradient(ellipse 120% 100% at 98% 104%,
        rgba(255, 210, 140, 0.40) 0%,
        rgba(255, 185, 105, 0.30) 12%,
        rgba(255, 155, 75,  0.20) 26%,
        rgba(255, 125, 55,  0.12) 42%,
        rgba(255, 100, 40,  0.06) 58%,
        rgba(255,  85, 30,  0.025) 74%,
        rgba(0, 0, 0, 0)            90%);
      /* Normal blend (no screen) so the glow sits as a calm layer
         underneath — the translucent panels' 45% black overlay can
         then properly darken it where they cover, instead of the
         additive screen-blend making it pop through them. */
      opacity:0;
    }
    .command-center.visible .cc-light{
      animation:
        cc-light-in      0.9s var(--ease-out) 200ms forwards,
        cc-light-breathe 7.2s ease-in-out 1.5s infinite;
    }
    @keyframes cc-light-in{ to{opacity:1;} }
    @keyframes cc-light-breathe{
      0%,100%{opacity:1;}
      50%   {opacity:0.78;}
    }

    /* Inner scroll container — content lives here so the glow + grid
       stay anchored to the visible viewport, not the scroll height. */
    .cc-inner{
      position:relative;z-index:2;
      flex:1;overflow-y:auto;overflow-x:hidden;
      display:flex;flex-direction:column;gap:32px;
      padding:clamp(20px, 2.4vw, 48px);
      padding-top:clamp(28px, 3vw, 56px);
      width:100%;
      /* Firefox scrollbar */
      scrollbar-width:thin;
      scrollbar-color:rgba(212,177,138,0.22) transparent;
    }
    .cc-inner > *{max-width:1480px;width:100%;margin-left:auto;margin-right:auto;}

    /* Aesthetic scrollbars — gold-on-dark, thin, idle is nearly
       invisible, warmer on hover. Applied to both the page scroller
       and the activity feed scroller. */
    .cc-inner::-webkit-scrollbar,
    .cc-activity-feed::-webkit-scrollbar{
      width:10px;height:10px;
    }
    .cc-inner::-webkit-scrollbar-track,
    .cc-activity-feed::-webkit-scrollbar-track{
      background:transparent;
    }
    .cc-inner::-webkit-scrollbar-thumb,
    .cc-activity-feed::-webkit-scrollbar-thumb{
      background:rgba(255,255,255,0.06);
      border:3px solid transparent;
      background-clip:padding-box;
      border-radius:8px;
      transition:background 200ms ease-out;
    }
    .cc-inner:hover::-webkit-scrollbar-thumb,
    .cc-activity-feed:hover::-webkit-scrollbar-thumb{
      background:rgba(212,177,138,0.22);
      background-clip:padding-box;
    }
    .cc-inner::-webkit-scrollbar-thumb:hover,
    .cc-activity-feed::-webkit-scrollbar-thumb:hover{
      background:rgba(212,177,138,0.42);
      background-clip:padding-box;
    }
    .cc-inner::-webkit-scrollbar-corner,
    .cc-activity-feed::-webkit-scrollbar-corner{
      background:transparent;
    }
    .cc-activity-feed{
      scrollbar-width:thin;
      scrollbar-color:rgba(212,177,138,0.22) transparent;
    }

    /* Hide the floating Price/Graph/Map view dropdown while the
       command center is on screen — there's no chart to switch
       view modes for, and the dropdown floats over the pulse bar.
       Restores as soon as a stock is selected. */
    body:has(#command-center:not(.hidden)) .view-toggle{display:none!important;}

    /* ── PULSE BAR ─────────────────────────────────────────── */
    /* Frosted glass slab. Built up from four background layers so the
       surface reads as a real pane of glass:
         1. Top-left corner light-catch (radial)  — like a window
            reflection bouncing off the rim
         2. Bottom-right shadow pool (radial)     — gives weight
         3. Vertical sheen (linear)               — fakes glass
            thickness fading top→bottom
         4. Base translucent tint                 — the medium itself
       Backdrop-filter blurs whatever's behind so the grid texture
       reads softly through.  Top hairline + dual drop-shadows make
       the slab float above the page. */
    .cc-pulse{
      position:relative;
      display:grid;
      grid-template-columns:1.4fr repeat(4, 1fr);
      gap:0;
      /* Flex item in .cc-inner (column flex) — without flex-shrink:0
         the grid gets squeezed below its 96px row and overflow:hidden
         clips the values/subs. Let cc-inner's overflow-y:auto handle
         spillover instead. */
      flex-shrink:0;
      border:1px solid rgba(255,255,255,0.04);
      border-radius:10px;
      background:rgba(0,0,0,0.45);
      box-shadow:
        inset 0 1px 0 rgba(255,255,255,0.09),
        inset 0 -1px 0 rgba(0,0,0,0.32),
        0 22px 48px -28px rgba(0,0,0,0.85),
        0 4px 14px -8px rgba(0,0,0,0.50);
      overflow:hidden;
      opacity:0;transform:translateY(8px);
      animation:cc-piece-in 540ms var(--ease-out) 60ms forwards;
    }
    /* Top inner sheen — bright rim of light along the upper edge */
    .cc-pulse::before{
      content:'';position:absolute;
      top:0;left:6%;right:6%;height:1px;
      background:linear-gradient(90deg,
        transparent 0%,
        rgba(255,255,255,0.28) 50%,
        transparent 100%);
      pointer-events:none;z-index:3;
    }
    .cc-pulse-cell{
      position:relative;
      padding:18px 24px 20px;
      display:flex;flex-direction:column;gap:8px;
      min-width:0;
      min-height:96px;
    }
    /* Hairline dividers as gradient lines that fade at top/bottom
       so they don't slam into the rounded corners. */
    .cc-pulse-cell + .cc-pulse-cell::before{
      content:'';position:absolute;
      top:22%;bottom:22%;left:0;width:1px;
      background:linear-gradient(180deg,
        transparent 0%,
        rgba(255,255,255,0.10) 50%,
        transparent 100%);
      pointer-events:none;
    }
    .cc-pulse-cell.headline{
      background:linear-gradient(135deg,
        rgba(212,177,138,0.075) 0%,
        rgba(212,177,138,0.020) 55%,
        transparent 100%);
    }
    .cc-pulse-eyebrow{
      font-family:var(--font-sans);
      font-size:0.625rem;font-weight:700;letter-spacing:var(--tr-caps);
      color:var(--text-muted);text-transform:uppercase;
    }
    .cc-pulse-value{
      font-family:var(--font-mono);
      font-size:1.5rem;font-weight:700;letter-spacing:var(--tr-mono);
      color:#fafafa;font-variant-numeric:tabular-nums;
      line-height:1.15;
      white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
    }
    .cc-pulse-cell.headline .cc-pulse-value{
      font-family:var(--font-sans);
      font-size:1.25rem;font-weight:600;letter-spacing:0;
      color:#fafafa;
    }
    .cc-pulse-sub{
      font-family:var(--font-mono);
      font-size:0.6875rem;color:var(--text-secondary);
      letter-spacing:var(--tr-mono);font-variant-numeric:tabular-nums;
    }
    .cc-pulse-sub.up{color:var(--green);}
    .cc-pulse-sub.down{color:var(--red);}
    .cc-pulse-dot{
      display:inline-block;width:7px;height:7px;border-radius:50%;
      margin-right:8px;vertical-align:middle;
      background:var(--text-muted);
    }
    .cc-pulse-dot.live{
      background:var(--green);
      box-shadow:0 0 0 0 rgba(34,197,94,0.5);
      animation:cc-pulse-glow 2s ease-in-out infinite;
    }
    .cc-pulse-dot.extended{background:var(--amber);}
    @keyframes cc-pulse-glow{
      0%,100%{box-shadow:0 0 0 0 rgba(34,197,94,0.45);}
      50%   {box-shadow:0 0 0 6px rgba(34,197,94,0);}
    }

    /* ── SECTION HEADERS ───────────────────────────────────── */
    .cc-section{display:flex;flex-direction:column;gap:14px;}
    .cc-section-head{
      position:relative;
      display:flex;align-items:baseline;justify-content:space-between;
      padding:0 4px 10px;
    }
    /* Gradient underline — visually anchors the eyebrow to the panel
       below without using a hard rule.  Fades from a soft white on
       the left to nothing on the right. */
    .cc-section-head::after{
      content:'';position:absolute;
      left:4px;right:4px;bottom:0;height:1px;
      background:linear-gradient(90deg,
        rgba(255,255,255,0.10) 0%,
        rgba(255,255,255,0.03) 35%,
        transparent 100%);
      pointer-events:none;
    }
    .cc-section-title{
      font-family:var(--font-sans);
      font-size:0.75rem;font-weight:700;letter-spacing:var(--tr-caps);
      color:var(--text-primary);text-transform:uppercase;
    }
    .cc-section-sub{
      font-family:var(--font-mono);
      font-size:0.6875rem;letter-spacing:var(--tr-mono);
      color:var(--text-muted);
    }

    /* ── CARD GRID ─────────────────────────────────────────── */
    .cc-grid{
      display:grid;
      grid-template-columns:repeat(auto-fill, minmax(340px, 1fr));
      gap:16px;
    }

    /* ── CARD ──────────────────────────────────────────────── */
    /* Frosted-glass card — same four-layer construction as the
       pulse bar so the whole page reads as one material.  The
       top-left radial gives each card its own subtle light catch
       (as if hit by a window above-left); bottom-right radial
       provides the matching shadow pool for depth.  Top hairline
       brightens on hover, and the card lifts slightly. */
    .cc-card{
      position:relative;
      display:flex;flex-direction:column;
      padding:22px 22px 18px;
      background:rgba(0,0,0,0.45);
      border:1px solid rgba(255,255,255,0.04);
      border-radius:10px;
      box-shadow:
        inset 0 1px 0 rgba(255,255,255,0.085),
        inset 0 -1px 0 rgba(0,0,0,0.32),
        0 14px 32px -22px rgba(0,0,0,0.85),
        0 4px 12px -8px rgba(0,0,0,0.55);
      cursor:pointer;
      overflow:hidden;
      transition:
        transform 360ms var(--ease-out),
        border-color 260ms ease-out,
        box-shadow 360ms var(--ease-out),
        background 260ms ease-out;
      opacity:0;transform:translateY(12px);
      animation:cc-piece-in 600ms var(--ease-out) calc(180ms + var(--i, 0) * 60ms) forwards;
    }
    .cc-card:hover{
      transform:translateY(-4px);
      border-color:rgba(255,255,255,0.16);
      background:rgba(255,255,255,0.055);
      box-shadow:
        inset 0 1px 0 rgba(255,255,255,0.12),
        inset 0 -1px 0 rgba(0,0,0,0.32),
        0 26px 44px -24px rgba(0,0,0,0.92),
        0 6px 16px -10px rgba(0,0,0,0.60);
    }
    .cc-card:active{
      transform:translateY(-1px) scale(0.998);
      transition-duration:140ms;
    }
    /* Top edge sheen — a brighter hairline of light along the rim.
       Tightens/brightens on hover so the rim "catches" the cursor. */
    .cc-card::before{
      content:'';position:absolute;
      top:0;left:14%;right:14%;height:1px;
      background:linear-gradient(90deg,
        transparent 0%,
        rgba(255,255,255,0.24) 50%,
        transparent 100%);
      opacity:0.65;
      transition:opacity 320ms ease-out, left 320ms ease-out, right 320ms ease-out;
      z-index:3;
      pointer-events:none;
    }
    .cc-card:hover::before{opacity:1;left:8%;right:8%;}

    .cc-card-head{
      display:flex;align-items:center;gap:10px;
      margin-bottom:14px;min-width:0;
    }
    .cc-card-sym{
      font-family:var(--font-sans);
      font-size:1rem;font-weight:700;letter-spacing:var(--tr-heading);
      color:var(--text-primary);
      flex-shrink:0;
    }
    .cc-card-name{
      font-family:var(--font-sans);
      font-size:0.75rem;font-weight:500;color:var(--text-muted);
      letter-spacing:0;
      overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
      min-width:0;flex:1;
    }
    /* Time-range tag — top-right of the card header, not on the spark.
       Small mono caps, glass pill, recedes when the row is busy. */
    .cc-card-range{
      flex-shrink:0;
      font-family:var(--font-mono);
      font-size:0.625rem;font-weight:700;
      letter-spacing:var(--tr-caps);
      color:var(--text-muted);
      padding:2px 8px;
      border:1px solid rgba(255,255,255,0.07);
      border-radius:3px;
      background:rgba(255,255,255,0.035);
      box-shadow:inset 0 1px 0 rgba(255,255,255,0.05);
    }

    .cc-card-pricerow{
      display:flex;align-items:center;gap:12px;
      margin-bottom:14px;
      flex-wrap:nowrap;min-width:0;
    }
    .cc-card-price{
      font-family:var(--font-mono);
      font-size:1.75rem;font-weight:600;letter-spacing:-0.01em;
      color:var(--text-primary);
      font-variant-numeric:tabular-nums;
      line-height:1;
      flex-shrink:0;
    }
    .cc-card-chg{
      display:inline-flex;align-items:center;gap:4px;
      margin-left:auto;
      flex-shrink:0;
      font-family:var(--font-mono);
      font-size:0.75rem;font-weight:600;
      font-variant-numeric:tabular-nums;letter-spacing:var(--tr-mono);
      padding:3px 8px;
      border-radius:0;
      white-space:nowrap;
    }
    .cc-card-chg.up{
      color:var(--green);
      background:rgba(34,197,94,0.10);
      border:1px solid rgba(34,197,94,0.20);
      border-radius:3px;
    }
    .cc-card-chg.down{
      color:var(--red);
      background:rgba(239,68,68,0.10);
      border:1px solid rgba(239,68,68,0.20);
      border-radius:3px;
    }
    .cc-card-chg.flat{
      color:var(--text-secondary);
      background:rgba(255,255,255,0.03);
      border:1px solid rgba(255,255,255,0.06);
      border-radius:3px;
    }
    .cc-card-chg-arrow{font-size:0.625rem;line-height:1;}

    .cc-spark{
      position:relative;
      height:54px;width:100%;
      margin-bottom:16px;
    }
    .cc-spark svg{
      position:absolute;inset:0;width:100%;height:100%;
      overflow:visible;
    }
    /* Time-range tag on the sparkline so the user can read the
       window at a glance. Mono, small caps, sits in the top-right
       of the spark area like a chart-app range selector. */
    .cc-spark-label{
      position:absolute;
      top:-2px;right:0;
      z-index:2;
      font-family:var(--font-mono);
      font-size:0.625rem;font-weight:700;
      letter-spacing:var(--tr-caps);
      color:var(--text-muted);
      background:rgba(9,9,11,0.78);
      padding:2px 7px;
      border:1px solid var(--border-subtle);
      pointer-events:none;
      backdrop-filter:blur(2px);
    }
    .cc-spark .cc-spark-fill{opacity:0.18;}
    .cc-spark .cc-spark-line{
      fill:none;
      stroke-width:1;
      stroke-linecap:round;
      stroke-linejoin:round;
      stroke-dasharray:1000;
      stroke-dashoffset:1000;
      animation:cc-spark-draw 1100ms var(--ease-out) calc(360ms + var(--i, 0) * 60ms) forwards;
    }
    @keyframes cc-spark-draw{to{stroke-dashoffset:0;}}

    .cc-card-sent{
      display:flex;align-items:center;gap:10px;
      margin-bottom:14px;
    }
    .cc-sent-label{
      font-size:0.625rem;font-weight:700;letter-spacing:var(--tr-caps);
      color:var(--text-muted);text-transform:uppercase;
      flex-shrink:0;
    }
    .cc-sent-bar{
      flex:1;height:5px;
      background:linear-gradient(180deg,
        rgba(0,0,0,0.35) 0%,
        rgba(0,0,0,0.18) 100%);
      box-shadow:inset 0 1px 0 rgba(0,0,0,0.4),
                 inset 0 -1px 0 rgba(255,255,255,0.04);
      position:relative;
      border-radius:3px;
      overflow:hidden;
    }
    .cc-sent-bar::before{
      content:'';position:absolute;
      top:1px;bottom:1px;left:50%;width:1px;
      background:rgba(255,255,255,0.10);
    }
    .cc-sent-bar-fill{
      position:absolute;top:0;bottom:0;
      background:currentColor;
      border-radius:2px;
      transition:width 600ms var(--ease-out), left 600ms var(--ease-out);
    }
    .cc-sent-val{
      font-family:var(--font-mono);
      font-size:0.75rem;font-weight:600;letter-spacing:var(--tr-mono);
      color:var(--text-secondary);font-variant-numeric:tabular-nums;
      min-width:48px;text-align:right;
    }

    .cc-card-stats{
      display:flex;align-items:center;gap:14px;
      padding-top:14px;
      border-top:1px solid rgba(255,255,255,0.025);
    }
    .cc-stat{
      display:inline-flex;align-items:center;gap:6px;
      font-family:var(--font-mono);
      font-size:0.6875rem;color:var(--text-secondary);
      font-variant-numeric:tabular-nums;letter-spacing:var(--tr-mono);
    }
    .cc-stat svg{
      width:11px;height:11px;
      color:var(--text-muted);
      flex-shrink:0;
    }
    .cc-stat-num{color:var(--text-primary);font-weight:600;}

    .cc-card.skeleton{cursor:default;pointer-events:none;}
    .cc-card.skeleton .cc-card-price,
    .cc-card.skeleton .cc-card-chg,
    .cc-card.skeleton .cc-card-name,
    .cc-card.skeleton .cc-spark{
      background:linear-gradient(90deg,
        rgba(255,255,255,0.02) 0%,
        rgba(255,255,255,0.05) 50%,
        rgba(255,255,255,0.02) 100%);
      background-size:200% 100%;
      animation:cc-skel-shimmer 1.4s ease-in-out infinite;
      color:transparent;
      border-color:transparent;
    }
    @keyframes cc-skel-shimmer{
      0%{background-position:200% 0;}
      100%{background-position:-200% 0;}
    }

    /* ── ACTIVITY STREAM ───────────────────────────────────── */
    /* Frosted-glass panel matching the card + pulse treatment so the
       three pieces feel cut from the same material.  Same four-layer
       build: corner light + corner shadow + vertical sheen + base
       tint.  The sticky header gets its own subtle wash and a
       gradient hairline so it reads above the scrolling list. */
    .cc-activity{
      position:relative;
      display:flex;flex-direction:column;
      border:1px solid rgba(255,255,255,0.04);
      border-radius:10px;
      background:rgba(0,0,0,0.45);
      box-shadow:
        inset 0 1px 0 rgba(255,255,255,0.085),
        inset 0 -1px 0 rgba(0,0,0,0.30),
        0 22px 48px -26px rgba(0,0,0,0.85),
        0 4px 14px -10px rgba(0,0,0,0.50);
      overflow:hidden;
      opacity:0;transform:translateY(8px);
      animation:cc-piece-in 600ms var(--ease-out) 540ms forwards;
    }
    /* Top edge sheen on the activity panel — bright rim of light */
    .cc-activity::before{
      content:'';position:absolute;
      top:0;left:6%;right:6%;height:1px;
      background:linear-gradient(90deg,
        transparent 0%,
        rgba(255,255,255,0.24) 50%,
        transparent 100%);
      pointer-events:none;z-index:3;
    }
    .cc-activity-head{
      position:relative;
      display:flex;align-items:baseline;justify-content:space-between;
      padding:16px 22px;
      background:linear-gradient(180deg,
        rgba(212,177,138,0.030) 0%,
        rgba(255,255,255,0.008) 60%,
        transparent 100%);
    }
    /* Gradient hairline under the header — fades at both ends so it
       doesn't cut hard against the rounded corners. */
    .cc-activity-head::after{
      content:'';position:absolute;
      bottom:0;left:5%;right:5%;height:1px;
      background:linear-gradient(90deg,
        transparent 0%,
        rgba(255,255,255,0.10) 50%,
        transparent 100%);
      pointer-events:none;
    }
    .cc-activity-feed{
      display:flex;flex-direction:column;
      max-height:520px;overflow-y:auto;
    }
    .cc-act-row{
      position:relative;
      display:grid;
      grid-template-columns:64px 56px 86px 1fr auto;
      gap:14px;align-items:center;
      padding:12px 22px;
      border-bottom:1px solid rgba(255,255,255,0.04);
      cursor:pointer;
      transition:background 200ms ease-out, padding-left 200ms ease-out;
      min-width:0;
    }
    .cc-act-row:last-child{border-bottom:none;}
    /* Hover: a thin warm accent rail slides in from the left, the
       row tints, and content nudges right. */
    .cc-act-row::before{
      content:'';position:absolute;
      left:0;top:0;bottom:0;width:2px;
      background:linear-gradient(180deg,
        transparent 0%,
        var(--accent-warm) 50%,
        transparent 100%);
      transform:scaleY(0);
      transform-origin:center;
      transition:transform 220ms var(--ease-out);
    }
    .cc-act-row:hover{
      background:linear-gradient(90deg,
        rgba(212,177,138,0.045) 0%,
        rgba(212,177,138,0.012) 30%,
        transparent 70%);
      padding-left:26px;
    }
    .cc-act-row:hover::before{transform:scaleY(1);}
    .cc-act-time{
      font-family:var(--font-mono);
      font-size:0.6875rem;color:var(--text-muted);
      font-variant-numeric:tabular-nums;letter-spacing:var(--tr-mono);
    }
    .cc-act-sym{
      display:inline-flex;align-items:center;justify-content:center;
      font-family:var(--font-sans);
      font-size:0.6875rem;font-weight:700;letter-spacing:var(--tr-heading);
      color:var(--text-primary);
      padding:3px 7px;
      background:linear-gradient(180deg,
        rgba(255,255,255,0.055) 0%,
        rgba(255,255,255,0.012) 100%);
      border:1px solid rgba(255,255,255,0.07);
      border-radius:3px;
      box-shadow:inset 0 1px 0 rgba(255,255,255,0.06);
    }
    .cc-act-src{
      font-family:var(--font-mono);
      font-size:0.625rem;color:var(--text-muted);
      text-transform:uppercase;letter-spacing:var(--tr-mono);
      overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
    }
    .cc-act-headline{
      font-family:var(--font-sans);
      font-size:0.8125rem;font-weight:500;color:var(--text-primary);
      letter-spacing:0;
      overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
      min-width:0;
    }
    .cc-act-sent{
      display:inline-block;width:7px;height:7px;border-radius:50%;
      flex-shrink:0;
    }
    .cc-act-empty{
      padding:48px 20px;text-align:center;
      font-family:var(--font-sans);font-size:0.8125rem;
      color:var(--text-muted);
    }

    @keyframes cc-piece-in{to{opacity:1;transform:translateY(0);}}

    @media(max-width:760px){
      .cc-pulse{grid-template-columns:1fr 1fr;}
      .cc-pulse-cell{border-right:none;border-bottom:1px solid var(--border-subtle);}
      .cc-pulse-cell.headline{grid-column:span 2;}
      .cc-grid{grid-template-columns:1fr;}
      .cc-act-row{grid-template-columns:54px 1fr auto;}
      .cc-act-row .cc-act-sym{display:none;}
      .cc-act-row .cc-act-src{display:none;}
    }

    /* ═══════════════════════════════════════════════════════════
       MOBILE
    ═══════════════════════════════════════════════════════════ */
    @media(max-width:640px){
      :root{--sidebar-w:200px;}
      body{height:auto;min-height:100vh;overflow:auto;}
      .main{height:auto;min-height:100vh;overflow:auto;}
      .charts{min-height:65vh;}
      .hdr{padding:0 16px;gap:10px;}
      .hdr-stats{display:none;}
      .sent-bar{padding:0 16px;gap:8px;flex-wrap:wrap;height:auto;padding:6px 16px;}
      .time-controls{padding:8px 16px;}
    }

    /* ── Chart resizer: drag handle between the price panel and the graphs.
       Dragging it caps --charts-scroll-max so the graph wrapper scrolls and
       the price panel stretches; graph panels keep their fixed 145px. ───── */
    .chart-resizer{
      flex:0 0 7px;
      position:relative;
      cursor:ns-resize;
      background:transparent;
      transition:background .15s ease;
    }
    .chart-resizer::before{
      content:'';
      position:absolute;left:50%;top:50%;
      width:42px;height:2px;
      transform:translate(-50%,-50%);
      border-radius:1px;
      background:rgba(255,255,255,0.12);
      transition:background .15s ease,width .15s ease;
    }
    .chart-resizer:hover{background:rgba(255,255,255,0.035);}
    .chart-resizer:hover::before,
    .chart-resizer.dragging::before{background:var(--accent,#a78bfa);width:58px;}
    .chart-resizer.dragging{background:rgba(167,139,250,0.07);}
    /* While dragging, force the resize cursor everywhere + kill text selection. */
    body.chart-resizing,body.chart-resizing *{cursor:ns-resize!important;user-select:none!important;}

    /* ── Signals view: sentiment graphs only (no price), for a second monitor.
       The price LightweightCharts instance stays alive — the graph canvases
       read their X-axis from its time scale — so it's parked off-screen with a
       real size (visibility:hidden keeps layout) rather than display:none. ── */
    .charts.signals-only{position:relative;}
    .charts.signals-only #cp-price{
      position:absolute;top:0;left:0;
      width:100%;height:320px;
      visibility:hidden;pointer-events:none;
    }
    .charts.signals-only #chart-resizer{display:none!important;}
    /* The graph-toolbar becomes the signals-view top bar: a clean 56px strip
       holding the "Modify graphs" button on the left. The floating view-toggle
       dropdown sits on the right (same top:10 it uses in the price header), so
       the graphs start below this strip and neither button overlaps them. */
    .charts.signals-only #graph-toolbar{
      flex:0 0 56px;
      justify-content:flex-start;
      padding:0 16px;
    }
    .charts.signals-only .charts-scroll{
      flex:1 1 auto;
      max-height:none!important;          /* ignore the price-resizer drag cap */
    }
    /* Every visible graph stretches to share the whole canvas — this view is
       their dedicated space. Collapsed dot panels stay folded (excluded). */
    .charts.signals-only .charts-scroll > .cp:not(.cp-collapsed){
      flex:1 1 0;
      min-height:70px;
    }

    /* ── Graph toolbar: thin separator between price panel and lower panels.
       Compact 28px strip holding the "Modify graphs" trigger on the right. ── */
    .graph-toolbar{
      flex:0 0 28px;
      display:flex;align-items:center;justify-content:flex-end;
      padding:0 14px;
      background:rgba(13,13,19,0.55);
      -webkit-backdrop-filter:blur(8px) saturate(135%);
              backdrop-filter:blur(8px) saturate(135%);
      border-top:1px solid rgba(255,255,255,0.04);
      border-bottom:1px solid rgba(255,255,255,0.04);
      position:relative;z-index:9;
    }
    /* "Modify graphs" trigger — restrained Chivalry-gold chip. Small enough
       to recede into the toolbar but still warm-toned so it reads as a CTA. */
    .gtb-btn{
      display:inline-flex;align-items:center;gap:7px;
      font-family:inherit;font-size:0.7rem;font-weight:700;
      text-transform:uppercase;letter-spacing:.09em;
      color:var(--accent-warm,#d4b18a);
      background:rgba(212,177,138,.08);
      border:1px solid rgba(212,177,138,.35);
      border-radius:4px;padding:5px 12px;cursor:pointer;
      transition:color .18s ease,border-color .18s ease,
                 background .18s ease,transform .12s ease;
    }
    .gtb-btn:hover{
      color:#f0d0a0;
      border-color:rgba(212,177,138,.60);
      background:rgba(212,177,138,.13);
    }
    .gtb-btn:active{ transform:translateY(1px); }
    .gtb-btn svg{stroke:currentColor;flex-shrink:0;width:13px;height:13px;}

    /* ── Modify-graphs modal ─────────────────────────────────
       Full-page overlay with backdrop blur on everything behind it,
       centered card with one checkbox row per lower panel. */
    .gtb-modal{
      position:fixed;inset:0;z-index:1000;
      display:flex;align-items:center;justify-content:center;
      background:rgba(9,9,11,0.55);
      -webkit-backdrop-filter:blur(10px) saturate(120%);
              backdrop-filter:blur(10px) saturate(120%);
      animation:gtb-fade .18s ease;
    }
    .gtb-modal.hidden{display:none!important;}
    @keyframes gtb-fade{from{opacity:0;}to{opacity:1;}}
    .gtb-modal-card{
      min-width:340px;max-width:440px;
      background:var(--bg-elevated,#16161d);
      border:1px solid var(--border-default,#2a2a35);
      border-radius:var(--radius-md,6px);
      padding:18px 20px 14px;
      box-shadow:0 14px 44px rgba(0,0,0,0.55);
      animation:gtb-rise .22s cubic-bezier(.22,.61,.36,1);
    }
    @keyframes gtb-rise{
      from{opacity:0;transform:translateY(6px);}
      to{opacity:1;transform:translateY(0);}
    }
    .gtb-modal-head{
      display:flex;align-items:center;justify-content:space-between;
      font-size:0.75rem;font-weight:700;color:var(--text-primary);
      text-transform:uppercase;letter-spacing:.08em;
      padding-bottom:10px;margin-bottom:8px;
      border-bottom:1px solid rgba(255,255,255,0.05);
    }
    .gtb-close{
      background:transparent;border:none;color:var(--text-muted);
      font-size:1.4rem;line-height:1;cursor:pointer;padding:0 6px;
      transition:color .15s ease;
    }
    .gtb-close:hover{color:var(--text-primary);}
    .gtb-modal-body{
      display:flex;flex-direction:column;gap:2px;
      max-height:60vh;overflow-y:auto;
    }
    /* "Technical Indicators" section divider inside the Modify-graphs modal */
    .gtb-section{
      font-size:0.625rem;font-weight:700;color:var(--text-muted);
      text-transform:uppercase;letter-spacing:.08em;
      margin-top:12px;padding:8px 6px 4px;
      border-top:1px solid rgba(255,255,255,0.05);
    }
    /* per-category sub-header (momentum / overlay / volatility / volume) */
    .gtb-cat{
      font-size:0.5625rem;font-weight:700;color:var(--text-muted);
      text-transform:uppercase;letter-spacing:.07em;
      opacity:.55;padding:7px 6px 2px;
    }
    .gtb-row{
      display:flex;align-items:center;gap:10px;
      padding:7px 6px;border-radius:3px;cursor:pointer;
      font-size:0.8125rem;color:var(--text-primary);
      transition:background .15s ease;
    }
    .gtb-row:hover{background:rgba(255,255,255,0.025);}
    .gtb-row input[type=checkbox]{
      accent-color:var(--accent,#a78bfa);
      width:14px;height:14px;cursor:pointer;flex-shrink:0;
    }

    /* Hidden by the modal's checkbox toggle. Separate from .cp-collapsed
       (which folds within the layout) — this removes the panel entirely. */
    .cp.cp-modal-hidden{display:none!important;}

    /* ── Oscillator panes (top of the graph stack, below the Modify-graphs
       toolbar) ──────────────────────────────────────────────────────────── */
    /* flex:0 0 auto — content-sized, never shrinks; the wrapper scrolls
       instead, matching the fixed .cp graph panels. */
    #indicatorPanes { display: flex; flex-direction: column; flex: 0 0 auto; }
    .indicator-pane { position: relative; height: 120px; border-top: 1px solid rgba(255,255,255,.08); }
    /* Match .cp-label exactly — same tinted chip the sentiment graphs use, so
       indicator names share the same typographic treatment. */
    .indicator-pane__label {
      position: absolute; top: 6px; left: 10px; z-index: 5;
      font-size: 0.625rem; font-weight: 700; color: var(--text-muted);
      text-transform: uppercase; letter-spacing: .08em;
      pointer-events: none;
      padding: 2px 7px; border-radius: 3px;
      background: rgba(9, 9, 11, .62);
      -webkit-backdrop-filter: blur(4px);
              backdrop-filter: blur(4px);
    }

    /* ═══════════════════════════════════════════════════════════
       Home hero — Tracking ⇄ Research, in place (no page travel).
       Both heroes occupy the SAME cell, stacked. Switching crossfades
       them; the incoming background pops up from below. Nothing slides
       sideways, so the layout never "moves".
       ═══════════════════════════════════════════════════════════ */
    .hero-track{
      flex:1;
      position:relative;
      min-height:0;
    }
    .hero-track > .welcome{ position:absolute; inset:0; width:100%; }
    .welcome{ transition:opacity .6s ease; }
    /* Tracking shows by default; Eva crossfades in over it. */
    .main[data-slide="track"] .welcome-eva{ opacity:0; pointer-events:none; }
    .main[data-slide="eva"]   #welcome{ opacity:0; pointer-events:none; }
    .main[data-slide="eva"]   .welcome-eva{ opacity:1; }

    /* Circular slider arrows pinned to each vertical edge of the hero. */
    .hero-arrow{
      position:absolute; top:50%; transform:translateY(-50%);
      z-index:30;
      width:48px; height:48px; border-radius:50%;
      display:flex; align-items:center; justify-content:center;
      background:rgba(18,13,9,0.50);
      border:1px solid rgba(212,177,138,0.28);
      color:rgba(212,177,138,0.70);
      cursor:pointer;
      -webkit-backdrop-filter:blur(14px) saturate(1.3);
      backdrop-filter:blur(14px) saturate(1.3);
      box-shadow:inset 0 1px 0 rgba(255,210,160,0.08);
      transition:opacity .45s ease, background .20s ease,
                 border-color .20s ease, color .20s ease,
                 box-shadow .20s ease, transform .20s ease;
    }
    .hero-arrow:hover{
      background:rgba(25,18,12,0.65);
      border-color:rgba(212,177,138,0.60);
      color:#e7c9a3;
      box-shadow:
        inset 0 1px 0 rgba(255,210,160,0.14),
        0 6px 20px -8px rgba(212,140,70,0.35);
      transform:translateY(-50%) scale(1.04);
    }
    .hero-arrow:active{ transform:translateY(-50%) scale(.94); }
    .hero-arrow svg{ display:block; transition:transform .45s cubic-bezier(0.22, 1, 0.36, 1); }
    /* Single toggle arrow, always on the right edge. */
    .hero-arrow-toggle{ right:20px; }
    /* On the research slide the chevron flips to point left (= go back). */
    .main[data-slide="eva"] .hero-arrow-toggle svg{ transform:rotate(180deg); }

    /* ───────────────────────────────────────────────────────────
       Consistent pop-up transition for BOTH slides.
       Whichever slide is .is-active plays the SAME entrance: its
       background(s), CAVALRY and logo rise up from below and fade in;
       the other slide fades out. JS sets .is-active on the INCOMING
       slide on every toggle (and on tracking at load), so the motion
       is identical in both directions.
       ─────────────────────────────────────────────────────────── */

    /* Backgrounds pop up via keyframe ANIMATIONS (not transitions) so the
       restart trick replays them on EVERY activation — identical both ways.
       animation:none !important on the base opts out of the old one-shot
       tree-in; the active rules re-assert with !important. */
    .welcome .tree-stage{ animation:none !important; opacity:0; }

    #welcome .tree-stage{ transform:translate(-13.5vw, 120vh); }
    #welcome.is-active .tree-stage{
      animation:tree-pop-track .9s cubic-bezier(0.22, 1, 0.36, 1) forwards !important;
    }
    @keyframes tree-pop-track{
      0%  { opacity:0; transform:translate(-13.5vw, 120vh); }
      100%{ opacity:1; transform:translate(-13.5vw, 5.15vh); }
    }

    /* Eva: rose-bridge in front. */
    .welcome-eva .tree-stage{
      background-image:url("/static/rose/bg_bridge.png");
      /* bg_bridge.png is 2.01:1 — same width cap as the tree (h × 2.01
         ≤ stage width) so fullscreen never hard-clips the hill's right side */
      background-size:auto min(95%, 49.7vw);
      transform:translate(-20.5vw, 120vh) scale(0.95);
    }
    #welcome-eva.is-active .tree-stage{
      animation:tree-pop-eva .9s cubic-bezier(0.22, 1, 0.36, 1) forwards !important;
    }
    @keyframes tree-pop-eva{
      0%  { opacity:0; transform:translate(-20.5vw, 120vh) scale(0.95); }
      100%{ opacity:1; transform:translate(-20.5vw, 25.15vh) scale(0.95); }
    }

    /* Eva: archer-tower behind the bridge, rises a beat later (+0.22s). */
    .welcome-eva .tree-back{
      position:absolute; inset:0; z-index:0;
      background-image:url("/static/rose/archer_tower_v2.png");
      background-repeat:no-repeat;
      /* Height-limited to ~70% of the panel and anchored higher (33%
         from the top, not bottom) so the tower rises clear of the
         bridge instead of hiding behind it. */
      background-position:center 33%;
      background-size:auto 70%;
      opacity:0;
      transform:translate(-30vw, 120vh);
      pointer-events:none;
    }
    #welcome-eva.is-active .tree-back{
      animation:archer-pop .9s cubic-bezier(0.22, 1, 0.36, 1) .22s forwards;
    }
    @keyframes archer-pop{
      0%  { opacity:0; transform:translate(-30vw, 120vh); }
      100%{ opacity:1; transform:translate(-30vw, -2vh); }
    }

    /* Rose petals on the air — each blows IN from off-screen left and drifts
       diagonally down toward the bottom. The field is a plain full-panel
       overlay (not the transformed bridge stage) so the path stays clean.
       Per-petal CSS vars (--x0/--y0 start, --drift/--fall end) shape each arc. */
    .welcome-eva .petal-field{
      position:absolute; inset:0; z-index:1;
      overflow:hidden; pointer-events:none;
    }
    .welcome-eva .petal{
      position:absolute; top:var(--top, 0%); left:0;
      width:var(--size, 32px); height:var(--size, 32px);
      background:var(--img) center / contain no-repeat;
      opacity:0;
      will-change:transform, opacity;
      filter:drop-shadow(0 4px 6px rgba(0,0,0,0.35));
      animation:petal-drift var(--dur, 15s) linear var(--delay, 0s) infinite;
    }
    @keyframes petal-drift{
      0%   { transform:translate3d(var(--x0, -14vw), var(--y0, -6vh), 0) rotate(0deg); opacity:0; }
      8%   { opacity:var(--peak, 0.92); }
      88%  { opacity:var(--peak, 0.92); }
      100% { transform:translate3d(var(--drift, 45vw), var(--fall, 104vh), 0) rotate(var(--spin, 210deg)); opacity:0; }
    }

    /* Eva ambient light — soft spring rose-pink (no icy blue), dialed down so
       it doesn't wash out the centre of the hero. The amber autumn glow is
       untouched on the tracking slide. */
    .welcome-eva .welcome-light{
      background:radial-gradient(ellipse 135% 125% at 98% 104%,
        rgba(255, 176, 206, 0.34) 0%,
        rgba(255, 150, 190, 0.23) 16%,
        rgba(255, 135, 178, 0.13) 36%,
        rgba(250, 165, 200, 0.06) 58%,
        rgba(0, 0, 0, 0)          82%);
    }
    /* Central glow pulled WAY down (was the main source of mid-page wash). */
    .welcome-eva .tree-glow{
      background:radial-gradient(ellipse 52% 44% at 30% 48%,
        rgba(255, 178, 208, 0.07) 0%,
        rgba(255, 150, 190, 0.03) 38%,
        rgba(0, 0, 0, 0)          68%);
    }

    /* Eva eyebrow badge — rose pink glass instead of amber. */
    .welcome-eva .welcome-eyebrow{
      color:rgba(242,168,200,0.92);
      border-color:rgba(220,100,155,0.38);
      background:rgba(35,10,20,0.48);
    }

    /* Research CTA — glass rose pink to match the glassmorphism system. */
    .welcome-eva .welcome-cta{
      background:linear-gradient(180deg,
        rgba(220,100,155,0.38) 0%,
        rgba(200,75,135,0.20) 100%);
      border-color:rgba(232,130,175,0.55);
      color:#f5c4db;
      box-shadow:
        inset 0 1px 0 rgba(255,210,235,0.22),
        0 12px 32px -12px rgba(210,80,145,0.50);
    }
    .welcome-eva .welcome-cta:hover{
      background:linear-gradient(180deg,
        rgba(220,100,155,0.52) 0%,
        rgba(200,75,135,0.32) 100%);
      border-color:rgba(240,150,190,0.78);
      color:#fce0ee;
      box-shadow:
        inset 0 1px 0 rgba(255,210,235,0.30),
        0 16px 40px -10px rgba(210,80,145,0.65);
    }
    .welcome-eva .welcome-cta svg{ opacity:1; }

    /* The research logo occupies the EXACT same box as the knight video so the
       lockup width — and therefore the CAVALRY position and the logo's size +
       position — is pixel-identical on both slides (seamless crossfade). The
       knight is height:clamp(60,7.8vw,124) width:auto on a 1.5:1 frame, i.e.
       width:clamp(90,11.7vw,186), with the same negative tuck. The square logo
       is centred inside that box via object-fit. */
    .welcome-wordmark .brand-logo{
      height:clamp(60px, 7.8vw, 124px);
      width:clamp(90px, 11.7vw, 186px);
      object-fit:contain;
      object-position:center;
      margin-left:clamp(-32px, -1.4vw, -8px);
      flex-shrink:0; display:block;
      position:relative; z-index:1;
      opacity:0;
    }

    /* Content hidden by default; the active slide rises + fades it in. These
       selectors are more specific than the original load-time rules, so they
       win for BOTH slides. */
    .welcome .welcome-eyebrow,
    .welcome .welcome-tagline,
    .welcome .track-stock-row,
    .welcome .welcome-wordmark video,
    .welcome .welcome-wordmark .brand-logo{ animation:none; opacity:0; }
    .welcome .ch-l{ animation:none; opacity:0; transform:translateY(110%); }

    .welcome.is-active .welcome-eyebrow{
      animation:welcome-piece-in 720ms cubic-bezier(0.22, 1, 0.36, 1) 60ms forwards;
    }
    .welcome.is-active .ch-l{
      animation:ch-letter-in 720ms cubic-bezier(0.22, 0.8, 0.18, 1) forwards;
      animation-delay:calc(var(--i) * 55ms + 140ms);
    }
    /* The knight AND the research logo pop up from below (was a plain fade) so
       the logo swap matches CAVALRY + the background motion. */
    .welcome.is-active .welcome-wordmark video,
    .welcome.is-active .welcome-wordmark .brand-logo{
      animation:ch-logo-in 620ms cubic-bezier(0.22, 1, 0.36, 1) 540ms forwards;
    }
    .welcome.is-active .welcome-tagline{
      animation:welcome-piece-in 720ms cubic-bezier(0.22, 1, 0.36, 1) 260ms forwards;
    }
    .welcome.is-active .track-stock-row{
      animation:welcome-piece-in 720ms cubic-bezier(0.22, 1, 0.36, 1) 460ms forwards;
    }


/* ═══════════════════════════════════════════════════════════
   WELCOME HERO — RESPONSIVE
   Goal: every hero piece (name, logo, tagline, search row, CTA) must
   shrink FASTER than the viewport so on a small window they read
   small — proportional, not desktop-sized.

   Each tier uses a LOW vw coefficient + a low cap, so the value tracks
   the window tightly and never balloons. The 1366 tier catches laptops
   (which sit above the old 1000 cut and were getting full desktop size).
   Selectors are double-class (.welcome .x) so they beat the single-class
   base rules. Sizes step DOWN monotonically across the tiers. */

/* KEY TRICK: every tier uses the SAME vw coefficient (ch 4.0vw, logo 6.5vw,
   logo-width 9.75vw). Only the cap (upper clamp) and floor (lower clamp)
   step down per tier. That makes each property a SINGLE continuous line as
   the window shrinks — it can only get smaller, never bumps back up at a
   breakpoint (the bug before, where a steeper per-tier coefficient made the
   text grow again after crossing a breakpoint). */

/* Laptops / small desktops — start shrinking before the layout flips.
   MUST shrink the CONTROLS too (eyebrow, search field, input, button),
   not just the name/logo — laptops sit in this 1000–1366 band and were
   keeping full-desktop controls while only the wordmark scaled. */
@media screen and (max-width:1366px){
    .welcome .ch-text{ font-size:clamp(30px, 4.0vw, 56px); }
    .welcome .welcome-wordmark video,
    .welcome .welcome-wordmark .brand-logo{ height:clamp(48px, 6.5vw, 96px); }
    .welcome .welcome-wordmark .brand-logo{ width:clamp(72px, 9.75vw, 144px); }
    .welcome .welcome-tagline{ font-size:0.85rem; }
    .welcome .welcome-eyebrow{ font-size:0.6875rem; padding:5px 12px; margin-bottom:22px; }
    .welcome .track-stock-row{ width:min(480px, 42vw); }
    .welcome .track-stock-field{ padding:11px 15px; }
    .welcome .track-stock-field input{ font-size:0.8125rem; }
    .welcome .welcome-cta{ padding:11px 17px; font-size:0.75rem; }
}

/* Laptops (effective 1280–1680 with OS display scaling) — the artwork
   is height-fit and reaches further right relative to the narrower
   window, so the content column hugs the right edge harder: tighter
   right gutter + narrower column = less overlap with the tree/bridge. */
@media screen and (min-width:1001px) and (max-width:1680px){
    .hero-track .welcome{ padding-right:clamp(16px, 1.8vw, 32px); }
    .welcome .welcome-content{ max-width:min(600px, 41vw); }
    .welcome .welcome-tagline{ max-width:380px; }
}

/* Tablet / narrow window — flip to a CENTRED column so nothing spills
   over the artwork and the controls fit their parent. Caps drop; the 4.0vw
   line continues unbroken from the tier above. */
@media screen and (max-width:1000px){
    .hero-track .welcome{ justify-content:center; padding:0 24px; }
    .welcome .welcome-content{
      max-width:min(520px, 88vw);
      width:100%;
      margin-top:clamp(88px, 15vh, 150px);
    }
    .welcome .ch-text{ font-size:clamp(24px, 4.0vw, 40px); }
    .welcome .welcome-wordmark video,
    .welcome .welcome-wordmark .brand-logo{
      height:clamp(40px, 6.5vw, 65px);
      margin-left:clamp(-18px, -1vw, -6px);
    }
    .welcome .welcome-wordmark .brand-logo{ width:clamp(60px, 9.75vw, 98px); }
    .welcome .welcome-tagline{ font-size:0.82rem; max-width:340px; margin-bottom:16px; }
    .welcome .welcome-eyebrow{ font-size:0.6875rem; margin-bottom:16px; padding:5px 12px; }
    .welcome .track-stock-row{ width:100%; max-width:460px; }
    .welcome .track-stock-field{ padding:11px 14px; }
    .welcome .track-stock-field input{ font-size:0.8125rem; }
    .welcome .welcome-cta{ padding:11px 16px; font-size:0.75rem; }
}

/* Phones — smaller still; stack the search field above the CTA. */
@media screen and (max-width:620px){
    .welcome .welcome-content{
      max-width:none;
      margin-top:clamp(56px, 11vh, 104px);
      padding:8px 4px;
    }
    .welcome .ch-text{ font-size:clamp(20px, 4.0vw, 26px); }
    .welcome .welcome-wordmark video,
    .welcome .welcome-wordmark .brand-logo{ height:clamp(30px, 6.5vw, 40px); }
    .welcome .welcome-wordmark .brand-logo{ width:clamp(45px, 9.75vw, 60px); }
    .welcome .welcome-tagline{ font-size:0.78rem; max-width:280px; margin-bottom:14px; }
    .welcome .welcome-eyebrow{ font-size:0.625rem; margin-bottom:14px; }
    .welcome .track-stock-row{ width:min(340px, 90vw); flex-direction:column; gap:10px; }
    .welcome .track-stock-field{ padding:10px 13px; }
    .welcome .welcome-cta{ padding:11px 14px; font-size:0.72rem; gap:6px; justify-content:center; }
    /* Shrink + lift the tower a touch more on phones. */
    .welcome-eva .tree-back{ background-size:auto 60%; background-position:center 30%; }
}

/* Tiny phones. */
@media screen and (max-width:400px){
    .welcome .ch-text{ font-size:clamp(18px, 4.5vw, 20px); }
    .welcome .welcome-wordmark video,
    .welcome .welcome-wordmark .brand-logo{ height:clamp(28px, 7vw, 30px); }
    .welcome .welcome-wordmark .brand-logo{ width:clamp(42px, 10.5vw, 45px); }
    .welcome .welcome-tagline{ font-size:0.74rem; }
    .welcome .welcome-cta{ font-size:0.6875rem; }
}
