/* ---------- Design tokens ----------
   Every colour on the page is a custom property. Light is the default; dark is
   its own selected set (stepped for the dark surface, not an inversion), applied
   by `data-theme="dark"` on <html>, which a tiny script in index.html resolves
   before first paint from the saved choice or the system setting. */
:root {
  color-scheme: light;
  --font: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --bg: #f4f4f1;
  --panel: #fcfcfb;
  --panel-2: #f7f7f4;
  --ink: #141413;
  --ink-2: #52514e;
  --muted: #7d7c76;
  --line: #e4e3dd;
  --line-2: #eeede8;
  /* The one accent. Violet, because the range palette spends blue, orange,
     aqua, yellow and magenta, and the accent must never read as a range. */
  --brand: #5b4fc7;
  --brand-ink: #ffffff;
  --brand-soft: #eeecfa;
  /* Up and down only. Text-safe on the panel. */
  --pos: #107c3c;
  --neg: #c2352f;
  --pos-soft: #e6f3ea;
  --neg-soft: #fae9e7;
  --warn: #a8640a;
  --warn-soft: #fbf1df;
  /* Validated categorical order (dataviz reference palette, slots 1-5 + 7):
     worst adjacent CVD dE 9.1 light / 8.4 dark, normal-vision floor 19.6 /
     19.3. Light slots 3-5 sit under 3:1 on the panel, so every range mark is
     direct-labelled or has a table beside it. */
  --range-1: #2a78d6;
  --range-2: #eb6834;
  --range-3: #1baf7a;
  --range-4: #eda100;
  --range-5: #e87ba4;
  --range-6: #4a3aa7;
  --series-1: #2a78d6;
  --series-2: #eb6834;
  --series-3: #1baf7a;
  --series-4: #eda100;
  --series-5: #e87ba4;
  --series-6: #4a3aa7;
  --accent-1: var(--series-1);
  --accent-2: var(--series-6);
  --accent-3: var(--series-3);
  --accent-4: var(--series-4);
  --accent-5: var(--series-5);
  /* Sequential (heatmap) ramp: the accent's own hue, light to dark. */
  --seq-0: #f1f0fb;
  --seq-1: #d9d5f5;
  --seq-2: #b3aaec;
  --seq-3: #8a7ee0;
  --seq-4: #6252cc;
  --seq-5: #3e30a0;
  --grid: #ebeae5;
  --skeleton: #ecebe6;
  --skeleton-hi: #f6f5f1;
  --tooltip-bg: #141413;
  --tooltip-ink: #fcfcfb;
  --shadow: 0 1px 0 rgba(20, 20, 19, .03);
  --shadow-pop: 0 10px 30px rgba(20, 20, 19, .12);
  --radius: 12px;
  --radius-sm: 8px;
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #111110;
  --panel: #1a1a19;
  --panel-2: #20201e;
  --ink: #f3f2ee;
  --ink-2: #c3c2b7;
  --muted: #908f87;
  --line: #2d2d2a;
  --line-2: #252523;
  --brand: #9085e9;
  --brand-ink: #111110;
  --brand-soft: #2a2745;
  --pos: #3fbf6f;
  --neg: #f0706a;
  --pos-soft: #16301f;
  --neg-soft: #3a1c1a;
  --warn: #e0a33b;
  --warn-soft: #33270f;
  --range-1: #3987e5;
  --range-2: #d95926;
  --range-3: #199e70;
  --range-4: #c98500;
  --range-5: #d55181;
  --range-6: #9085e9;
  --series-1: #3987e5;
  --series-2: #d95926;
  --series-3: #199e70;
  --series-4: #c98500;
  --series-5: #d55181;
  --series-6: #9085e9;
  --seq-0: #222130;
  --seq-1: #2f2a55;
  --seq-2: #463d86;
  --seq-3: #6556bd;
  --seq-4: #8f82e6;
  --seq-5: #c3bbf7;
  --grid: #262624;
  --skeleton: #242422;
  --skeleton-hi: #2d2d2a;
  --tooltip-bg: #f3f2ee;
  --tooltip-ink: #141413;
  --shadow: none;
  --shadow-pop: 0 12px 34px rgba(0, 0, 0, .5);
}

/* Audience segments — a deliberately monochrome scale: identity by lightness,
   which survives every form of colour-vision deficiency. Stepped separately
   for the dark panel rather than flipped. */
:root {
  --aud-engaged: #141413;
  --aud-prospecting: #52514e;
  --aud-existing: #8a8983;
  --aud-unclassified: #c9c8c1;
}
:root[data-theme="dark"] {
  --aud-engaged: #f3f2ee;
  --aud-prospecting: #c3c2b7;
  --aud-existing: #86857e;
  --aud-unclassified: #4c4b47;
}

.chart-legend { display: flex; gap: 18px; justify-content: center;
  flex-wrap: wrap; margin: 2px 0 10px; }
.chart-legend .item { display: flex; align-items: center; gap: 7px;
  font-size: 12.5px; color: var(--ink-2); }
.chart-legend .sw { width: 11px; height: 11px; border-radius: 50%;
  flex: 0 0 auto; box-shadow: inset 0 0 0 1px rgba(128,128,128,.28); }

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--ink);
  font-size: 14px;
  -webkit-font-smoothing: antialiased;
}
.muted { color: var(--muted); }

/* ---------- Layout ---------- */
.app { display: grid; grid-template-columns: 232px 1fr; min-height: 100vh; }

.sidebar {
  background: var(--panel);
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  padding: 18px 14px;
  position: sticky;
  top: 0;
  height: 100vh;
  /* Nothing escapes the sidebar; the nav inside it owns the scrolling. */
  overflow: hidden;
}
.brand { display: flex; align-items: center; gap: 10px; padding: 6px 8px 18px; }
.brand-mark { color: var(--brand); font-size: 20px; }
.brand-text { font-weight: 700; font-size: 17px; letter-spacing: .2px; }

/* The nav scrolls on its own, so the brand above it and the sync/sign-out box
   below stay put however many tabs there are.
   `min-height: 0` is the load-bearing half: a flex item defaults to
   `min-height: auto`, which refuses to shrink below its content, so `flex: 1`
   alone let the list grow past the sidebar's 100vh and pushed the footer off
   the bottom — reaching the last tab meant scrolling the whole dashboard. */
.nav {
  display: flex; flex-direction: column; gap: 2px;
  flex: 1; min-height: 0; overflow-y: auto;
  /* Room for the scrollbar so it never sits on top of a label. */
  padding-right: 4px; margin-right: -4px;
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
}
.nav::-webkit-scrollbar { width: 6px; }
.nav::-webkit-scrollbar-track { background: transparent; }
.nav::-webkit-scrollbar-thumb { background: var(--line); border-radius: 3px; }
.nav::-webkit-scrollbar-thumb:hover { background: var(--muted); }
.nav-item {
  display: flex; align-items: center; gap: 10px;
  border: 0; background: transparent; color: var(--ink-2);
  padding: 10px 10px; border-radius: 10px; cursor: pointer;
  font-size: 13.5px; text-align: left; width: 100%; transition: .12s;
}
.nav-item .ic { width: 18px; text-align: center; font-size: 13px; }
.nav-item:hover { background: var(--panel-2); color: var(--ink); }
.nav-item.active { background: color-mix(in srgb, var(--brand) 14%, transparent); color: var(--brand); font-weight: 600; }

.sidebar-foot { border-top: 1px solid var(--line); padding-top: 12px; margin-top: 8px; }
.sync-box { margin-bottom: 12px; }
.sync-row { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.sync-label { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); font-weight: 600; }
.sync-detail { font-size: 11px; color: var(--muted); margin-top: 3px; line-height: 1.45; }
.sync-detail.busy { color: var(--brand); }
.sync-detail.err { color: var(--neg); }
.filters { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 14px; }
.filters input, .filters select {
  background: var(--panel); color: var(--ink); border: 1px solid var(--line);
  border-radius: 9px; padding: 7px 10px; font-size: 13px; font-family: inherit;
}
.filters input { min-width: 200px; }
.filters input:focus, .filters select:focus { outline: none; border-color: var(--brand); }
.store-name { font-weight: 600; font-size: 13px; }
.store-domain { color: var(--muted); font-size: 11.5px; }

.main { padding: 22px 26px 40px; min-width: 0; }
.topbar { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; margin-bottom: 18px; }
.topbar h1 { margin: 0 0 2px; font-size: 22px; }
.topbar-controls { display: flex; align-items: center; gap: 12px; }
.range { display: flex; align-items: center; gap: 8px; color: var(--muted); font-size: 12.5px; }
.range select {
  background: var(--panel); color: var(--ink); border: 1px solid var(--line);
  border-radius: 9px; padding: 7px 10px; font-size: 13px;
}
.badge { font-size: 11px; font-weight: 600; padding: 4px 9px; border-radius: 999px; text-transform: uppercase; letter-spacing: .4px; }
.badge-mock { background: color-mix(in srgb, var(--warn) 16%, transparent); color: var(--warn); }
.badge-live { background: color-mix(in srgb, var(--pos) 16%, transparent); color: var(--pos); }

.warning-bar {
  background: color-mix(in srgb, var(--warn) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--warn) 35%, transparent);
  color: var(--warn); padding: 10px 14px; border-radius: 10px; margin-bottom: 16px; font-size: 13px;
  line-height: 1.55;
}
.ok-bar {
  background: color-mix(in srgb, var(--pos) 11%, transparent);
  border: 1px solid color-mix(in srgb, var(--pos) 32%, transparent);
  color: var(--pos); padding: 10px 14px; border-radius: 10px; margin-bottom: 16px; font-size: 13px;
  line-height: 1.55;
}
.inline-fix {
  background: none; border: 0; padding: 0; margin-left: 4px;
  color: inherit; font: inherit; font-weight: 700; cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px;
}
.inline-fix:hover { opacity: .78; }

/* ---------- Cards / grids ---------- */
.grid { display: grid; gap: 16px; }
/* Grid items default to min-width:auto, so a wide table props its card open and
   the overflow escapes to the page instead of scrolling inside .table-wrap.
   Cells are white-space:nowrap, so a table only has to gain a column to hit it. */
.grid > * { min-width: 0; }
/* auto-fit rather than a fixed 6 columns: INR amounts run long (₹296,882,144)
   and would otherwise overflow their card. */
.cols-2 { grid-template-columns: 2fr 1fr; }
@media (max-width: 1100px) { .cols-2 { grid-template-columns: 1fr; } }

.card {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 16px 18px; box-shadow: var(--shadow);
}
.card h3 { margin: 0 0 12px; font-size: 13.5px; font-weight: 600; color: var(--ink-2); }
.card-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 12px; }
.card-head h3 { margin: 0; }

.delta-pos { color: var(--pos); }
.delta-neg { color: var(--neg); }

.section-gap { margin-top: 16px; }

/* A card head carrying more than one control. .card-head is a two-way split, so
   the caption, any switch and the download button travel as a single node. */
.head-tools { display: inline-flex; align-items: center; gap: 10px; }
.dl-btn {
  border: 1px solid var(--line); background: var(--panel); color: var(--ink-2);
  border-radius: 9px; padding: 5px 10px; cursor: pointer;
  font: 600 12px/1 inherit; font-family: inherit; white-space: nowrap; transition: .12s;
}
.dl-btn:hover { color: var(--brand); border-color: var(--brand); }
.dl-btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }

/* ---------- Tables ---------- */
.table-wrap { overflow-x: auto; }
/* Inventory lists every SKU in scope rather than a top-N slice, so the tables
   scroll inside the card. Without a height the sticky header has no scrolling
   ancestor of its own and rides off the top of the page with the rows. */
.table-tall { max-height: 460px; overflow-y: auto; }
td code { font-size: 11.5px; color: var(--ink-2); background: var(--panel-2);
          border: 1px solid var(--line); border-radius: 5px; padding: 2px 6px; }
/* Collab product titles run to ~90 characters ("… X LoveChild By Masaba Bare
   Browns Luxe Matte Lipstick"). Cells are nowrap, so one of those pushes days
   left, on hand and net sales past the right edge — the columns the table
   exists for. Clip the name instead; the full text stays in the tooltip. */
td.cell-wide { max-width: 232px; overflow: hidden; text-overflow: ellipsis; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--line); white-space: nowrap; }
th { color: var(--muted); font-weight: 600; font-size: 11.5px; text-transform: uppercase; letter-spacing: .4px; position: sticky; top: 0; background: var(--panel); }
tbody tr:hover { background: var(--panel-2); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }

.pill { font-size: 11px; font-weight: 600; padding: 3px 8px; border-radius: 999px; display: inline-block; }
.pill-green { background: color-mix(in srgb, var(--pos) 16%, transparent); color: var(--pos); }
.pill-red { background: color-mix(in srgb, var(--neg) 16%, transparent); color: var(--neg); }
.pill-amber { background: color-mix(in srgb, var(--warn) 16%, transparent); color: var(--warn); }
.pill-gray { background: color-mix(in srgb, var(--muted) 18%, transparent); color: var(--ink-2); }
.pill-blue { background: color-mix(in srgb, var(--brand) 16%, transparent); color: var(--brand); }

/* ---------- Charts ---------- */
.chart { width: 100%; display: block; }
.legend { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 10px; font-size: 12px; color: var(--ink-2); }
.legend span { display: inline-flex; align-items: center; gap: 6px; }
.legend i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }


.mini-list { display: flex; flex-direction: column; gap: 2px; }
.stat-inline { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid var(--line); }
.stat-inline:last-child { border-bottom: 0; }

.loading { color: var(--muted); padding: 40px; text-align: center; }
.empty { color: var(--muted); padding: 24px; text-align: center; font-size: 13px; }

/* ---------- Filter controls ---------- */
.filter-wrap { position: relative; }
.dropdown {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 40;
  background: var(--panel); border: 1px solid var(--line); border-radius: 12px;
  box-shadow: var(--shadow); padding: 8px; min-width: 230px; max-height: 340px; overflow-y: auto;
}
/* The Daily tab's own channel menu borrows this look rather than restating it,
   so the two pickers cannot drift apart visually. */
.dropdown .chk, .chan-menu .chk {
  display: flex; align-items: center; gap: 9px; padding: 8px 9px; border-radius: 8px;
  font-size: 13px; cursor: pointer; color: var(--ink-2);
}
.dropdown .chk:hover, .chan-menu .chk:hover { background: var(--panel-2); }
.dropdown .chk input, .chan-menu .chk input { accent-color: var(--brand); width: 15px; height: 15px; }
.dropdown .chk-actions, .chan-menu .chk-actions { display: flex; justify-content: space-between; padding: 6px 6px 8px; border-top: 1px solid var(--line); margin-top: 6px; }
.dropdown .link-btn, .chan-menu .link-btn { background: none; border: 0; color: var(--brand); font-size: 12px; cursor: pointer; font-weight: 600; }

.chan-pick { position: relative; }
.chan-menu {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 40;
  background: var(--panel); border: 1px solid var(--line); border-radius: 12px;
  box-shadow: var(--shadow); padding: 8px; min-width: 250px; max-height: 340px; overflow-y: auto;
}
.chan-menu[hidden] { display: none; }
.custom-range { display: flex; align-items: center; gap: 6px; }
.custom-range[hidden] { display: none; }  /* class display:flex would beat [hidden] */
.custom-range input[type=date] {
  background: var(--panel); color: var(--ink); border: 1px solid var(--line);
  border-radius: 8px; padding: 6px 8px; font-size: 12.5px; font-family: inherit; color-scheme: light dark;
}
.custom-range .arrow { color: var(--muted); }

/* ---------- Funnel ---------- */
.funnel { display: flex; flex-direction: column; gap: 8px; }
.funnel-row { display: grid; grid-template-columns: 130px 1fr; align-items: center; gap: 12px; }
.funnel-row .flabel { color: var(--ink-2); font-size: 13px; }
.funnel-bar { position: relative; background: var(--panel-2); border: 1px solid var(--line); border-radius: 8px; height: 34px; overflow: hidden; }
.funnel-fill { height: 100%; display: flex; align-items: center; padding-left: 10px; color: #fff; font-weight: 600; font-size: 12.5px; border-radius: 8px 0 0 8px; white-space: nowrap; }
.funnel-pct { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }

/* ---------- Segmented controls (Funnels tab) ---------- */
.seg-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* .seg-row carries no margin of its own, so stacked rows would sit flush. */
.seg-row + .seg-row { margin-top: 10px; }
.seg-spacer { flex: 1; }
.seg {
  display: inline-flex; background: var(--panel-2); border: 1px solid var(--line);
  border-radius: 10px; padding: 3px; gap: 3px;
}
.seg-btn {
  border: 0; background: transparent; color: var(--ink-2); cursor: pointer;
  font-size: 12.5px; font-weight: 600; padding: 6px 12px; border-radius: 8px;
  font-family: inherit; white-space: nowrap; transition: .12s;
}
.seg-btn:hover { color: var(--ink); }
.seg-btn.on { background: var(--panel); color: var(--brand); box-shadow: var(--shadow); }
.seg-btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
/* A .seg used as a card's own control. .card-head aligns on the baseline, which
   for an inline-flex box is its last line's — that dropped the switch a few
   pixels below the heading it sits beside. */
.card-head .seg { align-self: center; }
tr.no-sess td { opacity: .7; }
.sub-note { font-size: 11px; color: var(--muted); margin-top: 2px; }
/* period-over-period change, sitting under the figure it belongs to */
.d { font-size: 11px; font-weight: 600; margin-top: 3px; font-variant-numeric: tabular-nums; }
.d-up { color: var(--pos); }
.d-down { color: var(--neg); }
.d-new { color: var(--brand); font-weight: 700; }
/* Change without a verdict — ad spend moving is not itself good or bad. */
.d-flat { color: var(--muted); }

/* ---- hourly tab ---- */
/* Eleven columns of figures, each with a delta under it, so the default row
   padding would push a day off the screen. */
table.tight th, table.tight td { padding: 7px 10px; }
/* An ordinary row is two lines tall — figure plus its change underneath. The
   totals and the partial hour have no change to show, so without this they come
   out 15px shorter and read as squeezed against the rows below.
   Selector has to out-specify `table.tight td` above, which is why it repeats
   the table qualifier rather than standing alone. */
table.tight .row-total td,
table.tight .row-partial td { padding-top: 14px; padding-bottom: 14px; }
.row-total td { background: var(--panel-2); font-weight: 700; border-bottom: 2px solid var(--line); }
/* The hour still running. Dimmed because it is not comparable to the rows
   below it — it has had less time to earn what it is being read against. */
.row-partial td { opacity: .72; font-style: italic; }
.tag-partial {
  display: inline-block; margin-left: 8px; padding: 2px 7px; border-radius: 999px;
  font-size: 10px; font-weight: 700; font-style: normal; letter-spacing: .3px;
  background: color-mix(in srgb, var(--warn) 18%, transparent); color: var(--warn);
}
/* A qualifier under a column head, for a column that means something narrower
   than its name suggests. */
.hdr-note {
  display: block; font-size: 9.5px; font-weight: 600; letter-spacing: .2px;
  text-transform: none; color: var(--warn); opacity: .85; margin-top: 1px;
}
.hour-pick {
  display: inline-flex; align-items: center; gap: 7px;
  color: var(--muted); font-size: 12.5px; font-weight: 600;
}
.hour-pick input {
  background: var(--panel-2); border: 1px solid var(--line); color: var(--ink);
  border-radius: 8px; padding: 6px 9px; font-family: inherit; font-size: 12.5px;
}
.pace-row { display: flex; flex-wrap: wrap; gap: 10px 28px; }
.pace-item { min-width: 92px; }
.pace-label { color: var(--muted); font-size: 11.5px; margin-bottom: 4px; }
.pace-val { font-size: clamp(16px, 1.3vw, 21px); font-weight: 700; letter-spacing: -.3px; }
/* The hourly tab fixes its own window and channel set, so these controls would
   be levers wired to nothing. Hidden by class rather than by the `hidden`
   attribute, which the period select owns — leaving it be means returning to
   another tab restores whatever state that select was in. */
.topbar-controls.no-filters .filter-wrap,
.topbar-controls.no-filters .range,
.topbar-controls.no-filters .custom-range { display: none; }
.cmp-note { font-size: 12.5px; color: var(--muted); margin: 12px 0 0; }
.cov-note {
  font-size: 12.5px; color: var(--ink-2); line-height: 1.55;
  background: var(--panel-2); border: 1px solid var(--line);
  border-radius: 9px; padding: 9px 12px; margin: 0 0 12px;
}
/* The shorthand above sets margin-top to 0, and it is declared after
   .section-gap, so `class="cov-note section-gap"` silently lost its top margin
   and the note sat flush against the controls above it. */
.cov-note.section-gap { margin-top: 16px; }

.src-tag {
  display: inline-block; margin-left: 8px; padding: 2px 7px; border-radius: 999px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .03em; vertical-align: middle;
  background: color-mix(in srgb, var(--brand) 14%, transparent); color: var(--brand);
}
.dim-hint { font-size: 12.5px; color: var(--muted); margin: 10px 0 0; }

/* ---------- Highlights (the "what to look at" strip) ---------- */
.hl-wrap { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 14px; }
.hl {
  display: grid; grid-template-columns: auto 1fr; gap: 12px; align-items: start;
  background: var(--panel); border: 1px solid var(--line); border-left-width: 3px;
  border-radius: var(--radius); padding: 14px 16px; box-shadow: var(--shadow);
}
.hl-mark {
  width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center;
  font-size: 11px; font-weight: 800; flex: none;
}
.hl-top { font-size: 13.5px; color: var(--ink); line-height: 1.45; }
.hl-detail { font-size: 12.5px; color: var(--muted); margin-top: 4px; line-height: 1.5; }
.hl-good { border-left-color: var(--pos); }
.hl-good .hl-mark { background: color-mix(in srgb, var(--pos) 16%, transparent); color: var(--pos); }
.hl-warn { border-left-color: var(--warn); }
.hl-warn .hl-mark { background: color-mix(in srgb, var(--warn) 18%, transparent); color: var(--warn); }
.hl-bad { border-left-color: var(--neg); }
.hl-bad .hl-mark { background: color-mix(in srgb, var(--neg) 16%, transparent); color: var(--neg); }

/* traffic bar sits under the row label rather than in its own column */
td .mini-bar { display: block; margin-top: 5px; max-width: 180px; }

.mini-bar {
  display: inline-block; height: 7px; border-radius: 3px;
  background: var(--brand); vertical-align: middle; min-width: 2px;
}
.note { font-size: 12px; color: var(--muted); margin-top: 10px; line-height: 1.5; }
.note code { font-size: 11px; }

/* ---------- Buttons ---------- */
.btn {
  border: 1px solid var(--line); background: var(--panel); color: var(--ink);
  padding: 8px 14px; border-radius: 9px; font-size: 13px; font-weight: 600; cursor: pointer;
  transition: .12s;
}
.btn:hover { background: var(--panel-2); }
.btn-primary { background: var(--brand); border-color: var(--brand); color: var(--brand-ink); }
.btn-primary:hover { filter: brightness(1.05); background: var(--brand); }
.btn-primary:disabled { opacity: .6; cursor: default; }
.btn-danger { background: transparent; border-color: color-mix(in srgb, var(--neg) 50%, transparent); color: var(--neg); }
.btn-danger:hover { background: color-mix(in srgb, var(--neg) 12%, transparent); }
.icon-btn { border: 0; background: transparent; color: var(--muted); font-size: 16px; cursor: pointer; padding: 4px 8px; border-radius: 8px; }
.icon-btn:hover { background: var(--panel-2); color: var(--ink); }

/* ---------- Modal ---------- */
.overlay {
  position: fixed; inset: 0; background: rgba(10,12,16,.55);
  display: flex; align-items: center; justify-content: center; padding: 20px; z-index: 50;
  backdrop-filter: blur(2px);
}
.overlay[hidden] { display: none; }  /* class display:flex would otherwise beat [hidden] */
.modal {
  background: var(--panel); border: 1px solid var(--line); border-radius: 16px;
  box-shadow: var(--shadow); width: 100%; max-width: 460px; padding: 22px 24px;
}
.modal-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; }
.modal-head h2 { margin: 0; font-size: 18px; }
.field { display: flex; flex-direction: column; gap: 6px; margin-top: 14px; }
.field > span { font-size: 12.5px; font-weight: 600; color: var(--ink-2); }
.field input {
  background: var(--panel-2); border: 1px solid var(--line); color: var(--ink);
  border-radius: 9px; padding: 10px 12px; font-size: 13.5px; font-family: inherit;
}
.field input:focus { outline: none; border-color: var(--brand); }
.hint { color: var(--muted); font-size: 11.5px; line-height: 1.5; }
.hint code, .privacy-note code, code { background: var(--panel-2); border: 1px solid var(--line); border-radius: 5px; padding: 1px 5px; font-size: 11.5px; }
.form-error {
  margin-top: 14px; background: color-mix(in srgb, var(--neg) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--neg) 40%, transparent); color: var(--neg);
  padding: 10px 12px; border-radius: 9px; font-size: 12.5px; line-height: 1.5;
}
.modal-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 20px; }
.privacy-note { color: var(--muted); font-size: 11px; line-height: 1.5; margin: 14px 0 0; }
#connected-state { margin: 8px 0 4px; }
#connected-state .btn { margin-top: 12px; }

/* Original id kept beside a mapped campaign name, so rows stay traceable
   back to Google Ads. */
.id-tag {
  display: inline-block; margin-left: 7px; padding: 1px 6px; border-radius: 5px;
  font-size: 10.5px; font-weight: 600; vertical-align: middle;
  background: var(--panel-2); border: 1px solid var(--line); color: var(--muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* Shown only when logins are enabled. */
.signout { font-size: 11px; color: var(--muted); margin-bottom: 8px; line-height: 1.5; }
.signout a { color: var(--brand); text-decoration: none; font-weight: 600; }
.signout a:hover { text-decoration: underline; }

/* ---- CM2 tab ---- */
/* Period stays visible here — the ladder is a period P&L — but the channel
   picker does not: the four online channels are fixed, because the ladder
   charges every unit a shipping leg, a gateway fee and a share of ad spend
   that a retail counter sale never incurs. */
.topbar-controls.no-channels .filter-wrap { display: none; }
/* Eighteen columns of figures. Same treatment as the hourly table: without it
   a SKU row runs off the side before the margin columns are reached. */
table.ladder th, table.ladder td { padding: 7px 9px; font-size: 12.5px; }
table.ladder td.name { white-space: normal; min-width: 190px; max-width: 280px; }
table.ladder .sku { display: block; font-size: 10.5px; color: var(--muted); margin-top: 2px; }
/* The three margin lines. A left rule marks where each stage of the ladder
   begins, so GM1/GM2/CM1/CM2 read as four blocks rather than one wall of
   numbers. */
table.ladder th.stage, table.ladder td.stage { border-left: 1px solid var(--line); }
table.ladder td.neg { color: var(--neg); }
/* The composition bar: one unit of ASP, split into where it goes. */
/* The formula chain, so a figure here can be reconciled against the sheet
   line by line rather than taken on trust. */
.basis { display: flex; flex-direction: column; gap: 0; font-size: 12.5px; }
.basis-row { display: grid; grid-template-columns: 1fr auto; gap: 14px; padding: 7px 0; border-bottom: 1px solid var(--line); align-items: baseline; }
.basis-row:last-child { border-bottom: 0; }
.basis-row .f { color: var(--muted); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11.5px; }
.basis-row .v { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--ink); }
.basis-row.step .v { color: var(--brand); }

/* A .cov-note that is a warning rather than context — the spend sheet not
   covering every day on screen makes CM2 read high, which has to be visible
   before the number is, not in a footnote under it. */
.warn-note {
  border-color: color-mix(in srgb, var(--warn) 45%, var(--line));
  background: color-mix(in srgb, var(--warn) 9%, var(--panel-2));
  color: var(--ink-2);
}
.warn-note strong { color: var(--warn); }

/* ---------- CM2 assumption inputs ----------
   The four rates the CM2 ladder rests on that this store cannot measure. An
   overridden box is tinted and its label goes brand-coloured, because the one
   thing a reader must never do is mistake an assumption someone typed for a
   figure Shopify reported. */
.rate-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 12px; margin-bottom: 12px;
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 12px;
}
/* The boxes wrap inside here rather than loose in the row. Loose, they were
   flex items in their own right, so filling the width left Reset — which
   carries margin-left:auto — stranded on a line of its own with a 30px empty
   band beside it. As one item they wrap among themselves and Reset stays put.
   The 340px basis is what decides the layout: above it the lead, the boxes and
   Reset share a line; below it the boxes take a row to themselves and Reset
   drops under them. A flex basis rather than a media query because what
   constrains this row is the *column* it sits in, and that depends on the
   sidebar — a viewport breakpoint was wrong by ~300px and squeezed five inputs
   into a 241px column at 726px wide. */
.rate-fields {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  flex: 1 1 340px; min-width: 0;
}
/* A rate row following the compare-mode buttons would otherwise sit flush
   against them — .seg-row carries no margin of its own by design. */
.seg-row + .rate-row { margin-top: 12px; }
.rate-lead {
  font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted); font-weight: 700; cursor: help; margin-right: 2px;
}
.rate-in {
  display: inline-flex; align-items: center; gap: 6px; cursor: help;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: 9px; padding: 4px 8px 4px 10px;
}
.rate-lbl { font-size: 12px; color: var(--ink-2); font-weight: 600; white-space: nowrap; }
.rate-in input {
  width: 58px; border: 0; background: transparent; color: var(--ink);
  font: 600 13px/1 inherit; font-family: inherit; text-align: right;
  padding: 2px 0; -moz-appearance: textfield; appearance: textfield;
}
/* The spinner Chrome draws on focus lands on top of the digits in a box this
   narrow — "16.54" reads as "16.5⇅". Firefox was already told to drop it. */
.rate-in input::-webkit-outer-spin-button,
.rate-in input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.rate-in input:focus { outline: 0; }
.rate-in:focus-within { border-color: var(--brand); }
.rate-pc { font-size: 12px; color: var(--muted); }
/* Overridden — no longer the finance sheet's own figure. */
.rate-in.on { border-color: var(--brand); background: color-mix(in srgb, var(--brand) 7%, var(--panel)); }
.rate-in.on .rate-lbl { color: var(--brand); }
.rate-reset {
  flex: 0 0 auto; align-self: center; margin-left: auto;
  border: 1px solid var(--line); background: var(--panel);
  color: var(--ink-2); border-radius: 9px; padding: 6px 12px; cursor: pointer;
  font: 600 12.5px/1 inherit; font-family: inherit; transition: .12s;
}
.rate-reset:hover:not(:disabled) { color: var(--ink); border-color: var(--muted); }
.rate-reset:disabled { opacity: .4; cursor: default; }
/* Stacked layout: Reset reads better under the boxes on the left than pinned to
   the far right of a row it is the only thing on. */
@media (max-width: 720px) {
  .rate-reset { margin-left: 0; }
}

/* ---------- Pool Health ----------
   Stock health is a status scale, not a set of categories, so it gets its own
   tokens rather than reusing --pos/--warn/--neg. Those three are the store's
   semantic trio and they are the right colours for a labelled pill, but they
   are near-identical under deuteranopia (green vs red measures ΔE 2.6 in OKLab,
   where 8 is the floor). The mix bar puts the three states edge to edge with no
   text between them, so the ramp below also *darkens* with severity: the
   ordering survives with no colour vision at all. Light and dark are stepped
   separately against their own surface rather than flipped — every pair clears
   ΔE 8 under both protanopia and deuteranopia, and every step clears 3:1
   contrast against the panel it sits on. */
:root {
  --health-ok: #2f9e72;
  --health-low: #b8791f;
  --health-out: #94303f;
}
:root[data-theme="dark"] {
    --health-ok: #3daa7d;
    --health-low: #c68020;
    --health-out: #bd4a5c;
  }


.pill-ok   { background: color-mix(in srgb, var(--health-ok) 15%, transparent);  color: var(--health-ok); }
.pill-low  { background: color-mix(in srgb, var(--health-low) 16%, transparent); color: var(--health-low); }
.pill-out  { background: color-mix(in srgb, var(--health-out) 16%, transparent); color: var(--health-out); }

/* The bar is the only place colour carries meaning without a label beside it,
   so the counts live in their own columns and the legend is always present. */
.mix { display: flex; gap: 2px; height: 11px; min-width: 130px; }
.mix > i { display: block; border-radius: 2px; }
.mix > i:first-child { border-radius: 4px 2px 2px 4px; }
.mix > i:last-child { border-radius: 2px 4px 4px 2px; }
.mix > i:only-child { border-radius: 4px; }
.mix-ok { background: var(--health-ok); }
.mix-low { background: var(--health-low); }
.mix-out { background: var(--health-out); }
.mix-none { background: color-mix(in srgb, var(--muted) 55%, transparent); }
td.mix-cell { width: 26%; min-width: 150px; }

.health-legend { display: flex; gap: 16px; flex-wrap: wrap; margin-bottom: 12px;
  font-size: 12px; color: var(--ink-2); }
.health-legend span { display: inline-flex; align-items: center; gap: 6px; }
.health-legend i { width: 10px; height: 10px; border-radius: 3px; flex: 0 0 auto;
  box-shadow: inset 0 0 0 1px rgba(128,128,128,.25); }

.num-ok { color: var(--health-ok); }
.num-low { color: var(--health-low); }
.num-out { color: var(--health-out); }

/* The catalogue crawl takes ~33s, so the tab has a real waiting state. */
.index-card { text-align: center; padding: 40px 24px; }
.index-card h3 { margin: 0 0 8px; }
.index-card p { color: var(--ink-2); font-size: 13px; max-width: 46ch;
  margin: 0 auto 8px; line-height: 1.6; }
.index-card .progress { font-size: 12px; color: var(--muted); margin-top: 14px; }

/* ---- web vs app ---- */
/* A KPI tile holding two storefronts instead of one figure. Every number on
   that tab is only meaningful beside its counterpart, so the pairing belongs
   inside the card rather than being left to the reader to do across ten of
   them. Wider than a normal tile because it carries two labelled rows. */
.kpi-split { min-width: 0; }
.kpi-split .split-row { display: flex; align-items: baseline;
  justify-content: space-between; gap: 10px; padding: 5px 0; }
.kpi-split .split-row + .split-row { border-top: 1px solid var(--line); }
.kpi-split .split-key { display: inline-flex; align-items: center; gap: 6px;
  color: var(--muted); font-size: 11.5px; font-weight: 600; white-space: nowrap; }
.kpi-split .split-key i { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.kpi-split .split-val { font-size: clamp(14px, 1.05vw, 17px); font-weight: 700;
  letter-spacing: -.2px; text-align: right; display: flex; flex-direction: column;
  align-items: flex-end; }
/* The change keeps its own line under the figure, as it does everywhere else on
   the dashboard. The slot is reserved whether or not there is a change to put in
   it: a long rupee figure used to wrap its delta and push the divider below it
   down, so the two storefronts sat at different heights from one card to the
   next along the row. */
.kpi-split .split-d { display: block; min-height: 15px; }
.kpi-split .split-val .d { margin: 1px 0 0; }
@media (min-width: 1101px) { .kpi-split { min-width: 210px; } }

/* The spanning header that says which five columns belong to which storefront.
   Colour-matched to the chart lines, because the table and the chart above it
   are the same two series and nothing else on the row says which is which. */
.grp-head th { border-bottom: 0; padding-bottom: 2px; z-index: 3; }
.grp-head .grp {
  text-align: center; color: var(--grp); letter-spacing: .04em;
  border-bottom: 2px solid color-mix(in srgb, var(--grp) 45%, transparent);
}
/* Two header rows, and `th` is sticky at top:0 for all of them — left alone the
   second would ride up over the first as the page scrolls. The offset is the
   group row's own height: 7px padding + a 17px line + 2px + its 2px rule.
   Shared with the A/B table, which has the same two-row head for the same
   reason: one rule, so the two cannot drift a pixel apart. */
.wva-table thead tr:last-child th,
.ab-table thead tr:last-child th,
.pr-table thead tr:last-child th { top: 28px; z-index: 2; }
/* A gutter column, so the eye does not have to count five cells to find where
   one storefront ends and the other begins. */
.wva-table .wva-gap,
.ab-table .ab-gap-col,
.pr-table .pr-gap { width: 14px; min-width: 14px; padding: 0; border-bottom: 0; }

/* ---------- Pool Report ----------
   Eight groups wide by up to seven metrics each, so the day column has to stay
   put while the rest scrolls; without it the reader loses which row they are on
   about three pools in. */
.pr-table th:first-child,
.pr-table td:first-child {
  position: sticky; left: 0; z-index: 1;
  background: var(--panel); border-right: 1px solid var(--line);
}
.pr-table thead th:first-child { z-index: 4; }
.pr-table .row-total td:first-child { background: var(--panel-2); }

/* Prose in the coverage card. Left to itself a sentence runs the full width of a
   1900px monitor, which is about 200 characters a line and unreadable; the
   paragraphs also need their own rhythm, since .card only spaces its heading. */
.pr-prose { max-width: 96ch; margin: 0 0 10px; line-height: 1.55; }
.pr-prose:last-of-type { margin-bottom: 0; }

/* The coverage table is six columns of which one is a name and five are figures.
   Without this the browser shares the width equally and the numbers drift a
   third of a screen away from the platform they belong to. */
.pr-cov th:first-child, .pr-cov td:first-child { width: 40%; }

/* The pool the picker is on, marked in the summary so the selection is visible
   in the comparison table as well as in the matrix it filters. */
.pr-table tbody tr.pr-sel td, tr.pr-sel td { background: var(--panel-2); }
tr.pr-sel td:first-child { box-shadow: inset 2px 0 0 var(--accent, #5b8def); }

/* ---------- Headless A/B Test ----------
   Thirteen columns of ratios, where the reader's whole job is telling two
   things apart: the two arms, and whether the difference between them is real.
   Everything below serves one of those. */

/* Gaps are signed from the headless arm's point of view — green is headless
   ahead — and sit in a tabular figure so a column of them scans as a column. */
.ab-gap { font-weight: 700; font-variant-numeric: tabular-nums; }
.ab-gap.up { color: var(--pos); }
.ab-gap.down { color: var(--neg); }
.kpi .ab-gap { font-size: inherit; }

/* A p-value is the one number here that gets read as a verdict, so a
   significant one is marked rather than left to be spotted: 0.041 and 0.410 are
   two characters apart on screen and opposite conclusions. */
.ab-p { font-variant-numeric: tabular-nums; color: var(--muted); }
.ab-p.sig {
  color: var(--brand); font-weight: 700;
  background: color-mix(in srgb, var(--brand) 12%, transparent);
  border-radius: 5px; padding: 1px 6px;
}

/* The headline sentence. The left rule is the only colour on the tab that
   states a conclusion, so it is only ever painted when the test actually
   reached one — `flat` stays neutral rather than picking a side quietly. */
.ab-verdict { border-left: 3px solid var(--muted); }
.ab-verdict.win { border-left-color: var(--pos); }
.ab-verdict.loss { border-left-color: var(--neg); }
.ab-verdict.flat { border-left-color: var(--warn); }
.ab-verdict strong:first-child { color: var(--ink); }


/* ---------- Loss of Revenue ----------
   The group header repeats Web vs App's two-row pattern, but the three groups
   here are stages of one calculation rather than competing series, so they share
   one neutral rule instead of being colour-coded against a chart. */
.lor-table .grp {
  text-align: center; color: var(--muted); letter-spacing: .04em;
  font-weight: 600;
  border-bottom: 2px solid color-mix(in srgb, var(--muted) 32%, transparent);
}
.lor-table thead tr:last-child th { top: 28px; }

/* A directionless delta: same weight and size as the coloured ones, so these
   tiles do not read as less important than the tiles beside them — only as
   tiles making no claim about which way is better. */
.delta-flat { color: var(--muted); }

/* The how-long-out split. Reuses the Pool Health tokens rather than
   --pos/--warn/--neg for the reason documented there: this is an ordered
   severity scale read with the segments edge to edge and no text between them,
   and that ramp darkens as well as shifts hue, so the ordering survives with no
   colour vision at all. The scale runs the other way here — the *shortest*
   stockout is the most actionable, so it gets the strongest colour. */
.lor-bar {
  display: flex; height: 10px; border-radius: 999px; overflow: hidden;
  background: var(--panel-2); margin-top: 4px;
}
.lor-bar span { display: block; min-width: 0; }
.lor-dot {
  display: inline-block; width: 9px; height: 9px; border-radius: 999px;
  margin-right: 7px; vertical-align: baseline;
}
.lor-note { font-size: 12px; line-height: 1.45; max-width: 46ch; white-space: normal; }

/* Revenue tiers. A five-step ordered ramp read off a bar with no labels on it,
   so it darkens as it descends as well as shifting hue — same requirement, and
   same OKLab spacing, as the Pool Health scale. Stepped separately for light
   and dark against their own surface rather than flipped. */
:root {
  --tier-hero: #1f7a5a;
  --tier-top:  #3f8f6d;
  --tier-mid:  #b8791f;
  --tier-slow: #a4562c;
  --tier-dead: #7d7f88;
  --tier-none: #4d5058;
}
:root[data-theme="dark"] {
    --tier-hero: #34c48c;
    --tier-top:  #59b98f;
    --tier-mid:  #d99a3c;
    --tier-slow: #cf7448;
    --tier-dead: #767a86;
    --tier-none: #4a4e58;
  }


/* ---------- SKU Performance ----------
   The four range buttons are the tab's spine, not a filter, so they are a row of
   cards rather than a .seg: each carries its own SKU count and revenue, which is
   most of what a reader wants before choosing one. */
.st-ranges {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px;
}
.st-range {
  display: flex; flex-direction: column; gap: 3px;
  padding: 12px 14px; text-align: left; cursor: pointer;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--panel); color: var(--ink-2);
  font: inherit; transition: border-color .12s, color .12s;
}
.st-range:hover { border-color: color-mix(in srgb, var(--brand) 45%, var(--line)); color: var(--ink); }
.st-range.on {
  border-color: var(--brand); color: var(--ink);
  box-shadow: inset 0 -2px 0 var(--brand), var(--shadow);
}
.st-range:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.st-range-name { font-weight: 600; font-size: 14px; }
.st-range-sub { font-size: 11.5px; color: var(--muted); }

.st-search {
  min-width: 220px; padding: 6px 10px;
  border: 1px solid var(--line); border-radius: 8px;
  background: var(--panel); color: var(--ink); font: inherit; font-size: 13px;
}
.st-search:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.st-select { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; }
.st-select select {
  padding: 5px 8px; border: 1px solid var(--line); border-radius: 8px;
  background: var(--panel); color: var(--ink); font: inherit; font-size: 13px;
  max-width: 190px;
}

/* The tag pill. Coloured from the tier's own variable so it reads the same as
   the Loss of Revenue tab's bands, which are the same bands. */
.st-tag {
  display: inline-block; padding: 1px 7px; border-radius: 999px;
  font-size: 11px; font-weight: 600; white-space: nowrap;
}

/* Sortable headers. The button is the whole cell so the hit area matches what
   looks clickable, and the caret only appears on the sorted column. */
.st-table th { padding: 0; }
.st-table th.grp, .st-table .grp-head th { padding: 6px 10px; }
.st-sort {
  width: 100%; padding: 8px 10px; text-align: inherit;
  background: none; border: 0; color: inherit; font: inherit; font-weight: 600;
  cursor: pointer; white-space: nowrap;
}
.st-table th.num .st-sort { text-align: right; }
.st-sort:hover { color: var(--brand); }
.st-table th.st-sorted .st-sort { color: var(--brand); }
.st-table th.st-sorted .st-sort::after { content: " ▾"; font-size: 9px; }
.st-table th.st-sorted.asc .st-sort::after { content: " ▴"; }

/* Columns that do not apply to the selected range — the stock four on Gold. Kept
   in place and greyed rather than removed: a column that vanishes reads as a
   layout bug, and the note above the table says why these are blank. */
.st-dim { opacity: .38; }

/* Creative Mix and Women vs Men. The residual row is the spend whose ad name
   did not parse — italic and dimmed so it reads as "not a creative type"
   rather than as one more bucket ranked alongside the others. */
.resid-row td { color: var(--muted); font-style: italic; }
.resid-row td strong { font-weight: 500; }
/* The men's column on the paired rate tables. Tinted rather than bordered so a
   ten-column table still scans as five pairs and not ten separate columns. */
td.alt, th.alt { background: color-mix(in srgb, var(--brand) 5%, transparent); }
th.sub { font-size: 10px; font-weight: 600; letter-spacing: .04em; opacity: .8; }
.share-cell { font-variant-numeric: tabular-nums; color: var(--ink-2); }
.sub-note.pos { color: var(--pos); }
.sub-note.neg { color: var(--neg); }

/* Paired share bars — spend against revenue, one pair per bucket. */
.wbar-head { display: grid; grid-template-columns: 130px 1fr 76px; align-items: center;
  gap: 10px; padding: 0 0 8px; border-bottom: 1px solid var(--line); margin-bottom: 4px;
  font-size: 11px; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); }
.wbar-key { display: flex; align-items: center; gap: 7px; text-transform: none; letter-spacing: 0;
  font-size: 11.5px; }
.wbar-key i { display: inline-block; width: 11px; height: 8px; border-radius: 2px; }
.wbar-gap-head { text-align: right; }
.wbar-row { display: grid; grid-template-columns: 130px 1fr 76px; align-items: center;
  gap: 10px; padding: 7px 0; }
.wbar-row.resid .wbar-label { color: var(--muted); font-style: italic; }
.wbar-label { color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wbar-tracks { display: flex; flex-direction: column; gap: 3px; }
.wbar-track { position: relative; background: var(--panel-2); border: 1px solid var(--line);
  border-radius: 5px; height: 11px; }
.wbar-fill { height: 100%; border-radius: 4px; }
.wbar-key i.spend, .wbar-fill.spend { background: var(--series-1); }
.wbar-key i.rev, .wbar-fill.rev { background: var(--series-4); }
.wbar-v { position: absolute; right: 6px; top: -1px; font-size: 9.5px; line-height: 13px;
  color: var(--ink-2); font-variant-numeric: tabular-nums; }
.wbar-gap { text-align: right; font-variant-numeric: tabular-nums; font-weight: 600;
  font-size: 12px; color: var(--muted); }
.wbar-gap.pos { color: var(--pos); }
.wbar-gap.neg { color: var(--neg); }
.chart-key { display: flex; gap: 16px; justify-content: center; flex-wrap: wrap;
  font-size: 12px; color: var(--muted); padding-top: 4px; }
.chart-key i { display: inline-block; width: 12px; height: 3px; border-radius: 2px;
  vertical-align: middle; margin-right: 6px; }
.weight-block { padding: 4px 0 14px; border-bottom: 1px solid var(--line); margin-bottom: 14px; }
.cell-share { font-size: 10.5px; color: var(--muted); font-variant-numeric: tabular-nums;
  margin-top: 1px; }

/* Demo-mode badge and nav section headings (brand config). */

.nav-section { font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted); padding: 14px 12px 4px; }
[hidden] { display: none !important; }

/* =====================================================================
   Shell and components (v2). Later in the file than the legacy rules, so
   they win where the two overlap; the legacy selectors are kept because
   every tab's markup still uses them.
   ===================================================================== */
html, body { background: var(--bg); color: var(--ink); }
body { font-family: var(--font); font-size: 13.5px; line-height: 1.5;
  -webkit-font-smoothing: antialiased; font-feature-settings: "cv11", "ss01"; }
.num, td.num, th.num, .kpi-value, .kv-value, .tnum, .axis, table { font-variant-numeric: tabular-nums; }

/* ---- layout: sidebar + main ---- */
.app { display: grid; grid-template-columns: 248px minmax(0, 1fr); min-height: 100vh; }
.sidebar { position: sticky; top: 0; height: 100vh; overflow: hidden; display: flex; flex-direction: column;
  background: var(--panel); border-right: 1px solid var(--line); padding: 18px 12px 12px; }
.brand { display: flex; align-items: center; gap: 10px; padding: 2px 8px 18px; }
.brand-mark { width: 30px; height: 30px; border-radius: 9px; display: grid; place-items: center;
  background: var(--ink); color: var(--panel); font-weight: 650; font-size: 12.5px; letter-spacing: -.02em; }
.brand-text { font-weight: 650; font-size: 14.5px; letter-spacing: -.01em; color: var(--ink); }
.nav { flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 1px; padding-right: 2px; }
.nav-section { font-size: 10.5px; letter-spacing: .09em; text-transform: uppercase; font-weight: 600;
  color: var(--muted); padding: 16px 10px 6px; }
.nav-section:first-child { padding-top: 2px; }
.nav-item { all: unset; box-sizing: border-box; display: flex; align-items: center; gap: 10px; cursor: pointer;
  padding: 7px 10px; border-radius: var(--radius-sm); color: var(--ink-2); font-size: 13.5px; font-weight: 500;
  position: relative; }
.nav-item:hover { background: var(--panel-2); color: var(--ink); }
.nav-item.active { background: var(--brand-soft); color: var(--brand); font-weight: 600; }
.nav-item:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.sidebar-foot { border-top: 1px solid var(--line); padding: 12px 8px 2px; margin-top: 8px; }
.store-name { font-weight: 600; font-size: 12.5px; color: var(--ink); }
.store-domain { font-size: 11.5px; color: var(--muted); }

.main { min-width: 0; display: flex; flex-direction: column; }
.topbar { position: sticky; top: 0; z-index: 20; display: flex; align-items: center; gap: 14px;
  padding: 12px 28px; min-height: 60px; background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: saturate(1.4) blur(10px); -webkit-backdrop-filter: saturate(1.4) blur(10px);
  border-bottom: 1px solid var(--line); margin: 0; }
.topbar-title { min-width: 0; flex: 1; }
.topbar h1 { font-size: 16px; font-weight: 650; letter-spacing: -.015em; margin: 0; line-height: 1.3; }
.topbar #view-sub { margin: 1px 0 0; font-size: 12.5px; color: var(--muted); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.topbar-controls { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
.view { padding: 24px 28px 48px; max-width: 1480px; width: 100%; box-sizing: border-box; }

/* ---- controls ---- */
.btn, .range select, .icon-btn, .theme-btn, .menu-btn {
  font: inherit; font-size: 12.5px; color: var(--ink); background: var(--panel);
  border: 1px solid var(--line); border-radius: var(--radius-sm); height: 32px; padding: 0 12px; }
.btn:hover, .icon-btn:hover, .theme-btn:hover, .menu-btn:hover { border-color: color-mix(in srgb, var(--ink) 22%, var(--line)); }
.range { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--muted); }
.range select { padding-right: 26px; }
.theme-btn, .menu-btn { width: 32px; padding: 0; display: inline-grid; place-items: center; cursor: pointer; }
.theme-btn svg, .menu-btn svg { width: 16px; height: 16px; stroke: currentColor; fill: none; stroke-width: 1.8; }
.menu-btn { display: none; }
.badge { font-size: 11px; font-weight: 600; letter-spacing: .01em; padding: 4px 9px; border-radius: 999px; }
.badge-demo { background: var(--warn-soft); color: var(--warn); border: 1px solid color-mix(in srgb, var(--warn) 30%, transparent); }
:root[data-theme="dark"] .badge-demo { background: var(--warn-soft); color: var(--warn); border-color: color-mix(in srgb, var(--warn) 35%, transparent); }

/* ---- surfaces ---- */
.card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 18px 20px; box-shadow: var(--shadow); }
.card h3 { font-size: 13.5px; font-weight: 600; color: var(--ink); letter-spacing: -.005em; margin: 0; }
.card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 14px; flex-wrap: wrap; }
.card-sub { font-size: 12px; color: var(--muted); margin-top: 2px; }
.grid { gap: 16px; }
.section-gap { margin-top: 16px; }
.note, .pr-prose, .cmp-note { color: var(--ink-2); }
table th { color: var(--muted); font-weight: 600; font-size: 11.5px; letter-spacing: .01em; }
th, td { border-color: var(--line-2); }
tbody tr:hover { background: var(--panel-2); }

/* ---- KPI row ---- */
.kpi-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 16px; }
.kv { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 16px 18px 12px;
  display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.kv-label { font-size: 12px; color: var(--muted); font-weight: 500; display: flex; justify-content: space-between; gap: 8px; }
.kv-value { font-size: 24px; font-weight: 650; letter-spacing: -.025em; line-height: 1.15; color: var(--ink); }
.kv-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; min-height: 30px; }
.kv-delta { font-size: 11.5px; font-weight: 600; padding: 2px 7px; border-radius: 999px; white-space: nowrap; }
.kv-delta.good { color: var(--pos); background: var(--pos-soft); }
.kv-delta.bad { color: var(--neg); background: var(--neg-soft); }
.kv-delta.flat { color: var(--muted); background: var(--panel-2); }
.kv-vs { font-size: 11px; color: var(--muted); margin-left: 6px; font-weight: 500; }
.kv-spark { width: 96px; height: 30px; flex: none; overflow: visible; }
.kv-spark .sl { fill: none; stroke: var(--brand); stroke-width: 1.75; stroke-linejoin: round; stroke-linecap: round; }
.kv-spark .sa { fill: var(--brand); opacity: .10; }
.kv-spark .sd { fill: var(--brand); stroke: var(--panel); stroke-width: 1.5; }

/* ---- charts ---- */
.chart { width: 100%; height: auto; display: block; overflow: visible; }
.chart .axis, .axis { fill: var(--muted); font-size: 10.5px; }
.chart .gridline { stroke: var(--grid); }
.hit { fill: transparent; cursor: default; }
.legend-row { display: flex; flex-wrap: wrap; gap: 6px 16px; font-size: 12px; color: var(--ink-2); margin: 2px 0 10px; }
.legend-row i { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 6px; vertical-align: -1px; }
.legend-row i.line { height: 2px; width: 14px; border-radius: 1px; vertical-align: 3px; }
.legend-row i.dash { height: 0; width: 14px; border-top: 2px dashed var(--muted); border-radius: 0; background: none; vertical-align: 3px; }

/* Range bars: a labelled horizontal bar per range. */
.rbars { display: flex; flex-direction: column; gap: 12px; }
.rbar-top { display: flex; justify-content: space-between; gap: 10px; font-size: 12.5px; }
.rbar-name { display: flex; align-items: center; gap: 8px; color: var(--ink); font-weight: 500; min-width: 0; }
.rbar-name i { width: 10px; height: 10px; border-radius: 3px; flex: none; }
.rbar-val { color: var(--ink); font-weight: 600; white-space: nowrap; }
.rbar-val span { color: var(--muted); font-weight: 500; margin-left: 6px; }
.rbar-track { height: 8px; background: var(--panel-2); border-radius: 4px; margin-top: 6px; overflow: hidden; }
.rbar-fill { height: 100%; border-radius: 4px; }

/* Heatmap: style x size. */
.hm { display: grid; gap: 3px; font-size: 12px; }
.hm-h { color: var(--muted); font-size: 11px; font-weight: 600; text-align: center; padding-bottom: 4px; }
.hm-name { color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding-right: 10px;
  align-self: center; font-size: 12.5px; }
.hm-name small { display: block; color: var(--muted); font-size: 11px; }
.hm-c { height: 34px; border-radius: 6px; display: grid; place-items: center; font-size: 11px; font-weight: 600;
  color: var(--ink-2); background: var(--seq-0); position: relative; }
.hm-c.na { background: repeating-linear-gradient(135deg, var(--panel-2) 0 4px, var(--panel) 4px 8px); color: transparent; }
.hm-c.dark { color: #fff; }
:root[data-theme="dark"] .hm-c.dark { color: #141413; }
.hm-c.out::after { content: ""; position: absolute; inset: 0; border-radius: 6px; box-shadow: inset 0 0 0 1.5px var(--neg); }
.hm-scale { display: flex; align-items: center; gap: 8px; font-size: 11.5px; color: var(--muted); margin-top: 12px; flex-wrap: wrap; }
.hm-scale .ramp { display: flex; gap: 2px; }
.hm-scale .ramp i { width: 18px; height: 10px; border-radius: 2px; }
.hm-scale .out-key { width: 14px; height: 10px; border-radius: 2px; box-shadow: inset 0 0 0 1.5px var(--neg); }

/* Insight strip: one sentence computed from the payload. */
.insight { display: flex; gap: 12px; align-items: flex-start; padding: 14px 16px; border-radius: var(--radius);
  background: var(--brand-soft); color: var(--ink); border: 1px solid color-mix(in srgb, var(--brand) 18%, transparent); }
.insight b { font-weight: 650; }
.insight .ic { flex: none; width: 22px; height: 22px; border-radius: 6px; background: var(--brand); color: var(--brand-ink);
  display: grid; place-items: center; font-size: 12px; font-weight: 700; margin-top: 1px; }

/* ---- tooltip (one element, driven by data-tip on any mark) ---- */
.tip { position: fixed; z-index: 100; pointer-events: none; background: var(--tooltip-bg); color: var(--tooltip-ink);
  font-size: 12px; line-height: 1.45; padding: 8px 10px; border-radius: 8px; box-shadow: var(--shadow-pop);
  max-width: 280px; opacity: 0; transform: translateY(4px); transition: opacity .08s, transform .08s; }
.tip.on { opacity: 1; transform: none; }
.tip b { font-weight: 650; }
.tip .t-sub { opacity: .7; }

/* ---- skeletons ---- */
.sk { background: linear-gradient(90deg, var(--skeleton) 0%, var(--skeleton-hi) 50%, var(--skeleton) 100%);
  background-size: 200% 100%; animation: sk 1.3s ease-in-out infinite; border-radius: 6px; }
@keyframes sk { from { background-position: 100% 0; } to { background-position: -100% 0; } }
@media (prefers-reduced-motion: reduce) { .sk { animation: none; } }
.sk-kv { height: 104px; border-radius: var(--radius); }
.sk-card { height: 300px; border-radius: var(--radius); }
.sk-line { height: 12px; margin: 8px 0; }

/* ---- mobile: sidebar becomes a drawer ---- */
.scrim { display: none; }
@media (max-width: 900px) {
  .app { grid-template-columns: minmax(0, 1fr); }
  .sidebar { position: fixed; z-index: 60; inset: 0 auto 0 0; width: 272px; transform: translateX(-102%);
    transition: transform .2s ease; box-shadow: var(--shadow-pop); }
  body.nav-open .sidebar { transform: none; }
  .scrim { display: block; position: fixed; inset: 0; z-index: 55; background: rgba(0,0,0,.35); opacity: 0;
    pointer-events: none; transition: opacity .2s; }
  body.nav-open .scrim { opacity: 1; pointer-events: auto; }
  .menu-btn { display: inline-grid; }
  .topbar { padding: 10px 16px; gap: 10px; flex-wrap: wrap; }
  .topbar-title { order: 1; }
  .menu-btn { order: 0; }
  .topbar-controls { order: 2; width: 100%; justify-content: flex-start; }
  .topbar #view-sub { white-space: normal; }
  .view { padding: 16px 16px 40px; }
  .kpi-row { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .kv { padding: 12px 12px 10px; }
  .kv-value { font-size: 19px; }
  .kv-spark { width: 64px; }
  .card { padding: 14px; }
  .table-wrap { overflow-x: auto; }
}
@media (max-width: 380px) { .kpi-row { grid-template-columns: minmax(0, 1fr); } }
.main { padding: 0; }
.split-main { display: grid; grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr); gap: 16px; }
@media (max-width: 1100px) { .split-main { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 380px) { .kpi-row { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 330px) { .kpi-row { grid-template-columns: minmax(0, 1fr); } }
.hm-wrap { overflow-x: auto; }
@media (max-width: 900px) {
  .kv-vs { display: none; }
  .hm-c { height: 30px; font-size: 10.5px; }
  .hm-name { font-size: 12px; padding-right: 6px; }
}

/* =====================================================================
   Phase 3 rollout: the legacy KPI and chart markup, drawn as v2.
   ===================================================================== */
/* Hand-written tiles (a split, a note under the value) get the tile look. */
.card.kpi { padding: 16px 18px 12px; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.card.kpi .kpi-label { font-size: 12px; color: var(--muted); font-weight: 500; }
.card.kpi .kpi-value { font-size: 24px; font-weight: 650; letter-spacing: -.025em; line-height: 1.15; color: var(--ink); }
.card.kpi .kpi-delta { font-size: 11.5px; font-weight: 600; padding: 2px 7px; border-radius: 999px; align-self: flex-start;
  background: var(--panel-2); }
.card.kpi .kpi-delta.delta-pos { color: var(--pos); background: var(--pos-soft); }
.card.kpi .kpi-delta.delta-neg { color: var(--neg); background: var(--neg-soft); }
.card.kpi .sub-note { margin-top: 0; }
@media (max-width: 900px) {
  .card.kpi { padding: 12px 12px 10px; }
  .card.kpi .kpi-value { font-size: 19px; }
}
.kv-value { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kv-note { font-size: 11.5px; color: var(--muted); }

/* Ranked bars (barList) reuse the range-bar rows. */
.rbar-txt { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.card > h3 + .rbars, .card > h3 + .funnel { margin-top: 14px; }

/* Funnel: one hue, stepping lighter down the stages. */
.funnel-row { cursor: default; }
.funnel-fill { color: var(--brand-ink); }

/* Chart dots a tooltip hangs off get a hit area wider than the dot. */
.chart circle[data-tip]:not([stroke]) { stroke: transparent; stroke-width: 12px; }

/* Sub-views: a tab that holds more than one view (Stock Health, SKU
   Performance, Channels & Funnels) shows them as a segmented control. */
.subviews { display: flex; gap: 4px; padding: 3px; border-radius: 10px; background: var(--panel-2);
  border: 1px solid var(--line); width: fit-content; max-width: 100%; overflow-x: auto; margin-bottom: 16px; }
.subviews button { all: unset; cursor: pointer; padding: 6px 12px; border-radius: 7px; font-size: 12.5px; font-weight: 500;
  color: var(--ink-2); white-space: nowrap; }
.subviews button:hover { color: var(--ink); }
.subviews button.on { background: var(--panel); color: var(--ink); font-weight: 600; box-shadow: 0 1px 2px rgba(0,0,0,.08); }
.subviews button:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }

/* Nav emoji. */
.nav-item .nav-emoji { width: 20px; text-align: center; font-size: 14px; line-height: 1; flex: none; }

/* Pacing gauge (Month Pacing). */
.pace-card { display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; }
.gauge-track { position: relative; height: 14px; border-radius: 7px; background: var(--panel-2); overflow: visible; }
.gauge-banked { position: absolute; left: 0; top: 0; bottom: 0; background: var(--brand); border-radius: 7px 0 0 7px; }
.gauge-proj { position: absolute; top: 0; bottom: 0; background: var(--brand); opacity: .28;
  background-image: repeating-linear-gradient(135deg, transparent 0 4px, rgba(255,255,255,.35) 4px 7px); }
.gauge-target { position: absolute; top: -6px; bottom: -6px; width: 2px; background: var(--ink); border-radius: 1px; }
.gauge-today { position: absolute; top: -3px; bottom: -3px; width: 0; border-left: 1.5px dashed var(--muted); }
.gauge-scale { display: flex; justify-content: space-between; font-size: 11px; color: var(--muted); margin-top: 6px; }
.gauge-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; }
.gauge-stat { padding: 10px 12px; border-radius: var(--radius-sm); background: var(--panel-2); }
.gauge-stat .l { font-size: 11.5px; color: var(--muted); }
.gauge-stat .v { font-size: 17px; font-weight: 650; letter-spacing: -.015em; }
.gauge-stat .v.pos { color: var(--pos); }
.gauge-stat .v.neg { color: var(--neg); }

/* Waterfall (Unit Economics). */
.wf .wf-bar-up { fill: var(--brand); }
.wf .wf-bar-down { fill: var(--neg); opacity: .78; }
.wf .wf-bar-total { fill: var(--pos); }
.wf .wf-bar-total.neg { fill: var(--neg); }
.wf .wf-link { stroke: var(--muted); stroke-dasharray: 2 3; }
.wf .wf-val { fill: var(--ink-2); font-size: 11px; font-weight: 600; }
.wf .wf-lab { fill: var(--muted); font-size: 11px; }

/* Diverging bars: a figure that can go below zero (per-range CM2). */
.dbars { display: flex; flex-direction: column; gap: 12px; }
.dbar-top { display: flex; justify-content: space-between; gap: 10px; font-size: 12.5px; }
.dbar-track { position: relative; height: 8px; margin-top: 6px; background: var(--panel-2); border-radius: 4px; }
.dbar-zero { position: absolute; top: -3px; bottom: -3px; width: 1px; background: var(--ink-2); opacity: .5; }
.dbar-fill { position: absolute; top: 0; bottom: 0; border-radius: 4px; }
.dbar-sub { font-size: 11.5px; color: var(--muted); margin-top: 3px; }

/* Donut. */
.donut-wrap { display: flex; gap: 20px; align-items: center; flex-wrap: wrap; }
.donut { width: 150px; height: 150px; flex: none; }
.donut .dn-c { fill: var(--ink); font-size: 15px; font-weight: 650; }
.donut .dn-s { fill: var(--muted); font-size: 10px; }
.donut-legend { display: flex; flex-direction: column; gap: 8px; flex: 1; min-width: 160px; font-size: 12.5px; }
.donut-legend div { display: flex; justify-content: space-between; gap: 10px; }
.donut-legend i { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 8px; vertical-align: -1px; }
.donut-legend b { font-weight: 600; }
.donut-legend span.s { color: var(--muted); margin-left: 6px; }

/* Tiles size to their row: a narrow tile drops the "vs prev" words first,
   then the sparkline, so the value and its change never wrap. */
@media (min-width: 901px) { .kpi-row { grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); } }
.kv { container-type: inline-size; }
.kv-spark { width: auto; flex: 0 1 96px; min-width: 44px; }
@container (max-width: 230px) { .kv-vs { display: none; } }
@container (max-width: 120px) { .kv-spark { display: none; } }
@media (max-width: 900px) {
  /* Charts keep a legible size and scroll sideways inside their card. */
  .card { overflow-x: auto; }
  .card svg.chart { min-width: 560px; }
}
/* A segmented control longer than the screen scrolls inside itself rather
   than widening the page (Stock Health's eight pools on a phone). */
.seg { max-width: 100%; overflow-x: auto; scrollbar-width: none; }
.seg::-webkit-scrollbar { display: none; }
.seg .seg-btn { flex: none; }
.halves { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 1100px) { .halves { grid-template-columns: minmax(0, 1fr); } }
