/* ══════════════════════════════════════════════════════════════════════
   QDS — QuantHub Design System
   Single source of truth for all dashboard/app UI primitives.
   Tokens and primitives aligned to docs/mocks/dashboard-live-qds.html.
   Story 15.1.1 — bootstrap design system + /qds gallery
   Story 15.1.1-fix — correct token drift + restore OS-style primitives
   Story 15.4.3 — own the fonts import + global body palette
   ══════════════════════════════════════════════════════════════════════ */

/* Google Fonts — Inter (UI) + Montserrat (display). Owned here so every
   page that loads qds.css (directly or via style.css's @import) gets
   them; individual templates don't need to repeat the <link> tag. */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Montserrat:wght@600;700;800&display=swap');

/* ── Design Tokens (v2: OS-tuned) ─────────────────────────────────── */
:root {
    /* Surfaces */
    --bg-page:        #000000;
    --bg-card:        #1e2235;
    --bg-card-2:      #0d1018;
    --bg-band:        #1a2540;
    --bg-select:      #020217;
    --border:         #2a2f45;
    --divider:        rgba(255,255,255,0.05);
    --hover:          rgba(255,255,255,0.035);

    /* Semantic gain/loss aliases */
    --positive:       #059669;
    --negative:       #c15757;

    /* Text */
    --text-primary:   #f5f5f7;
    --text-secondary: #9ca3af;
    --text-muted:     #6b7280;
    --text-subtle:    #4b5563;

    /* Semantic colors — each has a base, soft (bg tint), and fg (text-on-soft) */
    --green:          #22c55e;
    --green-soft:     rgba(34,197,94,0.18);
    --green-fg:       #059669;

    --red:            #ff3b3b;
    --red-soft:       rgba(255,59,59,0.18);
    --red-fg:         #c15757;

    --amber:          #ff9f0a;
    --amber-soft:     rgba(255,159,10,0.16);
    --amber-fg:       #ffc26b;

    --blue:           #0a84ff;
    --blue-soft:      rgba(10,132,255,0.16);
    --blue-fg:        #69b1ff;
    --blue-action:    #1b9fdf;

    /* Type scale — px based, matches OS reference */
    --text-xs:        12px;
    --text-sm:        14px;
    --text-md:        16px;
    --text-lg:        19px;
    --text-xl:        24px;
    --text-hero:      32px;

    /* Font families */
    --font-display:   'Montserrat', -apple-system, BlinkMacSystemFont, "SF Pro Display", sans-serif;
    --font-ui:        'Inter', -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;

    /* Spacing scale — 6 steps */
    --space-1: 4px;  --space-2: 8px;  --space-3: 12px;
    --space-4: 16px; --space-5: 20px; --space-6: 24px;

    /* Radii — 3 steps */
    --radius-sm: 4px;
    --radius-md: 8px;
    --radius-lg: 12px;

    /* Aliases (story 15.4.4) — semantic roles that showed up in templates
       before qds.css owned them. Each alias maps to an existing token so
       there's exactly one truth for every color; templates can keep using
       the more descriptive name. */
    --card-bg:        var(--bg-card);       /* common in inline styles */
    --bg-elevated:    var(--bg-card);       /* elevated surfaces (modals, dropdowns) */
    --bg-hover:       var(--hover);         /* hover-state backgrounds */
    --border-subtle:  var(--divider);       /* subtler than --border, for inner dividers */
}


/* ── Global body defaults (story 15.4.3) ──────────────────────────────
   Apply QDS palette at the document level so every page that loads
   qds.css renders QDS true-black + --text-primary on body, not just
   subtrees that happen to wrap in .qds. Kept minimal — specific
   sections still layer on their own .qds-scoped primitives below.
*/
body {
    background: var(--bg-page);
    color: var(--text-primary);
    font-family: var(--font-ui);
    font-size: var(--text-md);
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
}

/* ── Reset scoped to .qds ─────────────────────────────────────────── */
.qds {
    font-family: var(--font-ui);
    color: var(--text-primary);
    background: var(--bg-page);
    font-size: var(--text-md);
    line-height: 1.4;
    font-variant-numeric: tabular-nums;
    -webkit-font-smoothing: antialiased;
}
.qds *, .qds *::before, .qds *::after {
    box-sizing: border-box;
}
.qds a { color: inherit; text-decoration: none; }
.qds h1, .qds h2, .qds h3 { font-family: var(--font-display); }
.qds button, .qds input, .qds select, .qds textarea {
    font-family: inherit;
    color: inherit;
}


/* ══════════════════════════════════════════════════════════════════════
   PRIMITIVES
   ══════════════════════════════════════════════════════════════════════ */

/* ── .card — surface container ────────────────────────────────────── */
.qds .card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    margin-bottom: var(--space-6);
    overflow: hidden;
}

/* ── .section-header — collapsible header bar inside a card ───────── */
.qds .section-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-4) var(--space-5);
    cursor: pointer;
    user-select: none;
}
.qds .section-header h2 {
    margin: 0;
    font-size: var(--text-lg);
    font-weight: 600;
    color: var(--text-primary);
    letter-spacing: -0.2px;
}
.qds .section-header .chev {
    color: var(--text-muted);
    font-size: var(--text-lg);
}
.qds .section-body {
    padding: 0 var(--space-2) var(--space-3);
}

/* ── .sublabel — within-card section label ─────────────────────────── */
.qds .sublabel {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.6px;
    color: var(--text-muted);
    padding: var(--space-3) var(--space-4) var(--space-1);
    font-weight: 600;
}
.qds .sublabel:first-child { padding-top: 0; }
.qds .sublabel .meta {
    color: var(--text-subtle);
    font-weight: 500;
    margin-left: 4px;
}

/* ── .toolbar — above tables, OS-style (selects + export) ─────────── */
.qds .toolbar {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-4) var(--space-3);
    font-size: var(--text-sm);
    flex-wrap: wrap;
}
.qds .toolbar .group {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--text-muted);
}
.qds .toolbar select {
    background: var(--bg-select);
    color: var(--text-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    font-family: inherit;
    padding: 5px 22px 5px 8px;
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path d='M1 1l4 4 4-4' stroke='%239ca3af' stroke-width='1.5' fill='none'/></svg>");
    background-repeat: no-repeat;
    background-position: right 7px center;
}
.qds .toolbar .spacer { flex: 1; }
.qds .toolbar button.export {
    background: var(--blue-action);
    color: #fff;
    border: none;
    border-radius: var(--radius-sm);
    padding: 6px 14px;
    font-size: var(--text-sm);
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
}
.qds .toolbar button.export:hover { filter: brightness(1.1); }

/* ── .empty-state — calm zero-data message ──────────────────────────── */
.empty-state { color: var(--text-secondary); text-align: center; padding: var(--space-6); font-size: var(--text-md); }
.empty-state a { color: var(--blue-action); cursor: pointer; }


/* ── .os-table — dense data table (OptionStrat-inspired) ──────────── */
/* Columns: Name | Day | Total Return | Target Upside | Tags           */
/* tr.band = full-width group banner (STOCKS, UNCOVERED, etc.)         */
/* .dual = stacked dual-format (primary on top, secondary below)       */

.qds .os-table { width: 100%; border-collapse: collapse; }

/* ── .os-table-wrap — scroll container for Income Opportunities ─── */
.qds .os-table-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    position: relative;
}
.qds .os-table-wrap::after {
    content: '';
    position: absolute;
    top: 0; right: 0; bottom: 0;
    width: 32px;
    background: linear-gradient(to right, transparent, var(--bg-card));
    pointer-events: none;
}
/* 15.5.1 — On mobile, give .os-table a min-width so the wrap actually
   scrolls horizontally instead of squishing columns. Excludes .os-cards
   (Holdings flips to a card layout at ≤640px via the existing rule). */
@media (max-width: 768px) {
    .qds .os-table-wrap > .os-table:not(.os-cards) {
        min-width: 600px;
    }
}

/* thead — sentence case headers, no text-transform */
.qds .os-table thead th {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text-secondary);
    padding: var(--space-2) var(--space-3);
    text-align: left;
    background: var(--bg-card-2);
    border-bottom: 1px solid var(--divider);
    text-transform: none;
    font-variant-numeric: tabular-nums;
}
.qds .os-table thead th.num { text-align: right; }
/* 17.27.1 — header tooltips invite hover with a subtle dotted underline */
.qds .os-table thead th[title] { text-decoration: underline dotted var(--text-muted); text-underline-offset: 3px; }
.qds .os-table thead th.sorted::after {
    content: " \2191";
    color: var(--blue-action);
    font-weight: 700;
}

/* tr.band — full-width group banner row */
.qds .os-table tbody tr.band td {
    background: var(--bg-band);
    color: var(--text-primary);
    font-weight: 700;
    padding: 7px var(--space-3);
    font-size: var(--text-md);
    letter-spacing: 0.3px;
    border-top: 1px solid rgba(255,255,255,0.04);
}
.qds .os-table tbody tr.band td .meta {
    font-weight: 400;
    color: var(--text-secondary);
    font-size: var(--text-sm);
    margin-left: var(--space-2);
}

/* tr.data — regular data rows */
.qds .os-table tbody tr.data td {
    padding: 9px var(--space-3);
    font-size: var(--text-md);
    border-top: 1px solid var(--divider);
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
    vertical-align: middle;
}
.qds .os-table tbody tr.data:hover { background: var(--hover); }

/* Column alignment */
.qds .os-table td.num { text-align: right; }
.qds .os-table td .secondary {
    color: var(--text-muted);
    font-size: var(--text-sm);
}

/* .dual — stacked dual-format numbers (primary on top, +% below) */
.qds .os-table td .dual {
    display: inline-flex;
    flex-direction: column;
    gap: 1px;
    align-items: flex-end;
    line-height: 1.15;
}

/* Name column with ticker + description */
.qds .os-table td.name-col .ticker {
    color: var(--text-primary);
    font-weight: 600;
}
.qds .os-table td.name-col .desc {
    color: var(--text-muted);
    margin-left: var(--space-2);
    font-size: var(--text-sm);
}

/* Gain / loss cell coloring */
.qds .os-table td .gain { color: var(--green-fg); }
.qds .os-table td .loss { color: var(--red-fg); }

/* Tags cell */
.qds .os-table .tags {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}


/* ── .pill — solid day-change pill ────────────────────────────────── */
.qds .pill {
    display: inline-block;
    padding: 2px 9px;
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    font-weight: 600;
    color: #fff;
    font-variant-numeric: tabular-nums;
    min-width: 60px;
    text-align: center;
}
.qds .pill.up   { background: var(--green); }
.qds .pill.down { background: var(--red); }
.qds .pill.flat { background: var(--text-subtle); }

/* ── .badge — inline categorical tag ──────────────────────────────── */
.qds .badge {
    display: inline-block;
    padding: 1px 7px;
    border-radius: var(--radius-sm);
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    line-height: 1.6;
}

/* Conviction badges */
.qds .badge.conv-high { background: var(--green-soft); color: var(--green-fg); }
.qds .badge.conv-med  { background: var(--blue-soft);  color: var(--blue-fg);  }
.qds .badge.conv-low  { background: var(--amber-soft); color: var(--amber-fg); }
.qds .badge.no-research { background: rgba(107,114,128,0.18); color: var(--text-secondary); }
/* Holdings tag-chip overflow badge (story 17.26.1) — muted "+N more" indicator
   with full label list surfaced via title attribute on hover. */
.qds .badge.chip-overflow {
    background: rgba(107,114,128,0.12);
    color: var(--text-muted);
    font-weight: 600;
    cursor: help;
}

/* ── .qds-research-cta — File-research CTA chip on uncovered holdings (17.35.1)
   Renders only on rows in HOLDING (NO RESEARCH FILE) group. Anchor with
   mailto: opens email to ops@quanthub.ai with prefilled subject. Blue
   action accent — distinct from categorical conviction / valuation badges
   and from the muted "no research" badge so the call-to-action reads as
   tappable, not as another tag. */
.qds .qds-research-cta {
    display: inline-block;
    padding: 1px 7px;
    border-radius: var(--radius-sm);
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    line-height: 1.6;
    background: var(--blue-soft);
    color: var(--blue-fg);
    text-decoration: none;
    cursor: pointer;
}
.qds .qds-research-cta:hover {
    filter: brightness(1.15);
    text-decoration: none;
}

/* ── .qds-info-badge / .qds-info-popover — group-band educational popover
   (17.35.3). Small circular (i) badge sits next to a group band header
   (HOLDING (NO RESEARCH FILE) initially). Click opens a dark-themed
   popover with a 3-bullet plain-language explanation of why a holding
   lands in that group, plus two action CTAs. Dismissible via outside
   click or clicking the badge again (handlers in dashboard_live.html). */
.qds .qds-info-host { display: inline-block; margin-left: var(--space-2); vertical-align: middle; }
.qds .qds-info-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    padding: 0;
    border-radius: 50%;
    background: var(--bg-card-2);
    color: var(--text-secondary);
    border: 1px solid var(--border);
    font-family: var(--font-ui, Inter, sans-serif);
    font-size: 10px;
    font-weight: 700;
    font-style: italic;
    line-height: 1;
    cursor: pointer;
    user-select: none;
}
.qds .qds-info-badge:hover, .qds .qds-info-badge:focus {
    background: var(--blue-soft);
    color: var(--blue-fg);
    border-color: var(--blue-fg);
    outline: none;
}
.qds .qds-info-popover {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    z-index: 20;
    min-width: 280px;
    max-width: 360px;
    padding: var(--space-3) var(--space-4);
    background: var(--bg-card-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: 0 4px 14px rgba(0,0,0,0.45);
    color: var(--text-primary);
    font-family: var(--font-ui, Inter, sans-serif);
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
    text-align: left;
    white-space: normal;
}
.qds .qds-info-popover-title {
    font-size: var(--text-md);
    font-weight: 700;
    color: var(--text-primary);
    margin: 0 0 var(--space-2);
}
.qds .qds-info-popover-list {
    margin: 0 0 var(--space-3);
    padding-left: 18px;
    font-size: var(--text-sm);
    color: var(--text-secondary);
    line-height: 1.5;
}
.qds .qds-info-popover-list li { margin-bottom: 4px; }
.qds .qds-info-popover-list li:last-child { margin-bottom: 0; }
.qds .qds-info-popover-ctas {
    display: flex;
    gap: var(--space-2);
    flex-wrap: wrap;
    margin-top: var(--space-2);
}
.qds .qds-info-popover-btn {
    display: inline-block;
    padding: 5px 10px;
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    font-weight: 600;
    text-decoration: none;
    line-height: 1.2;
    cursor: pointer;
}
.qds .qds-info-popover-btn-primary {
    background: var(--blue-action);
    color: #fff;
    border: 1px solid var(--blue-action);
}
.qds .qds-info-popover-btn-primary:hover { filter: brightness(1.1); text-decoration: none; }
.qds .qds-info-popover-btn-secondary {
    background: transparent;
    color: var(--blue-fg);
    border: 1px solid var(--border);
}
.qds .qds-info-popover-btn-secondary:hover {
    background: var(--blue-soft);
    text-decoration: none;
}
.qds .qds-info-popover-foot {
    font-size: 11px;
    color: var(--text-muted);
    font-style: italic;
    margin-top: var(--space-2);
    line-height: 1.4;
}

/* Valuation badges */
.qds .badge.val-cheap     { background: var(--green-soft); color: var(--green-fg); }
.qds .badge.val-fair      { background: var(--blue-soft);  color: var(--blue-fg);  }
.qds .badge.val-expensive { background: var(--amber-soft); color: var(--amber-fg); }
.qds .badge.val-veryexp   { background: var(--red-soft);   color: var(--red-fg);   }


/* ── .qds-badge-with-reason — badge + 1-line reason caption (10.5.20c) ──
   Pairs a categorical badge (Dividend cut / Earnings risk / Underperform)
   with a plain-language reason sentence so we never ship a bare badge.
   Mirrors the /stocks/{t} zone-banner explanation pattern. */
.qds .qds-badge-with-reason {
    display: inline-flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    line-height: 1.3;
}
.qds .qds-badge-with-reason .badge { margin: 0; }
.qds .qds-badge-with-reason__reason {
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--text-secondary);
    max-width: 60ch;
}
/* Severity tints — match zone-banner accent palette */
.qds .qds-badge-with-reason.severity-red    .badge { background: var(--red-soft);   color: var(--red-fg);   }
.qds .qds-badge-with-reason.severity-amber  .badge { background: var(--amber-soft); color: var(--amber-fg); }
.qds .qds-badge-with-reason.severity-blue   .badge { background: var(--blue-soft);  color: var(--blue-fg);  }

/* Dashboard Portfolio Risk Insights container (10.5.20c) — section that
   stacks badge-with-reason rows underneath the Doctor narrative. */
.qds .pv-risk-insights { margin: var(--space-3) 0; }
.qds .pv-risk-row { padding: var(--space-2) 0; border-bottom: 1px solid var(--divider); }
.qds .pv-risk-row:last-child { border-bottom: 0; }


/* ── .zone — buy zone indicator with glow dot ────────────── */
.qds .zone {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    color: var(--green-fg);
    font-size: var(--text-sm);
    font-weight: 600;
}
.qds .zone .dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--green);
    box-shadow: 0 0 6px rgba(34,197,94,0.7);
}

/* ── .pct — color-coded percentage ────────────────────────────────── */
.qds .pct {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}
.qds .pct.positive { color: var(--green-fg); }
.qds .pct.negative { color: var(--red-fg); }
.os-table .pct.neutral {
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}

/* ── .upside — target-upside text ─────────────────────────────────── */
.qds .upside {
    color: var(--text-primary);
    font-weight: 600;
    font-size: var(--text-md);
}
.qds .upside.neg { color: var(--red-fg); }

/* ── QH-vs-analyst agreement chip (story 17.32.2) ─────────────────────
   Small inline pill rendered next to the single Analyst consensus column.
   Three classifications: agree (within ±10%), QH bearish (QH FV bearish
   while analysts neutral/bullish), QH bullish (QH FV bullish while
   analysts neutral/bearish). Muted colors so the chip does not compete
   with the analyst arrow + % for first read; tooltip carries the why. */
.qds .qh-chip {
    display: inline-block;
    margin-left: var(--space-2);
    padding: 3px 9px;
    font-size: var(--text-sm);
    font-weight: 700;
    line-height: 1.4;
    border-radius: 10px;
    border: 1px solid currentColor;
    vertical-align: middle;
    font-variant-numeric: tabular-nums;
    cursor: help;
}
.qds .qh-chip.qh-agree   { background: rgba(34,197,94,0.18);  color: var(--green-fg); }
.qds .qh-chip.qh-bearish { background: rgba(255,159,10,0.18); color: var(--amber-fg); }
.qds .qh-chip.qh-bullish { background: rgba(10,132,255,0.18); color: var(--blue-fg, #0a84ff); }

/* ── Per-row exception chips (story 17.32.4 — slice d) ────────────────
   Rendered AFTER the agreement chip in the Analyst column. Calm by
   default: a row gets a chip only when its state genuinely diverged
   (THESIS PRESSURE three-way disagreement), an event is imminent
   (EARNINGS within 7 days), or a transition happened today (BUY ZONE
   entry diffed vs prior-day snapshot). Same pill geometry as .qh-chip
   so the stack reads as a single inline strip without disrupting the
   row's vertical rhythm. */
.qds .exc-chip {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 7px;
    font-size: var(--text-xs);
    font-weight: 700;
    line-height: 1.4;
    border-radius: 10px;
    vertical-align: middle;
    letter-spacing: 0.02em;
    cursor: help;
}
.qds .exc-thesis-pressure { background: rgba(255,159,10,0.20); color: var(--amber-fg); }
.qds .exc-earnings        { background: rgba(10,132,255,0.18); color: var(--blue-fg, #0a84ff); }
.qds .exc-buy-zone        { background: rgba(34,197,94,0.20);  color: var(--green-fg); }


/* ── .metric-grid + .metric — KPI summary cards ──────────────────── */
.qds .metric-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: var(--space-4);
    padding: 0 var(--space-4) var(--space-4);
}
.qds .metric { padding: var(--space-3); }
.qds .metric .label {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.6px;
    color: var(--text-muted);
    font-weight: 600;
    margin-bottom: var(--space-1);
}
.qds .metric .value {
    font-size: var(--text-xl);
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    line-height: 1.1;
    font-family: var(--font-display);
}
.qds .metric .hint {
    font-size: var(--text-sm);
    color: var(--text-secondary);
    margin-top: var(--space-1);
}
.qds .metric .value.green { color: var(--green-fg); }
.qds .metric .value.red   { color: var(--red-fg); }

/* Impact badges (catalysts & risks) */
.qds .badge.impact-high   { background: var(--red-soft);   color: var(--red-fg);   }
.qds .badge.impact-medium { background: var(--amber-soft); color: var(--amber-fg); }
.qds .badge.impact-low    { background: rgba(107,114,128,0.18); color: var(--text-secondary); }

/* Maturity badges (growth engines) */
.qds .badge.maturity-early   { background: var(--amber-soft); color: var(--amber-fg); }
.qds .badge.maturity-scaling { background: var(--green-soft); color: var(--green-fg); }
.qds .badge.maturity-mature  { background: rgba(107,114,128,0.18); color: var(--text-secondary); }


/* ── .chip-grid + .chip — compact tags ────────────────────────────── */
.qds .chip-grid {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    padding: 0 var(--space-4) var(--space-4);
}
.qds .chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 10px;
    border-radius: var(--radius-sm);
    background: var(--bg-card-2);
    border: 1px solid var(--border);
    font-size: var(--text-sm);
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}
.qds .chip .ticker {
    color: var(--text-primary);
    font-weight: 700;
}


/* ── .signal-card — convergence signal card ───────────────────────── */
.qds .signal-card {
    background: var(--bg-card-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: var(--space-3) var(--space-4);
    transition: border-color 0.12s;
    cursor: pointer;
}
.qds .signal-card:hover { border-color: var(--blue); }
.qds .signal-card .head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: var(--space-2);
}
.qds .signal-card .ticker {
    font-size: var(--text-md);
    font-weight: 700;
    color: var(--text-primary);
}
.qds .signal-card .score {
    font-size: var(--text-xs);
    color: var(--blue-fg);
    font-weight: 700;
}
.qds .signal-card .pills {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}


/* ── .action-item — recommended action list item ──────────────────── */
.qds .actions {
    padding: 0 var(--space-4) var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}
.qds .action-item {
    background: var(--bg-card-2);
    border-left: 3px solid var(--blue);
    padding: var(--space-3) var(--space-4);
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
    display: flex;
    gap: var(--space-3);
    align-items: flex-start;
}
.qds .action-item .body { flex: 1; }
.qds .action-item .title {
    font-size: var(--text-md);
    color: var(--text-primary);
    font-weight: 600;
}
.qds .action-item .reason {
    font-size: var(--text-sm);
    color: var(--text-secondary);
    margin-top: 4px;
    line-height: 1.5;
}


/* ── .intraday-update — Portfolio Intelligence auto-refresh (17.1.3) ─── */
.intraday-update {
    background: var(--bg-card-2);
    /* Emerald accent (QDS --positive = #059669) signals a live-data update
       distinct from blue recommended-action items. */
    border-left: 3px solid var(--positive, #059669);
    padding: var(--space-3) var(--space-4);
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
}
.intraday-update + .intraday-update {
    margin-top: var(--space-2);
}


/* ── .indices-grid + .index-card — market index cards ─────────────── */
.qds .indices-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: var(--space-3);
    padding: 0 var(--space-4) var(--space-4);
}
.qds .index-card {
    background: var(--bg-card-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: var(--space-3);
    text-align: center;
}
.qds .index-card .name {
    font-size: var(--text-xs);
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    font-weight: 600;
}
.qds .index-card .price {
    font-size: var(--text-lg);
    font-weight: 700;
    margin: 4px 0 2px;
    font-variant-numeric: tabular-nums;
    font-family: var(--font-display);
}
.qds .index-card .change {
    font-size: var(--text-sm);
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}


/* ── .earnings-chip — upcoming earnings date chip ─────────────────── */
.qds .earnings-chip {
    background: var(--bg-card-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: var(--space-3);
    text-align: center;
}
.qds .earnings-chip.today {
    background: var(--amber-soft);
    border-color: var(--amber);
}
.qds .earnings-chip .symbol {
    font-size: var(--text-md);
    font-weight: 700;
    color: var(--text-primary);
}
.qds .earnings-chip .date {
    font-size: var(--text-xs);
    color: var(--text-secondary);
    margin-top: 2px;
    font-weight: 500;
}
.qds .earnings-chip.today .date {
    color: var(--amber-fg);
    font-weight: 700;
}

/* ── .earnings-grid — layout container for earnings chips ───────── */
.qds .earnings-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: var(--space-2);
    padding: 0 var(--space-4) var(--space-4);
}


/* ── [data-tip] tooltip — pure CSS hover tooltip ──────────────────── */
.qds [data-tip] {
    position: relative;
    cursor: help;
}
.qds [data-tip]:hover::after {
    content: attr(data-tip);
    position: absolute;
    bottom: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%);
    background: #1f2230;
    color: var(--text-primary);
    font-size: var(--text-xs);
    font-weight: 500;
    line-height: 1.4;
    padding: 8px 10px;
    border-radius: 6px;
    white-space: normal;
    width: 240px;
    border: 1px solid rgba(255,255,255,0.1);
    z-index: 100;
    pointer-events: none;
}


/* ── Utility: gain/loss text anywhere ─────────────────────────────── */
.qds .gain { color: var(--green-fg); }
.qds .loss { color: var(--red-fg); }


/* ── .narrative — morning intelligence text block ─────────────────── */
.qds .narrative {
    padding: 0 var(--space-4) var(--space-4);
    color: var(--text-secondary);
    font-size: var(--text-md);
    line-height: 1.65;
}
.qds .narrative b { color: var(--text-primary); font-weight: 600; }
.qds .narrative .market-status {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--green-fg);
    font-size: var(--text-sm);
    font-weight: 600;
    margin-bottom: var(--space-3);
}
.qds .narrative .market-status .dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--green);
    box-shadow: 0 0 6px rgba(34,197,94,0.6);
}

/* ── .hero — page hero heading ────────────────────────────────────── */
.qds .hero {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    padding: var(--space-2) 0 var(--space-6);
}
.qds .hero h1 {
    font-size: var(--text-hero);
    font-weight: 700;
    margin: 0 0 var(--space-1);
    letter-spacing: -0.5px;
    font-family: var(--font-display);
    line-height: 1.05;
}
.qds .hero .sub {
    color: var(--text-muted);
    font-size: var(--text-sm);
}
.qds .grade-badge {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--blue-soft);
    color: var(--blue-fg);
    font-size: var(--text-xl);
    font-weight: 800;
    border: 2px solid var(--blue);
    font-family: var(--font-display);
}

/* Story 17.10.1: letter-grade pill variants for the email-style inline badge
   (also usable on web). Colors map to DESIGN.md §3 grade tokens. */
.grade-pill {
    display: inline-block;
    font-weight: 700;
    border-radius: 4px;
    padding: 4px 10px;
    font-size: 14px;
    line-height: 1;
    color: #ffffff;
}
.grade-pill.grade-a { background: #059669; }
.grade-pill.grade-b { background: #3b82f6; }
.grade-pill.grade-c { background: #d97706; }
.grade-pill.grade-d { background: #ea580c; }
.grade-pill.grade-f { background: #dc2626; }

/* Grade-variant coloring for .grade-badge (the circular headline grade badge)
   — was hardcoded to var(--blue)/var(--blue-soft) regardless of the actual
   letter grade, the one rule the .grade-pill mapping above already got right.
   Reuses the exact same hex values as .grade-pill (DESIGN.md §3 grade→color
   rule) as a soft-fill/ring variant to match .grade-badge's own visual
   language (translucent fill + colored ring) rather than the pill's solid
   fill. Class is derived from the grade's first letter, lowercased — same
   as .grade-pill (see dashboard_live.html renderGradeBadge()). No grade-*
   class present (unknown/missing grade) falls back to the base blue rule
   above. */
.grade-badge.grade-a { background: rgba(5,150,105,0.18);  color: #059669; border-color: #059669; }
.grade-badge.grade-b { background: rgba(59,130,246,0.18); color: #3b82f6; border-color: #3b82f6; }
.grade-badge.grade-c { background: rgba(217,119,6,0.18);  color: #d97706; border-color: #d97706; }
.grade-badge.grade-d { background: rgba(234,88,12,0.18);  color: #ea580c; border-color: #ea580c; }
.grade-badge.grade-f { background: rgba(220,38,38,0.18);  color: #dc2626; border-color: #dc2626; }

/* Grade-variant coloring for .pv-grade-float — the LIVE headline grade badge
   on /dashboard/portfolio (Portfolio hub + Doctor tab, rendered by
   templates/_portfolio_doctor_body.html). Its base rule in static/css/style.css
   hardcodes var(--pv-blue) on the box and the .mark letter regardless of
   grade — the product's single most prominent number ignoring the
   .grade-pill color rule. Fixed here (not in style.css) by overriding with
   the same hex values as .grade-pill above; the .qds ancestor gives these
   rules enough specificity to beat style.css's rules regardless of
   stylesheet load order. Class is added by the Alpine :class binding in
   _portfolio_doctor_body.html (first-letter-lowercased, same derivation as
   .grade-pill). No grade-* class present (unknown/missing grade) falls back
   to style.css's blue rule. */
.qds .pv-grade-float.grade-a { border-color: #059669; background: rgba(5,150,105,0.08); }
.qds .pv-grade-float.grade-a .mark { color: #059669; }
.qds .pv-grade-float.grade-b { border-color: #3b82f6; background: rgba(59,130,246,0.08); }
.qds .pv-grade-float.grade-b .mark { color: #3b82f6; }
.qds .pv-grade-float.grade-c { border-color: #d97706; background: rgba(217,119,6,0.08); }
.qds .pv-grade-float.grade-c .mark { color: #d97706; }
.qds .pv-grade-float.grade-d { border-color: #ea580c; background: rgba(234,88,12,0.08); }
.qds .pv-grade-float.grade-d .mark { color: #ea580c; }
.qds .pv-grade-float.grade-f { border-color: #dc2626; background: rgba(220,38,38,0.08); }
.qds .pv-grade-float.grade-f .mark { color: #dc2626; }

/* ── .signals-grid — convergence signal grid ──────────────────────── */
.qds .signals-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: var(--space-3);
    padding: 0 var(--space-4) var(--space-4);
}


/* ── Gallery page layout helpers (for /qds only) ──────────────────── */
.qds-gallery {
    max-width: 1080px;
    margin: 0 auto;
    padding: var(--space-6);
}
.qds-gallery h1 {
    font-family: var(--font-display);
    font-size: var(--text-hero);
    font-weight: 800;
    letter-spacing: -0.03em;
    margin-bottom: var(--space-2);
}
.qds-gallery .subtitle {
    color: var(--text-secondary);
    font-size: var(--text-md);
    margin-bottom: 32px;
}
.qds-gallery section {
    margin-bottom: 40px;
}
.qds-gallery section > h2 {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--text-primary);
    margin-bottom: var(--space-4);
    padding-bottom: var(--space-2);
    border-bottom: 1px solid var(--border);
}
.qds-gallery section > h3 {
    font-size: var(--text-md);
    font-weight: 600;
    color: var(--text-secondary);
    margin: var(--space-4) 0 var(--space-2);
}
.qds-gallery .swatch-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: var(--space-3);
}
.qds-gallery .swatch {
    padding: var(--space-4);
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
    font-size: var(--text-sm);
}
.qds-gallery .swatch .var-name {
    font-family: monospace;
    font-size: var(--text-xs);
    color: var(--text-secondary);
    margin-top: var(--space-1);
}
.qds-gallery .type-sample {
    margin-bottom: var(--space-3);
}
.qds-gallery .type-sample .label {
    font-family: monospace;
    font-size: var(--text-xs);
    color: var(--text-muted);
}
.qds-gallery .demo-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    align-items: center;
    margin-bottom: var(--space-3);
}
.qds-gallery .tokens-card {
    background: var(--bg-card-2);
    padding: var(--space-4) var(--space-5);
    margin-bottom: var(--space-6);
    border-radius: var(--radius-lg);
    border: 1px dashed rgba(255,255,255,0.1);
}


/* ── Skeleton rows (17.8.2) — NO animation ────────────────────────── */
/* First-load placeholder rows. No keyframes, no pulse, no shimmer.   */
.skeleton-row td { padding: 8px 12px; }
.skeleton-block { background: var(--bg-card-2); border-radius: 4px; height: 14px; display: inline-block; }
.skeleton-block.w-50 { width: 50%; }
.skeleton-block.w-75 { width: 75%; }

/* ── Form primitives (story 15.4.8) ──────────────────────────────── */

/* .form-input — text / email / number / select / textarea */
.qds .form-input {
    width: 100%;
    padding: 10px var(--space-4);
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
    background: var(--bg-card-2);
    color: var(--text-primary);
    font-size: var(--text-sm);
    font-family: inherit;
    outline: none;
    transition: border-color 0.15s, box-shadow 0.15s;
    box-sizing: border-box;
}
.qds .form-input:focus {
    border-color: var(--blue-action);
    box-shadow: 0 0 0 3px var(--blue-soft);
}
.qds .form-input::placeholder { color: var(--text-muted); }
.qds textarea.form-input { resize: vertical; min-height: 100px; }

/* .form-label — label above a form-input */
.qds .form-label {
    display: block;
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text-primary);
    margin-bottom: var(--space-2);
}
.qds .form-hint {
    font-size: var(--text-xs);
    color: var(--text-secondary);
    margin-top: 6px;
}

/* .btn — base button (all variants extend this) */
.qds .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-2) var(--space-5);
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    border: none;
    transition: filter 0.15s, background 0.15s;
    line-height: 1.4;
    white-space: nowrap;
}
.qds .btn:disabled { opacity: 0.5; cursor: not-allowed; }

/* .btn-primary — solid blue CTA */
.qds .btn-primary {
    background: var(--blue-action);
    color: #fff;
    border: none;
}
.qds .btn-primary:hover:not(:disabled) { filter: brightness(1.1); }

/* .btn-secondary — ghost button */
.qds .btn-secondary {
    background: transparent;
    color: var(--text-secondary);
    border: 1px solid var(--border);
}
.qds .btn-secondary:hover:not(:disabled) {
    color: var(--text-primary);
    border-color: var(--text-secondary);
}

/* .btn-danger — destructive action (always uses --red-fg) */
.qds .btn-danger {
    background: transparent;
    color: var(--red-fg);
    border: 1px solid var(--red-fg);
}
.qds .btn-danger:hover:not(:disabled) { background: var(--red-soft); }

/* .save-status — inline save feedback (success must use --green-fg) */
.qds .save-status {
    font-size: var(--text-sm);
    min-height: 1.4em;
    color: var(--text-secondary);
}
.qds .save-status.success { color: var(--green-fg); }
.qds .save-status.error   { color: var(--red-fg); }

/* .toggle-switch / .toggle-track — iOS-style toggle (shared by settings+setup) */
.qds .toggle-switch {
    position: relative;
    width: 44px;
    height: 24px;
    cursor: pointer;
    flex-shrink: 0;
}
.qds .toggle-switch input { opacity: 0; width: 0; height: 0; }
.qds .toggle-track {
    position: absolute;
    inset: 0;
    background: var(--bg-card-2);
    border-radius: 12px;
    border: 1px solid var(--border);
    transition: all 0.2s;
}
.qds .toggle-track::after {
    content: '';
    position: absolute;
    width: 18px;
    height: 18px;
    background: var(--text-secondary);
    border-radius: 50%;
    top: 2px;
    left: 2px;
    transition: all 0.2s;
}
.qds .toggle-switch input:checked + .toggle-track {
    background: var(--blue-action);
    border-color: var(--blue-action);
}
.qds .toggle-switch input:checked + .toggle-track::after {
    background: #fff;
    transform: translateX(20px);
}

/* .toggle-slider variant (setup.html uses this class name) */
.qds .toggle-slider {
    position: absolute;
    cursor: pointer;
    top: 0; left: 0; right: 0; bottom: 0;
    background: var(--bg-card-2);
    border: 1px solid var(--border);
    border-radius: 24px;
    transition: 0.2s;
}
.qds .toggle-slider:before {
    content: "";
    position: absolute;
    height: 18px;
    width: 18px;
    left: 2px;
    bottom: 2px;
    background: white;
    border-radius: 50%;
    transition: 0.2s;
    box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}
.qds .toggle-switch input:checked + .toggle-slider {
    background: var(--blue-action);
    border-color: var(--blue-action);
}
.qds .toggle-switch input:checked + .toggle-slider:before { transform: translateX(20px); }


/* ── Responsive ───────────────────────────────────────────────────── */
@media (max-width: 640px) {
    .qds .metric-grid {
        grid-template-columns: repeat(2, 1fr);
    }
    .qds .indices-grid {
        grid-template-columns: repeat(2, 1fr);
    }
    .qds .os-table tbody tr.data td {
        font-size: var(--text-sm);
    }
    /* Holdings card layout — os-cards class added by JS builder */
    .qds .os-table.os-cards thead { display: none; }
    .qds .os-table.os-cards tbody tr.data {
        display: flex;
        flex-wrap: wrap;
        gap: var(--space-1) var(--space-3);
        padding: var(--space-3);
        border-bottom: 1px solid var(--divider);
    }
    .qds .os-table.os-cards tbody tr.data td {
        display: block;
        border-top: none;
        padding: 0;
        font-size: var(--text-sm);
    }
    .qds .os-table.os-cards tbody tr.data td.name-col { flex: 0 0 100%; }
    .qds .os-table.os-cards tbody tr.data td.sparkline-col,
    .qds .os-table.os-cards tbody tr.data td.weight-col { display: none; }
    .qds .os-table.os-cards tbody tr.data td[data-col]::before {
        content: attr(data-col);
        display: block;
        font-size: 10px;
        color: var(--text-muted);
        text-transform: uppercase;
        letter-spacing: 0.4px;
        margin-bottom: 1px;
    }
    .qds [data-tip]:hover::after {
        width: 180px;
        left: 0;
        transform: none;
    }
}


/* ── Quinn FAB — mobile-only floating action button (story 14.5.7) ── */
.quinn-fab {
    position: fixed;
    bottom: var(--space-4);
    right: var(--space-4);
    width: 56px;
    height: 56px;
    min-width: 44px;
    min-height: 44px;
    border-radius: 50%;
    background: var(--blue-action);
    color: #fff;
    border: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
    z-index: 1000;
    transition: transform 0.15s ease;
}
.quinn-fab:active { transform: scale(0.93); }
@media (min-width: 768px) { .quinn-fab { display: none; } }

/* ── Since Your Last Visit strip (Story 10.5.17) ──
   Compact horizontal row above Portfolio Intelligence. Holdings-scoped diff
   bullets capped at 3. Signal-only saturation per DESIGN.md §3: accent text
   only, no row backgrounds, no animation. */
.qds .since-last-visit-strip {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-3);
    padding: var(--space-2) var(--space-4);
    margin: 0 0 var(--space-3);
    background: var(--bg-card-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    font-family: var(--font-ui);
    font-size: var(--text-sm);
    color: var(--text-secondary);
}
.qds .since-last-visit-strip .slv-label {
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    white-space: nowrap;
}
.qds .since-last-visit-strip .slv-bullets {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-4);
    margin: 0;
    padding: 0;
    list-style: none;
}
.qds .since-last-visit-strip .slv-bullet {
    color: var(--text-secondary);
    font-weight: 500;
}
.qds .since-last-visit-strip .slv-bullet.slv-accent-amber  { color: var(--amber-fg); }
.qds .since-last-visit-strip .slv-bullet.slv-accent-emerald { color: var(--green-fg); }
.qds .since-last-visit-strip .slv-bullet.slv-accent-muted  { color: var(--text-muted); }
.qds .since-last-visit-strip .slv-empty {
    color: var(--text-muted);
    font-style: italic;
}
.qds .since-last-visit-strip .slv-more {
    margin-left: auto;
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--blue-fg);
    text-decoration: none;
}
.qds .since-last-visit-strip .slv-more:hover { text-decoration: underline; }

@media (max-width: 768px) {
    .qds .since-last-visit-strip {
        flex-direction: column;
        align-items: flex-start;
    }
    .qds .since-last-visit-strip .slv-bullets {
        flex-direction: column;
        gap: var(--space-1);
        width: 100%;
    }
    .qds .since-last-visit-strip .slv-more {
        margin-left: 0;
    }
}

/* === Nav Component === */
/* Ported from style.css in story 15.4.10b — prerequisite for deleting style.css in 15.4.11. */

.container {
    max-width: 1080px;
    margin: 0 auto;
    padding: 0 var(--space-6);
}

nav {
    padding: var(--space-5) 0;
    border-bottom: 1px solid var(--border);
}

nav .container {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.logo {
    font-size: 1.25rem;
    font-weight: 700;
    color: var(--text-primary);
    text-decoration: none;
    letter-spacing: -0.02em;
}

.logo span { color: var(--blue-action); }

.nav-link {
    color: var(--text-primary);
    text-decoration: none;
    font-size: var(--text-sm);
    transition: color 0.2s;
}
.nav-link:hover { color: var(--blue-action); }

.nav-tag {
    font-size: var(--text-xs);
    color: var(--blue-action);
    background: var(--blue-soft);
    padding: var(--space-1) var(--space-3);
    border-radius: 20px;
    font-weight: 500;
    text-decoration: none;
    cursor: pointer;
}

.nav-links {
    display: flex;
    gap: var(--space-3);
    align-items: center;
}

/* Hamburger — hidden on desktop, shown on mobile */
.hamburger {
    display: none;
    background: none;
    border: none;
    color: var(--text-primary);
    cursor: pointer;
    padding: var(--space-1);
    line-height: 0;
}

/* Story 17.75.1 (CAND-2026-05-21-028 finding #2): hamburger breakpoint
   raised from 480px to 768px so the nav collapses for all mobile-sized
   screens (the prior 480px gap left 11 logged-in links overflowing
   horizontally on standard 390-414px phones). */
@media (max-width: 768px) {
    .hamburger {
        display: block;
    }

    .nav-links {
        display: none;
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        background: var(--bg-card-2);
        border-bottom: 1px solid var(--border);
        flex-direction: column;
        padding: var(--space-2) 0;
        z-index: 1000;
    }

    .nav-links.open {
        display: flex;
    }

    .nav-links .nav-link,
    .nav-links .nav-tag {
        display: block;
        padding: var(--space-3) var(--space-6);
        min-height: 44px;
        line-height: 20px;
        font-size: var(--text-md);
        border-bottom: 1px solid var(--border);
    }

    .nav-links .nav-link:last-child,
    .nav-links .nav-tag:last-child {
        border-bottom: none;
    }

    .nav-links .nav-link:hover,
    .nav-links .nav-tag:hover {
        background: var(--blue-soft);
    }

    .nav-links .nav-tag {
        text-align: left;
        border-radius: 0;
    }

    nav {
        position: relative;
    }
}

/* === Landing page + footer === */
/* Ported from style.css in story 15.4.9 — prerequisite for deleting style.css in 15.4.11.
   All selectors live here (not style.css) so the landing page continues rendering
   once style.css is removed. Raw hex values were swapped for QDS tokens where a
   close match exists in :root. */

/* ── Hero ── */
.hero {
    padding: 60px 0 40px;
    text-align: center;
}

.hero h1 {
    font-size: clamp(2.2rem, 5vw, 3.5rem);
    font-weight: 800;
    line-height: 1.15;
    letter-spacing: -0.03em;
    margin-bottom: var(--space-5);
    font-family: var(--font-display);
}

.hero h1 .highlight {
    background: linear-gradient(135deg, var(--blue), var(--blue-fg));
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}

.hero .subtitle {
    font-size: 1.2rem;
    color: var(--text-secondary);
    max-width: 600px;
    margin: 0 auto 40px;
    line-height: 1.6;
}

/* ── Signup card ── */
.signup-card {
    max-width: 620px;
    margin: 0 auto;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: var(--space-6) 36px var(--space-5);
    box-shadow: 0 4px 24px rgba(0, 0, 0, 0.2), 0 0 0 1px var(--blue-soft);
}

/* ── Signup form ── */
.signup-form {
    display: flex;
    gap: var(--space-3);
    margin: 0 auto;
    justify-content: center;
}

.signup-form input[type="email"],
.signup-form input[type="text"] {
    flex: 1;
    padding: 14px var(--space-5);
    border-radius: var(--radius-lg);
    border: 1px solid var(--border);
    background: var(--bg-card-2);
    color: var(--text-primary);
    font-size: 1rem;
    font-family: inherit;
    outline: none;
    transition: border-color 0.2s;
}

.signup-form input[type="email"]:focus,
.signup-form input[type="text"]:focus {
    border-color: var(--blue-action);
    box-shadow: 0 0 0 3px var(--blue-soft);
}

.signup-form input[type="email"]::placeholder,
.signup-form input[type="text"]::placeholder {
    color: var(--text-secondary);
}

/* .btn-primary — global CTA used by landing + other pages */
.btn-primary {
    padding: 14px 28px;
    border-radius: var(--radius-lg);
    border: none;
    background: var(--blue-action);
    color: #fff;
    font-size: 1rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.2s, transform 0.1s;
    white-space: nowrap;
}

.btn-primary:hover { background: var(--blue-action); filter: brightness(1.1); }
.btn-primary:active { transform: scale(0.98); }
.btn-primary:disabled { opacity: 0.6; cursor: not-allowed; }

.signup-message {
    margin-top: 0;
    font-size: 0.9rem;
    min-height: 0;
}
.signup-message:not(:empty) {
    margin-top: 14px;
}

.signup-message.success   { color: var(--green-fg); }
.signup-message.error     { color: var(--red-fg); }
.signup-message.duplicate { color: var(--blue-action); }
.signup-message.waitlist  { color: var(--amber-fg); }

.signup-note {
    margin-top: 10px;
    font-size: 0.8rem;
    color: var(--text-secondary);
}

/* ── Sample briefing preview ── */
.preview {
    padding: 40px 0;
}

.preview h2 {
    text-align: center;
    font-size: 1.5rem;
    font-weight: 700;
    margin-bottom: var(--space-3);
    letter-spacing: -0.02em;
}

.preview .preview-sub {
    text-align: center;
    color: var(--text-secondary);
    margin-bottom: 40px;
    font-size: 0.95rem;
}

.preview-frame {
    max-width: 680px;
    margin: 0 auto;
    border-radius: var(--radius-lg);
    overflow: hidden;
    border: 1px solid var(--border);
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
}

.preview-frame img {
    width: 100%;
    display: block;
}

/* ── Preview tabs (note: tab chrome renders light-on-dark because preview
   mirrors the briefing email palette, which is intentionally light-themed.
   Email-palette hexes retained here since they match the email design
   tokens, not the web QDS tokens.) ── */
.preview-tabs {
    display: flex;
    background: #f1f5f9;
    border-bottom: 1px solid #e2e8f0;
}

.preview-tab {
    flex: 1;
    padding: var(--space-3) var(--space-2);
    border: none;
    background: none;
    font-size: 0.8rem;
    font-weight: 600;
    font-family: inherit;
    color: #64748b;
    cursor: pointer;
    transition: all 0.15s ease;
    border-bottom: 2px solid transparent;
}

.preview-tab:hover {
    color: #334155;
    background: rgba(59, 130, 246, 0.04);
}

.preview-tab.active {
    color: #1e293b;
    background: #ffffff;
    border-bottom-color: #3b82f6;
}

.preview-panel {
    display: none;
}

.preview-panel.active {
    display: block;
}

/* ── Features ── */
.features {
    padding: 40px 0;
    background: var(--bg-card);
    border-top: 1px solid var(--divider);
}

.features h2 {
    text-align: center;
    font-size: 1.5rem;
    font-weight: 700;
    margin-bottom: 40px;
    letter-spacing: -0.02em;
}

.features-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: var(--space-6);
}

.feature-card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 28px;
    display: flex;
    flex-direction: column;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.feature-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
}

.feature-icon {
    color: var(--blue-action);
    margin-bottom: 14px;
    line-height: 1;
}

.feature-card h3 {
    font-size: 1.05rem;
    font-weight: 600;
    margin-bottom: var(--space-2);
}

.feature-card p {
    font-size: 0.9rem;
    color: var(--text-secondary);
    line-height: 1.5;
}

/* ── Social proof ── */
.social-proof {
    padding: 56px 0;
    background: linear-gradient(180deg, var(--green-soft) 0%, var(--blue-soft) 100%);
    border-top: 1px solid var(--green-soft);
    border-bottom: 1px solid var(--blue-soft);
}

.proof-eyebrow {
    text-align: center;
    font-size: 0.75rem;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 1px;
    margin-bottom: var(--space-2);
}

.social-proof h2 {
    text-align: center;
    font-size: 1.8rem;
    font-weight: 800;
    margin-bottom: 36px;
    letter-spacing: -0.03em;
}

.proof-stats {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--space-5);
    max-width: 760px;
    margin: 0 auto 28px;
}

.proof-stat {
    text-align: center;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: var(--space-6) var(--space-3);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.proof-stat:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
}

.proof-stat.highlight-stat {
    border-color: var(--green-soft);
    background: linear-gradient(135deg, var(--bg-card) 0%, var(--green-soft) 100%);
}

.stat-number {
    display: block;
    font-size: 1.8rem;
    font-weight: 800;
    color: var(--green-fg);
    letter-spacing: -0.02em;
}

.stat-number.dollar {
    font-size: 2.2rem;
}

.stat-label {
    display: block;
    font-size: 0.72rem;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-top: var(--space-1);
}

.proof-link {
    text-align: center;
    margin-top: var(--space-5);
}

.proof-link a {
    color: var(--blue-action);
    text-decoration: none;
    font-size: 0.9rem;
    font-weight: 600;
    padding: var(--space-2) var(--space-5);
    border: 1px solid var(--blue-action);
    border-radius: 20px;
    transition: all 0.2s;
}

.proof-link a:hover {
    background: var(--blue-action);
    color: #fff;
}

/* ── Stats bar ── */
.stats-bar {
    text-align: center;
    font-size: 0.85rem;
    color: var(--text-secondary);
    margin-bottom: var(--space-3);
    font-weight: 500;
    letter-spacing: 0.01em;
}

.stats-bar-item {
    color: var(--text-primary);
    font-weight: 600;
}

.stats-bar-sep {
    margin: 0 var(--space-2);
    opacity: 0.4;
}

/* ── Subscriber count ── */
.subscriber-count {
    text-align: center;
    font-size: 0.9rem;
    color: var(--green-fg);
    font-weight: 600;
    margin-bottom: 28px;
}

/* ── Trust signals ── */
.trust-signals {
    display: flex;
    justify-content: center;
    gap: var(--space-6);
    flex-wrap: wrap;
    margin-top: var(--space-6);
}

.trust-signal {
    font-size: 0.78rem;
    color: var(--text-secondary);
    display: flex;
    align-items: center;
    gap: 6px;
}

.trust-signal::before {
    content: "\2713";
    color: var(--green-fg);
    font-weight: 700;
    font-size: 0.85rem;
}

/* ── Options Proof (amber-accented backtest section) ── */
.options-proof {
    padding: 56px 0;
    text-align: center;
    background: linear-gradient(180deg, var(--amber-soft) 0%, rgba(255, 159, 10, 0.02) 100%);
    border-top: 1px solid var(--amber-soft);
    border-bottom: 1px solid var(--amber-soft);
}

.options-proof-badge {
    display: inline-block;
    font-size: 0.65rem;
    font-weight: 700;
    color: var(--amber-fg);
    background: var(--amber-soft);
    border: 1px solid var(--amber);
    padding: 3px var(--space-3);
    border-radius: 20px;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    margin-bottom: var(--space-3);
}

.options-proof h2 {
    font-size: 1.5rem;
    font-weight: 700;
    margin-bottom: var(--space-2);
    letter-spacing: -0.02em;
}

.options-proof-sub {
    color: var(--text-secondary);
    font-size: 0.9rem;
    margin-bottom: 32px;
    max-width: 560px;
    margin-left: auto;
    margin-right: auto;
}

.options-proof-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-5);
    max-width: 680px;
    margin: 0 auto var(--space-6);
}

.options-proof-card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: var(--space-6) var(--space-4);
}

.options-proof-highlight {
    border-color: var(--amber);
    background: linear-gradient(135deg, var(--bg-card) 0%, var(--amber-soft) 100%);
}

.options-stat-number {
    display: block;
    font-size: 1.8rem;
    font-weight: 800;
    color: var(--amber-fg);
    letter-spacing: -0.02em;
}

.options-stat-dollar {
    font-size: 2rem;
}

.options-stat-per {
    font-size: 0.9rem;
    font-weight: 600;
    opacity: 0.7;
}

.options-stat-label {
    display: block;
    font-size: 0.72rem;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-top: var(--space-1);
}

.options-stat-sub {
    display: block;
    font-size: 0.7rem;
    color: var(--text-secondary);
    opacity: 0.7;
    margin-top: 2px;
}

.options-proof-cta {
    margin-top: var(--space-5);
}

.options-proof-cta a {
    color: var(--amber-fg);
    text-decoration: none;
    font-size: 0.9rem;
    font-weight: 600;
    padding: var(--space-2) var(--space-5);
    border: 1px solid var(--amber);
    border-radius: 20px;
    transition: all 0.2s;
}

.options-proof-cta a:hover {
    background: var(--amber);
    color: var(--bg-page);
}

.options-proof-disclaimer {
    margin-top: var(--space-4);
    font-size: 0.7rem;
    color: var(--text-secondary);
    opacity: 0.6;
}

/* ── How it works ── */
.how-it-works {
    padding: 40px 0;
    background: var(--bg-card-2);
    border-top: 1px solid var(--divider);
}

.how-it-works h2 {
    text-align: center;
    font-size: 1.5rem;
    font-weight: 700;
    margin-bottom: 40px;
    letter-spacing: -0.02em;
}

.steps {
    display: flex;
    gap: 32px;
    justify-content: center;
    flex-wrap: wrap;
    list-style: none;
    counter-reset: step;
}

.step {
    text-align: center;
    max-width: 260px;
    counter-increment: step;
}

.step h3::before {
    content: counter(step) ". ";
    color: var(--blue-action);
    font-weight: 700;
}

.step h3 {
    font-size: 1rem;
    font-weight: 600;
    margin-bottom: var(--space-2);
}

.step p {
    font-size: 0.85rem;
    color: var(--text-secondary);
    line-height: 1.5;
}

/* ── FAQ ── */
.faq {
    padding: 56px 0;
    background: var(--bg-card);
    border-top: 1px solid var(--divider);
}

.faq h2 {
    text-align: center;
    font-size: 1.5rem;
    font-weight: 700;
    margin-bottom: 36px;
    letter-spacing: -0.02em;
}

.faq-list {
    max-width: 680px;
    margin: 0 auto;
}

.faq-item {
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--bg-card);
    margin-bottom: var(--space-3);
    overflow: hidden;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.faq-item:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
}

.faq-question {
    width: 100%;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 18px var(--space-5);
    background: none;
    border: none;
    color: var(--text-primary);
    font-size: 0.95rem;
    font-weight: 600;
    cursor: pointer;
    text-align: left;
    font-family: inherit;
    line-height: 1.4;
    gap: var(--space-3);
}

.faq-question:hover {
    background: var(--blue-soft);
}

.faq-chevron {
    flex-shrink: 0;
    color: var(--text-secondary);
    transition: transform 0.2s ease;
}

.faq-item.open .faq-chevron {
    transform: rotate(180deg);
}

.faq-answer {
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.3s ease;
}

.faq-item.open .faq-answer {
    max-height: 400px;
}

.faq-answer p {
    padding: 0 var(--space-5) 18px;
    font-size: 0.9rem;
    color: var(--text-secondary);
    line-height: 1.6;
}

.faq-answer a {
    color: var(--blue-action);
    text-decoration: none;
    font-weight: 500;
}

.faq-answer a:hover {
    text-decoration: underline;
}

/* ── Founder blurb ── */
.founder-blurb {
    padding: 40px 0;
    text-align: center;
    background: var(--bg-card-2);
    border-top: 1px solid var(--divider);
}

.founder-text {
    max-width: 560px;
    margin: 0 auto;
    font-size: 0.95rem;
    color: var(--text-secondary);
    line-height: 1.7;
}

.founder-text strong {
    color: var(--text-primary);
}

/* ── Bottom CTA ── */
.bottom-cta {
    padding: 40px 0;
    text-align: center;
    background: var(--bg-card-2);
    border-top: 1px solid var(--divider);
}

.bottom-cta h2 {
    font-size: 1.8rem;
    font-weight: 700;
    margin-bottom: var(--space-3);
    letter-spacing: -0.02em;
}

.bottom-cta p {
    color: var(--text-secondary);
    margin-bottom: 32px;
    font-size: 1rem;
}

/* ── Footer (global) ── */
footer {
    padding: 32px 0;
    border-top: 1px solid var(--border);
    text-align: center;
}

footer p {
    font-size: 0.8rem;
    color: var(--text-secondary);
}

footer a {
    color: var(--text-secondary);
    text-decoration: none;
}

footer a:hover { color: var(--text-primary); }

/* ── Sections always visible — no scroll-reveal animation ──
   Previous scroll-reveal used opacity:0 on below-fold sections, which created
   empty dark space because invisible elements still occupy layout space.
   Removed entirely after recurring regressions (c8a4364, 4f06a6c). */
.fade-in-section {
    opacity: 1;
    transform: none;
}

/* ── Hero social-proof mini-badge ── */
.hero-proof {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    margin-top: var(--space-4);
    font-size: 0.82rem;
    color: var(--text-secondary);
}

.hero-proof-dot {
    width: 6px;
    height: 6px;
    background: var(--green-fg);
    border-radius: 50%;
    display: inline-block;
    animation: pulse-dot 2s ease-in-out infinite;
}

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

.hero-proof-count {
    color: var(--green-fg);
    font-weight: 600;
}

/* ── Landing responsive ── */
@media (max-width: 600px) {
    .hero { padding: 50px 0 40px; }

    .signup-form {
        flex-direction: column;
        gap: var(--space-4);
    }

    .signup-form input[type="email"],
    .signup-form input[type="text"],
    .btn-primary {
        width: 100%;
        max-width: none;
    }

    .signup-card {
        padding: var(--space-6) var(--space-5);
        margin: 0 auto;
    }

    .steps { flex-direction: column; align-items: center; }

    .proof-stats {
        grid-template-columns: repeat(2, 1fr);
    }

    .stat-number.dollar { font-size: 1.8rem; }
    .stats-bar-sep { margin: 0 var(--space-1); }
    .trust-signals { flex-direction: column; align-items: center; gap: var(--space-2); }

    .options-proof-grid {
        grid-template-columns: 1fr;
        max-width: 300px;
    }
}

@media (max-width: 480px) {
    .preview {
        border-top: 1px solid var(--divider);
    }
}

/* ── Drawer / Sheet primitive (story 17.32.5) ────────────────────────────
 * Right-side slide-in panel used by the Holdings row-click drawer. Aligns
 * with the existing .research-panel implementation in
 * templates/dashboard_live.html so the patterns can converge: future
 * drawers (options strategy detail, portfolio doctor drill-down) should
 * use these QDS classes instead of greenfielding parallel surfaces. The
 * visible state is toggled by adding .is-open (or via Alpine x-show on
 * the existing research-panel).
 */
.qds-drawer {
    position: fixed;
    top: 0;
    right: 0;
    width: 400px;
    max-width: 90vw;
    height: 100vh;
    background: var(--bg-page);
    border-left: 1px solid var(--border);
    z-index: 901;
    overflow-y: auto;
    box-shadow: -4px 0 24px rgba(0, 0, 0, 0.3);
    transform: translateX(100%);
    transition: transform 0.2s ease-out;
}
.qds-drawer.is-open { transform: translateX(0); }
.qds-drawer-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 900;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease-out;
}
.qds-drawer-overlay.is-open {
    opacity: 1;
    pointer-events: auto;
}
@media (max-width: 480px) {
    .qds-drawer { width: 100%; max-width: 100vw; }
}
