/* ══ Index Pulse — terminal revamp ═══════════════════════════════════════
 * Palette and layout adapted from the redesign. Scoped by loading: pulse.css
 * is only linked by /pulse/, so redefining the tokens here restyles this page
 * without touching the rest of the site.
 *
 * The ground is a near-black neutral rather than the site's cool navy, the
 * hairlines are tighter, and the accent is amber. Direction keeps its own two
 * hues; everything else is greyscale, so a dense board reads as one surface.
 *
 * Type: the redesign specified IBM Plex Sans + Plex Mono, which is what the
 * site already runs — so it was not what made it feel generated. The pairing
 * here is JetBrains Mono for every figure and label (fixed-width, so columns
 * of numbers do not shift as prices tick) and Archivo, a grotesque, for names
 * and headings. Inter is deliberately avoided: it is the single most
 * recognisable "generated design" typeface.
 */
:root {
  --font-ui:   'Archivo', system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, monospace;

  --bg:          #0a0b0d;
  --bg-card:     #0d0f11;
  --bg-panel:    #0f1114;
  --bg-chip:     #16191d;
  --border:      #1a1d21;
  --border-soft: #14171a;
  --border-hard: #1e2226;   /* page-level rules, input + button edges */

  --text:        #e6e8ea;
  --text-strong: #f2f4f6;
  --text-soft:   #c3c9cf;
  --muted:       #8b929a;
  /* The redesign's dim tone was #6e757d, which measures 4.12:1 on the card —
     under the 4.5 AA floor, and it is used for every column label, index
     label and sector abbreviation on the page. Lifted along the same hue to
     the first value that clears it (4.60 on card, 4.71 on canvas). */
  --muted-dim:   #757d85;

  --up:          #4ec9a0;  --up-rgb:   78 201 160;
  --up-soft:     rgba(78,201,160,0.12);   --up-line:   rgba(78,201,160,0.34);
  --down:        #e06a62;  --down-rgb: 224 106 98;
  --down-soft:   rgba(224,106,98,0.12);   --down-line: rgba(224,106,98,0.34);
  --down-strong: #e17069;   /* on a --down-soft badge; the plain tone is 4.32:1 there */

  --accent:      #e0a83c;  --accent-rgb: 224 168 60;
  --accent-strong:#f0bb52;
  --accent-soft: rgba(224,168,60,0.10);
  --accent-line: rgba(224,168,60,0.30);
  --grid:        #14171a;
}

/* The redesign is dark-only; this is its light counterpart in the same
 * spirit — a neutral near-white ground, the same amber darkened until it
 * carries on white, and direction hues taken down to match. */
html.light {
  --bg:          #f6f6f7;
  --bg-card:     #ffffff;
  --bg-panel:    #f0f1f2;
  --bg-chip:     #e6e8ea;
  --border:      #dcdee1;
  --border-soft: #e9ebed;
  --border-hard: #cdd0d4;

  --text:        #16181a;
  --text-strong: #08090a;
  --text-soft:   #3a3e42;
  --muted:       #5f666e;
  --muted-dim:   #6b727a;

  --up:          #10714f;  --up-rgb:   16 113 79;
  --up-soft:     rgba(16,113,79,0.10);    --up-line:   rgba(16,113,79,0.28);
  --down:        #bb3b33;  --down-rgb: 187 59 51;
  --down-soft:   rgba(187,59,51,0.10);    --down-line: rgba(187,59,51,0.28);
  --down-strong: #b13830;

  --accent:      #85601a;  --accent-rgb: 133 96 26;
  --accent-strong:#6d4e12;
  --accent-soft: rgba(133,96,26,0.10);
  --accent-line: rgba(133,96,26,0.28);
  --grid:        #e6e8ea;
}

html, body { height: 100%; }
body {
  font-family: var(--font-ui);
  background: var(--bg);
  color: var(--text);
  display: flex;
  flex-direction: column;
  overflow: hidden;         /* single scrollbar lives on .table-container */
}
/* Fixed-height chrome sits above the scroll region */
.tab-nav, .statbar, .toolbar, .screener-panel { flex: 0 0 auto; }
/* Table + rail share the remaining height and scroll independently. */
.pulse-main { flex: 1 1 auto; display: flex; min-height: 0; }

/* ══ Stat strip ═════════════════════════════════════════════════════════ */
.statbar {
  display: flex;
  align-items: stretch;
  background: var(--bg-card);
  border-bottom: 1px solid var(--border);
}
.sb-title {
  padding: 12px 20px;
  display: flex; flex-direction: column; justify-content: center; gap: 4px;
  min-width: 230px;
  border-right: 1px solid var(--border);
}
.sb-title-row { display: flex; align-items: baseline; gap: 9px; }
.sb-title h1 {
  font-size: 1.15rem; font-weight: 600; letter-spacing: -0.01em;
  color: var(--text-strong);
}
.sb-state { font-size: 0.6rem; color: var(--down); line-height: 1; }
.sb-state.live { color: var(--up); }
/* Extended hours: live data, but not the regular session. Amber rather than
   the green "live" or the red "closed" — both of those would be a lie. */
.sb-state.extended { color: #f59e0b; }
.sb-state-text {
  font-family: var(--font-mono);
  font-size: 0.62rem; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--accent);
  border: 1px solid var(--accent-line);
  background: var(--accent-soft);
  padding: 2px 6px; border-radius: 2px;
}
.sb-sub { font-family: var(--font-mono); font-size: 0.68rem; color: var(--muted-dim); }

.sb-indices { display: flex; flex: 1 1 auto; min-width: 0; }
.hidx {
  padding: 10px 18px;
  border-right: 1px solid var(--border);
  display: flex; flex-direction: column; gap: 3px;
  flex: 1 1 0; min-width: 140px;
}
.hidx-label {
  font-family: var(--font-mono);
  font-size: 0.6rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--muted-dim);
}
.hidx-bottom { display: flex; align-items: baseline; gap: 8px; }
.hidx-price {
  font-family: var(--font-mono);
  font-size: 0.92rem; font-weight: 500; color: var(--text);
}
.hidx-chg { font-family: var(--font-mono); font-size: 0.72rem; font-weight: 500; }
.hidx-chg.pos { color: var(--up); }
.hidx-chg.neg { color: var(--down); }
.hidx-chg.flat { color: var(--muted-dim); }

/* Advance/decline. Widths are set in pulse.js from the loaded rows. */
.breadth {
  height: 3px; border-radius: 2px; overflow: hidden;
  display: flex; background: var(--bg-chip); margin-top: 3px;
}
.breadth-adv { background: var(--up); width: 0; transition: width var(--dur-2) var(--ease); }
.breadth-dec { background: var(--down); width: 0; transition: width var(--dur-2) var(--ease); }

.sb-rotation {
  flex: 1 1 auto; min-width: 320px;
  padding: 10px 20px;
  display: flex; flex-direction: column; gap: 5px;
}
.sb-rot-label {
  font-family: var(--font-mono);
  font-size: 0.6rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--muted-dim);
}
.sb-rot-bars { display: flex; gap: 3px; align-items: flex-end; height: 32px; }
.rot {
  flex: 1 1 0; min-width: 24px;
  display: flex; flex-direction: column; justify-content: flex-end; align-items: center;
  gap: 3px; padding: 0; border: 0; background: transparent;
  color: inherit; cursor: pointer; overflow: hidden;
}
.rot-bar { width: 100%; border-radius: 1px; min-height: 2px; }
.rot-bar.pos { background: var(--up); }
.rot-bar.neg { background: var(--down); }
.rot-abbr {
  font-family: var(--font-mono); font-size: 0.55rem; letter-spacing: 0.04em;
  color: var(--muted-dim); white-space: nowrap;
}
.rot:hover .rot-abbr { color: var(--text); }
.rot.active .rot-abbr { color: var(--accent); }
.rot.active .rot-bar { box-shadow: 0 0 0 1px var(--accent); }
.rot:focus-visible { outline-offset: 2px; }

/* ══ Site footer ════════════════════════════════════════════════════════
 * The nav.js footer is a flex sibling of .pulse-main on this fixed-height
 * shell, so every pixel it takes is a table row the reader cannot see. Its
 * default 48px top margin buys separation on a scrolling page and buys
 * nothing here. The legal links stay — they just stop costing two rows.
 */
.gt-footer { margin-top: 0; }
.gt-footer-inner { padding: 8px 20px; font-size: 0.66rem; gap: 4px 20px; }

/* ══ Toolbar ════════════════════════════════════════════════════════════ */
.toolbar {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 20px;
  border-bottom: 1px solid var(--border);
  background: var(--bg-card);
  flex-wrap: wrap;
}
.tb-rule { width: 1px; height: 18px; background: var(--border-hard); }
.tb-spacer { flex: 1 1 auto; }
.tb-label {
  font-family: var(--font-mono);
  font-size: 0.6rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--muted-dim);
}
/* Segmented controls: one always on, mutually exclusive. */
.seg {
  display: flex; gap: 1px; padding: 1px;
  background: var(--border); border-radius: 4px;
  overflow-x: auto; scrollbar-width: none; max-width: 100%;
}
.seg::-webkit-scrollbar { display: none; }
.seg-btn, .view-tab {
  padding: 4px 11px; border: 0; border-radius: 3px;
  background: var(--bg-card); color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.66rem; font-weight: 500; letter-spacing: 0.06em;
  text-transform: uppercase; white-space: nowrap; cursor: pointer;
  transition: color var(--dur-1), background var(--dur-1);
}
.seg-btn:hover, .view-tab:hover { color: var(--text); background: var(--bg-chip); }
.seg-btn.active, .view-tab.active { background: var(--accent); color: var(--bg); }

#row-count {
  font-family: var(--font-mono); font-size: 0.68rem;
  color: var(--muted-dim); white-space: nowrap;
}
#row-count .rc-shown { color: var(--accent); font-weight: 500; }
#row-count .rc-sep { color: var(--border-hard); margin: 0 4px; }
#row-count .rc-total, #row-count .rc-label { color: var(--muted-dim); }

.ticker-search {
  background: var(--bg-panel);
  border: 1px solid var(--border-hard);
  border-radius: 4px;
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 0.68rem; letter-spacing: 0.03em;
  padding: 5px 10px; width: 170px; outline: none;
  transition: border-color var(--dur-1);
}
.ticker-search::placeholder { color: var(--muted-dim); }
.ticker-search:focus { border-color: var(--accent); }

.tb-toggle {
  padding: 5px 11px;
  border: 1px solid var(--border-hard); border-radius: 4px;
  background: transparent; color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.62rem; letter-spacing: 0.08em; text-transform: uppercase;
  cursor: pointer; white-space: nowrap;
}
.tb-toggle:hover { color: var(--text); border-color: var(--muted-dim); }
.tb-toggle.active { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); }


/* ── Screener (STO-84): config-driven chip row + collapsible panel ── */
.screener-bar {
  padding: 10px 24px;
  display: flex;
  align-items: center;
  gap: 12px;
  border-bottom: 1px solid var(--border);
  background: var(--bg);
}
/* Scroll rather than wrap: seven screens plus seven views plus four
   universes will not fit one row on a laptop, and a wrapping toolbar pushes
   the table down by a whole line. */
.preset-chips {
  display: flex;
  gap: 6px;
  flex: 0 1 auto;
  min-width: 0;
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
}
.preset-chips::-webkit-scrollbar { display: none; }
.preset-chip { flex: 0 0 auto; white-space: nowrap; }
.preset-chip {
  background: none;
  border: 1px solid var(--border);
  color: var(--muted);
  padding: 5px 12px;
  border-radius: 14px;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  cursor: pointer;
  transition: all 0.15s;
  font-family: inherit;
}
.preset-chip:hover { border-color: var(--muted-dim); color: var(--muted); }
.preset-chip.active { background: var(--border); border-color: var(--accent); color: var(--accent); }
.preset-chip[data-preset="bullish"].active { background: var(--up-soft); border-color: var(--up); color: var(--up); }
.preset-chip[data-preset="bearish"].active { background: var(--down-soft); border-color: var(--down); color: var(--down); }

.screener-toggle {
  background: none;
  border: 1px solid var(--border);
  color: var(--muted);
  padding: 5px 12px;
  border-radius: 4px;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  cursor: pointer;
  transition: all 0.15s;
  font-family: inherit;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}
.screener-toggle:hover { border-color: var(--muted-dim); color: var(--muted); }
.screener-toggle[aria-expanded="true"] { border-color: var(--accent); color: var(--accent); }
.screener-toggle .screener-caret { font-size: 0.6rem; transition: transform 0.15s; }
.screener-toggle[aria-expanded="true"] .screener-caret { transform: rotate(180deg); }
.screener-badge {
  background: var(--accent);
  color: var(--bg);
  padding: 1px 6px;
  border-radius: 8px;
  font-size: 0.65rem;
  line-height: 1.2;
  font-weight: 700;
}

.screener-panel {
  padding: 14px 24px 16px;
  border-bottom: 1px solid var(--border);
  background: var(--bg);
  max-height: 50vh;          /* never eat more than half the viewport */
  overflow-y: auto;          /* scrolls internally if fields ever exceed that */
}
#screener-panel-body {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 12px;
}
.screener-section {
  /* Each section is its own boxed card; --accent colors the label + left border */
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: 6px;
  padding: 10px 12px 12px;
}
.screener-section-label {
  font-size: 0.65rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 8px;
  font-weight: 700;
}
.screener-fields {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.screener-field {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.72rem;
  color: var(--muted);
}
.screener-field-label {
  flex: 1 1 auto;
  min-width: 0;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.screener-range {
  display: flex;
  gap: 4px;
  flex: 0 0 auto;
}
.screener-range input {
  width: 64px;
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 3px 6px;
  border-radius: 3px;
  font-family: inherit;
  font-size: 0.7rem;
  font-variant-numeric: tabular-nums;
}
.screener-range input:focus {
  outline: none;
  border-color: var(--accent);
}
.screener-cat select {
  flex: 0 0 auto;
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 3px 6px;
  border-radius: 3px;
  font-family: inherit;
  font-size: 0.7rem;
  min-width: 120px;
  max-width: 160px;
}
.screener-cat select:focus { outline: none; border-color: var(--accent); }
.screener-panel-footer {
  margin-top: 12px;
  display: flex;
  justify-content: flex-end;
}
.screener-clear {
  background: none;
  border: 1px solid var(--border);
  color: var(--muted);
  padding: 4px 12px;
  border-radius: 4px;
  font-size: 0.7rem;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
  letter-spacing: 0.03em;
}
.screener-clear:hover { border-color: var(--accent)55; color: var(--accent); }


/* ── Table container ── */
/* flex:1 + min-height:0 makes this the only scrolling region in the page;
   shrinks/grows automatically when the screener panel expands/collapses. */
.table-container {
  flex: 1 1 0;
  min-height: 0;
  min-width: 0;      /* so the rail cannot push it wider than the viewport */
  overflow-x: auto;
  overflow-y: auto;
}

table {
  border-collapse: collapse;
  font-size: 0.78rem;
  background: var(--bg-card);
  /* min-width keeps the All view at its natural 4,200px and scrolling; width
     lets the narrower views spread across the viewport instead of stopping
     short and leaving dead space to the right. */
  min-width: max-content;
  width: 100%;
}

thead {
  position: sticky;
  top: 0;
  z-index: 10;
}

/* Category header row */
/* Category banners carried eight saturated hues (sky, fuchsia, purple, teal,
 * orange, amber…) averaging 78% saturation, on a page whose own token file
 * deliberately holds green and red to ~50% so a dense board reads as one
 * palette. They are neutral now and told apart by the rules between them —
 * which leaves hue on this page meaning exactly one thing: direction. */
tr#category-row th {
  padding: 6px 10px;
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-align: center;
  /* --muted, not --muted-dim: the dim tone measured 4.18:1 on the panel, and
     this is 0.62rem uppercase — small text, so AA still wants 4.5:1. The size
     and tracking carry the hierarchy against the column header, not the tone. */
  color: var(--muted);
  background: var(--bg-panel);
  border-bottom: 1px solid var(--border);
  border-right: 1px solid var(--border);
  white-space: nowrap;
}
tr#category-row th:last-child { border-right: 0; }

/* Column header row */
tr#col-header-row th {
  padding: 8px 10px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-align: left;
  color: var(--muted);
  background: var(--bg-card);
  border-bottom: 2px solid var(--border);
  cursor: pointer;
  white-space: nowrap;
  user-select: none;
}
tr#col-header-row th.sorted { color: var(--text); }
tr#col-header-row th:hover { background: var(--border); }
tr#col-header-row th .sort-arrow {
  display: inline-block;
  margin-left: 4px;
  opacity: 0.4;
  font-size: 0.65rem;
}
tr#col-header-row th.sorted .sort-arrow { opacity: 1; }

/* Data rows */
tbody tr {
  border-bottom: 1px solid var(--bg-card);
  transition: background 0.1s;
}
tbody tr:hover { background: var(--border); }

tbody td {
  padding: 6px 10px;
  white-space: nowrap;
  color: var(--text);
  vertical-align: middle;
}

/* Keep primary market values at the same reading weight as the index strip.
   Directional and deliberately dimmed cells retain their own semantic color. */
td.cell-price {
  font-weight: 500;
}

/* Sticky first column */
thead tr th:first-child,
tbody tr td:first-child {
  position: sticky;
  left: 0;
  z-index: 5;
  background: var(--bg-card);
}
thead tr#category-row th:first-child { background: var(--bg-panel); }
thead tr#col-header-row th:first-child { background: var(--bg-card); }
tbody tr:hover td:first-child { background: var(--border); }

/* Ticker cell */
td.cell-ticker {
  font-weight: 700;
  color: var(--text);
  font-size: 0.82rem;
  letter-spacing: 0.02em;
  line-height: 1.1;
  /* Two lines have to live inside the 40px row that VT_ROW_HEIGHT assumes.
     The first line is as tall as the 22px star button, so the vertical
     padding comes down from 6px to make room for the name beneath it. */
  padding-top: 2px;
  padding-bottom: 2px;
}
/* Company name under the symbol. The row is locked to 40px because row
 * virtualisation measures against VT_ROW_HEIGHT, so both lines have to fit
 * the 28px content box: 14px + 12px with these line-heights. */
.cell-ticker-sub {
  display: block;
  margin-left: 30px;         /* clears the freshness dot + star */
  max-width: 150px;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 0.62rem;
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.1;
  /* --muted, not --muted-dim: at this size the dim tone measured 4.09:1 on
     the card in dark and 3.23:1 in light, both under the 4.5:1 AA floor. */
  color: var(--muted);
}
.ticker-link {
  color: inherit;
  text-decoration: none;
}
.ticker-link:hover {
  color: var(--accent);
  text-decoration: underline;
}

/* Freshness dot */
.freshness-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--down);
  margin-right: 6px;
  vertical-align: middle;
  flex-shrink: 0;
  transition: background 0.4s;
}
.freshness-dot.fresh { background: var(--up); }

/* Positive / negative coloring */
.pos { color: var(--up); }
.neg { color: var(--down); }

/* SMA alignment badges */
.sma-bullish {
  display: inline-block;
  background: var(--up-soft);
  color: var(--up);
  border: 1px solid var(--up-line);
  border-radius: 3px;
  padding: 1px 6px;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.05em;
}
.sma-bearish {
  display: inline-block;
  /* The tinted ground costs contrast: --down on --down-soft measured 4.32:1
     dark / 4.20:1 light. The bullish twin clears it because the mint is
     lighter; the coral needs the brighter step to match. */
  background: var(--down-soft);
  color: var(--down-strong);
  border: 1px solid var(--down-line);
  border-radius: 3px;
  padding: 1px 6px;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.05em;
}

/* Breakout badge */
.breakout-yes {
  display: inline-block;
  background: var(--up-soft);
  color: var(--up);
  border: 1px solid var(--up-line);
  border-radius: 3px;
  padding: 1px 6px;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.06em;
}
.breakout-no {
  /* --muted: the dim tone is 4.48:1 on a card, just under the AA floor. */
  color: var(--muted);
  font-size: 0.72rem;
}

/* Growth dots */
.dots-row {
  display: flex;
  gap: 3px;
  align-items: center;
}
.dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  cursor: default;
  flex-shrink: 0;
}
.dot-hollow {
  border: 1px solid var(--border);
  background: transparent;
}

/* Price flash */
@keyframes flash-green {
  0%   { background: var(--up-soft); }
  100% { background: transparent; }
}
@keyframes flash-red {
  0%   { background: var(--down-soft); }
  100% { background: transparent; }
}
.flash-up { animation: flash-green 0.6s ease-out; }
.flash-down { animation: flash-red 0.6s ease-out; }

/* Loading / error */
.loading-msg {
  padding: 60px 24px;
  color: var(--muted-dim);
  font-size: 0.9rem;
  text-align: center;
}

/* Name / sector / industry cells */
td.cell-name {
  max-width: 160px;
  overflow: hidden;
  text-overflow: ellipsis;
}
td.cell-name.has-info { cursor: default; }
td.cell-sector, td.cell-industry {
  max-width: 150px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Hover tooltip */
#hover-tooltip {
  display: none;
  position: fixed;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 10px 14px;
  max-width: 320px;
  font-size: 0.75rem;
  color: var(--muted);
  line-height: 1.5;
  z-index: 9999;
  box-shadow: 0 4px 16px rgba(0,0,0,0.5);
}

/* Column filter icon */
.col-filter-btn {
  position: absolute;
  right: 5px;
  top: 50%;
  transform: translateY(-50%);
  opacity: 0.28;
  cursor: pointer;
  width: 18px;
  height: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 3px;
  transition: opacity 0.15s, background 0.15s;
  color: var(--muted);
  flex-shrink: 0;
}
.col-filter-btn:hover { opacity: 1; background: rgba(255,255,255,0.07); }
.col-filter-btn.active { opacity: 1; color: var(--accent); }
tr#col-header-row th:hover .col-filter-btn { opacity: 0.7; }

/* Column filter popover */
#col-filter-popover {
  display: none;
  position: fixed;
  z-index: 10000;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 10px;
  min-width: 210px;
  box-shadow: 0 4px 16px rgba(0,0,0,0.5);
  font-size: 0.75rem;
}
.fp-label {
  color: var(--muted);
  font-size: 0.65rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: 8px;
}
.fp-row { display: flex; gap: 6px; margin-bottom: 2px; }
#col-filter-popover input[type="number"],
#col-filter-popover .fp-search {
  width: 100%;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 3px;
  color: var(--text);
  font-size: 0.75rem;
  padding: 5px 7px;
  font-family: inherit;
  outline: none;
  box-sizing: border-box;
}
#col-filter-popover input[type="number"]:focus,
#col-filter-popover .fp-search:focus { border-color: var(--accent); }
.fp-search { margin-bottom: 6px; }
.fp-select-all {
  padding: 3px 2px 6px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 4px;
}
.fp-options {
  max-height: 200px;
  overflow-y: auto;
  margin-bottom: 2px;
}
.fp-options label, .fp-select-all label {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 3px 4px;
  cursor: pointer;
  color: var(--muted);
  border-radius: 2px;
  white-space: nowrap;
}
.fp-options label:hover, .fp-select-all label:hover { background: var(--border); color: var(--text); }
.fp-options input[type="checkbox"], .fp-select-all input[type="checkbox"] {
  accent-color: var(--accent);
  cursor: pointer;
  flex-shrink: 0;
}
.fp-clear {
  margin-top: 8px;
  width: 100%;
  background: none;
  border: 1px solid var(--border);
  border-radius: 3px;
  color: var(--muted);
  font-size: 0.7rem;
  padding: 4px 8px;
  cursor: pointer;
  font-family: inherit;
  transition: color 0.15s, border-color 0.15s;
}
.fp-clear:hover { color: var(--text); border-color: var(--muted-dim); }
.fp-done {
  margin-top: 8px;
  width: 100%;
  background: var(--accent);
  border: none;
  border-radius: 3px;
  color: var(--bg);
  font-size: 0.7rem;
  font-weight: 700;
  padding: 5px 8px;
  cursor: pointer;
  font-family: inherit;
  letter-spacing: 0.04em;
  transition: background 0.15s;
}
.fp-done:hover { background: var(--accent-strong); }

/* Clear all filters button */
#clear-col-filters {
  display: none;
  background: none;
  border: 1px solid var(--accent)55;
  border-radius: 4px;
  color: var(--accent);
  font-size: 0.7rem;
  font-weight: 600;
  padding: 5px 10px;
  cursor: pointer;
  font-family: inherit;
  letter-spacing: 0.04em;
  transition: background 0.15s;
}
#clear-col-filters:hover { background: var(--accent)18; }
@media (max-width: 700px) {
  /* The page itself used to scroll sideways ~158px on a 390px phone: the
     header's index tiles and the ticker-search input sat on one unwrappable
     row. The table is allowed to scroll horizontally — it is a 43-column
     table — but the chrome around it is not. */
  .pulse-header { padding: 14px 12px 10px; flex-wrap: wrap; row-gap: 10px; }
  .header-indices {
    margin-left: 0; width: 100%; gap: 14px;
    justify-content: space-between;
    overflow-x: auto; scrollbar-width: none;
  }
  .header-indices::-webkit-scrollbar { display: none; }
  .index-tabs { padding: 10px 12px; flex-wrap: wrap; row-gap: 8px; }
  .ticker-search { margin-left: 0; flex: 1 1 100%; min-width: 0; }
  #row-count { margin-left: auto; }
  .view-bar { padding: 7px 12px; gap: 8px; }
  .view-bar-label { display: none; }   /* the segmented control reads as itself */

  .screener-bar { padding: 10px 12px; flex-wrap: wrap; }
  .preset-chips { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
  .preset-chips::-webkit-scrollbar { display: none; }
  .preset-chip { white-space: nowrap; flex: 0 0 auto; }
  .screener-panel { padding: 12px 12px; max-height: 60vh; overflow-y: auto; }
  #screener-panel-body { grid-template-columns: 1fr; }
  .screener-field-label { min-width: 0; }
}
/* Row virtualization (Phase 2): only ~50 rows are mounted at any time.
   Fixed row height lets the virtualizer compute spacer heights without
   measuring the DOM. overflow:hidden guards against runaway content
   pushing the row past 40px and corrupting scroll math. */
.pulse-table tbody tr { height: 40px; box-sizing: border-box; }
.pulse-table tbody tr.vt-spacer td { padding: 0; border: 0; }

/* ══ Ticker cell ════════════════════════════════════════════════════════
 * Star, symbol, sector chip, and the company name beneath — the redesign's
 * identity block. Sector as a three-letter chip costs ~34px where the old
 * Sector column cost 150px and truncated mid-word anyway.
 */
td.cell-ticker { padding: 5px 12px; }
.tk-wrap { display: flex; align-items: center; gap: 8px; }
.tk-main { min-width: 0; }
.tk-row { display: flex; align-items: center; gap: 7px; }
.tk-sym {
  font-family: var(--font-mono);
  font-size: 0.76rem; font-weight: 600; letter-spacing: 0.02em;
  color: var(--text);
}
a.ticker-link:hover .tk-sym { color: var(--accent); }
.sector-chip {
  font-family: var(--font-mono);
  font-size: 0.52rem; font-weight: 500; letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted-dim);
  border: 1px solid var(--border-hard);
  border-radius: 2px;
  padding: 1px 4px;
  flex-shrink: 0;
}
.cell-ticker-sub {
  display: block;
  font-family: var(--font-ui);
  font-size: 0.64rem; font-weight: 400; letter-spacing: 0;
  line-height: 1.2;
  color: var(--muted);
  max-width: 170px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ══ Profile column ═════════════════════════════════════════════════════
 * The five score dimensions as one 5-bar sparkline, so the shape of a
 * company reads at a glance without spending five columns on it. Each bar
 * is 0-20; the Scores view still shows the numbers.
 */
.profile { display: flex; gap: 2px; align-items: flex-end; height: 18px; }
.profile-bar { width: 4px; border-radius: 1px; background: var(--muted-dim); min-height: 2px; }
.profile-bar.hi { background: var(--up); }
.profile-bar.mid { background: var(--accent); }
.profile-bar.lo { background: var(--down); }

/* ══ Detail rail ════════════════════════════════════════════════════════ */
.rail {
  width: 352px; flex: 0 0 352px;
  border-left: 1px solid var(--border);
  background: var(--bg-card);
  display: flex; flex-direction: column;
  overflow: hidden;
}
.rail.hidden { display: none; }
.rail-tabs { display: flex; border-bottom: 1px solid var(--border); flex: 0 0 auto; }
.rail-tab {
  flex: 1 1 auto; padding: 9px 0; border: 0; background: transparent;
  color: var(--muted-dim);
  font-family: var(--font-mono);
  font-size: 0.62rem; letter-spacing: 0.1em; text-transform: uppercase;
  cursor: pointer;
  border-bottom: 2px solid transparent;
}
.rail-tab:hover { color: var(--text); }
.rail-tab.active { color: var(--accent); border-bottom-color: var(--accent); }
.rail-close {
  flex: 0 0 auto; width: 34px; border: 0; background: transparent;
  color: var(--muted-dim); cursor: pointer; font-size: 0.7rem;
}
.rail-close:hover { color: var(--text); }
.pin-count {
  font-size: 0.58rem; padding: 0 4px; border-radius: 6px;
  background: var(--bg-chip); color: var(--muted);
}
.rail-body { flex: 1 1 auto; overflow-y: auto; }
.rail-empty {
  padding: 40px 22px; text-align: center;
  font-size: 0.72rem; color: var(--muted-dim);
}
.rail-sec { padding: 14px 18px; border-bottom: 1px solid var(--border); }
.rail-sec-label {
  font-family: var(--font-mono);
  font-size: 0.58rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--muted-dim); margin-bottom: 9px;
}
.rail-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; }
.rail-sym { font-family: var(--font-mono); font-size: 1.05rem; font-weight: 600; color: var(--text-strong); }
.rail-name { font-size: 0.72rem; color: var(--muted); margin-top: 2px; }
.rail-meta { font-family: var(--font-mono); font-size: 0.6rem; color: var(--muted-dim); margin-top: 4px; }
.rail-price { font-family: var(--font-mono); font-size: 1.05rem; font-weight: 500; text-align: right; color: var(--text); }
.rail-chg { font-family: var(--font-mono); font-size: 0.72rem; text-align: right; margin-top: 2px; }
.rail-actions { display: flex; gap: 7px; margin-top: 12px; }
.rail-btn {
  flex: 1 1 0; text-align: center; padding: 6px 0;
  border: 1px solid var(--border-hard); border-radius: 3px;
  background: transparent; color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.6rem; letter-spacing: 0.08em; text-transform: uppercase;
  cursor: pointer; text-decoration: none;
}
.rail-btn:hover { color: var(--text); border-color: var(--muted-dim); }
.rail-btn.on { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); }

.rail-score-top { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 10px; }
.rail-score-val { font-family: var(--font-mono); font-size: 1.6rem; font-weight: 600; line-height: 1; }
.rail-score-grade { font-family: var(--font-mono); font-size: 0.8rem; color: var(--muted); }
.rail-sub { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.rail-sub-label {
  font-family: var(--font-mono); font-size: 0.58rem; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--muted-dim); width: 74px; flex: 0 0 auto;
}
.rail-sub-track { flex: 1 1 auto; height: 4px; background: var(--bg-chip); border-radius: 2px; overflow: hidden; }
.rail-sub-fill { height: 100%; border-radius: 2px; background: var(--accent); }
.rail-sub-val { font-family: var(--font-mono); font-size: 0.62rem; color: var(--muted); width: 26px; text-align: right; flex: 0 0 auto; }

.rail-range { height: 4px; background: var(--bg-chip); border-radius: 2px; position: relative; margin: 4px 0 7px; }
.rail-range-mark { position: absolute; top: -3px; width: 2px; height: 10px; background: var(--accent); border-radius: 1px; }
.rail-range-ends { display: flex; justify-content: space-between; font-family: var(--font-mono); font-size: 0.6rem; color: var(--muted-dim); }

.rail-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.rail-cell { display: flex; flex-direction: column; gap: 2px; }
.rail-cell-label { font-family: var(--font-mono); font-size: 0.55rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted-dim); }
.rail-cell-val { font-family: var(--font-mono); font-size: 0.74rem; color: var(--text); }
.rail-kv { display: flex; justify-content: space-between; gap: 10px; padding: 3px 0; }
.rail-kv-label { font-size: 0.68rem; color: var(--muted-dim); }
.rail-kv-val { font-family: var(--font-mono); font-size: 0.68rem; color: var(--text); }

.rail-cmp { width: 100%; border-collapse: collapse; }
.rail-cmp th, .rail-cmp td {
  font-family: var(--font-mono); font-size: 0.62rem;
  padding: 5px 8px; border-bottom: 1px solid var(--border-soft); text-align: right;
}
.rail-cmp th { color: var(--muted-dim); font-weight: 500; letter-spacing: 0.06em; text-transform: uppercase; }
.rail-cmp td:first-child, .rail-cmp th:first-child { text-align: left; color: var(--text); }
.rail-unpin { border: 0; background: transparent; color: var(--muted-dim); cursor: pointer; font-size: 0.7rem; }
.rail-unpin:hover { color: var(--down); }

/* Selected row */
tbody tr.row-selected { background: var(--accent-soft); box-shadow: inset 2px 0 0 var(--accent); }

@media (max-width: 1100px) {
  /* The rail would leave the table under ~700px; it becomes an overlay. */
  .rail {
    position: fixed; top: 0; right: 0; height: 100dvh; z-index: 500;
    box-shadow: var(--shadow-3);
  }
}
@media (max-width: 700px) {
  .statbar { flex-wrap: wrap; }
  .sb-title { min-width: 100%; border-right: 0; border-bottom: 1px solid var(--border); }
  /* Three tiles on one row. The desktop 140px floor would need 420px and
     scroll the page sideways, so the floor goes and the type steps down until
     "53,463.88 −0.21%" fits a third of a 360px phone. Wrapping to two rows
     (the previous fix) cost 78px of table on the screen that can least
     afford it — the tiles are chrome, the table is the page. */
  .sb-indices { flex-wrap: nowrap; }
  /* Two lines, not three: the change moves up beside the label and the price
     gets the full tile width. Price + change side by side needs 113px and a
     360px phone gives the tile 99px, so keeping them on one row would either
     wrap raggedly (S&P fits, Dow does not) or shrink the price to ~11px. */
  .hidx {
    min-width: 0; flex: 1 1 0; padding: 6px 10px;
    display: grid; grid-template-columns: 1fr auto;
    align-items: baseline; column-gap: 6px; row-gap: 1px;
  }
  .hidx-bottom { display: contents; }
  .hidx-label { grid-column: 1; font-size: 0.54rem; letter-spacing: 0.06em; }
  .hidx-chg { grid-row: 1; grid-column: 2; justify-self: end; font-size: 0.62rem; }
  .hidx-price { grid-column: 1 / -1; font-size: 0.82rem; }
  .breadth { grid-column: 1 / -1; margin-top: 2px; }
  /* Eleven sector bars in ~360px is 30px each — unreadable, and it costs the
     table 60px of height on the screen that can least afford it. */
  .sb-rotation { display: none; }
  .toolbar { padding: 6px 12px; gap: 6px; }
  .tb-rule, .tb-label { display: none; }
  .ticker-search { flex: 1 1 140px; width: auto; min-width: 0; }
  .rail { width: 100%; flex-basis: 100%; }
  .gt-footer-inner { padding: 7px 12px; font-size: 0.62rem; gap: 4px; }
  .gt-footer-links { gap: 12px; flex-wrap: wrap; }
}

/* Price-latency cell shading — red once a ticker has stopped trading. */
.cell-stale { text-align: right; font-variant-numeric: tabular-nums; }
.cell-stale.stale-warn { color: #fbbf24; }
.cell-stale.stale-bad  { color: #f87171; font-weight: 600; }

/* Score coverage badge (STO-268) — a marker, never a colour change: the score's
   own colour already carries its grade. */
.score-cov { color: var(--muted); font-size: 0.72em; margin-left: 2px; cursor: help; }

/* Derived aggregates that have gone stale (STO-270): the number is still shown
   — it was true when computed — but it stops claiming to be current. */
.breadth.stale { opacity: 0.55; }
