:root {
  --bg: #0b0e14;
  --panel: #121722;
  --panel-2: #171d2a;
  --line: #232b3b;
  --text: #e6edf7;
  --muted: #8b97ad;
  /* Measured 3.21:1 on --panel at the old #5d6880, below the 4.5:1 AA needs for
     body text -- and it carries most of the small print. #7b879c measures
     4.94:1 while staying clearly quieter than --muted. */
  --dim: #7b879c;
  --up: #34d399;
  --down: #f87171;
  --accent: #60a5fa;
  --warn: #fbbf24;
  --violet: #c084fc;
  --radius: 10px;

  /* Fixed z-index scale. Arbitrary values drift into conflicts as surfaces are
     added; these are the only layers this app has. */
  --z-base: 1;
  --z-sticky: 100;
  --z-overlay: 200;
  --z-modal: 300;
  /* Shared so the thumbnails and the expand controls promise the same thing. */
  --cursor-zoom: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Cg fill='none' stroke='%23ffffff' stroke-width='5.5' stroke-linecap='round'%3E%3Ccircle cx='13' cy='13' r='8.6'/%3E%3Cpath d='M19.3 19.3 28 28'/%3E%3C/g%3E%3Ccircle cx='13' cy='13' r='8.6' fill='rgba(255,255,255,0.55)' stroke='%23141414' stroke-width='2.4'/%3E%3Cpath d='M19.3 19.3 28 28' stroke='%23141414' stroke-width='3.4' stroke-linecap='round'/%3E%3Cpath d='M9.2 13h7.6M13 9.2v7.6' stroke='%23141414' stroke-width='2.1' stroke-linecap='round'/%3E%3C/svg%3E") 13 13, zoom-in;
  --z-chart: 320;
  --z-tooltip: 400;

  /* Spacing rhythm, so panels and sections share one vertical scale. */
  --gap-xs: 6px;
  --gap-sm: 10px;
  --gap-md: 14px;
  --gap-lg: 22px;
  --gap-xl: 34px;

  /* Elevation. Panels sit flat, things that float get progressively more lift. */
  --shadow-sm: 0 1px 2px rgba(4, 7, 14, 0.5);
  --shadow-md: 0 4px 14px rgba(4, 7, 14, 0.55);
  --shadow-lg: 0 18px 44px rgba(3, 5, 11, 0.62);

  /* Surfaces that cannot be derived from the palette above: a hover border
     brighter than --line, and the tooltip and banner, which are deliberately
     contrasted against the page rather than matching a panel. */
  --line-strong: #35405a;
  /* The extended-hours band on an intraday chart. --panel-2 is too close to
     the panel it sits on in dark to register as a separate session. */
  --chart-ext: #1f2939;
  --ring-accent: var(--ring-accent);
  --tip-bg: #1b2231;
  --tip-line: #33405a;
  --tip-text: #e6edf7;
  --banner-bg: #2a2410;
  --banner-line: #4a3f18;
  --overlay: rgba(4, 6, 10, 0.66);
  /* Geist for the interface, Geist Mono for every figure. A real mono matters
     here: the tables are the product, and system mono stacks render at
     different widths on each OS. */
  --font: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --mono: "Geist Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 14px/1.5 var(--font);
  -webkit-font-smoothing: antialiased;
}

/* ---------- top bar ---------- */
.topbar {
  display: flex;
  align-items: center;
  gap: 24px;
  padding: 10px 20px;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  flex-wrap: wrap;
}
.brand { display: flex; align-items: center; gap: 10px; flex: none; }
.brand-mark { width: 30px; height: 30px; }
/* The wordmark is a link home, but it is branding first: without this it picks
   up the global link colour and underline and reads as body copy. */
.brand-name {
  display: block;
  font-weight: 650;
  letter-spacing: -0.2px;
  color: var(--text);
  text-decoration: none;
}
.brand-name:hover { color: var(--accent); }
.brand-name:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }
.brand-sub { font-size: 11px; color: var(--dim); }

/* One row, always. Wrapping six tabs into a ragged block reads as broken
   layout; below the width they need, the row scrolls sideways instead. */
.tabs {
  display: flex;
  gap: 2px;
  flex: 1 1 auto;
  min-width: 0;
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tab {
  background: none;
  border: 0;
  color: var(--muted);
  padding: 8px 13px;
  border-radius: 8px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 500;
  font-family: inherit;
  flex: none;
  white-space: nowrap;
}
.tab:hover { color: var(--text); background: var(--panel-2); }
.tab.is-active { color: var(--text); background: var(--panel-2); box-shadow: inset 0 -2px 0 var(--accent); }

.topbar-right { display: flex; align-items: center; gap: 12px; flex: none; margin-left: auto; }

/* Narrow screens: drop the tagline, then let the right-hand controls take
   their own row rather than squeezing the tabs to nothing. */
@media (max-width: 1100px) {
  .topbar { gap: 14px; }
  .brand-sub { display: none; }
}
@media (max-width: 820px) {
  .topbar { flex-wrap: wrap; row-gap: 8px; }
  .tabs { order: 3; width: 100%; flex-basis: 100%; }
}
.asof { font-size: 11px; color: var(--dim); text-align: right; line-height: 1.35; }
.btn {
  background: var(--panel-2);
  border: 1px solid var(--line);
  color: var(--text);
  padding: 7px 13px;
  border-radius: 8px;
  cursor: pointer;
  font-size: 13px;
  font-family: inherit;
}
.btn:hover { border-color: var(--accent); color: var(--accent); }
.btn:disabled { opacity: 0.5; cursor: default; }

.banner {
  padding: 9px 20px;
  background: var(--banner-bg);
  color: var(--warn);
  border-bottom: 1px solid var(--banner-line);
  font-size: 13px;
}

/* Full width. The app is a data console -- tables and scan results earn every
   pixel of a wide monitor, and a centred column just wastes the sides. */
main { padding: 16px 20px 24px; margin: 0; }
@media (max-width: 640px) { main { padding: 12px 12px 20px; } }

/* ---------- loading ---------- */
.loading { display: flex; gap: 20px; align-items: flex-start; padding: 48px 8px; }
.loading h2 { margin: 0 0 6px; font-size: 17px; font-weight: 600; }
.loading p { margin: 0 0 12px; color: var(--muted); }
.spinner {
  width: 26px; height: 26px; flex: none; margin-top: 4px;
  border: 3px solid var(--line);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.9s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.log {
  font-family: var(--mono); font-size: 11.5px; color: var(--dim);
  background: var(--panel); border: 1px solid var(--line); border-radius: 8px;
  padding: 10px 12px; max-height: 260px; overflow: auto; margin: 0;
  white-space: pre-wrap; max-width: 760px;
}

/* ---------- layout ---------- */
.grid { display: grid; gap: 14px; }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.span-2 { grid-column: span 2; }
@media (max-width: 1150px) {
  .grid-4 { grid-template-columns: repeat(2, 1fr); }
  .grid-3, .grid-2 { grid-template-columns: 1fr; }
  .span-2 { grid-column: auto; }
}

.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--gap-md) 16px;
  min-width: 0;
  box-shadow: var(--shadow-sm);
}
.card-head {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: var(--gap-sm); margin-bottom: var(--gap-md);
  padding-bottom: var(--gap-sm); border-bottom: 1px solid var(--line);
}
.card h3 { margin: 0; font-size: 13.5px; font-weight: 620; letter-spacing: -0.01em; }
.card-note { font-size: 11px; color: var(--dim); }
/* A card head that carries controls rather than just a note. Wraps to its own
   line before the heading gets squeezed. */
.card-head-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.card-link { font-size: 11px; color: var(--accent); text-decoration: none; white-space: nowrap; }
.card-link:hover { text-decoration: underline; }
/* Same look as the anchor, but it moves the page rather than navigating. */
.card-link-btn { border: 0; background: none; font: inherit; font-size: 11px; cursor: pointer; padding: 0; }
.section-title { margin: 24px 0 12px; font-size: 15px; font-weight: 600; }
.section-title:first-child { margin-top: 0; }

/* ---------- stat tiles ---------- */
.stat-label { font-size: 10.5px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.08em; font-weight: 600; }
.stat-value {
  font-size: 28px; font-weight: 620; font-family: var(--mono); margin: 6px 0 2px;
  letter-spacing: -0.6px; font-variant-numeric: tabular-nums;
}
.stat-sub { font-size: 11.5px; color: var(--dim); }

/* Three related figures sharing one box. The label sits above a divided row so
   the box reads as a single idea -- how much of the market is participating --
   rather than three tiles that happen to be adjacent. */
.stat-head {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 10px; margin-bottom: 12px; padding-bottom: 9px;
  border-bottom: 1px solid var(--line);
}
.stat-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}
/* Sharing a row with the charts makes this card taller than its contents; the
   figures stay at the top instead of drifting to the middle. */
.internals-row > .card { display: flex; flex-direction: column; }
/* Hairline separators between cells, not around them. */
.stat-cell + .stat-cell {
  padding-left: 16px;
  border-left: 1px solid var(--line);
}
.stat-cell-label {
  font-size: 10.5px; color: var(--muted); text-transform: uppercase;
  letter-spacing: 0.06em; font-weight: 600; line-height: 1.3;
  /* Two lines are reserved so all three values sit on one baseline whether or
     not a label wraps. */
  min-height: 2.6em;
}
.stat-cell-label[data-help] { cursor: help; }
/* Three abreast in half the width: smaller than a full-width tile, still the
   dominant figure in its cell. */
.stat-row .stat-value { font-size: 23px; margin: 2px 0 3px; }
/* The unit is set in em, so it tracks whichever value size it sits in rather
   than needing a rule per tile size. At 0.78 it reads as part of the figure;
   the 0.54-0.61 it was before read as a typo, and dropping it to --dim on top
   of that made it look like an afterthought. */
.stat-unit { font-size: 0.78em; color: var(--muted); margin-left: 1px; }

@media (max-width: 640px) {
  .stat-row { grid-template-columns: 1fr; gap: 12px; }
  .stat-cell + .stat-cell {
    padding-left: 0; padding-top: 12px;
    border-left: 0; border-top: 1px solid var(--line);
  }
  .stat-cell-label { min-height: 0; }
}


/* ---------- meters ---------- */
.meter { margin-bottom: 13px; }
.meter:last-child { margin-bottom: 0; }
.meter-top { display: flex; justify-content: space-between; font-size: 12px; margin-bottom: 5px; }
.meter-track { height: 7px; background: var(--panel-2); border-radius: 4px; overflow: hidden; }
/* Scaled on the compositor rather than transitioning width, which would relayout
   the row on every frame. */
.meter-fill {
  height: 100%; width: 100%; border-radius: 4px;
  transform-origin: left center;
  transition: transform 180ms ease-out;
}

/* ---------- sector performance ---------- */

/* A three-column row: name, a centre-anchored bar, then the value. The bar
   column is the only flexible one so the numbers stay in a straight edge. */
.perf-row {
  display: grid;
  grid-template-columns: minmax(96px, 1.1fr) minmax(70px, 2fr) 62px;
  align-items: center;
  gap: 10px;
  padding: 4px 0;
}
.perf-label {
  font-size: 12px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.perf-sym { margin-left: 6px; font-size: 10.5px; color: var(--dim); font-family: var(--mono); }
.perf-track {
  position: relative;
  display: block;
  height: 15px;
  background: var(--panel-2);
  border-radius: 3px;
}
.perf-zero {
  position: absolute; left: 50%; top: 0; bottom: 0;
  width: 1px; background: var(--line-strong);
}
/* Both directions start at the midpoint; only the edge they grow toward and
   the corner rounding differ. */
.perf-bar { position: absolute; top: 2px; bottom: 2px; }
.perf-bar.is-up {
  left: 50%; background: var(--up); border-radius: 0 3px 3px 0;
}
.perf-bar.is-down {
  right: 50%; background: var(--down); border-radius: 3px 0 0 3px;
}
.perf-value {
  font-family: var(--mono);
  font-size: 11.5px;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* Timeframe switch, shared with any card that needs one. */
.tf-switch {
  display: inline-flex; gap: 2px; padding: 2px;
  border: 1px solid var(--line); border-radius: 7px; background: var(--panel-2);
}
.tf-switch button {
  border: 0; background: none; color: var(--muted);
  font: inherit; font-size: 11px; font-weight: 550;
  padding: 3px 9px; border-radius: 5px; cursor: pointer;
  transition: background 140ms ease, color 140ms ease;
}
.tf-switch button:hover { color: var(--text); }
.tf-switch button.is-active { background: var(--panel); color: var(--text); box-shadow: var(--shadow-sm); }

/* ---------- internals row ---------- */

/* Market internals beside the two breadth charts. The figures need less room
   than the charts, so the row is weighted rather than split in equal thirds. */
.internals-row {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1.45fr) minmax(0, 1.4fr);
  gap: 14px;
  margin-top: 14px;
  align-items: stretch;
}
/* The three stat cells inside a third of the width would be too tight to read,
   so the card takes a full row of its own before the charts pair up. */
@media (max-width: 1360px) {
  .internals-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .internals-row > .card:first-child { grid-column: 1 / -1; }
}
@media (max-width: 820px) {
  .internals-row { grid-template-columns: 1fr; }
  .internals-row > .card:first-child { grid-column: auto; }
}

/* ---------- top band ---------- */

/* One row across the full width: regime, the index tiles, the monitor, then
   the week's earnings. The column ratios follow the reference layout, and every
   member stretches to a common height. */
.top-band {
  display: grid;
  grid-template-columns:
    minmax(0, 1.05fr) minmax(0, 2.4fr) minmax(0, 1.9fr) minmax(0, 1.5fr);
  gap: 14px;
  align-items: stretch;
}
/* Two abreast before stacking: regime beside the tiles, monitor beside the
   calendar, which keeps each pair readable rather than squeezing four. */
@media (max-width: 1460px) {
  .top-band { grid-template-columns: minmax(0, 1fr) minmax(0, 1.55fr); }
}
@media (max-width: 820px) {
  .top-band { grid-template-columns: 1fr; }
}

/* ---------- index strip ---------- */

.idx-strip {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
}
/* Inside the band the four tiles get half the room they had as a full row, so
   they pair up rather than shrinking to nothing. */
@media (max-width: 1460px) {
  .idx-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.idx-tile {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 11px 14px 12px;
  min-width: 0;
  box-shadow: var(--shadow-sm);
}
.idx-head { display: flex; align-items: baseline; gap: 7px; min-width: 0; }
.idx-sym {
  font-size: 12px; font-weight: 680; letter-spacing: 0.02em;
}
.idx-name {
  font-size: 10.5px; color: var(--dim); overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
.idx-price {
  font-family: var(--mono); font-size: 21px; font-weight: 620;
  letter-spacing: -0.5px; font-variant-numeric: tabular-nums;
  margin: 4px 0 1px;
}
.idx-price.idx-muted { color: var(--dim); }
.idx-chg { font-family: var(--mono); font-size: 12.5px; font-variant-numeric: tabular-nums; }
/* The moving-average state, split into what price is above and below. */
.idx-ma {
  display: flex; flex-wrap: wrap; gap: 4px 10px;
  margin-top: 6px; font-size: 10.5px; font-family: var(--mono);
}
.ma-ok { color: var(--up); }
.ma-bad { color: var(--down); }
.idx-regime { color: var(--muted); font-family: var(--sans, inherit); font-size: 11px; }

@media (max-width: 460px) {
  .idx-strip { grid-template-columns: 1fr; }
}

/* ---------- market monitor ---------- */

table.monitor { width: 100%; border-collapse: collapse; }
table.monitor th {
  position: static; padding: 0 0 5px; cursor: default;
  border-bottom: 1px solid var(--line); background: none;
}
table.monitor th:first-child { width: 45%; }
table.monitor td {
  padding: 4px 0; border-bottom: 1px solid var(--line);
  font-size: 12px;
}
table.monitor tbody tr:last-child td { border-bottom: 0; }
.monitor-label {
  text-align: left; font-family: inherit; font-size: 12px; color: var(--text);
  white-space: nowrap;
}
.monitor-window { margin-left: 6px; font-size: 10.5px; color: var(--dim); font-family: var(--mono); }
.monitor-counts { font-family: var(--mono); }

/* ---------- earnings this week ---------- */

.earn-week { display: flex; flex-direction: column; }
/* A session per row: fixed label column, then the tickers running across. */
.earn-day {
  display: grid;
  grid-template-columns: 76px minmax(0, 1fr);
  align-items: baseline;
  gap: 8px;
  padding: 4px 0;
  border-bottom: 1px solid var(--line);
}
.earn-day:last-child { border-bottom: 0; }
.earn-day-label {
  display: flex; align-items: baseline; gap: 5px;
  font-size: 11px; font-weight: 620; white-space: nowrap;
}
.earn-day-count { font-family: var(--mono); font-size: 10px; color: var(--dim); font-weight: 400; }
/* Tickers wrap within the row; the row grows rather than clipping them. */
.earn-tickers { display: flex; flex-wrap: wrap; gap: 2px 7px; min-width: 0; }
/* Ranked names are buttons; the rest are inert text at the same size so the
   column still reads as one list. */
.earn-tick {
  display: inline-block; padding: 0; border: 0; background: none;
  font-family: var(--mono); font-size: 11px; color: var(--dim);
  text-align: left; line-height: 1.55;
}
.earn-tick.is-known { color: var(--text); cursor: pointer; font-weight: 550; }
.earn-tick.is-known:hover { color: var(--accent); }
.earn-tick.is-known:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; }


/* ---------- scan legend ---------- */

/* Collapsed by default: it is reference material, and someone reading the table
   every morning does not need it open every morning. */
.scan-legend { margin: 0 0 12px; font-size: 12px; }

/* The control, not a caption. It carries an icon, sits on the accent colour and
   has a hover and focus state, so it reads as something to click -- which the
   plain text summary it replaced did not. */
.scan-legend > summary {
  cursor: pointer;
  list-style: none;
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 11px 5px 9px;
  border: 1px solid var(--accent);
  border-radius: 999px;
  background: var(--tint-accent, transparent);
  color: var(--accent);
  font-size: 11.5px; font-weight: 550;
  transition: background 140ms ease, color 140ms ease, border-color 140ms ease;
}
.scan-legend > summary::-webkit-details-marker { display: none; }
.scan-legend > summary::marker { content: ''; }
.scan-legend > summary:hover { background: var(--accent); color: var(--panel); }
.scan-legend > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.legend-icon { flex: none; }
.legend-label { white-space: nowrap; }
.legend-chevron { flex: none; transition: transform 160ms ease; }
.scan-legend[open] > summary .legend-chevron { transform: rotate(-180deg); }

/* The panel itself, once open. */
.legend-body {
  margin-top: 12px; padding: 14px 16px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--panel-2);
}
.legend-body .legend-block:first-child,
.legend-body .legend-tiers:first-child { margin-top: 0; }

@media (prefers-reduced-motion: reduce) {
  .scan-legend > summary, .legend-chevron { transition: none; }
}

.legend-tiers {
  display: flex; flex-wrap: wrap; gap: 8px 20px;
  margin: 0 0 4px; font-size: 11.5px; color: var(--muted);
}
.legend-tiers span { display: inline-flex; align-items: center; gap: 6px; }

.legend-block { margin-top: 14px; }
.legend-head { font-size: 12px; font-weight: 620; margin-bottom: 7px; }
.legend-sub { font-weight: 400; color: var(--dim); font-size: 11px; margin-left: 6px; }
.legend-list { list-style: none; margin: 0; padding: 0; }
/* Label, weight, then the explanation — the weights line up so the scoring
   reads as a budget adding to 100. */
.legend-list li {
  display: grid; grid-template-columns: 130px 34px minmax(0, 1fr);
  gap: 10px; align-items: baseline;
  padding: 3px 0; font-size: 11.5px; line-height: 1.5;
}
.legend-key { color: var(--text); }
.legend-max {
  font-family: var(--mono); color: var(--accent); text-align: right;
  font-variant-numeric: tabular-nums;
}
.legend-detail { color: var(--dim); }
.legend-lynch li { grid-template-columns: 130px 34px minmax(0, 1fr); }
.lynch-letter {
  grid-column: 2; justify-self: end;
  font-family: var(--mono); font-weight: 650; color: var(--up);
}
.legend-note { margin: 8px 0 0; font-size: 11.5px; line-height: 1.55; color: var(--dim); }

@media (max-width: 620px) {
  .legend-list li { grid-template-columns: 1fr; gap: 2px; }
  .legend-max, .lynch-letter { text-align: left; justify-self: start; grid-column: auto; }
}

/* ---------- setup scores ---------- */

.scan-score {
  font-family: var(--mono); font-weight: 650;
  font-variant-numeric: tabular-nums;
}
/* Tier badges. The three read as a ladder, so they share a shape and differ
   only in weight of colour. */
.sbadge {
  display: inline-block; padding: 1px 7px; border-radius: 999px;
  font-size: 10.5px; font-weight: 650; letter-spacing: 0.02em;
  border: 1px solid transparent; white-space: nowrap;
}
.sb-setup { color: var(--up); background: var(--tint-up, transparent); border-color: var(--up); }
.sb-watch { color: var(--accent); background: var(--tint-accent, transparent); border-color: var(--accent); }
.sb-monitor { color: var(--muted); border-color: var(--line-strong); }
.sb-none { color: var(--dim); }

/* The CANSLIM legs, one fixed slot per letter so the column reads as a
   checklist down the table instead of a different string on every row. */
.canslim-letters {
  display: inline-flex; gap: 3px;
  font-family: var(--mono); font-size: 11px; font-weight: 620;
}
.canslim-letters i {
  font-style: normal; width: 14px; text-align: center;
  border-radius: 3px; padding: 1px 0;
}
.canslim-letters i.on { color: var(--up); background: var(--tint-up); }
.canslim-letters i.off { color: var(--dim); opacity: 0.5; }

.lynch-flags {
  font-family: var(--mono); font-size: 11.5px; letter-spacing: 0.08em; color: var(--muted);
}
.scan-asof { font-family: var(--mono); font-size: 11px; color: var(--dim); }

/* ---------- dashboard scan panel ---------- */

.scan-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 12px;
}
.scan-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel-2);
  color: var(--muted);
  font: inherit;
  font-size: 12px;
  font-weight: 550;
  cursor: pointer;
  white-space: nowrap;
  transition: color 140ms ease, border-color 140ms ease, background 140ms ease;
}
.scan-chip:hover { color: var(--text); border-color: var(--line-strong); }
.scan-chip.is-active {
  color: var(--text);
  background: var(--panel);
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--ring-accent);
}
.scan-chip-count {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.scan-chip.is-active .scan-chip-count { color: var(--accent); }

/* The rank and company columns only exist in this compact table. */
.scan-compact .rank-col {
  text-align: right;
  width: 1%;
  color: var(--dim);
  font-size: 11.5px;
}
.scan-compact .company-col {
  text-align: left;
  font-family: inherit;
  color: var(--muted);
  font-size: 12px;
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.scan-foot {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--line);
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--dim);
}
.scan-foot-count { white-space: nowrap; color: var(--muted); }
.scan-foot-count a { color: var(--accent); text-decoration: none; }
.scan-foot-count a:hover { text-decoration: underline; }

@media (max-width: 700px) {
  .scan-foot { flex-direction: column; gap: 6px; }
  .scan-compact .company-col { max-width: 120px; }
}

@media (prefers-reduced-motion: reduce) {
  .scan-chip { transition: none; }
}

/* ---------- earnings surprise ---------- */

.earn-surprise { font-family: var(--mono); font-weight: 600; font-variant-numeric: tabular-nums; }
.earn-eps { display: block; margin-top: 2px; font-size: 10.5px; color: var(--dim); font-family: var(--mono); }
.earn-when { font-size: 10.5px; color: var(--dim); font-family: var(--mono); white-space: nowrap; }

@media (prefers-reduced-motion: reduce) {
  .tf-switch button { transition: none; }
}

/* ---------- tables ---------- */
.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th {
  text-align: right; padding: 9px 10px; font-size: 10.5px; font-weight: 620;
  color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em;
  border-bottom: 1px solid var(--line); white-space: nowrap; position: sticky; top: 0;
  background: var(--panel); cursor: pointer; user-select: none;
  /* Keeps the header legible when rows scroll beneath it. */
  box-shadow: 0 1px 0 var(--line);
}
th:first-child, td:first-child { text-align: left; }
th.no-sort { cursor: default; }
th:hover:not(.no-sort) { color: var(--text); }
th .arrow { color: var(--accent); }
td {
  padding: 8px 10px; text-align: right; border-bottom: 1px solid var(--line);
  white-space: nowrap; font-family: var(--mono); font-size: 12.5px;
  /* Digits share a width so figures line up down the column. */
  font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1;
}
td:first-child { font-family: inherit; }
tbody tr { transition: background 120ms ease-out; }
tbody tr:hover { background: var(--panel-2); }
/* A marker on the row being pointed at, so the eye keeps its place across a
   wide table without needing zebra striping. */
tbody tr.clickable td:first-child { box-shadow: inset 2px 0 0 transparent; transition: box-shadow 120ms ease-out; }
tbody tr.clickable:hover td:first-child,
tbody tr.clickable:focus-visible td:first-child { box-shadow: inset 2px 0 0 var(--accent); }
.sym { font-weight: 620; letter-spacing: -0.1px; }
.sym-name { color: var(--dim); font-size: 11px; font-weight: 400; margin-left: 7px; }
.clickable { cursor: pointer; }

.up { color: var(--up); }
.down { color: var(--down); }
.flat { color: var(--muted); }

.pill {
  display: inline-block; padding: 2px 7px; border-radius: 5px;
  font-size: 11px; font-weight: 600; font-family: var(--mono);
}
.pill-strong { background: rgba(52,211,153,0.14); color: var(--up); }
.pill-constructive { background: rgba(96,165,250,0.14); color: var(--accent); }
.pill-mixed { background: rgba(251,191,36,0.14); color: var(--warn); }
.pill-weak { background: rgba(248,113,113,0.14); color: var(--down); }

.rs-cell { display: inline-block; min-width: 34px; padding: 2px 6px; border-radius: 5px; font-weight: 620; }

.tag { font-size: 10px; padding: 1px 5px; border-radius: 4px; background: var(--panel-2); color: var(--muted); margin-left: 5px; }
.tag-hi { background: rgba(52,211,153,0.14); color: var(--up); }

/* ---------- filters ---------- */
.filters { display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end; margin-bottom: 14px; }
.field { display: flex; flex-direction: column; gap: 4px; }
.field label { font-size: 10.5px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; }
input[type="text"], input[type="number"], select {
  background: var(--panel-2); border: 1px solid var(--line); color: var(--text);
  padding: 7px 9px; border-radius: 7px; font-size: 13px; font-family: inherit; min-width: 120px;
}
input:focus, select:focus { outline: none; border-color: var(--accent); }
.range-val { font-family: var(--mono); color: var(--accent); font-size: 12px; }

/* ---------- detail drawer ---------- */
.drawer-backdrop {
  position: fixed; inset: 0; background: var(--overlay); z-index: var(--z-overlay);
}
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(560px, 100%);
  background: var(--panel); border-left: 1px solid var(--line);
  z-index: var(--z-modal); overflow-y: auto; padding: 18px 20px;
}
.drawer-head { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 16px; }
.drawer h2 { margin: 0; font-size: 22px; }
.drawer-sub { color: var(--muted); font-size: 12.5px; margin-top: 3px; }
.kv { display: grid; grid-template-columns: 1fr auto; gap: 6px 14px; font-size: 13px; }
.kv dt { color: var(--muted); }
.kv dd { margin: 0; text-align: right; font-family: var(--mono); }
.close-x { background: none; border: 0; color: var(--muted); font-size: 24px; cursor: pointer; line-height: 1; padding: 0 4px; }
.close-x:hover { color: var(--text); }

.empty { color: var(--dim); padding: 28px 4px; text-align: center; }

.footer {
  padding: 16px 20px 28px; color: var(--dim); font-size: 11.5px;
  border-top: 1px solid var(--line); margin-top: 28px;
  display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap;
}
.footer .disclaimer { color: var(--dim); }

.chart-svg { width: 100%; height: auto; display: block; overflow: visible; }
/* The panel charts have no intrinsic size and are meant to fill their card, but
   the in-table renderers (sparkline, mini candles, contraction bars) declare
   their own pixel size. Stretching those to 100% of a narrow table cell was
   collapsing a 116x30 thumbnail to 19x5 -- an unreadable sliver, and far too
   small to aim at. An SVG that states its own size now keeps it. */
.chart-svg[width] { width: auto; height: auto; }

/* ---------- scanners ---------- */
.scanner-grid {
  display: grid;
  /* auto-fit, not auto-fill: with four scans and room for five tracks, the
     empty track collapses and the cards share the full width instead of
     huddling at 284px with a phantom column beside them. The 240px floor lets
     all four sit in one row from about 1030px up. */
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  /* Every row the same height, so a card that wraps to a second row still
     matches the ones above it. */
  grid-auto-rows: 1fr;
  gap: 10px;
  margin-bottom: 16px;
}
.scanner-card {
  text-align: left;
  /* A column, so every card's rows start at the same offset and the slack a
     grid row creates is absorbed at the bottom instead of leaving the text
     floating in the middle of a taller box. */
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px 13px;
  cursor: pointer;
  color: var(--text);
  font-family: inherit;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.scanner-card:hover { border-color: var(--line-strong); background: var(--panel-2); }
.scanner-card.is-active {
  border-color: var(--accent);
  background: var(--panel-2);
  box-shadow: inset 0 0 0 1px var(--ring-accent);
}
.scanner-top { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
/* The name has to be free to wrap to two lines without shoving the count out
   of the corner, and the count must never wrap or shrink. */
/* Two lines are reserved whether or not the name needs them. "Qullamaggie
   Episodic Pivots" wraps at card width while the other three do not, and
   without a reserved slot that one card's tag and description sit a line lower
   than its neighbours'. */
.scanner-name {
  font-size: 13.5px; font-weight: 620; letter-spacing: -0.1px;
  min-width: 0; line-height: 1.3; min-height: 2.6em;
}
.scanner-count {
  font-family: var(--mono);
  font-size: 22px;
  font-weight: 650;
  line-height: 1;
  color: var(--accent);
  flex: none;
}
.scanner-count.is-zero { color: var(--dim); }
.scanner-tag {
  display: inline-block; align-self: flex-start;
  margin-top: 5px; font-size: 10px; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--muted);
  background: var(--panel-2); border: 1px solid var(--line);
  padding: 1px 6px; border-radius: 4px;
}
.scanner-card.is-active .scanner-tag { background: var(--panel); }
.scanner-desc {
  margin-top: 8px; font-size: 11.5px; line-height: 1.45; color: var(--dim);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
/* The clamp stays on when a card is selected. The full description is already
   printed in the results panel directly below, so expanding it here duplicated
   the text and -- because a grid row is as tall as its tallest card -- inflated
   every other card in the row to match. */
.scanner-card.is-active .scanner-desc { color: var(--muted); }
.scanner-explain {
  margin: -4px 0 14px; font-size: 12.5px; line-height: 1.5;
  color: var(--muted); max-width: 90ch;
}
.scanner-hint {
  color: var(--dim); font-size: 13px; padding: 18px 4px 4px; text-align: center;
}
.btn-mini { padding: 3px 9px; font-size: 11px; border-radius: 6px; }

.section-head { display: flex; align-items: baseline; gap: 12px; margin: 24px 0 12px; }
.section-head:first-child { margin-top: 0; }
.section-head .section-title { margin: 0; }
.section-note { font-size: 11.5px; color: var(--dim); }
/* Both stops come from the palette, so the card lifts slightly in either
   theme instead of fading to a fixed dark colour. */
.scanner-grid-core .scanner-card {
  border-color: var(--line-strong);
  background: linear-gradient(180deg, var(--panel) 0%, var(--panel-2) 100%);
}
.scanner-grid-core .scanner-name { font-size: 14.5px; }
.scanner-grid-core .scanner-count { font-size: 30px; }

.scanner-tag-live { color: var(--up); border-color: #1f4436; background: rgba(52,211,153,0.10); }
/* Pinned to the bottom edge: it is a footer fact, and keeping it out of the
   flow above means the description starts at the same height on every card. */
.scanner-session {
  display: block; margin-top: auto; padding-top: 8px;
  font-size: 10.5px; font-family: var(--mono); color: var(--dim);
}
.scanner-session.premarket, .scanner-session.regular, .scanner-session.afterhours { color: var(--up); }
.live-note {
  margin: -4px 0 14px; padding: 9px 12px; border-radius: 8px;
  background: var(--panel-2); border: 1px solid var(--line);
  font-size: 12.5px; line-height: 1.5; color: var(--muted);
}
.live-note.ok { border-color: #1f4436; color: var(--up); }
.live-note.warn { border-color: #4a3f18; color: var(--warn); }

/* ---------- market regime spectrum ---------- */
.regime-card { display: flex; flex-direction: column; }
/* The band's cards stretch to a shared height, so their contents need to know
   what to do with the extra room. */
.top-band > .card { display: flex; flex-direction: column; }
.top-band .band-earn .earn-week { flex: 1; justify-content: flex-start; }
.regime-card .chart-svg { margin: 2px 0 0; width: 100%; }
.spectrum-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-top: 8px; }
.spectrum-label { font-size: 21px; font-weight: 650; letter-spacing: -0.3px; }
.spectrum-value { font-family: var(--mono); font-size: 12px; color: var(--muted); }
.regime-note { margin-top: auto; padding-top: 8px; line-height: 1.45; }

/* ---------- header tooltips ---------- */
th[data-help] { cursor: help; }
th[data-help]:hover { color: var(--text); }
.tip {
  position: fixed;
  z-index: var(--z-tooltip);
  max-width: 320px;
  padding: 9px 11px;
  border-radius: 8px;
  background: var(--tip-bg);
  border: 1px solid var(--tip-line);
  color: var(--tip-text);
  font-size: 12px;
  line-height: 1.5;
  text-transform: none;
  letter-spacing: normal;
  font-weight: 400;
  box-shadow: var(--shadow-lg);
  pointer-events: none;
}

/* ---------- catalyst ---------- */
.cat-badge {
  display: inline-block; padding: 2px 7px; border-radius: 5px;
  font-size: 11px; font-weight: 600; white-space: nowrap;
  background: rgba(96, 165, 250, 0.14); color: var(--accent);
}
.cat-badge-none { background: var(--panel-2); color: var(--dim); font-weight: 500; }
.cat-detail {
  white-space: normal; max-width: 260px; margin-top: 3px;
  font-size: 11px; line-height: 1.35; color: var(--dim);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, sans-serif;
}
.cat-summary { margin-bottom: 12px; }
.cat-summary-text { margin-top: 7px; font-size: 12.5px; line-height: 1.5; color: var(--text); }
.cat-section-title {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--muted); margin: 14px 0 7px;
}
.cat-list { list-style: none; margin: 0; padding: 0; }
.cat-list li { padding: 7px 0; border-bottom: 1px solid var(--line); }
.cat-list li:last-child { border-bottom: 0; }
.cat-list a { color: var(--text); text-decoration: none; font-size: 12.5px; line-height: 1.45; }
.cat-list a:hover { color: var(--accent); text-decoration: underline; }
.cat-meta { display: block; margin-top: 3px; font-size: 10.5px; color: var(--dim); }

/* ---------- VCP columns ---------- */
.vcp-count {
  display: inline-block; min-width: 22px; padding: 2px 7px; border-radius: 5px;
  background: rgba(52, 211, 153, 0.14); color: var(--up); font-weight: 620;
}
.vcp-adr { display: block; font-size: 10px; color: var(--dim); margin-top: 2px; }


/* ---------- focus, motion, and text rendering ---------- */

/* A visible focus ring is the only way a keyboard user can tell where they are.
   :focus-visible keeps it off for mouse clicks. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}
.tab:focus-visible,
.btn:focus-visible,
.scanner-card:focus-visible { outline-offset: 3px; }

/* Column headers carry definitions, so they must be reachable by keyboard. */
th[data-help] { cursor: help; }
th[data-help]:focus-visible { outline-offset: -2px; }

/* Rows open a detail view; they behave as controls and must look focusable. */
tr.clickable:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* Skip past the header straight to content. */
.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: var(--z-tooltip);
  padding: 10px 16px; border-radius: 8px;
  background: var(--accent); color: #06121f; font-weight: 600; text-decoration: none;
  transition: top 120ms ease-out;
}
.skip-link:focus { top: 12px; }

/* Headings should not leave a single orphaned word; body text wraps evenly. */
h1, h2, h3, .stat-value { text-wrap: balance; }
p, .stat-sub, .card-note, .scanner-desc { text-wrap: pretty; }

@media (prefers-reduced-motion: reduce) {
  /* Motion is decorative here; honour the system preference rather than
     overriding it. Transitions collapse instead of being removed so state
     changes still happen instantly. */
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}


/* ---------- polish ---------- */

/* Loading: a structural placeholder reads as "content is coming" where a lone
   spinner reads as "something is wrong". */
.skeleton {
  background: linear-gradient(90deg, var(--panel-2) 25%, var(--line) 37%, var(--panel-2) 63%);
  background-size: 400% 100%;
  border-radius: 6px;
  animation: shimmer 1.4s ease-in-out infinite;
}
@keyframes shimmer {
  0% { background-position: 100% 50%; }
  100% { background-position: 0 50%; }
}
.skeleton-row { height: 30px; margin-bottom: 8px; }
.skeleton-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--gap-md); margin-bottom: var(--gap-md); }
.skeleton-tile { height: 96px; }

/* Empty states need one obvious way forward, not just an apology. */
.empty {
  color: var(--muted); padding: 34px 16px; text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: var(--gap-sm);
}
.empty-action {
  background: var(--panel-2); border: 1px solid var(--line); color: var(--text);
  padding: 7px 14px; border-radius: 8px; cursor: pointer; font-size: 13px; font-family: inherit;
}
.empty-action:hover { border-color: var(--accent); color: var(--accent); }

/* The top bar sits over scrolling content, so it needs to read as a surface. */
.topbar { box-shadow: var(--shadow-sm); }
.drawer { box-shadow: var(--shadow-lg); }
.tip { box-shadow: var(--shadow-lg); }

/* Section headings get air above them without collapsing into the card above. */
.section-title { margin: var(--gap-xl) 0 var(--gap-md); font-size: 15.5px; font-weight: 640; letter-spacing: -0.2px; }
.section-title:first-child { margin-top: 0; }

/* Pills and rank chips align on the same baseline grid as the numerals. */
.pill, .rs-cell, .cat-badge, .vcp-count { font-variant-numeric: tabular-nums; }

/* Scanner cards: clearer resting state, and the active one is unmistakable. */
.scanner-card { box-shadow: var(--shadow-sm); }
.scanner-card.is-active { box-shadow: var(--shadow-md), inset 0 0 0 1px var(--ring-accent); }


/* ---------- surface texture ---------- */

/* A single fixed grain layer. Flat vector surfaces read as sterile; a trace of
   noise gives the panels a material quality. Static, pointer-transparent, and
   painted once -- it never animates, so it costs nothing after first paint. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: var(--z-base);
  pointer-events: none;
  opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---------- pressed states ---------- */

/* Every control answered hover but nothing answered a press, so clicks felt
   inert. A small displacement is enough to read as physical. */
.btn:active:not(:disabled),
.tab:active,
.empty-action:active,
.scanner-card:active {
  transform: translateY(1px);
}
.btn, .empty-action { transition: border-color 140ms ease-out, color 140ms ease-out, transform 90ms ease-out; }
.tab { transition: background 140ms ease-out, color 140ms ease-out, transform 90ms ease-out; }
.scanner-card:active { transform: translateY(-1px) scale(0.995); }

/* Anchor jumps inside the app land softly; the reduced-motion block above
   still forces this back to instant when the system asks for it. */
html { scroll-behavior: smooth; }

/* ---------- typographic polish ---------- */

/* Geist carries its own tabular figures; make sure every numeric surface asks
   for them rather than relying on the default. */
.stat-value, td, th, .rs-cell, .pill, .lp-price, .auth-plan-price, .scanner-count {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1, "cv01" 1;
}
.stat-value { letter-spacing: -0.8px; }
.card h3 { letter-spacing: -0.2px; }

/* ---------- light theme ---------- */

/* A warm cream ground rather than white: less glare over long sessions, and it
   keeps the semantic colours legible without shouting. Every value here was
   checked against WCAG AA on both --bg and --panel-2 before being accepted. */
:root[data-theme="light"] {
  --bg: #f4f2ed;
  --panel: #ffffff;
  --panel-2: #edeae2;
  --line: #e4e1d9;
  --text: #1a1a18;
  --muted: #63615c;
  --dim: #6a675e;
  --up: #1b6b4f;
  --down: #9e3f35;
  --accent: #3d5468;
  --warn: #7d5a0e;
  --violet: #6d4b8f;

  /* Light surfaces need far less shadow; the same weights would read as dirt. */
  --shadow-sm: 0 1px 2px rgba(40, 36, 28, 0.06);
  --shadow-md: 0 4px 14px rgba(40, 36, 28, 0.09);
  --shadow-lg: 0 18px 44px rgba(40, 36, 28, 0.16);

  --line-strong: #cfcbc0;
  --chart-ext: #e8e4d9;
  --ring-accent: rgba(61, 84, 104, 0.35);
  /* The tooltip stays dark in light mode -- it floats above the page and reads
     faster as an inverted surface -- but its own text colour must invert too. */
  --tip-bg: #2b2926;
  --tip-line: #43403a;
  --tip-text: #f4f2ed;
  --banner-bg: #fdf3d8;
  --banner-line: #e6d4a2;
  --overlay: rgba(40, 36, 28, 0.42);
}

/* Grain is a dark-surface device. On cream it turns to visible dirt, so it is
   dialled back to a trace. */
:root[data-theme="light"] body::after { opacity: 0.02; }

/* Tints derived per theme rather than baked into markup. */
:root { --tint-up: rgba(52, 211, 153, 0.14); --tint-accent: rgba(96, 165, 250, 0.14);
        --tint-warn: rgba(251, 191, 36, 0.14); --tint-down: rgba(248, 113, 113, 0.14); }
:root[data-theme="light"] {
  --tint-up: rgba(27, 107, 79, 0.12);
  --tint-accent: rgba(61, 84, 104, 0.12);
  --tint-warn: rgba(125, 90, 14, 0.12);
  --tint-down: rgba(158, 63, 53, 0.12);
}

/* The marketing page paints its own ambient washes; they need re-tinting or the
   dark-theme greens glow oddly over cream. */
:root[data-theme="light"] body.landing {
  background:
    radial-gradient(1100px 520px at 50% -8%, rgba(27, 107, 79, 0.07), transparent 65%),
    radial-gradient(900px 460px at 88% 12%, rgba(61, 84, 104, 0.06), transparent 60%),
    var(--bg);
}
:root[data-theme="light"] .lp-btn-primary { background: var(--up); color: #ffffff; }
:root[data-theme="light"] .lp-btn-primary:hover { background: #17805c; }
:root[data-theme="light"] .lp-plan-flag,
:root[data-theme="light"] .auth-plan-flag { color: #ffffff; }
:root[data-theme="light"] .auth-google { border-color: #cfcbc0; }
:root[data-theme="light"] .skip-link { color: #ffffff; }

/* ---------- theme toggle ---------- */

.theme-toggle {
  display: inline-flex; align-items: center; gap: 2px; padding: 3px;
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 9px;
}
.theme-toggle button {
  border: 0; background: none; color: var(--muted); cursor: pointer;
  font: inherit; font-size: 12px; font-weight: 560; line-height: 1;
  padding: 6px 11px; border-radius: 6px;
  transition: background 140ms ease-out, color 140ms ease-out;
}
.theme-toggle button:hover { color: var(--text); }
.theme-toggle button[aria-pressed="true"] {
  background: var(--panel); color: var(--text); box-shadow: var(--shadow-sm);
}
.theme-toggle button:active { transform: translateY(1px); }


/* Rank bands. The hue comes from the semantic tokens and the wash from the
   per-theme tint, so both themes stay legible without duplicated markup. */
.rs-strong { color: var(--up); background: var(--tint-up); }
.rs-good { color: var(--accent); background: var(--tint-accent); }
.rs-mid { color: var(--warn); background: var(--tint-warn); }
.rs-weak { color: var(--down); background: var(--tint-down); }

/* Existing chips move onto the same tints. */
.pill-strong { background: var(--tint-up); color: var(--up); }
.pill-constructive { background: var(--tint-accent); color: var(--accent); }
.pill-mixed { background: var(--tint-warn); color: var(--warn); }
.pill-weak { background: var(--tint-down); color: var(--down); }
.tag-hi { background: var(--tint-up); color: var(--up); }
.cat-badge { background: var(--tint-accent); color: var(--accent); }
.vcp-count { background: var(--tint-up); color: var(--up); }
.scanner-tag-live { background: var(--tint-up); color: var(--up); border-color: var(--up); }
.live-note.ok { border-color: var(--up); color: var(--up); }
.live-note.warn { border-color: var(--warn); color: var(--warn); }
.auth-status-ok { border-color: var(--up); }
.auth-status-warn { border-color: var(--warn); }


/* ---------- expandable charts ---------- */

/* Every chart sits in a figure so the expand control has something to anchor
   to. The control stays hidden until the chart is hovered or something inside
   it takes focus, which keeps the panels clean while leaving it reachable by
   keyboard. */
.chart-figure { position: relative; margin: 0; }
/* Inside a stat card the figure starts below the label, so the control would
   float over the chart itself; nudge it clear. */
.regime-card .chart-expand { top: -30px; }
.chart-expand {
  position: absolute;
  top: 0;
  right: 0;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border-radius: 9px;
  /* On a pale card the old muted-on-panel-2 combination all but vanished. The
     control now sits on the panel colour with a strong border, full-strength
     text and a shadow, so it reads as something floating above the chart. */
  border: 1px solid var(--line-strong);
  background: var(--panel);
  color: var(--text);
  box-shadow: var(--shadow-md);
  cursor: var(--cursor-zoom);
  /* Softened rather than hidden: a control nobody can see is a control nobody
     uses, and every chart in the app has one. */
  opacity: 0.8;
  transition: opacity 160ms ease, color 160ms ease, border-color 160ms ease, transform 160ms ease;
}
.chart-figure:hover .chart-expand,
.chart-expand:hover,
.chart-expand:focus-visible { opacity: 1; }
.chart-expand:hover { color: var(--accent); border-color: var(--accent); transform: scale(1.08); }
.chart-expand:active { transform: scale(0.96); }
/* Same control, but sitting in a card's header row rather than floating over
   the content -- on a dense list it would otherwise cover the first value. */
/* In a card's header row there is no chart underneath to lift away from, so it
   loses the shadow and shrinks to match the controls beside it. */
.chart-expand-inline {
  position: static; opacity: 1; width: 26px; height: 26px;
  box-shadow: none; border-radius: 7px;
}
.chart-expand-inline svg { width: 15px; height: 15px; }

/* The 30-day thumbnail in a table cell. It is a button, but must not look or
   space like one -- the row around it is already a click target. */
.mini-chart {
  display: inline-block;
  padding: 3px;
  border: 0;
  border-radius: 5px;
  background: none;
  cursor: var(--cursor-zoom);
  line-height: 0;
  box-shadow: inset 0 0 0 1px transparent;
  transition: background 140ms ease, box-shadow 140ms ease;
}
/* Hovering used to fade the chart to 72% opacity, which made the thing you
   were pointing at harder to read. It now lifts instead: a tinted ground and
   an accent ring, so the cell reads as a target without obscuring the data. */
.mini-chart:hover {
  background: var(--panel-2);
  box-shadow: inset 0 0 0 1px var(--accent);
}
.mini-chart:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.chart-modal-backdrop {
  position: fixed;
  inset: 0;
  background: var(--overlay);
  z-index: var(--z-chart);
}
.chart-modal {
  position: fixed;
  z-index: calc(var(--z-chart) + 1);
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(1180px, calc(100vw - 32px));
  max-height: calc(100vh - 48px);
  overflow-y: auto;
  padding: 18px 20px 22px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--panel);
  box-shadow: var(--shadow-lg);
}
.chart-modal-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 18px;
  margin-bottom: 14px;
  flex-wrap: wrap;
}
.chart-modal h2 { margin: 0; font-size: 19px; letter-spacing: -0.3px; }
.chart-modal-meta { margin-top: 4px; font-size: 12.5px; color: var(--muted); }
.chart-modal-actions { display: flex; align-items: center; gap: 12px; }

.chart-tabs {
  display: flex;
  gap: 2px;
  padding: 3px;
  border-radius: 9px;
  background: var(--panel-2);
  border: 1px solid var(--line);
}
.chart-tab {
  border: 0;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: 12.5px;
  padding: 5px 11px;
  border-radius: 7px;
  cursor: pointer;
  white-space: nowrap;
  transition: background 160ms ease, color 160ms ease;
}
.chart-tab:hover { color: var(--text); }
.chart-tab.is-active { background: var(--panel); color: var(--text); box-shadow: var(--shadow-sm); }

.chart-loading { padding: 60px 0; text-align: center; color: var(--dim); font-size: 13px; }

/* The draggable price surface. `touch-action: pan-y` keeps vertical page
   scrolling working on a phone while claiming horizontal drags for the chart. */
.chart-pan {
  cursor: grab;
  touch-action: pan-y;
  user-select: none;
  border-radius: 6px;
}
.chart-pan.is-grabbing { cursor: grabbing; }
.chart-pan:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.pan-hint {
  margin-top: 8px;
  font-size: 11.5px;
  color: var(--dim);
  font-variant-numeric: tabular-nums;
}
.pan-windows[hidden] { display: none !important; }

@media (max-width: 640px) {
  .chart-modal { padding: 14px 14px 18px; width: calc(100vw - 16px); }
  .chart-modal-actions { width: 100%; justify-content: space-between; }
  .chart-tab { font-size: 12px; padding: 5px 8px; }
  .chart-expand { opacity: 1; }
}

@media (hover: none) {
  .chart-expand { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .chart-expand, .chart-tab, .mini-chart { transition: none; }
  .chart-expand:hover, .chart-expand:active { transform: none; }
}
