/* ============================================================
   Stock Dabbler — Card Stack Design System
   Fonts: Space Grotesk (headings) + DM Sans (body)
   Theme: Light / warm off-white + coral accent + charcoal darks
   ============================================================ */

/* font-size bare-dot spelling normalised to the leading-zero 0.NN form
   (A5, purely cosmetic — identical rendered size). */
/* @trace code:my9vs8r56g req:y6zckf2fhy */

/* === Reset & Base === */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; caret-color: transparent; }
input, textarea, select, [contenteditable] { caret-color: auto; }

:root {
  /* @trace req:4881 — make native controls (date picker, scrollbars, select
     popups) follow the theme; the dark override lives in [data-theme="dark"]
     so the date input's calendar renders dark-on-dark, not a white popup. */
  color-scheme: light;
  --bg: #f5f5f0;
  --bg-card: #ffffff;
  --bg-hover: #f0f0eb;
  --bg-inset: #eeeee8;
  /* @trace code:3241 req:4244
      — elevated-surface shade for popups
     (e.g. `.dropdown-menu`) that open over a `.card`. Must stay
     visibly distinct from --bg-card (else the popup blends into the
     card and reads as transparent) and distinct from --bg-hover (else
     item hover-state disappears). Matches the page `--bg` shade so the
     popup reads as "the page surface", clearly different from the
     white card it overlays. */
  --bg-elev: #f5f5f0;
  --border: #e5e5e0;
  --border-strong: #d4d4cf;
  --text: #1a1a1a;
  --text-dim: #606874;
  --text-muted: #697179;
  --charcoal: #1a1a1a;
  --charcoal-light: #2a2a2a;
  --accent: #f97316;
  --accent-light: #fb923c;
  --accent-dark: #ea580c;
  --accent-bg: #fff7ed;
  --green: #22c55e;
  --red: #ef4444;
  --yellow: #eab308;
  --orange: #f97316;
  /* Amber "note"/caution token — names the already-shipped strategies.ts
     note-triad hexes so the note box themes with its siblings (B2b). */
  /* @trace code:0amdtec4mz req:2bx44384e5 */
  --amber: #8a6d00;
  --amber-bg: #fff8e1;
  --amber-border: #f3d28a;
  --fit: #dcfce7;
  --fit-text: #166534;
  --poor-fit: #fee2e2;
  --poor-fit-text: #991b1b;
  --weak-fit: #fef9c3;
  --weak-fit-text: #854d0e;
  --radius: 12px;
  --radius-sm: 8px;
  --radius-lg: 18px;
  --shadow-sm: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
  --shadow: 0 4px 6px rgba(0,0,0,0.05), 0 2px 4px rgba(0,0,0,0.04), 0 10px 20px rgba(0,0,0,0.03);
  --shadow-lg: 0 10px 25px rgba(0,0,0,0.08), 0 6px 10px rgba(0,0,0,0.05), 0 20px 40px rgba(0,0,0,0.04);
  --shadow-xl: 0 15px 35px rgba(0,0,0,0.1), 0 10px 15px rgba(0,0,0,0.06), 0 25px 50px rgba(0,0,0,0.06);
  --shadow-dark: 0 10px 25px rgba(0,0,0,0.2), 0 6px 10px rgba(0,0,0,0.15);
}

/* === Dark Mode === */
[data-theme="dark"] {
  color-scheme: dark; /* @trace req:4881 — native controls render dark */
  --bg: #111113;
  --bg-card: #1c1c1f;
  --bg-hover: #252528;
  --bg-inset: #18181b;
  /* @trace code:3242 req:4244
      — see :root note. Visibly lighter than
     --bg-card so the popup reads as elevated; also clearly above
     --bg-hover so item hover-feedback stays visible against the menu. */
  --bg-elev: #2c2c30;
  --border: #2e2e33;
  --border-strong: #3a3a40;
  --text: #e8e8ec;
  --text-dim: #8b8b95;
  --text-muted: #8a8a94;
  --charcoal: #e8e8ec;
  --charcoal-light: #d4d4da;
  --accent-bg: rgba(249,115,22,0.12);
  --fit: #16351e;
  --fit-text: #86efac;
  --poor-fit: #351616;
  --poor-fit-text: #fca5a5;
  --weak-fit: #352e0e;
  --weak-fit-text: #fde68a;
  --shadow-sm: 0 1px 3px rgba(0,0,0,0.3), 0 1px 2px rgba(0,0,0,0.2);
  --shadow: 0 4px 6px rgba(0,0,0,0.3), 0 2px 4px rgba(0,0,0,0.2), 0 10px 20px rgba(0,0,0,0.15);
  --shadow-lg: 0 10px 25px rgba(0,0,0,0.4), 0 6px 10px rgba(0,0,0,0.3), 0 20px 40px rgba(0,0,0,0.2);
  --shadow-xl: 0 15px 35px rgba(0,0,0,0.5), 0 10px 15px rgba(0,0,0,0.3), 0 25px 50px rgba(0,0,0,0.25);
  --shadow-dark: 0 10px 25px rgba(0,0,0,0.6), 0 6px 10px rgba(0,0,0,0.4);
}

[data-theme="dark"] .header {
  background: rgba(17, 17, 19, 0.85);
}

[data-theme="dark"] .hero-badge {
  background: var(--bg-card);
  color: var(--text);
}

[data-theme="dark"] .hero-btn-secondary {
  color: var(--text);
  border-color: var(--border);
}
[data-theme="dark"] .hero-btn-secondary:hover {
  border-color: var(--text);
}

[data-theme="dark"] .landing-feature-card.dark {
  background: #0e0e10;
  border-color: #1a1a1d;
}

[data-theme="dark"] .landing-stat-card:nth-child(2) {
  background: #0e0e10;
  border-color: #1a1a1d;
}

[data-theme="dark"] .hiw-num {
  background: #0e0e10;
}

[data-theme="dark"] .cta-card {
  background: #0e0e10;
}

[data-theme="dark"] .tag-market { background: #1e2a3f; color: #7cb9f7; }
[data-theme="dark"] .tag-strongfit, [data-theme="dark"] .class-STRONG-FIT, [data-theme="dark"] .class-STRONG_FIT { background: #0f2918; color: #4ade80; }
[data-theme="dark"] .tag-nofit, [data-theme="dark"] .class-NO-FIT, [data-theme="dark"] .class-NO_FIT { background: #2a0f0f; color: #f87171; }
[data-theme="dark"] .class-PENDING { background: var(--bg-inset); color: var(--text-muted); }

[data-theme="dark"] .chip {
  background: rgba(249,115,22,0.12);
  border-color: rgba(249,115,22,0.25);
  color: var(--accent-light);
}

[data-theme="dark"] .company-logo {
  background: var(--bg-inset);
}

[data-theme="dark"] .chart-loading {
  background: rgba(17, 17, 19, 0.8);
}

[data-theme="dark"] .pricing-card.featured {
  background: #0e0e10;
  border-color: #1a1a1d;
}

/*
 * @trace code:3167 req:4143
 * Deliberate-link colour contract: every bare <a> / <router-link> in
 * the app renders in --accent (#f97316), matching the convention
 * already followed by .analyst-link, .ext-link, .source-link a,
 * .description-meta a, .research-source-list a. Without this rule the
 * user-agent stylesheet's blue/purple wins, which is unreadable
 * against --bg-card on dark and clashes on light. The selector is
 * intentionally low-specificity (0,0,1) so every class-level override
 * (.btn, .footer-link, .hl-ticker-link, .col-symbol a, etc.) keeps
 * winning on the cascade — the new rule only kicks in for anchors
 * that previously had no explicit colour.
 */
a, a:visited { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

/* Theme toggle button */
.theme-toggle {
  background: none;
  border: 1px solid var(--border);
  color: var(--text-dim);
  width: 32px; height: 32px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: all .2s;
  font-size: 1rem;
  padding: 0;
  flex-shrink: 0;
}
.theme-toggle:hover {
  color: var(--accent);
  border-color: var(--accent);
  background: var(--accent-bg);
}

html { scroll-behavior: smooth; overflow-x: hidden; }

body {
  font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background: var(--bg);
  color: var(--text);
  line-height: 1.6;
  min-height: 100vh;
  overflow-x: hidden;
}

h1, h2, h3, h4, h5, h6 {
  font-family: 'Space Grotesk', sans-serif;
  line-height: 1.2;
}

/* === Footer === */
.site-footer {
  padding: 20px 24px; padding-bottom: max(20px, env(safe-area-inset-bottom)); margin-top: 40px;
  border-top: 1px solid var(--border);
  text-align: center; font-size:0.75rem; color: var(--text-muted);
  line-height: 1.5;
}
.footer-link { color: var(--text-muted); text-decoration: underline; }
.footer-link:hover { color: var(--text-dim); }

/* Busy state */
.busy { opacity: .6; }

/* AI working modal */
.ai-modal { max-width: 320px; margin: 0 auto; text-align: center; padding: 40px 32px; }
.ai-modal-content { display: flex; flex-direction: column; align-items: center; gap: 12px; }
.ai-modal-content h3 { font-size: 1.1rem; }
.ai-modal-content .text-dim { font-size:0.85rem; }
/* @trace req:4820 — stepped filter-generation progress shown in the working
   modal: an ordered phase list above a fill bar, current phase highlighted. */
.filter-progress { width: 100%; display: flex; flex-direction: column; gap: 10px; }
.filter-progress-steps { display: flex; flex-wrap: wrap; justify-content: center; gap: 4px 10px; }
.filter-progress-step { font-size:0.72rem; color: var(--text-dim); opacity: .5; }
.filter-progress-step.done { opacity: .9; color: var(--text); }
.filter-progress-step.active { opacity: 1; color: var(--accent); font-weight: 600; }

/* === Header === */
.header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* req:4641 — floor the edge padding with the safe-area insets so the sticky
     header clears the notch / status bar under viewport-fit=cover (req:4639). */
  padding: max(14px, env(safe-area-inset-top)) max(24px, env(safe-area-inset-right)) 14px max(24px, env(safe-area-inset-left));
  border-bottom: 1px solid var(--border);
  background: rgba(245, 245, 240, 0.85);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  position: sticky;
  top: 0;
  z-index: 100;
}

.header-left { display: flex; align-items: center; gap: 12px; }
.header h1 {
  font-family: 'Space Grotesk', sans-serif;
  font-size: 1.2rem; font-weight: 700; color: var(--charcoal);
}
.stock-count { color: var(--text-dim); font-size:0.85rem; }

.nav-logo-icon {
  width: 32px; height: 32px;
  background: var(--accent);
  border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  color: white; font-family: 'Space Grotesk', sans-serif;
  font-size: 13px; font-weight: 700;
  transform: rotate(-3deg);
  box-shadow: var(--shadow-sm);
  flex-shrink: 0;
}

.user-menu { position: relative; }
.user-menu-trigger { cursor: pointer; }
.user-menu-dropdown {
  position: absolute; right: 0; top: 100%; margin-top: 4px;
  background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 12px; min-width: 200px; z-index: 200;
  display: flex; flex-direction: column; gap: 6px;
  box-shadow: var(--shadow-lg);
}
.user-menu-header { display: flex; flex-direction: column; gap: 2px; }
.user-menu-header small { color: var(--text-dim); font-size:0.8rem; }
.user-menu-dropdown hr { border: none; border-top: 1px solid var(--border); margin: 4px 0; }
.user-menu-dropdown .btn { text-align: left; width: 100%; }

/* === Symbol drilldown ☰ actions menu (req:4800) === */
.symbol-menu-item:hover { background: var(--bg-hover, rgba(0, 0, 0, 0.05)); }
.symbol-menu-item.active { color: var(--accent); font-weight: 500; }

/* === Buttons === */
.btn {
  background: var(--bg-card);
  color: var(--text);
  border: 1px solid var(--border);
  padding: 4px 12px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-family: 'DM Sans', sans-serif;
  font-size:0.8rem;
  font-weight: 500;
  transition: all .2s;
  box-shadow: var(--shadow-sm);
  text-decoration: none;
}
.btn:hover { background: var(--bg-hover); border-color: var(--border-strong); transform: translateY(-1px); box-shadow: var(--shadow); text-decoration: none; }
.btn.active {
  background: var(--accent); border-color: var(--accent); color: #fff;
  box-shadow: 0 4px 12px rgba(249,115,22,0.3);
}
.btn.active:hover { background: var(--accent-dark); }
.btn-sm { padding: 4px 12px; font-size:0.8rem; }
.btn-back { padding: 4px 12px; font-size:0.8rem; }
.btn:disabled { opacity: .5; cursor: not-allowed; }

/* Primary CTA button */
.btn-primary {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--accent); color: white;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 600; font-size:0.8rem;
  padding: 4px 12px; border-radius: var(--radius-sm);
  text-decoration: none; border: none; cursor: pointer;
  box-shadow: 0 4px 14px rgba(249,115,22,0.3);
  transition: transform .2s, box-shadow .3s, background .2s;
}
.btn-primary:hover:not(:disabled) { background: var(--accent-dark); transform: translateY(-2px); box-shadow: 0 6px 20px rgba(249,115,22,0.4); }
.btn-primary:disabled { opacity: .5; cursor: not-allowed; transform: none; box-shadow: none; }

/* Danger button */
/* @trace code:81kz2d3jkx req:dnagzmpttj */
/* Danger/success surfaces use the canonical themed --red/--green tokens.
   The former --color-danger/--color-success names were never defined at
   :root, so their call sites were pinned to hardcoded fallback hex — bug B1. */
.btn-danger {
  background: var(--red); color: #fff; border-color: var(--red);
  font-weight: 600; white-space: nowrap;
}
.btn-danger:hover { background: #c9302c; border-color: #c9302c; transform: translateY(-1px); box-shadow: 0 4px 12px rgba(217,83,79,0.35); }
.btn-danger:disabled { opacity: .5; cursor: not-allowed; transform: none; box-shadow: none; }

/* === Tags === */
.tag, .tag-sm {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 20px;
  font-size:0.75rem;
  font-weight: 600;
  letter-spacing: .02em;
}
.tag { font-size:0.8rem; padding: 3px 12px; }
.tag-market { background: #e0f2fe; color: #0369a1; }
.tag-score { background: var(--bg-inset); color: var(--text); }
.tag-fit, .class-FIT { background: var(--fit); color: var(--fit-text); }
.tag-strongfit, .class-STRONG-FIT, .class-STRONG_FIT { background: #bbf7d0; color: #14532d; }
.tag-poorfit, .class-POOR-FIT, .class-POOR_FIT { background: var(--poor-fit); color: var(--poor-fit-text); }
.tag-nofit, .class-NO-FIT, .class-NO_FIT { background: #fecaca; color: #7f1d1d; }
.tag-weakfit, .class-WEAK-FIT, .class-WEAK_FIT { background: var(--weak-fit); color: var(--weak-fit-text); }
.class-PENDING { background: var(--bg-inset); color: var(--text-muted); }
.text-green { color: #16a34a; }
.text-red { color: #dc2626; }
.text-muted { color: var(--text-muted); }

/* === Filters === */
.filters {
  display: flex; flex-wrap: wrap; gap: 12px;
  padding: 16px 24px;
  background: var(--bg-card);
  border-bottom: 1px solid var(--border);
  align-items: end;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  box-shadow: var(--shadow-sm);
}

/* req:4159 — on the Scan Results page only, the filter bar is followed
   by a separate .scan-results-card (not a fused table-wrap), so the
   bar gets all-corner rounding + a 16px gap underneath. Scoped via the
   page's section-scan-results data-test attribute so Notes / Stock
   Drilldown / Portfolio (the other four .filters callers) keep their
   original flat-bottom shape that butts against their table. */
[data-test="section-scan-results"] .filters {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  margin-bottom: 16px;
}

/* req:4159 — bumped gap from 4px to 8px so the uppercase mini-label
   no longer sits flush against the dropdown's top border. The label
   colour moves to text-muted (a touch lighter than text-dim, which is
   the same value used inside the field) so the label visually sits
   above the input rather than blending with it. */
.filter-group { display: flex; flex-direction: column; gap: 8px; }
.filter-group label { font-size:0.75rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: .05em; font-family: 'Space Grotesk', sans-serif; font-weight: 600; }
.filter-group select, .filter-group input {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  padding: 6px 10px;
  border-radius: var(--radius-sm);
  font-size:0.85rem;
  min-width: 100px;
  font-family: 'DM Sans', sans-serif;
}
.filter-group select { min-width: 140px; }
.filter-group input[type="text"] { min-width: 180px; }
.filter-group input[type="number"] { width: 70px; }
.filter-checkbox { justify-content: flex-end; padding-bottom: 6px; }
.filter-checkbox label { display: flex; align-items: center; gap: 4px; font-size:0.85rem; color: var(--text); text-transform: none; cursor: pointer; white-space: nowrap; }
.filter-checkbox input[type="checkbox"] { min-width: auto; width: 16px; }

/* Wrapper card around the scan results table. Gives the page a
   consistent rounded-card frame matching the filter bar above.

   @trace code:3168 req:4962
   req:4962 — the table region scrolls INTERNALLY so its horizontal
   scrollbar is always reachable. The app scrolls on the body under a
   sticky header, so the previous fixed `max-height: 70vh` cap left the
   wrap's bottom edge (where the horizontal scrollbar lives) below the
   fold on a long list — you had to scroll the whole page to the very
   bottom to use it. Instead the results PANEL is bounded to the viewport
   (height = 100dvh minus the chrome above it: sticky header + list
   header + tabs + filters ≈ 13rem; dvh tracks mobile browser UI) and
   laid out as a flex column; the card + .table-wrap flex-fill it, so the
   table runs from the chrome down to the viewport foot and the
   horizontal scrollbar pins on-screen. min-height keeps it usable on
   short viewports (the page just scrolls). The .stock-table thead is
   position:sticky so the column header pins to the top of the wrap as
   rows scroll past. Scoped to the results panel so the Charts tab and
   every other .table-wrap are untouched. */
[data-test="panel-scan-results"] {
  display: flex;
  flex-direction: column;
  height: calc(100dvh - 13rem);
  min-height: 320px;
}
.scan-results-card {
  padding: 0;
  overflow: hidden;
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.scan-results-card > .table-wrap {
  padding: 8px;
  flex: 1;
  min-height: 0;
  max-height: none;
  overflow: auto;
}

/* === Table === */
/* req:4176 — slim themed scrollbars on every overflowing table region.
   Firefox honours scrollbar-width / scrollbar-color; Chromium/WebKit
   honours the ::-webkit-scrollbar pseudo-elements. Both axes get 8px
   because Scan Results scrolls horizontally (wide measure-column
   table) AND vertically (max-height: 70vh wrap). qa.yaml does not
   scan CSS, so the requirement linkage is pinned by the vitest in
   tests/ts/scrollbar_slim_tablewrap.test.ts rather than a @trace
   marker here. */
.table-wrap {
  overflow-x: auto;
  padding: 0 8px;
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}
.table-wrap::-webkit-scrollbar { width: 8px; height: 8px; }
.table-wrap::-webkit-scrollbar-track { background: transparent; }
.table-wrap::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border-radius: 4px;
}
.table-wrap::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }

.stock-table {
  width: 100%;
  border-collapse: collapse;
  font-size:0.85rem;
  background: var(--bg-card);
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
  overflow: hidden;
}

.stock-table th {
  position: sticky; top: 0;
  background: var(--bg-card);
  padding: 10px 12px;
  text-align: left;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 600;
  color: var(--text-dim);
  font-size:0.75rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  border-bottom: 2px solid var(--border);
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}

.stock-table th:hover { color: var(--text); }
.stock-table th.sort-asc::after { content: ' \25b2'; font-size:0.65rem; }
.stock-table th.sort-desc::after { content: ' \25bc'; font-size:0.65rem; }

.stock-table td {
  padding: 8px 12px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

.stock-table tbody tr { cursor: pointer; transition: background .15s; }
.stock-table tbody tr:hover { background: var(--bg-hover); }
/* req:4165 — stock-table variant with non-navigable rows (e.g. the
   sim-group Aggregate stats table where each row is one metric, not a
   clickable item). Drops the pointer cursor and the hover-highlight so
   the user isn't misled into clicking. */
.stock-table.table-static tbody tr { cursor: default; }
.stock-table.table-static tbody tr:hover { background: transparent; }
/* req:4966 — a static table whose rows are individually navigable (the
   All-Scans history page: a completed scan row links to its report, but
   running / 0-candidate rows do not). Restore the click affordance only on
   the rows that actually navigate, leaving the rest with the static default. */
.stock-table.table-static tbody tr.row-clickable { cursor: pointer; }
.stock-table.table-static tbody tr.row-clickable:hover { background: var(--bg-hover); }

.stock-table .col-sticky-left { position: sticky; left: 0; background: var(--bg-card); z-index: 1; }
.stock-table thead .col-sticky-left { z-index: 2; }
.stock-table tbody tr:hover .col-sticky-left { background: var(--bg-hover); }

.col-symbol { font-weight: 600; color: var(--accent); }
.col-symbol a { color: inherit; text-decoration: none; }
.col-name { max-width: 200px; overflow: hidden; text-overflow: ellipsis; color: var(--text-dim); }
.col-num { text-align: right; font-variant-numeric: tabular-nums; }
.col-center { text-align: center; }

/* req:4625 — a scan-results cell whose value's two independent sources
   disagree (likely-bad source data, e.g. a baby bond's bogus dividend
   yield). The number is shown unchanged; this just flags it for review.
   Amber tint + help cursor; the cell's title carries the explanation. */
.stock-table td.cell-warn {
  background: color-mix(in srgb, var(--orange) 18%, transparent);
  color: var(--orange);
  font-weight: 600;
  cursor: help;
}
.stock-table td.cell-warn::after { content: " \26A0"; font-size:0.85em; }

/*
 * @trace code:3169 req:4026
 * Source-article link inside the analyst-estimates stock-tables
 * (grade-change + price-target rows). The browser-default link colour
 * (blue/purple) is unreadable against --bg-card on the dark theme;
 * --accent (#f97316, the same orange every other deliberate link in
 * the app uses — `.source-link a`, `.description-meta a`) restores
 * contrast in both themes.
 */
.analyst-link {
  color: var(--accent);
  text-decoration: none;
}
.analyst-link:hover { text-decoration: underline; }

/*
 * @trace code:3170 req:4149
 * Dashboard Portfolio News headline cell. The shared `.stock-table td`
 * rule pins `white-space: nowrap` so analyst/score/scan cells stay on
 * one line; news headlines are free-form sentences and overflow the
 * card horizontally under that default. Scope the wrap behaviour to
 * this column only so sibling stock-tables remain single-line.
 * `overflow-wrap: anywhere` lets the browser break inside long
 * unbroken tokens (URL-like strings) while still preferring whitespace
 * breaks for normal titles.
 */
.stock-table td.news-headline-cell {
  white-space: normal;
  overflow-wrap: anywhere;
}

.score-pill {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 20px;
  font-size:0.8rem;
  font-weight: 600;
}
.score-high { background: var(--fit); color: var(--fit-text); }
.score-mid { background: var(--weak-fit); color: var(--weak-fit-text); }
.score-low { background: var(--poor-fit); color: var(--poor-fit-text); }

/* Stale-score chip treatments (req:4945). Redundant encoding — outline
   style + trailing glyph, never colour alone — so the signal survives in
   greyscale and for colour-blind users. `outline` (not `border`) avoids
   layout shift on the dense holdings tables. Applied alongside the normal
   score-pill / tag-sm / dash-holding-* classes. */
.stale-aged {
  filter: saturate(0.45) opacity(0.72);
  outline: 1px dashed var(--text-muted);
  outline-offset: 1px;
}
.stale-aged::after {
  content: " \23f0"; /* ⏰ alarm clock */
  font-size: 0.85em;
}
.stale-invalidated {
  outline: 1px dashed var(--poor-fit);
  outline-offset: 1px;
}
.stale-invalidated::after {
  content: " \26a0"; /* ⚠ warning sign */
  font-size: 0.85em;
}

/* Shared <score-chip> capsule wrapper — score pill + class tag rendered
   identically on every surface (req:4945). */
.score-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.held-dot { color: var(--accent); font-size: 1rem; }

/* === Detail View === */
.detail-view { padding: 0 24px 40px; max-width: 1200px; margin: 0 auto; }

.detail-header {
  padding: 20px 0;
  display: flex;
  align-items: flex-start;
  gap: 20px;
}

.detail-title h2 { font-size: 1.4rem; display: flex; align-items: center; gap: 10px; }
.symbol-badge {
  background: var(--accent);
  color: #fff;
  padding: 2px 10px;
  border-radius: 8px;
  font-size: 1rem;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
}
.detail-meta { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
/* @trace req:4696 code:2100 — the one tab-strip container layout. Every
   tab list (admin/portfolio/dashboard strips, perf-report tabs, the
   filter-error-modal tabs) uses this class instead of re-declaring the
   flex row inline; tabs inside are tab-link / tab-button (.tab-link).
   The ≤768px media block overrides flex-wrap to nowrap + scroll. */
.tab-strip {
  display: flex;
  align-items: center;
  gap: 0;
  flex-wrap: wrap;
  border-bottom: 2px solid var(--border);
  margin-bottom: 1.5rem;
}

/* === Cards — Card Stack Signature === */
.card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 20px;
  margin-bottom: 16px;
  box-shadow: var(--shadow);
  transition: transform .3s cubic-bezier(0.22, 1, 0.36, 1), box-shadow .3s;
}
.card:hover {
  box-shadow: var(--shadow-lg);
}

.card h3 { font-size: 1rem; margin-bottom: 12px; color: var(--text); }

/* Dark card variant */
.card-dark {
  background: var(--charcoal);
  color: #fff;
  border-color: var(--charcoal-light);
}
.card-dark h3 { color: #fff; }
.card-dark .text-dim { color: var(--text-muted); }

/* === Description === */
.card-description { background: var(--bg-card); }
.description-row { display: flex; gap: 16px; align-items: flex-start; }
.company-logo { width: 56px; height: 56px; border-radius: var(--radius); object-fit: contain; background: var(--bg); padding: 4px; flex-shrink: 0; }
.description-text p { font-size:0.9rem; color: var(--text-dim); line-height: 1.6; margin-bottom: 8px; }
.description-meta { display: flex; flex-wrap: wrap; gap: 16px; font-size:0.8rem; color: var(--text-muted); }
.description-meta a { color: var(--accent); text-decoration: none; }
.description-meta a:hover { text-decoration: underline; }

/* === Verdict === */
.card-verdict { border-left: 4px solid var(--border); }
.card-verdict h3 { display: flex; align-items: center; margin-bottom: 12px; }
.verdict-body {
  padding: 10px 14px; background: var(--bg); border-radius: var(--radius-sm);
  font-size:0.85rem; color: var(--text-dim); line-height: 1.6;
}
.verdict-body p { margin-bottom: 8px; }
.verdict-body p:last-child { margin-bottom: 0; }
.verdict-body strong { color: var(--text); }
.verdict-fit { border-left-color: var(--green); }
.verdict-strong-fit { border-left-color: var(--green); }
.verdict-poor-fit { border-left-color: var(--red); }
.verdict-no-fit { border-left-color: var(--red); }
.verdict-weak-fit { border-left-color: var(--yellow); }
.card-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.card-header h3 { margin-bottom: 0; }

.card-holdings { border-color: var(--accent); border-width: 2px; }

/* === Metrics Row === */
.metrics-row {
  display: flex; gap: 12px;
  margin-bottom: 16px;
  flex-wrap: wrap;
}
.metric-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px 20px;
  flex: 1;
  min-width: 140px;
  box-shadow: var(--shadow-sm);
}
.metric-label { font-size:0.75rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: .04em; font-family: 'Space Grotesk', sans-serif; font-weight: 600; }
.metric-value { font-size: 1.2rem; font-weight: 600; margin-top: 4px; font-family: 'Space Grotesk', sans-serif; }

/* === Holdings === */
.holdings-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px; }
.holding-item { display: flex; flex-direction: column; }
.holding-label { font-size:0.75rem; color: var(--text-dim); text-transform: uppercase; font-family: 'Space Grotesk', sans-serif; font-weight: 600; }
.holding-value { font-size: 1.1rem; font-weight: 600; font-family: 'Space Grotesk', sans-serif; }
.holding-total .holding-value { font-size: 1.2rem; }
.holdings-history { margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--border); cursor: pointer; }
.holdings-history h4 { font-size:0.85rem; color: var(--text-dim); margin-bottom: 8px; }
.toggle-arrow { font-size:0.7rem; margin-left: 4px; }
.recommendation { margin-top: 12px; color: var(--text-dim); font-style: italic; font-size:0.9rem; line-height: 1.5; }

/* === Scoring === */
.scoring-grid { display: flex; flex-direction: column; gap: 12px; }
.scoring-item {
  padding: 12px;
  background: var(--bg);
  border-radius: var(--radius-sm);
  border-left: 4px solid var(--border);
}
/* @trace code:? req:4260 — scope the rating colour-coding to the
   item's header only. Pre-fix `:has(.rating-X)` walked the entire
   subtree including sub-row badges (req:4254 composite-reference
   breakdown), so a composite row's left-border colour flipped
   between collapsed (parent badges only) and expanded (parent +
   sub-row badges, last-matching-rule wins) states. Restricting to
   the header keeps the parent's own score class as the sole driver. */
.scoring-item:has(> .scoring-header .rating-pass) { border-left-color: var(--green); }
.scoring-item:has(> .scoring-header .rating-marginal) { border-left-color: var(--yellow); }
.scoring-item:has(> .scoring-header .rating-fail) { border-left-color: var(--red); }

/* @trace code:? req:4259 — composite/reference criterion styling.
   Pre-req:4259 the parent reference row carried an accent-tinted
   left border + lighter background so the "this is a composite
   signal" read at a glance — but the ``:has(.rating-X)`` rules above
   match sub-row badges too, which made the left-border colour shift
   between collapsed (parent badges only) and expanded (parent +
   sub-row badges, last-matching-class wins) states. The user asked
   for matching colour in both states, so the dedicated reference
   styling is dropped entirely: a composite row looks identical to
   any other criterion row; the chevron toggle is the only visual
   cue that it's foldable. */

/* @trace code:? req:4260 — disclosure toggle on composite reference
   rows. ``position: absolute`` so it leaves the flex flow entirely:
   the criterion name flushes left at the same x-coordinate as every
   non-reference row's name, and the chevron lives in the padding
   gutter between the colored left bar (4px) and the content. Width
   plus the ``left`` offset leave ~4px clearance from the bar so the
   chevron doesn't visually fuse with it. */
.scoring-ref-toggle {
  position: absolute;
  left: -8px;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  color: var(--text-dim);
  font-size:0.7rem;
  line-height: 1;
  width: 10px;
  height: 10px;
  text-align: center;
}
.scoring-ref-toggle:hover { color: var(--text); }
/* @trace code:? req:4261 — small left margin so the chevron (which
   protrudes ~2px into the content area at left:-8 / width:10) has
   visible breathing room before the name starts. */
.scoring-ref-name { user-select: none; margin-left: 6px; }
/* @trace code:? req:4262 — composite-reference sub-rows now reuse
   the full ``.scoring-item`` markup so they pick up the same colored
   left bar, padding, badges, and metric pills as parent rows. The
   wrapping container's only job is to indent + cluster them as
   "nested under the parent". The dedicated sub-row styles from
   req:4254/4255/4260 are gone — duplicating the parent's visual
   language inside ``.scoring-subrows`` was busy and the user asked
   for one shared layout. */
.scoring-subrows {
  margin-top: 8px;
  padding-left: 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
/* @trace code:? req:4263 — nested sub-cards get a 1px ``--border``
   outline so each sub-card is visibly distinct from its sibling and
   from the parent reference row's background (both share the same
   ``--bg`` light grey, otherwise they'd merge into one block). The
   colour matches the design-system separator the rest of the app
   uses for subtle delineation between same-tone surfaces. */
.scoring-subrows .scoring-item {
  border: 1px solid var(--border);
}

.scoring-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; position: relative; }
.scoring-name { font-weight: 600; font-size:0.9rem; }
.scoring-badge {
  padding: 2px 10px;
  border-radius: 20px;
  font-size:0.75rem;
  font-weight: 700;
}
.rating-pass { background: var(--fit); color: var(--fit-text); }
.rating-marginal { background: var(--weak-fit); color: var(--weak-fit-text); }
.rating-fail { background: var(--poor-fit); color: var(--poor-fit-text); }
.scoring-badges { display: flex; gap: 6px; align-items: center; }
/*
 * .scoring-override carries the manual-override badge AND the
 * AI-override badge. The badge must look like a peer .scoring-badge
 * (rounded coloured pill); the rating-pass / rating-marginal /
 * rating-fail class drives the colour. Only the letter-spacing tweak
 * remains as a subtle differentiator. The previous variant (smaller
 * font, italic, dim text, var(--bg-offset) background) overrode the
 * bubble look and beat the rating-* colours — see req:4022.
 */
.scoring-override {
  letter-spacing: .02em;
}
/* @trace req:4227 — importance pills on per-criterion drilldown rows.
 * Critical = red, major = amber, standard = neutral grey, nice = dim.
 * Sits in the same .scoring-badges flex strip as the score pill. */
.importance-badge {
  letter-spacing: .03em;
  text-transform: uppercase;
  font-size:0.7rem;
  padding: 1px 8px;
}
.importance-critical { background: var(--red, #c0392b); color: #fff; }
.importance-major { background: var(--yellow, #d68910); color: #1f1f1f; }
.importance-standard { background: var(--bg-offset, #555); color: var(--text-dim, #ddd); }
.importance-nice_to_have { background: transparent; color: var(--text-dim, #888); border: 1px dashed var(--text-dim, #666); }
.critical-fail-badge {
  background: var(--red, #c0392b);
  color: #fff;
  font-size:0.7rem;
  letter-spacing: .03em;
  text-transform: uppercase;
}
/* Importance selector inside filter editor — same colour cues as the badges */
.importance-select {
  font-size:0.75rem;
  padding: 2px 6px;
  border-radius: 4px;
  border: 1px solid var(--border, #444);
  font-weight: 600;
  /* Default chip colours when no importance-* class is active. */
  background: var(--bg-card);
  color: var(--text);
}
/* The dropdown popup (<option> children) inherits browser defaults
 * unless we style it explicitly — without this rule, opening the
 * dropdown shows light-grey text on a white panel that is unreadable
 * in dark mode. Pin both layers to the theme's card / text vars. */
.importance-select option {
  background: var(--bg-card);
  color: var(--text);
  font-weight: 600;
}
.importance-select.importance-critical { background: var(--red, #c0392b); color: #fff; }
.importance-select.importance-major { background: var(--yellow, #d68910); color: #1f1f1f; }
.importance-select.importance-standard { background: var(--bg-card); color: var(--text); }
.importance-select.importance-nice_to_have { background: var(--bg-card); color: var(--text-dim); }
/* @trace req:4022 code:? — discreet pencil for inline override editing */
.scoring-edit-btn {
  background: transparent;
  border: 0;
  padding: 0 0 0 4px;
  margin: 0;
  cursor: pointer;
  color: var(--text-dim);
  font-size:0.8rem;
  line-height: 1;
  opacity: .55;
  transition: opacity 120ms ease, color 120ms ease;
}
.scoring-edit-btn:hover:not(:disabled) {
  opacity: 1;
  color: var(--accent, var(--text));
}
.scoring-edit-btn:disabled {
  cursor: not-allowed;
  opacity: .25;
}
.scoring-metrics {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 6px;
}
.scoring-metric {
  display: inline-flex;
  gap: 4px;
  align-items: baseline;
  padding: 2px 8px;
  border-radius: 4px;
  font-size:0.78rem;
  background: var(--bg-card);
  border: 1px solid var(--border);
}
.scoring-metric .metric-label {
  color: var(--text-dim);
  font-weight: 500;
  font-size: inherit;
}
.scoring-metric .metric-value {
  font-weight: 700;
  color: var(--text);
  font-size: inherit;
  margin-top: 0;
}
.scoring-metric.metric-positive .metric-value { color: var(--green); }
.scoring-metric.metric-negative .metric-value { color: var(--red); }
.scoring-detail { font-size:0.85rem; color: var(--text-dim); line-height: 1.5; }

.yearly-breakdown { margin-top: 8px; display: flex; flex-wrap: wrap; gap: 8px; font-size:0.8rem; color: var(--text-muted); }
.yearly-item { display: flex; gap: 12px; padding: 4px 8px; background: var(--bg-card); border-radius: 4px; border: 1px solid var(--border); }

/* === Financial Grid === */
.financial-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 12px; }
.fin-item { display: flex; flex-direction: column; }
.fin-label { font-size:0.75rem; color: var(--text-dim); text-transform: uppercase; font-family: 'Space Grotesk', sans-serif; font-weight: 600; }
.fin-value { font-size: 1.05rem; font-weight: 600; font-family: 'Space Grotesk', sans-serif; }

/* === Analyst === */
.analyst-bar { display: flex; height: 32px; border-radius: var(--radius-sm); overflow: hidden; font-size:0.8rem; font-weight: 600; }
.analyst-buy { background: var(--green); color: #fff; display: flex; align-items: center; justify-content: center; }
.analyst-hold { background: var(--yellow); color: #000; display: flex; align-items: center; justify-content: center; }
.analyst-sell { background: var(--red); color: #fff; display: flex; align-items: center; justify-content: center; }
.price-target { margin-top: 8px; color: var(--text-dim); font-size:0.9rem; }
/* Per-event grade-change badges (req:1539). Color follows the
   action's polarity — upgrade green, downgrade red, hold/init
   yellow/neutral. The template applies `grade-action-${action}`
   inline; the helper lowercases `action` so the class name is
   stable. */
.grade-action-upgrade { color: var(--green); font-weight: 600; }
.grade-action-downgrade { color: var(--red); font-weight: 600; }
.grade-action-hold { color: var(--yellow); font-weight: 600; }
.grade-action-init { color: var(--text-dim); font-weight: 600; }

/* === Risks/Catalysts === */
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
@media (max-width: 768px) { .two-col { grid-template-columns: 1fr; } }
.data-row-4 { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 16px; margin-bottom: 20px; }
.data-row-4 > .card { margin-bottom: 0; }
.data-row-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; margin-bottom: 20px; }
.data-row-3 > .card { margin-bottom: 0; }
.data-row-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.data-row-2 > .card { margin-bottom: 0; }
@media (max-width: 900px) { .data-row-4 { grid-template-columns: 1fr 1fr; } .data-row-3 { grid-template-columns: 1fr; } .data-row-2 { grid-template-columns: 1fr; } }

.risk-list, .catalyst-list { list-style: none; }
.risk-list li, .catalyst-list li {
  padding: 6px 0;
  border-bottom: 1px solid var(--border);
  font-size:0.85rem;
  color: var(--text-dim);
  line-height: 1.5;
}
.risk-list li:last-child, .catalyst-list li:last-child { border-bottom: none; }
.risk-list li::before { content: '\26A0'; margin-right: 8px; color: var(--red); }
.catalyst-list li::before { content: '\2713'; margin-right: 8px; color: var(--green); }

/* === Charts Section === */
.charts-section { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.charts-section .card:first-child { grid-column: 1 / -1; }
@media (max-width: 900px) { .charts-section { grid-template-columns: 1fr; } }
/* History-window toggle (req:4779): spans the grid, and keeps the primary
   (Revenue) card full-width even though it is no longer :first-child. */
.charts-timeframe { grid-column: 1 / -1; display: flex; align-items: center; gap: 10px; }
.charts-timeframe-label { font-size: 12px; color: var(--text-dim); text-transform: uppercase; letter-spacing: .04em; }
.charts-timeframe + .card { grid-column: 1 / -1; }

/* === Chart === */
.chart-container { position: relative; height: 300px; }
.chart-loading {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-dim); font-size:0.9rem;
  background: rgba(255, 255, 255, 0.8);
  border-radius: var(--radius-sm);
}
.chart-periods { display: flex; gap: 4px; }

/* === P/L colors === */
.pl-positive { color: #16a34a; }
.pl-negative { color: #dc2626; }

/* === Measure tier colors (scan table + then-vs-now) === */
.measure-pass { color: #16a34a; font-weight: 600; }
.measure-marginal { color: #ca8a04; }
.measure-fail { color: #dc2626; font-weight: 600; }

/* === Loading === */
.loading {
  padding: 60px;
  text-align: center;
  color: var(--text-dim);
  font-size: 1rem;
}

/* === Page Layout === */
.page-content { max-width: 1200px; margin: 0 auto; padding: 24px; }
.page-content > h2:first-child { margin: 0 0 20px; }
.list-view { padding: 0 8px 40px; }
.list-header { display: flex; align-items: center; gap: 16px; padding: 16px 8px; }
/* Compact inline add-symbol control in the holdings header (req:4810).
   No margin-left:auto — it sits grouped with the action buttons, not
   pushed to the far right (req:4830). position:relative anchors the
   reveal popover so opening it never reflows the header buttons. */
.inline-add { position: relative; display: inline-flex; align-items: center; }
/* The symbol/strategy/Add reveal drops below the +Add button as a floating
   popover instead of expanding inline (which shoved the header around).
   @trace code:3171 req:4830 */
.inline-add-popover {
  position: absolute; left: 0; top: 100%; margin-top: 6px; z-index: 200;
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 8px; box-shadow: var(--shadow-lg);
}
/* The ticker-search dropdown here is wider than the compact symbol input so
   "TICKER  Company Name  EXCHANGE" rows fit without truncation. Scoped to
   this popover so the nav/reports symbol searches keep their own widths.
   @trace code:3172 req:4830 */
.inline-add-popover .sym-ac-drop { right: auto; min-width: 300px; }
/* @trace req:4879 req:4881 — the operation-add variant lays its six fields out
   on TWO fixed rows (action/date/symbol, then qty/price/amount + actions) so
   the form is wide, not tall. The popover becomes a vertical stack of
   horizontal `.op-add-row`s. */
.inline-add-popover--op { flex-direction: column; align-items: flex-start; gap: 6px; }
.op-add-row { display: flex; align-items: center; gap: 6px; flex-wrap: nowrap; }
.page-center { display: flex; align-items: center; justify-content: center; min-height: calc(100vh - 60px); }

/* === User Select / Landing === */
.user-list { display: flex; flex-direction: column; gap: 8px; margin: 16px 0; }
.user-item {
  display: flex; justify-content: space-between; align-items: center;
  padding: 12px 16px; background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--radius); cursor: pointer; transition: all .2s;
}
.user-item:hover { background: var(--bg-hover); transform: translateY(-2px); box-shadow: var(--shadow); }
.user-name { font-weight: 600; }

/* === Forms === */
.input {
  background: var(--bg); color: var(--text); border: 1px solid var(--border);
  padding: 8px 12px; border-radius: var(--radius-sm); font-size:0.9rem; width: 100%;
  font-family: 'DM Sans', sans-serif;
}
.input:focus { border-color: var(--accent); outline: none; box-shadow: 0 0 0 3px rgba(249,115,22,0.15); }

/* @trace code:3173 req:4877
   `.form-input`/`.form-label` are used across the admin forms
   (Create Demo, Admin Models, …) but were never defined, so those fields fell
   back to default browser styling (white slabs in dark mode). Theme them off
   the same CSS variables as `.input` so they match the app in both themes. */
.form-label { display: block; margin-bottom: 0.3rem; font-size: 0.85rem; color: var(--text-dim); font-weight: 500; }
.form-input {
  background: var(--bg); color: var(--text); border: 1px solid var(--border);
  padding: 8px 12px; border-radius: var(--radius-sm); font-size:0.9rem; width: 100%;
  font-family: 'DM Sans', sans-serif;
}
.form-input:focus { border-color: var(--accent); outline: none; box-shadow: 0 0 0 3px rgba(249,115,22,0.15); }

/* --- Symbol Autocomplete --- */
.sym-ac { position: relative; display: inline-block; }
/* @trace code:? req:4171 — text-transform:uppercase removed so users
   can type company names ("Apple", "Tesla") naturally. The dropdown
   still surfaces the canonical upper-case ticker on selection. */
.sym-ac-input { width: 100% !important; }
.sym-ac-drop {
  position: absolute; top: 100%; left: 0; right: 0; z-index: 200;
  background: var(--bg-card); border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-lg);
  max-height: 260px; overflow-y: auto; margin-top: 2px;
}
.sym-ac-item {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 10px; cursor: pointer; font-size:0.85rem;
  border-bottom: 1px solid var(--border);
}
.sym-ac-item:last-child { border-bottom: none; }
.sym-ac-item:hover, .sym-ac-item.active { background: var(--bg-hover); }
.sym-ac-ticker { font-weight: 700; min-width: 56px; font-family: 'Space Grotesk', sans-serif; color: var(--text); }
.sym-ac-name { flex: 1; color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sym-ac-exchange { font-size:0.7rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: .03em; }

.textarea { resize: vertical; font-family: inherit; }
.form-group { margin-bottom: 12px; }
.form-group label { display: block; font-size:0.75rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: .05em; margin-bottom: 4px; font-family: 'Space Grotesk', sans-serif; font-weight: 600; }
.form-row { display: flex; gap: 8px; }
.form-row .input { flex: 1; }
.form-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 16px; }
.params-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 12px; }
.text-error { color: var(--red); font-size:0.85rem; }
.text-dim { color: var(--text-dim); font-size:0.85rem; }
.time-badge { font-size:0.8rem; white-space: nowrap; }

/* === Strategy Cards — Stacked Style === */
.strategies-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 20px; margin-top: 20px; }
.strategy-card {
  cursor: pointer;
  transition: transform .3s cubic-bezier(0.22, 1, 0.36, 1), box-shadow .3s;
}
.strategy-card:nth-child(3n+1) { transform: rotate(-1deg); }
.strategy-card:nth-child(3n+2) { transform: rotate(0.8deg); }
.strategy-card:nth-child(3n+3) { transform: rotate(-0.5deg); }
.strategy-card:hover {
  transform: rotate(0) translateY(-6px) !important;
  box-shadow: var(--shadow-xl);
  z-index: 5;
}
.strategy-header { display: flex; justify-content: space-between; align-items: center; gap: 10px; }
/* @trace code:2510 req:4791 — generated strategy icon, large on the card, small in compact refs. */
.strategy-title { display: flex; align-items: center; gap: 12px; min-width: 0; }
.strategy-icon { width: 56px; height: 56px; border-radius: 14px; flex-shrink: 0; box-shadow: var(--shadow-sm); }
.strategy-icon-sm { width: 22px; height: 22px; border-radius: 6px; flex-shrink: 0; vertical-align: middle; }
.strategy-new { border-style: dashed; border-color: var(--border-strong); }
.strategy-new:hover { border-color: var(--accent); }
/* @trace code:2580 req:4791 — strategy detail header icon (clickable to edit). */
.strategy-icon-md { width: 36px; height: 36px; border-radius: 10px; flex-shrink: 0; box-shadow: var(--shadow-sm); }
.strategy-icon-btn { background: none; border: none; padding: 0; cursor: pointer; line-height: 0; border-radius: 10px; }
.strategy-icon-btn:hover { box-shadow: 0 0 0 2px var(--accent); }
/* @trace code:2580 req:4791 — icon editor panel (detail modal + wizard). */
.icon-editor-preview { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.icon-editor-preview-img { width: 64px; height: 64px; }
.icon-editor-group { margin-bottom: 14px; }
.icon-swatch-grid { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.icon-swatch { width: 40px; height: 40px; padding: 2px; border: 2px solid var(--border); border-radius: 10px; background: var(--bg-hover); cursor: pointer; line-height: 0; }
.icon-swatch img { width: 100%; height: 100%; border-radius: 7px; }
.icon-swatch:hover { border-color: var(--border-strong); }
.icon-swatch-active { border-color: var(--accent); }
/* req:4856 — Symbol|Letter toggle, letter input, custom color swatch. */
.icon-editor-group-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.icon-mark-toggle { display: flex; gap: 4px; }
.icon-letter-input { width: 56px; margin-top: 6px; text-align: center; text-transform: uppercase; font-weight: 700; font-size: 1.1rem; }
.icon-color-swatch { display: inline-flex; align-items: center; justify-content: center; overflow: hidden; }
.icon-color-swatch input[type="color"] { width: 100%; height: 100%; padding: 0; border: none; background: none; cursor: pointer; }
/* req:4875 — Rotation slider: spin the background pattern angle (seed). */
.icon-rotation-row { display: flex; align-items: center; gap: 10px; margin-top: 6px; }
.icon-rotation-slider { flex: 1; accent-color: var(--accent); cursor: pointer; }
.icon-rotation-value { min-width: 38px; text-align: right; font-variant-numeric: tabular-nums; color: var(--text-dim); font-size:0.85rem; }
.badge-pending {
  font-size:0.7rem; font-weight: 600; padding: 2px 8px; border-radius: 9999px;
  background: var(--yellow, #eab308); color: #000; white-space: nowrap;
}
.qa-question { padding: 10px 0; border-bottom: 1px solid var(--border); }
.qa-question:last-child { border-bottom: none; }
.qa-radio-label, .qa-check-label {
  display: flex; align-items: center; gap: 6px;
  padding: 6px 12px; border-radius: 6px; cursor: pointer;
  font-size:0.85rem; border: 1px solid var(--border); transition: all .15s;
}
.qa-radio-label:hover, .qa-check-label:hover { border-color: var(--accent); }
.qa-radio-label.active, .qa-check-label.active {
  background: var(--accent); color: #fff; border-color: var(--accent);
}
.qa-radio-label input, .qa-check-label input { display: none; }

/* === Modal === */
/* @trace code:3243 req:4512
    — canonical modal overlay. The legacy
   `.modal-backdrop` class was retired (V6 quick win); see the
   tombstone in the SIMULATION section near .modal-box. */
.modal-overlay {
  position: fixed; inset: 0; background: rgba(0,0,0,0.4);
  backdrop-filter: blur(4px);
  display: flex; align-items: center; justify-content: center; z-index: 200;
}
.modal-card {
  width: 90%; max-width: 600px; max-height: 90vh; overflow-y: auto;
  box-shadow: var(--shadow-xl);
  transition: transform 0.25s ease;
}
/* @trace req:4278 code:? — the help-chat / notes panels are
   `position: fixed; right: 0` with z-index 10000 (above any modal).
   When either is open, the modal CARD (the graph popup) physically
   shifts left by half the chat width so it stays centered in the
   visible viewport-minus-chat area instead of sitting under the chat
   panel. The dim backdrop is left full-viewport intentionally — the
   chat panel is opaque on top so the dim under it is invisible. */
html.help-chat-open .modal-card,
html.notes-panel-open .modal-card {
  transform: translateX(calc(-1 * var(--chat-width) / 2));
}

/* @trace req:4698 code:2102 — <dialog-host> confirm/prompt dialogs.
   z-index matches the lib/api.ts dabble modals (10000): these are
   system-wide gates that must stack above any app-level modal that
   opened them. */
.dialog-overlay { z-index: 10000; }
.dialog-card { max-width: 440px; padding: 24px 28px; }
.dialog-title { margin: 0 0 8px; }
.dialog-message {
  color: var(--text-dim); margin: 0 0 16px; line-height: 1.5;
  /* Confirm bodies built from multi-line strings keep their breaks. */
  white-space: pre-line;
  overflow-wrap: break-word;
}
/* @trace code:3244 req:4873
    — the prompt input had no explicit colours, so it
   fell back to the browser default (white box / black text) and read as a
   bright slab in dark mode. Inherit the themed surface like `.input`. */
.dialog-input {
  width: 100%; box-sizing: border-box; margin-bottom: 16px;
  background: var(--bg); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 8px 12px; font-size:0.9rem; font-family: 'DM Sans', sans-serif;
}
.dialog-input:focus { border-color: var(--accent); outline: none; box-shadow: 0 0 0 3px rgba(249,115,22,0.15); }

/* @trace code:3245 req:4873
    — the rail's single "+" opens ONE CENTERED MODAL (like
   the old name dialog, not a popover anchored to the far-left "+") that asks for
   the name AND the type (Monitoring list vs Ledger) together: a name field, two
   radio choices, and a Create button. `.rail-add-menu` is the modal card itself
   (centered + sized by .modal-card/.dialog-card on the .modal-overlay); here it
   only lays the form out as a column. The name input borrows `.input` for its
   themed (dark-mode) surface. */
.rail-add-wrap { display: inline-flex; }
.rail-add-menu { display: flex; flex-direction: column; gap: 10px; }
.rail-add-name { margin: 0; }
.rail-add-choice {
  display: flex; align-items: flex-start; gap: 8px; text-align: left;
  padding: 6px 8px; border-radius: var(--radius-sm); cursor: pointer;
  color: var(--text); font-family: inherit;
}
.rail-add-choice:hover { background: var(--bg-hover); }
.rail-add-choice input[type="radio"] { margin: 3px 0 0; flex: none; }
.rail-add-choice-title { display: block; font-weight: 600; font-size:0.9rem; }
.rail-add-choice-desc { display: block; font-size:0.78rem; color: var(--text-dim); }
.rail-add-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 4px; }
/* @trace req:4886 — the optional default-strategy picker on the create modal. */
.rail-add-strategy { display: flex; flex-direction: column; gap: 4px; }
.rail-add-strategy .rail-add-choice-desc { padding-left: 2px; }
.dialog-actions { display: flex; gap: 8px; justify-content: flex-end; }

/* === Strategy Detail Layout === */
.strategy-layout {
  display: grid;
  grid-template-columns: 280px 1fr;
  gap: 20px;
  align-items: start;
}
.strategy-sidebar { display: flex; flex-direction: column; gap: 16px; }
.strategy-main { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
@media (max-width: 800px) {
  .strategy-layout { grid-template-columns: 1fr; }
}

/* === Newsletter Config Layout (left list, right detail) ===
   req:bhbw5x9nyy — mirrors the .strategy-layout master-detail grid; the
   sidebar lists newsletters, the main pane configures the selected one. */
.newsletter-layout {
  display: grid;
  grid-template-columns: 260px 1fr;
  gap: 20px;
  align-items: start;
}
.newsletter-sidebar { display: flex; flex-direction: column; gap: 12px; }
.newsletter-main { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.newsletter-sidebar .scan-item.active { background: var(--bg-hover); border-color: var(--accent); }
@media (max-width: 800px) {
  .newsletter-layout { grid-template-columns: 1fr; }
}

/* Cadence shelves (req:bhrnm6941p): one row per cadence, holding its
   newsletter card (draggable) or a Create button. Drag a card onto another
   shelf to move it (empty target) or swap (occupied). */
/* Stacked: the cadence label sits on its own line above the draggable card. */
.nl-shelf {
  display: flex; flex-direction: column; align-items: stretch; gap: 4px;
  padding: 6px 8px;
  border: 1px dashed var(--border); border-radius: var(--radius-sm);
  transition: background .12s, border-color .12s;
}
.nl-shelf-label {
  font-weight: 600; font-size:0.78rem; color: var(--text-dim);
  text-transform: uppercase; letter-spacing: .04em;
}
.nl-shelf-dragover { border-color: var(--accent); border-style: solid; background: var(--bg-hover); }
.nl-shelf-disabled { opacity: .55; }
/* The whole card is the drag handle + click-to-select button; it fills the
   shelf to the right of the label/divider and carries the editable name. */
.nl-shelf-card {
  display: flex; align-items: center; gap: 8px; min-width: 0;
  padding: 5px 10px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--bg-card); cursor: grab; user-select: none;
}
.nl-shelf-card:active { cursor: grabbing; }
.nl-shelf-card.active { border-color: var(--accent); background: var(--bg-hover); }
.nl-shelf-grip { color: var(--text-dim); font-weight: 700; letter-spacing: -2px; cursor: grab; }
.nl-shelf-name { font-weight: 600; font-size:0.85rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nl-shelf-name-input {
  flex: 1; min-width: 0; font-size:0.85rem; padding: 2px 6px;
  border: 1px solid var(--accent); border-radius: var(--radius-sm);
  background: var(--bg-card); color: var(--text);
}
.nl-shelf-edit {
  border: none; background: none; cursor: pointer; padding: 0 2px;
  color: var(--text-dim); font-size:0.8rem;
}
.nl-shelf-edit:hover { color: var(--accent); }
/* Short one-word label (full text in the title tooltip); nowrap + ellipsis
   so a status pill can never spill its text past the pill border in the
   narrow shelf (req:m3jr5vamhs). */
.nl-shelf-status {
  margin-left: auto; flex-shrink: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
.nl-shelf-create { align-self: flex-start; }
.nl-shelf-locked { align-self: flex-start; font-size:0.8rem; }
/* Section blocks (req:1zwzz7faz2): each configurable section is a self-contained,
   reorderable card with an Active/Inactive toggle. */
.newsletter-section-block {
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 8px 10px; margin-bottom: 8px; background: var(--bg);
}
.newsletter-section-block.inactive { opacity: 0.6; }
.nsb-header { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.nsb-title { font-weight: 600; }
.nsb-body { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--border); }
/* Include/Exclude chip lists (req:x5eqte7gve): each list anchors its +picker
   dropdown; defaults stay hidden. */
.nl-chip-group { position: relative; margin-bottom: 6px; }

/* Tri-state item pills (req:rf0w3v1gyt): each configurable item (symbol,
   strategy, list, market, scan) is a single click-to-cycle button so many fit
   per line. States, kept consistent everywhere: default = transparent outline
   (budget decides), on = filled green (always included), off = red outline +
   strike-through (excluded). Markets are two-state (default/on only). */
.state-pill-cloud { display: flex; flex-wrap: wrap; gap: 5px; align-items: center; }
.state-pill {
  display: inline-flex; align-items: center; gap: 3px;
  padding: 2px 10px; border-radius: 20px;
  font-size:0.76rem; font-weight: 600; white-space: nowrap;
  border: 1px solid var(--border); background: transparent;
  color: var(--text); cursor: pointer;
  transition: background .12s, border-color .12s, color .12s, opacity .12s;
}
.state-pill:hover:not(.state-locked) { border-color: var(--text-dim); }
.state-pill.state-default { color: var(--text-dim); border-style: dashed; }
.state-pill.state-on {
  background: var(--green); border-color: var(--green); color: #fff;
}
.state-pill.state-off {
  border-color: var(--red); color: var(--red); text-decoration: line-through;
  background: color-mix(in srgb, var(--red) 10%, transparent);
}
.state-pill.state-locked { cursor: default; opacity: .8; }
.state-pill .pill-lock { font-size:0.7rem; }

/* Spend tally meter (req:rf0w3v1gyt): pinned content cost vs the budget. */
.budget-bar {
  display: inline-block; width: 120px; height: 8px;
  border-radius: 4px; background: var(--bg-hover); overflow: hidden;
  vertical-align: middle;
}
.budget-bar-fill { display: block; height: 100%; background: var(--green); transition: width .15s; }
.budget-bar-fill.over { background: var(--red); }

/* Legend: one compact key so the pill colours self-explain (req:rf0w3v1gyt). */
.state-legend {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px;
  font-size:0.74rem; color: var(--text-dim); margin: 2px 0 4px;
}
.state-legend .legend-item { display: inline-flex; align-items: center; gap: 5px; }
.state-legend .state-pill { cursor: default; pointer-events: none; padding: 1px 8px; }

/* The single "+ Add" affordance next to a pill cloud. Selector is qualified
   with .btn-inline so it out-specifies the base .btn-inline rule below (which
   would otherwise force a 22px square and clip the text).
   @trace code:py7z3fk1tg req:8w8bsxy45v */
.btn-inline.btn-add-row {
  width: auto; height: auto; padding: 2px 10px; gap: 3px;
  white-space: nowrap; border-radius: 20px;
  font-size:0.74rem;
}
/* The "Show all N / Show fewer" expander — dim + dashed so it reads as a
   view control, distinct from the accent "+ Add". Same specificity bump so the
   dashed border survives .btn-inline's `border` shorthand. */
.btn-inline.btn-show-all { border-style: dashed; color: var(--text-dim); }
.btn-inline.btn-show-all:hover { color: #fff; }

/* === Symbol Detail Layout === */
.symbol-layout {
  display: grid;
  grid-template-columns: 300px 1fr;
  gap: 20px;
  align-items: start;
}
.symbol-sidebar { display: flex; flex-direction: column; gap: 16px; }
.symbol-main { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
@media (max-width: 900px) {
  .symbol-layout { grid-template-columns: 1fr; }
}

/* === Portfolio Section Layout (left rail, replaces the tab strip) ===
   @trace code:2565 req:4806 — mirrors the .strategy-layout/.symbol-layout
   master-detail grid; the rail nests portfolio/op-set instances under the
   Holdings/Operations group heads. */
.portfolio-layout {
  display: grid;
  grid-template-columns: 220px 1fr;
  gap: 20px;
  align-items: start;
}
.portfolio-main { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.portfolio-rail { display: flex; flex-direction: column; gap: 1px; }
.rail-group { display: flex; flex-direction: column; }
.rail-items { display: flex; flex-direction: column; }
.rail-head, .rail-item {
  display: block;
  text-decoration: none;
  color: var(--text-dim);
  border-radius: 6px;
  border-left: 2px solid transparent;
}
.rail-head { padding: 7px 10px; font-weight: 600; font-size:0.9rem; }
.rail-item { padding: 5px 10px 5px 24px; font-size:0.85rem; }
.rail-head:hover, .rail-item:hover { background: var(--bg-hover); color: var(--text); }
.rail-head.active, .rail-item.active {
  color: var(--text);
  background: var(--bg-card);
  border-left-color: var(--orange);
  font-weight: 700;
}
.rail-empty { padding: 4px 10px 4px 24px; font-size:0.8rem; color: var(--text-dim); opacity: .7; }
/* Inline list management in the rail (create + per-item archive). The head/
   item links flex-grow so the +/× buttons pin to the right edge. Archive is
   hover-revealed on pointer devices and kept tappable on touch. @trace code:2591 code:2592 req:4813 */
.rail-head-row, .rail-item-row { display: flex; align-items: center; }
.rail-head-row .rail-head, .rail-item-row .rail-item { flex: 1 1 auto; min-width: 0; }
.rail-add, .rail-archive {
  flex-shrink: 0; background: none; border: none; cursor: pointer;
  color: var(--text-dim); line-height: 1; padding: 4px 8px; border-radius: 6px;
}
.rail-add { font-size: 1.1rem; font-weight: 700; }
.rail-add:hover { background: var(--bg-hover); color: var(--text); }
.rail-archive { font-size: 1rem; opacity: 0; }
/* Reveal on row hover, and on keyboard focus so the control is reachable by
   tab (it's otherwise opacity:0); touch devices have no hover, so keep it
   visible there. */
.rail-item-row:hover .rail-archive,
.rail-item-row:focus-within .rail-archive { opacity: .55; }
.rail-archive:hover, .rail-archive:focus-visible { opacity: 1; background: var(--bg-hover); color: var(--red); }
@media (hover: none) { .rail-archive { opacity: .45; } }
.rail-sep { height: 1px; background: var(--border); margin: 8px 4px; }
@media (max-width: 900px) {
  .portfolio-layout { grid-template-columns: 1fr; }
}

/* Admin section side rail (req:jvnzyd4b0q) — two-column layout + collapsible
   category groups. Reuses the shared `.rail-head`/`.rail-item`/`.active` rules
   above (same as the Portfolio rail); the classes below add the group headers,
   chevrons, unread badge and the pinned QA/panic footer. */
.admin-layout {
  display: grid;
  grid-template-columns: 220px 1fr;
  gap: 20px;
  align-items: start;
}
.admin-main { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.admin-rail { display: flex; flex-direction: column; gap: 1px; }
.admin-rail .rail-group { margin-top: 6px; }
/* Category header: a full-width button that reads like a rail head but toggles
   its item list. The chevron rotates the disclosure state. */
.rail-cat-head {
  display: flex; align-items: center; gap: 6px; width: 100%;
  padding: 7px 10px; border: none; background: none; cursor: pointer;
  text-align: left; font-weight: 700; font-size:0.78rem; letter-spacing: .03em;
  text-transform: uppercase; color: var(--text-dim); border-radius: 6px;
}
.rail-cat-head:hover { background: var(--bg-hover); color: var(--text); }
.rail-chevron { flex: none; font-size:0.7rem; width: .8em; color: var(--text-dim); }
.rail-cat-title { flex: 1 1 auto; min-width: 0; }
.rail-cat-items { display: flex; flex-direction: column; }
/* Rail items carry the label + optional unread badge on one row. */
.admin-rail .rail-item { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
.rail-badge {
  flex: none; background: var(--red, #d9534f); color: #fff; border-radius: 10px;
  padding: 0 .45rem; font-size:0.72rem; font-weight: 700; line-height: 1.5;
}
/* Footer holds the dev-only QA link and the always-present KILL SERVER button,
   separated from the nav by a hairline so they read as chrome, not routes. */
.rail-footer {
  display: flex; flex-direction: column; gap: 4px;
  margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--border);
}
.rail-panic {
  background: var(--red); color: #fff; font-weight: 700; text-align: center;
  border: none; cursor: pointer;
}
.rail-panic:hover { filter: brightness(1.08); color: #fff; }
.rail-panic:disabled { opacity: .6; cursor: default; }
@media (max-width: 900px) {
  .admin-layout { grid-template-columns: 1fr; }
}

/* Score bars */
.score-bars { display: flex; flex-direction: column; gap: 10px; }
.score-bar-label { display: flex; justify-content: space-between; font-size:0.82rem; margin-bottom: 3px; }
.score-bar-track { height: 6px; background: var(--bg-inset); border-radius: 3px; overflow: hidden; }
.score-bar-fill { height: 100%; border-radius: 3px; transition: width .3s; }
.bar-pass { background: var(--green); }
.bar-marginal { background: var(--yellow); }
.bar-fail { background: var(--red); }

/* Metrics grid */
.metrics-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
  gap: 10px;
}
.metric-item {
  padding: 8px;
  background: var(--bg);
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
}
.metric-item .metric-label { font-size:0.7rem; }
.metric-item .metric-value { font-size:0.95rem; margin-top: 2px; }

/* === Scan === */
.scan-controls { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
.scan-market-check { display: flex; align-items: center; gap: 4px; font-size:0.9rem; cursor: pointer; }
.scan-market-check input { width: 16px; height: 16px; }
.scan-progress { margin-top: 12px; }
.progress-bar { height: 8px; background: var(--bg-inset); border-radius: 4px; overflow: hidden; margin-bottom: 6px; }
.progress-fill { height: 100%; background: var(--accent); transition: width .3s; border-radius: 4px; }
.scan-list { display: flex; flex-direction: column; gap: 8px; }
.scan-item {
  display: flex; flex-wrap: wrap; gap: 6px 12px; align-items: center;
  padding: 10px 12px; background: var(--bg); border-radius: var(--radius-sm);
  cursor: pointer; transition: all .15s; border: 1px solid transparent;
}
.scan-item:hover { background: var(--bg-hover); border-color: var(--border); }
.scan-date { font-weight: 600; }
.edit-icon { cursor: pointer; opacity: .3; font-size:0.8rem; }
.edit-icon:hover { opacity: .8; }
.strategy-sidebar .scan-item { font-size:0.85rem; }

/* === Params Display === */
.params-display { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 8px; }
.param-item { display: flex; flex-direction: column; padding: 8px; background: var(--bg); border-radius: var(--radius-sm); border: 1px solid var(--border); }
.param-key { font-size:0.75rem; color: var(--text-dim); text-transform: uppercase; font-family: 'Space Grotesk', sans-serif; font-weight: 600; }
.param-val { font-weight: 600; }

/* req:4165 — key/value rows used on the simulation group detail page
   (and anywhere else that stacks a `param-row` list). Previously had
   no rule, so the uppercase key sat flush against the bold value with
   no breathing room. Horizontal flex layout with a 12px gap restores
   the rhythm; the divider lines visually separate the rows inside the
   wrapping `.card`. The minimum width on `.param-key` reserves a
   consistent label column so values line up vertically across rows. */
.param-row {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 6px 0;
}
.param-row + .param-row { border-top: 1px solid var(--border); }
.param-row .param-key { min-width: 120px; }

/* === Upload === */
.upload-zone {
  border: 2px dashed var(--border-strong); border-radius: var(--radius);
  padding: 32px; text-align: center; color: var(--text-dim);
  cursor: pointer; transition: all .2s;
}
.upload-zone:hover { border-color: var(--accent); background: var(--accent-bg); }
.file-list { margin-top: 12px; }
.file-item {
  display: flex; gap: 12px; align-items: center;
  padding: 8px 12px; background: var(--bg); border-radius: var(--radius-sm);
  margin-bottom: 4px; border: 1px solid var(--border);
}
.file-item span:first-child { flex: 1; }

/* === Scan Source Picker === */
.scan-source-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
.btn-inline {
  background: var(--bg-hover); border: 1px solid var(--border-strong, var(--border)); color: var(--accent);
  width: 22px; height: 22px; border-radius: 4px; cursor: pointer;
  font-size:0.85rem; display: inline-flex; align-items: center; justify-content: center;
  transition: all .15s;
  box-shadow: var(--shadow-sm);
}
.btn-inline:hover { background: var(--accent); color: #fff; border-color: var(--accent); }

.chip-row { display: flex; flex-wrap: wrap; gap: 4px; }
.chip {
  display: inline-flex; align-items: center; gap: 3px;
  padding: 1px 8px; background: var(--accent-bg); border: 1px solid #fed7aa;
  border-radius: 20px; font-size:0.75rem; font-weight: 600; white-space: nowrap;
  color: var(--accent-dark);
}
/* @trace code:3246 req:4247
    — matches the app-wide red-cross convention
   used by `.filter-criterion-header .btn-remove`,
   `.filter-condition-row .btn-remove-cond`, and the per-row archive
   buttons in strategies.ts that inline `style="color:var(--red)"`.
   Baseline red at half opacity, full opacity on hover (no colour
   shift on hover — opacity-only — so the glyph stays red end-to-end). */
.chip-x { cursor: pointer; color: var(--red); opacity: 0.5; font-size:0.85rem; line-height: 1; transition: opacity .15s; }
.chip-x:hover { opacity: 1; }

/* @trace code:? req:4236 — input-strategies table + segmented mode toggle.
   The card column is narrow (1/3 of the wizard grid) so the layout has to
   stay compact: the segmented buttons share a border and use minimal
   padding, the remove glyph is a plain span (chip-x), and the table
   collapses horizontally with overflow-safe sizing so the right column
   never gets clipped. */
.input-strategies-table {
  width: 100%;
  margin-bottom: 8px;
  font-size:0.8rem;
  border-collapse: collapse;
  table-layout: auto;
  /* @trace code:? req:4236 — the strategy picker's `.dropdown-backdrop`
     sits at z-index:49 covering the viewport while open; without a
     stacking context above it, clicks on the per-row mode toggle land
     on the backdrop instead of the buttons. */
  position: relative;
  z-index: 50;
}
.input-strategies-table tr {
  border-bottom: 1px solid var(--border-soft, var(--border));
}
.input-strategies-table tr:last-child { border-bottom: none; }
.input-strategies-name {
  padding: 4px 6px 4px 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 0;     /* allow shrinking inside the narrow column */
}
.input-strategies-mode {
  padding: 4px 0;
  white-space: nowrap;
  width: 1%;        /* shrink-to-fit; the name cell takes the rest */
}
.input-strategies-remove {
  padding: 4px 0 4px 6px;
  text-align: right;
  width: 1%;
}
.seg-toggle {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: 4px;
  overflow: hidden;
  background: var(--bg);
}
.seg-btn {
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  border: none;
  border-left: 1px solid var(--border);
  padding: 2px 8px;
  font-size:0.72rem;
  font-weight: 500;
  color: var(--text-dim);
  cursor: pointer;
  line-height: 1.2;
  transition: background .12s, color .12s;
}
.seg-btn:first-child { border-left: none; }
.seg-btn:hover:not(:disabled) {
  background: var(--bg-hover);
  color: var(--text);
}
.seg-btn.seg-active {
  background: var(--accent);
  color: var(--accent-fg, #fff);
  font-weight: 600;
}
.seg-btn:disabled {
  opacity: .45;
  cursor: not-allowed;
}

.dropdown-wrap { position: relative; }
/* @trace code:3247 req:4244
    — uses --bg-elev (not --bg-card) so the popup
   reads as a distinct surface even when it opens over a `.card`
   (e.g. the wizard columns on /strategies/new). z-index:60 sits above
   `.input-strategies-table`'s z-index:50 (req:4236, which puts the
   table above the backdrop so per-row toggles stay clickable while
   the picker is open). Without this bump, the table — a later sibling
   in the same stacking context — paints on top of the menu wherever
   the picker overlaps the table area, and since the table has no
   background the menu reads as transparent. */
.dropdown-menu {
  position: absolute; right: 0; top: 24px; z-index: 60;
  background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 6px 0; min-width: 180px; box-shadow: var(--shadow-lg);
}
.dropdown-item {
  display: flex; align-items: center; gap: 6px;
  padding: 5px 12px; font-size:0.8rem; cursor: pointer; white-space: nowrap;
}
.dropdown-item:hover { background: var(--bg-hover); }
.dropdown-item input { width: 14px; height: 14px; }
.dropdown-backdrop { position: fixed; inset: 0; z-index: 49; }
.dropdown-menu-search { padding-top: 0; }
.dropdown-search {
  width: 100%; padding: 7px 12px; border: none;
  border-bottom: 1px solid var(--border);
  /* @trace code:3248 req:4244
      — matches `.dropdown-menu`'s surface
     colour so the sticky search header doesn't paint a card-coloured
     stripe at the top of the elevated popup. */
  background: var(--bg-elev); color: var(--text);
  font-size:0.8rem; outline: none;
  border-radius: var(--radius) var(--radius) 0 0;
  position: sticky; top: 0; z-index: 1;
}
.dropdown-search::placeholder { color: var(--text-muted); }
.dropdown-scroll { max-height: 240px; overflow-y: auto; }

/* === Lists === */
/* === Create wizard (inline + button) === */
.btn-add-inline {
  width: 28px; height: 28px; padding: 0; font-size: 1.2rem; font-weight: 700;
  line-height: 1; display: flex; align-items: center; justify-content: center;
  border-radius: 50%; flex-shrink: 0;
}
.create-wizard {
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 12px; margin-bottom: 12px; display: flex; flex-direction: column; gap: 8px;
}
.create-wizard-actions { display: flex; gap: 8px; justify-content: flex-end; }

.lists-grid { display: flex; flex-direction: column; gap: 8px; }
.list-card {
  padding: 10px 14px; background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius); cursor: pointer; transition: all .2s;
  box-shadow: var(--shadow-sm);
}
.list-card:hover { background: var(--bg-hover); transform: translateY(-2px); box-shadow: var(--shadow); }
.list-card.expanded { background: var(--bg-card); border-color: var(--accent); box-shadow: var(--shadow-lg); }
.list-card-header { display: flex; justify-content: space-between; align-items: center; }
.list-name { font-weight: 600; font-size:0.9rem; }
.list-card-body { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border); cursor: default; }

/* === Watchlist === */
.watchlist-tags { display: flex; flex-wrap: wrap; gap: 4px; }
.watchlist-tag {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; background: var(--bg); border: 1px solid var(--border);
  border-radius: 20px; font-size:0.8rem; font-weight: 600;
}
.watchlist-remove {
  cursor: pointer; color: var(--text-muted); font-size: 1rem; line-height: 1;
}
.watchlist-remove:hover { color: var(--red); }

/* === AI Column === */
.col-ai { width: 36px; min-width: 36px; max-width: 36px; user-select: none; caret-color: transparent; }
.ai-btn {
  cursor: pointer; font-size: 1rem; color: var(--accent); opacity: .5;
  transition: opacity .15s; user-select: none;
}
.ai-btn:hover { opacity: 1; }
.ai-done { opacity: .35; }
.ai-done:hover { opacity: .8; }
.ai-failed { color: var(--red); opacity: .7; }
.ai-spinner {
  display: inline-block; width: .85em; height: .85em;
  border: 2px solid var(--accent); border-top-color: transparent;
  border-radius: 50%; animation: spin .8s linear infinite;
  vertical-align: middle;
}
/* Size modifiers for the <inline-spinner> primitive (req:4529).
 * `.ai-spinner-md` matches the historical default so a plain
 * <inline-spinner /> stays a drop-in for <span class="ai-spinner"></span>. */
.ai-spinner-sm { width: .6em; height: .6em; }
.ai-spinner-md { /* default — no override */ }
.ai-spinner-lg { width: 1.5rem; height: 1.5rem; }
@keyframes spin { to { transform: rotate(360deg); } }

/* === LoadingBlock primitive (req:4529) === */
.loading-block {
  display: flex; align-items: center; justify-content: center;
  gap: 12px; padding: 24px 16px;
  color: var(--text-dim); font-size:0.95rem;
}
.loading-block-label { line-height: 1; }

/* === EmptyState / EmptyTableRow primitives (req:4529) ===
 * Extends the existing `.empty-state` class (already used at one site
 * in admin.ts) with consistent vertical rhythm and an optional CTA. */
.empty-state {
  display: flex; flex-direction: column; align-items: center;
  gap: 12px; padding: 24px 16px;
  color: var(--text-dim); text-align: center;
}
.empty-state > p { margin: 0; }
.empty-row-cell {
  opacity: .5; text-align: center; padding: 12px 8px;
}

/* === TabLink primitive (req:4530) ===
 * Replaces the 18+ `:style="tab === '...' ? '...' : '...'"` ternaries
 * on admin <router-link> tabs. The base style matches the prior
 * inactive form (rounded-square corners + dimmed opacity); the
 * .active modifier matches the prior active form (orange underline
 * + bold weight). Wraps .btn .btn-sm so the existing button shape
 * carries through. */
.tab-link {
  border-radius: 0; opacity: .7;
}
/* @trace req:4696 code:2100 — the active tab is an UNDERLINE tab, never a
   solid-fill button. tab-link/tab-button carry the `active` class, which
   also matches `.btn.active` (solid accent fill); these declarations come
   after .btn.active in this file (same specificity → later wins) and reset
   the fill so every strip shares the flat orange-underline look the
   portfolio/dashboard strips always had. */
.tab-link.active {
  border-bottom: 2px solid var(--orange); font-weight: 700; opacity: 1;
  background: var(--bg-card); border-color: var(--border); color: var(--text);
  box-shadow: none;
}
.tab-link.active:hover { background: var(--bg-hover); }

/* === ToastHost / useToast primitive (req:4532) ===
 * Fixed-position polite live-region that hosts a stack of auto-
 * dismissing toasts. The host is mounted once at the bottom of the
 * SPA root (index.html); each toast click-dismisses early and
 * auto-decays after TOAST_TTL_MS (4s) via setTimeout.
 * Variants: .toast-info (default, neutral), .toast-success (green
 * accent), .toast-error (red accent). Screen readers announce them
 * via aria-live="polite" — replaces alert()'s accessibility win.
 * Stacks vertically; the top toast is the oldest. */
.toast-host {
  /* 10001: one above the dialog/dabble overlays (10000) so an error
     toast fired while a dialog is open isn't dimmed under its
     backdrop (req:4698). */
  position: fixed; bottom: max(1rem, env(safe-area-inset-bottom)); right: max(1rem, env(safe-area-inset-right)); z-index: 10001;
  display: flex; flex-direction: column; gap: 8px;
  max-width: min(420px, calc(100vw - 2rem));
  pointer-events: none;
}
.toast {
  pointer-events: auto;
  padding: 10px 14px; border-radius: var(--radius-sm, 6px);
  background: var(--bg-card); color: var(--text);
  border: 1px solid var(--border);
  box-shadow: 0 4px 12px rgba(0, 0, 0, .15);
  font-size:0.9rem; line-height: 1.4;
  cursor: pointer; user-select: none;
  animation: toast-in .18s ease-out;
}
.toast-info    { border-left: 3px solid var(--accent); }
.toast-success { border-left: 3px solid var(--green, #28a745); }
.toast-error   { border-left: 3px solid var(--red, #d9534f); }
@keyframes toast-in {
  from { transform: translateY(8px); opacity: 0; }
  to   { transform: translateY(0); opacity: 1; }
}

/* === useSort primitive (req:4532) === */
.sort-asc::after  { content: " \25B2"; opacity: .55; font-size:0.8em; }
.sort-desc::after { content: " \25BC"; opacity: .55; font-size:0.8em; }

/* === StatTile / StatTileGrid primitives (req:4530) ===
 * Drop-in for the recurring "display:grid + repeat(auto-fit,
 * minmax(Npx, 1fr))" inline pattern. The grid's min column width
 * is driven by the --stat-tile-min CSS custom property (default 160px),
 * settable per-call via the StatTileGrid `min` prop. */
.stat-tile-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(var(--stat-tile-min, 160px), 1fr));
  gap: .75rem;
  margin-bottom: 1rem;
}
.stat-tile {
  padding: 1rem;
  display: flex; flex-direction: column; gap: 4px;
}
.stat-tile-label { font-size:0.85rem; opacity: .7; }
.stat-tile-value { font-size: 1.5rem; font-weight: 700; }
.stat-tile-sub { font-size:0.8rem; opacity: .6; }

/* === Page header primitive (req:7vt12tjmfy, guideline §6/§20.4) ===
   One owner of the page/section <h2> margin. Default carries top-of-page
   breathing room; `.page-header-flush` drops the top margin for containers
   that already provide it (admin `.container` padding) or a sibling above
   (dashboard tab strip). */
.page-header { margin: 1.5rem 0 0.5rem; }
.page-header-flush { margin: 0 0 0.5rem; }
.page-header-title { margin: 0; }
.page-header-subtitle { margin: 0.25rem 0 0; color: var(--text-dim); }

/* === Whole-row navigation link (req:fn8c7n8t6m, §17/§20.18) ===
   Turns a clickable table row into a REAL link: a <router-link class=
   "row-link-cell"> in one cell whose ::before overlay covers the entire row.
   The <tr> is position:relative so the overlay's absolutely-positioned pseudo
   anchors to the row (not just its own cell). This gives a real href
   (middle-click / Ctrl-click open a new tab), Tab focus + Enter activation, and
   full-row left-click — without wrapping every cell's content in a link. Cells
   with their own interactive controls opt ABOVE the overlay via
   .row-link-actions so those buttons stay clickable and their empty space does
   not navigate. */
tr.row-link { position: relative; cursor: pointer; }
.row-link-cell { color: inherit; text-decoration: none; }
.row-link-cell::before { content: ""; position: absolute; inset: 0; z-index: 0; }
.row-link-cell:focus-visible { outline: none; }
.row-link-cell:focus-visible::before {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
tr.row-link .row-link-actions { position: relative; z-index: 1; }

/* === Analysis Engines === */
.analysis-engines { display: flex; gap: 8px; flex-wrap: wrap; }

/* === Connections === */
.connections-list { display: flex; flex-direction: column; gap: 8px; }
.connection-item {
  display: flex; justify-content: space-between; align-items: center;
  padding: 12px 16px; background: var(--bg-card); border-radius: var(--radius);
  border: 1px solid var(--border); box-shadow: var(--shadow-sm);
}
.connection-info { display: flex; align-items: center; gap: 12px; }
.connection-name { font-weight: 600; }
.connection-actions { display: flex; gap: 8px; }

/* === Strategy Wizard (three columns) === */
.wizard-columns { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; }
.wizard-col { display: flex; flex-direction: column; }
.wizard-col textarea { flex: 1; }
@media (max-width: 900px) { .wizard-columns { grid-template-columns: 1fr; } }

/* req:4630 — step-by-step strategy wizard. */
.wizard-rail {
  display: flex; gap: 4px; margin: 8px 0 16px; flex-wrap: wrap;
}
.wizard-rail-step {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 12px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--bg); color: var(--text-dim); cursor: pointer;
  font-size:0.82rem; transition: background .12s, border-color .12s;
}
.wizard-rail-step:disabled { cursor: default; opacity: .55; }
.wizard-rail-step.rail-active { border-color: var(--accent); color: var(--text); background: var(--bg-hover); }
.wizard-rail-step.rail-done { color: var(--text); }
.wizard-rail-num {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--border); color: var(--text); font-size:0.72rem; font-weight: 600;
}
.wizard-rail-step.rail-active .wizard-rail-num { background: var(--accent); color: #fff; }
.wizard-rail-step.rail-done .wizard-rail-num { background: var(--green, #2e7d32); color: #fff; }
.wizard-step { display: flex; flex-direction: column; min-height: 320px; margin-bottom: 16px; }
.wizard-nav { display: flex; align-items: center; gap: 8px; margin-top: 8px; }
/* @trace req:4817 — top mirror of the nav bar; sits between the step rail and
   the step card so Back/Continue are reachable without scrolling. */
.wizard-nav-top { margin-top: 0; margin-bottom: 12px; }
@media (max-width: 700px) { .wizard-rail-title { display: none; } }

/* === Strategy Wizard (two-column legacy) === */
.wizard-layout { display: flex; min-height: calc(100vh - 57px); }
.wizard-sidebar {
  width: 280px; min-width: 280px;
  background: var(--bg-card);
  border-right: 1px solid var(--border);
  padding: 16px;
  display: flex; flex-direction: column; gap: 4px;
}
.sidebar-section { padding: 12px 0; border-bottom: 1px solid var(--border); }
.sidebar-label { font-size:0.75rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: .05em; display: block; margin-bottom: 6px; font-family: 'Space Grotesk', sans-serif; font-weight: 600; }
.sidebar-actions { display: flex; gap: 8px; margin-top: auto; padding-top: 16px; border-bottom: none; }

.wizard-main {
  flex: 1;
  display: flex; flex-direction: column;
  padding: 20px 24px;
}
.wizard-editor-header {
  display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;
}
.wizard-editor-header h2 { font-size: 1.1rem; }
.wizard-textarea {
  flex: 1; min-height: 300px;
  background: var(--bg); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 16px; font-size:0.9rem; line-height: 1.6;
  font-family: 'DM Sans', sans-serif;
}

/* === Source List === */
.source-list { display: flex; flex-direction: column; gap: 2px; }
.source-item {
  display: flex; align-items: center; gap: 6px;
  padding: 6px 10px; border-radius: var(--radius-sm);
  font-size:0.85rem;
  cursor: pointer; transition: all .15s;
}
.source-item:hover { background: var(--bg-hover); }
.source-item.active { background: var(--accent); color: #fff; }
.source-item.loading { opacity: .7; }
.source-icon { font-size: 1rem; width: 20px; text-align: center; }
.source-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.source-status { font-size:0.75rem; }

/* === Markdown Content === */
.md-content { font-size:0.9rem; line-height: 1.7; color: var(--text-dim); }
.md-content h1, .md-content h2, .md-content h3 { color: var(--text); margin: 16px 0 8px; font-family: 'Space Grotesk', sans-serif; }
.md-content p { margin-bottom: 8px; }
.md-content ul, .md-content ol { margin-left: 20px; margin-bottom: 8px; }

/* === Nav Links === */
.header-right { display: flex; gap: 8px; align-items: center; }
.header-right a { text-decoration: none; }

/* === Section Labels (card-stack style) === */
.section-label {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 600; font-size:0.8rem;
  text-transform: uppercase; letter-spacing: .15em;
  color: var(--accent); margin-bottom: 8px;
}
.section-heading {
  font-size: clamp(2rem, 4vw, 3rem);
  font-weight: 700; letter-spacing: -0.02em;
  margin-bottom: 40px; max-width: 600px;
}

/* === Profile === */
.profile-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; margin-top: 12px; }
.dabble-count { font-size: 1.5rem; font-weight: 700; font-family: 'Space Grotesk', sans-serif; color: var(--accent); }
.tier-current { font-size:0.95rem; color: var(--text-dim); }
.tier-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px; }
.tier-card { padding: 16px; background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius); text-align: center; transition: all .2s; }
.tier-card.active { border-color: var(--accent); background: var(--accent-bg); box-shadow: 0 0 0 2px var(--accent); }
.tier-name { font-family: 'Space Grotesk', sans-serif; font-weight: 700; font-size: 1.1rem; margin-bottom: 4px; }
.tier-price { color: var(--accent); font-weight: 600; }
.tier-dabbles { color: var(--text-dim); font-size:0.85rem; margin-bottom: 8px; }
.pack-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 12px; }
.pack-card { padding: 16px; background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius); text-align: center; }
.pack-amount { font-weight: 700; font-family: 'Space Grotesk', sans-serif; }
.pack-price { color: var(--accent); font-weight: 600; margin: 4px 0 8px; }
.data-table { border-collapse: collapse; }
.data-table td { padding: 6px 12px; border-bottom: 1px solid var(--border); font-size:0.9rem; }

/* ============================================================
   PRICING PAGE
   ============================================================ */

.pricing-page { max-width: 1100px; margin: 0 auto; padding: 60px 24px 80px; }
.pricing-page .section-heading { text-align: center; margin: 0 auto 12px; }
.pricing-subtitle { text-align: center; color: var(--text-dim); font-size: 1.1rem; max-width: 520px; margin: 0 auto 48px; }

/* @trace code:kjw9680c1x req:8eherqh3yq */
.pricing-grid {
  display: grid;
  /* auto-fit (not a hard-coded 4) so the row always fills with exactly the
     cards that render: when a tier is dropped (e.g. curious is not
     subscribable, req:8eherqh3yq) the empty track collapses and the
     remaining cards expand to fill, staying centred instead of clinging to
     the left with a blank column on the right. Desktop still lands on 4
     equal tracks when 4 cards show; the media queries below govern
     tablet/mobile. */
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  justify-content: center;
  gap: 0;
  position: relative;
}

.pricing-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 32px 24px;
  display: flex; flex-direction: column;
  box-shadow: var(--shadow);
  transition: transform .3s cubic-bezier(0.22, 1, 0.36, 1), box-shadow .3s;
  position: relative;
}

.pricing-card:nth-child(1) { transform: rotate(-1.5deg); z-index: 2; margin-right: -6px; }
.pricing-card:nth-child(2) { transform: rotate(0.8deg); z-index: 3; margin-left: -6px; margin-right: -6px; }
.pricing-card:nth-child(3) { transform: rotate(-0.5deg); z-index: 4; margin-left: -6px; margin-right: -6px; }
.pricing-card:nth-child(4) { transform: rotate(1.2deg); z-index: 3; margin-left: -6px; }

.pricing-card:hover {
  transform: rotate(0) translateY(-8px) !important;
  box-shadow: var(--shadow-xl);
  z-index: 10 !important;
}

.pricing-card.featured {
  background: var(--charcoal);
  color: #fff;
  border-color: var(--charcoal-light);
  box-shadow: var(--shadow-dark);
}
.pricing-card.featured .pricing-card-price { color: var(--accent-light); }
.pricing-card.featured .pricing-feature { color: #9ca3af; border-bottom-color: #2a2a2a; }
.pricing-card.featured .pricing-feature-icon { color: var(--accent-light); }
.pricing-card.featured .pricing-dabbles { color: #9ca3af; }
.pricing-card.featured .text-dim { color: #9ca3af; }

.pricing-card.current { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent), var(--shadow-lg); }

.pricing-popular {
  position: absolute; top: -12px; left: 50%; transform: translateX(-50%);
  background: var(--accent); color: #fff;
  font-family: 'Space Grotesk', sans-serif; font-weight: 700; font-size:0.7rem;
  text-transform: uppercase; letter-spacing: .1em;
  padding: 4px 14px; border-radius: 20px;
  white-space: nowrap;
}

.pricing-card-name {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700; font-size: 1.3rem;
  margin-bottom: 4px;
}

.pricing-card-price {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700; font-size: 2.2rem;
  color: var(--accent); letter-spacing: -0.03em;
  line-height: 1.1;
}
.pricing-card-price span { font-size:0.9rem; font-weight: 500; color: var(--text-dim); }

.pricing-dabbles {
  color: var(--text-dim); font-size:0.85rem; margin-top: 4px; margin-bottom: 20px;
  padding-bottom: 20px; border-bottom: 1px solid var(--border);
}
.pricing-card.featured .pricing-dabbles { border-bottom-color: #2a2a2a; }

.pricing-features { list-style: none; flex: 1; display: flex; flex-direction: column; gap: 0; margin-bottom: 24px; }
.pricing-feature {
  display: flex; align-items: flex-start; gap: 8px;
  padding: 8px 0; font-size:0.85rem; color: var(--text-dim);
  border-bottom: 1px solid var(--border);
  line-height: 1.4;
}
.pricing-feature:last-child { border-bottom: none; }
.pricing-feature-icon { flex-shrink: 0; font-size:0.85rem; margin-top: 1px; }
.pricing-feature-icon.check { color: var(--green); }
.pricing-feature-icon.dash { color: var(--text-muted); }

.pricing-card .btn-primary { width: 100%; justify-content: center; }
.pricing-card .btn { width: 100%; text-align: center; }

.pricing-section {
  margin-top: 60px; text-align: center;
}
.pricing-section h3 { margin-bottom: 24px; }

.pricing-costs-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 12px; max-width: 700px; margin: 0 auto;
}
.pricing-cost-card {
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 16px; text-align: center;
  box-shadow: var(--shadow-sm);
}
.pricing-cost-value {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700; font-size: 1.5rem; color: var(--accent);
}
.pricing-cost-label { font-size:0.85rem; color: var(--text-dim); margin-top: 2px; }

@media (max-width: 1024px) {
  .pricing-grid { grid-template-columns: 1fr 1fr; gap: 16px; }
  .pricing-card:nth-child(1),
  .pricing-card:nth-child(2),
  .pricing-card:nth-child(3),
  .pricing-card:nth-child(4) { margin: 0; }
  .pricing-card:nth-child(odd) { transform: rotate(-0.8deg); }
  .pricing-card:nth-child(even) { transform: rotate(0.8deg); }
}
@media (max-width: 600px) {
  .pricing-grid { grid-template-columns: 1fr; }
  .pricing-card:nth-child(odd),
  .pricing-card:nth-child(even) { transform: none; }
  .pricing-page { padding: 40px 16px 60px; }
}

/* ============================================================
   LANDING PAGE — Card Stack Homepage
   ============================================================ */

.landing { overflow-x: hidden; }

/* Hero */
.landing-hero {
  min-height: calc(100vh - 60px);
  display: flex; align-items: center; justify-content: center;
  padding: 80px 40px;
  position: relative;
}

.hero-stack {
  position: relative;
  max-width: 900px; width: 100%;
}

.hero-accent-rect {
  position: absolute;
  top: -30px; right: -40px;
  width: 360px; height: 200px;
  background: var(--accent);
  border-radius: 16px;
  transform: rotate(3deg);
  z-index: 1;
  box-shadow: var(--shadow-lg);
}

.hero-accent-rect-2 {
  position: absolute;
  bottom: -20px; left: -30px;
  width: 200px; height: 140px;
  background: var(--accent-light);
  border-radius: 12px;
  transform: rotate(-5deg);
  z-index: 1;
  opacity: 0.6;
  box-shadow: var(--shadow);
}

.hero-dark-card {
  position: relative; z-index: 3;
  background: #181a20 !important;
  border-radius: 20px;
  padding: 60px 56px;
  box-shadow: var(--shadow-dark);
  transform: rotate(-1.5deg);
}

.hero-dark-card h1 {
  color: #fff !important;
  font-size: clamp(2.5rem, 6vw, 4.5rem);
  font-weight: 700;
  letter-spacing: -0.03em;
}

.hero-dark-card h1 span { color: var(--accent); }

.hero-white-card {
  position: relative; z-index: 4;
  background: var(--bg-card);
  border-radius: 16px;
  padding: 32px 40px;
  margin-top: -20px;
  margin-left: 40px;
  margin-right: -20px;
  box-shadow: var(--shadow-lg);
  transform: rotate(0.5deg);
}

.hero-white-card p {
  font-size: 1.15rem;
  color: var(--text-dim);
  line-height: 1.7;
  max-width: 560px;
}

.hero-actions { display: flex; gap: 16px; margin-top: 24px; flex-wrap: wrap; }

.hero-btn-secondary {
  display: inline-flex; align-items: center; gap: 8px;
  background: transparent; color: var(--charcoal);
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 600; font-size: 1rem;
  padding: 12px 24px; border-radius: 10px;
  text-decoration: none;
  border: 2px solid var(--border);
  cursor: pointer;
  transition: transform .2s, border-color .2s, box-shadow .2s;
}
.hero-btn-secondary:hover { border-color: var(--charcoal); transform: translateY(-2px); box-shadow: var(--shadow); }

.hero-badge {
  position: absolute;
  top: -50px; left: 50px; z-index: 5;
  background: var(--bg-card);
  border-radius: 50px;
  padding: 10px 20px;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 600; font-size: 0.85rem;
  box-shadow: var(--shadow-lg);
  transform: rotate(-4deg);
  color: var(--charcoal);
}

.hero-badge::before {
  content: '';
  display: inline-block;
  width: 8px; height: 8px;
  background: var(--green);
  border-radius: 50%;
  margin-right: 8px;
  animation: pulse-dot 2s infinite;
}

@keyframes pulse-dot {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.4; }
}

/* Features */
.landing-features {
  padding: 80px 40px 100px;
  max-width: 1200px; margin: 0 auto;
}

.landing-features-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
  position: relative;
  min-height: 700px;
}

.landing-feature-card {
  position: relative;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 36px 32px;
  box-shadow: var(--shadow-lg);
  transition: transform .4s cubic-bezier(0.22, 1, 0.36, 1), box-shadow .4s ease;
  cursor: default;
}

.landing-feature-card:hover {
  transform: translateY(-8px) rotate(0deg) !important;
  box-shadow: var(--shadow-xl);
  z-index: 10 !important;
}

.landing-feature-card:nth-child(1) { transform: rotate(-2deg); z-index: 6; margin-right: -10px; margin-bottom: -20px; }
.landing-feature-card:nth-child(2) { transform: rotate(1.5deg); z-index: 5; margin-top: 30px; margin-left: -10px; margin-right: -10px; }
.landing-feature-card:nth-child(3) { transform: rotate(-1deg); z-index: 4; margin-top: 10px; margin-left: -10px; }
.landing-feature-card:nth-child(4) { transform: rotate(1deg); z-index: 3; margin-right: -10px; margin-top: -20px; }
.landing-feature-card:nth-child(5) { transform: rotate(-1.8deg); z-index: 7; margin-left: -10px; margin-right: -10px; margin-top: -10px; }
.landing-feature-card:nth-child(6) { transform: rotate(2deg); z-index: 2; margin-left: -10px; margin-top: -30px; }

.landing-feature-card.dark {
  background: var(--charcoal);
  color: #fff;
  border-color: var(--charcoal-light);
}
.landing-feature-card.dark .feature-desc { color: #9ca3af; }
.landing-feature-card.dark .feature-number { color: var(--accent); }

.feature-icon {
  width: 52px; height: 52px;
  border-radius: 14px;
  display: flex; align-items: center; justify-content: center;
  font-size: 24px;
  margin-bottom: 20px;
  background: var(--accent-bg);
  color: var(--accent);
  box-shadow: var(--shadow-sm);
}
.landing-feature-card.dark .feature-icon { background: rgba(249, 115, 22, 0.15); }

.feature-number {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700; font-size:0.75rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: .1em;
  margin-bottom: 10px;
}
.feature-title { font-size: 1.35rem; font-weight: 700; margin-bottom: 10px; letter-spacing: -0.01em; }
.feature-desc { font-size:0.95rem; color: var(--text-dim); line-height: 1.65; }

/* Stats */
.landing-stats {
  padding: 60px 40px 100px;
  max-width: 1200px; margin: 0 auto;
  text-align: center;
}

.landing-stats-row {
  display: flex; justify-content: center; gap: 20px; flex-wrap: wrap;
}

.landing-stat-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 28px 36px;
  box-shadow: var(--shadow-lg);
  text-align: center;
  transition: transform .4s cubic-bezier(0.22, 1, 0.36, 1), box-shadow .3s;
  flex: 0 0 auto; min-width: 170px;
}
.landing-stat-card:hover { transform: translateY(-6px) rotate(0deg) !important; box-shadow: var(--shadow-xl); z-index: 5; }
.landing-stat-card:nth-child(1) { transform: rotate(-3deg) translateY(10px); }
.landing-stat-card:nth-child(2) { transform: rotate(1.5deg) translateY(-8px); background: var(--charcoal); color: #fff; border-color: var(--charcoal-light); }
.landing-stat-card:nth-child(3) { transform: rotate(-1deg) translateY(5px); }
.landing-stat-card:nth-child(4) { transform: rotate(2.5deg) translateY(-12px); }

.stat-number {
  font-family: 'Space Grotesk', sans-serif;
  font-size: 2.5rem; font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--accent); line-height: 1; margin-bottom: 6px;
}
.landing-stat-card:nth-child(2) .stat-number { color: var(--accent-light); }

.stat-label { font-size:0.85rem; font-weight: 500; color: var(--text-dim); }
.landing-stat-card:nth-child(2) .stat-label { color: #9ca3af; }

/* Marquee */
.landing-marquee {
  padding: 40px 0; overflow: hidden;
}

.marquee-track {
  display: flex; width: max-content;
  animation: marquee-scroll 30s linear infinite;
}
.marquee-track:hover { animation-play-state: paused; }

.marquee-content {
  display: flex; align-items: center;
  flex-shrink: 0;
}

.marquee-item {
  font-family: 'Space Grotesk', sans-serif;
  font-size: 1.4rem; font-weight: 700;
  color: var(--charcoal);
  white-space: nowrap;
  padding: 14px 24px;
  opacity: 0.2;
  transition: opacity .3s;
}
.marquee-item:hover { opacity: 1; }

.marquee-dot {
  width: 8px; height: 8px;
  background: var(--accent);
  border-radius: 50%;
  flex-shrink: 0;
}

@keyframes marquee-scroll {
  0% { transform: translateX(0); }
  100% { transform: translateX(-50%); }
}

/* How it works */
.landing-how {
  padding: 80px 40px;
  max-width: 1100px; margin: 0 auto;
}

.hiw-cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 40px; margin-top: 50px;
  position: relative;
}

.hiw-cards::before {
  content: '';
  position: absolute; top: 32px; left: 15%; right: 15%;
  height: 3px;
  background: linear-gradient(90deg, var(--accent), var(--accent-light), var(--accent));
  border-radius: 2px; z-index: 0; opacity: 0.3;
}

.hiw-card { position: relative; z-index: 1; text-align: center; }

.hiw-num {
  width: 64px; height: 64px;
  border-radius: 16px;
  background: var(--charcoal); color: var(--accent);
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700; font-size: 1.5rem;
  display: flex; align-items: center; justify-content: center;
  margin: 0 auto 24px;
  box-shadow: var(--shadow-dark);
  transition: transform .3s;
}
.hiw-card:nth-child(1) .hiw-num { transform: rotate(-4deg); }
.hiw-card:nth-child(2) .hiw-num { transform: rotate(2deg); }
.hiw-card:nth-child(3) .hiw-num { transform: rotate(-3deg); }
.hiw-card:hover .hiw-num { transform: rotate(0deg) scale(1.1); }

.hiw-body {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 32px 24px;
  box-shadow: var(--shadow-lg);
  transition: transform .3s, box-shadow .3s;
}
.hiw-card:nth-child(1) .hiw-body { transform: rotate(1deg); }
.hiw-card:nth-child(2) .hiw-body { transform: rotate(-0.8deg); }
.hiw-card:nth-child(3) .hiw-body { transform: rotate(1.5deg); }
.hiw-card:hover .hiw-body { transform: rotate(0deg) translateY(-4px); box-shadow: var(--shadow-xl); }

.hiw-title { font-size: 1.15rem; font-weight: 700; margin-bottom: 8px; }
.hiw-desc { font-size:0.92rem; color: var(--text-dim); line-height: 1.65; }

/* CTA */
.landing-cta {
  padding: 60px 40px 100px;
  max-width: 900px; margin: 0 auto;
  position: relative;
}

.cta-bg-card {
  position: absolute;
  top: 50px; left: 20px; right: 60px; bottom: 70px;
  background: var(--accent);
  border-radius: 24px;
  transform: rotate(2deg);
  box-shadow: var(--shadow-lg);
}

.cta-card {
  position: relative; z-index: 2;
  background: var(--charcoal);
  border-radius: 24px;
  padding: 72px 56px;
  text-align: center;
  box-shadow: var(--shadow-dark);
  transform: rotate(-1deg);
  transition: transform .4s;
}
.cta-card:hover { transform: rotate(0deg); }

.cta-card h2 {
  color: #fff;
  font-size: clamp(2rem, 4vw, 2.8rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  margin-bottom: 16px;
}
.cta-card h2 span { color: var(--accent); }
.cta-card p { color: #9ca3af; font-size: 1.1rem; max-width: 480px; margin: 0 auto 32px; line-height: 1.7; }

/* Scroll reveal animations */
.reveal {
  opacity: 0;
  transition: opacity .8s cubic-bezier(0.22, 1, 0.36, 1), transform .8s cubic-bezier(0.22, 1, 0.36, 1);
}
.reveal.from-left { transform: translateX(-60px) rotate(4deg); }
.reveal.from-right { transform: translateX(60px) rotate(-4deg); }
.reveal.from-bottom { transform: translateY(60px) rotate(2deg); }
.reveal.from-bottom-alt { transform: translateY(60px) rotate(-2deg); }
.reveal.from-scale { transform: scale(0.85) rotate(-1deg); }
.reveal.visible { opacity: 1; transform: none; }

/* Re-apply card rotations after reveal */
.landing-feature-card.reveal.visible:nth-child(1) { transform: rotate(-2deg); }
.landing-feature-card.reveal.visible:nth-child(2) { transform: rotate(1.5deg); }
.landing-feature-card.reveal.visible:nth-child(3) { transform: rotate(-1deg); }
.landing-feature-card.reveal.visible:nth-child(4) { transform: rotate(1deg); }
.landing-feature-card.reveal.visible:nth-child(5) { transform: rotate(-1.8deg); }
.landing-feature-card.reveal.visible:nth-child(6) { transform: rotate(2deg); }

.landing-stat-card.reveal.visible:nth-child(1) { transform: rotate(-3deg) translateY(10px); }
.landing-stat-card.reveal.visible:nth-child(2) { transform: rotate(1.5deg) translateY(-8px); }
.landing-stat-card.reveal.visible:nth-child(3) { transform: rotate(-1deg) translateY(5px); }
.landing-stat-card.reveal.visible:nth-child(4) { transform: rotate(2.5deg) translateY(-12px); }

/* === Responsive === */

/* Tablet */
@media (max-width: 1024px) {
  .metrics-row { gap: 8px; }
  .metric-card { min-width: 120px; padding: 10px 14px; }
  .page-content { padding: 16px; }
  .wizard-sidebar { width: 240px; min-width: 240px; }

  .landing-features-grid {
    grid-template-columns: 1fr 1fr;
    min-height: auto; gap: 16px;
  }
  .landing-feature-card:nth-child(1),
  .landing-feature-card:nth-child(2),
  .landing-feature-card:nth-child(3),
  .landing-feature-card:nth-child(4),
  .landing-feature-card:nth-child(5),
  .landing-feature-card:nth-child(6) { margin: 0; }
  .landing-feature-card:nth-child(odd) { transform: rotate(-1deg); }
  .landing-feature-card:nth-child(even) { transform: rotate(1deg); }
  .landing-feature-card.reveal.visible:nth-child(odd) { transform: rotate(-1deg); }
  .landing-feature-card.reveal.visible:nth-child(even) { transform: rotate(1deg); }

  .hiw-cards { grid-template-columns: 1fr; gap: 30px; }
  .hiw-cards::before { display: none; }
}

/* Mobile */
@media (max-width: 768px) {
  .header { padding: max(10px, env(safe-area-inset-top)) max(12px, env(safe-area-inset-right)) 10px max(12px, env(safe-area-inset-left)); flex-wrap: wrap; gap: 8px; }
  .header h1 { font-size: 1rem; }
  .header-right { gap: 4px; }
  .header-right .btn-sm { padding: 4px 8px; font-size:0.75rem; }

  .page-content { padding: 12px; }
  .detail-view { padding: 0 12px 24px; }

  /* @trace req:4994 code:? — symbol drilldown header: without wrapping, the long
     company-name title held this flex row wider than the viewport and the
     right-side action group (Star + ☰ menu, margin-left:auto) was pushed off
     the right edge and became unreachable. Wrap the row and drop the title
     onto its own full-width line so the back button + action group share a
     reachable top row (the ☰ dropdown opens flush-right, staying on-screen). */
  .detail-header { flex-wrap: wrap; gap: 12px; padding: 16px 0; }
  .detail-header .detail-title { order: 3; flex-basis: 100%; }
  .detail-header-actions { flex-shrink: 1; }
  /* Belt-and-braces: the ☰ dropdown opens right:0 against the action group
     (now hard against the viewport's right edge) and grows leftward from its
     min-width:230px. Clamp it to the viewport so it can never clip off the
     left edge on a very narrow (≈320px) phone. */
  .symbol-menu-dropdown { max-width: calc(100vw - 24px); }

  .filters { padding: 12px; gap: 8px; }
  .filter-group select, .filter-group input { min-width: 100px; font-size:0.8rem; }

  .strategies-grid { grid-template-columns: 1fr; }
  .strategy-card:nth-child(3n+1),
  .strategy-card:nth-child(3n+2),
  .strategy-card:nth-child(3n+3) { transform: none; }

  .params-grid { grid-template-columns: 1fr; }
  .metrics-row { flex-direction: column; }
  .metric-card { min-width: auto; }

  .wizard-layout { flex-direction: column; }
  .wizard-sidebar { width: 100%; min-width: auto; border-right: none; border-bottom: 1px solid var(--border); }
  .sidebar-actions { margin-top: 8px; }
  .wizard-textarea { min-height: 200px; }

  .holdings-grid { grid-template-columns: repeat(2, 1fr); }
  .financial-grid { grid-template-columns: repeat(2, 1fr); }
  .params-display { grid-template-columns: 1fr; }

  .connection-item { flex-direction: column; align-items: flex-start; gap: 8px; }

  .stock-table { font-size:0.75rem; }
  .stock-table th, .stock-table td { padding: 6px 8px; }

  .modal-card { width: 95%; }

  /* Landing responsive */
  .landing-hero { padding: 60px 20px; }
  .hero-accent-rect { width: 180px; height: 120px; right: -15px; top: -15px; }
  .hero-accent-rect-2 { width: 120px; height: 90px; left: -10px; bottom: -10px; }
  .hero-dark-card { padding: 36px 28px; transform: rotate(-0.5deg); }
  .hero-white-card { margin-left: 10px; margin-right: 0; padding: 24px; }
  .hero-badge { left: 20px; top: -40px; font-size:0.75rem; padding: 8px 14px; }

  .landing-features, .landing-stats, .landing-how, .landing-cta { padding-left: 20px; padding-right: 20px; }

  .landing-features-grid { grid-template-columns: 1fr; }
  .landing-feature-card:nth-child(odd),
  .landing-feature-card:nth-child(even) { transform: none; }
  .landing-feature-card.reveal.visible:nth-child(odd),
  .landing-feature-card.reveal.visible:nth-child(even) { transform: none; }

  .landing-stats-row { flex-direction: column; align-items: center; }
  .landing-stat-card { min-width: 240px; }
  .landing-stat-card:nth-child(1),
  .landing-stat-card:nth-child(2),
  .landing-stat-card:nth-child(3),
  .landing-stat-card:nth-child(4) { transform: none; }
  .landing-stat-card.reveal.visible:nth-child(1),
  .landing-stat-card.reveal.visible:nth-child(2),
  .landing-stat-card.reveal.visible:nth-child(3),
  .landing-stat-card.reveal.visible:nth-child(4) { transform: none; }

  .cta-bg-card { left: 10px; right: 30px; top: 40px; bottom: 60px; }
  .cta-card { padding: 48px 28px; transform: rotate(0deg); }

  .marquee-item { font-size: 1.1rem; }
}

/* ============================================================
   SIMULATION
   ============================================================ */

/* `.modal-backdrop` removed (req:4512, REFACTOR V6) — its 2 sites in
   strategies.ts now use `.modal-overlay` (defined at line 1015 in the
   Modal section above) like the other 14 modal sites. `.modal-box`
   remains distinct from `.modal-card` because the two are different
   concepts (self-contained styled card vs help-chat-aware layout
   helper). */
.modal-box {
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: 28px 32px;
  width: 90%; max-width: 480px; max-height: 90vh; overflow-y: auto;
  box-shadow: var(--shadow-xl);
}
.modal-box h3 { margin-bottom: 16px; }
.modal-box .form-group { margin-bottom: 12px; }
.modal-box .form-group label { display: block; font-size:0.85rem; color: var(--text-dim); margin-bottom: 4px; }
.modal-box .input-range { width: 80%; vertical-align: middle; }

.sim-summary {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 12px; margin-bottom: 20px;
}
.sim-card {
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 16px;
  text-align: center; box-shadow: var(--shadow-sm);
}
.sim-card.positive { border-left: 3px solid var(--green); }
.sim-card.negative { border-left: 3px solid var(--red); }
.sim-card.neutral { border-left: 3px solid var(--text-muted); }
.sim-card-label { font-size:0.75rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: .05em; margin-bottom: 4px; }
.sim-card-value {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700; font-size: 1.3rem;
}
.sim-card.positive .sim-card-value { color: var(--green); }
.sim-card.negative .sim-card-value { color: var(--red); }

/* @trace req:4754 — backtest warnings (excluded live-only criteria):
   prominent, distinct from the dim informational caveats box. */
.sim-warnings {
  margin-top: 8px; padding: 10px 12px;
  border-left: 3px solid var(--yellow);
  background: color-mix(in srgb, var(--yellow) 12%, transparent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  font-size:0.8rem; color: var(--text);
}
.sim-warnings-item { display: flex; gap: 8px; align-items: flex-start; }
.sim-warnings-item + .sim-warnings-item { margin-top: 6px; }

.table-scroll { overflow-x: auto; }
.data-table th {
  padding: 8px 12px; text-align: left; font-size:0.8rem;
  color: var(--text-dim); border-bottom: 2px solid var(--border);
  white-space: nowrap;
}
.tag-buy { background: var(--fit); color: var(--fit-text); padding: 2px 8px; border-radius: 4px; font-size:0.8rem; font-weight: 600; }
.tag-sell { background: var(--poor-fit); color: var(--poor-fit-text); padding: 2px 8px; border-radius: 4px; font-size:0.8rem; font-weight: 600; }

.sim-step-detail {
  margin-top: 16px; padding: 16px;
  background: var(--bg-inset); border-radius: var(--radius);
  border: 1px solid var(--border);
}
.expandable-header {
  display: flex; align-items: center; gap: 6px;
  cursor: pointer; padding: 6px 0;
  user-select: none;
}
.expandable-header:hover { opacity: 0.8; }
.expand-arrow { font-size:0.7rem; color: var(--text-dim); width: 12px; }

@media (max-width: 768px) {
  .sim-summary { grid-template-columns: repeat(2, 1fr); }
  .modal-box { width: 95%; padding: 20px; }
}

/* ============================================================
   Dashboard Overview
   ============================================================ */
.dash-overview h2 { margin-bottom: 16px; }
.dash-loading { text-align: center; padding: 60px 0; color: var(--text-dim); }

/* AI Highlights */
.dash-highlights {
  border-left: 3px solid var(--accent);
}
.dash-highlights-header {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 12px;
}
.dash-highlights-header h3 { margin-bottom: 0; }
.dash-hl-actions { display: flex; gap: 8px; align-items: center; }
.hl-hist-entry { padding: 14px 20px; }
.hl-hist-header {
  display: flex; align-items: center; gap: 10px; cursor: pointer;
  font-weight: 500; font-size:0.9rem; user-select: none;
}
.hl-hist-header:hover { color: var(--accent); }
.hl-hist-arrow {
  font-size:0.65rem; transition: transform .15s; color: var(--text-dim);
  display: inline-block; width: 12px;
}
.hl-hist-arrow.open { transform: rotate(90deg); }
.dash-hl-content { line-height: 1.65; font-size:0.9rem; }
/* @trace req:4948 code:? — newsletter headline shown above the summary body. */
.dash-hl-title { font-size: 1.05rem; font-weight: 700; margin: 0 0 12px; color: var(--text); line-height: 1.3; }
.dash-hl-content h3 { font-size:0.95rem; margin: 16px 0 6px; color: var(--accent); }
.dash-hl-content h3:first-child { margin-top: 0; }
.dash-hl-content ul { margin: 4px 0 12px 18px; }
.dash-hl-content li { margin-bottom: 4px; }
.dash-hl-content p { margin-bottom: 8px; }
.dash-hl-content strong { color: var(--text); }
/* @trace code:3249 req:4822
    — LLM briefings sometimes emit markdown horizontal
   rules (`---`) between sections and sometimes don't; hide them so the
   highlights format stays consistent (covers both the live card and the
   history entries, which share .dash-hl-content). */
.dash-hl-content hr { display: none; }
.hl-ticker-link { color: inherit; text-decoration: none; cursor: pointer; }
.hl-ticker-link:hover strong { color: var(--accent); }
.dash-hl-meta { margin-top: 12px; font-size:0.75rem; text-align: right; }
.dash-hl-placeholder { font-size:0.9rem; line-height: 1.5; padding: 8px 0; }
.dash-hl-error { color: var(--red); font-size:0.9rem; padding: 8px 0; }
.dash-hl-generating {
  display: flex; align-items: center; gap: 12px;
  padding: 16px 0; font-size:0.9rem; color: var(--text-dim);
}
.dash-hl-spinner {
  width: 20px; height: 20px; border: 2px solid var(--border);
  border-top-color: var(--accent); border-radius: 50%;
  animation: dash-spin 0.8s linear infinite; flex-shrink: 0;
}
@keyframes dash-spin { to { transform: rotate(360deg); } }
/* Newsletter generation progress bar (req:4914) — replaces the indeterminate
   spinner once the backend streams a stage. Track + accent fill, themed off
   the shared vars so it follows light/dark. */
.dash-hl-progress {
  flex: 1; min-width: 0; height: 8px; border-radius: 4px;
  background: var(--border); overflow: hidden;
}
.dash-hl-progress-fill {
  height: 100%; background: var(--accent); border-radius: 4px;
  transition: width 0.4s ease;
}

/* Newsletter card — dashboard access point (req:4826) */
.dash-newsletter-latest {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 8px 0; cursor: pointer;
}
.dash-newsletter-latest:hover .dash-nl-title { color: var(--accent); }
.dash-nl-title { font-weight: 600; font-size:0.9rem; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Inline, theme-aware newsletter rendering (req:4827).
   The server maps the email's fixed light palette onto CSS variables and
   wraps the body in `.newsletter-web`; these rules own typography/spacing
   so the fragment reads as a native app surface in both day and night. */
.stored-report-card { padding: 24px; }
.newsletter-web { color: var(--text); font-size:0.9rem; line-height: 1.6; }
.newsletter-web a { color: var(--accent); }
.newsletter-web h1, .newsletter-web h2, .newsletter-web h3 { color: var(--text); }
.newsletter-web table { max-width: 100%; }
.newsletter-web img { max-width: 100%; height: auto; }
.newsletter-web hr { display: none; }

/* Dabble balance bar */
.dash-dabble-bar {
  display: flex; align-items: center; gap: 16px;
  padding: 10px 16px; margin-bottom: 20px;
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.dash-dabble-info { display: flex; align-items: center; gap: 10px; white-space: nowrap; }
.dash-dabble-tier {
  text-transform: capitalize; font-weight: 600; font-size:0.8rem;
  padding: 2px 8px; border-radius: 4px;
  background: var(--accent-bg); color: var(--accent);
}
.dash-dabble-counts { font-size:0.85rem; color: var(--text-dim); }
.dash-dabble-counts strong { color: var(--text); }
.dash-dabble-track {
  flex: 1; height: 6px; background: var(--bg-inset);
  border-radius: 3px; overflow: hidden; min-width: 80px;
}
.dash-dabble-fill {
  height: 100%; border-radius: 3px;
  background: var(--green); transition: width .3s ease;
}
.dash-dabble-fill.dabble-low { background: var(--orange); }

/* Sections */
.dash-section {
  margin-bottom: 24px; padding: 20px;
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius);
}
.dash-section h3 {
  font-size: 1rem; font-weight: 600; margin-bottom: 12px;
  display: flex; align-items: center; gap: 8px;
}
.dash-empty p { color: var(--text-dim); font-size:0.9rem; }
.dash-sub-label {
  font-size:0.75rem; font-weight: 600; text-transform: uppercase;
  color: var(--text-dim); margin-bottom: 6px; letter-spacing: .03em;
}

/* Aggregate stat row */
.dash-agg-row {
  display: flex; gap: 24px; flex-wrap: wrap; margin-bottom: 16px;
  padding: 12px 16px; background: var(--bg-inset); border-radius: var(--radius-sm);
}
.dash-stat { display: flex; flex-direction: column; gap: 2px; }
.dash-stat-label { font-size:0.75rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: .03em; }
.dash-stat-value { font-size: 1.15rem; font-weight: 600; font-family: 'Space Grotesk', sans-serif; }

/* Cards grid */
.dash-cards {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 12px;
}

/* Portfolio header with sync */
.dash-portfolio-header {
  display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;
}
.dash-portfolio-header h3 { margin-bottom: 0; }
.dash-portfolio-sync { display: flex; align-items: center; gap: 10px; }

/* Portfolio card */
.dash-portfolio-card { cursor: pointer; padding: 14px; transition: box-shadow .15s; }
.dash-portfolio-card:hover { box-shadow: var(--shadow); }
.dash-portfolio-name { font-weight: 600; margin-bottom: 6px; }
.dash-portfolio-stats { display: flex; gap: 10px; align-items: baseline; font-size:0.9rem; flex-wrap: wrap; }
.dash-movers { margin-top: 6px; display: flex; gap: 8px; flex-wrap: wrap; }
.dash-mover { font-size:0.78rem; font-weight: 500; padding: 1px 6px; border-radius: 4px; }

/* Strategy card */
.dash-strategy-card { cursor: pointer; padding: 14px; transition: box-shadow .15s; }
.dash-strategy-card:hover { box-shadow: var(--shadow); }
.dash-strategy-name { font-weight: 600; margin-bottom: 4px; }
.dash-strategy-meta { font-size:0.8rem; display: flex; gap: 8px; align-items: center; }
.dash-strategy-scan { margin-top: 6px; font-size:0.85rem; display: flex; flex-direction: column; gap: 4px; }
.dash-tag {
  font-size:0.7rem; padding: 1px 6px; border-radius: 3px;
  background: var(--accent-bg); color: var(--accent); font-weight: 600;
}

/* Classification bar */
.dash-class-bar {
  display: flex; height: 5px; border-radius: 3px; overflow: hidden;
  background: var(--bg-inset); margin-top: 2px;
}
.dash-class-seg { min-width: 3px; }
.cls-fit { background: var(--green); }
.cls-poor-fit { background: var(--red); }
.cls-weak-fit { background: var(--yellow); }
.cls-other { background: var(--text-muted); }

/* Classification pills */
.dash-class-pills { display: inline-flex; gap: 4px; }
.dash-class-pill {
  font-size:0.7rem; font-weight: 600; padding: 1px 5px;
  border-radius: 3px; color: #fff;
}
.dash-class-pill.cls-fit { background: var(--green); }
.dash-class-pill.cls-poor-fit { background: var(--red); }
.dash-class-pill.cls-weak-fit { background: var(--yellow); color: #854d0e; }
.dash-class-pill.cls-other { background: var(--text-muted); }

/* Two-column layout */
.dash-two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
/* @trace req:4812 code:2589 — when only one section renders (Top Positions
   hidden under Tier-A preview, or the radar card hidden when empty), the row
   collapses to one full-width column instead of a stranded half-width box. */
.dash-two-col--single { grid-template-columns: 1fr; }

/* Decision rows */
.dash-decision-row {
  display: flex; align-items: center; gap: 8px; padding: 6px 0;
  border-bottom: 1px solid var(--border); cursor: pointer; font-size:0.85rem;
}
.dash-decision-row:last-child { border-bottom: none; }
.dash-decision-row:hover { background: var(--bg-hover); margin: 0 -8px; padding: 6px 8px; border-radius: 4px; }
.dash-decision-symbol { font-weight: 600; min-width: 50px; }
.dash-decision-type { font-size:0.7rem; font-weight: 600; padding: 1px 6px; border-radius: 3px; }
.dash-decision-price { font-size:0.8rem; color: var(--text-dim); white-space: nowrap; }
.dash-decision-return { font-weight: 600; min-width: 55px; text-align: right; }
.dash-decision-strat { font-size:0.75rem; margin-left: auto; }
.dtype-buy { background: var(--fit); color: var(--fit-text); }
.dtype-sell { background: var(--poor-fit); color: var(--poor-fit-text); }
.dtype-hold, .dtype-watch { background: var(--weak-fit); color: var(--weak-fit-text); }

/* Badge */
.dash-badge {
  font-size:0.7rem; font-weight: 600; padding: 2px 7px;
  border-radius: 4px; margin-left: 2px;
}

/* Scan rows */
.dash-scan-row {
  padding: 8px 0; border-bottom: 1px solid var(--border);
  cursor: pointer; font-size:0.85rem;
}
.dash-scan-row:last-child { border-bottom: none; }
.dash-scan-row:hover { background: var(--bg-hover); margin: 0 -8px; padding: 8px 8px; border-radius: 4px; }
.dash-scan-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 3px; }
.dash-scan-name { font-weight: 600; }
.dash-scan-stats { display: flex; gap: 10px; align-items: center; }

/* Holding rows */
.dash-holding-row {
  display: flex; align-items: center; gap: 8px; padding: 5px 0;
  border-bottom: 1px solid var(--border); cursor: pointer; font-size:0.85rem;
}
.dash-holding-row:last-child { border-bottom: none; }
.dash-holding-row:hover { background: var(--bg-hover); margin: 0 -8px; padding: 5px 8px; border-radius: 4px; }
.dash-holding-sym { font-weight: 600; min-width: 50px; }
.dash-holding-co { min-width: 100px; font-size:0.8rem; }
.dash-holding-score { font-weight: 600; min-width: 35px; text-align: right; }
.dash-holding-class { font-size:0.7rem; font-weight: 600; padding: 1px 6px; border-radius: 3px; }

/* Attention items */
.dash-attention-item {
  display: flex; align-items: center; gap: 8px; padding: 8px 10px;
  border-left: 3px solid var(--yellow); margin-bottom: 6px;
  background: var(--bg-inset); border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  font-size:0.85rem; cursor: pointer;
}
.dash-attention-item:hover { background: var(--bg-hover); }
.attn-stale_score { border-left-color: var(--orange); }
.attn-old_decision { border-left-color: var(--yellow); }
.attn-interrupted_scan { border-left-color: var(--red); }
.dash-attn-icon { font-size: 1rem; }

/* Activity rows */
/* req:4839 — slim themed scrollbar, matching the .table-wrap (req:4176)
   and .help-toc (req:4809) treatment, so the activity list's overflow
   chrome is the lean bar used elsewhere, not the OS-default chunky one.
   Pinned by tests/ts/scrollbar_slim_tablewrap.test.ts. */
.dash-activity-list {
  max-height: 320px;
  overflow-y: auto;
  padding-right: 12px;
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}
.dash-activity-list::-webkit-scrollbar { width: 8px; height: 8px; }
.dash-activity-list::-webkit-scrollbar-track { background: transparent; }
.dash-activity-list::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border-radius: 4px;
}
.dash-activity-list::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }
.dash-activity-row {
  display: flex; align-items: center; gap: 8px; padding: 6px 0;
  border-bottom: 1px solid var(--border); font-size:0.85rem;
}
.dash-activity-row:last-child { border-bottom: none; }
.dash-activity-row.clickable { cursor: pointer; }
.dash-activity-row.clickable:hover { background: var(--bg-hover); margin: 0 -8px; padding: 6px 8px; border-radius: 4px; }
.dash-act-icon { font-size:0.95rem; width: 22px; text-align: center; }
.dash-act-desc { flex: 1; }
.dash-act-dabbles { font-size:0.75rem; color: var(--orange); font-weight: 600; }
.dash-act-time { font-size:0.75rem; white-space: nowrap; min-width: 55px; text-align: right; }

/* ===== Monitoring ===== */
.monitoring-stats-banner {
  display: flex; gap: 12px; margin-bottom: 16px; flex-wrap: wrap;
}
.monitoring-stats-banner .stat-card {
  flex: 1; min-width: 120px; padding: 12px 16px; border-radius: 8px;
  background: var(--bg-card); border: 1px solid var(--border); cursor: pointer;
  text-align: center; transition: border-color 0.15s;
}
.monitoring-stats-banner .stat-card:hover { border-color: var(--accent); }
.monitoring-stats-banner .stat-card .stat-value { font-size: 1.5rem; font-weight: 700; color: var(--text); }
.monitoring-stats-banner .stat-card .stat-label { font-size: 0.75rem; color: var(--text-dim); margin-top: 2px; }
.monitoring-stats-banner .stat-attention .stat-value { color: var(--orange); }

.row-caution { background: color-mix(in srgb, var(--yellow) 12%, transparent) !important; }
.row-invalidated { background: color-mix(in srgb, var(--red) 10%, transparent) !important; }
.row-exceeded { background: color-mix(in srgb, var(--green) 10%, transparent) !important; }

.rating-exceed { background: var(--fit); color: var(--fit-text); }

.btn-xs {
  padding: 2px 8px; font-size: 0.7rem; border-radius: 4px;
  border: 1px solid var(--border); background: var(--bg-card); color: var(--text);
  cursor: pointer; transition: background 0.15s;
}
.btn-xs:hover { background: var(--bg-hover); }
.btn-xs:disabled { opacity: 0.5; cursor: default; }

.input-sm { padding: 2px 6px; font-size: 0.75rem; height: 26px; }

/* Responsive */
@media (max-width: 768px) {
  .dash-two-col { grid-template-columns: 1fr; }
  .dash-agg-row { gap: 16px; }
  .dash-cards { grid-template-columns: 1fr; }
  .dash-dabble-bar { flex-direction: column; align-items: stretch; }
  .dash-decision-price { display: none; }
  .dash-holding-co { display: none; }
  .monitoring-stats-banner { gap: 8px; }
  .monitoring-stats-banner .stat-card { min-width: 90px; padding: 8px 12px; }
}

/* ===== Dashboard Referral Vignette =====
   Sticky left rail on desktop (~240px), collapses to a top card on mobile
   so the layout still works on phones. The rail is only rendered when the
   /api/me/referral request succeeds, so logged-out / file-mode users see
   the dashboard exactly as before.
*/
/* Anchor the vignette near the top-left of the page, just below the
   header. `position: absolute` (not fixed) so it scrolls away naturally
   when the user moves down — it's a "welcome card" anchored to the top,
   not a persistent overlay. Out of the dashboard's content flow so the
   existing single-column layout stays untouched. Hidden under 900px to
   free up mobile/tablet real estate; same content lives on profile. */
.dash-rail {
  position: absolute;
  right: 16px;
  width: 260px;
  z-index: 5;
  /* `top` is set in JS so the rail tracks the Highlights section's
     vertical position rather than a fixed page offset. The fallback
     here covers the brief window before the first sync. */
  top: 84px;
}
/* Tighter screens — shrink the rail so it leaves more room for the
   dashboard column. The JS overlap detector in dashboard.ts measures
   the actual width and adjusts only the sections that visually
   overlap, so no column-wide padding rules are needed. */
@media (max-width: 1199px) {
  .dash-rail { width: 224px; }
}
@media (max-width: 900px) { .dash-rail { display: none; } }

/* Minimise button — small "−" tucked into the top-right of the card.
   The vignette itself is already position: relative, so absolute here
   anchors to the card. */
.referral-vignette .ref-min-btn {
  position: absolute;
  top: 6px; right: 8px;
  width: 22px; height: 22px;
  padding: 0;
  border: none; background: transparent;
  color: var(--text-dim); cursor: pointer;
  font-size: 1.1rem; line-height: 1;
  border-radius: 4px;
  display: flex; align-items: center; justify-content: center;
}
.referral-vignette .ref-min-btn:hover {
  background: var(--bg-hover); color: var(--text);
}

/* Minimised state — the rail collapses to a narrow vertical pill
   with text reading bottom-to-top (read it by tilting your head
   left). The `writing-mode: vertical-rl` puts text on a vertical
   axis with characters rotated 90° clockwise; the extra
   `rotate(180deg)` flips the whole pill so the reading direction
   becomes bottom-to-top and the characters end up rotated 90°
   counter-clockwise. The icon counter-rotates so it stays upright.
   Position (right edge, top anchored to Highlights) is inherited
   from `.dash-rail`; `is-min` only collapses the box width. */
.dash-rail.is-min {
  width: auto;
  max-width: none;
}
.ref-pill {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 12px 6px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 16px;
  color: var(--text);
  cursor: pointer;
  font-size:0.72rem; font-weight: 600; letter-spacing: .04em;
  box-shadow: var(--shadow-sm);
  font-family: inherit;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
}
.ref-pill:hover {
  border-color: var(--accent);
  background: var(--bg-hover);
}
.ref-pill .ref-pill-icon {
  color: var(--accent);
  font-size:0.9rem;
  writing-mode: horizontal-tb;
  transform: rotate(180deg);
}

/* Layered titled-card design — kept the structure that worked the first
   time (eyebrow + heading + accent rectangle peeking from behind), but
   in a light register: white card, soft borders, and the accent rect
   uses a tinted/low-opacity accent color instead of full saturation.
   The card itself stays in normal colors so it doesn't compete with
   the rest of the page. */

.referral-vignette-wrap {
  position: relative;
  padding: 10px 6px 6px 10px;  /* room for the floating rect */
}
.referral-vignette-wrap::before {
  /* Soft accent rectangle — very low opacity so it reads as a hint of
     color, not a billboard. Slight rotation echoes the landing-hero
     accent rects without screaming. */
  content: '';
  position: absolute;
  top: -4px; right: -4px;
  width: 80px; height: 50px;
  background: var(--accent);
  border-radius: 10px;
  transform: rotate(6deg);
  z-index: 0;
  opacity: 0.18;
}
.referral-vignette {
  position: relative; z-index: 1;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 16px 18px;
  box-shadow: var(--shadow-sm, 0 2px 6px rgba(0,0,0,.05));
}

.referral-vignette .ref-eyebrow {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700; font-size:0.62rem;
  color: var(--text-dim);
  text-transform: uppercase; letter-spacing: .12em;
  margin-bottom: 4px;
}

.referral-vignette h4 {
  color: var(--text);
  margin: 0 0 8px 0;
  font-size: 1rem; font-weight: 600;
  letter-spacing: -0.01em; line-height: 1.25;
}
.referral-vignette h4 .accent-word { color: var(--accent); }

.referral-vignette p.ref-pitch {
  font-size:0.75rem; line-height: 1.5;
  color: var(--text-dim); margin: 0 0 12px;
}
.referral-vignette p.ref-pitch strong { color: var(--text); font-weight: 600; }

.referral-vignette .ref-link-row {
  display: flex; gap: 6px;
}
.referral-vignette input.ref-link {
  flex: 1; min-width: 0;
  padding: 6px 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 4px);
  background: var(--bg-inset);
  color: var(--text);
  font-family: ui-monospace, monospace;
  font-size:0.72rem;
}
.referral-vignette input.ref-link:focus {
  outline: none; border-color: var(--accent);
}
.referral-vignette button.ref-copy {
  padding: 6px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 4px);
  background: var(--bg-card);
  color: var(--text);
  cursor: pointer;
  font-size:0.73rem;
  font-weight: 600;
}
.referral-vignette button.ref-copy:hover {
  background: var(--bg-hover);
  border-color: var(--accent);
}

/* ----- Profile-page referral card — same titled-card design, wider. */
.referral-card-wrap {
  position: relative;
  margin-top: 20px;
  padding: 14px 12px 8px 14px;
}
.referral-card-wrap::before {
  content: '';
  position: absolute;
  top: -8px; right: 24px;
  width: 180px; height: 70px;
  background: var(--accent);
  border-radius: 12px;
  transform: rotate(-3deg);
  z-index: 0;
  opacity: 0.18;
}
.referral-card {
  position: relative; z-index: 1;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 22px 26px;
  box-shadow: var(--shadow-sm, 0 2px 6px rgba(0,0,0,.05));
}
.referral-card .ref-eyebrow {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700; font-size:0.68rem;
  color: var(--text-dim);
  text-transform: uppercase; letter-spacing: .14em;
  margin-bottom: 6px;
}
.referral-card h3 {
  margin: 0 0 10px 0;
  font-size: 1.25rem; font-weight: 700;
  letter-spacing: -0.01em;
}
.referral-card h3 .accent-word { color: var(--accent); }
.referral-card .ref-pitch {
  margin: 0 0 16px 0;
  font-size:0.9rem;
  color: var(--text-dim);
  line-height: 1.6;
}
.referral-card .ref-pitch strong { color: var(--text); font-weight: 600; }
.referral-card .ref-link-row { display: flex; gap: 8px; }
.referral-card input.ref-link {
  flex: 1; min-width: 0;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 4px);
  background: var(--bg-inset);
  color: var(--text);
  font-family: ui-monospace, monospace;
  font-size:0.85rem;
}
.referral-card input.ref-link:focus {
  outline: none; border-color: var(--accent);
}
.referral-card button.ref-copy {
  padding: 9px 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 4px);
  background: var(--bg-card);
  color: var(--text);
  cursor: pointer;
  font-size:0.85rem;
  font-weight: 600;
}
.referral-card button.ref-copy:hover {
  background: var(--bg-hover);
  border-color: var(--accent);
}

@media (max-width: 720px) {
  .referral-card-wrap::before { width: 120px; height: 60px; right: 8px; }
  .referral-card .ref-link-row { flex-direction: column; }
  .referral-card button.ref-copy { width: 100%; }
}

/* ===== Pricing Yearly toggle =====
   Pill toggle above the pricing cards. Yearly mode renders the per-month
   equivalent of the yearly_cost (yearly_cost / 12) plus a savings badge
   computed against 12 × monthly_cost.
*/
.pricing-billing-toggle {
  display: flex; justify-content: center; gap: 4px;
  margin: 0 auto 24px; width: max-content;
  background: var(--bg-inset); padding: 4px; border-radius: 999px;
}
.pricing-billing-toggle button {
  padding: 8px 18px; border: none; border-radius: 999px;
  background: transparent; cursor: pointer; font-size: 0.85rem; font-weight: 600;
  color: var(--text-dim);
}
.pricing-billing-toggle button.active {
  background: var(--bg-card); color: var(--text);
  box-shadow: 0 1px 3px rgba(0,0,0,0.08);
}
.pricing-savings-badge {
  display: inline-block; margin-left: 6px; padding: 2px 8px;
  background: var(--green); color: #fff;
  font-size: 0.65rem; font-weight: 700; border-radius: 999px;
  text-transform: uppercase; letter-spacing: 0.04em;
}
.pricing-card-period {
  display: block; font-size: 0.7rem; color: var(--text-dim); margin-top: 4px;
}

/* ===== Help Chatbot ===== */
:root { --chat-width: 420px; }
/* @trace code:3250 req:4243
    — expanded chat scope. When the panel's
 * `expanded` ref is on, CardChatPanel mirrors it into this html class,
 * overriding --chat-width. Both the panel itself (width / min-width /
 * max-width all use the var) and #app's margin-right (which also uses
 * the var) pick up the new value, so the chat grows wider AND the page
 * narrows to keep both visible side-by-side instead of the chat
 * covering everything. */
html.help-chat-expanded { --chat-width: min(900px, 65vw); }

.help-chat { position: fixed; bottom: 24px; right: 24px; z-index: 9999; }

/* FAB button */
.help-chat-fab {
  width: 52px; height: 52px; border-radius: 50%; border: none;
  background: var(--accent); color: #fff; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 4px 16px rgba(0,0,0,0.18);
  transition: transform 0.2s, background 0.2s;
}
.help-chat-fab:hover { transform: scale(1.08); }

/* Side panel — full height, fixed right */
.help-chat-panel {
  position: fixed; top: 0; right: 0; bottom: 0;
  width: var(--chat-width); min-width: var(--chat-width); max-width: var(--chat-width);
  background: var(--bg-card); border-left: 1px solid var(--border);
  box-shadow: -4px 0 24px rgba(0,0,0,0.12);
  display: flex; flex-direction: column; overflow: hidden;
  z-index: 10000;
}

/* Push main content left when chat is open */
html.help-chat-open #app { margin-right: var(--chat-width); transition: margin-right 0.25s ease; }
html:not(.help-chat-open) #app { transition: margin-right 0.25s ease; }

.help-chat-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px; border-bottom: 1px solid var(--border);
  font-weight: 600; font-size: 0.95rem;
  min-height: 52px;
}
.help-chat-hdr-btn {
  background: none; border: none; color: var(--text-dim);
  cursor: pointer; padding: 4px; border-radius: 4px;
  display: flex; align-items: center;
}
.help-chat-hdr-btn:hover { background: var(--bg-hover); color: var(--text); }

.help-chat-body {
  flex: 1; overflow-y: auto; padding: 18px;
  display: flex; flex-direction: column; gap: 14px;
}

.help-chat-empty {
  text-align: center; color: var(--text-dim);
  margin: auto; padding: 20px;
}
.help-chat-empty p { margin: 0; line-height: 1.5; }

.help-chat-msg { display: flex; }
.help-chat-msg-user { justify-content: flex-end; }
.help-chat-msg-assistant { justify-content: flex-start; }

.help-chat-msg-content {
  max-width: 92%; padding: 10px 14px; border-radius: 12px;
  font-size: 0.85rem; line-height: 1.55; word-wrap: break-word;
  overflow-wrap: break-word; overflow: hidden;
}
.help-chat-msg-user .help-chat-msg-content {
  background: var(--accent); color: #fff; border-bottom-right-radius: 4px;
}
.help-chat-msg-assistant .help-chat-msg-content {
  background: var(--bg-hover); color: var(--text); border-bottom-left-radius: 4px;
}
.help-chat-msg-assistant .help-chat-msg-content p { margin: 0 0 6px; }
.help-chat-msg-assistant .help-chat-msg-content p:last-child { margin-bottom: 0; }
.help-chat-msg-assistant .help-chat-msg-content code {
  background: var(--border); padding: 1px 4px; border-radius: 3px; font-size: 0.82rem;
}

/* Typing dots */
.help-chat-typing {
  display: flex; gap: 4px; padding: 10px 14px !important; align-items: center;
}
.help-chat-typing span {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--text-dim); animation: chatDot 1.4s infinite;
}
.help-chat-typing span:nth-child(2) { animation-delay: 0.2s; }
.help-chat-typing span:nth-child(3) { animation-delay: 0.4s; }
@keyframes chatDot {
  0%, 80%, 100% { opacity: 0.3; transform: scale(0.8); }
  40% { opacity: 1; transform: scale(1); }
}

.help-chat-input {
  display: flex; align-items: flex-end; gap: 8px;
  padding: 14px 18px; border-top: 1px solid var(--border);
}
.help-chat-input textarea {
  flex: 1; resize: none; border: 1px solid var(--border);
  border-radius: 8px; padding: 8px 12px; font-size: 0.85rem;
  font-family: inherit; background: var(--bg); color: var(--text);
  max-height: 100px; line-height: 1.4;
}
.help-chat-input textarea:focus { outline: none; border-color: var(--accent); }
.help-chat-input textarea:disabled { opacity: 0.6; }

.help-chat-send {
  background: var(--accent); color: #fff; border: none;
  border-radius: 8px; padding: 8px; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: opacity 0.15s;
}
.help-chat-send:disabled { opacity: 0.4; cursor: default; }
.help-chat-send:not(:disabled):hover { opacity: 0.85; }

.help-chat-close {
  background: none; border: 1px solid var(--border); color: var(--text-dim);
  border-radius: 8px; padding: 8px; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: color 0.15s, border-color 0.15s;
}
.help-chat-close:hover { color: var(--text); border-color: var(--text-dim); }

/* Disconnected banner */
.help-chat-disconnected {
  padding: 14px 18px; text-align: center; font-size: 0.82rem;
  color: var(--red); background: var(--bg-hover); border-top: 1px solid var(--border);
  line-height: 1.5;
}

/* Chat panel slide transition */
.chat-fade-enter-active, .chat-fade-leave-active { transition: transform 0.25s ease; }
.chat-fade-enter-from, .chat-fade-leave-to { transform: translateX(100%); }

/* @trace code:3251 req:4241 req:4243
    — Expanded panel: when the user
 * clicks the expand button, the panel root gains .help-chat-fullscreen
 * AND html gains .help-chat-expanded (the latter overrides --chat-width
 * for a coordinated panel + #app reflow). The panel's width / min-width
 * / max-width all bind to var(--chat-width) on the base rule above, so
 * we don't override them here — the variable change is enough. We only
 * smooth the transition. The class name `help-chat-fullscreen` is kept
 * because the inline-card descendant selectors at req:4242 use it. */
.help-chat-panel.help-chat-fullscreen {
  transition: width 0.2s ease, min-width 0.2s ease, max-width 0.2s ease;
}
@media (prefers-reduced-motion: reduce) {
  .help-chat-panel.help-chat-fullscreen { transition: none; }
}

/* @trace req:4242 code:? — Inline ephemeral cards rendered inside an
 * assistant chat bubble. The chart variant gets a fixed height so
 * Chart.js's responsive sizing has a real box to fill; in fullscreen
 * the chart grows to take advantage of the extra screen height. */
.chat-inline-card {
  margin-top: 8px; padding: 8px 10px;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--bg); color: var(--text);
  font-size: 0.82rem;
}
.chat-inline-card-title { font-weight: 600; margin-bottom: 6px; font-size: 0.82rem; }
.chat-inline-card-chart { position: relative; height: 180px; width: 100%; }
.help-chat-fullscreen .chat-inline-card-chart { height: 320px; }
.chat-inline-card-kpi { text-align: center; padding: 6px 0; }
.chat-inline-card-kpi .metric-value { font-size: 1.6rem; font-weight: 700; }
.chat-inline-card-kpi .chat-inline-card-subtitle {
  color: var(--text-dim); font-size: 0.78rem; margin-top: 2px;
}
.chat-inline-card-grid { overflow-x: auto; }
.chat-inline-card-grid table { width: 100%; border-collapse: collapse; }
.chat-inline-card-grid th, .chat-inline-card-grid td {
  text-align: left; padding: 4px 6px; border-bottom: 1px solid var(--border);
}
.help-chat-msg-assistant .help-chat-msg-content .chat-inline-card-text p:last-child { margin-bottom: 0; }

/* @trace req:4895 — staged-action confirmation card (propose → confirm). */
.chat-action-card {
  margin-top: 8px; padding: 8px 10px;
  border: 1px solid var(--accent, var(--border)); border-radius: 8px;
  background: var(--bg); color: var(--text);
  font-size: 0.82rem;
}
.chat-action-summary { margin-bottom: 6px; }
.chat-action-buttons { display: flex; gap: 8px; }
.chat-action-resolved { font-size: 0.78rem; }

/* ===== Notes Side Panel ===== */
.notes-panel {
  position: fixed; top: 0; right: 0; bottom: 0;
  width: var(--chat-width); min-width: var(--chat-width); max-width: var(--chat-width);
  background: var(--bg-card); border-left: 1px solid var(--border);
  box-shadow: -4px 0 24px rgba(0,0,0,0.12);
  display: flex; flex-direction: column; overflow: hidden;
  z-index: 10000;
}
html.notes-panel-open #app { margin-right: var(--chat-width); transition: margin-right 0.25s ease; }
html:not(.notes-panel-open) #app { transition: margin-right 0.25s ease; }
html.notes-panel-open .help-chat { display: none; }

.notes-panel-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px; border-bottom: 1px solid var(--border);
  font-weight: 600; font-size: 0.95rem; min-height: 52px;
}
.notes-panel-body {
  flex: 1; overflow-y: auto; padding: 18px;
  display: flex; flex-direction: column; gap: 12px;
}
.notes-empty { text-align: center; margin: auto; padding: 20px; }
.notes-form { padding: 12px; }
.notes-card { padding: 12px; }
.notes-card.notes-alerted { border-left: 3px solid var(--orange); }
.notes-card-header {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 6px;
}
.notes-card-text { font-size: 0.88rem; line-height: 1.5; white-space: pre-wrap; }
.notes-card-alert {
  margin-top: 8px; padding-top: 6px; border-top: 1px solid var(--border);
  font-size: 0.82rem; line-height: 1.4;
}
.notes-alert-badge {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: 50%;
  font-size: 0.72rem; font-weight: 700;
  background: var(--bg-hover); color: var(--text-dim);
}
.notes-alert-badge.alerted { background: var(--orange); color: #fff; }

/* Filter editor modal — opened from a note's alert field. The
 * notes side panel is too narrow to host the two-column editor body,
 * so we float it as a centered overlay that covers the parent app. */
.filter-modal-overlay {
  position: fixed; inset: 0; z-index: 10001;
  background: rgba(0,0,0,0.55);
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
}
.filter-modal {
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: 0 20px 60px rgba(0,0,0,0.35);
  width: min(1200px, 100%); max-height: calc(100vh - 48px);
  display: flex; flex-direction: column; overflow: hidden;
}
.filter-modal-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 20px; border-bottom: 1px solid var(--border);
}
.filter-modal-header h3 { margin: 0; font-size: 1rem; }
.filter-modal-body {
  flex: 1; overflow-y: auto; padding: 20px 24px;
}
.filter-modal-footer {
  display: flex; align-items: center; justify-content: flex-end; gap: 10px;
  padding: 12px 20px; border-top: 1px solid var(--border);
}

/* ===== Filter Editor (full page) ===== */
.filter-editor-page { display: flex; flex-direction: column; gap: 0; }
.filter-editor-topbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; margin-bottom: 20px; flex-wrap: wrap;
}
.filter-editor-layout {
  display: grid; grid-template-columns: 1fr 320px; gap: 24px;
  align-items: start;
}
.filter-editor-main {
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: 24px 28px;
}
.filter-editor-ref {
  position: sticky; top: 20px;
  max-height: calc(100vh - 100px); overflow-y: auto;
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: 16px;
}
.fe-ref-heading {
  font-size:0.82rem; margin: 0; padding: 6px 0; cursor: pointer;
  user-select: none; color: var(--text);
}
.fe-ref-heading:hover { color: var(--accent); }
.fe-ref-section { border-bottom: 1px solid var(--border); }
.fe-ref-section:last-child { border-bottom: none; }
.fe-ref-body { padding: 4px 0 10px; }
.fe-ref-item {
  display: flex; gap: 8px; align-items: baseline; padding: 2px 4px;
  font-size:0.78rem; cursor: pointer; border-radius: 4px;
}
.fe-ref-item:hover { background: var(--bg); }
.fe-ref-item code {
  font-size:0.75rem; background: var(--bg); padding: 1px 5px;
  border-radius: 3px; white-space: nowrap; color: var(--accent);
}
.fe-ref-prose { font-size:0.78rem; line-height: 1.5; }
.fe-ref-prose p { margin: 0 0 8px; }
.fe-ref-prose code {
  font-size:0.75rem; background: var(--bg); padding: 1px 4px; border-radius: 3px;
}
@media (max-width: 900px) {
  .filter-editor-layout { grid-template-columns: 1fr; }
  .filter-editor-ref { position: static; max-height: none; }
}

/* Adherence row */
.filter-adherence { display: flex; gap: 6px; margin-bottom: 20px; align-items: center; }
.filter-adherence label { font-size:0.8rem; color: var(--text-dim); margin-right: 8px; font-weight: 600; }
.filter-adherence .adherence-opt {
  padding: 4px 12px; border: 1px solid var(--border); border-radius: 6px;
  font-size:0.8rem; cursor: pointer; background: var(--bg);
  color: var(--text-dim); transition: all .15s;
}
.filter-adherence .adherence-opt:hover { border-color: var(--accent); color: var(--text); }
.filter-adherence .adherence-opt.active {
  background: var(--accent); color: #fff; border-color: var(--accent);
}

/* Boolean group container (scoped to filter editor to avoid affecting scan filter bar) */
.filter-editor-main .filter-group {
  border-left: 3px solid var(--accent); padding: 10px 0 10px 16px;
  margin-bottom: 8px;
}
.filter-editor-main .filter-group.group-and { border-color: #3b82f6; }
.filter-editor-main .filter-group.group-or { border-color: #22c55e; }
.filter-group-header {
  display: flex; align-items: center; gap: 8px; margin-bottom: 10px;
}
.filter-group-label {
  font-size:0.7rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; padding: 2px 8px; border-radius: 4px;
  cursor: pointer; user-select: none;
}
.group-and > .filter-group-header .filter-group-label { background: #dbeafe; color: #1d4ed8; }
.group-or > .filter-group-header .filter-group-label { background: #dcfce7; color: #15803d; }
[data-theme="dark"] .group-and > .filter-group-header .filter-group-label { background: #1e3a5f; color: #93c5fd; }
[data-theme="dark"] .group-or > .filter-group-header .filter-group-label { background: #14532d; color: #86efac; }

/* NOT wrapper */
.filter-not-badge {
  display: inline-block; font-size:0.65rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .06em;
  padding: 1px 6px; border-radius: 3px; margin-right: 6px;
  background: #fecaca; color: #b91c1c; vertical-align: middle;
}
[data-theme="dark"] .filter-not-badge { background: #450a0a; color: #fca5a5; }

/* Criterion card */
.filter-criterion {
  background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 12px 14px;
  margin-bottom: 8px; transition: border-color .15s;
}
.filter-criterion:hover { border-color: var(--text-dim); }
.filter-criterion-header {
  display: flex; align-items: center; gap: 8px; margin-bottom: 8px;
}
.filter-criterion-header .crit-name {
  font-weight: 600; font-size:0.9rem; flex: 1;
  border: none; background: transparent; color: var(--text);
  font-family: inherit; padding: 2px 4px; border-radius: 4px;
}
.filter-criterion-header .crit-name:focus {
  background: var(--bg-card); outline: none; box-shadow: 0 0 0 2px rgba(249,115,22,0.2);
}
/* @trace req:4770 code:2417 — description on its own full-width line below the
   name/importance/remove header row, so long descriptions no longer overlap the
   criterion name or wrap under the remove button. */
.filter-criterion .crit-desc {
  display: block; box-sizing: border-box; width: 100%;
  font-size:0.75rem; color: var(--text-dim);
  border: none; background: transparent; font-family: inherit;
  padding: 2px 4px; margin-bottom: 8px; border-radius: 4px; min-width: 0;
}
.filter-criterion .crit-desc:focus {
  background: var(--bg-card); outline: none; box-shadow: 0 0 0 2px rgba(249,115,22,0.15);
}
.filter-criterion-header .btn-remove {
  background: none; border: none; color: var(--red); cursor: pointer;
  font-size: 1.1rem; padding: 0 4px; opacity: 0.5; transition: opacity .15s;
}
.filter-criterion-header .btn-remove:hover { opacity: 1; }

/* Condition row */
.filter-condition-row {
  display: flex; gap: 6px; align-items: center; margin-bottom: 6px;
  flex-wrap: wrap;
}
.filter-condition-row select, .filter-condition-row input {
  padding: 4px 8px; border: 1px solid var(--border); border-radius: 6px;
  font-size:0.8rem; font-family: inherit; background: var(--bg-card);
  color: var(--text);
}
.filter-condition-row select:focus, .filter-condition-row input:focus {
  border-color: var(--accent); outline: none;
}
.filter-condition-row .field-input { width: 180px; }
.filter-condition-row .op-select { width: 70px; }
.filter-condition-row .val-input { width: 120px; }
.filter-condition-row .btn-remove-cond {
  background: none; border: none; color: var(--red); cursor: pointer;
  font-size:0.9rem; padding: 0 2px; opacity: 0.4;
}
.filter-condition-row .btn-remove-cond:hover { opacity: 1; }
.filter-condition-row .btn-add-cond {
  background: none; border: 1px dashed var(--border); color: var(--text-dim);
  cursor: pointer; font-size:0.75rem; padding: 3px 8px; border-radius: 4px;
}
.filter-condition-row .btn-add-cond:hover { border-color: var(--accent); color: var(--accent); }
/* Reference-comparator label between sub-inputs (req:4210). */
.filter-condition-row .ref-label,
.filter-scoring-body .ref-label {
  font-size:0.75rem; color: var(--text-dim); padding: 0 2px;
}

/* Scoring section */
.filter-scoring-toggle {
  font-size:0.75rem; color: var(--text-dim); cursor: pointer;
  user-select: none; margin-top: 4px; display: inline-block;
}
.filter-scoring-toggle:hover { color: var(--accent); }
.filter-scoring-body {
  margin-top: 6px; padding: 8px 10px; background: var(--bg-card);
  border: 1px solid var(--border); border-radius: 6px;
}
.filter-scoring-tier {
  display: flex; gap: 6px; align-items: center; margin-bottom: 4px;
  font-size:0.78rem;
}
.filter-scoring-tier .tier-label {
  font-weight: 600; width: 65px; text-transform: capitalize;
}
.tier-label-pass { color: var(--green); }
.tier-label-marginal { color: var(--yellow); }
.tier-label-fail { color: var(--red); }
.filter-scoring-tier select, .filter-scoring-tier input {
  padding: 2px 6px; border: 1px solid var(--border); border-radius: 4px;
  font-size:0.75rem; font-family: inherit; background: var(--bg);
  color: var(--text);
}
.filter-scoring-tier .op-select { width: 60px; }
.filter-scoring-tier .val-input { width: 80px; }

/* Add buttons */
.filter-add-row {
  display: flex; gap: 8px; margin-top: 8px;
}
.filter-add-btn {
  background: none; border: 1px dashed var(--border); color: var(--text-dim);
  cursor: pointer; font-size:0.78rem; padding: 6px 14px; border-radius: 6px;
  transition: all .15s;
}
.filter-add-btn:hover { border-color: var(--accent); color: var(--accent); }

/* Macro overlay section */
.filter-macro { margin-top: 20px; }
.filter-macro h4 { font-size:0.85rem; margin-bottom: 8px; cursor: pointer; }
.filter-macro h4:hover { color: var(--accent); }
.filter-macro textarea {
  width: 100%; min-height: 60px; padding: 8px 10px;
  border: 1px solid var(--border); border-radius: 6px;
  font-family: inherit; font-size:0.82rem; resize: vertical;
  background: var(--bg); color: var(--text);
}
.filter-macro textarea:focus { border-color: var(--accent); outline: none; }
.filter-macro-scores { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }
.filter-macro-score-row {
  display: flex; gap: 8px; align-items: center; font-size:0.8rem;
}
.filter-macro-score-row .tier-label { font-weight: 600; width: 65px; }
.filter-macro-score-row input {
  flex: 1; padding: 4px 8px; border: 1px solid var(--border);
  border-radius: 6px; font-size:0.8rem; font-family: inherit;
  background: var(--bg-card); color: var(--text);
}

/* Save bar */
.filter-save-bar {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
}
.filter-save-bar .btn { min-width: 120px; }
.filter-save-bar .save-status {
  font-size:0.82rem; display: flex; align-items: center; margin-left: auto;
}

/* Source attribution & external links */
.source-attribution {
  text-align: right; margin-top: 4px; margin-bottom: 2px;
}
.source-link {
  font-size:0.7rem; color: var(--text-dim);
}
.source-link a {
  color: var(--accent); text-decoration: none; opacity: 0.8;
}
.source-link a:hover { opacity: 1; text-decoration: underline; }
.external-links {
  display: flex; flex-wrap: wrap; gap: 8px;
}
.ext-link {
  display: inline-block; padding: 4px 12px; border-radius: 6px;
  border: 1px solid var(--border); font-size:0.8rem;
  color: var(--accent); text-decoration: none;
  transition: background 0.15s, border-color 0.15s;
}
.ext-link:hover {
  background: var(--accent-soft); border-color: var(--accent);
}
.research-source-list {
  list-style: none; padding: 0; margin: 0;
}
.research-source-list li {
  padding: 4px 0; font-size:0.82rem; border-bottom: 1px solid var(--border);
}
.research-source-list li:last-child { border-bottom: none; }
.research-source-list a {
  color: var(--accent); text-decoration: none;
}
.research-source-list a:hover { text-decoration: underline; }

/* === Custom Reports === */
.cr-page-list { display: flex; flex-direction: column; gap: 8px; }
.cr-page-card { cursor: pointer; transition: box-shadow .2s; }
.cr-page-card:hover { box-shadow: var(--shadow-lg); }

.cr-toolbar {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 0; margin-bottom: 12px; flex-wrap: wrap;
}
.cr-draft-indicator {
  background: rgba(249, 115, 22, 0.1); color: var(--orange);
  padding: 4px 10px; border-radius: 12px;
  font-size:0.75rem; font-weight: 600;
}
.cr-content { display: flex; gap: 16px; }
.cr-widgets-area { flex: 1; min-width: 0; }

.custom-widgets { display: flex; flex-wrap: wrap; gap: 16px; align-items: stretch; }
.custom-widget-full { width: 100%; }
.custom-widget-half { width: calc(50% - 8px); display: flex; }
.custom-widget-half > .card { flex: 1; display: flex; flex-direction: column; }
/* @trace req:4228 — right-aligned half-width card. Sits on the right
   side of its row even when alone; pairs naturally with a sibling
   .custom-widget-half (left-aligned) on the same flex row. */
.custom-widget-half-right { width: calc(50% - 8px); margin-left: auto; display: flex; }
.custom-widget-half-right > .card { flex: 1; display: flex; flex-direction: column; }
.custom-widget-draft .card {
  border-color: var(--orange); border-style: dashed;
}
.custom-widget-chart { min-height: 250px; position: relative; flex: 1; display: flex; flex-direction: column; }
.custom-widget-chart canvas { flex: 1; max-height: 350px; }

/* @trace req:4228 — zones take ZERO layout when not dragging (so
   opening the chat panel doesn't push the page down by N×34px) and
   expand to 22px during drag via the body.drilldown-drag-active
   class. The class is added on the NEXT animation frame (not
   synchronously in the dragstart handler), so the layout shift
   from collapsed → expanded happens AFTER Chromium has captured
   the drag source position. Without the rAF defer, the shift on
   dragstart cancelled the drag (verified bug: only dragstart +
   dragend fired with no drag/dragover events in between). */
.drilldown-drop-zone {
  height: 0;
  margin: 0;
  border: 0 dashed transparent;
  background: transparent;
  border-radius: 5px;
  overflow: hidden;
  visibility: hidden;
  /* No height/margin transition — a 120ms interpolation from 0→22px
     means the box is a sub-22px-tall hit target for most of the
     first frame after dragstart's rAF lands, and a fast cursor
     glides past the zone region without firing dragover (review
     M2). Snap to 22px instantly when the body class lands. */
}
body.drilldown-drag-active .drilldown-drop-zone {
  height: 22px;
  margin: 6px 0;
  border-width: 1px;
  border-color: var(--accent, #3b82f6);
  background: color-mix(in srgb, var(--accent, #3b82f6) 10%, transparent);
  visibility: visible;
}
body.drilldown-drag-active .drilldown-drop-zone-hot {
  height: 40px;
  background: color-mix(in srgb, var(--accent, #3b82f6) 30%, transparent);
  border-style: solid;
  border-width: 2px;
}

/* @trace req:4228 — fixed-position drop-target palette overlay,
   visible only while a card is being dragged. Lists every drop
   position (top through bottom) with a label so the user can drop
   anywhere on the unified stream regardless of scroll position.
   Lives in viewport coordinates (position: fixed) and z-indexed
   above page content. */
.drilldown-drop-palette {
  position: fixed;
  top: 80px;
  left: 16px;
  z-index: 10050;
  width: 320px;
  max-height: calc(100vh - 120px);
  overflow-y: auto;
  background: var(--bg-card, #fff);
  border: 2px solid var(--accent, #3b82f6);
  border-radius: 10px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.25);
  padding: 10px;
  font-size: 0.85rem;
  /* Hidden by default in edit mode; revealed by body.drilldown-drag-active. */
  visibility: hidden;
  opacity: 0;
  transition: opacity .12s ease-out;
}
body.drilldown-drag-active .drilldown-drop-palette {
  visibility: visible;
  opacity: 1;
}
.drilldown-drop-palette-title {
  font-weight: 700;
  color: var(--text-dim, #64748b);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: 0.7rem;
  margin-bottom: 8px;
  padding: 0 4px;
}
.drilldown-drop-palette-item {
  display: flex;
  gap: 10px;
  align-items: center;
  padding: 10px 12px;
  margin-bottom: 4px;
  border-radius: 6px;
  border: 1px dashed var(--accent, #3b82f6);
  background: color-mix(in srgb, var(--accent, #3b82f6) 6%, transparent);
  cursor: copy;
  transition: background .12s ease-out, transform .12s ease-out;
}
.drilldown-drop-palette-item-hot {
  background: color-mix(in srgb, var(--accent, #3b82f6) 35%, transparent);
  border-style: solid;
  border-width: 2px;
  transform: translateX(4px);
}
.drilldown-drop-palette-pos {
  font-family: var(--font-mono, monospace);
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--accent, #3b82f6);
  min-width: 38px;
  text-align: right;
}
.drilldown-drop-palette-label { flex: 1; color: var(--text, #0f172a); }
.drilldown-custom-card[draggable="true"] { cursor: grab; }
.drilldown-custom-card[draggable="true"]:active { cursor: grabbing; }
/* @trace code:2448 req:4778 — clickable ticker cells render through the
   markdown pipeline, which wraps the <a> in a block <p>; keep it inline
   so grid cells don't gain a blank line / extra height. */
.drilldown-custom-card td p { margin: 0; display: inline; }
.drilldown-card-pair-edge { transition: background .12s ease-out; }
.drilldown-card-pair-edge.pair-edge-hot {
  background: color-mix(in srgb, var(--accent, #3b82f6) 35%, transparent);
}

/* @trace req:4228 — vertical reorder toolbar inside a custom card.
   Title sits on its own row at the top of the card; the body and the
   vertical toolbar share a flex row below so a half-width card keeps
   the buttons readable on the right edge without crowding the title.

   IMPORTANT: when the .card element also carries .custom-widget-half
   (legacy page-editor pattern uses a separate wrapper, but the
   drilldown collapses wrapper + card into one element), the
   .custom-widget-half rule sets display:flex which would otherwise
   default to flex-direction:row and arrange title-row + body-row
   side-by-side. Force column direction so the title is always on
   top, never on the side. */
.drilldown-custom-card.custom-widget-half,
.drilldown-custom-card.custom-widget-half-right {
  flex-direction: column;
}
/* Title row: pack from the LEFT (drag handle, then title, then
   optional badges). Without this override the inherited
   .card-header { justify-content: space-between } would push the
   title to the opposite end when there's only a drag handle to its
   left in edit mode. */
.drilldown-card-title-row {
  justify-content: flex-start !important;
}
.drilldown-card-body-row { display: flex; gap: 8px; align-items: stretch; }
.drilldown-card-body-row > .drilldown-card-body { flex: 1; min-width: 0; }
.drilldown-card-toolbar-vertical {
  display: flex; flex-direction: column; gap: 2px;
  flex: 0 0 auto;
}
.drilldown-card-toolbar-vertical .btn { padding: 2px 6px; min-width: 28px; }
.drilldown-card-btn-delete { color: var(--red, #ef4444); }
.drilldown-card-btn-delete:hover:not(:disabled) {
  background: color-mix(in srgb, var(--red, #ef4444) 18%, transparent);
}
.drilldown-card-btn-edit { color: var(--accent, #3b82f6); }
.drilldown-card-btn-edit:hover:not(:disabled) {
  background: color-mix(in srgb, var(--accent, #3b82f6) 18%, transparent);
}

/* @trace req:4228 — while the Cards chat panel is open ("edit mode"),
   the sticky page header occludes anything scrolled to the top of
   the viewport — including a custom card's drag handle and the top
   drop zones. A user trying to drag a card that's "high in the view"
   literally can't click the handle because the header sits over it
   (z-index: 100). Solution: take the header OUT of sticky flow while
   edit mode is active so it scrolls away normally. Navigation in
   the header remains interactive when scrolled into view; the user
   just scrolls past it like any other content.

   The body class is toggled by the drilldown's cardChatOpen watcher
   in stock-drilldown.ts. */
body.drilldown-edit-mode .header {
  position: static !important;
}
/* During an active card drag, the header (now non-sticky in edit
   mode but in normal flow) still mustn't intercept drag events
   anywhere it happens to scroll into. Belt + braces: pointer events
   off on the header for the duration of the drag too. */
body.drilldown-drag-active .header,
body.drilldown-drag-active .header * {
  pointer-events: none;
}
@media (max-width: 700px) {
  .custom-widget-half-right { width: 100%; margin-left: 0; }
}

.cr-param-bar { display: flex; gap: 12px; align-items: center; margin-bottom: 8px; flex-wrap: wrap; }
.cr-param-group { display: flex; align-items: center; gap: 6px; }
.cr-param-label { font-size:0.75rem; color: var(--text-muted); font-weight: 500; }
.cr-param-buttons { display: flex; gap: 2px; background: var(--bg); border-radius: var(--radius-sm); padding: 2px; }
.cr-param-btn { font-size:0.72rem; padding: 3px 10px; border-radius: 6px; opacity: .6; transition: all .15s; }
.cr-param-btn:hover { opacity: .9; }
.cr-param-active { opacity: 1; background: var(--orange); color: #fff; font-weight: 600; }
.cr-param-active:hover { opacity: 1; }

/* Mobile: full-width overlay instead of side panel */
@media (max-width: 768px) {
  :root { --chat-width: 100%; }
  .help-chat-panel { min-width: 0; max-width: none; }
  html.help-chat-open #app { margin-right: 0; }
  .custom-widget-half { width: 100%; }
}

/* === Help icon (?) with rich popover === */
.help-icon {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  margin-left: 5px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text-dim);
  font-size:0.65rem;
  font-weight: 700;
  font-family: 'Inter', sans-serif;
  text-transform: none;
  letter-spacing: 0;
  cursor: help;
  user-select: none;
  outline: none;
  transition: color .15s, border-color .15s;
  vertical-align: middle;
}
.help-icon:hover, .help-icon:focus {
  color: var(--text);
  border-color: var(--accent, var(--orange));
}
.help-icon-mark {
  line-height: 1;
  pointer-events: none;
}
.help-popover {
  position: fixed;
  top: 0;
  left: 0;
  min-width: 240px;
  max-width: 320px;
  background: var(--card-bg, var(--bg-card));
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, .45);
  font-size:0.78rem;
  font-weight: 400;
  color: var(--text);
  text-align: left;
  text-transform: none;
  letter-spacing: 0;
  line-height: 1.45;
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
  transition: opacity .15s, visibility 0s linear .15s;
  z-index: 1000;
  white-space: normal;
}
.help-popover.help-popover-open {
  visibility: visible;
  opacity: 1;
  transition: opacity .15s;
}
.help-popover .help-summary {
  display: block;
  margin-bottom: 6px;
  color: var(--text);
  font-weight: 600;
}
/* @trace code:v61mm5ypkh req:0znv8stw37 */
/* Popover sub-blocks use their own scoped class (not the bare `.help-section`,
   which the /help page owns) so the /help rule's margin-bottom:2.75rem no
   longer bleeds a phantom gap into the popover — bug B5 fix. */
.help-popover .help-popover-section {
  display: block;
  margin-top: 6px;
  color: var(--text-dim);
}
.help-popover .help-popover-section strong {
  color: var(--text);
  font-weight: 600;
  margin-right: 4px;
}

/* ============================================================
   Mobile / touch foundation — @trace code:1915 req:4641 (Phase 1)

   Touch-target sizing, tap feedback, native-feel scrolling, and
   touch discoverability. DESKTOP IS UNCHANGED: the size bumps are
   gated behind (pointer: coarse) so a mouse keeps the compact
   controls; the tap-feedback / discoverability / scroll bits are
   harmless on a desktop (they only manifest on touch). Lives last
   in the file so these rules win on equal specificity.
   ============================================================ */

/* No double-tap-zoom delay, no grey tap-flash on touch. No-op on desktop. */
.btn, .btn-sm, .btn-back, .btn-primary, .btn-danger, .btn-xs,
button, a, [role="button"], .edit-icon, .ai-btn, .chip-x {
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

/* :active mirrors of the .btn :hover lift, so a tap is tactile on touch
   (where :hover never fires). On desktop a click briefly shows it too —
   that's feedback, not a regression. */
.btn:active { transform: translateY(0); box-shadow: var(--shadow-sm); filter: brightness(0.96); }
.btn-primary:active,
.btn-danger:active { transform: translateY(0); filter: brightness(0.94); }

/* Native-feel scrolling: contain overscroll so a scroll-to-end doesn't
   bounce the whole page / fire pull-to-refresh, and use the dynamic
   viewport height so the page doesn't jump as the mobile URL bar
   shows/hides (progressive — falls back to the 100vh rule above).
   @trace req:4641 code:2098 — the contain MUST live on html, the viewport
   scroller. body computes overflow-y:auto (forced by its overflow-x:hidden
   above) and is a scroll container with zero scrollable overflow, so
   `contain` on body traps every touch/wheel pan there and the page cannot
   be scrolled by touch at all. */
html { overscroll-behavior-y: contain; }
@supports (min-height: 100dvh) {
  body { min-height: 100dvh; }
}

/* Touch-device target sizing: 44px minimum (WCAG) + larger checkboxes.
   Gated on a coarse primary pointer so a mouse keeps the compact layout. */
@media (pointer: coarse) {
  .btn, .btn-sm, .btn-back, .btn-primary, .btn-danger {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  /* The account-menu rows are intentionally full-width + left-aligned
     (.user-menu-dropdown .btn); inline-flex would otherwise center them. */
  .user-menu-dropdown .btn { justify-content: flex-start; }
  input[type="checkbox"], input[type="radio"] {
    min-width: 20px;
    min-height: 20px;
  }
}

/* No-hover (touch) devices: reveal the action icons that are otherwise
   invisible — they sit at opacity .3–.5 until a :hover that never fires
   on touch — so they're discoverable. */
@media (hover: none) {
  .edit-icon, .ai-btn, .ai-done, .chip-x,
  .filter-criterion-header .btn-remove,
  .filter-condition-row .btn-remove-cond {
    opacity: 1;
  }
}

/* ============================================================
   Mobile navigation chrome — @trace code:1917 req:4643 (Phase 3)

   Hamburger off-canvas drawer for the header nav + horizontal-scroll
   tab strips. Desktop is unchanged: the hamburger is hidden, .nav-links
   stays an inline row, and the tab-strip nowrap/scroll only applies in
   the ≤768px media query.
   ============================================================ */

/* Desktop: nav links are an inline row (one flex item in .header-right);
   the hamburger + backdrop don't exist visually. */
.nav-links { display: flex; align-items: center; gap: 8px; }
.nav-hamburger {
  display: none;
  background: var(--bg-card);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  padding: 6px;
  align-items: center;
  justify-content: center;
}

@media (max-width: 768px) {
  .nav-hamburger { display: inline-flex; min-height: 44px; min-width: 44px; }

  /* Right-side off-canvas drawer. Slides in when .nav-drawer-open (bound
     to drawerOpen). Floors padding with the safe-area insets. */
  .nav-links {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(82vw, 300px);
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
    background: var(--bg-card);
    border-left: 1px solid var(--border);
    box-shadow: -8px 0 24px rgba(0, 0, 0, 0.18);
    padding: max(16px, env(safe-area-inset-top)) max(16px, env(safe-area-inset-right)) max(16px, env(safe-area-inset-bottom)) 16px;
    transform: translateX(100%);
    transition: transform 0.25s ease;
    z-index: 200;
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  .nav-links.nav-drawer-open { transform: translateX(0); }
  /* Drawer rows: full-width, left-aligned (override the inline-flex centering
     and the fixed 220px search width inside the column layout). */
  .nav-links .btn { width: 100%; justify-content: flex-start; text-align: left; }
  .nav-links .sym-ac { width: 100% !important; max-width: none; }

  .nav-drawer-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
    z-index: 199;
  }
}

/* Tab strips scroll horizontally on a phone instead of overflowing /
   wrapping into a tall block. nowrap !important overrides the inline
   flex-wrap:wrap on the build-time HTML fragments. */
@media (max-width: 768px) {
  .tab-strip {
    flex-wrap: nowrap !important;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
  }
  .tab-strip > * { flex-shrink: 0; }
}

/* ============================================================
   Mobile data-table reflow — @trace code:1918 req:4644 (Phase 4)

   Column-priority hiding: low-priority table columns drop at phone
   width so the essentials (symbol / score / price / P&L) fit without a
   long horizontal scroll. `.hide-mobile` MUST sit on both the <th> and
   its per-row <td> so the column drops cleanly (no header/cell skew).
   Desktop shows every column; the .table-wrap scroll remains the
   fallback for whatever still overflows.
   ============================================================ */
@media (max-width: 768px) {
  .hide-mobile { display: none; }
  /* @trace req:4644 code:2099 — C6/C8: tighter horizontal cell padding
     (12px → 8px) buys ~8px per column so the trimmed 4-5 column tables
     (scans history, holdings) genuinely fit a 390px viewport. */
  .stock-table th { padding: 10px 8px; }
  .stock-table td { padding: 8px 8px; }
  /* Opt-in escape from the .stock-table nowrap default for cells whose
     long text (e.g. a full datetime) should wrap on a phone instead of
     forcing the whole table past the viewport. Selector carries the
     .stock-table prefix to outrank the base `.stock-table td` nowrap. */
  .stock-table td.wrap-mobile { white-space: normal; }
}

/* ============================================================
   Mobile forms / modals — @trace code:1919 req:4645 (Phase 5)

   At phone width (≤600px — forms may stay two-column between 600 and
   768px), the filter-editor condition rows stack their fixed-width
   controls to full width (the surviving Phase-5 fix; targets the SHARED
   filter-editor-panel so the wizard AND the notes alert editor both
   benefit), .form-row collapses to one column, and modals become
   full-bleed sheets. Desktop is unchanged.
   ============================================================ */
@media (max-width: 600px) {
  .filter-condition-row { flex-direction: column; align-items: stretch; }
  /* Broad rule for any un-classed control in the row… */
  .filter-condition-row select,
  .filter-condition-row input { width: 100%; }
  /* …and same-specificity overrides for the named fixed-width controls
     (a single-class/type selector can't beat the original two-class rules). */
  .filter-condition-row .field-input,
  .filter-condition-row .op-select,
  .filter-condition-row .val-input { width: 100%; }

  .form-row { flex-direction: column; }

  /* Full-bleed modal sheet. !important so it wins over the per-modal inline
     style="max-width:NNNpx" / width / max-height several .modal-card host divs
     carry (inline beats a plain media-query rule). Cancel the help-chat/
     notes-panel translateX shift so a now-full-width card can't overflow. */
  .modal-card {
    width: 100% !important;
    max-width: none !important;
    max-height: 100dvh !important;
    border-radius: 0;
  }
  html.help-chat-open .modal-card,
  html.notes-panel-open .modal-card { transform: none; }
}

/* ============================================================
   Mobile charts — @trace code:1920 req:4646 (Phase 6)

   Responsive .chart-container heights so the per-chart stack isn't
   enormously tall on a phone, and a chart still fits a short landscape
   viewport. Charts are responsive:true + maintainAspectRatio:false, so
   the canvas follows the container — no chart.js config change.
   ============================================================ */
@media (max-width: 768px) {
  .chart-container { height: 200px; }
}
@media (max-height: 500px) and (orientation: landscape) {
  .chart-container { height: 150px; }
}

/* ============================================================
   Mobile touch interactions — @trace code:1921 req:4647 (Phase 7)

   Toast host moves bottom-CENTER on a phone so transient toasts don't
   sit over the bottom-right help-chat FAB / bottom-right actions. The
   safe-area bottom inset (req:4641) is preserved. Desktop keeps the
   bottom-right placement.
   ============================================================ */
@media (max-width: 768px) {
  .toast-host {
    left: 0;
    right: 0;
    align-items: center;
    max-width: none;
    padding-left: 12px;
    padding-right: 12px;
  }
}

/* ============================================================
   Help / Documentation tab (req:4792; live embeds retired by req:4834)
   Two-pane layout: a sticky table-of-contents on the left and the
   authored documentation prose on the right. (The original design also
   embedded live <doc-frame> renders of app routes; those were removed in
   req:4834 in favour of an in-depth written guide.)
   ============================================================ */
/* req:4809 — full-bleed like the Portfolio layout: the wide prose body
   wants the whole screen, so no centered max-width cap. */
.help-doc {
  display: grid;
  grid-template-columns: 260px minmax(0, 1fr);
  gap: 2rem;
  /* req:4842 — centered reading column matching the dashboard's
     `.page-content` (max-width 1200px, margin auto). req:4809 had dropped
     this cap for full-bleed live embeds; req:4834 retired the embeds, so the
     long-form prose now sits in a comfortable column the same overall width
     as the rest of the app instead of spanning the whole screen. */
  max-width: 1200px;
  margin: 0 auto;
  padding: 1.5rem 1rem 4rem;
  align-items: start;
}
.help-toc {
  /* req:4842 — the index is shorter than the body, so show it in full
     rather than capping it to the viewport with an inner scrollbar
     (supersedes req:4809 AC2's fixed-height + slim-scrollbar treatment).
     It stays sticky so it follows you down the page. */
  position: sticky;
  top: 84px;
  border-right: 1px solid var(--border);
  padding-right: 1rem;
}
.help-toc-title {
  font-family: "Space Grotesk", sans-serif;
  font-weight: 600;
  font-size: 0.8rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 0.75rem;
}
.help-toc-nav { display: flex; flex-direction: column; gap: 1px; }
.help-toc-link {
  display: block;
  padding: 0.32rem 0.6rem;
  border-radius: var(--radius-sm);
  border-left: 2px solid transparent;
  color: var(--text-dim);
  font-size: 0.9rem;
  line-height: 1.3;
  text-decoration: none;
  transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.help-toc-link:hover { background: var(--bg-hover); color: var(--text); }
.help-toc-l2 { padding-left: 1.4rem; font-size: 0.84rem; }
.help-toc-on {
  color: var(--accent);
  background: var(--accent-bg);
  border-left-color: var(--accent);
  font-weight: 600;
}
.help-body { min-width: 0; }
.help-intro { margin-bottom: 1.5rem; }
.help-intro h1 { margin: 0 0 0.25rem; }
.help-section { scroll-margin-top: 84px; margin-bottom: 2.75rem; }
.help-h1 {
  font-family: "Space Grotesk", sans-serif;
  margin: 0 0 0.6rem;
  padding-bottom: 0.4rem;
  border-bottom: 2px solid var(--border);
}
.help-h2 { margin: 1.4rem 0 0.5rem; color: var(--text); }
.help-section .md-content { color: var(--text-dim); line-height: 1.6; }
.help-section .md-content ul { margin: 0.5rem 0 0.5rem 1.1rem; }
.help-section .md-content li { margin: 0.2rem 0; }
.help-section .md-content code {
  background: var(--bg-inset);
  padding: 0.05rem 0.3rem;
  border-radius: var(--radius-sm);
  font-size: 0.88em;
}
/* req:4846 — the guide links out to app pages; make those links read as
   links (they open in a new tab via renderMdNewTab). */
.help-section .md-content a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.help-section .md-content a:hover { color: var(--accent-strong, var(--accent)); }

/* req:4858 — illustrative screenshots under a section's prose. Hidden by
   the view's @error handler when the capture script hasn't produced the file. */
.help-figure { margin: 1.25rem 0 0; }
.help-figure img {
  display: block;
  max-width: 100%;
  height: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-md, 8px);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
}
/* Two captures per figure (req:4858): show the one matching the active theme
   (`<html data-theme="dark">`). Inline display:none from the @error handler
   still wins, so a missing capture stays hidden. */
.help-figure .help-shot-dark { display: none; }
[data-theme="dark"] .help-figure .help-shot-light { display: none; }
[data-theme="dark"] .help-figure .help-shot-dark { display: block; }
.help-figure figcaption {
  margin-top: 0.4rem;
  font-size: 0.82rem;
  color: var(--text-muted, var(--text-dim));
  font-style: italic;
}

/* req:4844 — the "contact the team" form at the end of the guide. */
.help-contact-form { padding: 1rem; display: flex; flex-direction: column; gap: 0.6rem; max-width: 560px; }
.help-contact-label { font-size: 0.85rem; color: var(--text-dim); }
.help-contact-select,
.help-contact-textarea {
  width: 100%;
  box-sizing: border-box;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-card);
  color: var(--text);
  font: inherit;
}
.help-contact-textarea { resize: vertical; }
.help-contact-actions { display: flex; align-items: center; gap: 0.75rem; }
.help-contact-thanks { font-size: 0.85rem; color: var(--green, #2e9e5b); }
.help-contact-error { font-size: 0.85rem; color: var(--red); }

@media (max-width: 768px) {
  .help-doc { grid-template-columns: 1fr; gap: 1rem; }
  .help-toc {
    position: static;
    max-height: none;
    border-right: 0;
    border-bottom: 1px solid var(--border);
    padding-right: 0;
    padding-bottom: 0.75rem;
  }
  .help-toc-nav { flex-flow: row wrap; }
  .help-toc-l2 { display: none; }
}

/* ── Positions / scan Charts tab — on-chart encodings (req:4942) ───────── */
/* Top row: Y selector (left) + size/colour/number encodings (right). */
.position-chart .chart-topbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 2px 0;
}
.position-chart .chart-encodings {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  font-size: 0.75rem;
  color: var(--text-dim);
}
.position-chart .enc { display: inline-flex; align-items: center; gap: 5px; }
.position-chart .enc-glyph { opacity: 0.75; }
.position-chart .enc-name { color: var(--text-muted); }
/* Y label: horizontal, at the top-left of the plot (no left gutter). */
.position-chart .axis-y { display: flex; align-items: center; gap: 5px; }
.position-chart .canvas-wrap { position: relative; height: 460px; }

/* Multi-entry click picker — overlapping bubbles let the user choose. */
.position-chart .chart-picker {
  position: absolute;
  z-index: 20;
  min-width: 140px;
  max-height: 220px;
  overflow-y: auto;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow);
  padding: 4px;
}
.position-chart .chart-picker-title {
  font-size: 0.7rem;
  color: var(--text-muted);
  padding: 2px 6px 4px;
}
.position-chart .chart-picker-item {
  display: block;
  width: 100%;
  text-align: left;
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 0.8rem;
  padding: 4px 6px;
  cursor: pointer;
}
.position-chart .chart-picker-item:hover { background: var(--bg-hover); }
/* X label: at the right END of the X axis (mirrors the Y label at the top). */
.position-chart .axis-x {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 5px;
  margin-top: 2px;
}
.position-chart .axis-glyph { color: var(--text-dim); font-size: 0.85rem; }

/* Inline "chip" select — reads as clickable text at the axis / in the legend. */
.position-chart .chart-sel { position: relative; display: inline-flex; align-items: center; }
.position-chart .chart-sel::after {
  content: "\25be";
  position: absolute;
  right: 3px;
  font-size: 0.6rem;
  opacity: 0.55;
  pointer-events: none;
}
.position-chart .chart-sel select {
  -webkit-appearance: none;
  appearance: none;
  /* Inherit the page colour-scheme so the native popup (option/optgroup) is
     dark in dark mode instead of the browser default light. */
  color-scheme: inherit;
  background: transparent;
  border: none;
  border-bottom: 1px dashed var(--border);
  color: var(--text);
  font: inherit;
  font-size: 0.78rem;
  padding: 2px 15px 2px 3px;
  max-width: 150px;
  cursor: pointer;
}
.position-chart .chart-sel select:hover,
.position-chart .chart-sel select:focus {
  color: var(--accent);
  border-bottom-color: var(--accent);
  outline: none;
}
/* The open native option list + its group titles need an opaque themed
   backdrop — without it they paint with the browser default (light) regardless
   of the page theme. */
.position-chart .chart-sel select option {
  background: var(--bg);
  color: var(--text);
}
.position-chart .chart-sel select optgroup {
  background: var(--bg);
  color: var(--text-dim);
  font-weight: 600;
}
