/* Zeus dashboard — "lead-engine telemetry console" (appointment-first, density pass).
 * Metrics in monospace tabular figures; labels in a crisp sans with tracked
 * uppercase eyebrows; one cool signal accent; green/amber/red for KPI state only.
 * No web fonts/CDN (CSP self). No inline styles in markup (JS uses CSSOM). */
:root {
  /* one type scale for every primary number (3 tiers, not 7 sizes) */
  --n-hero: 30px;   /* appt outcomes — the headline metrics */
  --n-kpi: 24px;    /* readout cells, pipeline stages, week-over-week */
  --n-sub: 18px;    /* account mini, inventory, target gauges */
  --gap: 12px;      /* one inner-card grid gap */
  --ink: #0a0e15;
  --ink-2: #0c111a;
  --surface: #111824;
  --surface-2: #18212f;
  --edge: #233044;
  --edge-soft: #1b2433;
  --text: #e9edf6;
  --muted: #8492a8;
  --faint: #5a6883;
  --signal: #5cc8ff;
  --up: #57e0a0;
  --warn: #f3c156;
  --down: #ff7d8a;
  --unknown: #c58bff; /* "we are blind here" — apart from both listed and clean */
  --track: #18212f;   /* bar/gauge track — was undefined, so every track was invisible */
  --dim: #5a6883;
  --mono: ui-monospace, "SF Mono", "JetBrains Mono", "Cascadia Code", Menlo, Consolas, monospace;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Inter, system-ui, sans-serif;
  --r: 9px;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background: radial-gradient(1100px 520px at 78% -8%, #122033 0%, transparent 60%), var(--ink);
  color: var(--text);
  font: 13px/1.45 var(--sans);
  -webkit-font-smoothing: antialiased;
  padding-bottom: env(safe-area-inset-bottom);
}
.tnum { font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }

/* split-flap digits — each digit flips when it changes. No card/gap/min-width,
 * so the row is the SAME width as plain tabular text (no layout shift), and the
 * flip is a transform (composited, never reflows). Subtle by design. */
/* number changes roll smoothly into place (gentler than a hard flip; no
 * foreshortening, so a mid-update digit never looks shrunk) */
.flips { display: inline-block; vertical-align: baseline; overflow: hidden; }
.flap { display: inline-block; }
.flap.flap-roll { animation: rollin .36s cubic-bezier(.2,.7,.25,1); }
@keyframes rollin {
  0%   { transform: translateY(-46%); opacity: 0; }
  60%  { opacity: 1; }
  100% { transform: translateY(0);    opacity: 1; }
}
@media (prefers-reduced-motion: reduce) { .flap.flap-roll { animation: none; } }
.eyebrow { font-size: 9.5px; font-weight: 600; letter-spacing: .15em; text-transform: uppercase; color: var(--muted); }
h2 { margin: 0 0 9px; }
h2.eyebrow { color: var(--faint); display: flex; gap: 10px; align-items: baseline; }
.vol-note { color: var(--faint); font-weight: 400; text-transform: none; letter-spacing: 0; font-size: 10px; }
.vol-comp { margin-top: 8px; font: 11px var(--mono); color: var(--muted); letter-spacing: .01em; }

/* ---------- login ---------- */
.login-overlay { position: fixed; inset: 0; display: grid; place-items: center; z-index: 50; padding: 20px;
  background: radial-gradient(900px 480px at 50% -5%, #12203400 0%, var(--ink) 60%), var(--ink); }
.login-card { width: 100%; max-width: 320px; background: var(--surface); border: 1px solid var(--edge);
  border-radius: var(--r); padding: 28px 24px; display: flex; flex-direction: column; gap: 13px; text-align: center; position: relative; }
.login-card::before { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 2px;
  background: linear-gradient(90deg, transparent, var(--signal), transparent); border-radius: var(--r) var(--r) 0 0; }
.login-logo { font: 700 21px/1 var(--sans); letter-spacing: .02em; }
.login-logo b { color: var(--signal); }
.login-sub { color: var(--muted); margin: -6px 0 6px; font-size: 11.5px; letter-spacing: .04em; }
.login-card input { width: 100%; padding: 11px 13px; border-radius: 8px; border: 1px solid var(--edge);
  background: var(--ink-2); color: var(--text); font: 15px var(--mono); text-align: center; }
.login-card input:focus { outline: 2px solid var(--signal); outline-offset: 1px; border-color: transparent; }
.login-card button { padding: 11px; border-radius: 8px; border: 0; background: var(--signal); color: #04161f;
  font: 700 13.5px var(--sans); letter-spacing: .02em; cursor: pointer; }
.login-card button:disabled { opacity: .55; cursor: default; }
.login-error { color: var(--down); font-size: 12px; min-height: 14px; }

/* ---------- console header ---------- */
.topbar { position: sticky; top: 0; z-index: 30; display: flex; flex-wrap: wrap; gap: 12px;
  align-items: center; justify-content: space-between; padding: 10px 18px;
  background: linear-gradient(var(--ink-2), rgba(12,17,26,.82)); backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--edge); }
.brand { display: flex; align-items: center; gap: 9px; font: 700 13px var(--sans); letter-spacing: .12em; }
.brand .bolt { color: var(--signal); font-size: 15px; }
.brand .sub { color: var(--faint); font-weight: 600; }
.topbar-right { display: flex; align-items: center; gap: 13px; flex-wrap: wrap; }
.tf-selector { display: flex; gap: 2px; background: var(--ink-2); border: 1px solid var(--edge);
  border-radius: 8px; padding: 3px; overflow: auto; }
.tf-btn { border: 0; background: transparent; color: var(--muted); padding: 5px 11px; border-radius: 6px;
  font: 600 11.5px var(--sans); cursor: pointer; white-space: nowrap; letter-spacing: .02em; }
.tf-btn:hover { color: var(--text); }
.tf-btn.active { background: var(--signal); color: #04161f; }
.status { display: flex; align-items: center; gap: 6px; font: 10.5px var(--mono); color: var(--faint); }
.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--up); }
.dot.live { animation: pulse 2.4s ease-out infinite; }
@keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(87,224,160,.5);} 70%,100% { box-shadow: 0 0 0 6px rgba(87,224,160,0);} }
.logout-btn { background: transparent; border: 1px solid var(--edge); color: var(--muted);
  padding: 5px 10px; border-radius: 7px; cursor: pointer; font: 600 11.5px var(--sans); }
.logout-btn:hover { color: var(--text); border-color: var(--faint); }
/* refresh sweep: a thin signal line that runs L→R once per successful poll */
.refresh-bar { position: absolute; left: 0; bottom: -1px; height: 2px; width: 100%;
  background: linear-gradient(90deg, transparent, var(--signal), transparent);
  transform: scaleX(0); transform-origin: left; opacity: 0; }
.refresh-bar.sweep { animation: sweep .6s ease-out; }
@keyframes sweep { 0% { transform: scaleX(0); opacity: .9; } 100% { transform: scaleX(1); opacity: 0; } }

/* ---------- layout ---------- */
.app { max-width: 1200px; margin: 0 auto; padding: 16px; display: flex; flex-direction: column; gap: 14px; }
.panel { background: var(--surface); border: 1px solid var(--edge-soft); border-radius: var(--r); padding: 14px; }
.grid { display: grid; gap: 10px; }

/* ---------- hero (appt + pipeline) ---------- */
.hero { background: linear-gradient(180deg, var(--surface-2), var(--surface)); border: 1px solid var(--edge);
  border-radius: 11px; padding: 14px 16px; position: relative; overflow: hidden; }
.hero::before { content: ""; position: absolute; inset: 0;
  background-image: linear-gradient(var(--edge-soft) 1px, transparent 1px), linear-gradient(90deg, var(--edge-soft) 1px, transparent 1px);
  background-size: 26px 26px; opacity: .10; pointer-events: none; }
.hero.appt::after { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 2px;
  background: linear-gradient(90deg, var(--signal), transparent 45%); opacity: .6; }
.hero-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 12px;
  position: relative; gap: 10px; flex-wrap: wrap; }
.hero-head .title { font: 600 12px var(--sans); letter-spacing: .04em; color: var(--text); }
.hero-head .title b { color: var(--signal); font-weight: 700; }

/* appointment hero — outcomes (big) · funnel summary · vs-target verdict cards.
   3 rows: outcomes + summary are auto, the gauges fill the remaining height. */
.appt-grid { position: relative; display: grid; grid-template-columns: 1fr; grid-template-rows: auto auto 1fr; gap: 12px; }
.appt-outcomes { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
.out-tile { background: var(--ink-2); border: 1px solid var(--edge-soft); border-radius: 10px; padding: 14px 16px; }
.out-tile .eyebrow { display: block; margin-bottom: 8px; }
.out-tile .v { font: 700 38px var(--mono); letter-spacing: -.03em; line-height: 1; }
.out-tile .v.bad { color: var(--down); }
.out-tile small { display: block; margin-top: 7px; font: 600 11px var(--mono); color: var(--faint); }
.out-tile.ok { border-color: rgba(87,224,160,.22); }
.out-tile.warnzone { border-color: rgba(243,193,86,.2); }
/* booked → confirmed → showed, in one line */
.appt-summary { display: flex; align-items: center; flex-wrap: wrap; gap: 9px; padding: 10px 13px;
  background: var(--ink-2); border: 1px solid var(--edge-soft); border-radius: 10px; font: 600 11px var(--sans); color: var(--muted); }
.appt-summary b { font: 700 16px var(--mono); color: var(--text); margin-right: 3px; }
.appt-summary .ok b { color: var(--up); }
.appt-summary i { color: var(--dim); font-style: normal; }
.appt-summary .appt-rate { margin-left: auto; color: var(--faint); font: 600 10px var(--mono); }
/* vs-target: each metric is a self-contained verdict card */
.appt-targets { display: flex; flex-direction: column; justify-content: space-between; gap: 8px; }
.tg { padding: 10px 13px; border-radius: 9px; background: var(--ink-2); border: 1px solid var(--edge-soft); }
.tg.bad { border-color: rgba(255,125,138,.30); } .tg.good { border-color: rgba(87,224,160,.26); } .tg.warn { border-color: rgba(243,193,86,.26); }
.tg-row { display: flex; justify-content: space-between; align-items: center; }
.tg-row2 { display: flex; align-items: baseline; gap: 9px; margin: 4px 0 8px; }
.tg-l { font: 600 10px var(--sans); letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.tg-v { font: 700 22px var(--mono); line-height: 1; }
.tg-v.good { color: var(--up); } .tg-v.warn { color: var(--warn); } .tg-v.bad { color: var(--down); }
.tg-target { font: 600 10px var(--mono); color: var(--faint); }
.tg-pill { font: 700 9px var(--sans); letter-spacing: .08em; padding: 2px 8px; border-radius: 999px; color: var(--faint); background: var(--track); }
.tg-pill.ok { color: var(--up); background: rgba(87,224,160,.14); }
.tg-pill.warn { color: var(--warn); background: rgba(243,193,86,.14); }
.tg-pill.over { color: var(--down); background: rgba(255,125,138,.14); }
.tg-bar { position: relative; height: 8px; border-radius: 4px; background: var(--track); overflow: visible; }
.tg-bar .fill { position: absolute; inset: 0 auto 0 0; height: 100%; width: 0; border-radius: 4px; background: var(--muted);
  transition: width .55s cubic-bezier(.22,.61,.36,1); }
.tg-bar .fill.good { background: var(--up); } .tg-bar .fill.warn { background: var(--warn); } .tg-bar .fill.bad { background: var(--down); }
.tg-mark { position: absolute; top: -3px; bottom: -3px; width: 2px; background: var(--text); border-radius: 1px; opacity: .9; }
.tg-mark::after { content: "target"; position: absolute; top: -12px; left: 50%; transform: translateX(-50%);
  font: 600 7.5px var(--sans); letter-spacing: .06em; text-transform: uppercase; color: var(--faint); white-space: nowrap; }

/* pipeline */
/* pipeline — four conversion gauges (reuse .tg), each with its transition's
   two absolute counts on a readable line */
.pipeline { display: flex; flex-direction: column; }
/* The column is stretched to the (taller) appointment panel beside it. Spreading
   the four gauges with space-between paid for that with ~65px of dead air BETWEEN
   the cards, so they read as four unrelated tiles instead of one funnel. The
   cards absorb the slack instead, and stay a stack. */
.pf-gauges { flex: 1; display: flex; flex-direction: column; gap: 10px; }
.pf-gauges > .tg { flex: 1 1 auto; display: flex; flex-direction: column; justify-content: center; }
.pf-counts { display: flex; align-items: baseline; gap: 10px; margin: 7px 0 3px; }
.pf-cwrap { display: inline-flex; align-items: baseline; gap: 5px; min-width: 0; }
.pf-cn { font: 700 16px var(--mono); letter-spacing: -.02em; color: var(--text); line-height: 1; }
.pf-cl { font: 600 9px var(--sans); letter-spacing: .07em; text-transform: uppercase; color: var(--faint); }
.pf-car { color: var(--dim); font-size: 13px; line-height: 1; flex: none; }
/* right-hand pipeline gauges sit in a wider column — give them a taller bar +
   roomier padding than the compact left-panel (.appt-targets) verdict gauges */
.pf-gauges .tg { padding: 12px 14px; }
.pf-gauges .tg-bar { height: 12px; border-radius: 6px; }
.pf-gauges .tg-bar .fill { border-radius: 6px; }

/* ---------- readout strip ---------- */
.readout { grid-template-columns: repeat(2, 1fr); }
/* The section IS the grid, so its heading is a full-width grid ITEM. */
.readout-head { grid-column: 1 / -1; margin: 0 0 -2px; }
.cell { background: var(--surface); border: 1px solid var(--edge-soft); border-radius: var(--r); padding: 11px 13px;
  display: flex; flex-direction: column; }
.cell .eyebrow { display: block; font-size: 9px; color: var(--faint); letter-spacing: .14em; }
.cell .num { font: 700 var(--n-kpi) var(--mono); letter-spacing: -.03em; margin-top: 4px; line-height: 1; }
.cell .num small { font-size: 13px; color: var(--muted); font-weight: 600; }
/* The sub-label sits UNDER its number, so it aligns with it. It inherits the
 * generic `.foot` (a page-level caption: centred, 18px padded), which left every
 * readout tile with a left-aligned eyebrow, a left-aligned figure, and a centred
 * caption floating below a block of dead space — the "off-centre and weird" the
 * operator flagged. Reset both here; `.foot` elsewhere is unaffected. */
.cell .foot { color: var(--faint); font: 9.5px var(--mono); margin-top: auto; padding: 3px 0 0;
  letter-spacing: .02em; text-align: left; }
.delta { font: 600 10px var(--mono); margin-left: 6px; }
.delta.up { color: var(--up); } .delta.down { color: var(--down); } .delta.flat { color: var(--faint); }

/* ---------- inventory strip ---------- */
.inv-strip { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; }
/* Column with the figure pushed to the bottom: a two-line label (a windowed
   "Pushed · yesterday", a LIVE chip) otherwise shunts that tile's number down
   while its neighbours' sit high, and a strip of numbers at four different
   heights is the "off-centre" the operator flagged. Bottom-aligned, they line
   up whatever the labels do. */
.inv-cell { background: var(--ink-2); border: 1px solid var(--edge-soft); border-radius: 8px; padding: 9px 11px;
  display: flex; flex-direction: column; }
.inv-cell .ml { color: var(--muted); font-size: 9.5px; letter-spacing: .08em; text-transform: uppercase; }
.inv-cell .mv { font: 600 var(--n-sub) var(--mono); margin-top: auto; padding-top: 3px; }
.inv-cell .mv.good { color: var(--up); } .inv-cell .mv.warn { color: var(--warn); } .inv-cell .mv.bad { color: var(--down); }

/* intro→follow-up health, folded into the appointment-setting card: two values
   + a weekly conversion mini-trend, set off from the target gauges above */
.appt-followup { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--edge-soft); }
.fh-reps { margin-top: 6px; font-size: 12px; color: var(--muted); letter-spacing: .02em; }
.fh-reps .good { color: var(--up); } .fh-reps .warn { color: var(--warn); } .fh-reps .bad { color: var(--down); }
.fh-trend { margin-top: 8px; min-height: 92px; }

/* metric definitions — dotted-underline label revealing a tooltip (hover/tap/keyboard) */
.def { cursor: help; position: relative; }
.qm { display: inline-block; margin-left: 3px; font: 700 .64em var(--mono); color: var(--faint);
  border: 1px solid var(--edge); border-radius: 50%; width: 1.3em; height: 1.3em; line-height: 1.2em;
  text-align: center; vertical-align: super; }
.def:hover .qm, .def:focus .qm, .def.open .qm { color: var(--signal); border-color: var(--signal); }
/* iconography */
.icw { display: inline-flex; align-items: center; }
.ic { width: 1em; height: 1em; }
.eyebrow .icw, .hero-head .title .icw { margin-right: 6px; vertical-align: -.14em; }
.eyebrow .ic { width: 13px; height: 13px; color: var(--muted); }
.hero-head .title .ic { width: 15px; height: 15px; color: var(--signal); }
.dim { opacity: .4; }
/* attention strip */
.attention { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; padding: 11px 14px;
  background: linear-gradient(180deg, #1c1712, #16130f); border: 1px solid #3a3122; border-radius: 11px; }
.att-label { display: inline-flex; align-items: center; gap: 6px; font: 700 10.5px var(--sans);
  letter-spacing: .12em; text-transform: uppercase; color: var(--warn); margin-right: 2px; }
.att-label .ic { width: 15px; height: 15px; }
.att-item { display: inline-flex; align-items: center; gap: 6px; font: 12px var(--mono); color: var(--text);
  background: var(--ink-2); border: 1px solid var(--edge); border-radius: 20px; padding: 5px 11px;
  cursor: pointer; transition: border-color .15s ease, transform .08s ease; }
.att-item:hover { border-color: var(--muted); }
.att-item:active { transform: translateY(1px); }
.att-item .ic { width: 13px; height: 13px; color: var(--muted); }
@keyframes flashpanel { 0% { box-shadow: 0 0 0 0 rgba(92,200,255,.5); } 100% { box-shadow: 0 0 0 5px rgba(92,200,255,0); } }
.flash { animation: flashpanel 1.3s ease-out; }
.att-item.bad { color: var(--down); border-color: rgba(255,125,138,.4); } .att-item.bad .ic { color: var(--down); }
.att-item.warn { color: var(--warn); border-color: rgba(243,193,86,.38); } .att-item.warn .ic { color: var(--warn); }
.att-item.info .ic { color: var(--signal); }

/* settings / customize popover */
.settings-pop { position: absolute; top: calc(100% + 6px); right: 14px; z-index: 45; width: 290px;
  background: var(--surface); border: 1px solid var(--edge); border-radius: 10px; padding: 13px; box-shadow: 0 12px 34px rgba(0,0,0,.55); }
.set-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; }
.set-lbl { font: 600 11px var(--sans); letter-spacing: .04em; color: var(--text); }
.set-head { display: flex; justify-content: space-between; align-items: baseline; margin: 12px 0 8px; }
.set-hint { font: 9px var(--mono); color: var(--faint); letter-spacing: 0; font-weight: 400; text-transform: none; }
.set-sel { background: var(--ink-2); color: var(--text); border: 1px solid var(--edge); border-radius: 6px; padding: 4px 8px; font: 12px var(--mono); }
.set-tiles { display: flex; flex-direction: column; gap: 3px; max-height: 340px; overflow: auto; }
.cfg-row { display: flex; align-items: center; gap: 8px; padding: 6px 9px; border-radius: 7px; background: var(--ink-2);
  border: 1px solid var(--edge-soft); font: 12px var(--sans); color: var(--text); }
.cfg-row.dragging { opacity: .5; }
.cfg-row.hidden-row .nm { color: var(--faint); text-decoration: line-through; }
.cfg-grip { color: var(--faint); cursor: grab; font-size: 13px; }
.cfg-row .nm { flex: 1; }
.cfg-eye { background: transparent; border: 0; cursor: pointer; font-size: 12px; padding: 2px 4px; border-radius: 5px; }
.set-reset { margin-top: 11px; width: 100%; background: transparent; border: 1px solid var(--edge); color: var(--muted);
  border-radius: 7px; padding: 7px; font: 600 12px var(--sans); cursor: pointer; }
.set-reset:hover { color: var(--text); border-color: var(--faint); }
.hidden-panel { display: none !important; }
.config-off { display: none !important; }

/* metric trend drill-down — 📈 button + modal line chart */
.trend-btn { background: transparent; border: 0; color: var(--faint); cursor: pointer; padding: 2px; border-radius: 5px;
  display: inline-flex; opacity: .5; transition: opacity .15s ease, color .15s ease, background .15s ease; flex: none; }
.trend-btn .ic { width: 13px; height: 13px; }
.trend-btn:hover { opacity: 1; color: var(--signal); background: var(--ink-2); }
section:hover .trend-btn { opacity: .8; }
.out-head, .cell-head, .inv-head { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
.out-head { margin-bottom: 8px; } .out-head .eyebrow { margin-bottom: 0; }
.cell-head { margin-bottom: 2px; }
.tg-lwrap { display: inline-flex; align-items: center; gap: 7px; }
.trend-modal { position: fixed; inset: 0; z-index: 60; display: flex; align-items: center; justify-content: center;
  background: rgba(5,8,13,.72); padding: 20px; }
.trend-card { width: min(680px, 100%); background: var(--surface); border: 1px solid var(--edge); border-radius: 14px;
  padding: 18px 20px; box-shadow: 0 20px 60px rgba(0,0,0,.6); }
.trend-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }
.trend-title { font: 700 15px var(--sans); color: var(--text); }
.trend-close { background: transparent; border: 0; color: var(--muted); cursor: pointer; font-size: 16px; padding: 4px 9px; border-radius: 6px; }
.trend-close:hover { color: var(--text); background: var(--ink-2); }
.trend-stats { display: flex; flex-wrap: wrap; align-items: baseline; gap: 14px; margin-bottom: 12px; font: 11px var(--sans); color: var(--faint); }
.trend-stats .ts b { font: 700 14px var(--mono); color: var(--text); margin-right: 4px; }
.trend-stats .ts.tgt { color: var(--warn); margin-left: auto; font: 600 11px var(--mono); }
.trend-foot { text-align: center; color: var(--faint); font: 10px var(--mono); margin-top: 8px; }

/* ---------- ICP judge daily call cap ----------
 * Two surfaces, one guard: the standing gauge on the Audience tab's ICP panel
 * (where the verdicts it throttles are listed) and a chip on Operations' Lead
 * Inventory line (where the pool it starves is). Tone comes from
 * data/icp_budget so neither invents a threshold. */
.icp-budget { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 0 0 9px; margin-bottom: 4px; border-bottom: 1px solid var(--edge-soft);
  font: 500 10.5px var(--mono); color: var(--muted); }
.icp-budget .lbl { color: var(--faint); text-transform: uppercase;
  letter-spacing: .1em; font-size: 9px; }
.icp-budget .fig { font-weight: 700; color: var(--text); }
.icp-budget .bar { flex: 1; min-width: 60px; height: 6px; border-radius: 3px;
  background: var(--track); overflow: hidden; display: block; }
.icp-budget .bar i { display: block; height: 100%; }
.icp-budget .pct { font-weight: 600; }
.icp-budget .note { color: var(--faint); }
.icp-budget.warn .fig, .icp-budget.warn .pct { color: var(--warn); }
.icp-budget.bad .fig, .icp-budget.bad .pct, .icp-budget.bad .note { color: var(--down); }

/* The Operations chip is a footnote on the provenance line, not a second
   gauge — the standing reading lives on the Audience tab. */
.icp-cap { margin-left: 14px; padding: 0 6px; border-radius: 20px; cursor: help;
  border: 1px solid var(--edge-soft); color: var(--faint); white-space: nowrap; }
.icp-cap.warn { color: var(--warn); border-color: rgba(243,193,86,.4); }
.icp-cap.bad { color: var(--down); border-color: rgba(255,125,138,.4); }

/* "LIVE" marker for a figure or panel that cannot follow the timeframe selector
 * (a right-now snapshot with no history). Deliberately quiet — it is a caveat,
 * not a status: the green dot in the header already means "connected". */
.live-chip { font: 600 8.5px var(--mono); letter-spacing: .12em; color: var(--faint);
  border: 1px solid var(--edge-soft); border-radius: 20px; padding: 0 5px;
  margin-left: 7px; vertical-align: 2px; flex: none; cursor: help; white-space: nowrap; }
h2 > .live-chip { vertical-align: 1px; }

/* appointments detail card */
.count-chip { font: 600 10px var(--mono); color: var(--faint); background: var(--ink-2);
  border: 1px solid var(--edge-soft); border-radius: 20px; padding: 1px 8px; margin-left: 7px; vertical-align: 2px; }
.appt-log { max-height: 460px; overflow-y: auto; margin: 0 -4px; }
.al-row { display: grid; gap: 6px 12px; align-items: center; padding: 8px 6px; border-bottom: 1px solid var(--edge-soft);
  grid-template-columns: 78px 1fr; grid-template-areas: "when who" "conf outcome" "call closer" "links links"; }
.al-row:last-child { border-bottom: 0; }
.al-row.rebook { background: rgba(243,193,86,.05); }
.al-head { display: none; font: 600 9px var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--faint); }
.al-when { grid-area: when; display: flex; flex-direction: column; line-height: 1.25; }
.al-date { font: 700 12px var(--mono); }
.al-time { font: 10px var(--mono); color: var(--faint); }
.al-who { grid-area: who; min-width: 0; display: flex; flex-direction: column; }
.al-nrow { display: flex; align-items: baseline; gap: 7px; min-width: 0; }
.al-name { font: 600 13px var(--sans); color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.al-idx { flex: none; font: 600 10px var(--mono); color: var(--faint); }
.al-idx.multi { color: var(--warn); }
.al-title { font: 10px var(--mono); color: var(--faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.al-badge { justify-self: start; font: 600 11px var(--mono); padding: 2px 9px; border-radius: 20px;
  border: 1px solid var(--edge-soft); white-space: nowrap; }
.al-badge.ok { color: var(--up); border-color: rgba(87,224,160,.3); }
.al-badge.bad { color: var(--down); border-color: rgba(255,125,138,.3); }
.al-badge.warn { color: var(--warn); border-color: rgba(243,193,86,.3); }
.al-badge.muted { color: var(--faint); }
.al-conf { grid-area: conf; } .al-outcome { grid-area: outcome; }
.al-call { grid-area: call; font: 11px var(--mono); color: var(--muted); white-space: nowrap; }
.al-links { grid-area: links; display: flex; gap: 6px; flex-wrap: wrap; }
.al-link { display: inline-flex; align-items: center; gap: 4px; font: 600 10px var(--sans); text-decoration: none;
  padding: 3px 8px; border-radius: 6px; border: 1px solid var(--edge); }
.al-link .ic { width: 12px; height: 12px; }
.al-link.rec { color: var(--signal); border-color: rgba(92,200,255,.35); }
.al-link.rec:hover { background: rgba(92,200,255,.12); }
.al-link.ghl { color: var(--muted); }
.al-link.ghl:hover { color: var(--text); background: var(--ink-2); }
.al-nolink { color: var(--edge); font: 11px var(--mono); }
.al-closer { grid-area: closer; font: 11px var(--sans); color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@media (min-width: 720px) {
  /* Every .al-row is its OWN grid, so any content-sized track (auto / fr) would
     resolve to a DIFFERENT width per row → columns drift between rows and the
     header (visible once rows carry varied content: recordings, closer names).
     Keep links a FIXED width so the only flexible track (contact) resolves to a
     constant across all rows → columns line up. */
  .al-row { grid-template-columns: 84px minmax(140px, 1.5fr) 118px 102px 122px 118px 160px;
    grid-template-areas: "when who conf outcome call closer links"; }
  .al-head { display: grid; grid-template-areas: none; position: sticky; top: 0; background: var(--surface); z-index: 2; }
  .al-head span:last-child { justify-self: end; }   /* "Links" over the right-aligned buttons */
  .al-links { justify-content: flex-end; }
}

/* To rebook — past-dated no-shows & cancellations; reuses the appt-log cells */
.rb-sub { font: 400 10px var(--sans); letter-spacing: .02em; text-transform: none; color: var(--faint); }
.rb-log { max-height: 400px; overflow-y: auto; margin: 0 -4px; }
.rb-row { display: grid; gap: 6px 12px; align-items: center; padding: 8px 6px; border-bottom: 1px solid var(--edge-soft);
  grid-template-columns: 78px 1fr; grid-template-areas: "when who" "why closer" "links links"; }
.rb-row:last-child { border-bottom: 0; }
.rb-head { display: none; font: 600 9px var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--faint); }
.rb-why { grid-area: why; display: flex; align-items: center; gap: 8px; min-width: 0; }
.rb-ago { font: 10px var(--mono); color: var(--faint); white-space: nowrap; }
@media (min-width: 720px) {
  .rb-row { grid-template-columns: 84px minmax(160px, 1.6fr) 168px 130px 150px;
    grid-template-areas: "when who why closer links"; }
  .rb-head { display: grid; grid-template-areas: none; position: sticky; top: 0; background: var(--surface); z-index: 2; }
  .rb-head span:last-child { justify-self: end; }
  .rb-log .al-links { justify-content: flex-end; }
}

/* direct drag-to-reorder grip on every tile (top-right; appears on hover) */
.app > section { position: relative; }
.tile-grip { position: absolute; top: 8px; right: 9px; z-index: 6; background: transparent; border: 0;
  color: var(--edge); cursor: grab; font-size: 13px; line-height: 1; padding: 3px 5px; border-radius: 5px;
  opacity: 0; transition: opacity .15s ease, color .15s ease, background .15s ease; }
.app > section:hover .tile-grip { opacity: 1; }
.tile-grip:hover { color: var(--text); background: var(--ink-2); }
.tile-grip:active { cursor: grabbing; }
section.dragging { opacity: .5; outline: 1px dashed var(--signal); outline-offset: -2px; border-radius: 14px; }
@media (hover: none) { .tile-grip { opacity: .45; } }
.def:focus { outline: none; }
.deftip { position: absolute; left: 0; bottom: calc(100% + 6px); z-index: 40; width: max-content; max-width: 220px;
  background: var(--surface-2); border: 1px solid var(--edge); border-radius: 7px; padding: 6px 9px;
  font: 11px/1.35 var(--sans); color: var(--text); letter-spacing: 0; text-transform: none; font-weight: 400;
  box-shadow: 0 8px 22px rgba(0,0,0,.5); opacity: 0; visibility: hidden; transition: opacity .12s ease; pointer-events: none; }
.def:hover > .deftip, .def:focus > .deftip, .def.open > .deftip { opacity: 1; visibility: visible; }

/* system health — TUI-style: a CPU sparkline + labeled gauge bars */
.gauges { display: grid; grid-template-columns: 1fr; gap: 9px 20px; }
.gauge .top { display: flex; justify-content: space-between; font-size: 11px; margin-bottom: 4px; }
.gauge .top .k { color: var(--faint); } .gauge .top .v { font: 700 12px var(--mono); }
.gauge .top .v.good { color: var(--up); } .gauge .top .v.warn { color: var(--warn); } .gauge .top .v.bad { color: var(--down); }
.gauge .bar { height: 6px; }
.infra-graph { margin-bottom: 12px; }
.infra-graph-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 4px; flex-wrap: wrap; gap: 6px; }
.infra-graph-head .lbl { font: 600 9px var(--sans); letter-spacing: .14em; text-transform: uppercase; color: var(--faint); }
.infra-legend { display: flex; gap: 12px; align-items: center; }
.infra-legend .lg { display: inline-flex; align-items: center; gap: 5px; font: 600 11px var(--mono); color: var(--muted); }
.infra-legend .lg i { width: 9px; height: 3px; border-radius: 2px; display: inline-block; }
.infra-legend .lg.cpu i { background: var(--signal); }
.infra-legend .lg.mem i { background: var(--warn); }
.infra-legend .lg.load { color: var(--faint); }
.infra-foot { display: flex; gap: 18px; margin-top: 10px; font: 11px var(--mono); color: var(--muted); flex-wrap: wrap; }
@media (min-width: 560px) { .gauges { grid-template-columns: 1fr 1fr; } }

/* ---------- account consoles ---------- */
.accounts { grid-template-columns: 1fr; }
.acct { background: var(--surface); border: 1px solid var(--edge-soft); border-radius: var(--r); padding: 14px; }
.acct-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 3px; }
.acct-name { font: 600 13px var(--sans); }
.badge { font: 600 9.5px var(--mono); padding: 3px 8px; border-radius: 20px; letter-spacing: .06em; border: 1px solid var(--edge); color: var(--muted); }
.badge.active { color: var(--up); border-color: rgba(87,224,160,.35); }
.badge.paused { color: var(--down); border-color: rgba(255,125,138,.4); }
.badge.holiday { color: #7db8ff; border-color: rgba(125,184,255,.4); }
.acct-campaigns { color: var(--faint); font-size: 11px; margin-bottom: 11px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.barrow { margin: 8px 0; }
.barrow .top { display: flex; justify-content: space-between; font-size: 11.5px; margin-bottom: 4px; }
.barrow .top .k { color: var(--faint); } .barrow .top .v { font: 700 13px var(--mono); }
.barrow .top .v .rs { color: var(--muted); }
.barrow .top .v .rs.warn { color: var(--warn); } .barrow .top .v .rs.bad { color: var(--down); }
/* domain health — the Spamhaus tier is styled loud, the rest deliberately not */
.dh-zones { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; }
.dh-zones .badge.blind { color: var(--warn); border-color: rgba(243,193,86,.45); }
.dh-warn { color: var(--warn); font: 11px var(--mono); line-height: 1.5; margin: 0 0 10px; }
.dh-note { color: var(--faint); font: 11px var(--mono); line-height: 1.5; margin: 10px 0 0; }
.inv-cell .mv.unknown { color: var(--unknown); }
/* KPI cell: ONE dominant figure + its denominator on a dim second line, so the
 * six cells share a baseline and a reader compares like with like instead of
 * unpicking "166 (28%)" against "62 of 646". */
.inv-cell .dh-sub { color: var(--faint); font: 11px var(--mono); margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bar { position: relative; height: 6px; border-radius: 4px; background: var(--ink-2); overflow: hidden; }
.bar > span { position: absolute; inset: 0 auto 0 0; width: 0; border-radius: 4px; background: var(--signal); transition: width .6s ease; }
.bar.good > span { background: var(--up); } .bar.warn > span { background: var(--warn); } .bar.bad > span { background: var(--down); }
.mini { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-top: 11px; }
/* Same bottom-alignment as .inv-cell: "WATERFALL · TODAY" wraps to two lines and
   would otherwise drop that one figure below the eight it sits in a grid with. */
.mini .m { background: var(--ink-2); border: 1px solid var(--edge-soft); border-radius: 8px; padding: 7px 9px;
  display: flex; flex-direction: column; }
.mini .m .ml { color: var(--faint); font-size: 8.5px; letter-spacing: .09em; text-transform: uppercase; }
.mini .m .mv { font: 700 var(--n-sub) var(--mono); margin-top: auto; padding-top: 3px; line-height: 1; letter-spacing: -.02em; }

/* ---------- charts + tooltip ---------- */
svg { display: block; width: 100%; height: auto; }
.chart-wrap { position: relative; }
.tip { position: absolute; z-index: 20; pointer-events: none; background: var(--surface-2); border: 1px solid var(--edge);
  border-radius: 7px; padding: 7px 9px; box-shadow: 0 6px 20px rgba(0,0,0,.45); transform: translate(-50%, -115%); white-space: nowrap; }
.tip .d { font: 10px var(--mono); color: var(--faint); }
.tip .v { font: 700 13px var(--mono); color: var(--text); margin-top: 1px; }
.tip .v::before { content: "●"; color: var(--signal); font-size: 9px; margin-right: 5px; vertical-align: middle; }
.tip .c { font: 10px var(--mono); color: var(--muted); margin-top: 1px; }

.foot { text-align: center; color: var(--faint); font: 10px var(--mono); padding: 18px; letter-spacing: .03em; }
[hidden] { display: none !important; }

/* ---------- mobile compaction (phones) ----------
 * The HUD/KPI tiles are sized for a wide console; on a phone the appointment
 * outcome tiles (4-up, 38px figures) overflow the viewport and the whole stack
 * is needlessly bulky. Shrink the number scale, tighten padding, drop to fewer
 * columns. Desktop is untouched — everything here is gated < 640px. */
@media (max-width: 640px) {
  :root { --n-hero: 22px; --n-kpi: 19px; --n-sub: 16px; --gap: 9px; }
  .app { padding: 12px; gap: 11px; }
  .hero { padding: 12px; }
  .panel { padding: 12px; }

  /* topbar: compact the brand subtitle + controls so the row stays tidy */
  .topbar { padding: 8px 12px; gap: 8px; }
  .brand .sub { display: none; }
  .tf-btn { padding: 4px 8px; font-size: 11px; }
  .topbar-right { gap: 8px; }
  .view-btn { padding: 5px 12px; }

  /* appointment outcomes: 2-up, minimal tiles */
  .appt-outcomes { grid-template-columns: repeat(2, 1fr); gap: 8px; }
  .out-tile { padding: 9px 11px; border-radius: 8px; }
  .out-tile .v { font-size: 26px; }
  .out-tile .eyebrow { margin-bottom: 5px; }
  .out-tile small { margin-top: 5px; font-size: 10px; }
  .appt-summary { padding: 8px 11px; gap: 6px; }
  .appt-summary b { font-size: 14px; }

  /* accounts: the 3-up mini grid's tracks have implicit min-width:auto, so a long
     mono figure forces a track wider than 1fr and blows .acct past the viewport.
     minmax(0,1fr) lets the tracks shrink → .acct stays inside its column. */
  .accounts { grid-template-columns: minmax(0, 1fr); }
  .acct { padding: 12px; }
  .mini { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .mini .m { padding: 6px 7px; }
  .mini .m .mv { overflow: hidden; text-overflow: ellipsis; }

  /* metric-definition tooltips are position:absolute, left:0, max-content wide —
     even visibility:hidden they extend ~220px past a right-edge anchor and expand
     the page width. Take them out of layout until actually shown (touch = tap to
     open via .open); clamp width to the viewport when open. */
  .deftip { display: none; max-width: calc(100vw - 28px); }
  .def.open > .deftip, .def:focus > .deftip { display: block; }
}

/* ---------- responsive ---------- */
@media (min-width: 640px) {
  .readout { grid-template-columns: repeat(4, 1fr); }
  .accounts { grid-template-columns: repeat(2, 1fr); }
  .inv-strip { grid-template-columns: repeat(5, 1fr); }
}
@media (min-width: 1000px) {
  /* desktop: turn the vertical stack into a 12-col grid that uses its width.
     align-items: stretch (default) makes paired cards equal height; the short
     panels flex-fill their column (see below) so there's no dead space. */
  .app { display: grid; grid-template-columns: repeat(12, 1fr); gap: 14px; align-content: start; }
  /* auto-fit, not repeat(3): the account count is 2, and a hard 3-track grid
     left the whole right third of the panel empty while both cards rendered at
     two-thirds width. auto-fit collapses the tracks nothing occupies, so N
     accounts always split the full width into N equal columns — 2 → halves,
     3 → thirds — and the cards stay the same size as each other, which is the
     point: neither account gets more real estate than the other. */
  .accounts { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
  .readout { grid-template-columns: repeat(8, 1fr); }
  #attention { grid-column: 1 / -1; }
  #panel-appt { grid-column: span 8; }
  #panel-pipeline { grid-column: span 4; }
  #panel-appointments { grid-column: 1 / -1; }
  #panel-rebook { grid-column: 1 / -1; }
  #readout { grid-column: 1 / -1; }
  #panel-trend { grid-column: 1 / -1; }
  #panel-inventory { grid-column: 1 / -1; }
  #panel-accounts { grid-column: 1 / -1; }
  #panel-reservoir { grid-column: 1 / -1; }
  #panel-sprinkle { grid-column: span 6; }
  #panel-infra { grid-column: span 6; }
  /* equal heights: short panels distribute their content to fill the row */
  #panel-appt, #panel-pipeline, #panel-trend, #panel-sprinkle, #panel-infra { display: flex; flex-direction: column; }
  #panel-appt .appt-grid, #panel-pipeline .pipeline, #panel-trend .chart-wrap,
  #panel-sprinkle #sprinkle-body, #panel-infra #infra-body { flex: 1; }
  .appt-grid { grid-template-rows: auto 1fr; }
}
@media (prefers-reduced-motion: reduce) { * { transition: none !important; animation: none !important; } }

/* ── Audience tab ─────────────────────────────────────────────────────────── */
.viewtabs { margin-right: auto; }   /* sits next to the brand; pushes the controls to the right */
.viewtabs-pill { display: inline-flex; gap: 2px; background: var(--ink-2);
  border: 1px solid var(--edge); border-radius: 8px; padding: 3px; }
.view-btn { border: 0; background: transparent; color: var(--muted); padding: 6px 16px;
  border-radius: 6px; font: 600 11.5px var(--sans); letter-spacing: .04em; cursor: pointer; }
.view-btn:hover { color: var(--text); }
.view-btn.active { background: var(--signal); color: #04161f; }

.audview { max-width: 1200px; margin: 0 auto; padding: 16px; display: flex;
  flex-direction: column; gap: 14px; }
.aud-grid { grid-template-columns: 1fr; }
@media (min-width: 880px) { .aud-grid { grid-template-columns: 1fr 1fr; } .aud-wide { grid-column: 1 / -1; } }

/* headline */
.aud-headline { display: flex; flex-direction: column; gap: 8px; }
.aud-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
@media (max-width: 620px) { .aud-stats { grid-template-columns: repeat(2, 1fr); } }
.aud-stat { background: var(--ink-2); border: 1px solid var(--edge-soft); border-radius: 8px; padding: 9px 11px; }
.aud-stat .ml { color: var(--muted); font-size: 9.5px; letter-spacing: .08em; text-transform: uppercase; }
.aud-stat .mv { font: 600 var(--n-sub) var(--mono); margin-top: 3px; color: var(--text); }
.aud-stat .mv.accent { color: var(--signal); font-size: var(--n-hero); }
.aud-sub { color: var(--faint); font: 500 11px var(--mono); }

/* category bars */
.aud-cats { display: flex; flex-direction: column; }
.aud-cat { display: grid; grid-template-columns: 1fr 4fr auto auto; align-items: center; gap: 8px; }
.aud-cat .nm { font: 500 11.5px var(--sans); color: var(--text); white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; }
.aud-cat .bar { background: var(--track); border-radius: 4px; height: 7px; overflow: hidden; }
.aud-cat .bar i { display: block; height: 100%; background: var(--signal); border-radius: 4px; }
.aud-cat .ct { font: 600 11px var(--mono); color: var(--text); text-align: right; min-width: 48px; }
.aud-cat .st { font: 500 9.5px var(--sans); color: var(--faint); min-width: 22px; }

/* category treemap (hero) — tile area = lead count, blue intensity = share */
.aud-treemap { position: relative; width: 100%; height: 320px; border-radius: 8px; }
.tm-tile { position: absolute; overflow: hidden; cursor: pointer; padding: 6px 8px;
  display: flex; flex-direction: column; justify-content: space-between; gap: 2px;
  border: 1px solid var(--ink); border-radius: 5px; transition: filter .12s, outline-color .12s;
  outline: 2px solid transparent; outline-offset: -2px; }
.tm-tile:hover { filter: brightness(1.2); z-index: 2; }
.tm-tile.sel { outline-color: var(--text); z-index: 3; }
.tm-tile .tm-nm { font: 600 11px var(--sans); line-height: 1.12; color: #f3f8ff; overflow: hidden;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; text-shadow: 0 1px 2px rgba(0,0,0,.45); }
.tm-tile .tm-ct { font: 700 12px var(--mono); color: #fff; align-self: flex-start; text-shadow: 0 1px 2px rgba(0,0,0,.45); }
.tm-tile.sm .tm-nm { -webkit-line-clamp: 1; font-size: 9.5px; }
.tm-tile.sm .tm-ct { font-size: 10px; }
.tm-tile.xs { padding: 3px 4px; }
.tm-tile.xs .tm-nm { display: none; }
.tm-tile.xs .tm-ct { font-size: 9px; }
.tm-detail { margin-top: 12px; }
.tm-detail.empty { display: none; }
.tm-dh { display: flex; gap: 8px; align-items: baseline; margin-bottom: 8px; font: 600 12px var(--sans); color: var(--text); }
.tm-dh b { color: var(--signal); font-weight: 700; }
.tm-dh .ct { color: var(--text); font: 600 11px var(--mono); }
.tm-dh .dim { color: var(--faint); font-weight: 400; font-size: 10px; letter-spacing: .04em; text-transform: uppercase; margin-left: auto; }
.tm-strow { display: grid; grid-template-columns: 104px 1fr 54px; align-items: center; gap: 9px; padding: 2px 0; }
.tm-strow .s-nm { font: 500 11px var(--sans); color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tm-strow .s-bar { background: var(--track); height: 7px; border-radius: 4px; overflow: hidden; }
.tm-strow .s-bar i { display: block; height: 100%; background: var(--signal); border-radius: 4px; }
.tm-strow .s-ct { font: 600 11px var(--mono); color: var(--text); text-align: right; }
.tm-hint { font: 500 10.5px var(--sans); color: var(--faint); font-style: italic; margin-top: 9px; }

/* US lead heatmap (tile cartogram) */
.us-wrap { display: grid; grid-template-columns: 1.7fr 1fr; gap: 22px; align-items: start; }
@media (max-width: 760px) { .us-wrap { grid-template-columns: 1fr; } }
.us-grid { display: grid; grid-template-columns: repeat(11, 1fr); gap: 2.5px; }
.us-tile { aspect-ratio: 1 / 1; border-radius: 3px; background: var(--ink-2); border: 1px solid var(--edge-soft);
  display: flex; align-items: center; justify-content: center; min-width: 0; cursor: pointer;
  outline: 2px solid transparent; outline-offset: -2px; transition: filter .1s, outline-color .1s; }
.us-tile:hover { filter: brightness(1.25); }
.us-tile.empty { background: transparent; border-color: transparent; cursor: default; }
.us-tile.sel { outline-color: #fff; z-index: 2; }
.us-tile .us-ab { font: 600 9px var(--mono); color: rgba(255, 255, 255, .5); letter-spacing: -.02em; }
.us-tile.empty .us-ab { display: none; }
.us-tile.hot .us-ab { color: #04161f; }
.us-rank { display: flex; flex-direction: column; gap: 3px; }
.us-rank-h { font: 600 10px var(--sans); letter-spacing: .08em; text-transform: uppercase; color: var(--muted); margin-bottom: 4px; }
.us-rrow { display: grid; grid-template-columns: 15px 24px 1fr 52px; align-items: center; gap: 8px; }
.us-rrow .r-n { font: 600 9.5px var(--mono); color: var(--faint); text-align: right; }
.us-rrow .r-ab { font: 600 11px var(--mono); color: var(--text); }
.us-rrow .r-bar { background: var(--track); height: 6px; border-radius: 3px; overflow: hidden; }
.us-rrow .r-bar i { display: block; height: 100%; background: var(--signal); border-radius: 3px; }
.us-rrow .r-ct { font: 600 11px var(--mono); color: var(--text); text-align: right; }
.us-rmore { font: 500 10px var(--sans); color: var(--faint); font-style: italic; padding: 5px 0 0 23px; }
.us-legend { display: flex; align-items: center; gap: 8px; margin-top: 14px; }
.us-leg-lbl { font: 500 10px var(--sans); color: var(--faint); text-transform: uppercase; letter-spacing: .06em; }
.us-leg-grad { width: 120px; height: 8px; border-radius: 4px; background: linear-gradient(90deg, rgb(26, 39, 58), rgb(108, 200, 255)); }
.us-leg-note { margin-left: auto; font: 500 10.5px var(--mono); color: var(--faint); }

/* category coverage — dense 2-up, fired-% bar tinted by yield band */
.aud-matrix-wrap { display: flex; flex-direction: column; gap: 10px; }
.cov-grid { display: grid; grid-template-columns: 1fr; gap: 1px 28px; }
@media (min-width: 720px) { .cov-grid { grid-template-columns: 1fr 1fr; } }
.cov-row { display: grid; grid-template-columns: minmax(80px, 1fr) auto 30px; align-items: center; gap: 10px;
  padding: 2px 5px; border-radius: 5px; }
.cov-row.act { cursor: pointer; }
.cov-row.act:hover { background: var(--ink-2); }
.cov-row.sel { background: rgba(92, 200, 255, .13); }
.cov-nm { font: 500 11px var(--sans); color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cov-dots { display: inline-flex; gap: 4px; }
.cov-d { width: 9px; height: 9px; border-radius: 50%; border: 1px solid var(--edge); box-sizing: border-box; }
.cov-d.on { border-color: transparent; }
.cov-pct { font: 600 10.5px var(--mono); color: var(--muted); text-align: right; }
.cov-legend { display: flex; flex-wrap: wrap; gap: 4px 12px; align-items: center; margin-top: 4px; }
.cov-leg { font: 500 10.5px var(--sans); color: var(--faint); display: inline-flex; align-items: center; gap: 5px; }
.cov-leg.dim { color: var(--faint); }
.cov-leg .sw { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }

/* cross-filter pill */
.aud-filter { margin: 0; }
.xf-pill { display: inline-flex; align-items: center; gap: 10px; padding: 6px 8px 6px 12px;
  background: var(--ink-2); border: 1px solid var(--signal); border-radius: 999px; }
.xf-pill .xf-eye { font: 700 8.5px var(--sans); letter-spacing: .1em; color: var(--signal); }
.xf-pill .xf-k { font: 600 12px var(--sans); color: var(--text); }
.xf-pill .xf-note { font: 500 10.5px var(--sans); color: var(--faint); }
.xf-pill .xf-x { border: 0; background: var(--edge); color: var(--text); font: 600 10px var(--sans);
  padding: 4px 10px; border-radius: 999px; cursor: pointer; }
.xf-pill .xf-x:hover { background: var(--signal); color: #04161f; }

/* base growth — daily-add bars (bulk-import days capped + amber) */
.gro-bars { display: flex; align-items: flex-end; gap: 2px; height: 64px; }
.gro-col { flex: 1 1 0; height: 100%; display: flex; align-items: flex-end; min-width: 0; }
.gro-col i { display: block; width: 100%; background: var(--signal); border-radius: 2px 2px 0 0; min-height: 2px; }
.gro-col i.bulk { background: var(--warn); }
.gro-axis { display: flex; justify-content: space-between; margin-top: 5px; font: 500 10px var(--mono); color: var(--faint); }

/* stacked bars + legend (territory, providers) */
.aud-stack { display: flex; height: 12px; border-radius: 5px; overflow: hidden; background: var(--track);
  margin-bottom: 8px; }
.aud-stack i { display: block; height: 100%; }
.aud-legend { display: flex; flex-wrap: wrap; gap: 4px 12px; margin-bottom: 6px; }
.aud-legend .lg { font: 500 10.5px var(--sans); color: var(--text); display: inline-flex; align-items: center; gap: 5px; }
.aud-legend .lg.dim { color: var(--faint); }
.aud-legend .sw { width: 9px; height: 9px; border-radius: 2px; display: inline-block; }
.aud-line { font: 500 11px var(--sans); color: var(--text); margin-top: 4px; }
.aud-line.good { color: var(--up); }
.aud-line.dim { color: var(--faint); }
.aud-depth { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 6px; }
.aud-depth .dp { font: 500 10px var(--mono); color: var(--faint); display: inline-flex; align-items: center; gap: 4px; }
.aud-depth .dbar { width: 34px; height: 6px; background: var(--track); border-radius: 3px; overflow: hidden; }
.aud-depth .dbar i { display: block; height: 100%; background: var(--signal); }

/* growth */
.aud-spark { height: 34px; margin-bottom: 6px; }
.aud-spark svg { width: 100%; height: 100%; }

/* yield league */
.aud-yrow { display: grid; grid-template-columns: 1fr auto; grid-template-areas: "nm cpl" "meta meta";
  gap: 1px 8px; padding: 4px 0; border-bottom: 1px solid var(--edge-soft); }
.aud-yrow .nm { grid-area: nm; font: 500 11.5px var(--sans); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.aud-yrow .cpl { grid-area: cpl; font: 600 12px var(--mono); text-align: right; }
.aud-yrow .cpl.good { color: var(--up); } .aud-yrow .cpl.bad { color: var(--down); }
.aud-yrow .meta { grid-area: meta; font: 500 9.5px var(--mono); color: var(--faint); }
.aud-div { height: 1px; background: var(--edge); margin: 6px 0; }

/* eComm store niches — one row per footprint search term. The sparkline gets
 * its own grid cell so a niche's 30d shape reads on the same line as its ICP
 * fit; "—" in .pct.dim means NO verdict yet, which is not the same finding as
 * 0% and must not share the red. */
.aud-nrow { display: grid; grid-template-columns: 1fr 90px auto;
  grid-template-areas: "nm spk pct" "meta meta meta"; gap: 1px 8px; padding: 4px 0;
  border-bottom: 1px solid var(--edge-soft); }
.aud-nrow .nm { grid-area: nm; font: 500 11.5px var(--sans); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.aud-nrow .spk { grid-area: spk; display: flex; align-items: flex-end; gap: 0; height: 14px; }
.aud-nrow .spk i { display: block; flex: 1 1 0; background: var(--signal); min-height: 2px;
  box-shadow: inset -1px 0 0 var(--surface); }
.aud-nrow .pct { grid-area: pct; font: 600 12px var(--mono); text-align: right; }
.aud-nrow .pct.good { color: var(--up); }
.aud-nrow .pct.warn { color: var(--warn); }
.aud-nrow .pct.dim { color: var(--faint); }
.aud-nrow .meta { grid-area: meta; font: 500 9.5px var(--mono); color: var(--faint); }

/* ICP screening — one row per client rubric. Wide panel, so the IN count and
 * IN% sit on the headline row beside the name with the IN/UNSURE/OUT split bar,
 * and the evidence + freshness meta wraps underneath. Narrow screens collapse
 * the bar onto its own row (the grid areas below), never overflow. */
.aud-icp { display: flex; flex-direction: column; }
.icp-row { display: grid; grid-template-columns: minmax(9rem, 1fr) auto auto;
  grid-template-areas: "nm in inp" "bar bar bar" "meta meta meta";
  gap: 3px 10px; padding: 6px 0; border-bottom: 1px solid var(--edge-soft); align-items: baseline; }
@media (min-width: 880px) {
  .icp-row { grid-template-columns: minmax(9rem, 14rem) auto auto minmax(80px, 1fr);
    grid-template-areas: "nm in inp bar" "meta meta meta meta"; }
}
.icp-row .nm { grid-area: nm; font: 500 11.5px var(--sans); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.icp-row .in { grid-area: in; font: 600 var(--n-sub) var(--mono); color: var(--signal); text-align: right; }
.icp-row .inp { grid-area: inp; font: 500 10px var(--mono); color: var(--faint); }
.icp-row .bar { grid-area: bar; display: flex; height: 8px; border-radius: 4px;
  overflow: hidden; background: var(--track); align-self: center; }
.icp-row .bar i { display: block; height: 100%; }
.icp-row .meta { grid-area: meta; font: 500 9.5px var(--mono); color: var(--faint);
  display: inline-flex; align-items: center; gap: 5px; }
.icp-row .meta .dot { width: 6px; height: 6px; border-radius: 50%; flex: none; background: var(--faint); }
.icp-row .meta .dot.good { background: var(--up); }
.icp-row .meta .dot.warn { background: var(--warn); }
.icp-row .meta .dot.bad { background: var(--down); }

/* ---------- reservoir per-category strip ----------
 * Deliberately the SAME row grammar as the ICP rows above (name · dominant
 * figure · sub-figure · trend · dim meta with a tone dot) — one visual language
 * for "per-thing scorecard", not a second one. The extra `sig` area carries the
 * two exhaustion percentages, which are what a reader scans for.
 *
 * `in` is the VELOCITY and is deliberately a size up from the ICP rows' figure:
 * it is the number the operator reads this panel for. `trend` is a fixed 132px
 * — the 24h banking line is a shape, not a measurement, so it does not need to
 * grow, and pinning it stops it reclaiming the width the old split bar wasted
 * (that bar spanned the full remaining row to render a grey track). */
.res-row { grid-template-areas: "nm in inp" "trend trend trend" "sig sig sig" "meta meta meta"; }
/* A real size up from `.icp-row .in`'s --n-sub — it is the figure the panel
   exists to deliver. (This line read `font-size: var(--n-sub)` at first, which
   is what .icp-row already sets, so the comment above it was describing
   something the CSS did not do.) */
.res-row .in { color: var(--up); font-size: var(--n-kpi); letter-spacing: -.03em; }
.res-row .in.zero { color: var(--faint); }
.res-row .inp { font-size: 11px; }
.res-row .res-trend { grid-area: trend; display: block; width: 132px; height: 32px; align-self: center; }
.res-row .res-trend svg { display: block; }
.res-row .res-sig { grid-area: sig; display: inline-flex; gap: 10px;
  font: 500 9.5px var(--mono); color: var(--faint); }
@media (min-width: 880px) {
  /* Fixed tracks for the two figures, not `auto`: with auto tracks every row's
     chart started at a different x (the widths follow the digits), so the
     column of trends was ragged and could not be read down. */
  .res-row { grid-template-columns: minmax(9rem, 14rem) 7.5rem 5.5rem 132px minmax(0, 1fr);
    grid-template-areas: "nm in inp trend sig" "meta meta meta meta meta"; }
  .res-row .res-sig { justify-content: flex-end; }
}

/* ---------- collapsed sending block ----------
 * Shown in place of the send tiles when NO campaign is sending: the tab must
 * not spend most of its space rendering decayed history as live performance. */
.send-collapsed { grid-column: 1 / -1; display: flex; align-items: center; gap: 10px;
  flex-wrap: wrap; background: var(--surface); border: 1px solid var(--edge-soft);
  border-radius: var(--r); padding: 10px 13px; }
.sc-badge { font: 700 9px var(--sans); letter-spacing: .14em; text-transform: uppercase;
  color: var(--warn); border: 1px solid var(--warn); border-radius: 4px; padding: 2px 6px; }
.sc-txt { font: 11px var(--mono); color: var(--muted); letter-spacing: .01em; }
.cell.alarm .num { color: var(--down); }

.aud-empty { color: var(--faint); font: 500 11px var(--sans); font-style: italic; padding: 6px 0; }

/* ── Domains tab ──────────────────────────────────────────────────────────
 * Full-width single column: zone control strip + fleet KPIs, then the batch
 * summary (the actionable unit), then the per-domain table. Spamhaus is the
 * loud tier; SURBL et al stay a plain amber number, and "unknown" keeps its
 * own colour so a blind checker can never be mistaken for a clean verdict. */
.domview { max-width: 1200px; margin: 0 auto; padding: 16px; display: flex;
  flex-direction: column; gap: 14px; }

/* ---- type scale ----------------------------------------------------------
 * NOTHING on this tab is below 11px, and no column header is set smaller than
 * the data under it — the headers used to be ~9px letter-spaced uppercase, the
 * smallest text on screen, labelling 11.5px figures. The wide letter-spacing
 * went with them: it buys a "designed" look and costs legibility at exactly
 * the sizes where legibility is all that matters.
 *
 * The width this needed came from deleting the "Top codes" column and merging
 * the two warm-up columns — see BCOLS/COLS in domains.js. */
.domview .badge { font-size: 11px; letter-spacing: normal; }
.domview .foot { font-size: 11px; }
.domview .dm-g { font-size: 11px; }
/* The shared chrome is 9.5–10px elsewhere; on this tab it labels the numbers,
 * so it gets the same floor. Scoped, so no other view moves. */
.domview .eyebrow { font-size: 11px; letter-spacing: .06em; }
.domview .inv-cell .ml { font-size: 11px; letter-spacing: normal; text-transform: none; }
.domview .count-chip { font-size: 11px; }
.domview .rb-sub { font-size: 11px; }

/* ---- the two affordances -------------------------------------------------
 * They used to be the same glyph. Now:
 *  - INFO is the header TEXT itself: dotted underline + cursor:help. It costs
 *    no width, which is what makes it affordable on every column.
 *  - GRAPH is a bordered button with a chart glyph and a hover background. */
.dh-info { border-bottom: 1px dotted var(--muted); cursor: help; }
.dh-info:hover { border-bottom-color: var(--signal); color: var(--text); }

/* ---- legend --------------------------------------------------------------
 * Collapsed by default, so it costs one line. Same entries the tooltips above
 * are built from (payload `legend`) — one wording, no drift. */
.dh-legend { border: 1px solid var(--edge-soft); border-radius: 10px;
  background: var(--surface); padding: 10px 14px; }
.dh-legend > summary { color: var(--muted); font: 600 11px var(--mono);
  cursor: pointer; list-style: revert; }
.dh-legend > summary:hover { color: var(--text); }
.dh-legend h3 { color: var(--signal); font: 600 11px var(--mono);
  text-transform: uppercase; margin: 14px 0 6px; }
.dh-leg { display: grid; grid-template-columns: minmax(90px, 140px) 1fr;
  gap: 4px 14px; margin: 0; font: 11.5px var(--mono); }
.dh-leg dt { color: var(--text); font-weight: 600; }
.dh-leg dd { color: var(--muted); margin: 0; line-height: 1.5; }
/* severity vocabulary, usable outside a .barrow (the table's state glyphs) */
.dh-severe { color: var(--down); } .dh-blind { color: var(--warn); }
.dh-other { color: var(--warn); } .dh-clean { color: var(--up); }
.dh-unknown { color: var(--unknown); } .dh-dim { color: var(--faint); }
/* seven KPI cells, so the generic 5-up would wrap onto a lonely second row.
 * auto-fit keeps them one aligned band and degrades to 3/2/1 on its own. */
.domview .inv-strip { margin-top: 10px;
  grid-template-columns: repeat(auto-fit, minmax(148px, 1fr)); }

/* ---- the batch grid ------------------------------------------------------
 * Was a flex row with a left label and a right-aligned run of inline spans, so
 * no two rows' figures started at the same x and no column could be scanned.
 * It is now a real grid on the same discipline as .dm-row below: one figure per
 * cell, numerals right-aligned on a shared right edge, tabular figures. Column
 * 1 is minmax(190px, 2fr) — identical to .dm-row's first column — so the batch
 * grid and the domain grid share a left edge.
 * Wide content scrolls inside .dom-grid-wrap; the page body never does. */
.dom-grid-wrap { overflow-x: auto; }
.db-row { display: grid;
  /* 13 tracks, one per BCOLS entry:
     Batch Dom Mbx Capped Sent Spamhaus Other Clean Unknown Unchkd Auth Bnc Warmup */
  grid-template-columns: minmax(190px, 2fr) 54px 60px 62px 62px 116px 58px 58px 74px 74px 72px
    48px minmax(96px, 1fr);
  gap: 10px; align-items: center; min-width: 1222px; font: 11.5px var(--mono);
  padding: 5px 6px; border-radius: 7px; border: 1px solid transparent;
  border-bottom-color: var(--edge-soft); }
.db-row > .n { text-align: right; font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1; }
.db-name { display: flex; align-items: center; gap: 6px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.db-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* the disclosure: batches collapse under their account, the account SUBTOTAL
 * never hides. Collapsed is the default, so this is the affordance that says
 * there is more here. */
.db-tw { flex: 0 0 auto; border: 0; background: transparent; color: var(--muted);
  cursor: pointer; font: 11px var(--mono); line-height: 1; padding: 2px 3px;
  border-radius: 4px; }
.db-tw:hover { color: var(--text); background: var(--surface-2); }
.db-tw:focus-visible { outline: 2px solid var(--signal); outline-offset: 1px; }
.db-bn { flex: 0 0 auto; color: var(--faint); font: 11px var(--mono); }
/* Auth: NEVER the verdict palette — `auth.ok` is config hygiene, and a green
 * cell would assert a deliverability verdict it does not carry. Warmup keeps
 * the same rule for every NUMBER it shows (see .warm.ready below). */
.db-row .cfg, .db-row .warm { color: var(--muted); }
.db-row .cfg.zero, .db-row .warm.zero { color: var(--faint); }
.db-row .warm.low { color: var(--warn); }
.db-row .warm.blocked { color: var(--down); font-weight: 700; }
/* The ONE green on a warmup cell, and only ever on the word `ready`: no warmup
 * NUMBER is green, because a green number here reads as inbox placement, which
 * nothing on this tab measures. `ready` means "nothing wrong in the warmup
 * pool" and the tooltip and legend both say so. */
.db-row .warm.ready, .dm-warm.ready { color: var(--up); }
/* WARMUP is a STATE now, not a magnitude, so it left-aligns with the other
 * word columns instead of sharing a right edge with figures it can't be
 * compared against. (The numeric columns keep their right edge — that grid was
 * never the problem.) Same alignment as the TUI screen's WARMUP column. */
.db-row > .n.warm { text-align: left; }
.dh-graph { border: 1px solid var(--edge); background: transparent; color: var(--muted);
  cursor: pointer; font: 11px var(--mono); line-height: 1; padding: 1px 5px;
  margin-left: 6px; border-radius: 4px; }
.dh-graph:hover { color: var(--signal); background: var(--surface-2);
  border-color: var(--signal); }
.dh-graph:focus-visible { outline: 2px solid var(--signal); outline-offset: 1px; }
/* Headers at 11.5px — the same size as the figures beneath them — and no
 * letter-spacing. They are the labels a reader needs most. */
.db-head { color: var(--muted); font: 600 11.5px var(--mono);
  border-bottom: 1px solid var(--edge); border-radius: 0; padding-bottom: 6px; }
/* an account line is a SUBTOTAL of the batch rows under it — same columns, not
 * a dot-separated caption */
.db-acct { color: var(--text); background: var(--ink-2); margin-top: 12px;
  border-bottom-color: var(--edge); }
.db-acct .db-name { color: var(--signal); font-weight: 700; text-transform: uppercase; }
.db-batch { cursor: pointer; }
.db-batch:hover, .db-sole:hover { background: var(--ink-2); }
.db-batch.sel, .db-sole.sel { background: var(--ink-2); border-color: var(--signal); }
.db-batch:focus-visible, .db-sole:focus-visible { outline: 2px solid var(--signal);
  outline-offset: 1px; }
/* an account whose ONLY batch is (untagged): the batch row was a copy of this
 * one, so it is gone and this row carries the click instead */
.db-sole { cursor: pointer; }
/* Spamhaus keeps a meter on EVERY row (an empty track is a reading, a missing
 * bar is an artifact) and the loudest type on the tab. */
.db-sev { display: flex; align-items: center; justify-content: flex-end; gap: 7px;
  font-weight: 700; font-size: 12.5px; font-variant-numeric: tabular-nums; }
.db-sev.hit { color: var(--down); }
.db-sev.none { color: var(--faint); }
.db-sev.blind { color: var(--warn); font-size: 11.5px; }
.db-meter { flex: 0 0 42px; height: 5px; border-radius: 3px; background: var(--track);
  overflow: hidden; }
.db-meter > i { display: block; height: 100%; width: 0; background: var(--down);
  border-radius: 3px; transition: width .5s ease; }
/* Volume, not a verdict — so no palette. A batch on Spamhaus sending 1.3k a day
 * is the thing to notice, and colouring the VOLUME green or red would assert a
 * judgement about it that nothing here measures. Zero dims, never hides. */
.db-row .sent, .dm-row .sent { color: var(--text); }
.db-row .sent.zero, .dm-row .sent.zero { color: var(--faint); }
.db-row .other { color: var(--warn); } .db-row .other.zero { color: var(--faint); }
.db-row .clean { color: var(--up); } .db-row .clean.zero { color: var(--faint); }
.db-row .unk { color: var(--unknown); } .db-row .unk.zero { color: var(--faint); }
.db-row .unchk { color: var(--warn); } .db-row .unchk.zero { color: var(--faint); }

/* ---- filters -------------------------------------------------------------
 * Every axis is independent and they AND together; the active set is echoed as
 * chips below so a filtered count can never be misread as the whole fleet. */
.dom-filters { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 9px; }
.dom-q { background: var(--ink-2); border: 1px solid var(--edge); border-radius: 8px;
  color: var(--text); font: 12px var(--mono); padding: 6px 10px; min-width: 170px; flex: 1 1 170px; }
.dom-q:focus { outline: 2px solid var(--signal); outline-offset: 1px; border-color: transparent; }
.dom-sel { display: inline-flex; align-items: center; gap: 6px; }
.dom-sel > span { color: var(--muted); font: 600 11px var(--mono); }
.dom-sel select { background: var(--ink-2); border: 1px solid var(--edge); border-radius: 8px;
  color: var(--text); font: 12px var(--mono); padding: 6px 8px; }
.dom-sel select:focus { outline: 2px solid var(--signal); outline-offset: 1px; }
.dom-active { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; margin-bottom: 10px; }
.dom-active .lbl { color: var(--muted); font: 600 11px var(--mono); }
.dom-chip { display: inline-flex; align-items: center; gap: 7px; font: 600 11px var(--mono);
  color: var(--text); background: var(--ink-2); border: 1px solid var(--edge);
  border-radius: 20px; padding: 4px 6px 4px 11px; }
.dom-chip .ck { color: var(--faint); font-weight: 400; }
.dom-x { border: 0; background: transparent; color: var(--muted); cursor: pointer;
  font: 11px var(--mono); padding: 0 4px; }
.dom-x:hover { color: var(--text); }
.dom-clear { border: 1px solid var(--edge); background: transparent; color: var(--muted);
  cursor: pointer; font: 600 11px var(--mono); border-radius: 20px; padding: 4px 11px; }
.dom-clear:hover { color: var(--text); border-color: var(--signal); }
/* sortable column headers on the domain table */
.dm-head .s { cursor: pointer; color: var(--faint); }
.dm-head .s:hover { color: var(--text); }
.dm-head .s.on { color: var(--signal); }

/* the table — wide content scrolls in its own box, never the page body */
.dom-table { overflow-x: auto; }
/* 13 tracks, one per COLS entry:
   Domain Account Lists Auth Web Warmup Mbx Capped Why Sent Bnc Added VerdictAge */
.dm-row { display: grid; grid-template-columns: minmax(190px, 2fr) 84px minmax(150px, 1.5fr)
  132px minmax(96px, 1fr) 108px 46px 52px 140px 52px 46px 86px 92px; gap: 10px;
  align-items: center;
  padding: 4px 2px; border-bottom: 1px solid var(--edge-soft); font: 11.5px var(--mono);
  min-width: 1404px; }
/* The policy's own reason string — never truncated into ambiguity: "reputation"
   and "reputation_recovery" are different verdicts. */
.dm-why { color: var(--muted); font-variant-numeric: tabular-nums;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dm-why.sev { color: var(--bad); }
.dm-row:last-child { border-bottom: 0; }
.dm-head { color: var(--muted); font: 600 11.5px var(--mono);
  border-bottom: 1px solid var(--edge); position: sticky; top: 0;
  background: var(--surface); z-index: 1; }
.dm-row.severe { background: rgba(255,125,138,.05); }
.dm-dom { display: flex; align-items: center; gap: 7px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.dm-g { font-style: normal; font-size: 11px; }
.dm-dim { color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dm-hits { display: flex; flex-wrap: wrap; gap: 4px; }
.dm-hit { font: 600 11px var(--mono); color: var(--warn); background: rgba(243,193,86,.10);
  border-radius: 4px; padding: 1px 5px; white-space: nowrap; }
.dm-hit.sev { color: var(--down); background: rgba(255,125,138,.14); }

/* ---- posture columns (auth / web / warmup) --------------------------------
 * Deliberately OUTSIDE the verdict palette. `auth.ok` is config hygiene —
 * domains that pass it are blocklisted at the same rate as the rest — and
 * warmup is pool state, not inbox placement, so neither is ever green. A dash
 * is "not checked yet", the state most of the fleet is in, and it must read as
 * absence of information rather than as a zero. */
.dm-cfg, .dm-web, .dm-warm { color: var(--muted); overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.dm-none { color: var(--faint); }
.dm-cfg.bad { color: var(--warn); }
/* the record looks correct and no report is ever sent — it earns its own mark */
.dm-cfg.rua { color: var(--text); border-bottom: 1px dotted var(--warn); }
.dm-cfg .more { color: var(--faint); }
/* self-hosting is the one web configuration the data indicts (25/25 listed) */
.dm-web.self { color: var(--warn); }
.dm-warm { text-align: left; display: flex; align-items: center; justify-content: flex-start;
  gap: 6px; font-variant-numeric: tabular-nums; }
.dm-warm.low { color: var(--warn); }
.dm-warm.blocked { color: var(--down); font-weight: 700; }
.dm-warm.zero { color: var(--faint); }
/* 14-day ramp progress, and ONLY inside that window: it qualifies the
 * reputation beside it (100% on day 2 is not 100% on day 40). Past the ramp
 * there is no meter, because nothing is ramping. */
.dm-ramp { flex: 0 0 26px; height: 4px; border-radius: 2px; background: var(--track);
  overflow: hidden; }
.dm-ramp > i { display: block; height: 100%; width: 0; background: var(--muted);
  border-radius: 2px; }

/* ---- insufficient history -------------------------------------------------
 * The daily table is forward-only with no backfill, so for its first days a
 * chart would be a line through one point. This panel replaces the chart. */
.dh-insufficient { padding: 26px 18px; text-align: center; color: var(--muted);
  font: 12px var(--mono); }
.dh-insufficient .hd { color: var(--text); font: 600 13px var(--sans); margin-bottom: 8px; }
.dh-insufficient p { margin: 0 auto 10px; max-width: 46ch; line-height: 1.55; }
.dh-insufficient .one { color: var(--text); font: 12px var(--mono); margin: 14px 0 10px; }
.dh-insufficient .one b { font-size: var(--n-sub); font-variant-numeric: tabular-nums; }
.dh-insufficient .sc { color: var(--faint); font-size: 11px; }
.domview .dh-note { margin-top: 12px; }

/* Domains tab: the spec's floor is 11px, but the KPI strip reuses .eyebrow /
   .inv-cell .ml / .foot, which are 9-9.5px because Operations and Audience
   want them that small. Scope the floor to .domview so the Domains tab meets
   the spec without changing the other two tabs. */
.domview .eyebrow,
.domview .inv-cell .ml { font-size: 11px; letter-spacing: .06em; }
.domview .foot { font-size: 11px; }


/* ---- Sales team tab -------------------------------------------------------
 * Same grid discipline as the Domains tab: one figure per cell, numerals on a
 * shared right edge, tabular figures. The column TEMPLATE is set per row in
 * reps.js because the two tables have different widths, and the last column is
 * a sparkline rather than a figure. Deliberately FEW columns — the derivations
 * (showed/no-show/cancelled, won/taken) live in the cell tooltips, so the row
 * stays scannable. */
.repview { max-width: 1200px; margin: 0 auto; padding: 16px; display: flex;
  flex-direction: column; gap: 14px; }
.repview .eyebrow { font-size: 11px; letter-spacing: .06em; }
.repview .inv-strip { margin-top: 10px;
  grid-template-columns: repeat(auto-fit, minmax(148px, 1fr)); }
.repview .inv-cell .ml { font-size: 11px; letter-spacing: normal; text-transform: none; }
.repview .count-chip { font-size: 11px; }
.repview .rb-sub { font-size: 11px; }
.rp-row { display: grid; gap: 10px; align-items: center; font: 11.5px var(--mono);
  padding: 6px; border-radius: 7px; border: 1px solid transparent;
  border-bottom-color: var(--edge-soft); }
.rp-row:last-child { border-bottom-color: transparent; }
.rp-row > .n { text-align: right; font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1; }
.rp-row > .n.good { color: var(--up); }
.rp-row > .n.warn { color: var(--warn); }
.rp-row > .n.bad { color: var(--down); }
.rp-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--text); }
/* Headers at the same size as the figures beneath them — they are the labels a
   reader needs most — and each carries its own definition as a tooltip. */
.rp-head { color: var(--muted); font: 600 11.5px var(--mono);
  border-bottom: 1px solid var(--edge); border-radius: 0; padding-bottom: 6px; }
.rp-head > .n { cursor: help; text-decoration: underline dotted var(--edge);
  text-underline-offset: 3px; }
/* Direction against the prior period. It rides the figure it qualifies rather
   than taking a column of its own — an arrow is not a number and should not
   share a right edge with one. */
.rp-d { font-size: 10px; }
.rp-d.good { color: var(--up); } .rp-d.bad { color: var(--down); }
.rp-spark { height: 32px; min-width: 90px; }
.rp-empty { color: var(--faint); font: 11.5px var(--mono); padding: 10px 6px; }
/* The coverage caveat: ONE line, always on. A stack of warning boxes stops
   being read; a single line under the KPI strip does not. */
.rp-coverage { margin-top: 10px; }
.rp-cov-line { padding: 7px 9px; border-radius: 7px; background: var(--ink-2);
  border: 1px solid var(--edge-soft); color: var(--muted);
  font: 11px var(--sans); line-height: 1.5; }
.rp-cov-line.warn { border-color: var(--warn); color: var(--text); }
.rp-leg { display: grid; grid-template-columns: 130px 1fr; gap: 4px 12px;
  padding: 5px 0; font: 11px var(--sans); color: var(--muted); line-height: 1.5; }
.rp-leg b { color: var(--text); }

/* The Campaigns tab had no container rule either — the same defect as .phview,
   caught by test_web_style_consistency rather than by eye. */
.cmpview { max-width: 1200px; margin: 0 auto; padding: 16px; display: flex;
  flex-direction: column; gap: 14px; }

/* ── Campaigns tab ──────────────────────────────────────────────────
   Grid columns are shared by the header, account and campaign rows so the
   three stay aligned; campaign rows indent via padding, never a second grid. */
/* The title ran straight into its own subtitle ("Campaignsdeliverability is
   per account…") — the other tabs' h2 supplies no gap and this one never added
   it. */
.cmpview h2 .rb-sub { margin-left: 10px; font-size: 11px; }
.cmp-table { display: flex; flex-direction: column; gap: 2px; }
.cmp-row {
  display: grid;
  grid-template-columns: minmax(230px, 2.1fr) 76px 72px 68px 62px 132px minmax(130px, 1fr);
  gap: 12px; align-items: center; padding: 9px 10px; border-radius: 5px;
}
.cmp-head { padding-bottom: 5px; border-bottom: 1px solid var(--edge-soft); }
.cmp-h { font: 600 10px var(--sans); letter-spacing: .09em; text-transform: uppercase; color: var(--faint); }
.cmp-h:not(:first-child) { text-align: right; }
.cmp-h:last-child { text-align: left; }
.cmp-acct { background: var(--surface-2); cursor: pointer; }
.cmp-acct:hover { background: var(--ink-2); }
.cmp-acct:focus-visible { outline: 2px solid var(--signal); outline-offset: -2px; }
/* An account with nothing in the window: one dim line, no row of dashes. */
.cmp-idle { background: transparent; cursor: default; opacity: .62; }
/* No margin: the two flexible tracks split any left margin between them, so
   it pushed campaign rows out of step with the header they sit under. */
.cmp-camp { padding-left: 26px; border-left: 2px solid var(--edge-soft); }
.cmp-c-name { display: flex; flex-direction: column; min-width: 0; gap: 3px; }
.cmp-ahead { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.cmp-caret { color: var(--faint); }
.cmp-aname { font: 700 13px var(--sans); text-transform: capitalize; }
.cmp-count { font: 500 10.5px var(--sans); color: var(--faint); }
.cmp-cname { font: 500 12.5px var(--sans); }
.cmp-cname, .cmp-aname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Deliverability facts as separate items, dot-separated by rule rather than by
   a hand-built string — so one of them can carry a colour without the whole
   sentence turning red. */
.cmp-csub { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 0;
            font: 11px var(--sans); color: var(--muted); min-width: 0; }
/* Separator AFTER each item but the last — as a leading ::before it opened
   any wrapped line with an orphan "·". */
.cmp-csub > span:not(:last-child)::after { content: "·"; margin: 0 6px; color: var(--dim); }
.cmp-csub .warn { color: var(--warn); }
.cmp-csub .bad { color: var(--down); }
.cmp-status { text-transform: uppercase; letter-spacing: .06em; font-weight: 600; font-size: 9.5px; }
.cmp-status.on { color: var(--up); }
.cmp-status.off { color: var(--faint); }

.cmp-num { text-align: right; font: 12.5px var(--mono); font-variant-numeric: tabular-nums;
           color: var(--text); min-width: 0; }
.cmp-num.strong { font-weight: 700; }
.cmp-num.bad { color: var(--down); }
/* The 30-day bounce under the coloured 7-day one: kept visible, never coloured. */
.cmp-bsub { font: 10px var(--mono); color: var(--faint); font-weight: 400; margin-top: 2px; }

/* The anchor column. $543 and $45 are the finding on this page; they used to
   render as identical 12px text in a 74px column. */
/* min-width:0 — a grid item's default `auto` let this cell grow past its
   132px track, dragging the cost bar back underneath the Per-1K column. */
.cmp-cost { display: flex; flex-direction: column; align-items: stretch; gap: 4px;
            min-width: 0; text-align: right; }
.cmp-costv { font: 700 16px var(--mono); letter-spacing: -.02em; line-height: 1; }
.cmp-costv.good { color: var(--up); }
.cmp-costv.warn { color: var(--warn); }
.cmp-costv.bad  { color: var(--down); }
/* Cost-model marks (contract cohort.marks): ~ thin and ⚠ excluded are dimmed,
   *▲/*▼ carry the engine's significance test as bad/good. */
.cmp-costv.thin, .cmp-num.thin { color: var(--muted); }
.cmp-costv.excl, .cmp-num.excl { color: var(--faint); text-decoration: line-through; }
.cmp-num.good { color: var(--up); }
.cmp-more { cursor: pointer; color: var(--signal); }
/* Per-campaign cohort table: week bought in column A, CPL | CPB per vertical. */
.cmp-cohort { margin: 2px 0 10px 26px; overflow-x: auto; }
.cmp-ctab { border-collapse: collapse; font: 11.5px var(--mono); font-variant-numeric: tabular-nums; }
.cmp-ctab th { font: 600 9.5px var(--sans); letter-spacing: .07em; text-transform: uppercase;
               color: var(--faint); padding: 3px 8px; text-align: right; white-space: nowrap; }
.cmp-ctab td { padding: 3px 8px; text-align: right; white-space: nowrap; }
.cmp-ctab td.wk, .cmp-ctab th:first-child { text-align: left; }
.cmp-ctab td.thin { color: var(--muted); }
.cmp-ctab td.bad { color: var(--down); }
.cmp-ctab td.good { color: var(--up); }
.cmp-ctab tr.excl td { color: var(--faint); text-decoration: line-through; }
.cmp-ctab tr.tot td { border-top: 1px solid var(--edge-soft); font-weight: 700; }
.cmp-blind { font: 10.5px var(--sans); color: var(--faint); font-style: italic; }
.cmp-dash { color: var(--dim); font: 14px var(--mono); }
/* Bar is the CHEAPEST call over this one, so a full bar is the best on the
   page and a stub is the multiple you are paying. */
/* Sized to sit UNDER the number, not across the whole 132px track — a
   full-width rule read as belonging to the Per-1K column beside it. */
.cmp-costbar { width: 84px; margin-left: auto; height: 3px; border-radius: 2px; background: var(--track); overflow: hidden; }
.cmp-costbar > i { display: block; height: 100%; border-radius: 2px; background: var(--muted); }
.cmp-costbar > i.good { background: var(--up); }
.cmp-costbar > i.warn { background: var(--warn); }
.cmp-costbar > i.bad  { background: var(--down); }

/* Totals strip — the number the whole table is evidence for. */
/* auto-fit, not flex-wrap: a wrapped flex row stretches its last item, so
   between ~640 and ~790px the strip ended with one 698px-wide card. */
.cmp-sum { display: grid; grid-template-columns: repeat(auto-fit, minmax(118px, 1fr));
           gap: 10px; margin-bottom: 14px; }
.cmp-sumcell { background: var(--surface-2); border: 1px solid var(--edge-soft);
               border-radius: 6px; padding: 9px 11px; }
.cmp-sumv { font: 700 18px var(--mono); letter-spacing: -.02em; line-height: 1.1; color: var(--text); }
.cmp-sumv.strong { color: var(--up); }
.cmp-sumv.good { color: var(--up); }
.cmp-sumv.warn { color: var(--warn); }
.cmp-sumv.bad  { color: var(--down); }
.cmp-suml { font: 600 9.5px var(--sans); letter-spacing: .07em; text-transform: uppercase;
            color: var(--faint); margin-top: 3px; }

/* Daily sends: one column per day, booked calls marked on top of THEIR OWN bar
   (the marker used to sit at the top of the column, floating free of the sends
   it annotates), and a silent day is empty rather than a 2% stub. */
.cmp-spark { display: flex; align-items: flex-end; gap: 1px; height: 30px; }
/* The axis rule belongs to a chart that HAS bars — account rows append an
   empty .cmp-spark to hold the column, and it drew a baseline under nothing. */
.cmp-spark:not(:empty) { border-bottom: 1px solid var(--edge-soft); }
.cmp-spark-col { flex: 1 1 0; height: 100%; display: flex; flex-direction: column;
                 justify-content: flex-end; align-items: center; position: relative; }
.cmp-spark-bar { width: 100%; background: #2f6f88; border-radius: 1px 1px 0 0; }
.cmp-spark-dot { position: absolute; width: 4px; height: 4px; border-radius: 50%;
                 background: var(--warn); }

.cmp-notes { margin-top: 14px; display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.cmp-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.cmp-chip { font: 11px var(--sans); color: var(--muted); background: var(--surface-2);
            border: 1px solid var(--edge-soft); border-radius: 999px; padding: 3px 10px; }
.cmp-chip.warn { color: var(--warn); border-color: rgba(243,193,86,.28); }
.cmp-disc { font: 11px var(--sans); color: var(--faint); background: none; border: 0;
            padding: 2px 0; cursor: pointer; text-align: left; }
.cmp-disc:hover { color: var(--muted); }
.cmp-discbody { display: flex; flex-direction: column; gap: 5px; }
.cmp-note { font: 11px var(--sans); color: var(--muted); line-height: 1.45; max-width: 82ch; }
.cmp-empty { padding: 14px 10px; color: var(--muted); font-size: 12px; }
@media (max-width: 1100px) {
  /* Drop the per-1K rate and the trend before anything else: the rate is
     derivable from the two columns beside it and the trend is context. */
  .cmp-row { grid-template-columns: minmax(180px, 2fr) 72px 68px 64px 120px; }
  .cmp-row > :nth-child(5), .cmp-row > :nth-child(7) { display: none; }
}
@media (max-width: 760px) {
  .cmp-row { grid-template-columns: minmax(140px, 2fr) 70px 110px; }
  .cmp-row > :nth-child(3), .cmp-row > :nth-child(4) { display: none; }
}

/* ── Perpetual Health tab ─────────────────────────────────────────────────
   External client, own Odoo CRM. Funnel table + per-funnel sparkline.

   THE CONTAINER BLOCK BELOW WAS MISSING ENTIRELY until 2026-09-16. `.phview`
   was set on the wrapper in index.html and defined in no stylesheet, so while
   every sibling view (.audview, .domview, .repview) centred itself at 1200px
   with 16px gutters and a 14px gap, PH rendered as a bare block: full-bleed to
   the viewport, no gutters, and sections butted edge to edge with no rhythm.
   That one absent rule was most of what read as "the padding and components are
   different on this tab". The type overrides that follow mirror .repview for
   the same reason it has them — the 9.5px/.15em `.eyebrow` default is a label
   size, not a section-heading size, and PH has more sections than any other
   tab. Keep these four in sync with .repview; they are one design, not two. */
.phview { max-width: 1200px; margin: 0 auto; padding: 16px; display: flex;
  flex-direction: column; gap: 14px; }
/* The attention strip is the SAME element as Operations' — same class, same
   markup, rendered by the same function in app.js. It is listed here only so a
   reader looking for it in the PH block finds the note rather than nothing. */
.phview .attention { margin: 0; }
.phview .eyebrow { font-size: 11px; letter-spacing: .06em; }
.phview .inv-cell .ml { font-size: 11px; letter-spacing: normal; text-transform: none; }
/* "638 in window" wrapped to two lines and shoved the heading around. */
.phview .count-chip { font-size: 11px; white-space: nowrap; }
.phview .rb-sub { font-size: 11px; }
/* The strip is the tab's headline row (calls / texts / appointments / sales).
   auto-fit rather than a fixed 2-up so four tiles sit on one line on a desktop
   and stack honestly on a phone, matching .repview. */
.phview .inv-strip { margin-top: 10px;
  grid-template-columns: repeat(auto-fit, minmax(148px, 1fr)); }
/* Every PH chart gets the same box so a reader compares shapes, not frames.
   Previously each panel sized its own and the two-up call row drew one chart at
   500 max beside another at 40, which reads as two unrelated instruments. */
.phview .chart-wrap { margin-top: 2px; }

/* Headline tiles: a figure, its trend arrow, and the window it covers. The
   arrow is never the only carrier of direction — the delta text repeats it, so
   it survives colour-blindness and a greyscale print. */
.ph-kpi .mv { display: flex; align-items: baseline; gap: 7px; flex-wrap: wrap; }
.ph-kpi .ph-delta { font: 600 10.5px var(--mono); letter-spacing: .01em; }
.ph-kpi .ph-delta.up { color: var(--up); }
.ph-kpi .ph-delta.down { color: var(--down); }
.ph-kpi .ph-delta.flat { color: var(--faint); }
.ph-kpi .ph-foot { color: var(--faint); font: 9.5px var(--mono); margin-top: 4px;
  letter-spacing: .02em; }
.ph-kpi.nofeed .mv { color: var(--faint); }

/* A stale hand-dropped export must announce itself. The Aircall CSV froze at
   2026-08-28 and silently flattened every call chart for 19 days; nothing on
   screen said the file was old. */
.ph-stale { display: inline-flex; align-items: center; gap: 6px; font: 600 10.5px var(--mono);
  color: var(--warn); background: rgba(243,193,86,.08); border: 1px solid rgba(243,193,86,.28);
  border-radius: 20px; padding: 2px 9px; margin-left: 7px; }

/* Chart legend — needed the moment a chart carries two series (calls split by
   direction, leads split mapped/unmapped). Swatch + word, never colour alone. */
.ph-legend { display: flex; flex-wrap: wrap; gap: 14px; margin: 6px 0 2px;
  font: 10.5px var(--mono); color: var(--muted); }
.ph-legend span { display: inline-flex; align-items: center; gap: 6px; }
.ph-legend i { width: 9px; height: 9px; border-radius: 2px; display: inline-block; }

/* Share-of-total pie + its legend (who is texting). Colour is never the only
   carrier: every slice is named with its count and share. */
/* The global `svg { width: 100% }` stretched the pie to the full panel width —
   a 900px circle. A pie is sized by its own geometry, not by its container. */
.ph-pie-wrap { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; margin-top: 6px; }
.ph-pie-wrap svg { width: 168px; height: 168px; flex: 0 0 auto; }
.ph-pie-legend { display: grid; gap: 4px; font: 11.5px var(--mono); }
.ph-pie-legend span { display: flex; align-items: center; gap: 8px; }
.ph-pie-legend i { width: 9px; height: 9px; border-radius: 2px; flex: 0 0 auto; }
.ph-pie-legend b { font-weight: 400; color: var(--text); min-width: 122px; }
.ph-pie-legend .pv { color: var(--muted); font-variant-numeric: tabular-nums; }
/* the band-stack legend reuses the same shape */
.ph-legend .pv { color: var(--muted); margin-left: 4px; font-variant-numeric: tabular-nums; }
.ph-legend b { font-weight: 400; color: var(--text); }

/* Rep table: top 5, rest behind a toggle. */
.ph-more { margin-top: 8px; background: transparent; border: 1px solid var(--edge);
  color: var(--muted); padding: 5px 11px; border-radius: 7px; cursor: pointer;
  font: 600 11px var(--sans); }
.ph-more:hover { color: var(--text); border-color: var(--faint); }
.rep-n.warn { color: var(--warn); }

/* Live-event cohort blocks: a heading per webinar, then its funnel. */
.ph-ev-head { display: flex; align-items: baseline; gap: 10px; margin-top: 18px; }
.ph-ev-head:first-child { margin-top: 4px; }
.phview #ph-events .inv-strip { margin-bottom: 10px; }
.ph-row { display: grid; grid-template-columns: minmax(170px, 1.7fr) 74px 64px 62px 58px
  56px 70px 48px minmax(96px, 1fr); gap: 9px; align-items: center;
  padding: 5px 2px; border-bottom: 1px solid var(--edge-soft); font: 11.5px var(--mono);
  min-width: 880px; }
.ph-row:last-child { border-bottom: 0; }
.ph-head { color: var(--muted); font: 600 11.5px var(--mono);
  border-bottom: 1px solid var(--edge); position: sticky; top: 0;
  background: var(--surface); z-index: 1; }
.ph-name { display: flex; align-items: center; gap: 7px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
/* A funnel excluded from opt-in totals is still shown — hiding it would make
   the numbers unexplainable — but it must not read as a peer. */
.ph-row.excl .ph-name { color: var(--muted); }
.ph-num { text-align: right; }
/* Null, not zero: no spend feed is wired, so every cost column is "—" until
   credentials land. Never render 0 here — it would read as "free". */
.ph-null { color: var(--faint); text-align: right; }
.ph-spark { height: 32px; }

/* PH: bar rows (pipeline, ageing, speed buckets, inbound-by-hour) and the
   two-up chart row. Bar WIDTHS are set through CSSOM in ph.js, never as an
   inline style attribute — the dashboard's CSP forbids those. */
.ph-bars { display: grid; gap: 4px; }
.ph-brow { display: grid; grid-template-columns: minmax(120px, 200px) 1fr 132px;
  gap: 10px; align-items: center; font: 11.5px var(--mono); }
.ph-btrack { position: relative; height: 12px; border-radius: 3px; background: var(--ink-2); overflow: hidden; }
.ph-bfill { position: absolute; inset: 0 auto 0 0; border-radius: 3px; background: var(--accent, #5cc8ff); opacity: .55; }
.ph-bfill.bad { background: #ff7d8a; }
.ph-bfill.warn { background: #f3c156; }
.ph-bval { text-align: right; color: var(--muted); }
.ph-sub-h { font: 600 10px var(--mono); letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted); margin: 14px 0 6px; }
.ph-2col { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
@media (max-width: 900px) { .ph-2col { grid-template-columns: 1fr; } }
.ph-crow { display: grid; grid-template-columns: minmax(150px, 2fr) 74px 74px 74px 74px;
  gap: 10px; align-items: center; padding: 5px 2px;
  border-bottom: 1px solid var(--edge-soft); font: 11.5px var(--mono); min-width: 560px; }
.ph-crow:last-child { border-bottom: 0; }
.ph-prow { display: grid; grid-template-columns: minmax(150px, 2fr) 64px 64px 64px 64px 64px 88px 88px;
  gap: 10px; align-items: center; padding: 5px 2px;
  border-bottom: 1px solid var(--edge-soft); font: 11.5px var(--mono); min-width: 800px; }
.ph-prow:last-child { border-bottom: 0; }

/* reservoir per-row verdict word — the shared judgement from
   data/reservoir_health, rendered as text so it needs no decoding. */
.res-verdict { font-weight: 600; letter-spacing: .02em; }
.res-verdict.warn { color: var(--warn); }
/* A rep who dialled all month and never held a call for a minute: broken audio,
   not poor technique. Loud enough to act on, quiet enough not to shout. */
.ph-alarm { color: #ff7d8a; font-weight: 600; }
.ph-prow.alarm { background: rgba(255,125,138,.05); }

/* ── PH rep performance ───────────────────────────────────────────────────
   The question this table answers is "who is actually having conversations",
   so CONVERSATIONS sorts it and TALK TIME carries a bar. Everything else is
   supporting evidence and stays quiet. Bar widths are set via CSSOM (CSP). */
.rep-table { overflow-x: auto; }
/* 7 columns since the inbound-answered column landed; a template one short of
   the row's children wraps every row to double height. */
.rep-row { display: grid;
  grid-template-columns: minmax(190px, 1.5fr) 70px 104px 60px 62px 238px 76px;
  gap: 12px; align-items: center; padding: 9px 4px;
  border-bottom: 1px solid var(--edge-soft); min-width: 840px; }
.rep-row:last-child { border-bottom: 0; }
.rep-row.head { border-bottom: 1px solid var(--edge); padding-bottom: 7px;
  color: var(--muted); font: 600 10px var(--mono); letter-spacing: .09em;
  text-transform: uppercase; }
.rep-row.head .rep-name { text-transform: uppercase; }
.rep-name { font: 12.5px var(--mono); color: var(--text); overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
/* The rep's own window, small and dim: it explains a low dial count without
   competing with it. */
.rep-since { display: block; font: 10px var(--mono); color: var(--faint); margin-top: 2px; }
.rep-n { font: 13px var(--mono); color: var(--text); text-align: right; font-variant-numeric: tabular-nums; }
.rep-n.dim { color: var(--muted); font-size: 12px; }
.rep-n.none { color: var(--faint); }
/* One number per row is the headline — conversations. Give it the weight. */
.rep-n.lead { font-size: 15px; font-weight: 600; }
.rep-bar { display: grid; grid-template-columns: 1fr 52px; gap: 8px; align-items: center; }
.rep-track { height: 8px; border-radius: 4px; background: var(--ink-2); overflow: hidden; }
.rep-fill { display: block; height: 100%; border-radius: 4px; background: #5cc8ff; opacity: .75; }
.rep-fill.flat { background: #ff7d8a; opacity: .9; }
.rep-bar-v { font: 11.5px var(--mono); color: var(--muted); text-align: right;
  font-variant-numeric: tabular-nums; }
/* A rep who dialled all month and never held a call for a minute has broken
   audio, not a weak pitch. Loud enough to act on, not loud enough to shout. */
.rep-row.broken { background: rgba(255,125,138,.055); }
.rep-row.broken .rep-flag { color: #ff7d8a; font-weight: 600; }
.rep-flag { font: 12px var(--mono); text-align: right; color: var(--muted);
  font-variant-numeric: tabular-nums; }

/* ── the cap controller strip (Domains tab) ──────────────────────────────
   Chips, not a KPI grid: these are heterogeneous facts about one controller
   (armed / queue / DBL / rails), not comparable measures sharing a baseline,
   and a reader scans them for the one that is loud. */
.dh-fleetmgr { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.fm-chip { font: 11.5px var(--mono); padding: 3px 8px; border-radius: 999px;
  border: 1px solid var(--edge-soft); color: var(--muted);
  background: var(--surface); cursor: help; }
.fm-chip.good { color: var(--good); border-color: var(--good); }
.fm-chip.warn { color: var(--warn); border-color: var(--warn); }
.fm-chip.bad  { color: var(--bad);  border-color: var(--bad); }
.fm-chip.unk  { color: var(--faint); border-style: dashed; }

/* Leads tab (spec 2026-09-30 §7; UX v4 2026-10-01): tier sections of people to call now; tier 7 is a
   closed <details> with a count. Same 1200px card as every other tab. First .ld-row rule = the desktop
   tracks (tests count them): Status · Links · Lead · Us vs Them · Close · Campaign.
   Every track can shrink to 0 (minmax(0, …)) or is a small fixed px, so the row never outgrows its card —
   no horizontal scroll at 1440 / 1024 / 768 / 390 (test_the_leads_board_never_scrolls_sideways). */
.ld-row { display: grid; gap: 6px 10px; align-items: center; padding: 8px 6px; border-bottom: 1px solid var(--edge-soft);
  grid-template-columns: 32px 170px 176px minmax(0, 1fr) 96px 128px 56px 100px; }
.ld-row > * { min-width: 0; overflow-wrap: anywhere; }
.ld-head { font: 600 9px var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--faint); }
.ld-tier { font: 600 10px var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--muted); margin: 16px 0 2px; }
.ld-empty { font: 11px var(--mono); color: var(--faint); padding: 6px; }
.ld-hud { text-transform: none; letter-spacing: normal; font-weight: 400; min-width: 0; flex-wrap: wrap; }
.dot.stale { background: var(--warn); animation: none; }
.dot.down { background: var(--down); animation: none; }
/* Pipeline: a status pill (where the lead is stuck) over six step dots joined by a rail. */
.ld-pipe { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
.ld-status { font: 600 11px var(--sans); border-radius: 20px; padding: 2px 9px; border: 1px solid var(--edge);
  color: var(--muted); white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
.ld-status.stuck { color: var(--warn); border-color: rgba(243,193,86,.5); background: rgba(243,193,86,.08); }
.ld-status.moving { color: var(--up); border-color: rgba(87,224,160,.5); background: rgba(87,224,160,.08); }
.ld-status.bad { color: var(--down); border-color: var(--down); background: rgba(255,107,107,.1); }
.ld-status.ld-none { border: 0; padding: 0; }
.ld-dots { position: relative; display: flex; gap: 6px; cursor: help; }
.ld-dots::before { content: ""; position: absolute; left: 6px; right: 6px; top: 5px; height: 2px; background: var(--edge); }
.ld-dot { position: relative; width: 12px; height: 12px; border-radius: 50%; background: var(--edge-soft);
  border: 2px solid var(--edge); box-sizing: border-box; }
.ld-dot.green { background: var(--up); border-color: var(--up); }
.ld-dot.amber { background: var(--warn); border-color: var(--warn); }
.ld-dot.red { background: var(--down); border-color: var(--down); }
/* The dots' hover card: each step and its state, in words. */
.ld-dottip { position: absolute; left: 0; top: calc(100% + 6px); z-index: 40; width: max-content; display: grid; gap: 3px;
  background: var(--surface-2); border: 1px solid var(--edge); border-radius: 8px; padding: 8px 10px;
  font: 11px var(--sans); color: var(--text); box-shadow: 0 8px 22px rgba(0,0,0,.5);
  opacity: 0; visibility: hidden; transition: opacity .12s ease; pointer-events: none; }
.ld-dots:hover > .ld-dottip, .ld-dots:focus-visible > .ld-dottip { opacity: 1; visibility: visible; }
.ld-dotline { display: flex; align-items: center; gap: 6px; }
.ld-legend { display: grid; gap: 4px; margin: 4px 0 2px; }
.ld-legend-line { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 14px;
  font: 11px var(--sans); color: var(--muted); }
.ld-key { display: inline-flex; align-items: center; gap: 5px; }
.ld-lead { position: relative; display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; }
.ld-name { font: 600 13px var(--sans); color: var(--text); background: none; border: 0; padding: 0; margin: 0;
  cursor: pointer; text-align: left; overflow-wrap: anywhere; }
.ld-name::after { content: " ▸"; color: var(--signal); font-size: 11px; }
.ld-name[aria-expanded="true"]::after { content: " ▾"; }
.ld-name:hover, .ld-name[aria-expanded="true"] { color: var(--signal); }
.ld-name:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; border-radius: 3px; }
.ld-biz { flex-basis: 100%; font: 11px var(--sans); color: var(--muted); }
.ld-chip { font: 600 9px var(--mono); color: var(--faint); border: 1px solid var(--edge-soft); border-radius: 20px; padding: 0 6px; }
.ld-chip.warn { color: var(--warn); border-color: rgba(243,193,86,.3); }
/* Hover card: the prospect's own latest words (else the latest recap). Hidden while the details are open. */
.ld-tip { position: absolute; left: 0; top: calc(100% + 6px); z-index: 40; width: max-content; max-width: min(360px, 85vw);
  display: grid; gap: 4px; background: var(--surface-2); border: 1px solid var(--edge); border-radius: 8px; padding: 8px 10px;
  font: 12px/1.45 var(--sans); color: var(--text); box-shadow: 0 8px 22px rgba(0,0,0,.5);
  opacity: 0; visibility: hidden; transition: opacity .12s ease; pointer-events: none; }
.ld-lead:hover > .ld-tip, .ld-name:focus-visible ~ .ld-tip { opacity: 1; visibility: visible; }
.ld-name[aria-expanded="true"] ~ .ld-tip { display: none; }
/* Pin (team-wide, top of its section) and Note → GHL (operator 2026-10-01). */
/* The pin leads the row: an outlined square, filled when the lead is pinned. */
.ld-pincell { display: flex; justify-content: center; }
.ld-pin { width: 26px; height: 26px; padding: 0; cursor: pointer; font-size: 13px; line-height: 1;
  background: transparent; border: 1px solid var(--edge); border-radius: 6px; filter: grayscale(1); opacity: .6; }
.ld-pin:hover, .ld-pin:focus-visible { opacity: 1; filter: none; border-color: var(--signal); }
.ld-pin.on { filter: none; opacity: 1; border-color: var(--signal); background: rgba(92,200,255,.15); }
.ld-row.pinned { box-shadow: inset 3px 0 0 var(--signal); background: rgba(92,200,255,.04); }
.ld-act.ld-notebtn { color: var(--text); }
.ld-note { display: grid; gap: 6px; margin-top: 6px; padding-top: 8px; border-top: 1px solid var(--edge-soft); }
.ld-note-text, .ld-note-who { width: 100%; max-width: 100%; box-sizing: border-box; background: var(--ink-2);
  border: 1px solid var(--edge); border-radius: 6px; color: var(--text); font: 12px var(--sans); padding: 6px 8px; }
.ld-note-text { resize: vertical; min-height: 54px; }
.ld-note-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
.ld-note-who { width: 160px; }
button.ld-act { background: none; cursor: pointer; }
.ld-note-msg { font: 11px var(--sans); color: var(--muted); }
.ld-why { font: 11px var(--sans); color: var(--muted); }
/* Us vs Them: who touched last (Us / Them / Meeting) + age, the kind of touch under it. */
.ld-touch { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 6px; font: 11px var(--sans); color: var(--muted); }
.ld-who { font: 700 11px var(--mono); border-radius: 4px; padding: 1px 6px; color: var(--ink); background: var(--muted); }
.ld-who.them { background: var(--up); }
.ld-who.us { background: var(--signal); }
.ld-who.late { background: var(--down); }
.ld-key .ld-who { display: inline-block; width: 18px; height: 10px; padding: 0; }
.ld-what, .ld-by { flex-basis: 100%; }
.ld-by { font-style: italic; }
.ld-close { font: 700 12px var(--mono); color: var(--muted); }
.ld-owner { font: 600 12px var(--sans); color: var(--text); }
/* A column blank for every row of a section is dropped there (operator 2026-10-01: no all-"—" columns). */
.ld-sec.no-owner .ld-owner, .ld-sec.no-owner .ld-h-owner,
.ld-sec.no-close .ld-close, .ld-sec.no-close .ld-h-close { display: none; }
@media (min-width: 900px) {
  .ld-sec.no-owner .ld-row { grid-template-columns: 32px 170px 176px minmax(0, 1fr) 128px 56px 100px; }
  .ld-sec.no-close .ld-row { grid-template-columns: 32px 170px 176px minmax(0, 1fr) 96px 128px 100px; }
  .ld-sec.no-owner.no-close .ld-row { grid-template-columns: 32px 170px 176px minmax(0, 1fr) 128px 100px; }
}
.ld-owner.setter { font-weight: 400; color: var(--muted); }
.ld-close.hi { color: var(--up); }
.ld-camp { justify-self: start; max-width: 100%; font: 600 10px var(--mono); color: var(--muted);
  border: 1px solid var(--edge); border-radius: 20px; padding: 1px 8px; }
.ld-camp.ld-none { border: 0; }
/* The three links: one grid track each on a wide screen (the wrapper steps aside), one strip on a phone. */
.ld-acts { display: flex; flex-wrap: wrap; gap: 6px; }
.ld-act { justify-self: start; font: 600 11px var(--mono); color: var(--signal); text-decoration: none; white-space: nowrap;
  border: 1px solid var(--edge); border-radius: 6px; padding: 3px 7px; }
a.ld-act:hover { border-color: var(--signal); }
.ld-act.ld-rec { color: var(--up); }
.ld-none { color: var(--edge); font: 11px var(--mono); }
.ld-detail { display: grid; gap: 4px; padding: 8px 12px 10px; border-bottom: 1px solid var(--edge-soft);
  background: var(--surface-2); font: 12px var(--sans); color: var(--muted); overflow-wrap: anywhere; }
.ld-detail[hidden] { display: none; }
.ld-recap-body { white-space: pre-line; color: var(--text); padding-bottom: 4px; }
.ld-kv { display: flex; flex-wrap: wrap; gap: 0 10px; }
.ld-k { min-width: 76px; font: 600 9px/1.9 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--faint); }
.ld-phone, .ld-reclink { color: var(--signal); font: 600 12px var(--mono); text-decoration: none; }
.ld-collapsed > summary { cursor: pointer; margin-top: 16px; font: 600 11px var(--sans); color: var(--faint); }
.ld-collapsed .ld-row, .ld-row.done { opacity: .65; }
/* "!" — data that doesn't add up; hover / focus names it. */
.ld-flag { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px;
  border-radius: 50%; background: var(--down); color: var(--ink); font: 800 11px var(--sans); cursor: help; }
.ld-flagtip { position: absolute; left: 0; top: calc(100% + 6px); z-index: 40; width: max-content;
  max-width: min(320px, calc(100vw - 32px));
  display: grid; gap: 3px; background: var(--surface-2); border: 1px solid var(--edge); border-radius: 8px; padding: 8px 10px;
  font: 400 11px/1.4 var(--sans); color: var(--text); box-shadow: 0 8px 22px rgba(0,0,0,.5);
  opacity: 0; visibility: hidden; transition: opacity .12s ease; pointer-events: none; }
.ld-flag:hover > .ld-flagtip, .ld-flag:focus-visible > .ld-flagtip { opacity: 1; visibility: visible; }
/* One card at a time: on the "!" its reason shows, the lead's hover card steps aside (they overlapped). */
.ld-flag:hover ~ .ld-tip, .ld-flag:focus-visible ~ .ld-tip { opacity: 0; visibility: hidden; }
.ld-act.ld-donebtn { color: var(--up); }
.ld-act.ld-donebtn.on { border-color: var(--up); background: rgba(87,224,160,.12); }
/* opacity makes each row a stacking context: lift the hovered one so its hover card paints on top. */
.ld-collapsed .ld-row:hover, .ld-collapsed .ld-row:focus-within,
.ld-row.done:hover, .ld-row.done:focus-within { opacity: 1; position: relative; z-index: 1; }
/* Narrow screens: pin · status · campaign, then the links strip, the lead, us vs them + close. */
@media (max-width: 899px) {
  .ld-row { grid-template-columns: 36px minmax(0, 1fr) minmax(0, 1fr); }
  .ld-row > .ld-touch { grid-column: 1 / 3; }
  .ld-head { display: none; }
  .ld-pincell, .ld-pipe, .ld-row > .ld-camp { order: -1; }
  .ld-pincell { justify-content: flex-start; }
  .ld-row > .ld-camp { justify-self: end; }
  .ld-lead, .ld-acts { grid-column: 1 / -1; }
  .ld-flagtip { left: auto; right: -40px; }   /* a phone: open toward the middle, never off-screen */
}
/* Filter bar (closer · timeframe · stage + Reset): wraps on a phone; no control outgrows the card. */
.ld-filters { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; margin: 8px 0 4px; }
.ld-filters[hidden] { display: none; }
/* Own arrow, inset from the edge (the native one hugged the border). */
.ld-filters select { min-width: 0; max-width: 100%; border: 1px solid var(--edge); appearance: none;
  border-radius: 8px; color: var(--text); font: 12px var(--mono); padding: 5px 30px 5px 10px;
  background-color: var(--ink-2); background-repeat: no-repeat; background-size: 5px 5px;
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%),
                    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 17px) 55%, calc(100% - 12px) 55%; }
.ld-reset[hidden] { display: none; }
.ld-filters select:focus { outline: 2px solid var(--signal); outline-offset: 1px; }
/* Each tier is a <details> (click the header to fold it); a long one shows 10, then "Show all N". */
.ld-sec > summary { cursor: pointer; }
.ld-more { display: flex; flex-wrap: wrap; gap: 4px 14px; padding: 8px 6px; border-bottom: 1px solid var(--edge-soft); }
.ld-reset, .ld-page { background: none; border: 0; padding: 4px 2px; color: var(--signal); font: 600 11px var(--mono);
  text-decoration: underline; cursor: pointer; }
.ld-showing { margin-left: 8px; color: var(--warn); }
.ld-stale { margin: 6px 0; padding: 8px 10px; border: 1px solid rgba(243,193,86,.4); border-radius: 6px;
  font: 600 12px var(--sans); color: var(--warn); }
/* Team updates (spec 2026-10-01): the team's word under a row's status; Needs a decision below the board. */
.ld-team { font: 11px var(--sans); color: var(--signal); }
.ld-dryrun { margin: 6px 0; padding: 6px 10px; border: 1px dashed var(--edge-soft); border-radius: 6px;
  font: 12px var(--sans); color: var(--muted); }
.ld-dec { display: flex; flex-direction: column; gap: 4px; padding: 8px 6px; border-bottom: 1px solid var(--edge-soft);
  min-width: 0; overflow-wrap: anywhere; }
.ld-dec.settled { color: var(--faint); }
.ld-dec-head { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: baseline; }
.ld-dec-name { font: 600 13px var(--sans); }
.ld-dec-change { font: 600 11px var(--mono); color: var(--warn); }
.ld-dec.settled .ld-dec-change { color: var(--faint); }
.ld-dec-quote { font: italic 12px var(--sans); }
.ld-dec-meta { font: 11px var(--sans); color: var(--muted); }
.ld-dec-acts { display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: center; }
.ld-dec-msg { font: 11px var(--sans); color: var(--muted); }
.ld-act.ld-dec-reject { color: var(--muted); }
.ld-unm { margin-top: 10px; }
