/* ═════════════════════════════════════════════════════════════════════════════
   MOWGLI·SCAN — styles/app.css (eng-modernization task 9; F6, N-F7 partial)
   THE one obvious place for application CSS.

   Collapsed from three of the four former CSS layers, preserving cascade
   order exactly:
     1. index.html's ~1,350-line inline <style> block  (was: after the two
        design-system <link>s)
     2. index.html's small second inline block (mcap modal)
     3. user-management.js injectCSS() (~250 lines — was appended to <head>
        at runtime, therefore last; it stays last here)
   The fourth layer — the Token_Bridge — is RETIRED: its alias tokens were
   migrated to the colors_and_type.css design tokens at every reference.

   Load order (wiring contract): colors_and_type.css → mws-components.css →
   THIS FILE. Only the FOUC-prevention theme preload stays inline in
   index.html.
   ═══════════════════════════════════════════════════════════════════════════ */


*{margin:0;padding:0;box-sizing:border-box}
body{--filter-w:360px;background:var(--bg-1,var(--bg-0));color:var(--fg-1,var(--fg-hi));font-family:system-ui,-apple-system,sans-serif;min-height:100vh;overflow-x:hidden;max-width:100vw;padding-left:calc(var(--rail-w,56px) + var(--filter-w,0px));padding-bottom:calc(var(--statusbar-h,24px) + 60px)}
html{overflow-x:hidden}
/* ── Terminal density tokens (terminal-ui Req 1.1, 1.2) ───────────────────────
   All scan-grid density/layout is driven by these CSS variables so theming and
   density stay variable-only (no hardcoded density values, no framework/build),
   and so a viewport resize never reflows columns. Per-column widths are fixed
   px values: with table-layout:fixed the column widths are content- AND
   viewport-independent, which is what keeps monospace alignment stable on
   resize (Req 1.5) with no per-row reflow. */
:root{
  /* ── Terminal density tokens (task 9: the Token_Bridge is RETIRED) ────────────
     The legacy alias tokens (--term-*/--cb-*/--conn-*/--st-*/--row-h/…,
     --green) are gone — every consumer now references the design tokens
     from colors_and_type.css directly. What remains here is the REAL density
     system: the 4px column-width grid (--td-col-unit × --td-w-*) and the one
     documented unmapped token (--td-line-h). */

  /* ── Density / layout tokens → Design_Tokens (Req 4.8) ─────────────────── */
  /* UNMAPPED (Req 4.9 / decision D8): --td-line-h has no Design_Token equivalent.
     --lh-tight is 1.1, which would break the one-text-line-per-row invariant.
     Retained as literal 1 — the single token that cannot be re-pointed. */
  --td-line-h:1;                   /* keep each row to exactly one text line */

  /* ── Column-width helper + per-column widths → 4px design grid (Req 4.8, D7) ─
     --td-col-unit = var(--space-2) = 4px (design spacing base).
     Each --td-w-* is calc(var(--td-col-unit) * N), snapping to nearest 4px
     multiple (≤2px delta per column). */
  --td-col-unit:var(--space-2);    /* 4px base unit */
  --td-w-ticker:calc(var(--td-col-unit) * 45);    /* earnings-icon (2026-07-29): 38u→45u. The cell gained a FIFTH flex-shrink:0 child (the DATA-3 earnings icon beside XD). Measured headless, real fonts: 180px td − 16px pad = 164px content; worst admissible case ABR.PD(6ch, universe_bouncer.SYMBOL_VALID_RE) + XD + 14px icon = 159.45px → +4.55px headroom. 38u clipped it by 23.45px SILENTLY (element child ⇒ no ellipsis); 44u cleared by 0.55px and was rejected as sub-pixel */
  --td-w-price:calc(var(--td-col-unit) * 20);     /* 78→80px    (+2) */
  --td-w-change:calc(var(--td-col-unit) * 18);    /* 72→72px    (±0) */
  --td-w-trend:calc(var(--td-col-unit) * 22);     /* 88→88px    (±0) */
  --td-w-rsi:calc(var(--td-col-unit) * 24);       /* 96→96px    (±0) */
  --td-w-rsivs:calc(var(--td-col-unit) * 24);     /* 96→96px    (±0) */
  --td-w-macd:calc(var(--td-col-unit) * 18);      /* 70→72px    (+2) */
  --td-w-ma:calc(var(--td-col-unit) * 38);        /* 150→152px  (+2) */
  --td-w-vol:calc(var(--td-col-unit) * 21);       /* 84→84px    (±0) */
  --td-w-bb:calc(var(--td-col-unit) * 34);        /* Q6b option 1 (2026-07-28): 136px td − 16px pad = 120px content; OVERBOUGHT 100% = 116.00px measured, +4.00px headroom */
  --td-w-pat:calc(var(--td-col-unit) * 28);       /* 110→112px  (+2) */
  --td-w-flag:calc(var(--td-col-unit) * 38);      /* 150→152px  (+2) */
  --td-w-score:calc(var(--td-col-unit) * 24);     /* 96→96px    (±0) */
  --td-w-scoredelta:calc(var(--td-col-unit) * 20);/* 82→80px    (-2) */
  --td-w-score5d:calc(var(--td-col-unit) * 19);   /* 76→76px    (±0) */
  --td-w-streak:calc(var(--td-col-unit) * 21);    /* 84→84px    (±0) */
  --td-w-gex:calc(var(--td-col-unit) * 25);       /* 100→100px  (±0) */
  --td-w-signal:calc(var(--td-col-unit) * 42);    /* 170→168px  (-2) */
  --td-w-mcap:calc(var(--td-col-unit) * 22);      /* 86→88px    (+2) */

  /* ── Theme_Engine body-background token → Design_Token (Req 4.4) ────────── */

  /* ── Command_Bar tokens → Design_Tokens (Req 4.1, 4.5) ─────────────────── */

  /* ── Connection_State badge tokens → Design_Tokens (Req 4.8 / R8.6) ─────── */

  /* ── Staleness_State badge tokens → Design_Tokens (Req 4.8 / R8.6) ─────── */

  /* ── Accessibility tokens → Design_Tokens (Req 4.4, R15.1) ─────────────── */
}
/* ── Theme_Engine per-theme CSS-variable overrides (design-system-adoption
   task 8.1; Req 11.1, 11.3) ──────────────────────────────────────────────────
   Each shipped theme overrides the Design_Tokens (--bg-*, --border) declared in
   colors_and_type.css. The Token_Bridge in :root above maps Legacy_Tokens onto
   those Design_Tokens (--bg-1:var(--bg-1), --bg-2:var(--bg-2),
   --border:var(--border), --bg-1:var(--bg-1), etc.), so overriding the
   Design_Tokens here causes all Legacy_Token consumers to resolve the per-theme
   palette automatically — no hex touches a Legacy_Token directly (Req 11.1).
   Default theme = base :root Design_Tokens; no override block needed.
   Bull→--green and bear→--red are not remapped by any theme (Req 11.8). */
body[data-theme="midnight"]{--bg-1:#0a0e1a;--bg-2:#111827;--bg-3:#1e2a3a;--border:#2a3548}
body[data-theme="deep-ocean"]{--bg-1:#0a1628;--bg-2:#0f1d32;--bg-3:#162640;--border:#1e3454}
body[data-theme="charcoal"]{--bg-1:#1a1a1a;--bg-2:#222222;--bg-3:#2a2a2a;--border:#3a3a3a}

/* ── Command_Bar (terminal-ui task 2.5; Req 2, 3) ─────────────────────────────
   A single fixed-position input surface accepting a Ticker_Token or a
   Function_Command. Styling is CSS-variable-driven and reuses the density font
   token so it stays consistent with the terminal grid. */
.cmd-bar{position:fixed;left:calc(var(--rail-w,56px) + var(--filter-w,0px));right:0;bottom:var(--statusbar-h,24px);z-index:400;display:flex;align-items:center;gap:10px;padding:8px 16px;background:var(--bg-2);border-top:1px solid var(--border);font-family:var(--font-mono)}
.cmd-bar-prompt{color:var(--green);font-size:.82rem;font-weight:700;line-height:1;flex-shrink:0}
/* task 5.7 (design-system-adoption): migrated to .mws-input Design_Tokens —
   --radius-1 (2px) corners; green --glow-focus on focus, no glow on blur.
   #tickerSearch and #customTickerInput were removed by unified-command-bar
   tasks 4.2 and 4.1 respectively; only #cmdBarInput survives (see D9). */
.cmd-bar-input{flex:0 0 360px;max-width:42vw;background:var(--bg-1);border:1px solid var(--border);color:var(--fg-1);font-family:var(--font-mono);font-size:.78rem;letter-spacing:1px;padding:8px 12px;border-radius:var(--radius-1);outline:none;text-transform:uppercase}
.cmd-bar-input::placeholder{color:var(--fg-mute);text-transform:none;letter-spacing:1px}
.cmd-bar-input:focus{border-color:transparent;box-shadow:var(--glow-focus)}
.cmd-bar-status{font-size:.62rem;letter-spacing:1.5px;text-transform:uppercase;color:var(--fg-mute);min-height:1em}
.cmd-bar-status.error{color:var(--red)}
.cmd-bar-suggest{display:none;position:absolute;left:16px;bottom:calc(100% + 6px);margin:0;padding:4px 0;list-style:none;min-width:360px;max-width:42vw;max-height:320px;overflow-y:auto;background:var(--bg-1);border:1px solid var(--border);border-radius:var(--radius-1);box-shadow:0 -8px 30px rgba(0,0,0,.5)}
.cmd-bar-suggest.show{display:block}
.cmd-bar-suggest li{padding:7px 14px;font-family:var(--font-mono);font-size:.68rem;letter-spacing:1px;color:var(--fg-1);cursor:pointer;display:flex;align-items:center;gap:10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cmd-bar-suggest li:hover,.cmd-bar-suggest li.active{background:var(--green-bg);color:var(--green)}
.cmd-bar-suggest .cb-sym{font-weight:700;min-width:78px;flex-shrink:0}
/* Batch D — the rename-alias note ("formerly SATS"), runtime-built by
   renderSuggestions on the one row the envelope's ticker_alias names. Amber =
   the brand's "warning / stale" register: the symbol the operator typed no
   longer exists. flex-shrink:0 matters — the row is a flex container whose
   .cb-name already shrinks, so without it the note would be the thing that
   collapses instead of the company name. */
.cmd-bar-suggest .cb-alias{color:var(--amber);flex-shrink:0}
.cmd-bar-suggest .cb-name{color:var(--fg-mute);overflow:hidden;text-overflow:ellipsis}
/* Req 7.4 — empty-focused hint. Hidden by default; shown only when the bar gains
   focus while empty AND the help modal is closed. Toggled by app.js via the
   .hint-visible class on #cmdBar. Positioned just above the bar (like the suggest
   list). The kbd element inherits the mono font and gets a subtle border. */
.cmd-bar-hint{display:none;position:absolute;left:16px;bottom:calc(100% + 6px);font-family:var(--font-mono);font-size:.62rem;letter-spacing:1px;color:var(--fg-mute);background:var(--bg-1);border:1px solid var(--border);border-radius:var(--radius-1);padding:5px 10px;pointer-events:none;white-space:nowrap}
.cmd-bar.hint-visible .cmd-bar-hint{display:block}
.cmd-bar-hint kbd{font-family:inherit;font-size:inherit;color:var(--green);background:transparent;border:1px solid var(--green);border-radius:var(--radius-1);padding:0 4px;letter-spacing:inherit}
/* ── terminal-ui task 14.1 (Req 13.1, 13.5) — visible keyboard-focus indicator.
   Every focusable element renders a visible focus ring driven by the
   --green CSS variable (no hardcoded/inline color; theme-ready).
   :focus-visible covers keyboard focus on interactive controls (no ring on a
   mouse press). Surfaces that receive PROGRAMMATIC focus — the scan-grid
   Active_Row and the detail dialog — use :focus, because scripted focus() does
   not reliably trigger the :focus-visible heuristic, so the ring must show on a
   scripted focus move (Req 13.5). All indicators are outlines/box-shadows, never
   color-only, so the focus change is not signaled by color alone. */
:focus-visible{outline:2px solid var(--green);outline-offset:2px}
a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,[tabindex]:focus-visible,.chip:focus-visible,.dp-tab:focus-visible,.wl-star:focus-visible,.gear-btn:focus-visible{outline:2px solid var(--green);outline-offset:2px}
/* the scan-grid Active_Row receives programmatic focus on an Active_Row change
   (Req 13.5): a native <tr> outline paints unevenly, so draw the ring as a
   top/bottom inset rule across the focused row's cells and keep the existing
   Active_Row accent bar on the first cell. */
table.term tbody tr:focus,table.term tbody tr:focus-visible{outline:none}
table.term tbody tr:focus td{box-shadow:inset 0 2px 0 0 var(--green),inset 0 -2px 0 0 var(--green)}
table.term tbody tr:focus td:first-child{box-shadow:inset 3px 0 0 0 var(--green),inset 0 2px 0 0 var(--green),inset 0 -2px 0 0 var(--green)}
/* the detail dialog / chart dialogs receive programmatic focus on open
   (Req 13.5): show the ring on the modal card rather than the full-screen
   backdrop so the indicator frames the visible panel. */
#detail-panel:focus,#chart-modal:focus,#gex-chart-modal:focus{outline:none}
#detail-panel:focus>.detail-modal-card,#chart-modal:focus>div,#gex-chart-modal:focus>div{outline:2px solid var(--green);outline-offset:2px}
body::before{content:'';position:fixed;inset:0;background-image:linear-gradient(rgba(51,255,102,.03) 1px,transparent 1px),linear-gradient(90deg,rgba(51,255,102,.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;z-index:0}
@keyframes spin{to{transform:rotate(360deg)}}
#chart-modal.open{display:flex!important;z-index:1000!important;background:transparent!important;backdrop-filter:none!important;align-items:flex-start!important;padding:24px 0!important}
#gex-chart-modal.open{display:flex!important;z-index:1000!important;background:transparent!important;backdrop-filter:none!important;align-items:flex-start!important;padding:24px 0!important}
.sig-row.clickable{cursor:pointer;transition:background .15s}
.sig-row.clickable:hover{background:rgba(0,184,255,.07);border-radius:var(--radius-1)}
/* Req 10.4 — emoji ([bar-chart]) removed; replaced with approved unicode glyph → (U+2192, right-arrow) as drill-in affordance */
.sig-row.clickable:hover .sig-key::after{content:' →';font-size:.55rem}
@keyframes pulse{0%,100%{opacity:1;box-shadow:0 0 0 0 color-mix(in srgb,var(--green) 40%,transparent)}50%{opacity:.7;box-shadow:0 0 0 6px color-mix(in srgb,var(--green) 0%,transparent)}}
/* task 8.1 (design-system-adoption): header translucent bg driven by --bg-1 so
   per-theme overrides propagate without inline styles (Req 11.1). color-mix with
   transparent at 5% gives the 0.95 alpha equivalent of the former rgba(t.bg,.95)
   that applyTheme() previously set as an inline style. */
/* ── Workstation chrome (design ui_kits/desktop Chrome.jsx) ──────────────────
   40px TopBar (brand · market status · command hint · account), 56px icon-only
   LeftRail, 24px bottom StatusBar. All colors/sizes via Design_Tokens so the
   Theme_Engine overrides propagate. */
header{position:sticky;top:0;z-index:300;height:var(--topbar-h,40px);display:flex;align-items:stretch;background:var(--bg-1);border-bottom:1px solid var(--border);margin-left:calc(-1 * (var(--rail-w,56px) + var(--filter-w,0px)));font-family:var(--font-mono)}
.tb-seg{display:flex;align-items:center;gap:10px;padding:0 14px;border-right:1px solid var(--border);white-space:nowrap}
.tb-brand{gap:8px}
.tb-brand img{display:block}
.tb-wordmark{font-size:14px;font-weight:var(--fw-bold,700);color:var(--fg-max);letter-spacing:var(--tracking-tight)}
.tb-wordmark .tb-dot{color:var(--tiger)}
.tb-cmd{flex:1;min-width:0;border-right:0;cursor:text;color:var(--fg-mute);overflow:hidden}
.tb-cmd-prompt{color:var(--green);font-size:13px;flex-shrink:0}
.tb-cmd-hint{font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}
.tb-account{border-right:0;border-left:1px solid var(--border);gap:8px}
#mws-rail{position:fixed;left:0;top:var(--topbar-h,40px);bottom:0;width:var(--rail-w,56px);display:flex;flex-direction:column;gap:2px;padding:10px 0 6px;background:var(--bg-1);border-right:1px solid var(--border);z-index:90}
.rail-btn{background:transparent;color:var(--fg-mute);border:0;border-left:2px solid transparent;padding:10px 0;font-family:var(--font-mono);font-size:16px;line-height:1;cursor:pointer;outline:0;width:100%;display:flex;align-items:center;justify-content:center}
.rail-btn:hover{background:var(--bg-4);color:var(--fg-2)}
.rail-btn.active{background:var(--bg-3);color:var(--green);border-left-color:var(--green)}
.rail-btn:focus-visible{box-shadow:var(--glow-focus)}
.rail-spacer{margin-top:auto}
#mws-statusbar{position:fixed;left:0;right:0;bottom:0;height:var(--statusbar-h,24px);z-index:401;display:flex;align-items:center;gap:14px;padding:0 14px;background:var(--bg-0);border-top:1px solid var(--border);font-family:var(--font-mono);font-size:10px;color:var(--fg-mute);letter-spacing:var(--tracking-wide);white-space:nowrap;overflow:hidden}
#mws-statusbar .sb-right{margin-left:auto;display:flex;align-items:center;gap:14px}
#mws-statusbar .mws-kbd{font-size:9px;padding:0 4px}
/* ── scanner-workstation task 1: screen switching (Req 1.2) ───────────────────
   body[data-screen] is the ONLY switch — CSS visibility, no routing, no DOM
   moves. Attribute absent = today's default scanner view, byte-identical
   (Req 1.4). #dashboard-screen's grid template/positioning lands in task 2;
   only the visibility toggle lives here. */
#dashboard-screen{display:none}
body[data-screen="dashboard"] #dashboard-screen{display:grid}
body[data-screen="dashboard"] .container{display:none}
/* ── screener-filter-panel: collapsible left filter panel (scanner view) ──────
   One CSS var drives BOTH the panel width and the content offset (folded into
   body padding-left / header margin-left / .cmd-bar left above). Attribute
   absent = open (default, Req 3.1); collapsed → --filter-w:0 reclaims the full
   content width and re-centers .container. Zeroed on the dashboard so no phantom
   gutter is reserved (Req 4.1). Instant show/hide — terminals don't ease. */
body[data-filters="collapsed"]{--filter-w:0px}
body[data-screen="dashboard"]{--filter-w:0px}
/* Fixed panel docked against the rail, under the topbar, above the statusbar.
   NO transform (would trap the position:fixed #weightsModal); width→0 + overflow
   hidden erases the body when collapsed. It is a .container child, so the
   dashboard's `.container{display:none}` hides it for free (Req 4.1). */
#filterPanel{position:fixed;top:var(--topbar-h,40px);left:var(--rail-w,56px);bottom:var(--statusbar-h,24px);width:var(--filter-w,0px);z-index:200;border:0;border-right:1px solid var(--border);overflow:hidden}
body[data-filters="collapsed"] #filterPanel{border-right:0}
#filterPanel .mws-panel__body{overflow-y:auto;overflow-x:hidden;padding:0 12px 16px}
/* The edge handle is a SEPARATE fixed element (never clipped by the width-0
   panel). It sits at the panel's right seam when open, flush to the rail when
   collapsed. go-live-ui-polish: it is the SOLE toggle (the #rail-filters funnel
   is gone), so the chevron wears var(--green); hover is the instant bg step-up
   only — no transition, terminals don't ease. */
#filterHandle{position:fixed;top:50%;transform:translateY(-50%);left:calc(var(--rail-w,56px) + var(--filter-w,0px));width:16px;height:64px;z-index:201;display:flex;align-items:center;justify-content:center;background:var(--bg-3);border:1px solid var(--border);border-left:0;color:var(--green);font-family:var(--font-mono);font-size:11px;cursor:pointer;padding:0}
#filterHandle:hover{background:var(--bg-4)}
#filterHandle:focus-visible{box-shadow:var(--glow-focus)}
body[data-screen="dashboard"] #filterHandle{display:none}
/* ── customizable-dashboard task 3: the composed grid shell (Req 1.x, 2.x) ────
   Fixed inside the chrome — below the 40px top bar, right of the 56px rail,
   above the 24px status bar — as a two-row CSS grid: the 28px toolbar strip
   (search placeholder · add panel · {n} panels) over the scrollable Gridstack
   field. display stays owned by the task-1 toggle rules above (display:grid).
   Panel wrappers/positions belong to Gridstack; the .mws-panel inside each
   .grid-stack-item-content flexes to fill its cell — min-width/min-height:0
   so panel bodies scroll internally; border-radius 0 (seamed-grid corners
   are sharp). */
/* grid rows: toolbar (28px) · ticker-bar (auto — collapses to 0 when the bar is
   hidden and drops out of the grid) · grid-wrap (1fr). grid-wrap is pinned to the
   last row so it always owns the 1fr whether or not the ticker bar is showing. */
#dashboard-screen{position:fixed;top:var(--topbar-h,40px);left:var(--rail-w,56px);right:0;bottom:var(--statusbar-h,24px);grid-template-columns:1fr;grid-template-rows:28px auto 1fr;gap:0;background:var(--bg-1);z-index:1}
.dash-toolbar{display:flex;align-items:center;gap:8px;padding:0 8px;background:var(--bg-2);border-bottom:1px solid var(--border);font-family:var(--font-mono)}
#dash-search{padding:2px 6px;font-size:.62rem;min-width:160px}
.dash-toolbar__status{margin-left:auto;font-size:.62rem;color:var(--fg-mute);letter-spacing:1px}
/* ── dashboard-panel-enhancements task 4: picked-ticker live info bar ──────────
   Dashboard CHROME (not a Gridstack panel): symbol · price · change% · rsi(14) ·
   day range · volume for _dashState.picked. Its own auto grid row so it never
   steals the grid-wrap's 1fr; the [hidden] guard removes it from the grid before
   a pick. Muted lowercase labels, default-fg values, tabular-nums so live-patched
   digits never reflow. Tokens only — no hard-coded hex (design system). */
.dash-ticker-bar{grid-row:2;display:flex;align-items:center;gap:var(--space-5);padding:0 var(--space-4);min-height:28px;background:var(--bg-2);border-bottom:1px solid var(--border);font-family:var(--font-mono);font-variant-numeric:tabular-nums;font-size:.68rem;overflow:hidden}
.dash-ticker-bar[hidden]{display:none}
.dash-tbar-cell{display:inline-flex;align-items:baseline;gap:var(--space-2);white-space:nowrap}
.dash-tbar-label{color:var(--fg-mute);font-size:.6rem;letter-spacing:.5px;text-transform:lowercase}
.dash-tbar-val{color:var(--fg-1)}
.dash-tbar-sym .dash-tbar-val{color:var(--green);font-weight:600;letter-spacing:.5px}
.dash-grid-wrap{grid-row:3;position:relative;min-height:0;overflow-y:auto;overflow-x:hidden}
#dash-empty{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;pointer-events:none;font-family:var(--font-mono);font-size:.62rem;color:var(--fg-dim);letter-spacing:1px}
/* panel-reset session undo — the `// layout cleared` note + its undo button,
   centered under the empty-state copy (#dash-empty is pointer-events:none, so
   the clickable half cannot live inside it). Absolutely positioned against the
   same .dash-grid-wrap; [hidden] must beat display:flex, hence the explicit
   override. Flat, lowercase, no transitions (design law). */
.dash-undo{position:absolute;left:50%;top:50%;transform:translate(-50%,18px);display:flex;align-items:center;gap:8px;font-family:var(--font-mono);font-size:.62rem;color:var(--fg-dim);letter-spacing:1px}
.dash-undo[hidden]{display:none}
/* panel-reset control at rest on an empty board. #dash-reset-layout ships
   `disabled` and app.js _dashSyncToolbar disables it whenever the layout is
   empty — i.e. the instant after a reset, exactly when the user is looking at
   it. .mws-btn declares no :disabled treatment and --danger sets color and
   border-color explicitly, so the UA's own dimming never shows: without this
   the button reads full red, keeps cursor:pointer and still takes the
   :hover step-up, i.e. it looks live. Muted treatment matching
   `.dash-catalog button:disabled` below; the id outranks .mws-btn:hover and
   .mws-btn--danger:hover, so the step-up is suppressed while disabled. */
#dash-reset-layout:disabled,#dash-reset-layout:disabled:hover{color:var(--fg-mute);border-color:var(--border);background:transparent;cursor:default}
#dash-grid .grid-stack-item-content{display:flex;overflow:hidden}
#dash-grid .mws-panel{flex:1 1 auto;min-width:0;min-height:0;border-radius:0}
/* the runtime add-panel catalog popover (app.js _dashToggleCatalog) — flat
   bordered menu, no shadow beyond the design system's dropdown allowance. */
.dash-catalog{position:absolute;z-index:10;background:var(--bg-2);border:1px solid var(--border);font-family:var(--font-mono);font-size:.62rem}
.dash-catalog button{display:block;width:100%;text-align:left;padding:4px 10px}
.dash-catalog button:disabled{color:var(--fg-mute);cursor:default}
/* ── customizable-dashboard task 12: the global ticker-search dropdown ────────
   Runtime-built by app.js (_dashSuggestEl/_dashSearchRender) under the
   toolbar input — the .dash-catalog popover conventions: flat 1px border, no
   shadow, hover/highlight is the instant --bg-4 step-up (no transitions). */
.dash-suggest{position:absolute;z-index:10;min-width:220px;max-width:340px;background:var(--bg-2);border:1px solid var(--border);font-family:var(--font-mono);font-size:.62rem}
.dash-suggest__item{display:flex;gap:8px;align-items:baseline;padding:3px 10px;cursor:pointer}
.dash-suggest__item:hover,.dash-suggest__item.is-active{background:var(--bg-4)}
.dash-suggest__sym{color:var(--green)}
/* Batch D — the dash surface's mirror of .cb-alias (same grammar, built by the
   same _aliasNote helper). Same amber register, same flex-shrink:0 reason: the
   sibling .dash-suggest__name owns the ellipsis. */
.dash-suggest__alias{color:var(--amber);flex-shrink:0}
.dash-suggest__name{color:var(--fg-mute);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dash-suggest__note{padding:4px 10px;color:var(--fg-dim);letter-spacing:1px}
/* picked-row highlight (Req 3.1) — the prototype's rgba(51,255,102,0.04) as
   4% --green via color-mix (same token form as the pulse keyframe) so theme
   overrides propagate. */
.dash-row--picked{background:color-mix(in srgb,var(--green) 4%,transparent)}
/* placeholder line inside the panel bodies — REUSED by the task-3 registry's
   placeholder mounts; the panel-module tasks (4-11) replace their bodies. */
.dash-placeholder{font-family:var(--font-mono);font-size:.62rem;color:var(--fg-mute);letter-spacing:1px;padding:14px}
/* ── scanner-workstation task 3: compact scanner-panel rows (Req 5.1) ─────────
   Prototype DataPanels.jsx ScannerTable translated to the production columns
   (sig/symbol/last/chg%/rsi/ms): 10px uppercase sticky header + 12px mono
   rows, tabular numerals, 1px row seams. Hover is the instant --bg-4 step-up
   the .mws-table rows use — no transitions (design rules). The panel body
   (.mws-panel__body) already scrolls; the sticky header pins inside it. */
.dash-scan-hd,.dash-scan-row{display:grid;grid-template-columns:92px minmax(0,1fr) 76px 72px 56px 48px;gap:0;align-items:center;font-family:var(--font-mono);font-variant-numeric:tabular-nums}
.dash-scan-hd{position:sticky;top:0;z-index:1;background:var(--bg-2);border-bottom:1px solid var(--border);font-size:10px;letter-spacing:.06em;text-transform:uppercase;color:var(--fg-mute)}
.dash-scan-hd>span{padding:5px 8px}
.dash-scan-row{border-bottom:1px solid var(--border-dim);font-size:12px;color:var(--fg-1);cursor:pointer}
.dash-scan-row:hover{background:var(--bg-4)}
.dash-scan-cell{padding:4px 8px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.dash-scan-cell--sym{color:var(--fg-hi);font-weight:600}
.dash-scan-hd>.num,.dash-scan-row>.num{text-align:right}
/* ── customizable-dashboard task 4: chart panel canvas sizing (Req 6.4) ───────
   The chart module sizes each instance's canvas to its panel body's
   clientWidth/Height, so the body must clip (not scroll — the compound
   selector outranks .mws-panel__body's overflow:auto regardless of cascade
   order) and the canvas must be a block — an inline canvas leaves a baseline
   gap below itself, which would overflow the exact fit into a phantom
   scrollbar. Class selectors, not ids: N instances (Req 6.1). Display
   toggling stays inline (canvas and degraded line ship hidden; the render
   shows at most one, Req 6.3): clearing the inline 'none' falls back to
   these rules — which is why .dash-chart-degraded carries no display of its
   own. The active D/W/M tab is the stock .mws-btn--armed variant toggled at
   runtime — no new class. */
.mws-panel__body.dash-chart-body{overflow:hidden}
.dash-chart-canvas{display:block;width:100%;background:var(--bg-0)}
.dash-chart-degraded{text-align:center;padding:20px;font-family:var(--font-mono);font-size:.62rem;color:var(--fg-dim);letter-spacing:1px}
/* ── scanner-workstation task 6: compact watchlist-panel rows (Req 6.3) ───────
   Prototype DataPanels.jsx Watchlist translated to the production columns
   (marker/sym/spark/last/chg%) — the .dash-scan-hd/.dash-scan-row conventions
   with the watchlist's own column grid: 20px marker, fluid symbol, 64px
   sparkline slot (56px SVG + 4px cell padding each side, so the fixed-size
   polyline never shrinks or clips), right-aligned numeric cells. Same 10px
   uppercase sticky header, 12px mono rows, tabular numerals, 1px row seams,
   instant --bg-4 hover (no transitions — design rules). */
.dash-wl-hd,.dash-wl-row{display:grid;grid-template-columns:20px minmax(0,1fr) 64px 76px 64px;gap:0;align-items:center;font-family:var(--font-mono);font-variant-numeric:tabular-nums}
.dash-wl-hd{position:sticky;top:0;z-index:1;background:var(--bg-2);border-bottom:1px solid var(--border);font-size:10px;letter-spacing:.06em;text-transform:uppercase;color:var(--fg-mute)}
.dash-wl-hd>span{padding:5px 8px}
.dash-wl-row{border-bottom:1px solid var(--border-dim);font-size:12px;color:var(--fg-1);cursor:pointer}
.dash-wl-row:hover{background:var(--bg-4)}
.dash-wl-cell{padding:4px 8px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.dash-wl-cell--sym{color:var(--fg-hi);font-weight:600}
.dash-wl-cell--marker{color:var(--fg-dim);font-size:11px;padding:4px 0 4px 8px}
.dash-wl-cell--spark{padding:4px;color:var(--fg-dim)}
.dash-wl-hd>.num,.dash-wl-row>.num{text-align:right}
/* task 5.4 — .live-badge text and .live-dot (stream-status dot) use Design_Token --green (Req 4.5) */
.live-badge{display:flex;align-items:center;gap:8px;font-family:var(--font-mono);font-size:.65rem;color:var(--green);letter-spacing:2px}
/* .live-dot is the stream-status dot: maps to .mws-dot--bull (live/glow) via the mws-dot component.
   color + glow from Design_Token --green; animation kept as live affordance. No second green. */
.live-dot{width:8px;height:8px;background:var(--green);border-radius:50%;animation:pulse 1.5s infinite}
.container{max-width:1500px;margin:0 auto;padding:0 20px;position:relative;z-index:1}
.controls{padding:20px 0 14px;display:flex;flex-wrap:wrap;gap:10px;align-items:flex-end}
.ctrl-group{display:flex;flex-direction:column;gap:5px}
.ctrl-label{font-family:var(--font-mono);font-size:.56rem;letter-spacing:2px;color:var(--fg-mute);text-transform:lowercase}
select,input[type=number]{background:var(--bg-3);border:1px solid var(--border);color:var(--fg-hi);font-family:var(--font-mono);font-size:.78rem;padding:9px 12px;border-radius:var(--radius-1);outline:none;cursor:pointer;min-width:120px;-webkit-appearance:none}
select:focus,input:focus{border-color:var(--green,#33ff66)}
.btn{font-family:var(--font-mono);font-size:.72rem;letter-spacing:2px;text-transform:lowercase;padding:9px 20px;border-radius:var(--radius-1,2px);cursor:pointer;border:none}
.btn-primary{background:var(--green,#33ff66);color:#0a0a0a;font-weight:700}
.btn-primary:hover{background:var(--green,#33ff66)}
.btn-primary:disabled{background:var(--border);color:var(--fg-mute);cursor:not-allowed}
.btn-secondary{background:transparent;color:var(--fg-1,#d4d4d4);border:1px solid var(--border,var(--border-hot))!important}
.btn-secondary:hover{background:var(--bg-4,#1e1e1e)}
.chips{display:flex;flex-wrap:wrap;gap:8px;padding-bottom:14px;align-items:center}
.gear-btn{background:none;border:1px solid var(--border,var(--border));border-radius:var(--radius-1,2px);color:var(--fg-mute,var(--fg-mute));cursor:pointer;font-family:var(--font-mono);letter-spacing:1px;margin-left:auto}
.gear-btn:hover{border-color:var(--border-hot,#58a6ff);color:var(--fg-1,#d4d4d4)}
.wl-star{cursor:pointer;font-size:.75rem;color:var(--border);transition:all .15s;line-height:1;user-select:none;flex-shrink:0}
.wl-star:hover{color:var(--amber);transform:scale(1.2)}
.wl-star.active{color:var(--amber)}
.wl-star-lg{font-size:1.3rem}
.wl-popup{position:absolute;background:var(--bg-2);border:1px solid var(--border-hot);border-radius:var(--radius-1);padding:8px 0;z-index:600;min-width:180px;box-shadow:0 8px 30px rgba(0,0,0,.5);font-family:var(--font-mono)}
.wl-popup-item{padding:6px 14px;font-size:.6rem;color:var(--fg-hi);letter-spacing:1px;cursor:pointer;display:flex;align-items:center;gap:8px;transition:background .1s}
.wl-popup-item:hover{background:rgba(255,255,255,.05)}
.wl-popup-item .wl-check{width:14px;color:var(--green,#33ff66);font-size:.7rem}
.wl-popup-item .wl-check.empty{color:transparent}
.wl-popup-divider{height:1px;background:var(--border);margin:4px 0}
.wl-popup-title{padding:4px 14px;font-size:.48rem;color:var(--fg-mute);letter-spacing:2px;text-transform:uppercase}
#weightsModal{display:none;position:fixed;inset:0;z-index:500;align-items:center;justify-content:center;background:rgba(0,0,0,.7)}
#weightsModal.open{display:flex}
#weightsModal .wm-card{background:var(--bg-2);border:1px solid var(--border);border-radius:var(--radius-2);padding:24px 28px;width:580px;max-width:95vw;max-height:88vh;overflow-y:auto;font-family:var(--font-mono)}
#weightsModal .wm-title{font-family:var(--font-mono);font-size:.65rem;letter-spacing:2px;color:var(--fg-hi);margin-bottom:4px}
#weightsModal .wm-sub{font-family:var(--font-mono);font-size:.55rem;letter-spacing:1px;color:var(--fg-mute);margin-bottom:20px}
#weightsModal .wm-section{margin-bottom:18px}
#weightsModal .wm-section-title{font-family:var(--font-mono);font-size:.55rem;letter-spacing:2px;color:var(--fg-mute);margin-bottom:10px;padding-bottom:5px;border-bottom:1px solid var(--border)}
#weightsModal .wm-row{display:flex;align-items:center;gap:10px;margin-bottom:8px}
#weightsModal .wm-label{font-family:var(--font-mono);font-size:.6rem;color:var(--fg-2);width:160px;flex-shrink:0}
#weightsModal .wm-slider{flex:1;accent-color:var(--cyan);cursor:pointer}
#weightsModal .wm-num{width:52px;background:var(--bg-3);border:1px solid var(--border);color:var(--fg-hi);font-family:var(--font-mono);font-size:.7rem;padding:4px 6px;border-radius:var(--radius-1);outline:none;text-align:center}
#weightsModal .wm-num:focus{border-color:var(--cyan)}
#weightsModal .wm-actions{display:flex;gap:10px;margin-top:20px;padding-top:16px;border-top:1px solid var(--border)}
#weightsModal .wm-btn{font-family:var(--font-mono);font-size:.6rem;letter-spacing:1px;padding:8px 16px;border-radius:var(--radius-1,2px);cursor:pointer;border:1px solid}
#weightsModal .wm-btn-apply{background:var(--green-bg,rgba(51,255,102,.1));border-color:var(--green,#33ff66);color:var(--green,#33ff66)}
#weightsModal .wm-btn-reset{background:none;border-color:var(--border,var(--border));color:var(--fg-mute,var(--fg-mute))}
#weightsModal .wm-btn-reset:hover{border-color:var(--fg-1,#d4d4d4);color:var(--fg-1,#d4d4d4)}
#weightsModal .wm-close{background:none;border:1px solid var(--border,var(--border));color:var(--fg-mute,var(--fg-mute));font-size:.8rem;font-family:var(--font-mono);cursor:pointer;margin-left:auto;padding:4px 7px;border-radius:var(--radius-1,2px)}
.chip{font-family:var(--font-mono);font-size:.62rem;letter-spacing:1px;padding:6px 14px;border-radius:var(--radius-1);border:1px solid var(--border);background:var(--bg-3);color:var(--fg-mute);cursor:pointer;user-select:none}
.chip:hover,.chip.active{border-color:var(--green,#33ff66);background:var(--green-bg,rgba(51,255,102,.1));color:var(--green,#33ff66)}
.stats-bar{display:flex;flex-wrap:wrap;gap:24px;padding:12px 18px;background:var(--bg-2);border:1px solid var(--border);border-radius:var(--radius-1);margin-bottom:14px}
.stat-item{display:flex;flex-direction:column;gap:2px}
.stat-val{font-family:var(--font-mono);font-size:1.3rem;letter-spacing:2px;line-height:1}
.stat-lbl{font-family:var(--font-mono);font-size:.54rem;letter-spacing:2px;color:var(--fg-mute);text-transform:uppercase}
.error-box{background:rgba(255,69,96,.1);border:1px solid var(--red);border-radius:var(--radius-1);padding:12px 16px;margin-bottom:14px;font-family:var(--font-mono);font-size:.72rem;color:var(--red);display:none}
.error-box.show{display:block}
/* PR 6.5 — Data freshness badge. Hidden by default; JS toggles .show + state class. */
.data-stale-badge{display:none;align-items:center;gap:8px;padding:6px 12px;margin-bottom:10px;border-radius:var(--radius-1);font-family:var(--font-mono);font-size:.66rem;letter-spacing:1.5px;text-transform:uppercase;border:1px solid;width:fit-content}
.data-stale-badge.show{display:inline-flex}
.data-stale-badge::before{content:'';display:inline-block;width:8px;height:8px;border-radius:50%}
/* design-system-adoption task 5.5 (Req 8.6, 8.7 / decision D5): legacy .live/.stale/.down
   classes tokenized — hardcoded hex removed. .live and .stale are ACTIVE (JS applies them);
   .down is LEGACY/DEAD (JS only removes it, never adds it) but no hardcoded hex may remain
   on a Migrated_Surface.
   .live  → --green  (= --green).  Active: Live state.
   .stale → --red (= --red, D5 intentional amber→red recolor). Active: Stale state.
   .down  → --red (= --red semantics, "data down"). Legacy dead class. */
.data-stale-badge.live{color:var(--green);border-color:color-mix(in srgb,var(--green) 40%,transparent);background:color-mix(in srgb,var(--green) 6%,transparent)}
.data-stale-badge.live::before{background:var(--green);box-shadow:0 0 6px var(--green)}
.data-stale-badge.stale{color:var(--red);border-color:color-mix(in srgb,var(--red) 40%,transparent);background:color-mix(in srgb,var(--red) 6%,transparent)}
.data-stale-badge.stale::before{background:var(--red)}
.data-stale-badge.down{color:var(--red);border-color:color-mix(in srgb,var(--red) 40%,transparent);background:color-mix(in srgb,var(--red) 8%,transparent)}
.data-stale-badge.down::before{background:var(--red);box-shadow:0 0 6px var(--red)}
/* ── terminal-ui task 9.4 (Req 11.4, 11.5, 11.6) — four-state Staleness_State.
   Extends the existing badge with the Delayed + Market_Closed states so it is
   driven by the `stalenessState` pure helper (Live/Delayed/Stale/Market_Closed),
   colored via the --st-* CSS variables only. Delayed surfaces the Polygon 15-min
   upstream delay explicitly (Req 11.5). */
.data-stale-badge.delayed{color:var(--amber);border-color:color-mix(in srgb,var(--amber) 40%,transparent);background:color-mix(in srgb,var(--amber) 6%,transparent)}
.data-stale-badge.delayed::before{background:var(--amber)}
.data-stale-badge.market-closed{color:var(--fg-mute);border-color:color-mix(in srgb,var(--fg-mute) 40%,transparent);background:color-mix(in srgb,var(--fg-mute) 6%,transparent)}
.data-stale-badge.market-closed::before{background:var(--fg-mute)}
/* ── terminal-ui task 9.4 (Req 11.1, 11.2) — always-visible Connection_State
   badge. Distinct from the Staleness_State badge (Req 11.4); colored via the
   --conn-* CSS variables only. Three states: Connected / Reconnecting /
   Disconnected. The `ws-not-live` body class de-emphasizes the live indicator so
   last-received values are not presented as currently live while the link is not
   open (Req 11.2) — an O(1) class toggle, never a grid re-render. */
.conn-badge{display:inline-flex;align-items:center;gap:8px;font-family:var(--font-mono);font-size:.62rem;letter-spacing:2px;text-transform:uppercase;padding:4px 10px;border:1px solid;border-radius:var(--radius-1);white-space:nowrap}
.conn-badge::before{content:'';display:inline-block;width:8px;height:8px;border-radius:50%}
.conn-badge.connected{color:var(--green);border-color:color-mix(in srgb,var(--green) 40%,transparent);background:color-mix(in srgb,var(--green) 6%,transparent)}
.conn-badge.connected::before{background:var(--green);box-shadow:0 0 6px var(--green)}
.conn-badge.reconnecting{color:var(--amber);border-color:color-mix(in srgb,var(--amber) 40%,transparent);background:color-mix(in srgb,var(--amber) 6%,transparent)}
.conn-badge.reconnecting::before{background:var(--amber);animation:pulse 1.5s infinite}
.conn-badge.disconnected{color:var(--red);border-color:color-mix(in srgb,var(--red) 40%,transparent);background:color-mix(in srgb,var(--red) 8%,transparent)}
.conn-badge.disconnected::before{background:var(--red);box-shadow:0 0 6px var(--red)}
/* task 5.4 — idle/not-live state: muted + no glow + no animation (→ .mws-dot--idle semantics).
   --fg-mute resolves to --fg-mute via Token_Bridge — already correct for --idle.
   Bear/warn have no stream-status source on this dot (those semantics live on the staleness badge → task 5.5). */
body.ws-not-live .live-dot,body.ws-not-live .mws-dot--bull{background:var(--fg-mute);animation:none;box-shadow:none}
body.ws-not-live #updated-label{color:var(--fg-mute)}
/* Spec 4 — /api/screen result states. Hidden by default; app.js toggles .show. */
.screen-empty{display:none;padding:14px 16px;margin-bottom:14px;border:1px solid rgba(110,118,129,.4);border-radius:var(--radius-1);background:rgba(110,118,129,.06);font-family:var(--font-mono);font-size:.72rem;letter-spacing:.5px;color:var(--fg-mute);text-align:center}
.screen-empty.show{display:block}
.screen-error{display:none;padding:12px 16px;margin-bottom:14px;border:1px solid var(--red);border-radius:var(--radius-1);background:rgba(255,69,96,.1);font-family:var(--font-mono);font-size:.72rem;color:var(--red)}
.screen-error.show{display:block}
.screen-degraded{display:none;align-items:center;gap:8px;padding:6px 12px;margin-bottom:10px;border-radius:var(--radius-1);border:1px solid rgba(210,153,34,.4);background:rgba(210,153,34,.06);font-family:var(--font-mono);font-size:.66rem;letter-spacing:1.5px;text-transform:uppercase;color:var(--amber);width:fit-content}
.screen-degraded.show{display:inline-flex}
.screen-pageonly-note{display:none;padding:6px 12px;margin-bottom:10px;border-radius:var(--radius-1);border:1px solid rgba(110,118,129,.35);background:rgba(110,118,129,.05);font-family:var(--font-mono);font-size:.62rem;letter-spacing:1px;color:var(--fg-mute)}
.screen-pageonly-note.show{display:block}
/* ── terminal-ui task 13.1 (Req 15.6) — "filtering unavailable" surface. Shown
   when /api/screen is unavailable: filtering is disabled and the outage is
   surfaced explicitly with NO client-side fallback (Req 15.5, 15.6). Static
   text (no server strings interpolated). Mirrors the .screen-error styling. */
.screen-filter-unavailable{display:none;padding:12px 16px;margin-bottom:14px;border:1px solid var(--red);border-radius:var(--radius-1);background:rgba(255,69,96,.1);font-family:var(--font-mono);font-size:.72rem;color:var(--red)}
.screen-filter-unavailable.show{display:block}
/* While filtering is disabled the results-filter controls are visually and
   interactively suppressed so the user cannot issue a filter the server cannot
   resolve — never a client-side fallback (Req 15.6). The CLEAR affordance stays
   usable so the user can return to the unfiltered Paginated_Mode grid. */
.results-filter-bar.filtering-disabled{opacity:.5}
.results-filter-bar.filtering-disabled input,.results-filter-bar.filtering-disabled select,.results-filter-bar.filtering-disabled .gex-filter-chip{pointer-events:none}
.results-filter-bar.filtering-disabled .rf-clear{pointer-events:auto;opacity:1}
.table-wrap{background:var(--bg-2);border:1px solid var(--border);border-radius:var(--radius-1);overflow-x:auto;overflow-y:auto;max-height:calc(100vh - 260px);margin-bottom:40px;position:relative}
table{width:100%;border-collapse:collapse;font-size:.8rem}
thead{background:var(--bg-3);border-bottom:1px solid var(--border)}
.col-picker-wrap{position:relative;margin-left:auto}
table.hide-rsiD      .col-rsiD      { display:none }
table.hide-rsiW      .col-rsiW      { display:none }
table.hide-rsiM      .col-rsiM      { display:none }
table.hide-rsiVsSmaD .col-rsiVsSmaD { display:none }
table.hide-rsiVsSmaW .col-rsiVsSmaW { display:none }
table.hide-rsiVsSmaM .col-rsiVsSmaM { display:none }
table.hide-ib   .col-ib   { display:none }
table.hide-ttm  .col-ttm  { display:none }
table.hide-vcp  .col-vcp  { display:none }
table.hide-flag .col-flag { display:none }
table.hide-gap  .col-gap  { display:none }
table.hide-rsiDiv .col-rsiDiv { display:none }
table.hide-ma   .col-ma   { display:none }
.col-picker-btn{font-family:var(--font-mono);letter-spacing:1px;color:var(--fg-mute,var(--fg-mute));border:1px solid var(--border,var(--border));border-radius:var(--radius-1,2px);cursor:pointer;white-space:nowrap}
.col-picker-btn:hover{border-color:var(--border-hot,#58a6ff);color:var(--fg-1,#d4d4d4)}
.col-picker-dropdown{display:none;position:absolute;right:0;top:calc(100% + 4px);background:var(--bg-3);border:1px solid var(--border);border-radius:var(--radius-1);padding:10px 14px;z-index:200;min-width:180px;box-shadow:0 8px 24px rgba(0,0,0,.6)}
.col-picker-dropdown.open{display:block}
.col-picker-item{display:flex;align-items:center;gap:8px;padding:5px 0;cursor:pointer;user-select:none}
.col-picker-item span{font-family:var(--font-mono);font-size:.62rem;letter-spacing:1px;color:var(--fg-2)}
.col-picker-item:hover span{color:var(--fg-hi)}
th{font-family:var(--font-mono);font-size:.6rem;letter-spacing:2px;text-transform:uppercase;color:var(--fg-mute);padding:12px 14px;text-align:center;white-space:nowrap;cursor:pointer;user-select:none;position:sticky;top:0;z-index:10;background:var(--bg-2);border-bottom:1px solid var(--border)}
th:first-child{position:sticky;left:0;z-index:20}
td:first-child{position:sticky;left:0;z-index:5;background:var(--bg-2)}
th:hover,th.sorted{color:var(--green,#33ff66)}
/* Terminal_UI Req 14.2 — a window-only sorted header carries a small typographic
   "⟨loaded⟩" marker (theme-agnostic; no color) so a loaded-window-only ordering
   reads distinctly from a universe-wide sort. The prominent, clear marking is
   #sortWindowOnlyNote; this is the per-column hint. */
table.term th.sorted-window-only{font-style:italic}
table.term th.sorted-window-only::after{content:' ⟨loaded⟩';font-size:.5rem;letter-spacing:.5px;opacity:.7;font-style:normal}
tbody tr{border-bottom:1px solid var(--border);cursor:pointer}
tbody tr:hover{background:rgba(255,255,255,.03)}
tbody tr:hover td:first-child{background:#12161c}
/* ── .mws-table treatment for table.term (design-system-adoption task 5.2) ──
   Req 7.1–7.8: collapsed border, mono, tabular-nums, sticky uppercase th,
   instant row hover (transition-duration:0, no easing), Design_Token bg step-up.
   Overrides are scoped to table.term so the general tbody/th selectors above
   remain for any other tables; specificity wins via `table.term` prefix. */
table.term{border-collapse:collapse;font-variant-numeric:tabular-nums}
/* Sticky header pinned to the top of the .table-wrap scroll container (Req 7.1).
   The existing `th { position:sticky; top:0 }` rule already supplies stickiness;
   these overrides add the .mws-table bg, uppercase, and tabular-nums treatment. */
table.term th{text-transform:uppercase;background:var(--bg-2);font-variant-numeric:tabular-nums}
/* Instant row hover — no easing, no transition (Req 7.4, 7.7).
   Overrides `tbody tr { transition:background .15s }` for the scan grid only. */
table.term tbody tr{transition:none}
table.term tbody tr:hover{background:var(--bg-4)}
table.term tbody tr:hover td:first-child{background:var(--bg-4)}
td{padding:12px 14px;font-family:var(--font-mono);font-size:.76rem;white-space:nowrap;vertical-align:middle}
.table-footer{display:flex;justify-content:space-between;padding:10px 16px;border-top:1px solid var(--border);font-family:var(--font-mono);font-size:.62rem;color:var(--fg-mute)}
/* ── Terminal density mode (terminal-ui Req 1.1, 1.2, 1.4, 1.5, 9.5, 9.6) ─────
   Applied to the single existing renderTable scan grid (`<table class="term">`)
   — there is no parallel grid path. `table-layout:fixed` plus the fixed
   per-column widths above make column geometry content- and viewport-
   independent, so resizing the viewport never reflows columns; the virtualizer
   keeps re-render cost O(visible rows). */
table.term{table-layout:fixed}
/* one text line per data row: fixed height, no wrap, truncate overflow with an
   explicit ellipsis indication (no wrapping, no reflow) */
table.term tbody tr{height:var(--row-h)}
table.term td,
table.term th{
  padding:var(--space-3) var(--space-4);
  font-family:var(--font-mono);
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}
table.term td{font-size:var(--fs-sm);line-height:var(--td-line-h)}
table.term th{font-size:var(--fs-xs)}
/* ── Scan-cell fit (batch B #16) ──────────────────────────────────────────────
   MECHANISM. The --td-w-* tokens above are the ONE source of scan-grid column
   geometry, and under table-layout:fixed a column cannot grow to its content.
   A cell's usable box is therefore width − 2×var(--space-4) of padding (e.g.
   SIGNAL 168px → 152px, TREND 88px → 72px). Cell content that asserts its OWN
   pixel width wider than that box is silently HARD-clipped by the
   overflow:hidden above, and the text-overflow:ellipsis beside it cannot
   signal the loss: ellipsis applies only to inline text overflowing its block
   box, never to an element child — and these cells contain elements (an <svg>
   sparkline, an inline-flex .sig pill), not text. Cause fix: content sizes
   FROM the column instead of duplicating a magic number that drifts from it.
   (The sparkline's half is in sparklineSVG — viewBox + max-width.) */
table.term .col-signal>.sig{width:100%}
/* The detail panel is not column-constrained — keep the established fixed pill
   width there so the confidence bar keeps its scale (rendering unchanged). */
.sig-row>.sig{width:170px}
/* no blank separator rows between data rows (Req 1.1): the virtualizer's
   aria-hidden spacer rows carry no border/background so they are invisible */
table.term tbody tr[aria-hidden="true"]{border:0;background:transparent}
/* Active_Row indicator (terminal-ui task 3.3; Req 4.3): marks the single
   scan-grid row holding keyboard focus. Styled exclusively through existing
   theme tokens (no hardcoded color) so it stays theme-ready — a left accent bar
   plus a subtle row tint mark exactly one row using only background/box-shadow,
   never changing row height or column layout (no reflow, O(visible rows)). */
table.term tbody tr.active-row td{background:var(--green-bg)}
table.term tbody tr.active-row td:first-child{background:var(--green-bg);box-shadow:inset 3px 0 0 0 var(--green)}
/* collapse the ticker cell's secondary company-name line so the row is one
   text line (the name remains available in the detail panel) */
table.term td:first-child>div:last-child{display:none}
/* collapse the stacked multi-timeframe MA cell onto a single inline line */
table.term .col-ma>div{flex-direction:row;flex-wrap:nowrap;gap:6px;overflow:hidden}
table.term .col-ma>div>div{flex-wrap:nowrap}
/* numeric columns right-aligned (Req 1.1) */
table.term .col-price,
table.term .col-change,
table.term .col-rsiVsSmaD,
table.term .col-rsiVsSmaW,
table.term .col-rsiVsSmaM,
table.term .col-macd,
table.term .col-score,
table.term .col-score-delta,
table.term .col-score5d,
table.term .col-score-streak,
table.term .col-mcap,
table.term th[data-col="price"],
table.term th[data-col="change"],
table.term th[data-col="rsiVsSmaD"],
table.term th[data-col="rsiVsSmaW"],
table.term th[data-col="rsiVsSmaM"],
table.term th[data-col="macd"],
table.term th[data-col="mowgliScore"],
table.term th[data-col="scoreDelta"],
table.term th[data-col="score5d"],
table.term th[data-col="scoreStreak"],
table.term th[data-col="mktCap"]{text-align:right}
/* fixed per-column widths — under table-layout:fixed the column widths are read
   from the header row, so widths live on the th (Req 1.1). Hidden columns
   (col-picker) collapse cleanly because the hide rules target both th and td. */
table.term th[data-col="ticker"]{width:var(--td-w-ticker)}
table.term th[data-col="price"]{width:var(--td-w-price)}
table.term th[data-col="change"]{width:var(--td-w-change)}
table.term th.col-trend{width:var(--td-w-trend)}
table.term th.col-rsiD,
table.term th.col-rsiW,
table.term th.col-rsiM{width:var(--td-w-rsi)}
table.term th.col-rsiVsSmaD,
table.term th.col-rsiVsSmaW,
table.term th.col-rsiVsSmaM{width:var(--td-w-rsivs)}
table.term th[data-col="macd"]{width:var(--td-w-macd)}
table.term th.col-ma{width:var(--td-w-ma)}
table.term th[data-col="volRatio"]{width:var(--td-w-vol)}
table.term th.col-bb{width:var(--td-w-bb)}
table.term th.col-ib,
table.term th.col-ttm,
table.term th.col-vcp,
table.term th.col-gap,
table.term th.col-rsiDiv{width:var(--td-w-pat)}
table.term th.col-flag{width:var(--td-w-flag)}
table.term th[data-col="mowgliScore"]{width:var(--td-w-score)}
table.term th[data-col="scoreDelta"]{width:var(--td-w-scoredelta)}
table.term th[data-col="score5d"]{width:var(--td-w-score5d)}
table.term th[data-col="scoreStreak"]{width:var(--td-w-streak)}
table.term th[data-col="gexZone"]{width:var(--td-w-gex)}
table.term th[data-col="signal"]{width:var(--td-w-signal)}
table.term th[data-col="mktCap"]{width:var(--td-w-mcap)}
.rsi-wrap{display:flex;align-items:center;gap:8px}
.rsi-bg{width:60px;height:4px;background:var(--border);border-radius:2px;overflow:hidden}
.rsi-fill{height:100%;border-radius:2px}
.rsi-sublabel{font-size:.54rem;color:var(--fg-mute);letter-spacing:1px;margin-top:2px;font-family:var(--font-mono)}
.sig{display:inline-block;padding:3px 10px;border-radius:var(--radius-1);font-size:.62rem;letter-spacing:1.5px;text-transform:uppercase;font-weight:700;font-family:var(--font-mono)}
.vol-wrap{display:flex;align-items:center;gap:6px}
.vol-bg{width:50px;height:3px;background:var(--border);border-radius:2px}
.vol-fill{height:100%;background:var(--cyan);border-radius:2px}
#loading{display:none;position:fixed;inset:0;background:rgba(8,12,16,.92);z-index:999;flex-direction:column;align-items:center;justify-content:center;gap:16px}
#loading.show{display:flex}
.spinner{width:40px;height:40px;border:2px solid var(--border);border-top-color:var(--green,#33ff66);border-radius:50%;animation:spin .8s linear infinite}
.load-text{font-family:var(--font-mono);font-size:.75rem;letter-spacing:3px;color:var(--green,#33ff66);text-align:center}
.progress-wrap{width:260px;height:4px;background:var(--border);border-radius:2px}
.progress-fill{height:100%;background:var(--green,#33ff66);border-radius:2px;transition:width .3s}
#detail-panel{display:none;position:fixed;inset:0;z-index:500;align-items:flex-start;justify-content:center;background:rgba(0,0,0,.6);padding:24px 0;overflow-y:auto}
#detail-panel.open{display:flex}
.detail-modal-card{background:var(--bg-2);border:1px solid var(--border);border-radius:var(--radius-2);width:1100px;max-width:97%;box-shadow:0 24px 80px rgba(0,0,0,.6);padding:28px 32px 120px;position:relative}
#dp-chart-view > div{width:100%!important;max-width:100%!important;border:none!important;border-radius:0!important;padding-left:0!important;padding-right:0!important;background:transparent!important;box-sizing:border-box!important}
#chart-modal.open > div,#gex-chart-modal.open > div{border-radius:var(--radius-2) !important}
.detail-close{background:none;border:1px solid var(--border,var(--border));color:var(--fg-mute,var(--fg-mute));width:30px;height:30px;border-radius:var(--radius-1,2px);cursor:pointer;font-size:1rem;display:flex;align-items:center;justify-content:center}
.detail-close:hover{border-color:var(--red,#ff2e63);color:var(--red,#ff2e63)}
/* Ticker hero (design ui_kits/desktop Screens.jsx TickerScreen): big mono
   numerals, symbol in max-white, tight tracking — not the legacy display font. */
.detail-ticker{font-family:var(--font-mono);font-size:var(--fs-2xl,28px);font-weight:var(--fw-bold,700);letter-spacing:var(--tracking-tight);color:var(--fg-max)}
.detail-name{font-size:var(--fs-sm,12px);color:var(--fg-mute);margin:4px 0 14px}
.detail-price{font-family:var(--font-mono);font-size:var(--fs-3xl,40px);font-weight:var(--fw-medium,500);line-height:1;letter-spacing:var(--tracking-tight)}
.detail-source{font-size:var(--fs-xs,11px);color:var(--fg-mute);font-family:var(--font-mono);letter-spacing:1px;margin-bottom:12px}
.ind-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin:14px 0}
.ind-card{background:var(--bg-3);border:1px solid var(--border);border-radius:var(--radius-1);padding:10px}
.ind-divider{grid-column:1/-1;border:none;border-top:1px solid var(--border);margin:6px 0}
.ind-lbl{font-family:var(--font-mono);font-size:.54rem;letter-spacing:2px;color:var(--fg-mute);margin-bottom:4px;text-transform:uppercase}
.ind-val{font-family:var(--font-mono);font-size:1.1rem;letter-spacing:1px}
.sig-section{background:var(--bg-3);border:1px solid var(--border);border-radius:var(--radius-1);padding:14px}
.sig-grid{display:grid;grid-template-columns:1fr 1fr;gap:0 16px}
.sig-title{font-family:var(--font-mono);font-size:.56rem;letter-spacing:2px;color:var(--fg-mute);margin-bottom:10px;text-transform:uppercase}
.sig-row{display:flex;justify-content:space-between;align-items:center;padding:5px 8px;border-bottom:1px solid var(--border);font-family:var(--font-mono);font-size:.66rem;border-radius:var(--radius-1)}
.sig-row:last-child{border-bottom:none;padding-top:8px}
.sig-key{color:var(--fg-mute)}
canvas.mini-chart{width:100%;height:140px;margin-bottom:4px;cursor:pointer;transition:opacity .15s}
#dp-two-col{display:flex;gap:24px;margin-bottom:12px}
#dp-col-left{flex:1;min-width:0}
#dp-col-right{flex:1;min-width:0}

.results-filter-bar{display:flex;flex-wrap:wrap;align-items:flex-start;gap:10px;padding:12px 16px;background:var(--bg-2);border:1px solid var(--border);border-radius:var(--radius-1);margin-bottom:14px}
.results-filter-bar .ctrl-label{font-family:var(--font-mono);font-size:.54rem;letter-spacing:2px;color:var(--fg-mute);text-transform:lowercase;margin-bottom:4px}
.rf-group{display:flex;flex-direction:column}
.rf-title{font-family:var(--font-mono);font-size:.58rem;letter-spacing:3px;color:var(--cyan);margin-bottom:10px;text-transform:uppercase;display:flex;align-items:center;gap:8px}
.rf-title::before{content:'';display:inline-block;width:6px;height:6px;background:var(--cyan);border-radius:50%}
.rf-clear{font-family:var(--font-mono);letter-spacing:1px;color:var(--fg-mute,var(--fg-mute));background:none;border:1px solid var(--border,var(--border));border-radius:var(--radius-1,2px);cursor:pointer;margin-left:auto}
.rf-clear:hover{border-color:var(--red,#ff2e63);color:var(--red,#ff2e63)}
/* Results-filter tile row (2026-07-27): one row, one height. Type + padding
   come from the shared .mws-btn--xs (these legacy rules no longer declare
   padding/font-size, so the component class governs); the pin below keeps the
   three tiles (✕/⊞ text vs the gear's 13px svg) in a single 24px box so glyph
   metrics can't stagger them (measured pre-fix: 23px / 27px / 25px). */
.rf-clear,.col-picker-btn,.gear-btn{height:24px}
#resultSectorSel{background:var(--bg-3);border:1px solid var(--border);color:var(--fg-hi);font-family:var(--font-mono);font-size:.78rem;padding:9px 12px;border-radius:var(--radius-1);outline:none;cursor:pointer;min-width:180px;-webkit-appearance:none}
#resultSectorSel:focus{border-color:var(--cyan)}
.rf-group input[type=number]{background:var(--bg-3);border:1px solid var(--border);color:var(--fg-hi);font-family:var(--font-mono);font-size:.78rem;padding:9px 12px;border-radius:var(--radius-1);outline:none}
.rf-group input[type=number]:focus{border-color:var(--cyan)}
.rf-group input[type=number]::placeholder{color:var(--fg-dim)}
.active-tags{display:flex;flex-wrap:wrap;gap:6px;align-items:center;min-height:28px}
.tag{display:inline-flex;align-items:center;gap:5px;background:rgba(0,184,255,.12);border:1px solid rgba(0,184,255,.3);color:var(--cyan);font-family:var(--font-mono);font-size:.62rem;letter-spacing:1px;padding:3px 8px;border-radius:var(--radius-1)}
.tag-x{cursor:pointer;opacity:.6;font-size:.8rem;line-height:1}
.tag-x:hover{opacity:1;color:var(--red)}

/* ── design-system-adoption task 5.1: .mws-panel context overrides ─────────
   These rules keep the panel's own sizing/layout properties (position, shadow,
   overflow, max-height) while layering the .mws-panel structure on top. The
   inline block has higher cascade priority than the linked component sheet. */

/* scan-panel: the .mws-panel outer wrapper holds the header; .table-wrap
   retains all its own overflow/scroll and max-height rules unchanged. */
.scan-panel{border:var(--border-w,1px) solid var(--border,#262626);border-radius:var(--radius-0,0);margin-bottom:40px}
.scan-panel .table-wrap{border:none;border-radius:0;margin-bottom:0;max-height:calc(100vh - 260px - var(--panel-header-h,28px))}

/* detail panel: overlay modal — use --shadow-modal per Req 6.2 overlay exception.
   The card keeps its own sizing; .mws-panel supplies the border token only. */
.detail-modal-card.mws-panel{box-shadow:var(--shadow-modal,0 24px 80px rgba(0,0,0,.6));border-color:var(--border,#262626);border-radius:var(--radius-0,0)}
/* The mws-panel__hd sits at the top of the card; the existing abs-positioned
   button bar (#dp-header-btns) has z-index:11 and stays above it. */
.detail-modal-card .mws-panel__hd{border-radius:0}

/* sig-section panels (GEX, holdings): the section already has a background;
   .mws-panel overrides border/radius in the render functions (classes applied inline). */
.sig-section.mws-panel{background:var(--bg-2,#111111);border:var(--border-w,1px) solid var(--border,#262626);border-radius:var(--radius-0,0)}
.sig-section.mws-panel .mws-panel__hd{border-radius:0}

.toggle-switch{position:relative;display:inline-block;width:44px;height:24px;margin-top:6px}
.toggle-switch input{opacity:0;width:0;height:0}
.toggle-slider{position:absolute;cursor:pointer;inset:0;background:var(--border);border-radius:var(--radius-1);transition:.3s;border:1px solid var(--border-hot)}
.toggle-slider:before{content:'';position:absolute;width:18px;height:18px;left:2px;top:2px;background:var(--fg-mute);border-radius:50%;transition:.3s}
.toggle-switch input:checked + .toggle-slider{background:var(--green-bg,rgba(51,255,102,.2));border-color:var(--green,#33ff66)}
.toggle-switch input:checked + .toggle-slider:before{transform:translateX(20px);background:var(--green,#33ff66)}

/* ── Help Modal ─────────────────────────────────────────────────── */
#helpModal{display:none;position:fixed;inset:0;z-index:600;align-items:center;justify-content:center;background:rgba(0,0,0,.75);backdrop-filter:blur(4px)}
#helpModal.open{display:flex}
.hm-card{background:var(--bg-2);border:1px solid var(--border);border-radius:var(--radius-2);width:1100px;max-width:96vw;max-height:90vh;display:flex;flex-direction:column;overflow:hidden}
.hm-header{display:flex;align-items:center;justify-content:space-between;padding:20px 28px 16px;border-bottom:1px solid var(--border);flex-shrink:0}
.hm-title{font-family:var(--font-mono);font-size:1rem;letter-spacing:4px;color:var(--green,#33ff66)}
.hm-title span{color:var(--fg-hi)}
.hm-sub{font-family:var(--font-mono);font-size:.55rem;letter-spacing:2px;color:var(--fg-mute);margin-top:3px}
.hm-close{background:none;border:1px solid var(--border,var(--border));color:var(--fg-mute,var(--fg-mute));font-family:var(--font-mono);font-size:.7rem;padding:5px 12px;border-radius:var(--radius-1,2px);cursor:pointer;letter-spacing:1px}
.hm-close:hover{border-color:var(--red,#ff2e63);color:var(--red,#ff2e63)}
.hm-tabs{display:flex;flex-wrap:wrap;justify-content:center;gap:0;padding:0 28px;border-bottom:1px solid var(--border);flex-shrink:0}
.hm-tab{font-family:var(--font-mono);font-size:.6rem;letter-spacing:2px;text-transform:lowercase;padding:11px 16px;color:var(--fg-mute);cursor:pointer;border-bottom:2px solid transparent;white-space:nowrap;transition:all .2s}
.hm-tab:hover{color:var(--fg-hi)}
.hm-tab.active{color:var(--green,#33ff66);border-bottom-color:var(--green,#33ff66)}
.hm-body{overflow-y:auto;padding:24px 28px;flex:1}
.hm-section{display:none}
.hm-section.active{display:block}
.hm-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:14px}
.hm-card-item{background:var(--bg-3);border:1px solid var(--border);border-radius:var(--radius-1);padding:16px 18px}
.hm-card-icon{font-size:1.3rem;margin-bottom:8px}
.hm-card-title{font-family:var(--font-mono);font-size:.62rem;letter-spacing:2px;text-transform:uppercase;margin-bottom:8px}
.hm-card-body{font-family:var(--font-mono);font-size:.64rem;color:var(--fg-2);line-height:1.65;letter-spacing:.3px}
.hm-card-body b{color:var(--fg-hi);font-weight:700}
.hm-card-body .tag-pill{display:inline-block;padding:1px 7px;border-radius:var(--radius-1);font-size:.58rem;letter-spacing:1px;font-weight:700;vertical-align:middle}
.hm-tip{display:flex;gap:10px;align-items:flex-start;background:rgba(0,184,255,.06);border:1px solid rgba(0,184,255,.2);border-radius:var(--radius-1);padding:10px 14px;margin-top:16px}
.hm-tip-icon{color:var(--cyan);font-size:.85rem;flex-shrink:0;margin-top:1px}
.hm-tip-text{font-family:var(--font-mono);font-size:.63rem;color:var(--fg-2);line-height:1.6;letter-spacing:.3px}
.hm-tip-text b{color:var(--cyan)}
.hm-section-label{font-family:var(--font-mono);font-size:.56rem;letter-spacing:3px;text-transform:uppercase;color:var(--fg-mute);margin:0 0 12px;padding-bottom:6px;border-bottom:1px solid var(--border)}
.hm-shortcut-row{display:flex;align-items:center;gap:12px;padding:7px 0;border-bottom:1px solid var(--border);font-family:var(--font-mono);font-size:.65rem}
.hm-shortcut-row:last-child{border-bottom:none}
.hm-shortcut-key{background:var(--border);border:1px solid var(--border-hot);border-radius:var(--radius-1);padding:2px 8px;font-size:.6rem;color:var(--fg-hi);letter-spacing:1px;flex-shrink:0}
.hm-shortcut-desc{color:var(--fg-2)}

/* ══════════════════════════════════════════════════════════════════════════
   MOBILE RESPONSIVE — Breakpoints: 768px (tablet), 480px (phone)
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Tablet & smaller (≤768px) ──────────────────────────────────────────── */
@media (max-width: 768px) {

  /* — Workstation chrome: drop the rail, compact the topbar — */
  body {
    padding-left: 0;
  }
  header {
    margin-left: 0;
  }
  #mws-rail {
    display: none;
  }
  .cmd-bar {
    left: 0;
  }
  /* screener-filter-panel: below the rail breakpoint there is no room to shift,
     so the panel becomes an overlay drawer. Width tracks --filter-w (360px open /
     0 collapsed) but is capped at 86vw so on a narrow phone the drawer never goes
     full-bleed — it leaves a peek of dimmed content behind as a close affordance.
     The edge handle is the only open affordance here since the rail is hidden. */
  #filterPanel {
    left: 0;
    width: min(var(--filter-w, 0px), 86vw);
    z-index: 360;
  }
  #filterHandle {
    left: var(--filter-w, 0px);
  }
  .tb-cmd {
    display: none;
  }
  .tb-seg {
    padding: 0 8px;
    gap: 6px;
  }
  .tb-market {
    flex: 1;
    min-width: 0;
    overflow: hidden;
  }
  .live-badge {
    font-size: .58rem;
    gap: 6px;
  }
  header button[onclick="signOut()"] {
    padding: 4px 8px;
    font-size: .52rem;
  }

  /* — Container & Controls — */
  .container {
    padding: 0 10px;
  }
  .controls {
    padding: 14px 0 10px;
    gap: 8px;
  }
  .controls select,
  .controls input[type=number] {
    min-width: 100px;
    font-size: .72rem;
    padding: 8px 10px;
  }
  .btn {
    font-size: .65rem;
    padding: 8px 14px;
    letter-spacing: 1.5px;
  }

  /* — Signal chips — */
  .chips {
    gap: 6px;
    padding-bottom: 10px;
  }
  .chip {
    font-size: .58rem;
    padding: 5px 10px;
  }

  /* — Stats bar — */
  .stats-bar {
    gap: 12px;
    padding: 10px 12px;
    justify-content: space-between;
  }
  .stat-val {
    font-size: 1rem;
  }
  .stat-lbl {
    font-size: .5rem;
  }

  /* — Results filter bar — */
  .results-filter-bar {
    padding: 10px 12px;
    gap: 8px;
    flex-direction: column;
  }
  #resultSectorSel {
    min-width: 140px;
    width: 100%;
  }
  .rf-group {
    width: 100%;
  }
  .rf-clear {
    width: auto;
  }

  /* — Table — */
  .table-wrap {
    margin-bottom: 20px;
    -webkit-overflow-scrolling: touch;
    position: relative;
    max-height: calc(100vh - 200px);
  }
  /* Scroll hint gradient on the right edge */
  .table-wrap::after {
    content: '';
    position: absolute;
    right: 0;
    top: 0;
    bottom: 0;
    width: 24px;
    background: linear-gradient(90deg, transparent, var(--bg-2));
    pointer-events: none;
    z-index: 2;
  }
  table {
    font-size: .7rem;
  }
  th {
    padding: 10px 10px;
    font-size: .54rem;
    letter-spacing: 1.5px;
  }
  td {
    padding: 10px 10px;
    font-size: .68rem;
  }

  /* — Detail panel (modal → full-screen on mobile) — */
  #detail-panel {
    padding: 0;
  }
  #dp-two-col {
    flex-direction: column;
    gap: 12px;
  }
  #dp-col-left {
    order: 2;
  }
  #dp-col-right {
    order: 1;
  }
  canvas.mini-chart {
    height: 90px;
  }
  .detail-modal-card {
    max-width: 100%;
    width: 100%;
    border-radius: 0;
    min-height: 100vh;
    padding: 20px 16px 120px;
  }
  .detail-ticker {
    font-size: 1.5rem;
    letter-spacing: 3px;
  }
  .detail-price {
    font-size: 1.2rem;
  }
  .ind-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 6px;
  }
  .ind-val {
    font-size: .9rem;
  }
  .sig-grid {
    grid-template-columns: 1fr;
  }
  .sig-row {
    font-size: .62rem;
    padding: 6px 8px;
  }
  .detail-close {
    width: 36px;
    height: 36px;
    font-size: 1.1rem;
  }

  /* — Weights modal — */
  #weightsModal .wm-card {
    padding: 18px 16px;
    width: 100%;
    max-width: 100vw;
    max-height: 95vh;
    border-radius:var(--radius-2) var(--radius-2) 0 0;
  }
  #weightsModal .wm-row {
    flex-wrap: wrap;
    gap: 6px;
  }
  #weightsModal .wm-label {
    width: 100%;
    font-size: .56rem;
  }
  #weightsModal .wm-slider {
    flex: 1;
    min-width: 100px;
  }
  #weightsModal .wm-num {
    width: 56px;
  }
  #weightsModal .wm-actions {
    flex-wrap: wrap;
    gap: 8px;
  }

  /* — Help modal — */
  .hm-card {
    width: 100%;
    max-width: 100vw;
    max-height: 96vh;
    border-radius:var(--radius-2) var(--radius-2) 0 0;
  }
  .hm-header {
    padding: 14px 16px 12px;
  }
  .hm-title {
    font-size: .85rem;
    letter-spacing: 3px;
  }
  .hm-tabs {
    padding: 0 12px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    flex-wrap: nowrap;
    justify-content: flex-start;
  }
  .hm-tab {
    font-size: .54rem;
    padding: 9px 12px;
    flex-shrink: 0;
  }
  .hm-body {
    padding: 16px 14px;
  }
  .hm-cards {
    grid-template-columns: 1fr;
    gap: 10px;
  }

  /* — Chart modal — */
  #chart-modal {
    align-items: flex-start !important;
    padding-top: env(safe-area-inset-top, 0px);
  }
  #chart-modal > div {
    width: 97vw !important;
    max-width: 97vw !important;
    max-height: 96vh;
    overflow-y: auto;
    padding: 16px 12px;
    margin-top: 2vh;
  }
  #chart-modal canvas {
    max-height: 55vh;
  }
  #cm-legend {
    gap: 4px;
  }
  #cm-legend-mas {
    gap: 8px !important;
  }
  #cm-close {
    padding: 8px 16px !important;
    font-size: .75rem !important;
    min-height: 44px;
  }
  #cm-copy {
    padding: 8px 14px !important;
    min-height: 44px;
  }

  /* — Login overlay — */
  #mowgli-login-overlay > div {
    width: 92vw !important;
    max-width: 380px;
    padding: 28px 20px !important;
  }

  /* — Screener/ETF panels — */
  #screenerGroup,
  #etfScreenerGroup {
    padding: 10px 12px;
    gap: 8px;
  }
  #screenerGroup .ctrl-group,
  #etfScreenerGroup .ctrl-group {
    flex: 1 1 calc(50% - 8px);
    min-width: 0;
  }
  #screenerGroup select,
  #screenerGroup input,
  #etfScreenerGroup input {
    width: 100%;
    min-width: 0;
  }

  /* — Toggle switches: bigger touch target on mobile — */
  .toggle-switch {
    width: 48px;
    height: 26px;
  }
  .toggle-slider:before {
    width: 20px;
    height: 20px;
  }
  .toggle-switch input:checked + .toggle-slider:before {
    transform: translateX(22px);
  }

  /* — Column picker — */
  .col-picker-dropdown {
    right: 0;
    left: auto;
  }

  /* — Table footer — */
  .table-footer {
    flex-direction: column;
    gap: 4px;
    padding: 8px 12px;
    font-size: .58rem;
  }

  /* — RSI bar widths — */
  .rsi-bg {
    width: 40px;
  }
  .vol-bg {
    width: 36px;
  }

  /* — Version badge — */
  div[style*="position:fixed;bottom:12px;right:16px"] {
    bottom: 6px !important;
    right: 8px !important;
    font-size: .55rem !important;
  }
}

/* ── Phone (≤480px) ─────────────────────────────────────────────────────── */
@media (max-width: 480px) {

  /* — Topbar compacts: brand glyph + status + account — */
  .tb-wordmark {
    display: none;
  }
  .live-badge {
    min-width: 0;
    flex-shrink: 1;
    overflow: hidden;
  }
  #delay-label {
    display: none;
  }

  /* — Controls stack — */
  .controls {
    display: grid !important;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    flex-direction: column;
    align-items: stretch;
  }
  .controls .ctrl-group {
    grid-column: 1 / -1;
    width: 100%;
  }
  .controls select {
    width: 100%;
    min-width: 0 !important;
  }
  .controls .btn {
    width: 100%;
    text-align: center;
  }

  /* — Stats bar: 3×2 grid — */
  .stats-bar {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
    padding: 10px;
  }
  .stat-val {
    font-size: .9rem;
  }

  /* — Table cells tighter — */
  th {
    padding: 8px 7px;
    font-size: .5rem;
    letter-spacing: 1px;
  }
  td {
    padding: 8px 7px;
    font-size: .62rem;
  }
  .sig {
    font-size: .54rem;
    padding: 2px 7px;
  }

  /* — Detail panel — */
  .detail-modal-card {
    padding: 16px 12px 120px;
  }
  .detail-ticker {
    font-size: 1.25rem;
  }
  .detail-price {
    font-size: 1rem;
  }
  .ind-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 5px;
  }
  .ind-card {
    padding: 8px;
  }
  .ind-lbl {
    font-size: .48rem;
  }
  .ind-val {
    font-size: .8rem;
  }

  /* — Weights modal — */
  #weightsModal .wm-card {
    padding: 14px 12px;
  }
  #weightsModal .wm-section-title {
    font-size: .52rem;
  }

  /* — Signal config tabs in weights modal — */
  #weightsModal div[style*="display:flex;gap:0;border-bottom"] {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  #weightsModal div[style*="display:flex;gap:0;border-bottom"] button {
    flex-shrink: 0;
    font-size: .54rem !important;
    padding: 8px 12px !important;
  }

  /* — Screener inputs — */
  #screenerGroup .ctrl-group,
  #etfScreenerGroup .ctrl-group {
    flex: 1 1 100%;
  }

  /* — Chart modal — */
  #chart-modal > div {
    padding: 12px 10px;
    border-radius:var(--radius-1);
    max-height: 94vh;
    margin-top: 3vh;
  }
  #cm-title {
    font-size: .75rem !important;
  }
  #cm-sub {
    font-size: .55rem !important;
  }

  /* — Login — */
  #mowgli-login-overlay > div {
    width: 95vw !important;
    padding: 24px 16px !important;
  }
  #mowgli-login-overlay > div > div:first-child {
    font-size: 1.1rem !important;
  }

  /* — Chips wrap more aggressively — */
  .chips {
    gap: 5px;
  }
  .chip {
    font-size: .54rem;
    padding: 4px 8px;
  }

  /* — Mini chart in detail panel — */
  canvas.mini-chart {
    height: 70px;
  }

  /* — Help modal — */
  .hm-header {
    padding: 12px 12px 10px;
    flex-direction: column;
    gap: 8px;
    align-items: flex-start;
  }
  .hm-title {
    font-size: .75rem;
  }
  .hm-body {
    padding: 12px 10px;
  }
  .hm-card-item {
    padding: 12px 14px;
  }
  .hm-card-body {
    font-size: .58rem;
  }
  .hm-shortcut-row {
    font-size: .58rem;
    gap: 8px;
  }

  /* — Pattern filter toggles in results-filter-bar — */
  .results-filter-bar > div[style*="flex-wrap:wrap;align-items:flex-start"] {
    display: grid !important;
    grid-template-columns: repeat(2, 1fr) !important;
    gap: 12px !important;
  }

  /* — Quantitative filter rows: stack vertically — */
  .results-filter-bar > div[style*="display:flex;flex-wrap:wrap;align-items:flex-end"] {
    flex-direction: column !important;
    gap: 12px !important;
  }
}

/* ── Touch improvements (all touch devices) ─────────────────────────────── */
@media (hover: none) and (pointer: coarse) {
  /* Bigger touch targets */
  .btn {
    min-height: 44px;
    min-width: 44px;
  }
  select, input[type=number], input[type=text] {
    min-height: 44px;
    font-size: max(16px, inherit); /* prevents iOS zoom on focus */
  }
  .chip {
    min-height: 36px;
    display: inline-flex;
    align-items: center;
  }
  .gear-btn {
    min-height: 36px;
    min-width: 36px;
  }
  .detail-close {
    min-width: 44px;
    min-height: 44px;
  }
  th {
    min-height: 44px;
  }
  tbody tr {
    min-height: 48px;
  }

  /* Disable hover states that don't make sense on touch */
  .sig-row.clickable:hover {
    background: transparent;
  }
  .sig-row.clickable:hover .sig-key::after {
    content: none;
  }

  /* Add active state instead */
  .sig-row.clickable:active {
    background: rgba(0, 184, 255, .1);
  }
  .btn:active {
    opacity: 0.85;
  }
  .chip:active {
    opacity: 0.85;
  }
  tbody tr:active {
    background: rgba(255, 255, 255, .05);
  }
  tbody tr:active td:first-child {
    background: #141920;
  }
}

/* ── Safe area insets for notched phones ─────────────────────────────────── */
@supports (padding: env(safe-area-inset-bottom)) {
  header {
    padding-top: max(12px, env(safe-area-inset-top));
    padding-left: max(14px, env(safe-area-inset-left));
    padding-right: max(14px, env(safe-area-inset-right));
  }
  .container {
    padding-left: max(10px, env(safe-area-inset-left));
    padding-right: max(10px, env(safe-area-inset-right));
  }
  .detail-modal-card {
    padding-bottom: max(120px, env(safe-area-inset-bottom));
  }
}

/* ── Landscape phone (short height) ─────────────────────────────────────── */
@media (max-height: 500px) and (max-width: 900px) {
  header {
    padding: 6px 12px;
    position: relative; /* unstick header to save vertical space */
  }
  .stats-bar {
    padding: 6px 10px;
  }
  .detail-modal-card {
    padding-top: 12px;
  }
  #chart-modal canvas {
    max-height: 40vh;
  }
}

/* ══ GEX Feature ══════════════════════════════════════════════════════════ */
.dp-tab-bar{display:flex;gap:0;border-bottom:1px solid var(--border);margin-top:14px}
.dp-tab{font-family:var(--font-mono);font-size:.58rem;letter-spacing:2px;text-transform:lowercase;padding:11px 16px;color:var(--fg-mute);cursor:pointer;border-bottom:2px solid transparent;transition:all .15s;white-space:nowrap}
.dp-tab:hover{color:var(--fg-hi)}
.dp-tab.active{color:var(--green,#33ff66);border-bottom-color:var(--green,#33ff66)}
.dp-tab-panel{display:none}
.dp-tab-panel.active{display:block}
.gex-controls{display:flex;align-items:center;gap:8px;margin-bottom:12px;flex-wrap:wrap;padding-top:14px}
.gex-select{background:var(--bg-3);border:1px solid var(--border);color:var(--fg-hi);font-family:var(--font-mono);font-size:.7rem;padding:8px 10px;border-radius:var(--radius-1);outline:none;cursor:pointer;-webkit-appearance:none;letter-spacing:1px;min-width:220px;line-height:1.4}
.gex-select:focus{border-color:var(--green,#33ff66)}
.gex-calc-toggle{display:flex;gap:0;border:1px solid var(--border);border-radius:var(--radius-1);overflow:hidden}
.gex-calc-btn{background:transparent;border:none;color:var(--fg-mute,var(--fg-mute));font-family:var(--font-mono);font-size:.56rem;letter-spacing:1px;padding:6px 11px;cursor:pointer}
.gex-calc-btn.active{background:var(--green-bg,rgba(51,255,102,.1));color:var(--green,#33ff66)}
.gex-calc-btn:hover:not(.active){background:rgba(255,255,255,.03)}
.gex-chart-btn{margin-left:auto;background:none;border:1px solid var(--border,var(--border));color:var(--fg-mute,var(--fg-mute));font-family:var(--font-mono);font-size:.56rem;letter-spacing:1px;padding:6px 12px;border-radius:var(--radius-1,2px);cursor:pointer;display:flex;align-items:center;gap:5px}
.gex-chart-btn:hover{border-color:var(--cyan);color:var(--cyan)}
.gex-status-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin:12px 0}
.gex-status-card{background:var(--bg-2);border-radius:var(--radius-1);padding:8px 10px}
.gex-status-lbl{font-family:var(--font-mono);font-size:.48rem;letter-spacing:2px;color:var(--fg-mute);text-transform:uppercase;margin-bottom:3px}
.gex-status-val{font-family:var(--font-mono);font-size:.85rem;letter-spacing:1px}
.gex-level-row{display:flex;justify-content:space-between;align-items:center;padding:6px 8px;border-bottom:1px solid var(--border);font-family:var(--font-mono);font-size:.66rem}
.gex-level-row:last-child{border-bottom:none}
.gex-level-row.hvl-row{background:rgba(0,184,255,.06);border-radius:var(--radius-1)}
.gex-level-row.spot-row{background:rgba(230,237,243,.04);border-top:1px dashed rgba(230,237,243,.25);border-bottom:1px dashed rgba(230,237,243,.25);border-radius:0}
.gex-spot-divider{display:flex;align-items:center;gap:6px;margin:5px 0;padding-left:48px}
.gex-spot-line{flex:1;border-top:1px dashed rgba(230,237,243,.3)}
.gex-spot-label{font-family:var(--font-mono);font-size:.48rem;color:var(--fg-hi);letter-spacing:1px;flex-shrink:0;opacity:.7}
.gex-dot{width:6px;height:6px;border-radius:50%;margin-right:7px;flex-shrink:0;display:inline-block}
.gex-level-name{color:var(--fg-mute);display:flex;align-items:center}
.gex-level-price{font-weight:700;letter-spacing:1px}
.gex-bar-row{display:flex;align-items:center;gap:6px;margin:3px 0}
.gex-bar-strike{font-family:var(--font-mono);font-size:.52rem;color:var(--fg-mute);width:42px;text-align:right;flex-shrink:0}
.gex-bar{height:7px;border-radius:var(--radius-1)}
.gex-hvl-divider{display:flex;align-items:center;gap:6px;margin:5px 0;padding-left:48px}
.gex-hvl-line{flex:1;border-top:1px dashed var(--cyan)}
.gex-hvl-label{font-family:var(--font-mono);font-size:.48rem;color:var(--cyan);letter-spacing:1px;flex-shrink:0}
.gex-zone-legend{display:flex;flex-wrap:wrap;gap:10px;margin-top:12px;padding-top:10px;border-top:1px solid var(--border)}
.gex-zone-item{display:flex;align-items:center;gap:5px;font-family:var(--font-mono);font-size:.52rem;color:#484f58;letter-spacing:.5px}
.gex-zone-swatch{width:8px;height:8px;border-radius:2px}
.gex-updated{font-family:var(--font-mono);font-size:.5rem;color:#484f58;letter-spacing:1px;margin-top:10px;display:flex;align-items:center;gap:6px}
.gex-updated-dot{width:5px;height:5px;border-radius:50%;background:var(--green,#33ff66)}
.zone-info-btn{display:inline-flex;align-items:center;justify-content:center;width:14px;height:14px;border-radius:50%;border:1px solid var(--border-hot);color:var(--fg-mute);font-family:var(--font-mono);font-size:.5rem;font-weight:900;cursor:pointer;margin-left:4px;transition:all .2s;line-height:1;vertical-align:middle}
.zone-info-btn:hover{border-color:var(--cyan);color:var(--cyan)}
.zone-tooltip{display:none;position:absolute;bottom:calc(100% + 8px);right:-8px;width:300px;background:var(--bg-2);border:1px solid var(--border);border-radius:var(--radius-1);padding:14px 16px;z-index:100;box-shadow:0 8px 30px rgba(0,0,0,.6)}
.zone-tooltip.open{display:block}
.zone-tooltip-title{font-family:var(--font-mono);font-size:.54rem;letter-spacing:2px;color:var(--fg-mute);text-transform:uppercase;margin-bottom:10px;padding-bottom:6px;border-bottom:1px solid var(--border)}
.zone-tooltip-row{display:flex;align-items:flex-start;gap:8px;padding:5px 0;border-bottom:1px solid var(--bg-3)}
.zone-tooltip-row:last-child{border-bottom:none}
.zone-tooltip-swatch{width:8px;height:8px;border-radius:2px;flex-shrink:0;margin-top:3px}
.zone-tooltip-name{font-family:var(--font-mono);font-size:.56rem;font-weight:700;letter-spacing:.5px;margin-bottom:2px}
.zone-tooltip-desc{font-family:var(--font-mono);font-size:.5rem;color:var(--fg-mute);line-height:1.5;letter-spacing:.3px}

/* ── the earnings hover card (2026-08-01) ────────────────────────────────────
   Borrows .zone-tooltip's TYPE SCALE, surface, border and shadow so the two
   read as one system — and departs from it on exactly one property, because
   that one was measured. .zone-tooltip is `position:absolute` inside its own
   anchor, which is correct in an unclipped panel; this card's anchor sits in
   .table-wrap (overflow-x:auto; overflow-y:auto; max-height:calc(100vh−260px)),
   so an absolute card on a bottom row or a right-edge column would be CLIPPED
   by the scroll container. `position:fixed` at document.body level escapes
   every clipping context; app.js positions it from the anchor's
   getBoundingClientRect() and flips it at the viewport edges.

   z-index 700 sits above #detail-panel (500), because the blade's own EARNINGS
   tag is an anchor too, and below #gex-chart-modal (1000) / #searchModal
   (1100), which the card never overlaps — opening either one tears it down.

   pointer-events:none is load-bearing, not decoration: the card must never
   capture the pointer, or moving toward it would fire the anchor's mouseout
   and leave a card the mouse is now sitting inside. It is display-only; every
   fact on it is also on the anchor's aria-label. */
.earn-tip{display:none;position:fixed;left:0;top:0;z-index:700;min-width:190px;max-width:340px;background:var(--bg-2);border:1px solid var(--border);border-radius:var(--radius-1);padding:10px 12px;box-shadow:0 8px 30px rgba(0,0,0,.6);font-family:var(--font-mono);pointer-events:none}
.earn-tip.open{display:block}
.earn-tip-day{font-size:.6rem;color:var(--fg-1);letter-spacing:.5px;white-space:nowrap}
.earn-tip-date{color:var(--fg-mute);margin-left:6px}
.earn-tip-session{font-size:.54rem;color:var(--fg-mute);letter-spacing:.3px;margin-top:3px}
.earn-tip-est{font-size:.5rem;color:var(--amber);letter-spacing:.3px;margin-top:3px}
.earn-tip-figs{margin-top:9px;padding-top:8px;border-top:1px solid var(--border)}
.earn-tip-block + .earn-tip-block{margin-top:8px}
.earn-tip-label{font-size:.5rem;letter-spacing:2px;color:var(--fg-mute)}
.earn-tip-val{display:flex;align-items:baseline;gap:10px;margin-top:2px;font-size:.6rem;color:var(--fg-1);font-variant-numeric:tabular-nums;white-space:nowrap}
.earn-tip-pct{margin-left:auto;font-weight:700;font-variant-numeric:tabular-nums}
#gex-chart-modal{display:none;position:fixed;inset:0;z-index:1000;align-items:center;justify-content:center}
@media (max-width:768px){
  .gex-status-grid{grid-template-columns:repeat(2,1fr)}
  .gex-controls{flex-direction:column;align-items:stretch}
  .gex-chart-btn{margin-left:0}
  .dp-tab{padding:9px 10px;font-size:.52rem;letter-spacing:1.5px}
  .zone-tooltip{width:260px;right:-4px}
}

/* Phase 6 — surgical WS update flash (Terminal refactor).
   Scanner-workstation task 8: widened beyond td — the dashboard's compact
   rows are spans (.dash-scan-cell / .dash-wl-cell) and the score-metric
   tiles are [data-metric] divs; _dashFlash/_dashPatchCell add the same
   class, which the td-scoped selector never animated. */
td.flash-update,
.dash-scan-cell.flash-update,
.dash-wl-cell.flash-update,
[data-metric].flash-update {
  animation: mowgli-flash 600ms ease-out;
}
@keyframes mowgli-flash {
  0%   { background-color: rgba(0, 184, 255, 0.35); }
  100% { background-color: transparent; }
}

/* ── design-system-adoption task 7.1 — Req 10.1, 10.3, 10.4 ───────────────
   Casing:  chrome containers → text-transform:lowercase (labels, prompts, metadata,
            modal field labels, tab navigation). Eyebrows/tags/signals already carry
            text-transform:uppercase and are NOT overridden here — the explicit
            uppercase guards below protect them from any future container-level cascade.
   Tabular-numerals: font-variant-numeric:tabular-nums on every digit-bearing readout
            not already covered by the table.term/`.num` treatment from task 5.2.
   Glyph audit: no emoji introduced; SVG stroke-width divergences flagged below.
   ──────────────────────────────────────────────────────────────────────────────── */

/* ── 10.1 — modal / weight-panel field labels → lowercase chrome ─────────── */
/* .wm-label contains factor names like "Daily RSI (extreme)" — chrome metadata */
#weightsModal .wm-label{text-transform:lowercase}

/* ── 10.1 — eyebrow / section-label UPPERCASE guards (already uppercase, pinned
   so a future container-level lowercase rule cannot cascade in) ─────────── */
/* These are section eyebrows, signal labels, and category headers — reserved UPPERCASE. */
.stat-lbl,
.ind-lbl,
.sig-title,
.rf-title,
.gex-status-lbl,
.hm-section-label,
.wl-popup-title,
.hm-card-title,
.conn-badge,
.data-stale-badge,
.cmd-bar-status{text-transform:uppercase}

/* ── 10.3 — tabular-nums on every digit-bearing readout not covered by task 5.2 ─
   task 5.2 already applied font-variant-numeric:tabular-nums to table.term
   (scan grid) and table.term th. The classes below render numbers outside
   that grid context and need the same treatment. ─────────────────────────── */

/* Detail-panel hero readouts */
.detail-price{font-variant-numeric:tabular-nums}
.detail-ticker{font-variant-numeric:tabular-nums}

/* Detail-panel indicator cards (RSI, MACD, EMA, SMA, BB, Score, etc.) */
.ind-val{font-variant-numeric:tabular-nums}

/* Stats bar (scan count, match count) */
.stat-val{font-variant-numeric:tabular-nums}

/* GEX status grid cards (gamma exposure readouts) */
.gex-status-val{font-variant-numeric:tabular-nums}

/* GEX level table (spot price, strike prices) */
.gex-level-price{font-variant-numeric:tabular-nums}
.gex-level-row{font-variant-numeric:tabular-nums}
.gex-bar-strike{font-variant-numeric:tabular-nums}

/* Weight modal numeric inputs */
#weightsModal .wm-num{font-variant-numeric:tabular-nums}

/* mcap-compare legend stats (Total %, CAGR %) */
#mcapModal .mcap-legend-stat{font-variant-numeric:tabular-nums}
#mcapModal .mcap-legend-item{font-variant-numeric:tabular-nums}

/* Signal detail rows (RSI / MACD / EMA values in the signals tab) */
.sig-row{font-variant-numeric:tabular-nums}

/* Pagination footer — digit-bearing counts missed by the 7.1 sweep (Req 10.3) */
.table-footer{font-variant-numeric:tabular-nums}

/* ── 10.4 — SVG glyph audit ([bar-chart] emoji removed; no emoji on migrated surfaces) ──
   All Lucide SVGs in index.html use stroke="currentColor" — conforming.
   The .sig-row.clickable hover ::after was carrying a [bar-chart] emoji — now replaced
   with → (U+2192) from the approved glyph set (Req 10.4 satisfied).
   Divergences found (flag only, not rewritten here per spec guidance):
     - Share/copy icons (index.html): stroke-width="2.2" vs target "1.5" (Lucide default)
     - Activity/compare icon (index.html): stroke-width="2" — minor divergence
     - Sparkline polyline (app.js line 3088): stroke-width="1.5" — AT TARGET (conforming)
     - Reconnect icon (app.js line 6492): stroke-width="2.5" — diverges above target 1.5
     - Info circle (app.js line 6786): stroke-width="1.2" — diverges below target 1.5;
       uses stroke="var(--fg-mute)" (hardcoded) — not currentColor; flagged
     - People/share icons (app.js lines 6581, 6605): stroke="var(--fg-mute)" hardcoded — not currentColor
     - mcap icon (index.html line 2866): stroke="var(--cyan)" hardcoded — not currentColor
     - Command icons (app.js lines 7126, 7132): stroke="var(--cyan)" hardcoded — not currentColor
   Rewrite of these divergent SVGs is deferred (per task 7.1 spec: "flag, do not
   necessarily rewrite"). No emoji was introduced by this task.
   ──────────────────────────────────────────────────────────────────────────────── */


/* ── (former index.html second inline block — mcap modal) ─────────────────── */

@keyframes spin{to{transform:rotate(360deg)}}
/* go-live-ui-polish (b): segmented-control overlap idiom. Both segments keep all
   four .mws-btn borders; the second overlaps the shared edge by -1px; the active
   segment wins the seam via z-index so its armed green border fully wraps. */
#mcapModal .mcap-view-btn{position:relative}
#mcapModal .mcap-view-btn + .mcap-view-btn{margin-left:-1px}
#mcapModal .mcap-view-btn.active{background:var(--border)!important;color:var(--fg-hi)!important;z-index:1}
#mcapModal .mcap-legend-item{display:flex;align-items:center;gap:8px;padding:8px 14px;background:var(--bg-3);border:1px solid var(--border);border-radius:var(--radius-1);font-family:var(--font-mono);font-size:.72rem;letter-spacing:1px}
#mcapModal .mcap-legend-dot{width:10px;height:10px;border-radius:50%;flex-shrink:0}
#mcapModal .mcap-legend-stat{color:var(--fg-mute);font-size:.6rem;margin-left:4px}


/* ── (former user-management.js injectCSS — profile/admin/watchlist modals;
      appended to <head> at runtime = last in cascade, so it stays last) ────── */

/* ── Profile & Admin Modal ─────────────────────────────── */
#profileModal{display:none;position:fixed;inset:0;z-index:550;align-items:center;justify-content:center;background:rgba(0,0,0,.75);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}
#profileModal.open{display:flex}
#profileModal .pm-card{background:#0d1117;border:1px solid #30363d;border-radius:10px;padding:28px 32px;width:480px;max-width:92vw;max-height:85vh;overflow-y:auto;font-family:'JetBrains Mono',monospace;box-shadow:0 16px 70px rgba(0,0,0,.7),0 0 0 1px rgba(255,255,255,.04);position:relative}
.pm-header{display:flex;align-items:flex-start;margin-bottom:4px}
.pm-title{font-size:.65rem;letter-spacing:2px;color:#e6edf3;font-family:'JetBrains Mono',monospace}
.pm-close{background:none;border:1px solid var(--border,#21262d);color:var(--fg-mute,#6e7681);font-size:.8rem;cursor:pointer;margin-left:auto;padding:4px 7px;font-family:'JetBrains Mono',monospace;border-radius:var(--radius-1,2px)}
.pm-tabs{display:flex;gap:0;border-bottom:1px solid #30363d;margin-bottom:18px;flex-wrap:wrap}
.pm-tab{font-family:'JetBrains Mono',monospace;font-size:.58rem;letter-spacing:2px;padding:9px 16px;background:none;border:none;border-bottom:2px solid transparent;color:var(--fg-mute,#6e7681);cursor:pointer;text-transform:lowercase}
.pm-tab.active{border-bottom-color:var(--green,#33ff66);color:var(--green,#33ff66)}
.pm-tab:hover:not(.active){color:var(--fg-2,#8b949e)}
.pm-pane{display:none}
.pm-pane.active{display:block}
.pm-section{margin-bottom:18px}
.pm-section-title{font-family:'JetBrains Mono',monospace;font-size:.55rem;letter-spacing:2px;color:#6e7681;margin-bottom:12px;padding-bottom:6px;border-bottom:1px solid #30363d}
.pm-field{margin-bottom:12px}
.pm-label{font-family:'JetBrains Mono',monospace;font-size:.56rem;letter-spacing:2px;color:#6e7681;text-transform:uppercase;margin-bottom:5px}
.pm-input{width:100%;background:#161b22;border:1px solid #21262d;color:#e6edf3;font-family:'JetBrains Mono',monospace;font-size:.76rem;padding:9px 12px;border-radius:4px;outline:none;box-sizing:border-box;transition:border-color .2s}
.pm-input:focus{border-color:var(--green,#33ff66)}
.pm-input:disabled{opacity:.5;cursor:not-allowed}
.pm-btn{font-family:'JetBrains Mono',monospace;font-size:.6rem;letter-spacing:1px;padding:8px 16px;border-radius:var(--radius-1,2px);cursor:pointer;border:1px solid;display:inline-block}
.pm-btn-primary{background:var(--green-bg,rgba(51,255,102,.1));border-color:var(--green,#33ff66);color:var(--green,#33ff66)}
.pm-btn-primary:hover{background:var(--green-bg,rgba(51,255,102,.15))}
.pm-btn-primary:disabled{opacity:.4;cursor:not-allowed}
.pm-btn-danger{background:var(--red-bg,rgba(255,46,99,.1));border-color:var(--red,#ff2e63);color:var(--red,#ff2e63)}
.pm-btn-danger:hover{background:var(--red-bg,rgba(255,46,99,.15))}
.pm-btn-secondary{background:none;border-color:var(--border,#21262d);color:var(--fg-mute,#6e7681)}
.pm-btn-secondary:hover{border-color:var(--fg-1,#d4d4d4);color:var(--fg-1,#d4d4d4)}
.pm-msg{font-size:.6rem;letter-spacing:1px;margin-top:8px;min-height:16px;font-family:'JetBrains Mono',monospace}
.pm-msg.success{color:var(--green,#33ff66)}
.pm-msg.error{color:var(--red,#ff2e63)}
.pm-badge{display:inline-block;padding:2px 8px;border-radius:3px;font-size:.56rem;letter-spacing:1.5px;text-transform:uppercase;font-weight:700;font-family:'JetBrains Mono',monospace}
.pm-badge.admin{background:rgba(0,184,255,.15);color:#00b8ff;border:1px solid rgba(0,184,255,.3)}
.pm-badge.member{background:rgba(110,118,129,.15);color:#8b949e;border:1px solid rgba(110,118,129,.3)}
.pm-user-row{display:flex;align-items:center;gap:12px;padding:12px 14px;border:1px solid #21262d;border-radius:6px;margin-bottom:8px;background:rgba(22,27,34,.5);transition:background .15s}
.pm-user-row:hover{background:rgba(255,255,255,.02)}
.pm-user-name{font-size:.72rem;color:#e6edf3;flex:1;font-family:'JetBrains Mono',monospace}
.pm-user-actions{display:flex;gap:6px;align-items:center;flex-wrap:wrap}
.pm-user-actions button{font-family:'JetBrains Mono',monospace;font-size:.52rem;letter-spacing:1px;padding:4px 10px;border-radius:var(--radius-1,2px);cursor:pointer;border:1px solid;background:none}
.pm-user-actions .btn-role{border-color:var(--border-hot,#58a6ff);color:var(--fg-1,#d4d4d4)}
.pm-user-actions .btn-role:hover{background:var(--bg-4,#1e1e1e)}
.pm-user-actions .btn-delete{border-color:var(--red,#ff2e63);color:var(--red,#ff2e63)}
.pm-user-actions .btn-delete:hover{background:var(--red-bg,rgba(255,46,99,.1))}
/* Stands where the demote button would be, for an account whose admin role is a
   standing ADMIN_DISCORD_IDS grant. Deliberately NOT button-shaped and with no
   hover state: it is a statement of where the role comes from, not a control. */
.pm-user-actions .pm-env-admin{font-family:'JetBrains Mono',monospace;font-size:.52rem;letter-spacing:1px;padding:4px 10px;border:1px dashed var(--border,#30363d);color:var(--fg-mute,#8b949e);cursor:help}
.pm-select{background:#161b22;border:1px solid #21262d;color:#e6edf3;font-family:'JetBrains Mono',monospace;font-size:.68rem;padding:5px 8px;border-radius:4px;outline:none;cursor:pointer}
.pm-create-form{background:#161b22;border:1px solid #21262d;border-radius:6px;padding:16px;margin-bottom:14px;box-shadow:inset 0 1px 3px rgba(0,0,0,.2)}
.pm-form-row{display:flex;gap:8px;align-items:flex-end;flex-wrap:wrap;margin-bottom:8px}
.pm-form-row .pm-field{margin-bottom:0;flex:1;min-width:120px}
/* Theme swatches */
.theme-grid{display:flex;flex-wrap:wrap;gap:10px;margin-top:10px}
.theme-swatch{width:90px;height:62px;border-radius:6px;cursor:pointer;border:2px solid #21262d;transition:all .2s;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;position:relative;overflow:hidden}
.theme-swatch:hover{border-color:#6e7681;transform:scale(1.05)}
.theme-swatch.active{border-color:var(--green,#33ff66);box-shadow:0 0 14px rgba(51,255,102,.25)}
.theme-swatch-label{font-family:'JetBrains Mono',monospace;font-size:.44rem;letter-spacing:1px;text-transform:uppercase;position:relative;z-index:1}
.theme-swatch-preview{position:absolute;inset:0;border-radius:4px}
/* Accent dots */
.accent-grid{display:flex;flex-wrap:wrap;gap:10px;margin-top:10px}
.accent-dot{width:30px;height:30px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all .2s}
.accent-dot:hover{transform:scale(1.15)}
.accent-dot.active{border-color:#e6edf3;box-shadow:0 0 10px rgba(255,255,255,.2)}
/* User button in header */
.user-btn{background:none;border:1px solid var(--border,#21262d);border-radius:var(--radius-1,2px);width:30px;height:30px;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--fg-mute,#6e7681);flex-shrink:0}
.user-btn:hover{border-color:var(--border-hot,#58a6ff);color:var(--fg-1,#d4d4d4)}
.pm-toggle-row{display:flex;align-items:center;justify-content:space-between;padding:10px 0;border-bottom:1px solid #21262d}
.pm-toggle-row:last-child{border-bottom:none}
.pm-toggle-label{font-family:'JetBrains Mono',monospace;font-size:.6rem;letter-spacing:1px;color:#8b949e}
.pm-toggle-sublabel{font-family:'JetBrains Mono',monospace;font-size:.48rem;letter-spacing:.5px;color:var(--fg-dim);margin-top:2px}
.pm-switch{position:relative;width:36px;height:20px;flex-shrink:0}
.pm-switch input{opacity:0;width:0;height:0}
.pm-switch-slider{position:absolute;inset:0;background:#21262d;border-radius:var(--radius-1);cursor:pointer;transition:all .2s}
.pm-switch-slider:before{content:'';position:absolute;width:16px;height:16px;left:2px;bottom:2px;background:#484f58;border-radius:50%;transition:all .2s}
.pm-switch input:checked+.pm-switch-slider{background:var(--green-bg,rgba(51,255,102,.2))}
.pm-switch input:checked+.pm-switch-slider:before{transform:translateX(16px);background:var(--green,#33ff66)}
.pm-wl-list{margin-top:8px}
.pm-wl-item{display:flex;align-items:center;gap:8px;padding:10px 12px;border:1px solid #21262d;border-radius:6px;margin-bottom:6px;background:rgba(22,27,34,.5);cursor:pointer;transition:background .15s}
.pm-wl-item:hover{background:rgba(22,27,34,.8)}
.pm-wl-item.active{border-color:var(--green,#33ff66);background:var(--green-bg,rgba(51,255,102,.05))}
.pm-wl-name{flex:1;font-family:'JetBrains Mono',monospace;font-size:.65rem;letter-spacing:1px;color:#e6edf3}
.pm-wl-count{font-family:'JetBrains Mono',monospace;font-size:.5rem;color:var(--fg-dim);letter-spacing:1px}
.pm-wl-tickers{margin-top:8px;display:flex;flex-wrap:wrap;gap:5px}
.pm-wl-chip{font-family:'JetBrains Mono',monospace;font-size:.55rem;letter-spacing:1px;padding:4px 10px;background:#161b22;border:1px solid #21262d;border-radius:4px;color:#8b949e;display:flex;align-items:center;gap:6px}
.pm-wl-chip .wl-remove{cursor:pointer;color:var(--fg-dim);font-size:.65rem;transition:color .15s}
.pm-wl-chip .wl-remove:hover{color:#ff4560}
.pm-wl-add-row{display:flex;gap:6px;margin-top:8px}
.pm-wl-add-row input{flex:1;background:#161b22;border:1px solid #21262d;color:#e6edf3;font-family:'JetBrains Mono',monospace;font-size:.65rem;padding:7px 10px;border-radius:4px;outline:none;letter-spacing:1px}
.pm-wl-add-row input:focus{border-color:#30363d}
.pm-wl-actions{display:flex;gap:6px;margin-top:6px}
.pm-wl-btn{font-family:'JetBrains Mono',monospace;font-size:.5rem;letter-spacing:1px;padding:4px 10px;border-radius:var(--radius-1,2px);cursor:pointer;border:1px solid var(--border,#21262d);background:none;color:var(--fg-mute,#6e7681)}
.pm-wl-btn-rename{color:var(--fg-1,#d4d4d4);border-color:var(--border,#21262d)}
.pm-wl-btn-rename:hover{background:var(--bg-4,#1e1e1e)}
.pm-wl-btn-delete{color:var(--red,#ff2e63);border-color:var(--red,#ff2e63)}
.pm-wl-btn-delete:hover{background:var(--red-bg,rgba(255,46,99,.1))}
.wl-star{cursor:pointer;transition:all .15s;flex-shrink:0}
.wl-star:hover{transform:scale(1.2)}
.wl-star.active svg{fill:#ffd60a;stroke:#ffd60a}
.wl-popover{position:absolute;background:#161b22;border:1px solid #30363d;border-radius:6px;padding:6px 0;min-width:160px;max-height:280px;overflow-y:auto;box-shadow:0 8px 30px rgba(0,0,0,.6);z-index:999;font-family:'JetBrains Mono',monospace}
.wl-popover-item{padding:6px 12px;font-size:.55rem;letter-spacing:1px;color:#8b949e;cursor:pointer;transition:background .1s;display:flex;align-items:center;gap:8px}
.wl-popover-item:hover{background:#21262d;color:#e6edf3}
.wl-popover-item .wl-check{color:var(--green,#33ff66);font-size:.6rem;width:12px}
.wl-popover-divider{height:1px;background:#21262d;margin:4px 0}
.wl-popover-create{padding:6px 12px;font-size:.5rem;letter-spacing:1px;color:var(--green,#33ff66);cursor:pointer;transition:background .1s}
.wl-popover-create:hover{background:#21262d}
/* Theme CSS variables — task 8.1 (design-system-adoption Req 11.3):
   --um-bg-* tokens now derive from the Design_Tokens (--bg-2, --bg-3, --border)
   rather than introducing an independent per-theme palette. The Design_Tokens are
   overridden per theme in index.html body[data-theme="…"] blocks; cascading through
   the Token_Bridge keeps the profile modal visually consistent with the page theme.
   No new hex values are introduced here (Req 11.1). */
body[data-theme="midnight"]  {--um-bg-secondary:var(--bg-2);--um-bg-tertiary:var(--bg-3);--um-border:var(--border)}
body[data-theme="deep-ocean"]{--um-bg-secondary:var(--bg-2);--um-bg-tertiary:var(--bg-3);--um-border:var(--border)}
body[data-theme="charcoal"]  {--um-bg-secondary:var(--bg-2);--um-bg-tertiary:var(--bg-3);--um-border:var(--border)}
body[data-theme="midnight"] #profileModal .pm-card,
body[data-theme="midnight"] .pm-create-form,
body[data-theme="midnight"] .pm-input{background:var(--um-bg-secondary)}
body[data-theme="midnight"] .pm-input,
body[data-theme="midnight"] .pm-select{background:var(--um-bg-tertiary);border-color:var(--um-border)}
body[data-theme="deep-ocean"] #profileModal .pm-card,
body[data-theme="deep-ocean"] .pm-create-form,
body[data-theme="deep-ocean"] .pm-input{background:var(--um-bg-secondary)}
body[data-theme="deep-ocean"] .pm-input,
body[data-theme="deep-ocean"] .pm-select{background:var(--um-bg-tertiary);border-color:var(--um-border)}
body[data-theme="charcoal"] #profileModal .pm-card,
body[data-theme="charcoal"] .pm-create-form,
body[data-theme="charcoal"] .pm-input{background:var(--um-bg-secondary)}
body[data-theme="charcoal"] .pm-input,
body[data-theme="charcoal"] .pm-select{background:var(--um-bg-tertiary);border-color:var(--um-border)}
/* Responsive */
@media(max-width:600px){
  #profileModal .pm-card{padding:18px 16px;width:100%;max-width:100vw;border-radius:0;max-height:100vh}
  .pm-tabs{overflow-x:auto;-webkit-overflow-scrolling:touch}
  .pm-tab{padding:8px 12px;font-size:.52rem}
  .pm-user-row{flex-direction:column;align-items:flex-start;gap:8px}
  .pm-user-actions{width:100%}
  .pm-form-row{flex-direction:column}
  .theme-grid{gap:6px}
  .theme-swatch{width:72px;height:50px}
}
/* ── Share Modal ───────────────────────────────────────────── */
#shareModal{display:none;position:fixed;inset:0;z-index:560;align-items:center;justify-content:center;background:rgba(0,0,0,.8);backdrop-filter:blur(6px)}
#shareModal.open{display:flex}
#shareModal .sm-card{background:#0d1117;border:1px solid #30363d;border-radius:10px;padding:24px 28px;width:460px;max-width:92vw;max-height:85vh;overflow-y:auto;font-family:'JetBrains Mono',monospace;box-shadow:0 16px 70px rgba(0,0,0,.7)}
.sm-title{font-size:.65rem;letter-spacing:2px;color:#e6edf3;margin-bottom:16px}
.sm-section{margin-bottom:16px}
.sm-section-label{font-size:.52rem;letter-spacing:2px;color:#6e7681;text-transform:uppercase;margin-bottom:8px}
.sm-mode-row{display:flex;gap:8px;margin-bottom:10px}
.sm-mode-btn{flex:1;padding:10px 12px;background:var(--bg-2,#161b22);border:1px solid var(--border,#21262d);border-radius:var(--radius-1,2px);cursor:pointer;text-align:center;font-family:'JetBrains Mono',monospace}
.sm-mode-btn:hover{border-color:var(--border-hot,#58a6ff)}
.sm-mode-btn.active{border-color:var(--border-hot,#58a6ff);background:var(--bg-3,#1e1e1e)}
.sm-mode-title{font-size:.58rem;letter-spacing:1px;color:#e6edf3;margin-bottom:2px}
.sm-mode-desc{font-size:.46rem;color:#6e7681;letter-spacing:.5px}
.sm-perm-row{display:flex;gap:8px;margin-bottom:10px}
.sm-perm-btn{flex:1;padding:8px 10px;background:var(--bg-2,#161b22);border:1px solid var(--border,#21262d);border-radius:var(--radius-1,2px);cursor:pointer;text-align:center;font-family:'JetBrains Mono',monospace;font-size:.52rem;letter-spacing:1px;color:var(--fg-2,#8b949e)}
.sm-perm-btn:hover{border-color:var(--border-hot,#58a6ff)}
.sm-perm-btn.active{border-color:var(--green,#33ff66);color:var(--green,#33ff66);background:var(--green-bg,rgba(51,255,102,.06))}
.sm-user-search{width:100%;background:#161b22;border:1px solid #21262d;color:#e6edf3;font-family:'JetBrains Mono',monospace;font-size:.65rem;padding:8px 12px;border-radius:4px;outline:none;box-sizing:border-box;letter-spacing:1px}
.sm-user-search:focus{border-color:#00b8ff}
.sm-user-dropdown{max-height:140px;overflow-y:auto;border:1px solid #21262d;border-top:none;border-radius:0 0 4px 4px;background:#161b22}
.sm-user-option{padding:7px 12px;font-size:.58rem;color:#8b949e;cursor:pointer;letter-spacing:1px;transition:background .1s;font-family:'JetBrains Mono',monospace}
.sm-user-option:hover{background:#21262d;color:#e6edf3}
.sm-selected-users{display:flex;flex-wrap:wrap;gap:5px;margin-top:8px}
.sm-user-chip{font-family:'JetBrains Mono',monospace;font-size:.52rem;letter-spacing:1px;padding:3px 8px;background:rgba(0,184,255,.1);border:1px solid rgba(0,184,255,.25);border-radius:3px;color:#00b8ff;display:flex;align-items:center;gap:5px}
.sm-user-chip .sm-chip-x{cursor:pointer;opacity:.6;font-size:.65rem;line-height:1}
.sm-user-chip .sm-chip-x:hover{opacity:1;color:#ff4560}
.sm-list-checks{max-height:120px;overflow-y:auto}
.sm-list-check{display:flex;align-items:center;gap:8px;padding:6px 8px;cursor:pointer;border-radius:4px;transition:background .1s}
.sm-list-check:hover{background:rgba(255,255,255,.03)}
.sm-list-check input{accent-color:#00b8ff}
.sm-list-check label{font-size:.58rem;color:#e6edf3;letter-spacing:1px;cursor:pointer;font-family:'JetBrains Mono',monospace}
.sm-actions{display:flex;gap:8px;justify-content:flex-end;margin-top:16px;padding-top:14px;border-top:1px solid #21262d}
/* ── Toast notifications ──────────────────────────────────── */
#mowgli-toasts{position:fixed;top:16px;right:16px;z-index:9999;display:flex;flex-direction:column;gap:8px;pointer-events:none}
.mowgli-toast{pointer-events:auto;background:#161b22;border:1px solid #30363d;border-radius:8px;padding:12px 16px;min-width:260px;max-width:360px;box-shadow:0 8px 30px rgba(0,0,0,.5);font-family:'JetBrains Mono',monospace;animation:toastIn .3s ease-out;display:flex;align-items:flex-start;gap:10px}
.mowgli-toast.removing{animation:toastOut .25s ease-in forwards}
@keyframes toastIn{from{opacity:0;transform:translateX(40px)}to{opacity:1;transform:translateX(0)}}
@keyframes toastOut{to{opacity:0;transform:translateX(40px)}}
.toast-icon{font-size:1rem;flex-shrink:0;margin-top:1px}
.toast-body{flex:1}
.toast-title{font-size:.58rem;letter-spacing:1px;color:#e6edf3;margin-bottom:2px}
.toast-desc{font-size:.5rem;color:#6e7681;letter-spacing:.5px}
.toast-close{background:none;border:none;color:#6e7681;cursor:pointer;font-size:.7rem;padding:0;flex-shrink:0;font-family:'JetBrains Mono',monospace}
.toast-close:hover{color:#ff4560}
/* ── Notification badge ───────────────────────────────────── */
.user-btn{position:relative}
.share-badge{position:absolute;top:-3px;right:-3px;background:#ff4560;color:#fff;font-size:.42rem;font-weight:700;min-width:14px;height:14px;border-radius:var(--radius-1);display:flex;align-items:center;justify-content:center;font-family:'JetBrains Mono',monospace;padding:0 3px;line-height:1;border:1.5px solid #0d1117}
.share-badge:empty{display:none}
/* ── Shared sections in watchlist pane ─────────────────────── */
.pm-invite-card{padding:12px;border:1px solid #21262d;border-radius:6px;margin-bottom:8px;background:rgba(0,184,255,.03)}
.pm-invite-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px}
.pm-invite-from{font-size:.6rem;color:#e6edf3;letter-spacing:1px;font-family:'JetBrains Mono',monospace}
.pm-invite-mode{font-size:.46rem;letter-spacing:1px;padding:2px 6px;border-radius:3px;font-family:'JetBrains Mono',monospace;text-transform:uppercase}
.pm-invite-mode.snapshot{background:var(--green-bg,rgba(51,255,102,.1));color:var(--green,#33ff66);border:1px solid rgba(51,255,102,.2)}
.pm-invite-mode.live{background:rgba(0,184,255,.1);color:#00b8ff;border:1px solid rgba(0,184,255,.2)}
.pm-invite-lists{font-size:.52rem;color:#6e7681;letter-spacing:.5px;margin-bottom:8px;font-family:'JetBrains Mono',monospace}
.pm-invite-actions{display:flex;gap:6px}
.pm-shared-item{display:flex;align-items:center;gap:8px;padding:10px 12px;border:1px solid #21262d;border-radius:6px;margin-bottom:6px;background:rgba(22,27,34,.5);cursor:pointer;transition:background .15s}
.pm-shared-item:hover{background:rgba(22,27,34,.8)}
.pm-shared-item.active{border-color:#00b8ff;background:rgba(0,184,255,.04)}
.pm-shared-badge{font-size:.42rem;letter-spacing:1px;padding:1px 5px;border-radius:2px;font-family:'JetBrains Mono',monospace;text-transform:uppercase;flex-shrink:0}
.pm-shared-badge.owner{background:var(--green-bg,rgba(51,255,102,.1));color:var(--green,#33ff66);border:1px solid rgba(51,255,102,.2)}
.pm-shared-badge.collab{background:rgba(0,184,255,.1);color:#00b8ff;border:1px solid rgba(0,184,255,.2)}
.pm-shared-badge.readonly{background:rgba(110,118,129,.1);color:#8b949e;border:1px solid rgba(110,118,129,.2)}
/* ── design-system-adoption task 5.1: .mws-panel overrides for overlay surfaces ──
   Overlay surfaces (modals, popovers) use --shadow-modal / --shadow-menu per
   Req 6.2 (overlay exception). They keep their own sizing and positioning;
   .mws-panel supplies the border-token only (inline styles win over the linked
   component sheet which uses display:flex/flex-direction:column — not suitable
   for these fixed-size, scrolling-overflow modal cards). */
#profileModal .pm-card.mws-panel{box-shadow:var(--shadow-modal,0 16px 70px rgba(0,0,0,.7),0 0 0 1px rgba(255,255,255,.04));border-color:var(--border,#262626);border-radius:var(--radius-0,0)}
#shareModal   .sm-card.mws-panel{box-shadow:var(--shadow-modal,0 16px 70px rgba(0,0,0,.7));border-color:var(--border,#262626);border-radius:var(--radius-0,0)}
.wl-popover.mws-panel{box-shadow:var(--shadow-menu,0 8px 30px rgba(0,0,0,.6));border-color:var(--border,#262626);border-radius:var(--radius-0,0);padding:0}
/* The .mws-panel__hd strip inside modals — zero border-radius inherits from panel */
.pm-card.mws-panel .mws-panel__hd,.sm-card.mws-panel .mws-panel__hd,.wl-popover.mws-panel .mws-panel__hd{border-radius:0;flex-shrink:0}
/* Panel body content area sits below the __hd strip — no extra padding needed */
.pm-card.mws-panel .pm-header,.sm-card.mws-panel>div:nth-child(2){margin-top:0}
/* Watchlist popover items sit directly in the panel after the __hd */
.wl-popover.mws-panel .wl-popover-item,.wl-popover.mws-panel .wl-popover-divider,.wl-popover.mws-panel .wl-popover-create{display:flex}

/* ══ customizable-dashboard task 5 — screener panel (in-panel controls) ══════
   The screener panel body is a column: fixed control strip + optional outcome
   line + scrolling results (the .dash-scan-* row/header rules above are
   REUSED for the rows) + fixed pager. Design law: borders not shadows, no
   hover transitions, lowercase chrome, tabular numerals inherit from rows. */
/* SCROLL REACHABILITY (pre-flip release #23, scroll half). The body was
   `overflow:hidden` with a `flex:none` control strip and a `min-height:0`
   results list. Per CSS flexbox §9.7 ALL negative free space lands on the only
   shrinkable item — the list — so as soon as controls + outcome + pager exceed
   the body height (the control strip wraps to 6-10 rows in a narrow panel,
   ~130-220px, against ~100px of body at the min 2x2 size) the list resolved to
   exactly 0px, the pager was clipped away, and NO scrollbar existed anywhere:
   the rendered rows (up to DASH_SCREENER_MAX = 100) were unreachable at any
   user-chosen small panel size.
   The two changes below are COUPLED and neither works alone: the list gets a
   min-height floor so shrinkage cannot collapse it (which is also what lets the
   column overflow the body at all), and the body scrolls so that overflow is
   reachable instead of clipped. The floor is ~the sticky header plus four rows
   (24px header + 4x25px rows). The pager STAYS: customizable-dashboard Req 7.4
   names pagination interaction as a legal query trigger, and no query fires
   from scrolling — the auto-run/fetch-on-scroll half is deliberately out. */
.mws-panel__body.dash-scr-body{display:flex;flex-direction:column;overflow-y:auto;overflow-x:hidden;padding:0}
.dash-scr-controls{display:flex;flex-wrap:wrap;gap:4px 8px;align-items:center;flex:none;padding:6px 8px;border-bottom:1px solid var(--border)}
.dash-scr-controls label{display:inline-flex;align-items:center;gap:4px;font-size:10px;letter-spacing:.04em;color:var(--fg-mute);white-space:nowrap}
.dash-scr-controls input.mws-input{width:56px;padding:2px 4px;font-size:11px;font-variant-numeric:tabular-nums}
.dash-scr-flag.is-on{color:var(--green);border-color:var(--green)}
.dash-scr-outcome{flex:none;padding:8px;font-size:11px;color:var(--fg-mute)}
.dash-scr-outcome--warn{color:var(--amber)}
.dash-scr-outcome--err{color:var(--red)}
.dash-scr-list{flex:1 1 auto;min-height:120px;overflow-y:auto;position:relative}
.dash-scr-pager{flex:none;display:flex;align-items:center;gap:8px;padding:4px 8px;border-top:1px solid var(--border);font-size:10px;color:var(--fg-mute)}

/* ══ customizable-dashboard task 10 — GEX panel ══════════════════════════════
   The GEX panel body is a scrolling column that REUSES the blade's .gex-*
   readout rules (status grid, level rows, profile bars, updated line) for the
   seam-rendered content. Panel-local chrome only here: the controls strip and
   the narrow-panel 2-up status grid. The mode buttons deliberately do NOT
   carry .gex-calc-btn — the blade's mode handler strips 'active' document-
   wide on that class (see the app.js module comment); they are .mws-btn ghost
   buttons armed via .mws-btn--armed. Design law: borders not shadows, no
   hover transitions, lowercase chrome. */
.mws-panel__body.dash-gex-body{display:flex;flex-direction:column;gap:6px;overflow-y:auto;overflow-x:hidden;padding:8px 10px}
.dash-gex-controls{display:flex;align-items:center;gap:4px;flex:none;flex-wrap:wrap}
.dash-gex-controls select.mws-input{flex:1 1 auto;min-width:0;padding:2px 4px;font-size:11px}
.dash-gex-body .gex-status-grid{grid-template-columns:repeat(2,1fr);margin:4px 0}
.dash-gex-body .gex-updated{margin-top:4px}

/* ══ customizable-dashboard task 11 — news + pulse panel bodies ══════════════
   The task-9 seam renderers emit the blade's inline-styled content; the panel
   body only adds the blade section's breathing room (.mws-panel__body already
   scrolls — mws-components.css). */
.mws-panel__body.dash-news-body,.mws-panel__body.dash-pulse-body{padding:8px 10px}

/* ══ screener-filter-panel · in-blade control re-flow ═════════════════════════
   The universe/screener controls and the whole #resultsFilterBar were authored
   as a WIDE horizontal bar — side-by-side groups with hard-coded pixel-width
   inputs (width:52px … 100px). Docked in the ~300px left blade those fixed
   widths overflowed the right edge (every min–max pair clipped its max box) and
   the mixed widths read as ragged. Everything below is scoped to #filterPanel so
   the horizontal-bar authoring is untouched anywhere else, and re-flows the
   controls into one clean, full-width vertical column. Inline width:NNpx is the
   one thing !important overrides here — inline styles can't be beaten otherwise.
   CSS-only; no markup/JS/wiring change. */

/* wide enough that the 3-across rows (sector/mcap/gex, score/Δ/5d) breathe —
   at 320 each control got ~85px and read cramped; 360 gives ~98px per cell */
body{--filter-w:360px}

/* top-level field groups → a single full-width column, consistent gaps */
#filterPanel .controls,
#filterPanel #screenerGroup,
#filterPanel #etfScreenerGroup{flex-direction:column;align-items:stretch;gap:10px}
#filterPanel .controls{padding:14px 0 12px}
#filterPanel .controls #btnReset{align-self:flex-start}
#filterPanel .ctrl-group{width:100%}

/* selects + the standalone screener number inputs fill the column width */
#filterPanel select,
#filterPanel .ctrl-group input[type=number]{width:100%!important;min-width:0!important;box-sizing:border-box}

/* results filter now lives in the blade — one column, comfortable padding */
#filterPanel .results-filter-bar{flex-direction:column;align-items:stretch;gap:14px;padding:12px}
/* header strip (title + clear/columns/gear) wraps instead of clipping/stacking text */
#filterPanel .results-filter-bar > div:first-child{flex-wrap:wrap;gap:8px}
#filterPanel .rf-title{letter-spacing:1.5px}

/* every in-row control (min–max pairs, gap/div selects) flexes to share the row,
   never a fixed pixel width that spills past the blade's right edge */
#filterPanel .results-filter-bar input[type=number],
#filterPanel .results-filter-bar select{flex:1 1 0;width:auto!important;min-width:0!important;box-sizing:border-box}

/* the min–max grouping rows (Sector·MCAP·GEX, MOWGLI SCORE, and the advanced
   RSI/SMA/GAP/DIV row) were laid side-by-side (align-items:flex-end); in the blade
   they must stack full-width so each group fills the column and its inputs get a
   definite width to flex within. flex-wrap:nowrap is load-bearing: in a WRAPPING
   column flex container align-items:stretch sizes items to the flex LINE's content
   width (up to 432px for the SCORE group), not the container's — nowrap forces one
   line that spans the blade so stretch actually clamps each group. !important beats
   the inline flex-wrap/align-items. */
#filterPanel .results-filter-bar div[style*="align-items:flex-end"]{flex-direction:column;flex-wrap:nowrap!important;align-items:stretch!important}
/* and min-width:0 clears the default min-width:auto so the inner group wrappers
   and rows can shrink to the blade instead of pinning to their min-content. */
#filterPanel .results-filter-bar div{min-width:0}

/* gex-zone chips share the row evenly, stay centred, and may shrink to fit 4-up */
#filterPanel .gex-filter-chip{flex:1 1 auto;min-width:0;justify-content:center}

/* ── Batch F: centered search palette (search-modal-hotkeys Req 8, 9) ────────
   Opened by cmd/ctrl+K; the design law for a command palette: mono, lowercase
   chrome, radius ≤ var(--radius-2) (4px — the one palette/modal allowance),
   borders not shadows, NO transitions (terminals don't ease). The backdrop
   mirrors #helpModal's; z-index 1100 sits above every closable surface
   (chart modals at 1000) and under only the login overlay — moot in practice
   because the chord closes everything first. The row grammar mirrors
   .dash-suggest__* (same three spans, same _aliasNote amber register, the
   name span owns the ellipsis). */
#searchModal{display:none;position:fixed;inset:0;z-index:1100;align-items:flex-start;justify-content:center;padding-top:16vh;background:rgba(0,0,0,.75)}
#searchModal.open{display:flex}
.search-modal__card{width:560px;max-width:92vw;border-radius:var(--radius-2);overflow:hidden}
.search-modal__hint{text-transform:lowercase}
.search-modal__input{margin:10px;border-radius:var(--radius-1)}
.search-modal__list{max-height:320px;overflow-y:auto;padding-bottom:6px;font-family:var(--font-mono);font-size:.68rem}
.search-modal__item{display:flex;gap:10px;align-items:baseline;padding:5px 14px;cursor:pointer}
.search-modal__item:hover,.search-modal__item.is-active{background:var(--bg-4)}
.search-modal__sym{color:var(--green)}
.search-modal__alias{color:var(--amber);flex-shrink:0}
.search-modal__name{color:var(--fg-mute);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.search-modal__note{padding:6px 14px;color:var(--fg-dim);letter-spacing:1px}
