/* Should I Rip? — paper-and-ink theme.
   Tokens, primitives, and screens per the v15 Heatmaps handoff. */

/* ┌───────────────────────────────────────────────────────────────────────┐
   │ A11y rule — brand lime (#c8e84a) usage                                │
   │   Lime may be: (a) foreground text on a dark surface,                 │
   │                (b) a fill behind DARK text only,                      │
   │                (c) a thin accent — underline / dot / 1–2px outline.   │
   │   Lime must NEVER be a fill behind white/light text — fails WCAG     │
   │   ~1.2:1 and is illegible under red/green CVD. When using lime as a   │
   │   background, set color: var(--on-lime) (a theme-fixed near-black)    │
   │   to guarantee ≥4.5:1 in both light and dark mode.                    │
   │                                                                       │
   │   The same rule extends to every theme-fixed bright accent (e.g.      │
   │   --amber for the Grail chip): pair its fills with var(--on-lime),    │
   │   not var(--ink). --ink theme-flips to cream in dark mode and would   │
   │   produce the same ~1.5:1 failure.                                    │
   └───────────────────────────────────────────────────────────────────────┘ */

:root {
  /* Foundation */
  --paper:      #f7f1de;
  --paper-dim:  #ede5cb;
  --paper-warm: #fdf8e8;

  /* Ink */
  --ink:        #1a1612;
  --ink-soft:   #2e2820;
  --muted:      #6f6555;

  /* Accents */
  --lime:       #c8e84a;
  --lime-deep:  #5a7a18;
  --lime-soft:  #f2f7d4;
  /* Theme-fixed near-black for text that sits on a lime fill (both themes).
     Lime stays the same hex in dark mode, so its text color must too —
     using var(--ink) would flip to cream and fail contrast (1.2:1). */
  --on-lime:    #1a1612;

  --coral:      #ff6b6b;
  --coral-deep: #c33a3f;
  --coral-soft: #fde0de;

  --amber:      #f0b937;
  --amber-soft: #fae6b8;
  --amber-deep: #a37414;

  --sky:        #5db4d4;
  --sky-soft:   #d8ecf3;
  --sky-deep:   #2a7799;

  /* Measure — the cap on how long a line of text may get.
     `ch` is the advance width of "0". A MONOSPACE font makes every glyph
     that wide, so `78ch` there is a hard 78-character line; the same 78ch on
     a proportional font renders ~95 characters, because average glyph width
     sits well below the "0" width. One number therefore meant two different
     measures, which is how 17 hand-picked values (14/24/34/42/52/56/60/62/
     64/70/72/76/78/80/82/90/92ch) ended up scattered across 18 files with
     nothing keeping them consistent.
     Caps apply to CUSTOMER-FACING prose only — blog, hero, product pages —
     where a reader goes down 20+ consecutive lines and the return sweep to
     the next line compounds. ADMIN surfaces are deliberately uncapped: their
     notes run 2-4 lines, so there are one or two return sweeps to get wrong,
     and a second bound only made the note stop at half the width of the
     table it describes. The 1100px container is the bound there. */
  --measure-lede:  56ch;   /* prominent intro text — hero sub, taglines   */
  --measure-prose: 72ch;   /* standard body / page-head paragraphs (sans) */
  --measure-tight: 44ch;   /* captions and callouts inside cards          */

  /* Borders */
  --rule:       rgba(26, 22, 18, .10);
  --rule-soft:  rgba(26, 22, 18, .06);

  /* Tier chips. Every value clears 4.5:1 against the chip's fixed cream
     text (#f7f1de) so the chip stays readable when --paper flips to dark.
     The hues fan around the wheel so adjacent rows (silver/misc/bronze,
     emerald/lime, sapphire/special-series) are distinguishable. */
  --tier-ruby:           #c33a3f;  /*  4.65:1  red       */
  --tier-sapphire:       #3a6ab0;  /*  4.81:1  blue      */
  --tier-emerald:        #4f6b14;  /*  5.40:1  green     */
  --tier-gold:           #7a5d12;  /*  5.43:1  burnt gold (was #b3892a — 2.85:1) */
  --tier-diamond:        #8a4ab8;  /*  4.67:1  purple    */
  --tier-silver:         #525e6a;  /*  5.84:1  slate     */
  --tier-bronze:         #8a4f1a;  /*  5.77:1  warm brown */
  --tier-special-series: #1a6a78;  /*  5.50:1  teal      */
  --tier-misc:           #6f6555;  /*  5.08:1  muddy     */
  --tier-legendary:      #1a1612;  /* 15.64:1  near-black */
  /* Theme-fixed cream for chip text — must not flip with --paper, or chips
     go invisible on the darker tiers in dark mode (gold/emerald/legendary). */
  --tier-text:           #f7f1de;

  /* Type stack */
  --display: "Bricolage Grotesque", "Archivo", "Helvetica Neue", Helvetica, sans-serif;
  --sans:    "IBM Plex Sans", -apple-system, system-ui, sans-serif;
  --mono:    "IBM Plex Mono", "JetBrains Mono", ui-monospace, monospace;

  /* Radii */
  --radius-card:   10px;
  --radius-medium:  8px;
  --radius-small:   6px;
  --radius-chip:    4px;

  /* Shadows */
  --shadow-card:    0 1px 2px rgba(26, 22, 18, .04), 0 6px 18px rgba(26, 22, 18, .07);
  --shadow-card-sm: 0 1px 2px rgba(26, 22, 18, .04), 0 3px  8px rgba(26, 22, 18, .06);

  /* Layout */
  --max-width: 1440px;
  --page-pad:    32px;
  --card-border: 1.5px solid var(--ink);
}

*, *::before, *::after { box-sizing: border-box; }
html, body {
  margin: 0; padding: 0;
  background: var(--paper); color: var(--ink);
  font-family: var(--sans); font-weight: 500; line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; }
a:hover { text-decoration: underline; }
button { font: inherit; cursor: pointer; }
[data-tabular], .num, .mono { font-variant-numeric: tabular-nums; }

main { max-width: var(--max-width); margin: 0 auto; padding: 0; }

/* ── Top nav (sticky) ─────────────────────────────────────────────────── */
.topbar {
  position: sticky; top: 0; z-index: 10;
  background: var(--paper);
  border-bottom: var(--card-border);
}
.topbar-inner {
  max-width: var(--max-width); margin: 0 auto;
  padding: 16px var(--page-pad);
  display: flex; align-items: center; gap: 22px;
}
.brand {
  font-family: var(--display); font-weight: 800; font-size: 22px;
  letter-spacing: -0.6px; color: var(--ink);
  white-space: nowrap; flex-shrink: 0;
}
.brand:hover { text-decoration: none; }
.brand-q { color: var(--coral-deep); }
.navlinks {
  flex: 1; display: flex; gap: 22px; margin-left: 18px;
}
.navlinks a {
  font-family: var(--sans); font-size: 13px; font-weight: 500;
  color: var(--ink-soft); position: relative; padding-bottom: 4px;
}
.navlinks a.active { color: var(--ink); font-weight: 700; }
.navlinks a.active::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -20px;
  height: 3px; background: var(--lime);
}

/* ── Account menu (consolidates tier chip + account chip + theme toggle +
   sign-out into one popover). Hover-open on mouse devices, click-open on
   touch. Server-rendered <details>-style behavior built with a button +
   small JS toggle in dashboard.js. */
.account-menu { position: relative; }
.account-trigger {
  background: none; border: none; padding: 0; cursor: pointer;
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
}
.account-trigger:focus-visible { outline: 2px solid var(--lime-deep); outline-offset: 2px; }
.account-avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 50%;
  border: 1.5px solid var(--ink); background: var(--paper-warm); color: var(--ink);
  font: 700 14px var(--mono); letter-spacing: 0.5px;
  transition: background 120ms ease;
}
.account-trigger:hover .account-avatar { background: var(--paper-dim); }
.account-avatar-founding { background: var(--amber-soft); border-color: var(--amber-deep); color: var(--amber-deep); }
.account-avatar-pro      { background: var(--sky-soft);   border-color: var(--sky-deep);   color: var(--sky-deep); }

.account-popover {
  display: none; position: absolute; top: calc(100% + 8px); right: 0;
  min-width: 240px; z-index: 60;
  background: var(--paper-warm);
  border: 1.5px solid var(--ink); border-radius: var(--radius-medium);
  box-shadow: 0 8px 24px rgba(26, 22, 18, .14);
  padding: 8px 0;
}
/* Click-to-toggle only — hover-open was unreliable because of the 8px
   gap between trigger and popover (mouse leaves the hover area while
   crossing the gap, popover closes before you can interact). Touch
   devices were already click-only via the JS toggle. */
.account-menu:focus-within .account-popover,
.account-menu.is-open .account-popover { display: block; }

.account-popover-id {
  display: flex; flex-direction: column; gap: 6px;
  padding: 10px 14px 12px;
  border-bottom: 1px solid var(--rule);
}
.account-popover-email {
  font: 500 12px var(--mono); color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.account-popover-section { padding: 8px 6px; border-bottom: 1px solid var(--rule); }
.account-popover-section:last-child { border-bottom: none; }
.account-popover-label {
  display: block; padding: 4px 8px 6px;
  font: 600 10px var(--mono); text-transform: uppercase; letter-spacing: .12em;
  color: var(--muted);
}
.account-popover-link {
  display: block; width: 100%; box-sizing: border-box;
  padding: 8px 12px; border-radius: var(--radius-small);
  background: none; border: none; cursor: pointer; text-align: left;
  font: 500 13px var(--sans); color: var(--ink); text-decoration: none;
}
.account-popover-link:hover, .account-popover-link:focus-visible {
  background: var(--paper-dim); text-decoration: none;
}
.account-popover-danger { color: var(--coral-deep); }
.account-popover-form { margin: 0; padding: 0; }

/* Mobile hamburger — collapses the page nav (.navlinks) into a popover on
   small screens so the bar isn't crammed. Reuses the .account-menu toggle
   (dashboard.js handles every [data-account-menu]). Hidden on desktop. */
.nav-menu { display: none; }
/* Bare hamburger icon (no circle) — it sits on its own at the far left, so it
   doesn't need to mirror the bell/avatar buttons. The 36px box keeps the tap
   target and vertical centering. */
.nav-toggle-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; color: var(--ink);
}
.nav-toggle-icon svg { width: 20px; height: 20px; }
.account-trigger:hover .nav-toggle-icon { color: var(--ink-soft); }
/* Opens left-aligned under the hamburger (the account popover opens right). */
.nav-popover { left: 0; right: auto; min-width: 200px; }
.nav-popover a {
  display: block; padding: 9px 14px;
  font: 500 14px var(--sans); color: var(--ink); text-decoration: none;
}
.nav-popover a:hover, .nav-popover a:focus-visible { background: var(--paper-dim); }
.nav-popover a.active { font-weight: 700; color: var(--ink); }
@media (max-width: 640px) {
  .navlinks { display: none; }
  .nav-menu { display: flex; align-items: center; }
  /* Hamburger leads on the far left, then brand; the brand's auto margin
     pushes the account cluster (bell, avatar) to the right. */
  .brand { margin-right: auto; }
}

.theme-picker {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px;
  padding: 0 8px 4px;
}
.theme-pick {
  display: inline-flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 8px 4px; border-radius: var(--radius-small);
  background: var(--paper); border: 1.5px solid var(--rule); color: var(--ink-soft);
  font: 600 11px var(--mono); cursor: pointer;
}
.theme-pick:hover { background: var(--paper-dim); }
.theme-pick.is-on {
  background: var(--ink); color: var(--paper); border-color: var(--ink);
}

/* Phone-width header — keep the brand on one line and trim the padding,
   gaps, and right-side controls so all visible chrome fits in ~390px. */
@media (max-width: 480px) {
  .topbar-inner { gap: 10px; padding: 12px 14px; }
  .brand { font-size: 17px; letter-spacing: -0.3px; }
  .navlinks { gap: 14px; margin-left: 4px; }
  .navlinks a { font-size: 12px; }
  .freshness { display: none; }
  .signin-link { font-size: 12px; padding: 6px 10px; }
  .account-avatar { width: 32px; height: 32px; font-size: 13px; }
  .account-popover { right: -4px; min-width: 220px; }
}

/* Tablet portrait / iPad split-view tier — previously fell through into
   the desktop layout, which over-packs the header at 600-1024px. */
@media (min-width: 481px) and (max-width: 1024px) {
  .topbar-inner { gap: 14px; padding: 14px 20px; }
  .navlinks { margin-left: 8px; }
}

/* ── Buttons ──────────────────────────────────────────────────────────── */
.btn {
  display: inline-block; font-family: var(--sans); font-weight: 700;
  border-radius: var(--radius-small); padding: 9px 16px; font-size: 13px;
  background: var(--paper); color: var(--ink); border: var(--card-border);
  cursor: pointer;
}
.btn:hover { text-decoration: none; }
.btn.primary {
  background: var(--coral-deep); color: var(--paper); border: none;
}
.btn.primary:hover { background: #a8322e; }
.btn.primary.big { padding: 12px 22px; font-size: 15px; }
.btn.small {
  font-size: 12px; padding: 6px 12px; font-weight: 700;
  background: var(--paper); color: var(--ink); border: var(--card-border);
}
.btn.tertiary {
  background: var(--paper); color: var(--ink-soft);
  border: 1.5px solid var(--rule); font-family: var(--mono);
  font-size: 11px; letter-spacing: 0.5px; padding: 8px 14px;
}
.btn.sort-active {
  background: var(--paper-warm); border: var(--card-border);
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.5px;
  padding: 8px 14px; color: var(--ink); font-weight: 600;
}
.cta-row { display: flex; align-items: center; gap: 14px; margin: 22px 0; flex-wrap: wrap; }
.cta-note {
  font-family: var(--mono); font-size: 10.5px; color: var(--muted);
  letter-spacing: 0.4px;
}

/* ── Card primitive ───────────────────────────────────────────────────── */
.card {
  background: var(--paper-warm);
  border: var(--card-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: 18px 22px;
}
.card.flush { padding: 0; overflow: hidden; background: var(--paper); }
.card.legend { padding: 14px 22px; background: var(--paper-warm); }

/* ── Lbl (mono caption) ───────────────────────────────────────────────── */
.lbl {
  font-family: var(--mono); font-size: 11px; color: var(--muted);
  letter-spacing: 1.4px; text-transform: uppercase;
}

/* ── Tier chips ───────────────────────────────────────────────────────── */
.tier {
  display: inline-block; color: var(--tier-text);
  font-family: var(--sans); font-weight: 700;
  font-size: 10.5px; padding: 2px 8px; letter-spacing: 0.4px;
  text-transform: uppercase; border-radius: var(--radius-chip);
  background: var(--tier-misc);
}
.tier.lg { font-size: 14px; padding: 3px 10px; }
.tier-ruby           { background: var(--tier-ruby); }
.tier-sapphire       { background: var(--tier-sapphire); }
.tier-emerald        { background: var(--tier-emerald); }
.tier-gold           { background: var(--tier-gold); }
.tier-diamond        { background: var(--tier-diamond); }
.tier-silver         { background: var(--tier-silver); }
.tier-bronze         { background: var(--tier-bronze); }
.tier-special-series { background: var(--tier-special-series); }
.tier-misc           { background: var(--tier-misc); }
.tier-legendary      { background: var(--tier-legendary); }
/* Legendary in dark mode: bg matches the page (#1a1612 = dark --paper), so
   without a border the chip disappears. A thin gold outline marks it as
   "premium" and delineates it from the page bg. Inset shadow preserves
   dimensions (no layout shift vs. other chips). */
html[data-theme="dark"] .tier-legendary {
  box-shadow: inset 0 0 0 1px #b3892a;
}

/* ── Collect Safe dot indicator ──────────────────────────────────────────── */
.ss { display: inline-flex; align-items: center; gap: 7px;
      font-family: var(--mono); font-size: 12px; white-space: nowrap; }
.ss-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; }
.ss-buy   { color: var(--lime-deep); font-weight: 700; }
.ss-buy   .ss-dot { background: var(--lime-deep); }
.ss-lean  { color: var(--amber-deep); font-weight: 600; }
.ss-lean  .ss-dot { background: var(--amber); }
.ss-skip  { color: var(--muted); font-weight: 500; }
.ss-skip  .ss-dot { background: transparent; border: 1.5px solid var(--muted); }
.ss-avoid { color: var(--coral-deep); font-weight: 700; }
.ss-avoid .ss-dot { background: var(--coral-deep); }
.ss-muted { color: var(--muted); font-weight: 500; }
.ss-muted .ss-dot { background: transparent; border: 1.5px dashed var(--muted); }

/* ── Velocity words ───────────────────────────────────────────────────── */
.vel {
  font-family: var(--mono); font-size: 12px; font-weight: 600; letter-spacing: 0.3px;
}
.vel-hot     { color: var(--coral-deep); }
.vel-warm    { color: var(--amber-deep); }
.vel-cool    { color: var(--sky-deep); }
.vel-frozen  { color: var(--muted); }
.vel-unknown { color: var(--muted); }

/* Hot rail (coral dot in the first column of a hot row) */
.hot-rail {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  background: var(--coral-deep); box-shadow: 0 0 0 3px var(--coral-soft);
}

/* ── Mark + Strike (inline text effects) ──────────────────────────────── */
/* isolation+z-index:-1 keeps the bar behind text without needing an inner <span>. */
.mark { position: relative; display: inline-block; isolation: isolate; }
.mark::before {
  content: ""; position: absolute; left: -4px; right: -4px; bottom: 1px;
  height: 45%; background: var(--lime); z-index: -1;
}
.mark > span { position: relative; z-index: 1; }
.mark.mark-coral::before  { background: var(--coral-soft); }
.mark.mark-amber::before  { background: var(--amber-soft); }
.mark.mark-sky::before    { background: var(--sky-soft); }
/* Light mode: lime bar behind ink-soft text — 10.79:1. */
.mark.mark-lime::before   { background: var(--lime); }
/* Dark mode: text is cream, so a lime fill behind it fails contrast (~1.2:1).
   Convert the mark to a 2px lime underline accent — text reads on the dark
   page bg (≥10:1) and lime serves as a thin indicator per the a11y rule. */
html[data-theme="dark"] .mark.mark-lime::before {
  height: 2px; bottom: -2px; left: 0; right: 0; background: var(--lime);
}
/* Dark CTAs (signup/final) keep the original fill: their text is always
   cream (the strips are pinned to a dark surface in both themes — see the
   token-scoping override below). paper-on-lime-deep is 4.39:1, which clears
   3:1 for the bold display headings (WCAG large text). */
.signup-cta .mark.mark-lime::before,
.final-cta  .mark.mark-lime::before { background: var(--lime-deep); }
/* Re-assert geometry/fill for marks inside the inverted CTAs in dark mode
   so the general dark-mode underline override above doesn't reach in. */
html[data-theme="dark"] .signup-cta .mark.mark-lime::before,
html[data-theme="dark"] .final-cta  .mark.mark-lime::before {
  background: var(--lime-deep);
  height: 45%; bottom: 1px; left: -4px; right: -4px;
}

.strike { position: relative; display: inline-block; color: var(--muted); opacity: 0.6; }
.strike::before {
  content: ""; position: absolute; left: 0; right: 0; top: 50%;
  height: 2px; background: var(--coral-deep);
  transform: rotate(-2deg) translateY(-50%); z-index: 1;
}

/* ── Shape (mini histogram, inline SVG) ───────────────────────────────── */
.shape-mini { display: block; width: 64px; height: 22px; }

/* ── Headings ─────────────────────────────────────────────────────────── */
h1 {
  font-family: var(--display); font-weight: 800; font-size: 36px;
  letter-spacing: -1.2px; line-height: 1; color: var(--ink); margin: 0;
}
h2 {
  font-family: var(--display); font-weight: 800; font-size: 28px;
  letter-spacing: -0.8px; line-height: 1; color: var(--ink); margin: 0;
}
h3 {
  font-family: var(--display); font-weight: 700; font-size: 18px;
  letter-spacing: -0.3px; line-height: 1.1; color: var(--ink); margin: 0;
}
.muted    { color: var(--muted); }
.positive { color: var(--lime-deep); }
.negative { color: var(--coral-deep); }
.right    { text-align: right; }
.center   { text-align: center; }
.small    { font-size: 12px; }

/* ── Hero (overview) ──────────────────────────────────────────────────── */
.hero {
  max-width: var(--max-width); margin: 0 auto;
  padding: 40px var(--page-pad) 24px;
}
.hero-headline {
  font-family: var(--display); font-weight: 800; font-size: 56px;
  letter-spacing: -2px; line-height: 1.02; color: var(--ink);
  max-width: 1100px;
}
.hero-sub {
  font-family: var(--sans); font-size: 17px; color: var(--ink-soft);
  margin-top: 18px; max-width: 820px; line-height: 1.5;
}
.hero-sub .coral { color: var(--coral-deep); font-weight: 700; }
.stat-grid-3 {
  margin-top: 28px;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px;
}
@media (max-width: 900px) { .stat-grid-3 { grid-template-columns: 1fr; } }
.stat-big {
  font-family: var(--display); font-weight: 800; font-size: 44px;
  font-variant-numeric: tabular-nums; letter-spacing: -1px; line-height: 1;
  color: var(--ink);
}
.stat-big.positive { color: var(--lime-deep); }
.stat-big.negative { color: var(--coral-deep); }
.stat-big .fraction { color: var(--muted); font-weight: 700; }
.stat-sub { font-family: var(--sans); font-size: 13px; color: var(--muted); margin-top: 4px; }

/* ── Trajectory chart card (hero) ─────────────────────────────────────── */
.trajectory-card { margin-top: 24px; padding: 20px 22px; background: var(--paper-warm); }
.trajectory-head {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: 14px; gap: 12px; flex-wrap: wrap;
}
.trajectory-legend {
  display: flex; align-items: center; gap: 8px;
  font-family: var(--mono); font-size: 11px; color: var(--ink-soft);
}
.trajectory-legend .swatch {
  width: 12px; height: 12px; background: var(--lime-soft);
  border: 1.5px solid var(--lime-deep); border-radius: 2px;
}
.trajectory-svg-wrap { position: relative; height: 260px; }
.trajectory-svg { display: block; width: 100%; height: 100%; }
/* Invisible-by-default hover targets at each chart bucket; the native SVG
   <title> shows the date/EV/top-pack tooltip. Faint visual cue on hover so
   users know the chart is interactive. */
.trajectory-hover { cursor: help; transition: fill 120ms ease; }
.trajectory-hover:hover { fill: rgba(90, 122, 24, 0.18); }
.trajectory-caption {
  font-family: var(--sans); font-size: 12.5px; color: var(--ink-soft);
  margin-top: 12px; line-height: 1.5; max-width: 920px;
}

/* ── Section / page H1 row ────────────────────────────────────────────── */
.section { max-width: var(--max-width); margin: 0 auto; padding: 32px var(--page-pad) 24px; }
.section-head {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: 14px; gap: 16px; flex-wrap: wrap;
}
.section-head .lede {
  font-family: var(--sans); font-size: 13px; color: var(--ink-soft);
  margin-top: 8px; max-width: 800px; line-height: 1.5;
}
.section-actions { display: flex; gap: 6px; }

/* ── Packs table (13-column grid) ─────────────────────────────────────── */
.packs-grid-cols {
  grid-template-columns: 24px 1.5fr .7fr .55fr .55fr .7fr .55fr .55fr .55fr .55fr .8fr .9fr .9fr;
}
.packs-head {
  display: grid; gap: 0; padding: 12px 18px;
  background: var(--paper-dim); border-bottom: var(--card-border);
  font-family: var(--mono); font-size: 10px; letter-spacing: 1.4px;
  color: var(--muted); text-transform: uppercase; align-items: center;
}
.packs-head a { color: var(--muted); }
.packs-head a:hover { color: var(--ink); text-decoration: none; }
.packs-head .right { text-align: right; padding-right: 8px; }
.packs-row {
  display: grid; gap: 0; padding: 14px 18px; align-items: center;
  font-size: 13.5px; font-variant-numeric: tabular-nums; position: relative;
  border-bottom: 1px solid var(--rule-soft);
}
.packs-row:last-child { border-bottom: none; }
.packs-row.zebra { background: rgba(26, 22, 18, .015); }
.packs-row:hover { background: rgba(26, 22, 18, .04); }
.packs-row .pack-name {
  font-family: var(--display); font-weight: 700; font-size: 15px;
  letter-spacing: -0.2px; color: var(--ink);
}
.packs-row .pack-name a { color: var(--ink); }
.packs-row .price { text-align: right; padding-right: 8px;
                    font-family: var(--mono); color: var(--ink-soft); }
.packs-row .polls {
  font-family: var(--mono); font-size: 11.5px; color: var(--muted);
}
.packs-row .polls .ink-soft { color: var(--ink-soft); }

/* Heatmap cells — bleed vertical padding into row */
.hcell {
  text-align: right; padding-right: 8px;
  padding-top: 6px; padding-bottom: 6px; margin: -6px 0;
}
.hcell-ev   { font-family: var(--display); font-weight: 700; letter-spacing: -0.2px; }
.hcell-max  { font-family: var(--mono); font-weight: 600; }
.hcell-p2x  { font-family: var(--mono); }
.hcell-p10x { font-family: var(--mono); }
.hcell-vp   { font-family: var(--mono); font-weight: 600; }
.hcell-p    { font-family: var(--mono); }
.hcell-evc  { font-family: var(--mono); }

/* Legend (under packs table) */
.legend-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px;
  font-family: var(--sans); font-size: 12.5px; color: var(--ink-soft);
  line-height: 1.45;
}
@media (max-width: 900px) { .legend-grid { grid-template-columns: repeat(2, 1fr); } }
.legend-swatch {
  display: inline-block; padding: 2px 8px;
  font-family: var(--mono); font-weight: 700;
}
.legend-note { margin-top: 6px; color: var(--muted); font-size: 11.5px; }

/* ── Pack detail header ───────────────────────────────────────────────── */
.breadcrumb {
  display: flex; align-items: center; gap: 10px; margin-bottom: 14px;
  font-family: var(--mono); font-size: 12px; color: var(--muted);
  letter-spacing: 0.4px;
}
.breadcrumb a { color: var(--muted); }
.breadcrumb .here { color: var(--ink); }

.pack-hero {
  display: flex; align-items: baseline; gap: 16px; flex-wrap: wrap;
}
.pack-name-big {
  font-family: var(--display); font-weight: 800; font-size: 56px;
  letter-spacing: -2px; line-height: 1; color: var(--ink);
}
.pack-price-big {
  font-family: var(--display); font-weight: 700; font-size: 24px;
  color: var(--ink-soft);
}
.pack-velocity-pill {
  font-family: var(--mono); font-size: 11px; font-weight: 700;
  letter-spacing: 0.4px;
}
.pack-hero-right {
  margin-left: auto;
  display: flex; flex-direction: column; align-items: flex-end; gap: 4px;
}
.pack-image-small {
  max-width: 120px; max-height: 120px; border-radius: 4px;
  border: var(--card-border); margin-left: auto;
}

/* Six heatmapped stat tiles */
.stat-grid-6 {
  margin-top: 22px;
  display: grid; grid-template-columns: repeat(6, 1fr); gap: 12px;
}
@media (max-width: 1100px) { .stat-grid-6 { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 700px)  { .stat-grid-6 { grid-template-columns: repeat(2, 1fr); } }
.stat-tile {
  border: var(--card-border); border-radius: var(--radius-card);
  padding: 14px 16px;
}
.stat-tile-value {
  font-family: var(--display); font-weight: 800; font-size: 32px;
  font-variant-numeric: tabular-nums; letter-spacing: -0.8px;
  margin-top: 4px; line-height: 1;
}
.stat-tile-sub {
  font-family: var(--mono); font-size: 11px; color: var(--ink-soft);
  margin-top: 2px;
}

/* Two-card rows used twice on the detail page */
.row-2up { margin-top: 16px; display: grid; grid-template-columns: 1.4fr 1fr; gap: 16px; }
@media (max-width: 900px) { .row-2up { grid-template-columns: 1fr; } }

/* Crossings list inside a card */
.crossings-list { margin-top: 8px; display: flex; flex-direction: column; }
.crossings-list .row {
  display: flex; justify-content: space-between; padding: 7px 0;
  border-bottom: 1px solid var(--rule-soft);
  font-family: var(--mono); font-size: 12px;
}
.crossings-list .row .when  { color: var(--muted); }
.crossings-list .row .delta { color: var(--lime-deep); font-weight: 700; }

/* Collect Safe verdict card body */
.verdict-body {
  font-family: var(--sans); font-size: 13.5px; color: var(--ink-soft);
  margin-top: 8px; line-height: 1.5;
}
.verdict-body strong { color: var(--ink); font-weight: 600; }
.verdict-head {
  display: flex; align-items: baseline; gap: 12px; margin-top: 6px;
}
.verdict-state {
  font-family: var(--display); font-weight: 800; font-size: 22px;
}
.verdict-state.buy   { color: var(--lime-deep); }
.verdict-state.lean  { color: var(--amber-deep); }
.verdict-state.skip  { color: var(--muted); }
.verdict-state.avoid { color: var(--coral-deep); }

/* Pool composition histogram (big) */
.shape-big-wrap { display: block; }
.shape-big-svg  { display: block; width: 100%; height: 246px; }
.shape-intro {
  font-family: var(--sans); font-size: 12.5px; color: var(--ink-soft);
  line-height: 1.45; margin-bottom: 14px; max-width: 640px;
}
.shape-intro .negative { font-weight: 600; }
.shape-intro .positive { font-weight: 600; }
.shape-intro .amber-text { color: var(--amber-deep); font-weight: 600; }
/* Pool-composition header: title + Collect Safe verdict chip, so the chart card
   reads as a self-contained "should I rip?" story when screenshotted. */
.pool-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.pool-verdict-chip { font-family: var(--mono); font-size: 11px; font-weight: 700; padding: 3px 10px; border-radius: 999px; border: 1.5px solid currentColor; }
.shape-legend { font-size: 11.5px; color: var(--muted); margin-bottom: 10px; }

/* EV trajectory (detail) */
.ev-traj-intro {
  font-family: var(--sans); font-size: 12.5px; color: var(--ink-soft);
}
.ev-traj-svg { display: block; width: 100%; height: 160px; margin-top: 12px; }

/* ── Card pool table ──────────────────────────────────────────────────── */
.pool-grid-cols {
  grid-template-columns: 32px 2.6fr 1.4fr .8fr .8fr .8fr .8fr .8fr .55fr .55fr;
}
/* Scoped to .pool-grid-cols so these table styles don't leak onto the
   "Pool composition" card head (a plain .pool-head that's a flex row — see
   above). Without the scope they overrode it into a grid + dim bar, colliding
   the label with the CS Trigger chip. */
.pool-head.pool-grid-cols, .pool-row {
  display: grid; gap: 0; padding: 12px 18px; align-items: center;
}
.pool-head.pool-grid-cols {
  background: var(--paper-dim); border-bottom: var(--card-border);
  font-family: var(--mono); font-size: 10px; letter-spacing: 1.4px;
  color: var(--muted); text-transform: uppercase;
}
.pool-head a { color: var(--muted); }
.pool-head a:hover { color: var(--ink); text-decoration: none; }
.pool-head .right { text-align: right; }
.pool-row {
  font-size: 13.5px; font-variant-numeric: tabular-nums;
  border-bottom: 1px solid var(--rule-soft);
}
.pool-row:last-child { border-bottom: none; }
.pool-row .idx { font-family: var(--mono); color: var(--muted); font-size: 11.5px; }
.pool-row .card-name-cell { display: flex; align-items: center; gap: 8px; min-width: 0; }
.pool-row .card-name { font-family: var(--sans); font-weight: 600; color: var(--ink); }
.pool-row .set-cell  { font-family: var(--sans); font-size: 12.5px; color: var(--muted); display: flex; align-items: baseline; min-width: 0; overflow: hidden; }
/* The set·grade text truncates in its own span, so a long set name can't
   swallow the trailing admin links (cert ↗ / fix ↗ / ✓ comped) — those are
   flex-none siblings and stay visible at any column width. Also matched
   inside the v2/v3 skins' .v2-set (their rows carry .pool-row too). */
.pool-row .set-text {
  display: block; flex: 0 1 auto; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pool-row .grade-cell {
  font-family: var(--mono); font-size: 11.5px; color: var(--muted);
}
.pool-row .val {
  text-align: right; font-family: var(--mono);
  color: var(--ink); font-weight: 700; padding-right: 4px;
}
.pool-row .offer {
  text-align: right; font-family: var(--mono); color: var(--ink-soft); padding-right: 4px;
}
.pool-row .added {
  text-align: right; font-family: var(--mono); font-size: 11.5px; color: var(--muted);
}
.grail-chip {
  font-family: var(--sans); font-size: 10px; font-weight: 700;
  /* --amber is theme-fixed (same hex in both themes), so its text must be
     too. var(--ink) would flip to cream in dark mode → ~1.6:1. Theme-fixed
     near-black on amber gives 8.85:1. */
  background: var(--amber); color: var(--on-lime);
  padding: 2px 7px; border-radius: 3px; letter-spacing: 0.5px;
  text-transform: uppercase;
}

/* Customer label chips, same family as .grail-chip above. Every filled chip
   repeats grail's pairing discipline: the fill is theme-fixed or near-fixed,
   so its text color must be theme-fixed too (var(--ink) flips to cream in dark
   mode and fails contrast on a light fill).

   Prominence deliberately descends — Grail/Chase (which tier the card is in) >
   1 of 1 (rarest possible claim) > Pop 1 > "No Market Comps Found", which is a
   disclosure rather than a badge and is styled quietest on purpose: it should
   read as an explanation of a missing number, never as a brag. */
.chase-chip {
  font-family: var(--sans); font-size: 10px; font-weight: 700;
  /* Sky is the established public Chase color (.ticker-evchip-chase); both
     themes' --sky are light enough for the same fixed near-black text. */
  background: var(--sky); color: var(--on-lime);
  padding: 2px 7px; border-radius: 3px; letter-spacing: 0.5px;
  text-transform: uppercase;
}
.oneofone-chip {
  font-family: var(--sans); font-size: 10px; font-weight: 700;
  /* Near-black fill + theme-fixed cream: the one chip that outranks Grail,
     and the only pairing that stays 15:1 in both themes (matches the
     legendary tier chip, which is the same "nothing above this" idea). */
  background: var(--tier-legendary); color: var(--tier-text);
  padding: 2px 7px; border-radius: 3px; letter-spacing: 0.5px;
  text-transform: uppercase; white-space: nowrap;
}
.popone-chip {
  font-family: var(--sans); font-size: 10px; font-weight: 700;
  /* One step down from 1 of 1: soft fill, not a solid slab. --sky-soft is
     translucent over the theme paper and --sky-deep re-derives per theme, so
     the pair holds contrast in light AND dark. */
  background: var(--sky-soft); color: var(--sky-deep);
  border: 1px solid var(--sky-deep);
  padding: 1px 6px; border-radius: 3px; letter-spacing: 0.5px;
  text-transform: uppercase; white-space: nowrap;
}
.nomarket-chip {
  font-family: var(--sans); font-size: 10px; font-weight: 600;
  /* Quietest of the set: muted outline, no fill, no uppercase — a sentence
     fragment explaining an absence, not a label competing with the tier
     chips. --muted re-derives per theme and clears 4.5:1 on both papers. */
  background: transparent; color: var(--muted);
  border: 1px solid var(--rule);
  padding: 1px 6px; border-radius: 3px; letter-spacing: 0.2px;
  white-space: nowrap;
}

/* Admin-only pack-inspection overlay (rendered only for user.is_admin — see
   _render_pack_detail). Outlined/soft, not filled, so the chips read as
   diagnostic markers next to the customer-styled Grail chip. Severity ramp:
   coral outline (no comps — market silent) > amber soft-fill (due — comp
   overdue) > amber outline (est — interpolated, loop will get there). */
.nocomp-chip {
  font-family: var(--sans); font-size: 10px; font-weight: 700;
  background: transparent; color: var(--coral-deep);
  border: 1px solid currentColor;
  padding: 1px 6px; border-radius: 3px; letter-spacing: 0.5px;
  text-transform: uppercase; white-space: nowrap;
}
.interp-chip {
  font-family: var(--sans); font-size: 10px; font-weight: 700;
  background: transparent; color: var(--amber-deep);
  border: 1px solid currentColor;
  padding: 1px 6px; border-radius: 3px; letter-spacing: 0.5px;
  text-transform: uppercase; white-space: nowrap;
}
.due-chip {
  font-family: var(--sans); font-size: 10px; font-weight: 700;
  /* --amber-soft is translucent over the theme paper and --amber-deep is
     re-derived per theme, so this pairing holds contrast in light AND dark. */
  background: var(--amber-soft); color: var(--amber-deep);
  border: 1px solid var(--amber-deep);
  padding: 1px 6px; border-radius: 3px; letter-spacing: 0.5px;
  text-transform: uppercase; white-space: nowrap;
}
.frozen-chip {
  font-family: var(--sans); font-size: 10px; font-weight: 700;
  /* Informational, not a problem state — sits OUTSIDE the severity ramp above:
     a frozen 1/1 means value updates stopped on purpose, so it gets the calm
     sky outline, not coral/amber. */
  background: transparent; color: var(--sky-deep);
  border: 1px solid currentColor;
  padding: 1px 6px; border-radius: 3px; letter-spacing: 0.5px;
  text-transform: uppercase; white-space: nowrap;
}
.adm-cert-link {
  font-family: var(--mono); font-size: 11px; color: var(--muted);
  text-decoration: none; white-space: nowrap; margin-left: 4px; flex: none;
}
.adm-cert-link:hover { color: var(--ink); text-decoration: underline; }
.adm-comped {
  font-family: var(--mono); font-size: 11px; color: var(--muted);
  white-space: nowrap; margin-left: 4px; flex: none;
}
/* Phone copy of the fix ↗ link, riding the always-visible card-name cell —
   the set-cell copy lives in a column that's hidden (classic collapse,
   v2/v3 skins) or off-by-default (v4 Columns picker) ≤760px. Revealed only
   by the phone media block below; desktop keeps the set-cell copy. */
.adm-fix-mobile { display: none; }
@media (max-width: 760px) {
  /* Bigger tap target than the 11px desktop link — this one is for thumbs. */
  .card-name-cell .adm-fix-mobile { display: inline-block; font-size: 12px; padding: 3px 6px; margin: -3px 0; }
  /* Name + Grail/admin chips + fix ↗ can exceed the narrow card track;
     wrap inside the cell rather than overflow into the set column. */
  .card-name-cell { flex-wrap: wrap; row-gap: 2px; }
  /* Phones: the set column (when shown at all) drops its admin tail — the
     name-cell fix ↗ above is the tap target, and 110px of set column
     shouldn't be spent on links that overflow into the Value column. */
  .set-cell .adm-cert-link, .set-cell .adm-comped,
  .v2-set .adm-cert-link, .v2-set .adm-comped { display: none; }
  /* The "your hits" panel and the live-activity feed carry their own fix ↗ —
     both stay visible on phones (unlike the set-cell copy above), because
     ripping happens on a phone and these are the rows you're ripping. Same
     thumb-sized treatment as the name-cell copy. */
  .mph-item .adm-cert-link,
  .activity-when .adm-cert-link,
  .v2-feed-when .adm-cert-link {
    display: inline-block; font-size: 12px; padding: 3px 6px; margin: -3px 0 -3px 4px;
  }
}

/* Sum row at bottom of card pool */
.pool-sum {
  display: grid; gap: 0; padding: 14px 18px;
  background: var(--paper-warm); border-top: var(--card-border);
  font-family: var(--mono); font-size: 13px;
  font-variant-numeric: tabular-nums; align-items: center;
}
.pool-sum .label { grid-column: 1 / 9; text-align: right; color: var(--muted); padding-right: 8px; }
.pool-sum .value { text-align: right; color: var(--lime-deep); font-weight: 700; padding-right: 8px; }

/* ── Footer ───────────────────────────────────────────────────────────── */
footer {
  border-top: var(--card-border);
  margin-top: 40px;
  background: var(--paper-dim);
}
.footer-inner {
  max-width: var(--max-width); margin: 0 auto;
  padding: 24px var(--page-pad);
  display: flex; justify-content: space-between; align-items: center;
  gap: 16px; flex-wrap: wrap;
}
.footer-brand {
  font-family: var(--display); font-weight: 800; font-size: 16px;
  letter-spacing: -0.4px; color: var(--ink);
}
.footer-domain {
  font-family: var(--mono); font-size: 11.5px; color: var(--muted);
  margin-left: 12px; letter-spacing: 0.4px;
}
.footer-tagline {
  font-family: var(--mono); font-size: 11px; color: var(--muted);
  letter-spacing: 0.4px;
}
.footer-disclaimer {
  max-width: var(--max-width); margin: 0 auto;
  padding: 0 var(--page-pad) 24px;
  font-family: var(--sans); font-size: 11px; color: var(--muted);
  line-height: 1.6; max-width: 900px;
}
.footer-copyright {
  margin-top: 10px;
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.4px;
}

/* ── Prose (about, alerts) ────────────────────────────────────────────── */
.prose {
  max-width: 760px; margin: 0 auto;
  padding: 40px var(--page-pad);
  font-family: var(--sans); font-size: 15px; color: var(--ink-soft);
  line-height: 1.55;
}
.prose h1 { font-size: 36px; margin-bottom: 18px; }
.prose h2 { font-size: 22px; margin: 30px 0 10px; letter-spacing: -0.4px; }
.prose p { margin: 12px 0; }
.prose ul { padding-left: 20px; }
.prose li { margin: 6px 0; }
.prose strong { color: var(--ink); }
.prose .formula {
  font-family: var(--mono); font-size: 13px;
  background: var(--paper-warm); padding: 10px 14px;
  border-radius: 4px; border-left: 3px solid var(--lime-deep);
  color: var(--ink);
}

/* ── Perf panel (paper/ink restyle, structure unchanged) ──────────────── */
.perf-panel {
  margin: 24px auto 18px; max-width: var(--max-width);
  border: var(--card-border); border-radius: var(--radius-medium);
  background: var(--paper-warm); font-size: 12px; color: var(--ink);
}
.perf-panel > summary {
  list-style: none; cursor: pointer; padding: 10px 18px;
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 12px;
  user-select: none; color: var(--ink-soft);
}
.perf-panel > summary::-webkit-details-marker { display: none; }
.perf-panel > summary::before {
  content: "▸"; display: inline-block; width: 12px;
  color: var(--muted); transition: transform 0.15s;
}
.perf-panel[open] > summary::before { transform: rotate(90deg); }
.perf-summary-label { font-weight: 700; color: var(--ink); font-family: var(--display); letter-spacing: -0.2px; }
.perf-summary-stats { color: var(--muted); font-family: var(--mono); }
.perf-summary-stats code {
  background: var(--paper-dim); padding: 1px 6px; border-radius: 3px;
  color: var(--ink); font-family: var(--mono);
}
.perf-summary-stats strong { color: var(--ink); font-variant-numeric: tabular-nums; }
.perf-hide { color: var(--muted); font-size: 11px; }
.perf-hide:hover { color: var(--coral-deep); }

.perf-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 18px;
  padding: 4px 18px 18px;
}
@media (max-width: 760px) { .perf-grid { grid-template-columns: 1fr; } }
.perf-block h4 {
  margin: 8px 0; font-family: var(--mono); font-size: 11px;
  text-transform: uppercase; letter-spacing: 1.4px;
  color: var(--muted); font-weight: 600;
}
.perf-note {
  text-transform: none; letter-spacing: 0; font-weight: 400;
  color: var(--muted); font-size: 11px; margin-left: 6px;
  font-family: var(--mono);
}
.perf-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.perf-table th, .perf-table td {
  padding: 5px 8px; border-bottom: 1px solid var(--rule-soft);
  text-align: left; vertical-align: middle;
}
.perf-table th { color: var(--muted); font-weight: 500; font-size: 11px; font-family: var(--mono); }
.perf-table td.right, .perf-table th.right { text-align: right; }
.perf-table tfoot td { border-bottom: none; border-top: var(--card-border); padding-top: 8px; }
.perf-table .mono { font-variant-numeric: tabular-nums; font-family: var(--mono); }
.perf-bar-cell { width: 30%; }
.perf-bar {
  display: block; height: 6px; border-radius: 3px;
  background: var(--lime); min-width: 1px;
}
.perf-slowest td { background: var(--coral-soft); }
.perf-slowest .perf-bar { background: var(--coral-deep); }
.perf-flag {
  display: inline-block; margin-left: 6px; padding: 1px 6px;
  border-radius: 3px; font-size: 10px;
  background: var(--coral-soft); color: var(--coral-deep);
  font-family: var(--mono); text-transform: uppercase; letter-spacing: 0.05em;
}
.perf-hint { color: var(--muted); font-size: 11px; margin: 10px 0 0; line-height: 1.5; }

/* ── Auth UI (M1) ─────────────────────────────────────────────────────── */
.signin-link {
  display: inline-flex; align-items: center;
  padding: 7px 12px; border: 1.5px solid var(--ink);
  border-radius: var(--radius-medium);
  background: var(--paper); color: var(--ink);
  font: 600 13px var(--sans); cursor: pointer;
  transition: background 120ms ease, transform 120ms ease;
}
.signin-link:hover, .signin-link:focus-visible {
  background: var(--ink); color: var(--paper); text-decoration: none;
}
.signout-form { display: inline; margin: 0; padding: 0; }

/* Tier chip in topbar */
.tier-chip {
  display: inline-flex; align-items: center;
  padding: 4px 10px; border-radius: 999px;
  font-family: var(--mono); font-size: 11px;
  font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;
  border: 1.5px solid var(--ink);
  background: var(--paper); color: var(--ink-soft);
}
.tier-chip-pro      { background: var(--sky-soft);   border-color: var(--sky-deep);   color: var(--sky-deep); }
.tier-chip-founding { background: var(--amber-soft); border-color: var(--amber-deep); color: var(--amber-deep); }

/* Legal pages */
.legal-page { max-width: 720px; margin: 32px auto 80px; padding: 0 var(--page-pad); }
.legal-eyebrow {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 10px;
}
.legal-page h1 {
  font-family: var(--display); font-weight: 800; font-size: 36px;
  letter-spacing: -0.8px; margin: 0 0 12px; color: var(--ink);
}
.legal-page h2 {
  font-family: var(--display); font-weight: 700; font-size: 20px;
  margin-top: 28px; margin-bottom: 6px; color: var(--ink);
}
.legal-page .lede { color: var(--ink-soft); font-size: 16px; }
.legal-page p { color: var(--ink-soft); line-height: 1.6; }
.legal-page ul { padding-left: 22px; }
.legal-page li { margin: 6px 0; color: var(--ink-soft); }
.legal-page a { color: var(--lime-deep); text-decoration: underline; }
.legal-page .small { font-family: var(--mono); font-size: 11px; }

/* Legal/policy tables (data-collected, sub-processors, CCPA, etc.). Thin
   ruled grid; cells wrap long content (e.g. provider URLs) instead of forcing
   a column wide. */
.legal-page table {
  width: 100%; border-collapse: collapse;
  margin: 14px 0 22px; font-size: 13px;
}
.legal-page th, .legal-page td {
  border: 1px solid var(--rule); padding: 8px 10px;
  text-align: left; vertical-align: top;
  color: var(--ink-soft); line-height: 1.5; overflow-wrap: anywhere;
}
.legal-page th {
  font-weight: 700; color: var(--ink); background: var(--paper-dim);
}
/* Sub-processor table: fixed layout so "Data Received" gets the room it needs
   and the long links wrap into their column instead of starving it. */
.legal-page table.subproc { table-layout: fixed; }
.legal-page table.subproc th:nth-child(1), .legal-page table.subproc td:nth-child(1) { width: 13%; }
.legal-page table.subproc th:nth-child(2), .legal-page table.subproc td:nth-child(2) { width: 16%; }
.legal-page table.subproc th:nth-child(3), .legal-page table.subproc td:nth-child(3) { width: 36%; }
.legal-page table.subproc th:nth-child(4), .legal-page table.subproc td:nth-child(4) { width: 14%; }
.legal-page table.subproc th:nth-child(5), .legal-page table.subproc td:nth-child(5) { width: 21%; }

/* ── Homepage hook (state-aware hero) ─────────────────────────────────── */
/* The dynamic, state-aware hook IS the hero. The brand-promise tagline
   sits below as supporting copy. Three states tint the headline accent:
     positive_now → lime (good news, act fast)
     recent       → ink  (matter-of-fact, missed opportunity)
     bleak        → coral (negative-market state)
   Card padding is generous so the hook reads as the page's anchor. */
.hook {
  margin: 8px 0 14px;
  padding: 0;
  background: transparent;
  border: none;
  box-shadow: none;
}
.hook-headline {
  font-family: var(--display);
  font-weight: 800;
  font-size: 56px;
  line-height: 1.05;
  letter-spacing: -1.4px;
  color: var(--ink);
  margin: 0 0 14px;
  max-width: 14ch;       /* keeps the headline tight; wraps at the right beat */
}
.hook-headline .mark { white-space: nowrap; }
.hook-headline .hook-qmark {
  display: block;
  color: var(--ink-soft);
  font-weight: 700;
  margin-top: 4px;
}
.hook-sub {
  color: var(--ink-soft);
  font-size: 19px;
  line-height: 1.45;
  margin: 0 0 22px;
  max-width: var(--measure-lede);
}
.hook-cta-row {
  display: flex; flex-wrap: wrap; gap: 14px; align-items: center;
  margin-bottom: 8px;
}
.hook-cta-row .btn.primary.big {
  padding: 14px 26px; font-size: 15px;
}
.hook-fine {
  font-family: var(--mono); font-size: 12px; color: var(--muted);
}
.hook-fine-link {
  font-family: var(--mono); font-size: 13px; color: var(--lime-deep);
  text-decoration: underline; margin-left: 8px;
}
.hook-signedin {
  color: var(--ink-soft); font-size: 15px;
  padding: 12px 16px; max-width: var(--measure-lede);
  background: var(--paper-warm);
  border: 1.5px solid var(--rule);
  border-radius: var(--radius-medium);
}

.hero-tagline {
  margin: 28px 0 18px;
  max-width: var(--measure-lede);
  color: var(--muted);
  font-size: 14px;
  font-style: italic;
  line-height: 1.5;
}
.hero-tagline .strike {
  position: relative;
  color: var(--muted);
}
.hero-tagline .strike::after {
  content: ""; position: absolute; left: -2px; right: -2px; top: 50%;
  border-top: 1.5px solid var(--coral-deep);
  transform: rotate(-2deg);
}

@media (max-width: 720px) {
  .hook-headline { font-size: 38px; letter-spacing: -0.8px; max-width: none; }
  .hook-sub { font-size: 16px; }
  .hook-cta-row { flex-direction: column; align-items: flex-start; gap: 10px; }
  .hook-cta-row .btn.primary.big { width: 100%; text-align: center; justify-content: center; }
}

/* ───────────────────────────────────────────────────────────────────────
   Homepage v3 — Apple-IAP free-only funnel.
   Mirrors design_handoff_homepage_paywall/sir-paywall.jsx. Big hook,
   Tufte stats, anonymized watchlist preview, FAQ, dark CTA strips.
   ─────────────────────────────────────────────────────────────────────── */

/* ── Nav: live +EV counter chip (clickable; jumps to the live row) ───── */
.nav-live {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--mono); font-size: 11px; font-weight: 700;
  color: var(--lime-deep); letter-spacing: 0.5px;
  padding: 5px 9px; border-radius: 999px;
  border: 1.5px solid transparent;
  text-decoration: none;
  transition: background 120ms ease, border-color 120ms ease;
}
.nav-live-label { display: flex; flex-direction: column; line-height: 1.2; }
.nav-live-asof {
  font-size: 9px; font-weight: 500; opacity: 0.7; letter-spacing: 0.3px;
}
.nav-live:hover, .nav-live:focus-visible {
  background: var(--lime-soft);
  border-color: var(--lime-deep);
  text-decoration: none;
}
.nav-live-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--lime-deep);
  box-shadow: 0 0 0 0 currentColor;
  animation: navPulse 2.2s ease-in-out infinite;
}
@keyframes navPulse {
  0%, 100% { box-shadow: 0 0 0 0 currentColor; opacity: 1; }
  50%      { box-shadow: 0 0 0 6px transparent; opacity: 0.55; }
}
@media (max-width: 480px) { .nav-live { display: none; } }

/* ── Hero (v3) ───────────────────────────────────────────────────────── */
.hero-v3 {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 44px var(--page-pad) 28px;
}
.hero-headline {
  font-family: var(--display);
  font-weight: 800;
  font-size: 78px;
  letter-spacing: -3px;
  line-height: 0.98;
  color: var(--ink);
  max-width: 1280px;
  margin: 0;
  text-wrap: pretty;
}
.hero-headline .mark { white-space: nowrap; }
.hero-qmark {
  display: block;
  color: var(--ink-soft);
  font-weight: 800;
  margin-top: 6px;
}
.hero-byline {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--muted);
  margin: 18px 0 0;
  line-height: 1.55;
  max-width: 720px;
  letter-spacing: 0.1px;
}
.hero-byline strong { color: var(--ink-soft); font-weight: 700; }
.hero-byline a {
  color: var(--ink-soft);
  text-decoration: underline;
  text-decoration-color: var(--rule);
  text-underline-offset: 3px;
}
.hero-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: 40px;
  margin-top: 28px;
  align-items: start;
}
.hero-sub {
  font-family: var(--sans);
  font-size: 19px;
  color: var(--ink-soft);
  line-height: 1.45;
  max-width: 680px;
  margin: 0;
}

/* UnlockTheWatchlist CTA card */
.unlock-card {
  background: var(--paper-warm);
  border: var(--card-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: 26px;
}
.unlock-eyebrow {
  display: block;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--coral-deep);
  margin-bottom: 6px;
}
.unlock-headline {
  font-family: var(--display);
  font-weight: 800;
  font-size: 26px;
  letter-spacing: -0.6px;
  line-height: 1.1;
  color: var(--ink);
}
.unlock-bullets {
  list-style: none;
  padding: 0;
  margin: 14px 0 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-family: var(--sans);
  font-size: 13px;
  color: var(--ink-soft);
  line-height: 1.35;
}
.unlock-bullets li {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 0;
  border: none;
}
.unlock-bullets li::before { content: none; }
.unlock-bullets strong { color: var(--ink); }
/* Tier mini-table — the receipt behind "N packs on sale right now". */
.unlock-tiers {
  width: 100%;
  margin-top: 12px;
  border-collapse: collapse;
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.4;
  color: var(--ink-soft);
}
.unlock-tiers td { padding: 4px 0; border-top: 1px solid var(--rule); }
.unlock-tiers .ut-tier { font-weight: 700; color: var(--ink); }
.unlock-tiers .ut-n { text-align: center; color: var(--muted); white-space: nowrap; }
.unlock-tiers .ut-price { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.unlock-check {
  flex-shrink: 0;
  margin-top: 2px;
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--lime-soft);
  border: 1px solid var(--lime-deep);
  color: var(--lime-deep);
  display: inline-flex; align-items: center; justify-content: center;
}
/* Crisp, centered SVG check (the old rotated-border ::after sat off-center
   in the circle). */
.unlock-check svg { width: 9px; height: 9px; display: block; }
.unlock-check svg path {
  fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
}
.unlock-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  margin-top: 18px;
  padding: 15px 18px;
  background: var(--coral-deep);
  color: var(--paper);
  border: none;
  border-radius: 8px;
  font-family: var(--sans);
  font-weight: 700;
  font-size: 16px;
  box-shadow: 0 2px 0 rgba(26,22,18,.18), 0 6px 14px rgba(195,58,63,.25);
  text-decoration: none;
}
.unlock-cta:hover { background: #a72c30; text-decoration: none; color: var(--paper); }
.unlock-meta {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--muted);
  margin-top: 10px;
  letter-spacing: 0.5px;
  text-align: center;
  text-transform: uppercase;
}
.unlock-already {
  border-top: 1px solid var(--rule);
  margin-top: 14px;
  padding-top: 11px;
  font-family: var(--sans);
  font-size: 12.5px;
  color: var(--ink-soft);
  text-align: center;
}
.unlock-already a { color: var(--ink); font-weight: 700; text-decoration: underline; }

@media (max-width: 760px) {
  .hero-v3 { padding: 24px var(--page-pad) 18px; }
  .hero-headline { font-size: 38px; letter-spacing: -1.4px; line-height: 1.02; }
  .hero-byline { font-size: 11.5px; margin-top: 12px; }
  .hero-grid { grid-template-columns: 1fr; gap: 18px; margin-top: 18px; }
  .hero-sub { font-size: 15px; }
  .unlock-card { padding: 20px; }
  .unlock-headline { font-size: 22px; }
}

/* ── Section primitives ──────────────────────────────────────────────── */
.section-h {
  font-family: var(--display);
  font-weight: 800;
  font-size: 44px;
  letter-spacing: -1.5px;
  line-height: 1;
  color: var(--ink);
  margin: 0;
}
.section-sub {
  font-family: var(--sans);
  font-size: 15px;
  color: var(--ink-soft);
  margin: 10px 0 0;
  max-width: 720px;
  line-height: 1.5;
}
.section-sub .strike {
  text-decoration: line-through;
  text-decoration-color: rgba(195,58,63,0.5);
  color: var(--muted);
  margin-right: 4px;
}
.section-head-row { display: flex; justify-content: space-between; align-items: flex-end; flex-wrap: wrap; gap: 16px; }

/* ── How it works ────────────────────────────────────────────────────── */
.how-it-works {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 64px var(--page-pad) 0;
}
.how-grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 16px;
  margin-top: 28px;
}
.how-card { padding: 24px 24px 20px; }
.how-card-head { display: flex; justify-content: space-between; align-items: flex-start; }
.how-step {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--muted);
  letter-spacing: 1.5px;
  font-weight: 700;
}
.how-stat {
  font-family: var(--display);
  font-weight: 800;
  font-size: 28px;
  color: var(--lime-deep);
  letter-spacing: -1px;
  line-height: 1;
  text-align: right;
  display: inline-flex;
  flex-direction: column;
}
.how-stat-label {
  font-family: var(--mono);
  font-size: 10px;
  color: var(--muted);
  letter-spacing: 0.6px;
  text-transform: uppercase;
  margin-top: 2px;
  font-weight: 500;
}
.how-title {
  font-family: var(--display);
  font-weight: 700;
  font-size: 22px;
  letter-spacing: -0.5px;
  color: var(--ink);
  margin-top: 16px;
  line-height: 1.15;
}
.how-body {
  font-family: var(--sans);
  font-size: 13.5px;
  color: var(--ink-soft);
  margin: 10px 0 0;
  line-height: 1.55;
}
@media (max-width: 760px) {
  .how-it-works { padding: 40px var(--page-pad) 0; }
  .section-h { font-size: 32px; letter-spacing: -1px; }
  .how-grid { grid-template-columns: 1fr; gap: 12px; margin-top: 20px; }
  .how-card { padding: 18px; }
}

/* ── Stat row (Tufte) ────────────────────────────────────────────────── */
.stat-row-tufte {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 56px var(--page-pad) 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 48px;
}
.stat-tufte { padding: 0; }
.stat-tufte-n {
  font-family: var(--display);
  font-weight: 800;
  font-size: 64px;
  letter-spacing: -2.4px;
  line-height: 1;
  color: var(--ink);
}
.stat-tufte-n.positive { color: var(--lime-deep); }
.stat-tufte-frac { color: var(--muted); font-weight: 700; font-size: 0.62em; }
.stat-tufte-rule {
  height: 1px;
  background: var(--ink);
  margin: 14px 0 10px;
  width: 100%;
}
.stat-tufte-label {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.stat-tufte-sub {
  font-family: var(--sans);
  font-size: 13.5px;
  color: var(--muted);
  margin-top: 6px;
}
@media (max-width: 760px) {
  .stat-row-tufte {
    grid-template-columns: 1fr 1fr;
    gap: 12px;
    padding: 32px var(--page-pad) 0;
  }
  .stat-tufte {
    background: var(--paper-warm);
    border: var(--card-border);
    border-radius: var(--radius-medium);
    padding: 16px;
  }
  .stat-tufte-n { font-size: 36px; letter-spacing: -1.2px; }
  .stat-tufte-rule { display: none; }
  .stat-tufte-label { margin-top: 8px; }
}

/* ── Trajectory ──────────────────────────────────────────────────────── */
.trajectory-section {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 48px var(--page-pad) 0;
}

/* ── Anonymized watchlist preview ────────────────────────────────────── */
.watchlist-anon {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 48px var(--page-pad) 0;
}
.watchlist-anon-card {
  position: relative;
  padding: 0;
  overflow: hidden;
}
.watchlist-anon-table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--sans);
  font-size: 14px;
}
.watchlist-anon-table thead th {
  background: var(--paper-dim);
  border-bottom: 1.5px solid var(--ink);
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--ink-soft);
  text-align: left;
  padding: 12px 16px;
}
.watchlist-anon-table th.right,
.watchlist-anon-table td.right { text-align: right; }
.watchlist-anon-table tbody td {
  padding: 14px 16px;
  border-bottom: 1px solid var(--rule-soft);
  color: var(--ink-soft);
}
.watchlist-anon-table tbody tr:last-child td { border-bottom: none; }
.watchlist-anon-table .anon-name {
  font-family: var(--display);
  font-weight: 700;
  color: var(--ink);
  font-size: 15px;
}
.watchlist-anon-table .anon-tier {
  font-family: var(--mono);
  font-size: 10px;
  color: var(--muted);
  margin-left: 8px;
  text-transform: uppercase;
  letter-spacing: 0.8px;
}
.watchlist-anon-table .mini-shape { width: 80px; height: 24px; display: block; }
.watchlist-anon-table .blur {
  filter: blur(5px);
  user-select: none;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  font-weight: 600;
}
.watchlist-anon-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(180deg, rgba(247,241,222,0.4) 0%, rgba(247,241,222,0.85) 40%, rgba(247,241,222,0.95) 100%);
  pointer-events: none;
}
.watchlist-anon-overlay-inner {
  text-align: center;
  padding: 32px;
  pointer-events: auto;
}
.overlay-headline {
  font-family: var(--display);
  font-weight: 800;
  font-size: 32px;
  letter-spacing: -1px;
  color: var(--ink);
  margin-bottom: 8px;
}
.overlay-sub {
  font-family: var(--sans);
  font-size: 15px;
  color: var(--ink-soft);
  max-width: 460px;
  margin: 0 auto 18px;
  line-height: 1.5;
}
@media (max-width: 760px) {
  .watchlist-anon-table thead th { padding: 10px 12px; font-size: 10px; }
  .watchlist-anon-table tbody td { padding: 12px; font-size: 13px; }
  .watchlist-anon-table .col-shape,
  .watchlist-anon-table thead th.col-shape { display: none; }
  .overlay-headline { font-size: 24px; }
  .overlay-sub { font-size: 14px; }
}

/* ── Signup CTA dark band ────────────────────────────────────────────── */
.signup-cta {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 64px var(--page-pad) 0;
}
.signup-cta-inner {
  background: var(--ink);
  border: 1.5px solid var(--ink);
  border-radius: var(--radius-card);
  padding: 48px 56px;
  position: relative;
  overflow: hidden;
}
.signup-cta-h {
  font-family: var(--display);
  font-weight: 800;
  font-size: 48px;
  letter-spacing: -1.8px;
  color: var(--paper);
  line-height: 1.04;
  max-width: 760px;
  margin: 0;
}
.signup-cta-sub {
  font-family: var(--sans);
  font-size: 16px;
  color: var(--paper-dim);
  margin: 16px 0 26px;
  line-height: 1.5;
  max-width: 680px;
}
.signup-chips {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  margin: 0 0 26px;
}
.chip {
  border-radius: 10px;
  padding: 18px 20px;
  position: relative;
}
.chip-free { background: rgba(247,241,222,0.05); border: 1px solid rgba(247,241,222,0.16); }
.chip-pro  { background: rgba(200,232,74,0.06); border: 1px solid rgba(200,232,74,0.30); }
.chip-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 6px; }
.chip-eyebrow {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--paper-dim);
}
.chip-eyebrow-lime { color: var(--lime); }
.chip-price {
  font-family: var(--display);
  font-weight: 700;
  font-size: 18px;
  letter-spacing: -0.4px;
  color: var(--paper);
}
.chip-price-now { color: var(--lime); }
.chip-price-period { color: var(--paper-dim); font-family: var(--mono); font-size: 10px; letter-spacing: 0.4px; font-weight: 400; margin-left: 4px; }
.chip-body {
  font-family: var(--sans);
  font-size: 13px;
  color: var(--paper-dim);
  line-height: 1.45;
}
.chip-body-light { color: var(--paper); }
.signup-cta-actions {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  align-items: center;
}
.signup-cta-signin {
  font-family: var(--sans);
  font-size: 14px;
  color: var(--paper);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: rgba(247,241,222,0.4);
}
.signup-cta-methods {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--paper-dim);
  letter-spacing: 0.6px;
  text-transform: uppercase;
  margin-left: auto;
}
.btn.lime {
  background: var(--lime);
  /* Fixed near-black so dark mode doesn't flip the text to cream (12.93:1). */
  color: var(--on-lime);
  border: none;
  box-shadow: 0 2px 0 rgba(26,22,18,0.18), 0 6px 14px rgba(200,232,74,0.32);
}
.btn.lime:hover { background: #b9d83f; color: var(--on-lime); text-decoration: none; }
.btn.big {
  padding: 16px 28px;
  font-size: 16px;
  border-radius: 8px;
  font-weight: 700;
}
.btn.outline-light {
  background: transparent;
  color: var(--paper);
  border: 1.5px solid var(--paper-dim);
}
.btn.outline-light:hover { background: rgba(247,241,222,0.08); color: var(--paper); text-decoration: none; }
@media (max-width: 760px) {
  .signup-cta { padding: 40px var(--page-pad) 0; }
  .signup-cta-inner { padding: 28px 22px; }
  .signup-cta-h { font-size: 32px; letter-spacing: -1px; }
  .signup-cta-sub { font-size: 14px; }
  .signup-chips { grid-template-columns: 1fr; gap: 10px; }
  .signup-cta-methods { margin-left: 0; }
}

/* ── FAQ ─────────────────────────────────────────────────────────────── */
.faq {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 64px var(--page-pad) 0;
}
.faq-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px 32px;
  margin-top: 28px;
}
.faq-item { border-top: 1.5px solid var(--ink); padding: 18px 0 6px; }
.faq-q {
  font-family: var(--display);
  font-weight: 700;
  font-size: 18px;
  letter-spacing: -0.3px;
  color: var(--ink);
  margin: 0;
}
.faq-a {
  font-family: var(--sans);
  font-size: 14px;
  color: var(--ink-soft);
  line-height: 1.55;
  margin: 8px 0 0;
}
@media (max-width: 760px) {
  .faq { padding: 40px var(--page-pad) 0; }
  .faq-grid { grid-template-columns: 1fr; gap: 0; margin-top: 18px; }
}

/* ── Final CTA strip ─────────────────────────────────────────────────── */
.final-cta {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 64px var(--page-pad) 0;
}
.final-cta-inner {
  background: var(--ink);
  border: 1.5px solid var(--ink);
  border-radius: var(--radius-card);
  padding: 40px 48px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 40px;
  flex-wrap: wrap;
}
.final-cta-left { max-width: 680px; }
.final-cta-eyebrow {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--lime);
  margin-bottom: 14px;
}
.final-cta-h {
  font-family: var(--display);
  font-weight: 800;
  font-size: 44px;
  letter-spacing: -1.6px;
  color: var(--paper);
  line-height: 1.04;
  margin: 0;
}
.final-cta-sub {
  font-family: var(--sans);
  font-size: 15px;
  color: var(--paper-dim);
  margin-top: 16px;
  line-height: 1.5;
}
.final-cta-right {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 260px;
}
.final-cta-meta {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--paper-dim);
  letter-spacing: 0.4px;
  text-transform: uppercase;
  text-align: center;
  margin-top: 4px;
}
@media (max-width: 760px) {
  .final-cta { padding: 40px var(--page-pad) 0; }
  .final-cta-inner { padding: 26px 22px; flex-direction: column; align-items: stretch; gap: 22px; }
  .final-cta-h { font-size: 30px; letter-spacing: -1px; }
  .final-cta-sub { font-size: 13.5px; }
  .final-cta-right { min-width: 0; }
}

/* ── Feedback widget (slide-out, signed-in users only) ──────────────── */
.fb-widget { position: fixed; top: 0; right: 0; height: 100vh; height: 100dvh; pointer-events: none; z-index: 50; }
.fb-tab {
  position: fixed; top: 50%; right: 0; transform: translateY(-50%);
  z-index: 50; display: inline-flex; align-items: center; justify-content: center;
  padding: 16px 9px; pointer-events: auto;
  /* Lime (the brand action color) so it actually catches the eye instead of
     blending into the page edge. on-lime keeps text dark across themes.
     Flush to the viewport edge — square outer corners, no right border —
     so it reads as a tab coming out of the side, not a floating badge.
     (An inset-pill variant shipped briefly and read as disconnected.)
     Collision with card borders on narrow viewports is handled by the
     tab-lane media query below, not by moving the tabs off the edge. */
  background: var(--lime); color: var(--on-lime);
  border: 1.5px solid var(--lime-deep); border-right: none;
  border-radius: var(--radius-medium) 0 0 var(--radius-medium);
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease, transform 120ms ease, box-shadow 120ms ease;
  box-shadow: -3px 3px 12px rgba(26, 22, 18, .22);
}
.fb-tab:hover, .fb-tab:focus-visible {
  background: var(--lime-deep); color: var(--paper);
  transform: translateY(-50%) translateX(-3px);
  box-shadow: -5px 4px 16px rgba(26, 22, 18, .26);
}
.fb-tab-label {
  writing-mode: vertical-rl; text-orientation: mixed;
  font: 700 13px var(--sans); letter-spacing: .03em;
  line-height: 1;
}

.fb-panel {
  position: absolute; top: 0; right: 0; height: 100vh; height: 100dvh;
  width: 380px; max-width: 92vw;
  background: var(--paper-warm); color: var(--ink);
  border-left: var(--card-border);
  transform: translateX(100%);
  transition: transform 220ms ease;
  pointer-events: auto;
  display: flex; flex-direction: column;
  box-shadow: -8px 0 24px rgba(26, 22, 18, .12);
}
.fb-widget.fb-open .fb-panel { transform: translateX(0); }
.fb-tab.fb-open { transform: translateY(-50%) translateX(-380px); }
@media (max-width: 420px) {
  .fb-tab.fb-open { transform: translateY(-50%) translateX(-92vw); }
}

/* Admin tab — sibling pill above the Ideas tab, admin-only.
   The Ideas tab is centered at 50vh; with its current label its top edge
   sits ~35px above center. Anchor the Admin tab's bottom edge 48px above
   center for a ~10px gap. (This was -72px, calibrated for the longer
   "Feedback" label — when the tab was renamed "Ideas" it got shorter and
   the gap silently grew to ~35px.) */
.admin-tab {
  position: fixed; right: 0; top: 50%;
  transform: translateY(-100%) translateY(-48px);
  padding: 16px 9px; z-index: 50; text-decoration: none;
  background: var(--paper); color: var(--ink);
  border: 1.5px solid var(--ink); border-right: none;
  border-radius: var(--radius-medium) 0 0 var(--radius-medium);
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease, transform 120ms ease, box-shadow 120ms ease;
  box-shadow: -3px 3px 10px rgba(26, 22, 18, .18);
  display: inline-flex; align-items: center; justify-content: center;
}
.admin-tab:hover, .admin-tab:focus-visible {
  background: var(--amber); color: var(--ink);
  transform: translateY(-100%) translateY(-48px) translateX(-3px);
  box-shadow: -5px 4px 14px rgba(26, 22, 18, .22);
}
.admin-tab-label {
  writing-mode: vertical-rl; text-orientation: mixed;
  font: 700 13px var(--sans); letter-spacing: .03em;
  line-height: 1;
}

/* Tab lane — when the 1440px content grid runs close to the viewport edge
   (MacBook-width windows), the fixed side tabs would sit on top of card
   borders. Reserve the lane by padding <main> instead of un-anchoring the
   tabs: card edges then stop ~48px short of the viewport (32px container
   pad + 16px lane), clearing the ~33px tabs plus their hover shift.
   Threshold: card-edge slack is (vw − 1440)/2 + 32px, which drops under
   the needed ~44px below 1464px-wide viewports. Phones excluded — tabs
   are slimmer there and horizontal space is too scarce to reserve. */
@media (min-width: 481px) and (max-width: 1464px) {
  main { padding-right: 16px; }
}

/* Phone-width side tabs — smaller, but still edge-anchored tabs (NOT inset
   floating pills): flush to the right edge, square outer corners, rounded
   inner corners only, no border on the edge side so they read as tabs
   coming out of the viewport rather than free-floating lozenges. */
@media (max-width: 480px) {
  .fb-tab, .admin-tab {
    padding: 9px 5px;
    border-right: none;
    border-radius: var(--radius-medium) 0 0 var(--radius-medium);
    right: 0;
  }
  .fb-tab-label, .admin-tab-label { font-size: 10px; letter-spacing: .14em; }
  /* Re-anchor when feedback panel slides open (panel is max-width: 92vw). */
  .fb-tab.fb-open { transform: translateY(-50%) translateX(-92vw); }
}

.fb-panel-head { display: flex; align-items: center; justify-content: space-between; padding: 18px 20px 6px; }
.fb-panel-head h2 { font: 800 19px var(--display); letter-spacing: -.3px; margin: 0; }
.fb-close { background: none; border: none; font: 600 24px var(--sans); color: var(--ink-soft); cursor: pointer; line-height: 1; padding: 4px 8px; border-radius: var(--radius-small); }
.fb-close:hover { background: var(--paper-dim); }
.fb-sub { padding: 0 20px; color: var(--ink-soft); font-size: 13px; margin: 0 0 12px; }

.fb-form { padding: 0 20px 20px; display: flex; flex-direction: column; gap: 14px; flex: 1; min-height: 0; }
.fb-sentiment {
  border: none; padding: 0; margin: 0;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;
}
.fb-sent-opt {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; padding: 12px 6px;
  border: 1.5px solid var(--rule); border-radius: var(--radius-medium);
  background: var(--paper); cursor: pointer;
  transition: border-color 120ms ease, background 120ms ease;
}
.fb-sent-opt input { position: absolute; opacity: 0; pointer-events: none; }
.fb-sent-opt:hover { border-color: var(--ink-soft); }
.fb-sent-opt:has(input:checked) { border-color: var(--ink); background: var(--lime-soft); }
.fb-sent-icon { font-size: 24px; line-height: 1; color: var(--ink); }
.fb-sent-text { font: 600 11px var(--mono); text-transform: uppercase; letter-spacing: .08em; color: var(--ink-soft); }

.fb-msg-label { font: 600 12px var(--mono); text-transform: uppercase; letter-spacing: .1em; color: var(--ink-soft); }
.fb-required { color: var(--coral-deep); }
#fb-message {
  flex: 1; min-height: 120px; resize: none;
  padding: 12px 14px;
  background: var(--paper); color: var(--ink);
  border: 1.5px solid var(--ink); border-radius: var(--radius-medium);
  font: 500 14px var(--sans); line-height: 1.45;
}
#fb-message:focus { outline: none; box-shadow: 0 0 0 3px var(--lime-soft); }

.fb-actions { display: flex; }
.fb-submit {
  flex: 1; padding: 12px 16px;
  /* on-lime is fixed near-black so dark mode keeps 12.93:1 contrast. */
  background: var(--lime); color: var(--on-lime);
  border: 1.5px solid var(--ink); border-radius: var(--radius-medium);
  font: 700 14px var(--sans); cursor: pointer;
  transition: background 120ms ease, transform 120ms ease;
}
/* Hover: lime-deep bg + paper text. 14px bold = WCAG large text (3:1).
   Light: 4.39:1 ✓ for large text. Dark: 10.09:1 ✓. */
.fb-submit:hover:not(:disabled) { background: var(--lime-deep); color: var(--paper); transform: translateY(-1px); }
.fb-submit:disabled { opacity: .6; cursor: progress; transform: none; }
.fb-msg { font-size: 13px; padding: 8px 10px; border-radius: var(--radius-small); display: none; }
.fb-msg.fb-msg-ok  { display: block; background: var(--lime-soft);  color: var(--lime-deep);  border: 1.5px solid var(--lime-deep); }
.fb-msg.fb-msg-err { display: block; background: var(--coral-soft); color: var(--coral-deep); border: 1.5px solid var(--coral-deep); }

/* ═══════════════════════════════════════════════════════════════════════
   Dashboard · Watchlist (Safe) + Pack Detail
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Dark mode tokens ────────────────────────────────────────────────── */
/* Activated via [data-theme="dark"] on <html>. Auto mode is resolved
   client-side in base.html and rewrites data-theme to "light" or "dark"
   before first paint, so this selector is always concrete. */
html[data-theme="dark"] {
  --paper:      #1a1612;
  --paper-dim:  #221d17;
  --paper-warm: #26201a;

  --ink:        #f6efd9;
  --ink-soft:   #dcd4ba;
  --muted:      #8c8170;

  --lime:       #c8e84a;
  --lime-deep:  #a8d028;
  --lime-soft:  rgba(200, 232, 74, .14);

  --coral:      #ff8077;
  --coral-deep: #e25a5e;
  --coral-soft: rgba(255, 107, 107, .18);

  --amber:      #f0b937;
  --amber-deep: #d99c1c;
  --amber-soft: rgba(240, 185, 55, .18);

  --sky:        #6cc4e0;
  --sky-deep:   #4a9bbb;
  --sky-soft:   rgba(93, 180, 212, .18);

  --rule:       rgba(246, 239, 217, .12);
  --rule-soft:  rgba(246, 239, 217, .06);

  --shadow-card:    0 1px 2px rgba(0,0,0,.3), 0 6px 18px rgba(0,0,0,.35);
  --shadow-card-sm: 0 1px 2px rgba(0,0,0,.3), 0 3px  8px rgba(0,0,0,.3);
}

/* ── Topbar additions: theme toggle + upgrade pill + account chip ────── */
.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px;
  background: var(--paper-warm); color: var(--ink-soft);
  border: 1.5px solid var(--rule); border-radius: 50%;
  cursor: pointer; padding: 0;
  transition: border-color 120ms ease, color 120ms ease;
}
.theme-toggle:hover { border-color: var(--ink); color: var(--ink); }
.theme-toggle .theme-icon { display: none; }
html[data-theme-pref="light"] .theme-toggle .theme-icon-sun  { display: block; }
html[data-theme-pref="dark"]  .theme-toggle .theme-icon-moon { display: block; }
html[data-theme-pref="auto"]  .theme-toggle .theme-icon-auto { display: block; }
@media (max-width: 760px) { .theme-toggle { display: none; } }

.upgrade-pill {
  display: inline-flex; align-items: center; gap: 6px;
  /* Light mode: dark bg + lime text (12.93:1). */
  background: var(--ink); color: var(--lime) !important;
  border: 1.5px solid var(--lime); border-radius: 100px;
  padding: 6px 12px;
  font: 700 11px var(--mono); letter-spacing: 0.6px; text-transform: uppercase;
  white-space: nowrap;
}
.upgrade-pill:hover { background: #000; text-decoration: none; }
/* Dark mode: lime bg with theme-fixed dark text (12.93:1). Was --ink which
   flipped to cream and dropped to 1.20:1. */
html[data-theme="dark"] .upgrade-pill { background: var(--lime); color: var(--on-lime) !important; border-color: var(--lime); }
html[data-theme="dark"] .upgrade-pill:hover { background: var(--lime-deep); color: var(--on-lime) !important; }

.account-chip {
  font: 600 13px var(--sans); color: var(--ink-soft);
  padding: 4px 10px; border-radius: 4px;
  background: var(--paper-dim);
  border: 1px solid var(--rule);
}
.account-chip:hover { text-decoration: none; color: var(--ink); }
@media (max-width: 900px) { .account-chip { display: none; } }

.tier-chip {
  font: 700 10px var(--mono); letter-spacing: 0.6px; text-transform: uppercase;
  padding: 3px 8px; border-radius: 4px;
  background: var(--paper-dim); color: var(--ink-soft);
  border: 1.2px solid var(--muted);
}
/* Light: dark bg + lime text (12.93:1). Dark mode override below pins a dark
   surface so the lime text doesn't end up on cream (would be 1.20:1). */
.tier-chip-pro,
.tier-chip-founding { background: var(--ink); color: var(--lime); border-color: var(--ink); }
html[data-theme="dark"] .tier-chip-pro,
html[data-theme="dark"] .tier-chip-founding {
  background: #1a1612; color: var(--lime); border-color: #1a1612;
}

/* ── Page-title strip ─────────────────────────────────────────────────── */
.watchlist-section {
  max-width: var(--max-width); margin: 0 auto;
  padding: 28px var(--page-pad) 60px;
}
.watchlist-titlebar {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 18px; flex-wrap: wrap; margin-bottom: 18px;
}
.watchlist-title {
  font: 800 36px var(--display); letter-spacing: -1.3px;
  line-height: 1; color: var(--ink); margin: 0;
}
.watchlist-byline {
  font: 500 14px var(--sans); color: var(--ink-soft);
  margin: 6px 0 0; max-width: 700px; line-height: 1.45;
}
.watchlist-byline .mark { font-weight: 600; }
.watchlist-search-wrap { min-width: 280px; width: clamp(280px, 35%, 380px); }
@media (max-width: 760px) {
  .watchlist-title { font-size: 26px; letter-spacing: -1px; }
  .watchlist-search-wrap { width: 100%; }
}

/* ── Card search ──────────────────────────────────────────────────────── */
.card-search {
  position: relative;
  display: flex; align-items: center; gap: 0;
  background: var(--paper-warm);
  border: 1.5px solid var(--rule); border-radius: 8px;
  padding: 8px 12px;
  transition: border-color 120ms ease;
}
.card-search:focus-within { border-color: var(--ink); }
.card-search-icon { color: var(--muted); flex-shrink: 0; margin-right: 8px; }
.card-search-input {
  flex: 1; min-width: 0; padding: 0; margin: 0;
  background: transparent; color: var(--ink);
  border: none; outline: none;
  font: 500 12.5px var(--mono);
}
.card-search-kbd {
  flex-shrink: 0;
  font: 700 10px var(--mono); color: var(--muted); letter-spacing: 0.4px;
  border: 1px solid var(--rule); border-radius: 4px;
  padding: 2px 6px; margin-left: 8px;
}
.card-search-clear {
  flex-shrink: 0; display: none;
  background: transparent; border: none; cursor: pointer;
  color: var(--muted); padding: 0; margin-left: 4px;
  font-size: 18px; line-height: 1; width: 18px; height: 18px;
}
.card-search.has-query .card-search-clear { display: inline-block; }
.card-search.has-query .card-search-kbd { display: none; }

.card-search-dropdown {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0;
  background: var(--paper-warm);
  border: 1.5px solid var(--ink); border-radius: 8px;
  box-shadow: var(--shadow-card);
  padding: 6px; z-index: 30; max-height: 420px; overflow-y: auto;
  min-width: 380px;
}
.card-search-dropdown[hidden] { display: none; }
.card-search-result {
  display: block; width: 100%; text-align: left;
  background: transparent; border: none; border-radius: 6px;
  padding: 10px; cursor: pointer; color: inherit;
  transition: background 100ms ease;
}
.card-search-result:hover { background: var(--rule-soft); text-decoration: none; }
.card-search-result-top {
  display: flex; justify-content: space-between; align-items: flex-start; gap: 12px;
}
.card-search-result-name { font: 700 13.5px var(--sans); color: var(--ink); letter-spacing: -0.2px; }
.card-search-result-set  { font: 500 10.5px var(--mono); color: var(--muted); margin-top: 2px; letter-spacing: 0.3px; }
.card-search-result-value { font: 700 14px var(--display); color: var(--ink); letter-spacing: -0.3px; font-variant-numeric: tabular-nums; }
.card-search-result-ev    { font: 700 10px var(--mono); color: var(--lime-deep); margin-top: 1px; }
.card-search-result-pack  { display: flex; align-items: center; gap: 6px; margin-top: 6px; }
.card-search-result-pack-name { font: 600 12px var(--sans); color: var(--ink-soft); }
.card-search-result-header {
  font: 700 10px var(--mono); color: var(--muted); letter-spacing: 1px; text-transform: uppercase;
  padding: 8px 10px 4px;
}
.card-search-empty {
  padding: 20px 10px; text-align: center;
  font: 500 13px var(--sans); color: var(--muted);
}
.card-search-empty strong { color: var(--ink-soft); font-weight: 600; }

/* ── Status strip ─────────────────────────────────────────────────────── */
.status-strip {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)) auto;
  gap: 0;
  border-top: 1px solid var(--ink);
  border-bottom: 1px solid var(--rule);
  background: var(--paper);
  margin-bottom: 0;
}
.status-stat {
  padding: 18px 24px;
  border-left: 1px solid var(--rule);
  display: flex; flex-direction: column; gap: 4px;
}
.status-stat:first-child { border-left: none; }
.status-stat-row { display: flex; align-items: baseline; gap: 8px; }
.status-stat-n {
  font: 800 36px var(--display); letter-spacing: -1px;
  line-height: 1; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.status-stat-n.positive { color: var(--lime-deep); }
.status-stat-n.amber    { color: var(--amber-deep); }
.status-stat-n.sky      { color: var(--sky-deep); }
.status-stat-sub {
  font: 500 12px var(--sans); color: var(--ink-soft);
  margin-top: 4px;
}
.status-stat-delay { padding: 18px 24px; align-items: flex-end; justify-content: center; }
@media (max-width: 760px) {
  .status-strip { grid-template-columns: 1fr 1fr; }
  .status-stat { padding: 14px 16px; }
  .status-stat-n { font-size: 26px; }
  .status-stat:nth-child(3),
  .status-stat-delay { display: none; }
}

/* ── Delay badge ──────────────────────────────────────────────────────── */
.delay-badge {
  display: inline-flex; align-items: center; gap: 6px;
  font: 700 10.5px var(--mono); color: var(--amber-deep);
  letter-spacing: 0.5px; text-transform: uppercase;
  background: var(--amber-soft); padding: 4px 8px; border-radius: 4px;
}
.delay-upgrade {
  font-weight: 500; text-decoration: none; opacity: 0.75;
  transition: opacity 120ms ease;
}
.delay-upgrade:hover { opacity: 1; text-decoration: underline; }
/* Wrapper that drops a .delay-badge under a page byline (dashboard, /packs) to
   stamp the 1h Free delay on the EV numbers below it. */
.delay-stamp { margin: 10px 0 2px; }

/* ── Pulse dot ────────────────────────────────────────────────────────── */
.dot {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  background: currentColor;
}
.dot-pulse {
  box-shadow: 0 0 0 4px currentColor;
  /* The shadow uses currentColor with low opacity by overriding via specific use */
  animation: dot-pulse 2.2s ease-in-out infinite;
}
@keyframes dot-pulse {
  0%, 100% { transform: scale(1);   box-shadow: 0 0 0 0 currentColor; opacity: 1; }
  50%      { transform: scale(1.1); box-shadow: 0 0 0 6px transparent; opacity: 0.9; }
}

/* ── Trajectory strip (compact dashboard variant) ─────────────────────── */
.trajectory-strip {
  background: var(--paper-warm);
  border-bottom: 1px solid var(--rule);
  padding: 20px 24px 16px;
}
.trajectory-strip-head {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: 10px; gap: 12px; flex-wrap: wrap;
}
.trajectory-strip-svg-wrap { position: relative; height: 160px; }
.trajectory-strip-svg { display: block; width: 100%; height: 100%; }
.trajectory-y { position: absolute; inset: 0; pointer-events: none; }
.trajectory-y-label {
  position: absolute; left: 0; transform: translateY(-50%);
  font: 500 9px var(--mono); color: var(--muted);
  background: var(--paper-warm); padding: 0 3px; border-radius: 2px; line-height: 1.2;
}
/* Peak badge — pinned on the spike that engaged the symlog scale. */
.trajectory-peak-label {
  position: absolute; pointer-events: none; white-space: nowrap;
  font: 700 10px var(--mono); color: var(--lime-deep);
  background: var(--paper); border: 1.5px solid var(--lime-deep);
  border-radius: 999px; padding: 1px 7px; line-height: 1.4;
}
.trajectory-peak-label.is-left  { transform: translate(calc(-100% - 8px), -50%); }
.trajectory-peak-label.is-right { transform: translate(8px, -50%); }
.trajectory-strip-legend {
  display: flex; flex-wrap: wrap; gap: 6px 14px; margin-top: 10px;
  font: 500 11px var(--mono); color: var(--muted);
}
.band-key { display: inline-flex; align-items: center; gap: 6px; }
.band-swatch {
  display: inline-block; width: 12px; height: 12px; border-radius: 2px;
  border: 1px solid var(--rule);
}
@media (max-width: 760px) {
  .trajectory-strip { padding: 16px 14px; }
  .trajectory-strip-svg-wrap { height: 120px; }
}

/* ── Winners strip (paid: real values; free: blurred upgrade prompt) ─── */
.winners-strip {
  position: relative;
  background: var(--paper-warm);
  border-bottom: 1px solid var(--rule);
  padding: 20px 24px 16px;
}
.winners-strip-head {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: 12px; gap: 12px; flex-wrap: wrap;
}
.winners-trio {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px;
}
.winner-card {
  display: flex; flex-direction: column; gap: 4px;
  padding: 12px 14px;
  background: var(--paper);
  border: 1.5px solid var(--rule); border-radius: var(--radius-medium);
}
.winner-label {
  font: 600 10px var(--mono); text-transform: uppercase; letter-spacing: .12em;
  color: var(--muted);
}
.winner-pack {
  font: 700 16px var(--display); letter-spacing: -0.2px; color: var(--ink);
}
.winner-stat {
  font: 500 12px var(--mono); color: var(--ink-soft);
}
/* Free-user lock: blur the data, lay an upgrade prompt on top. */
.winners-strip-locked .winners-trio { filter: blur(5px); user-select: none; pointer-events: none; }
.winners-overlay {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px; text-decoration: none; color: var(--ink);
  background: linear-gradient(to bottom, rgba(255, 252, 245, 0.4), rgba(255, 252, 245, 0.8));
  border-bottom: 1px solid var(--rule);
}
html[data-theme="dark"] .winners-overlay {
  background: linear-gradient(to bottom, rgba(26, 22, 18, 0.5), rgba(26, 22, 18, 0.85));
}
.winners-overlay:hover { text-decoration: none; }
.winners-overlay-lead {
  font: 600 13px var(--sans); color: var(--ink);
}
.winners-overlay-cta {
  font: 700 13px var(--sans); color: var(--paper);
  background: var(--ink); padding: 8px 14px; border-radius: var(--radius-small);
}
.winners-overlay:hover .winners-overlay-cta { background: var(--ink-soft); }
@media (max-width: 760px) {
  .winners-strip { padding: 16px 14px; }
  .winners-trio { grid-template-columns: 1fr; gap: 8px; }
  .winners-strip-locked .winners-trio { filter: blur(4px); }
}

/* ── Dashboard summary view (compact landing surface) ────────────────── */
.dashboard-section { max-width: var(--max-width); margin: 0 auto; padding: 0 var(--page-pad) 28px; }
.dashboard-titlebar {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 18px; flex-wrap: wrap;
  padding: 24px 0 4px;
}
.dashboard-title {
  margin: 0 0 4px;
  font: 800 28px var(--display); letter-spacing: -0.5px; color: var(--ink);
}
.dashboard-byline {
  margin: 0; font-size: 14px; color: var(--ink-soft);
}
@media (max-width: 760px) {
  .dashboard-section { padding: 0 14px 24px; }
  .dashboard-titlebar { padding: 18px 0 4px; }
  .dashboard-title { font-size: 22px; }
}

/* ── Top 8 packs strip ───────────────────────────────────────────────── */
.top-packs-strip {
  background: var(--paper-warm);
  border-bottom: 1px solid var(--rule);
  padding: 20px 24px 18px;
}
.top-packs-head {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: 12px; gap: 12px; flex-wrap: wrap;
}
.top-packs-all {
  font: 600 12px var(--mono); color: var(--ink); text-decoration: none;
  padding: 4px 10px; border: 1.5px solid var(--ink); border-radius: var(--radius-small);
  background: var(--paper);
}
.top-packs-all:hover { background: var(--paper-dim); text-decoration: none; }
.top-packs-grid {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px;
}
.top-pack-card {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 14px;
  background: var(--paper);
  border: 1.5px solid var(--rule); border-radius: var(--radius-medium);
  text-decoration: none; color: var(--ink);
  transition: border-color 120ms ease, transform 120ms ease;
}
.top-pack-card:hover {
  border-color: var(--ink); text-decoration: none; transform: translateY(-1px);
}
.top-pack-card.is-plusev { border-color: var(--lime-deep); }
.top-pack-img {
  width: 48px; height: 48px; flex-shrink: 0;
  border-radius: var(--radius-small); overflow: hidden;
  background: var(--paper-dim);
  display: flex; align-items: center; justify-content: center;
}
.top-pack-img img { width: 100%; height: 100%; object-fit: cover; }
.top-pack-img-fallback { color: var(--muted); font: 700 16px var(--display); }
.top-pack-body { flex: 1; min-width: 0; }
.top-pack-name {
  font: 700 14px var(--display); letter-spacing: -0.2px; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.top-pack-meta {
  display: flex; align-items: center; gap: 8px; margin-top: 3px;
  font: 500 11px var(--mono); color: var(--muted);
}
.top-pack-price { color: var(--ink-soft); }
.top-pack-hot { font-size: 11px; }
.top-pack-ev {
  font: 700 18px var(--display); letter-spacing: -0.3px; color: var(--ink-soft);
  flex-shrink: 0; min-width: 64px; text-align: right;
}
.top-pack-ev.positive { color: var(--lime-deep); }
.top-pack-ev.negative { color: var(--coral-deep); }
@media (max-width: 760px) {
  .top-packs-strip { padding: 16px 14px; }
  .top-packs-grid { grid-template-columns: 1fr; }
  .top-pack-name { font-size: 13px; }
  .top-pack-ev { font-size: 16px; min-width: 56px; }
}

/* ── Live activity ticker (Pro dashboard) ───────────────────────────── */
.ticker-strip {
  position: relative;
  background: var(--paper-warm);
  border-bottom: 1px solid var(--rule);
  padding: 20px 24px 18px;
}
.ticker-head {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: 10px; gap: 12px; flex-wrap: wrap;
}
.ticker-head .dot {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  margin-right: 6px; vertical-align: 1px;
}
.ticker-list { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 6px; }
.ticker-item {
  background: var(--paper);
  border: 1.5px solid var(--rule); border-radius: var(--radius-medium);
  padding: 10px 12px;
  display: flex; flex-direction: column; gap: 4px;
}
.ticker-item-notable { border-left: 3px solid var(--amber-deep); }
.ticker-item-alert  { border-left: 3px solid var(--lime-deep); }
.ticker-item-supergrail { background: linear-gradient(to right, var(--amber-soft) 0%, var(--paper) 30%); }
.ticker-row-top {
  display: flex; justify-content: space-between; align-items: baseline; gap: 10px;
}
.ticker-pack {
  display: inline-flex; align-items: center; gap: 8px; min-width: 0;
  text-decoration: none; color: var(--ink);
}
.ticker-pack:hover { text-decoration: none; }
.ticker-pack:hover .ticker-pack-name { text-decoration: underline; }
.ticker-pack-name {
  font: 700 14px var(--display); letter-spacing: -0.2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 280px;
}
.ticker-time {
  font: 500 11px var(--mono); color: var(--muted); white-space: nowrap;
}
.ticker-summary {
  display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: center;
  font: 500 12px var(--mono); color: var(--ink-soft);
}
.ticker-evchip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; border-radius: 999px;
  font: 700 11px var(--mono);
  border: 1px solid var(--rule);
}
.ticker-evchip-up   { background: var(--lime-soft);  color: var(--lime-deep);  border-color: var(--lime-deep); }
.ticker-evchip-down { background: var(--coral-soft); color: var(--coral-deep); border-color: var(--coral-deep); }
.ticker-evchip-grail { background: var(--amber-soft); color: var(--amber-deep); border-color: var(--amber-deep); }
.ticker-evchip-chase { background: var(--sky-soft); color: var(--sky-deep); border-color: var(--sky-deep); }
.ticker-pool { display: inline-flex; gap: 8px; align-items: center; }
.ticker-in  { color: var(--lime-deep); font-weight: 700; }
.ticker-out { color: var(--coral-deep); font-weight: 700; }
.ticker-delta.positive { color: var(--lime-deep); font-weight: 700; }
.ticker-delta.negative { color: var(--coral-deep); font-weight: 700; }
.ticker-inv { color: var(--muted); }
.ticker-cards {
  display: flex; flex-wrap: wrap; gap: 4px; margin-top: 2px;
}
.ticker-card {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 7px; border-radius: var(--radius-small);
  font: 500 11px var(--mono);
  border: 1px solid var(--rule); background: var(--paper-dim);
}
.ticker-card-out { color: var(--coral-deep); }
.ticker-card-in  { color: var(--lime-deep); }
.ticker-card-arrow { font-weight: 700; opacity: 0.6; }
.ticker-card-val { color: var(--ink-soft); margin-left: 2px; }
.ticker-card-grail { color: var(--amber-deep); }
.ticker-card-more {
  font: 500 11px var(--mono); color: var(--muted); padding: 2px 4px;
}
/* Brief flash on newly-prepended items so the eye catches the live add. */
@keyframes ticker-flash {
  0%   { background: var(--lime-soft); }
  100% { background: var(--paper); }
}
.ticker-item-new { animation: ticker-flash 1.5s ease-out; }

/* ── Per-pack STATE chips on a ticker row (+EV / Rip Mode; ships dark behind
   live_state_chips_enabled) ── Row-top, beside the tier pill in the same slot
   as .crossing-retired-tag — NOT the summary line, whose chips describe the
   minute's EVENT. The server renders both; JS toggles [hidden]. */
.ticker-state { display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0; }
/* +EV reuses .plus-ev-chip verbatim (solid lime, on-lime text) — the same
   chip as /packs and /dashboard, so the surfaces agree by construction. */
.ticker-state-rip {
  /* Solid coral: the site's "live right now" accent (.ev-live-pill,
     .rip-banner-dot). Deliberately NOT lime — lime already means +EV here,
     EV-up in the summary chips, and the resume chip; two lime chips side by
     side read as one blob, coral-beside-lime reads as two facts. */
  display: inline-block; padding: 2px 6px; border-radius: 3px;
  background: var(--coral-deep); color: #fff;
  font: 700 9.5px var(--mono); letter-spacing: 0.6px; text-transform: uppercase;
  white-space: nowrap; cursor: default;
  animation: rip-pulse 1.6s ease-in-out infinite;   /* keyframes: .rip-chip */
}
/* An author `display` beats the UA's [hidden] rule — same override
   .ticker-new-chip[hidden] needs. */
.ticker-state-ev[hidden], .ticker-state-rip[hidden] { display: none; }
@media (prefers-reduced-motion: reduce) { .ticker-state-rip { animation: none; } }
/* Narrow screens: the chips are flex-shrink:0 and the pack NAME is what
   ellipsizes, so with both chips on at 375px the name squeezed to "D.." and
   the expand button ran off the card. Let the row-top wrap instead — the name
   + tier keep the first line, the chips drop to a second line, and .ticker-time
   (margin-left:auto) still pins right on whichever line it lands. Verified in
   the browser at 375px with both chips forced on. */
@media (max-width: 760px) {
  .ticker-row-top { flex-wrap: wrap; row-gap: 4px; }
  /* Only the chip group is allowed to wrap. The pack link yields (its name
     already ellipsizes at 180px), and the time + expand button hold the
     first line — without this, wrapping let the BUTTON drop to its own line
     on a chip-less row whose name+tier+time already filled the width. */
  .ticker-row-top .ticker-pack { flex: 1 1 0; min-width: 0; }
  .ticker-row-top .ticker-time, .ticker-row-top .ticker-expand { flex-shrink: 0; }
  .ticker-state { order: 10; flex-basis: 100%; }
  .ticker-state-rip { letter-spacing: 0.3px; padding: 2px 5px; }
}

/* ── Click-to-expand detail (Pro; ships dark behind live_expand_enabled) ── */
/* Auto margin pins the time (and the expand button after it) to the right
   edge whether or not the button rendered — deploy-skew rows without a
   button keep today's layout. */
.ticker-row-top .ticker-time { margin-left: auto; }
/* The at-event EV readout sits right of center with the time; when present
   IT takes the auto margin and the time falls in beside it (two auto
   margins would split the free space and strand them apart). */
.ticker-ev { font: 700 12px var(--mono); color: var(--muted); white-space: nowrap; margin-left: auto; }
.ticker-ev.positive { color: var(--lime-deep); }
.ticker-ev.negative { color: var(--coral-deep); }
/* GENERAL sibling, not adjacent: the state chips (+EV / Rip Mode) sit
   between the readout and the time, so `.ticker-ev + .ticker-time` stopped
   matching when they shipped — .ticker-time kept its own margin-left:auto,
   the free space split 50/50 between two auto margins, and the readout was
   stranded mid-row at a position that tracked the pack name's width (~130px
   of drift across rows). Exactly the failure the rule was written to stop. */
.ticker-row-top .ticker-ev ~ .ticker-time { margin-left: 12px; }
.ticker-expand {
  background: none; border: 1px solid var(--rule); border-radius: var(--radius-small);
  padding: 3px 11px; line-height: 20px; cursor: pointer;
  font: 700 12px var(--mono); color: var(--muted);
  transition: transform 120ms ease;
}
.ticker-expand:hover, .ticker-expand:focus-visible { color: var(--ink); border-color: var(--ink-soft); }
.ticker-item-open > .ticker-row-top .ticker-expand { transform: rotate(90deg); color: var(--ink); }
/* The whole card is the toggle target (the pack-name link and the open
   panel are carved out in JS) — say so before the click: pointer + a lift
   on hover, only on rows that actually carry the expand affordance. */
[data-ticker] .ticker-item:has([data-ticker-expand]) { cursor: pointer; }
[data-ticker] .ticker-item:has([data-ticker-expand]):hover { border-color: var(--ink-soft); }
[data-ticker] .ticker-item .ticker-detail { cursor: default; }
/* Paused state: the strip's pulse freezes while a card is open — the page
   itself should look paused, not just say so in the status text. */
.ticker-strip.ticker-paused .dot-pulse { animation-play-state: paused; opacity: .5; }
/* The "N new updates" resume chip, pinned above the list while paused. */
.ticker-new-chip {
  display: block; margin: 0 auto 10px; padding: 5px 16px;
  border: 1.5px solid var(--lime-deep); border-radius: 999px;
  background: var(--lime-soft); color: var(--lime-deep);
  font: 700 11.5px var(--mono); letter-spacing: .04em; cursor: pointer;
}
.ticker-new-chip:hover, .ticker-new-chip:focus-visible { background: var(--lime-deep); color: var(--paper); }
.ticker-new-chip[hidden] { display: none; }
/* The panel is exactly as tall as the update — NO inner scroller. It shipped
   capped at 320px with overflow-y:auto, which is ~6 activity rows: a 15-row
   swap put 7 rows AND the "Full pack history" link out of sight, and because
   the cut landed flush with the card's bottom edge (no scrollbar gutter in
   this theme, no half-row peeking) the card read as a COMPLETE list rather
   than a scrollable one. overscroll-behavior:contain made it worse — a wheel
   over the panel moved the panel and refused to chain to the page, so the
   feed felt stuck.

   Unbounded is safe here because the ROW COUNT is bounded, not just typical:
   the endpoint caps its rows server-side, and a real minute bucket is 1-2 (a
   swap) to ~15 (a burst) — most updates are one card in, one card out.

   Re-capping this is a regression, not a tidy-up — a test fails the build if
   a scroller comes back, in this rule or in a media query. If a future
   pathological pack really needs a bound, bound the ROWS server-side (a
   lower row cap plus an honest "+N more" line into /pack/<id>) — never a
   silent viewport. */
.ticker-detail {
  margin-top: 8px; padding-top: 4px; border-top: 1px solid var(--rule);
}
.ticker-detail-empty { font: 500 12px var(--sans); color: var(--muted); margin: 8px 0 4px; }
/* Lead-in above the revalued-card rows on an EV-only update. Same muted
   register as the empty state it replaces — it is context for the rows
   below, not a heading competing with them. */
.ticker-detail-lead { font: 500 12px var(--sans); color: var(--muted); margin: 8px 0 2px; }
.ticker-detail-more {
  display: inline-block; margin: 8px 0 2px;
  font: 600 11.5px var(--sans); color: var(--sky-deep); text-decoration: none;
  border-bottom: 1px solid rgba(42, 119, 153, .4);
}
.ticker-detail-more:hover, .ticker-detail-more:focus-visible { border-bottom-color: var(--sky-deep); }
.ticker-detail-err {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin: 8px 0 4px; padding: 8px 10px;
  background: var(--coral-soft); border: 1.5px solid var(--coral-deep);
  border-radius: var(--radius-small);
  font: 500 12px var(--sans); color: var(--coral-deep);
}
.ticker-detail-retry {
  background: var(--coral-deep); color: var(--paper); border: none; border-radius: var(--radius-chip);
  padding: 3px 10px; cursor: pointer;
  font: 700 10.5px var(--mono); text-transform: uppercase; letter-spacing: .07em;
}
/* Free-tier locked state — match the winners-strip-locked pattern. */
.ticker-strip-locked .ticker-list-locked { filter: blur(5px); user-select: none; pointer-events: none; }
@media (max-width: 760px) {
  .ticker-strip { padding: 16px 14px; }
  .ticker-pack-name { max-width: 180px; font-size: 13px; }
  .ticker-card { font-size: 10px; }
}

/* ── EV crossings timeline (dashboard variant — distinct from the
   `.crossings-list .row` styles used on the marketing home) ──────────── */
.crossings-strip {
  background: var(--paper-warm);
  border-bottom: 1px solid var(--rule);
  padding: 20px 24px 18px;
}
.crossings-head {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: 10px; gap: 12px; flex-wrap: wrap;
}
.crossings-strip .crossings-list {
  margin: 0; padding: 0; list-style: none;
  display: flex; flex-direction: column;
}
.crossing-row {
  display: grid;
  grid-template-columns: 18px 64px 1fr auto;
  align-items: center; gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--rule);
  font: 500 13px var(--sans); color: var(--ink-soft);
}
.crossing-row:last-child { border-bottom: none; }
.crossing-icon {
  font: 700 14px var(--mono); text-align: center;
}
.crossing-up .crossing-icon { color: var(--lime-deep); }
.crossing-down .crossing-icon { color: var(--coral-deep); }
.crossing-time {
  font: 500 11px var(--mono); color: var(--muted);
  white-space: nowrap;
}
.crossing-pack {
  display: flex; align-items: center; gap: 8px;
  text-decoration: none; color: var(--ink);
  min-width: 0;
}
.crossing-pack:hover { text-decoration: none; }
.crossing-pack:hover .crossing-pack-name { text-decoration: underline; }
.crossing-pack-name {
  font: 600 13px var(--sans); color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.crossing-retired-tag {
  font: 600 9.5px var(--mono); text-transform: uppercase; letter-spacing: 0.12em;
  padding: 1px 6px; border-radius: 999px;
  background: var(--paper-dim); color: var(--muted); border: 1px solid var(--rule);
}
.crossing-retired .crossing-pack-name { color: var(--ink-soft); }
.crossing-retired .crossing-time,
.crossing-retired .crossing-delta { opacity: 0.7; }
.crossing-delta {
  font: 500 12px var(--mono); color: var(--ink-soft); white-space: nowrap;
}
.crossing-up .crossing-delta strong { color: var(--lime-deep); }
.crossing-down .crossing-delta strong { color: var(--coral-deep); }
@media (max-width: 760px) {
  .crossings-strip { padding: 16px 14px; }
  .crossing-row {
    grid-template-columns: 16px 48px 1fr;
    grid-template-rows: auto auto;
    row-gap: 2px; column-gap: 8px;
  }
  .crossing-delta { grid-column: 2 / -1; padding-left: 0; }
}

/* ── Upsell strip ─────────────────────────────────────────────────────── */
.upsell-strip {
  margin: 18px 0 14px;
  padding: 14px 22px;
  background: var(--paper-warm);
  border: 1.5px solid var(--ink); border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
}
.upsell-strip-left {
  display: flex; align-items: center; gap: 12px;
  font: 500 14px var(--sans); color: var(--ink-soft); line-height: 1.45;
}
.upsell-strip-left strong { color: var(--ink); }
.upsell-strip-left .mark { font-weight: 600; }
.btn.upgrade-cta {
  /* Light: dark bg + lime text (12.93:1). */
  background: var(--ink); color: var(--lime);
  border: 1.5px solid var(--lime); border-radius: 6px;
  padding: 8px 14px; font: 700 13px var(--sans);
  white-space: nowrap;
}
.btn.upgrade-cta:hover { background: #000; text-decoration: none; }
/* Dark: lime bg + theme-fixed dark text (12.93:1). Was --ink which flipped
   to cream and gave the reported 1.20:1 white-on-green failure. */
html[data-theme="dark"] .btn.upgrade-cta { background: var(--lime); color: var(--on-lime); }
html[data-theme="dark"] .btn.upgrade-cta:hover { background: var(--lime-deep); color: var(--on-lime); }
.btn.upgrade-cta-small {
  display: inline-block; margin-top: 10px;
  /* Light: dark bg + lime text (12.93:1). */
  background: var(--ink); color: var(--lime);
  border: 1.5px solid var(--lime); border-radius: 6px;
  padding: 7px 12px; font: 700 12.5px var(--sans);
}
/* Dark: lime bg + theme-fixed dark text (12.93:1). */
html[data-theme="dark"] .btn.upgrade-cta-small { background: var(--lime); color: var(--on-lime); }

/* ── Filter bar ───────────────────────────────────────────────────────── */
.filter-bar {
  margin: 14px 0 14px;
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
}
.filter-bar > * { flex-shrink: 0; }

.filter-toggle {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--paper-warm); color: var(--ink-soft);
  border: 1.5px solid var(--rule); border-radius: 100px;
  padding: 7px 12px;
  font: 700 12.5px var(--sans); cursor: pointer;
  white-space: nowrap;
}
.filter-toggle .dot {
  width: 7px; height: 7px; background: var(--muted);
}
.filter-toggle[aria-pressed="true"] {
  /* on-lime so dark mode keeps dark text on lime (12.93:1). */
  background: var(--lime); color: var(--on-lime); border-color: var(--lime-deep);
}
.filter-toggle[aria-pressed="true"] .dot {
  background: var(--lime-deep); animation: dot-pulse 2.2s ease-in-out infinite;
}
.filter-toggle-watched[aria-pressed="true"] {
  background: var(--amber-soft); color: var(--amber-deep);
  border-color: var(--amber-deep);
}
.filter-toggle-watched[aria-pressed="true"] .dot { display: none; }

.filter-chip { position: relative; display: inline-block; }
.filter-chip-btn {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--paper-warm); color: var(--ink-soft);
  border: 1.5px solid var(--rule); border-radius: 100px;
  padding: 7px 12px;
  font: 600 12.5px var(--sans); cursor: pointer; white-space: nowrap;
}
.filter-chip.is-active .filter-chip-btn {
  background: var(--ink); color: var(--paper);
  border-color: var(--ink);
}
.filter-chip-label {
  color: var(--muted); font: 700 10.5px var(--mono);
  letter-spacing: 0.6px; text-transform: uppercase;
}
/* Light: lime label on the dark active-chip surface (12.93:1). */
.filter-chip.is-active .filter-chip-label { color: var(--lime); }
/* Dark mode: --ink flips to cream, which would put lime label on cream
   (1.20:1). Pin the active chip to a dark surface so the lime label keeps
   its contrast. */
html[data-theme="dark"] .filter-chip.is-active .filter-chip-btn {
  background: #1a1612; color: #f6efd9; border-color: #1a1612;
}
.filter-chip-btn svg { opacity: 0.7; }

.filter-chip-popover {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 20;
  background: var(--paper-warm);
  border: 1.5px solid var(--ink); border-radius: 8px;
  box-shadow: var(--shadow-card);
  padding: 4px; min-width: 200px; max-height: 320px; overflow-y: auto;
}
.filter-chip-popover-wide { min-width: 280px; padding: 16px; }
.filter-chip-popover[hidden] { display: none; }
/* Backdrop is desktop-hidden; only the mobile bottom sheet (below) dims it in. */
.filter-backdrop { display: none; }
/* On phones, anchoring a popover to its chip overflows the viewport whenever the
   chip wraps away from the left edge (worst with the wide price card). Instead of
   chasing the anchor, present any open popover as a bottom sheet pinned to the
   viewport — always fully on-screen, whatever line the chip wrapped to. The sheet
   stays a DOM child of its [data-filter-chip], so outside-tap-to-close still works.
   A dimmed backdrop behind it makes it read as a modal. */
@media (max-width: 640px) {
  .filter-chip-popover {
    position: fixed; top: auto; bottom: 12px; left: 12px; right: 12px;
    width: auto; min-width: 0; max-width: none; max-height: 72vh; overflow-y: auto;
    z-index: 1000; border-radius: 12px;
    box-shadow: 0 -6px 28px rgba(26, 22, 18, .28);
  }
  .filter-chip-popover-wide { left: 12px; right: 12px; padding: 16px; }
  .filter-backdrop:not([hidden]) {
    display: block; position: fixed; inset: 0;
    background: rgba(26, 22, 18, .42); z-index: 999;
  }
}
.filter-opt {
  display: flex; align-items: center; justify-content: space-between;
  width: 100%; text-align: left;
  background: transparent; color: var(--ink); border: none; border-radius: 5px;
  padding: 8px 10px; cursor: pointer;
  font: 500 13px var(--sans);
}
.filter-opt:hover { background: var(--rule-soft); }
.filter-opt.on { background: var(--lime-soft); font-weight: 600; }
.filter-opt .check { color: var(--lime-deep); font-weight: 700; visibility: hidden; }
.filter-opt.on .check { visibility: visible; }

/* Sort chip (v4 Layout) — its options are <a class="col-sort"> links (server
   navigation, filter-preserving), styled like the button options above. */
.sort-opt { text-decoration: none; }
.sort-opt:hover { text-decoration: none; }
.sort-opt .sort-dir {
  color: var(--lime-deep); font: 700 11px var(--mono); min-width: 12px; text-align: right;
}

/* Price range slider */
.price-range-head {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: 12px;
}
.price-reset {
  background: transparent; color: var(--coral-deep); border: none; padding: 0;
  font: 600 11px var(--sans); cursor: pointer; text-decoration: underline; text-underline-offset: 2px;
}
.price-range-numerals {
  display: flex; justify-content: space-between; align-items: baseline;
  font: 800 22px var(--display); letter-spacing: -0.6px; color: var(--ink);
  margin-bottom: 14px;
}
.price-range-numerals .muted { font: 600 14px var(--sans); color: var(--muted); }
.price-range-track-wrap {
  position: relative; height: 28px; margin: 4px 6px;
}
.price-range-track {
  position: absolute; top: 12px; left: 0; right: 0; height: 4px;
  background: var(--rule); border-radius: 2px;
}
.price-range-fill {
  position: absolute; top: 12px; left: 0%; right: 0%; height: 4px;
  background: var(--lime); border-radius: 2px;
}
.price-range-input {
  position: absolute; inset: 0; width: 100%;
  -webkit-appearance: none; appearance: none;
  background: transparent; pointer-events: none;
  margin: 0; padding: 0; z-index: 4;
}
.price-range-input::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--lime); border: 2px solid var(--ink);
  cursor: grab; pointer-events: auto;
  margin-top: -7px;
  box-shadow: 0 1px 3px rgba(26,22,18,.2);
}
.price-range-input::-moz-range-thumb {
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--lime); border: 2px solid var(--ink);
  cursor: grab; pointer-events: auto;
  box-shadow: 0 1px 3px rgba(26,22,18,.2);
}
.price-range-presets {
  display: flex; gap: 4px; margin-top: 16px; flex-wrap: wrap;
}
.price-preset {
  background: transparent; color: var(--ink-soft);
  border: 1px solid var(--rule); border-radius: 4px;
  padding: 4px 8px;
  font: 700 10.5px var(--mono); letter-spacing: 0.4px;
  cursor: pointer;
}
/* Light: dark bg + lime text (12.93:1). Dark mode override pins a dark
   surface so lime text doesn't fall on cream (1.20:1). */
.price-preset.on { background: var(--ink); color: var(--lime); border-color: var(--ink); }
html[data-theme="dark"] .price-preset.on { background: #1a1612; color: var(--lime); border-color: #1a1612; }

.filter-clear {
  background: transparent; color: var(--coral-deep); border: none; padding: 6px 8px;
  font: 600 12.5px var(--sans); cursor: pointer; text-decoration: underline; text-underline-offset: 3px;
}
.filter-count {
  margin-left: auto;
  font: 500 11px var(--mono); color: var(--muted); letter-spacing: 0.4px;
  white-space: nowrap;
}

/* ── Watchlist heatmap table ──────────────────────────────────────────── */
.watchlist-card { overflow: hidden; background: var(--paper); }
.watchlist-grid-cols {
  display: grid; gap: 0;
  grid-template-columns: 32px 1.6fr .65fr .55fr .55fr .7fr .7fr .55fr .55fr .9fr .65fr;
}
/* v4 Layout (/packs): a 12th "Ceiling" (max multiple) column slots between
   ≥10× and CS Trigger; the wider tracks shave fractions to make room. */
.watchlist-grid-cols.has-ceiling {
  grid-template-columns: 32px 1.5fr .6fr .5fr .55fr .7fr .7fr .55fr .55fr .5fr .85fr .55fr;
}
.watchlist-head {
  padding: 14px 24px;
  background: var(--paper-dim); border-bottom: 1.5px solid var(--ink);
  align-items: center;
}
.watchlist-head > div {
  font: 700 10px var(--mono); letter-spacing: 1.2px;
  color: var(--muted); text-transform: uppercase;
}
.watchlist-head .right { text-align: right; padding-right: 8px; }
.watchlist-head .center { text-align: center; }
.watchlist-head .col-sort[data-align="center"] {
  display: flex; justify-content: center;
}
.watchlist-head .col-sort {
  color: var(--muted); cursor: pointer;
  display: inline-flex; align-items: center; gap: 4px;
}
.watchlist-head .col-sort.on { color: var(--ink); font-weight: 700; }
.watchlist-head .col-sort[data-align="right"] {
  display: flex; justify-content: flex-end;
}

.watchlist-row {
  padding: 14px 24px; align-items: center;
  font-size: 13.5px; font-variant-numeric: tabular-nums;
  border-bottom: 1px solid var(--rule-soft);
  color: inherit; text-decoration: none;
  transition: background 100ms ease;
}
.watchlist-row:last-child { border-bottom: none; }
.watchlist-row:hover { background: rgba(26, 22, 18, .04); text-decoration: none; }
.watchlist-row.zebra { background: rgba(26, 22, 18, .015); }
.watchlist-row.is-plus-ev { background: rgba(200, 232, 74, .08); }
html[data-theme="dark"] .watchlist-row:hover { background: rgba(246, 239, 217, .05); }
html[data-theme="dark"] .watchlist-row.zebra { background: rgba(246, 239, 217, .02); }
html[data-theme="dark"] .watchlist-row.is-plus-ev { background: rgba(200, 232, 74, .06); }
.watchlist-row.is-hidden { display: none; }

.watchlist-star { display: flex; align-items: center; justify-content: center; }
.star-btn {
  background: transparent; border: none; padding: 4px; cursor: pointer;
  color: var(--muted);
  border-radius: 4px;
}
.star-btn svg { display: block; }
.star-btn.is-on { color: var(--amber-deep); }
.star-btn.is-on svg { fill: var(--amber); stroke: var(--amber-deep); stroke-width: 1.2; }
.star-btn:not(.is-on) svg { stroke: currentColor; stroke-width: 1.2; }
.star-btn:hover { background: var(--rule-soft); color: var(--amber-deep); }

/* Watched-packs dashboard section */
.watched-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.watched-allpacks-link { font: 600 12px var(--mono); color: var(--lime-deep); text-decoration: none; white-space: nowrap; }
.watched-allpacks-link:hover { text-decoration: underline; }
.watched-empty-card { padding: 30px 24px; text-align: center; }
.watched-empty-card .we-star { font-size: 22px; color: var(--amber-deep); line-height: 1; margin-bottom: 8px; }
.watched-empty-card .we-lead { font: 700 15px var(--sans); color: var(--ink); margin: 0 0 6px; }
.watched-empty-card .we-sub { font-size: 13px; color: var(--ink-soft); margin: 0 auto; max-width: 460px; line-height: 1.5; }
.watched-empty-card .we-sub a { color: var(--lime-deep); font-weight: 600; text-decoration: none; }
.watched-empty-card .we-sub a:hover { text-decoration: underline; }

.watchlist-pack { display: flex; align-items: center; gap: 8px; }
.watchlist-pack .pack-name {
  font: 700 15px var(--display); letter-spacing: -0.2px; color: var(--ink);
}
.plus-ev-chip {
  font: 700 9.5px var(--mono); letter-spacing: 0.6px; text-transform: uppercase;
  /* on-lime keeps the chip readable in dark mode (12.93:1). */
  background: var(--lime); color: var(--on-lime);
  padding: 2px 6px; border-radius: 3px;
}
.sold-out-chip {
  font: 700 9.5px var(--mono); letter-spacing: 0.6px; text-transform: uppercase;
  background: var(--paper-dim); color: var(--muted);
  border: 1px solid var(--rule); padding: 1px 6px; border-radius: 3px;
}
/* Rip Mode active — a Pro member is ripping this pack right now. Pro-gated in
   the template. Gentle pulse to read as "live", reduced for motion-sensitive. */
.rip-chip {
  display: inline-block; font-size: 11px; line-height: 1; margin-left: 1px;
  cursor: default; animation: rip-pulse 1.6s ease-in-out infinite;
}
@keyframes rip-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
@media (prefers-reduced-motion: reduce) { .rip-chip { animation: none; } }
/* Sold-out rows: visible (when "Show sold out" is on) but clearly de-emphasized.
   Search results carry the same treatment — a retired pack stays findable there
   (its pack page still renders) and must not read as buyable. */
.watchlist-row.is-sold-out, .mobile-pack-card.is-sold-out,
.card-search-result.is-sold-out { opacity: 0.5; }
/* The result's EV slot says "Sold out" for these — not a +EV number. */
.card-search-result.is-sold-out .card-search-result-ev { color: var(--muted); }

.watchlist-row .price {
  text-align: right; padding-right: 8px;
  font-family: var(--mono); color: var(--ink-soft);
}

.watchlist-ss { display: flex; align-items: center; justify-content: center; }
.ss-locked {
  display: inline-flex; align-items: center; gap: 6px;
  font: 600 11.5px var(--mono); color: var(--muted);
  padding: 4px 8px; border-radius: 4px;
  border: 1px dashed var(--rule); cursor: help;
}
.watchlist-chev {
  display: flex; justify-content: flex-end;
  color: var(--muted); font: 400 18px var(--mono);
}

.watchlist-empty {
  padding: 60px 24px; text-align: center;
  font: 500 14px var(--sans); color: var(--muted);
}

/* ── Mobile pack cards ────────────────────────────────────────────────── */
.watchlist-mobile { display: none; flex-direction: column; gap: 10px; }
@media (max-width: 900px) {
  .watchlist-card { display: none; }
  .watchlist-mobile { display: flex; }
}

.mobile-pack-card {
  display: block; padding: 14px;
  background: var(--paper); border: 1.5px solid var(--ink);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card-sm);
  color: inherit; text-decoration: none;
}
.mobile-pack-card.is-plus-ev {
  background: rgba(200, 232, 74, .08);
  border-color: var(--lime-deep);
}
.mobile-pack-card.is-hidden { display: none; }

/* Rip Mode rows — a Pro member is actively ripping this pack. A clear green
   outline + tint so the row reads as "live" and stands out from +EV/zebra
   shading (placed after those rules so it wins on equal specificity). The
   pulsing ⚡ chip carries the motion; the row itself stays static. */
.watchlist-row.is-ripping {
  background: rgba(200, 232, 74, .16);
  box-shadow: inset 3px 0 0 0 var(--lime-deep), inset 0 0 0 1.5px rgba(90, 122, 24, .5);
}
.watchlist-row.is-ripping:hover { background: rgba(200, 232, 74, .22); }
html[data-theme="dark"] .watchlist-row.is-ripping { background: rgba(200, 232, 74, .10); }
.mobile-pack-card.is-ripping {
  background: rgba(200, 232, 74, .16);
  border-color: var(--lime-deep);
  box-shadow: inset 0 0 0 1.5px var(--lime-deep), var(--shadow-card-sm);
}
html[data-theme="dark"] .mobile-pack-card.is-ripping { background: rgba(200, 232, 74, .10); }

.mobile-pack-head {
  display: flex; justify-content: space-between; align-items: flex-start; gap: 10px;
}
.mobile-pack-id { display: flex; align-items: center; gap: 10px; min-width: 0; }
.mobile-pack-id .pack-name {
  font: 700 18px var(--display); letter-spacing: -0.3px; color: var(--ink);
  display: flex; align-items: center; gap: 6px;
}
.mobile-pack-meta {
  font: 500 11px var(--mono); color: var(--muted); margin-top: 2px; letter-spacing: 0.3px;
}
.mobile-pack-ev { text-align: right; flex-shrink: 0; }
.mobile-pack-ev-n {
  font: 800 22px var(--display); letter-spacing: -0.4px;
  font-variant-numeric: tabular-nums;
}
.mobile-pack-shape {
  margin-top: 10px; padding: 8px 10px;
  background: var(--paper-warm); border-radius: 6px;
  border: 1px solid var(--rule-soft);
  display: flex; align-items: center; gap: 10px;
}
.mobile-pack-shape .shape-mini-wide { width: 120px; height: 26px; display: block; }
.mobile-pack-stats {
  display: flex; gap: 18px; margin-top: 10px;
  font: 500 11.5px var(--mono);
}
.mobile-pack-stats .lbl { display: block; font-size: 9px; letter-spacing: 1.2px; }
.mobile-pack-stats .num { color: var(--ink-soft); font-weight: 600; }
.mobile-pack-stats .num.muted { color: var(--muted); font-weight: 500; }
.mobile-pack-stats .num.ss-buy   { color: var(--lime-deep); }
.mobile-pack-stats .num.ss-lean  { color: var(--amber-deep); }
.mobile-pack-stats .num.ss-skip  { color: var(--muted); }
.mobile-pack-stats .num.ss-avoid { color: var(--coral-deep); }

/* v4 Layout — mobile card additions: watch star (44px-ish touch target that
   doesn't inflate the card) and heat chips matching the desktop table cells
   (backgrounds arrive inline from the same heat_* helpers). */
.mobile-star { padding: 10px; margin: -8px 2px -8px -8px; flex-shrink: 0; }
.mobile-star svg { width: 16px; height: 16px; }
.mobile-pack-stats .num-heat {
  display: inline-block; padding: 2px 6px; margin-top: 2px; border-radius: 4px;
  font-variant-numeric: tabular-nums;
}
.mobile-pack-ev-n.ev-heat {
  padding: 1px 8px; border-radius: 6px;
}

/* ── Free floor reminder ──────────────────────────────────────────────── */
.watchlist-floor {
  margin-top: 14px;
  font: 700 10.5px var(--mono); color: var(--muted);
  letter-spacing: 0.5px; text-align: center; text-transform: uppercase;
}
.watchlist-floor .upgrade-link {
  color: var(--coral-deep); font-weight: 700; text-decoration: underline;
}

/* ═══════════════════════════════════════════════════════════════════════
   Pack Detail page
   ═══════════════════════════════════════════════════════════════════════ */

.pack-detail {
  max-width: var(--max-width); margin: 0 auto;
  padding: 24px var(--page-pad) 64px;
}
.breadcrumb .sep { color: var(--muted); opacity: 0.5; }
.pack-detail-header {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
}
.pack-detail-id {
  display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap;
}
.pack-name-xl {
  font: 800 60px var(--display); letter-spacing: -2px; line-height: 1;
  color: var(--ink); margin: 0;
}
.pack-price-xl {
  font: 700 24px var(--display); color: var(--ink-soft);
}
.vel-pulse {
  display: inline-flex; align-items: center; gap: 5px;
  font: 700 11px var(--mono); letter-spacing: 0.4px; text-transform: uppercase;
}
.vel-pulse.vel-hot    { color: var(--coral-deep); }
.vel-pulse.vel-hot    .dot { background: var(--coral-deep); }
.vel-pulse.vel-warm   { color: var(--amber-deep); }
.vel-pulse.vel-warm   .dot { background: var(--amber-deep); }
.vel-pulse.vel-cool   { color: var(--sky-deep); }
.vel-pulse.vel-cool   .dot { background: var(--sky-deep); }
.vel-pulse.vel-frozen { color: var(--muted); }
.vel-pulse.vel-frozen .dot { background: var(--muted); }
.vel-pulse .dot { width: 7px; height: 7px; }
@media (max-width: 760px) {
  .pack-name-xl { font-size: 38px; letter-spacing: -1.4px; }
  .pack-price-xl { font-size: 18px; }
  /* Actions take the full width and the Arena Club CTA drops to its own row so
     nothing scrolls off the edge on a phone. Watch + Rip Mode sit on the row
     above; the CTA spans full width (and is comfortably tappable). */
  .pack-detail-actions { width: 100%; }
  .pack-detail-actions .ac-cta { flex: 1 1 100%; justify-content: center; }
}

.pack-detail-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; flex-wrap: wrap; }
.watch-btn {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--paper-warm); color: var(--ink-soft);
  border: 1.5px solid var(--rule); border-radius: 6px;
  padding: 9px 14px;
  font: 700 13px var(--sans); cursor: pointer;
}
.watch-btn svg { stroke: var(--muted); stroke-width: 1.4; }
.watch-btn.is-on {
  background: var(--amber-soft); color: var(--amber-deep); border-color: var(--amber-deep);
}
.watch-btn.is-on svg { fill: var(--amber); stroke: var(--amber-deep); }

/* Rip Mode boost button — mirrors .watch-btn but with a lime "go/energy"
   accent. Active state (boost running) fills lime to read as live. */
/* Idle Rip Mode button: a lime-tinted "feature" affordance (the lightning icon
   carries the energy) so it reads as more than a second Watch button. */
.boost-btn {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--lime-soft); color: var(--ink);
  border: 1.5px solid var(--lime-deep); border-radius: 6px;
  padding: 9px 14px;
  font: 700 13px var(--sans); cursor: pointer;
  text-decoration: none;
}
.boost-btn svg { fill: var(--lime-deep); }
.boost-btn:hover { background: var(--lime); border-color: var(--lime-deep); color: var(--ink); text-decoration: none; }
/* Active: solid lime fill + a live pulsing dot before the label. */
.boost-btn.is-on {
  background: var(--lime); color: var(--on-lime); border-color: var(--lime-deep);
  box-shadow: 0 0 0 3px var(--lime-soft);
}
.boost-btn.is-on svg { fill: var(--on-lime); }
.boost-btn:disabled { opacity: 0.6; cursor: default; }
/* Locked (free) variant stays muted — it's an upsell, not the live feature. */
.boost-btn-locked { background: var(--paper-warm); color: var(--muted); border-color: var(--rule); }
.boost-btn-locked svg { stroke: var(--muted); fill: none; }
.boost-msg { font: 600 12px var(--sans); color: var(--coral-deep); padding-left: 6px; align-self: center; }

/* Brief highlight when a live (Rip Mode) refresh changes the hero EV number. */
@keyframes ev-flash { from { background: var(--lime-soft); } to { background: transparent; } }
.hero-ev-numeral.ev-flash { animation: ev-flash 1.2s ease-out; border-radius: 6px; }

/* ── Rip Mode live treatment ─────────────────────────────────────────── */
/* Pulsing "live" dot, shared by the banner + shared chip. */
@keyframes rip-dot-pulse { 0%,100% { opacity: 1; transform: scale(1); } 50% { opacity: .35; transform: scale(.7); } }
.rip-banner-dot {
  width: 9px; height: 9px; border-radius: 50%; background: var(--coral-deep);
  flex-shrink: 0; animation: rip-dot-pulse 1.3s ease-in-out infinite;
}

/* Booster's full banner — prominent strip under the header while YOU rip. */
.rip-banner {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 14px 0 4px; padding: 10px 14px; border-radius: 8px;
  background: var(--lime-soft); border: 1.5px solid var(--lime-deep);
  font: 600 13.5px var(--sans); color: var(--ink);
}
.rip-banner-time { color: var(--ink-soft); font-weight: 700; }
.rip-banner-stop {
  /* Light mode: dark bg + lime text (12.93:1). */
  margin-left: auto; background: var(--ink); color: var(--lime);
  border: none; border-radius: 5px; padding: 6px 12px;
  font: 700 12px var(--sans); cursor: pointer;
}
.rip-banner-stop:hover { background: #000; }
/* Dark mode: lime bg + theme-fixed dark text (12.93:1), matching the boost
   button it pairs with. Was --ink, which flips to cream and dropped the lime
   text to 1.20:1. */
html[data-theme="dark"] .rip-banner-stop { background: var(--lime); color: var(--on-lime); }
html[data-theme="dark"] .rip-banner-stop:hover { background: var(--lime-deep); color: var(--on-lime); }

/* Other Pro viewers — lighter "someone's ripping" chip, no controls. */
.rip-shared {
  display: flex; align-items: center; gap: 9px;
  margin: 14px 0 4px; padding: 8px 13px; border-radius: 8px;
  background: var(--paper-warm); border: 1px solid var(--rule);
  font: 600 13px var(--sans); color: var(--ink-soft);
}

/* Idle helper — explains the feature; hidden by JS once live. */
.rip-helper {
  display: flex; align-items: center; gap: 7px;
  margin: 12px 0 2px; color: var(--muted); font: 500 12.5px var(--sans);
}
.rip-helper svg { fill: var(--lime-deep); flex-shrink: 0; }
.rip-helper strong { color: var(--ink-soft); }
/* These default to display:flex above, which would otherwise beat the `hidden`
   attribute (equal specificity → source order). Re-assert hidden so JS can
   actually show/hide them (e.g. the booster shouldn't see the shared chip). */
.rip-banner[hidden], .rip-shared[hidden], .rip-helper[hidden] { display: none; }

/* "LIVE" pill next to the Current EV label — only while live (mine or shared). */
.ev-live-pill {
  display: none; align-items: center; gap: 4px; margin-left: 8px;
  padding: 1px 7px; border-radius: 999px; vertical-align: middle;
  background: var(--coral-deep); color: #fff;
  font: 800 10px var(--sans); letter-spacing: .06em;
}
.ev-live-pill .dot { width: 5px; height: 5px; border-radius: 50%; background: #fff; animation: rip-dot-pulse 1.3s ease-in-out infinite; }
body.rip-active .ev-live-pill, body.is-rip-shared .ev-live-pill { display: inline-flex; }

/* "checking for updates…" — appears next to the freshness stamp once a live
   reading ages past ~60s (toggled by freshness.js), so the climbing timer reads
   as actively working in the background rather than stuck. */
/* Sits NEXT TO the freshness chip (sibling of .delay-badge), no background of
   its own, so showing it never resizes the chip. */
.delay-checking { display: none; align-items: center; gap: 5px; margin-left: 8px; color: var(--lime-deep); font-weight: 700; vertical-align: middle; }
.delay-checking .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--lime-deep); animation: rip-dot-pulse 1.1s ease-in-out infinite; }
.hero-ev-status.is-checking .delay-checking { display: inline-flex; }

/* Live EV card: lime ring so the headline number reads as live. */
body.rip-active .hero-ev, body.is-rip-shared .hero-ev {
  border-radius: 10px;
  box-shadow: 0 0 0 2px var(--lime-deep), 0 0 18px -6px var(--lime-deep);
}
body.rip-active .pack-detail, body.is-rip-shared .pack-detail { position: relative; }
body.rip-active .pack-detail::before {
  content: ""; position: fixed; left: 0; right: 0; top: 0; height: 3px;
  background: var(--lime-deep); z-index: 50;
}

.btn.ac-cta {
  /* Light: dark bg + lime text (12.93:1). */
  background: var(--ink); color: var(--lime);
  border: 1.5px solid var(--lime); border-radius: 6px;
  padding: 11px 20px;
  font: 700 14px var(--sans);
  display: inline-flex; align-items: center; gap: 8px;
}
.btn.ac-cta.big { padding: 13px 24px; font-size: 15px; }
.btn.ac-cta:hover { background: #000; text-decoration: none; }
/* Dark: lime bg + theme-fixed dark text (12.93:1). Hover uses lime-deep
   which is the brighter #a8d028 in dark mode → on-lime gives 8.5:1. */
html[data-theme="dark"] .btn.ac-cta { background: var(--lime); color: var(--on-lime); border-color: var(--lime); }
html[data-theme="dark"] .btn.ac-cta:hover { background: var(--lime-deep); color: var(--on-lime); }

/* In the pack-header action row, the Arena Club link is a PEER action, not the
   loudest element — we're independent and neutral on whether you rip, so it
   shouldn't out-shout Watch / Rip Mode. Demote it to the understated Watch-style
   weight here. The bold dark+lime treatment stays for the page-end .big CTA. */
.pack-detail-actions .ac-cta {
  background: var(--paper-warm); color: var(--ink-soft);
  border: 1.5px solid var(--rule);
  padding: 9px 14px; font: 700 13px var(--sans);
}
.pack-detail-actions .ac-cta:hover { background: var(--paper); border-color: var(--ink-soft); color: var(--ink); }
html[data-theme="dark"] .pack-detail-actions .ac-cta { background: var(--paper-warm); color: var(--ink-soft); border-color: var(--rule); }
html[data-theme="dark"] .pack-detail-actions .ac-cta:hover { background: var(--paper); color: var(--ink); }

/* ── Hero EV anchor ──────────────────────────────────────────────────── */
.hero-ev {
  margin-top: 28px;
  display: grid; grid-template-columns: auto 1fr; gap: 32px;
  align-items: end;
  padding: 24px 28px;
  background: var(--paper-warm);
  border: 2px solid var(--ink); border-radius: var(--radius-card);
}
.hero-ev.is-plus-ev {
  background: rgba(200, 232, 74, .08);
  border-color: var(--lime-deep);
}
.hero-ev-numeral {
  font: 800 108px var(--display); letter-spacing: -4px; line-height: 0.92;
  font-variant-numeric: tabular-nums; margin-top: 4px;
}
.hero-ev-pct { font-size: 56px; }
.hero-ev-status {
  font: 500 11.5px var(--mono); color: var(--muted);
  margin-top: 6px; letter-spacing: 0.4px;
}
.hero-ev-live {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--lime-deep); font-weight: 700;
}
.hero-ev-supporting {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 0;
  border-left: 1px solid var(--rule); padding-left: 28px;
}
.hero-supp { padding: 8px 12px; }
.hero-supp-n {
  font: 800 28px var(--display); letter-spacing: -0.5px;
  margin-top: 2px; line-height: 1;
}
.hero-supp-sub {
  font: 500 10.5px var(--mono); color: var(--muted); margin-top: 2px;
}
@media (max-width: 900px) {
  .hero-ev { grid-template-columns: 1fr; gap: 14px; padding: 20px 18px; }
  .hero-ev-numeral { font-size: 72px; letter-spacing: -3px; }
  .hero-ev-pct { font-size: 40px; }
  .hero-ev-supporting { grid-template-columns: repeat(3, 1fr); border-left: none; padding-left: 0; border-top: 1px solid var(--rule); padding-top: 8px; }
  .hero-supp-n { font-size: 22px; }
}

/* ── Detail trajectory ───────────────────────────────────────────────── */
.detail-trajectory { margin-top: 22px; padding: 22px 24px; background: var(--paper-warm); }
/* Relative wrap so the HTML y-axis label overlay (.trajectory-y) can sit on
   top of the SVG, positioned by each tick's top_pct. */
.detail-trajectory .ev-traj-wrap { position: relative; }
.detail-trajectory .ev-traj-svg { width: 100%; height: 220px; margin-top: 0; }
.trajectory-range { font: 500 11px var(--mono); color: var(--muted); margin-top: 4px; }

/* ── 4-up stat tiles ─────────────────────────────────────────────────── */
.stat-grid-4 {
  margin-top: 16px;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px;
}
@media (max-width: 1100px) { .stat-grid-4 { grid-template-columns: repeat(2, 1fr); } }

.ss-verdict-tile {
  padding: 16px 18px;
}
.ss-verdict-state {
  font: 800 24px var(--display); letter-spacing: -0.5px; margin-top: 6px;
  display: flex; align-items: center; gap: 8px;
}
.ss-verdict-buy   { color: var(--lime-deep); }
.ss-verdict-lean  { color: var(--amber-deep); }
.ss-verdict-skip  { color: var(--muted); }
.ss-verdict-avoid { color: var(--coral-deep); }
.ss-verdict-muted { color: var(--muted); }
.ss-verdict-pro   { color: var(--muted); }
/* Odds-first Collect Safe: the % headline in the tile + the small unit after it. */
.ss-pays-unit { font: 600 12px var(--sans); color: var(--muted); letter-spacing: 0; }
/* Collect Safe floor % as it appears in the /packs + dashboard columns — a plain,
   judgment-free number (no buy/skip color). */
.ss-pays { font: 600 13px var(--mono); color: var(--ink-soft); }
.ss-verdict-reason {
  font: 500 13px var(--sans); color: var(--ink-soft);
  margin-top: 8px; line-height: 1.45;
}
.ss-verdict-locked { background: var(--paper-warm); }

/* ── Activity feed ───────────────────────────────────────────────────── */
.activity-card { position: relative; }
.activity-head {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: 14px; gap: 8px;
}
.activity-sub {
  font: 500 11px var(--mono); color: var(--muted); margin-top: 4px;
}
/* Right side of the card head: "See all →" into the history modal, then the
   live pulse dot keeping its original far-right position. */
.activity-head-right { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; }
.activity-all {
  font: 600 11px var(--mono); color: var(--sky-deep); text-decoration: none;
  border-bottom: 1px solid rgba(42, 119, 153, .35); white-space: nowrap;
}
.activity-all:hover, .activity-all:focus-visible { border-bottom-color: var(--sky-deep); }
.activity-list { display: flex; flex-direction: column; gap: 0; }
.activity-list.is-blurred { filter: blur(4px); pointer-events: none; user-select: none; }
.activity-row {
  display: grid; grid-template-columns: 24px 1fr auto;
  align-items: baseline; gap: 8px;
  padding: 10px 0;
  border-bottom: 1px solid var(--rule-soft);
}
.activity-row:last-child { border-bottom: none; }
.activity-icon {
  font: 700 16px var(--mono); text-align: center;
}
.activity-label { font: 500 12.5px var(--sans); color: var(--ink); line-height: 1.4; }
.activity-when  { font: 500 10.5px var(--mono); color: var(--muted); margin-top: 1px; letter-spacing: 0.3px; }
.activity-value {
  font: 700 11.5px var(--mono); color: var(--ink-soft);
  font-variant-numeric: tabular-nums; text-align: right;
}
.activity-empty {
  padding: 24px 8px; text-align: center;
  font: 500 13px var(--sans); color: var(--muted);
}
.activity-overlay {
  position: absolute; inset: 0; border-radius: var(--radius-card);
  background: rgba(247, 241, 222, .6); backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px;
}
html[data-theme="dark"] .activity-overlay { background: rgba(26, 22, 18, .7); }
.activity-overlay-eyebrow {
  display: flex; align-items: center; gap: 8px;
  font: 700 11px var(--mono); color: var(--muted);
  letter-spacing: 0.6px; text-transform: uppercase;
}
.activity-overlay-headline {
  font: 700 18px var(--display); letter-spacing: -0.3px; color: var(--ink);
  text-align: center; max-width: 280px; padding: 0 20px;
}

/* ── Mini trend sparkline (in card pool table) ───────────────────────── */
.trend-cell {
  text-align: right;
  font: 500 11px var(--mono); color: var(--muted);
}
.mini-trend { width: 60px; height: 18px; display: inline-block; vertical-align: middle; }

/* ── Card pool table grid spacing (override packs.html legacy) ───────── */
/* Set·grade gets 2fr (was 1.5fr): long set names were ellipsising almost
   immediately, and for admins the truncation swallowed the cert ↗ / fix ↗
   links riding the cell. The other columns give up the ~6% proportionally. */
.pool-grid-cols {
  grid-template-columns: 32px 2.2fr 2fr .9fr .7fr .8fr .8fr .8fr .65fr;
}
@media (max-width: 1000px) {
  .pool-grid-cols { grid-template-columns: 28px 2fr 1.55fr .8fr .6fr .7fr .7fr .7fr .55fr; }
}
@media (max-width: 760px) {
  /* On narrow screens, collapse to: rank · card · trend · value+ev */
  .pool-head, .pool-row {
    grid-template-columns: 18px 1fr auto auto;
    padding: 12px 14px;
  }
  .pool-head > div:nth-child(3),
  .pool-head > div:nth-child(5),
  .pool-head > div:nth-child(7),
  .pool-head > div:nth-child(8),
  .pool-head > div:nth-child(9),
  .pool-row .set-cell,
  .pool-row .hcell-vp,
  .pool-row .hcell-p,
  .pool-row .hcell-evc,
  .pool-row .added { display: none; }

  /* v4 Layout: keep all nine pool columns and scroll sideways instead of
     hiding data (the My-pulls table pattern). Overrides the collapse above;
     Classic is untouched — .pool-scroll has no styles outside body.ui-v4.
     Scoped under .pool-scroll so the flex .pool-head of the pool-composition
     section (same class, different element) is never affected. */
  .ui-v4 .pool-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .ui-v4 .pool-scroll .pool-head,
  .ui-v4 .pool-scroll .pool-row,
  .ui-v4 .pool-scroll .pool-sum { min-width: 700px; }
  .ui-v4 .pool-scroll .pool-head,
  .ui-v4 .pool-scroll .pool-row {
    grid-template-columns: 28px 2fr 1.2fr .8fr .6fr .7fr .7fr .7fr .55fr;
    padding: 12px 14px;
  }
  .ui-v4 .pool-scroll .pool-head > div:nth-child(3),
  .ui-v4 .pool-scroll .pool-head > div:nth-child(5),
  .ui-v4 .pool-scroll .pool-head > div:nth-child(7),
  .ui-v4 .pool-scroll .pool-head > div:nth-child(8),
  .ui-v4 .pool-scroll .pool-head > div:nth-child(9),
  .ui-v4 .pool-scroll .pool-row .set-cell,
  .ui-v4 .pool-scroll .pool-row .hcell-vp,
  .ui-v4 .pool-scroll .pool-row .hcell-p,
  .ui-v4 .pool-scroll .pool-row .hcell-evc,
  .ui-v4 .pool-scroll .pool-row .added { display: block; }
}

/* Columns picker chip (pool table) — rendered in the live fragment but only
   shown on v4 phones, where the table scrolls sideways and a curated default
   subset is visible. dashboard.js initPoolCols owns its behavior + the
   generated per-choice stylesheet; without JS the chip stays inert and the
   static full-table scroll above applies. */
.pool-cols-chip { display: none; }
/* The chip's show-rule lives in initPoolCols' generated stylesheet (it must
   beat the chip's inline display:none, and only exist when the JS runs). */
/* 641-760px band ONLY: the chip sits at the right edge of the section head,
   so right-anchor its dropdown to keep it on-screen. This must NOT extend
   down to ≤640px: this block sits later in the file than the shared
   bottom-sheet rules, so a max-width:760 version of it also overrode the
   sheet's left:12px on phones — collapsing the full-width sheet into a
   narrow right-pinned column directly under the floating support bubble.
   ≤640px now presents the standard centered bottom sheet, same as the
   pack-list filter chips. */
@media (min-width: 641px) and (max-width: 760px) {
  .pool-cols-popover { left: auto; right: 0; }
}
/* Phones held upright: narrow the Columns sheet to 60% and center it, so
   there's clear whitespace either side (reads as a dialog, and the ~20%
   right gutter keeps its rows fully clear of the floating support bubble).
   Comfortable because the sheet is a single-column checklist of short
   labels — revisit if it ever gains long option names. Later in the file
   than the shared bottom-sheet rules, so left/right win at equal
   specificity; landscape keeps the standard full-width sheet. */
@media (max-width: 640px) and (orientation: portrait) {
  .pool-cols-popover { left: 20%; right: 20%; }
}
.filter-opt.is-locked { opacity: .55; cursor: default; }
.filter-opt.is-locked .check { visibility: visible; }
.pool-cols-reset {
  color: var(--coral-deep); border-top: 1px solid var(--rule-soft);
  border-radius: 0; margin-top: 4px;
}
.pool-cols-reset .check { display: none; }

/* ── Reusable section header (pack detail card pool intro) ───────────── */
.card-pool-section { margin-top: 32px; }
.card-pool-section .section-head h2 {
  font: 800 30px var(--display); letter-spacing: -1px;
}
@media (max-width: 760px) {
  .card-pool-section .section-head h2 { font-size: 22px; letter-spacing: -0.8px; }
}

/* ── Mark variant: amber chip (grail chip in pool intro) ─────────────── */
.mark.mark-amber > span { color: var(--amber-deep); }

/* ── Dark-mode targeted overrides for legacy components ──────────────── */
html[data-theme="dark"] .ss-buy   .ss-dot { background: var(--lime); }
html[data-theme="dark"] body { background: var(--paper); color: var(--ink); }
html[data-theme="dark"] .card { box-shadow: var(--shadow-card); }
html[data-theme="dark"] .delay-badge { background: var(--amber-soft); color: var(--amber); }
html[data-theme="dark"] .star-btn.is-on svg { fill: var(--amber); }

/* Inverted CTA strips (signup-cta-inner, final-cta-inner) are designed as
   "dark card with cream text + lime accents". In dark mode without override,
   --ink flips to cream and the strip becomes a light card — lime accents
   inside (.chip-eyebrow-lime, .chip-price-now,
   .final-cta-eyebrow, and the .mark.mark-lime fill bar) would land on cream
   and drop to ~1.2:1 (lime-on-cream). Scoping the design tokens within these
   strips pins them to their light-mode values, so the dark-card design is
   preserved and every lime accent stays on a dark surface (≥10:1). The
   strip is delineated from the dark page bg with an explicit pale border. */
html[data-theme="dark"] .signup-cta-inner,
html[data-theme="dark"] .final-cta-inner {
  --paper:      #f7f1de;
  --paper-dim:  #ede5cb;
  --ink:        #1a1612;
  --ink-soft:   #2e2820;
  --lime-deep:  #5a7a18;
  border-color: rgba(246, 239, 217, 0.16);
}


/* ── In-app messages: bell + popover + banner ─────────────────────────────
   The bell reuses the account-menu popover mechanics (data-account-menu in
   dashboard.js); these rules only add the icon, the unread badge, the
   popover item rows, and the pinned banner under the topbar. */
/* Pull the bell toward the avatar: the topbar's 22px flex gap is right for
   unrelated nav items, but bell + avatar are one "account cluster" — a net
   ~12px reads as grouped. (Negative margin offsets the flex gap; the
   tablet/phone topbar blocks use smaller gaps, so they re-tune it.) */
.msg-bell, .refer-gift { margin-right: -10px; }
@media (min-width: 481px) and (max-width: 1024px) {
  .msg-bell, .refer-gift { margin-right: -4px; }
}
@media (max-width: 480px) {
  .msg-bell, .refer-gift { margin-right: 0; }
}
/* Gift badge shows banked dollars — lime, not coral: it's good news, not an
   unread count. The canonical pairing from the a11y box at the top of this
   file: theme-fixed lime fill + theme-fixed near-black text (~8.9:1 in both
   modes). NOT lime-deep — that token theme-flips lightness, so no single
   text color clears 4.5:1 on it in both themes (white fails dark at ~1.8:1,
   on-lime fails light at ~3.4:1 — the round-2 review catch on PR #733).
   COMPOUND selector on purpose: the badge also carries .msg-bell-badge,
   whose coral/white rule sits LATER in this file — at equal specificity the
   later rule wins the tie and this fix never renders (the round-4 catch,
   and the same source-order trap the .msg-bell-icon comment below already
   warns about). The two-class selector outranks it from any position. */
.msg-bell-badge.refer-gift-badge { background: var(--lime); color: var(--on-lime); }
.msg-bell-icon {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 50%;
  border: 1.5px solid var(--ink); background: var(--paper-warm); color: var(--ink);
  transition: background 120ms ease;
}
.account-trigger:hover .msg-bell-icon { background: var(--paper-dim); }
/* Match the avatar's mobile shrink (32px under 480px). This MUST live after
   the base rule above: media queries don't add specificity, so an earlier
   override would lose to this base on source order (the bug in the first
   attempt, where the override sat ~3000 lines up). */
@media (max-width: 480px) {
  .msg-bell-icon { width: 32px; height: 32px; }
}
.msg-bell-badge {
  position: absolute; top: -4px; right: -5px;
  min-width: 16px; height: 16px; padding: 0 4px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--coral-deep, #b3402a); color: #fff;
  border: 1.5px solid var(--paper); border-radius: 999px;
  font: 700 9px var(--mono); letter-spacing: 0;
}
.msg-popover { min-width: 280px; }
.msg-popover-item { display: flex; align-items: center; gap: 8px; }
.msg-popover-dot {
  flex: none; width: 7px; height: 7px; border-radius: 50%;
  background: transparent;
}
.msg-popover-item.msg-unread .msg-popover-dot { background: var(--lime-deep); }
.msg-popover-item.msg-unread .msg-popover-subject { font-weight: 700; }
.msg-popover-subject {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  max-width: 220px;
}
.msg-popover-empty {
  display: block; padding: 8px 10px;
  font: 500 12px var(--mono); color: var(--muted);
}

.msg-banner {
  display: flex; align-items: center; gap: 12px;
  max-width: 1200px; margin: 14px auto 0;
  padding: 10px 16px;
  background: var(--lime-soft, #f2f7d4); border: 1.5px solid var(--ink);
  border-radius: var(--radius-medium, 10px);
  box-shadow: var(--shadow-card);
}
.msg-banner-text {
  flex: 1; min-width: 0;
  font: 600 13.5px var(--sans); color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.msg-banner-link {
  flex: none; font: 700 13px var(--sans); color: var(--ink);
  text-decoration: underline;
}
.msg-banner-dismiss {
  flex: none; background: none; border: none; cursor: pointer;
  font: 700 18px var(--sans); line-height: 1; color: var(--ink-soft);
  padding: 2px 6px; border-radius: 6px;
}
.msg-banner-dismiss:hover { background: rgba(26, 22, 18, 0.08); }
@media (max-width: 720px) {
  .msg-banner { margin: 10px 12px 0; }
}
/* Dunning variant (card failing, Stripe retrying). Amber, not coral: coral is
   already spoken for by the destructive surfaces (.del-banner, .down-loss), and
   a red bar on every page for the length of a three-week retry window trains
   people to stop seeing it. Nothing is lost yet — this is a nudge, not an
   alarm. */
.msg-banner-warn {
  background: var(--amber-soft);
  border-color: var(--amber-deep);
}
.msg-banner-warn .msg-banner-link { color: var(--amber-deep); }

/* ── Getting-started strip (dashboard, new accounts) ───────────────────── */
.gs-strip {
  background: var(--paper-warm); border: var(--card-border);
  border-radius: var(--radius-card); padding: 14px 16px; margin-bottom: 18px;
}
.gs-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 10px;
}
.gs-dismiss {
  background: none; border: none; cursor: pointer;
  font: 700 18px var(--sans); line-height: 1; color: var(--ink-soft);
  padding: 2px 6px; border-radius: 6px;
}
.gs-dismiss:hover { background: rgba(26, 22, 18, 0.08); }
.gs-steps {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;
}
.gs-step {
  display: flex; gap: 10px; align-items: flex-start; text-decoration: none;
  background: var(--paper); border: 1.5px solid var(--rule);
  border-radius: var(--radius-medium); padding: 10px 12px; color: var(--ink);
}
.gs-step:hover { border-color: var(--ink); }
.gs-check {
  flex: none; width: 22px; height: 22px; border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center;
  font: 700 12px var(--mono); border: 1.5px solid var(--ink);
  background: var(--paper-dim); color: var(--ink);
}
.gs-step.is-done .gs-check {
  background: var(--lime); color: var(--on-lime, #1a1612);
}
.gs-step.is-done .gs-step-body strong { text-decoration: line-through; opacity: 0.65; }
.gs-step-body { display: block; min-width: 0; }
.gs-step-body strong { display: block; font: 700 13px var(--sans); }
.gs-step-body span { display: block; font: 500 12px var(--sans); color: var(--muted); margin-top: 2px; }
@media (max-width: 720px) {
  .gs-steps { grid-template-columns: 1fr; }
}

/* ── Freshness: reconnecting pill + still-watching modal (freshness.js) ──
   Injected on every non-admin page by freshness.js. The pill appears when a
   refresh probe fails (deploy blip / flap) — the page stays up, the pill says
   so honestly. The modal is the idle gate: refreshing paused, data age stated
   plainly, one tap to go live. Tokens only, so both themes just work. */
.fresh-pill {
  position: fixed; bottom: 18px; left: 50%; transform: translateX(-50%);
  z-index: 300; display: flex; align-items: center; gap: 9px;
  padding: 9px 16px; max-width: calc(100vw - 32px); box-sizing: border-box;
  background: var(--paper-warm); color: var(--ink-soft);
  border: 1.5px solid var(--ink); border-radius: 999px;
  font: 600 12.5px var(--mono); box-shadow: var(--shadow-card);
}
.fresh-pill[hidden] { display: none; }
.fresh-pill-spinner {
  width: 12px; height: 12px; flex: none; border-radius: 50%;
  border: 2px solid var(--rule); border-top-color: var(--lime-deep);
  animation: fresh-spin 0.9s linear infinite;
}
@keyframes fresh-spin { to { transform: rotate(360deg); } }

.fresh-modal { position: fixed; inset: 0; z-index: 400; display: flex; align-items: center; justify-content: center; }
.fresh-modal[hidden] { display: none; }
.fresh-modal-backdrop {
  position: absolute; inset: 0;
  background: rgba(26, 22, 18, .48);
  backdrop-filter: blur(2.5px); -webkit-backdrop-filter: blur(2.5px);
}
.fresh-modal-card {
  position: relative; width: min(400px, calc(100vw - 40px));
  background: var(--paper-warm); border: 2px solid var(--ink);
  border-radius: var(--radius-card); box-shadow: var(--shadow-card);
  padding: 30px 28px 24px; text-align: center;
}
.fresh-modal-card h2 {
  font: 800 24px var(--display); letter-spacing: -0.4px;
  margin: 0 0 10px; color: var(--ink);
}
.fresh-modal-card p { font: 400 14.5px var(--sans); line-height: 1.55; color: var(--ink-soft); margin: 0 0 20px; }
.fresh-modal-cta {
  display: block; width: 100%; box-sizing: border-box; padding: 13px 16px;
  font: 700 15px var(--sans); cursor: pointer;
  background: var(--lime); color: var(--on-lime);
  border: 1.5px solid var(--ink); border-radius: var(--radius-medium);
}
.fresh-modal-cta:hover { background: var(--lime-deep); color: var(--paper); }
.fresh-modal-cta:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
.fresh-modal-note { font: 500 11.5px var(--mono); color: var(--muted); line-height: 1.5; margin: 14px 0 0 !important; }
