/* ============================================================
   CDP design system — v2.8.0 sage rebrand UI, v2.9.0 Morandi chart series
   Primary #8A9585. Light + dark, auto-switched by prefers-color-scheme AND
   toggleable via the topbar button (sets data-theme, persisted in localStorage).
   Token names, layering, and 4px grid unchanged from the Atlas 2.0 baseline
   this replaces — see DESIGN-TOKENS.md for full derivation + contrast math,
   including the accepted accessibility trade-off on --series-*.
   4px radius · 4px spacing grid · Roboto/Noto Sans TC
   ============================================================ */

:root {
  color-scheme: light;

  /* Surfaces */
  --page-plane: #f6f7f5;
  --surface-1: #fdfefd;       /* cards, tables */
  --surface-2: #ebefe9;       /* inputs, buttons, fields */
  --surface-3: #e5ebe3;       /* labels, toolbars, table headers */

  /* Header (brand block — same hex both themes; on-header ink makes it work in both) */
  --header-bg: #8A9585;
  --on-header: #212a1d;

  /* Ink */
  --text-primary: #212a1d;
  --text-secondary: #535f4e;
  --text-muted: #7c8a75;

  /* Lines */
  --gridline: rgba(30, 35, 25, 0.12);
  --baseline: #aab6a5;
  --border: rgba(30, 35, 25, 0.12);

  /* Accent & interaction */
  --accent: #597f47;
  --accent-darken: #496b3a;
  --pagination-selected: #689d51;
  --on-pagination-selected: #212a1d;
  --hover-wash: rgba(30, 35, 25, 0.05);
  --on-accent: #ffffff;              /* text/icon on a filled --accent button (4.61:1) */
  --accent-wash: rgba(89, 127, 71, 0.12);
  --on-mark: #1a2118;                 /* dark ink on any bright chart-mark fill, both themes */

  /* Status (fixed meaning — never themed to the brand hue, only re-stepped per surface) */
  --status-good: #208143;
  --status-warning: #99660c;
  --status-critical: #d0372c;
  --status-good-bg: rgba(32, 129, 67, 0.14);
  --status-warning-bg: rgba(153, 102, 12, 0.14);
  --status-critical-bg: rgba(208, 55, 44, 0.14);

  /* Tag/badge text — hue-matched to a series family but independently solved for 4.5:1 text
     contrast (the raw series hex is a *mark* color, only guaranteed ~2.7:1 in this Morandi set —
     see DESIGN-TOKENS.md). */
  --tag-free: #a6463f;      --tag-free-bg: rgba(192, 95, 89, 0.16);
  --tag-paid: #8f7130;      --tag-paid-bg: rgba(198, 161, 83, 0.16);
  --tag-existing: #5f7f44;  --tag-existing-bg: rgba(137, 175, 106, 0.16);
  --tag-new: #4d7c8f;       --tag-new-bg: rgba(106, 155, 175, 0.16);

  /* Chart series — v2.9.0: rebased on the Dulux "莫蘭迪色系 精選36色" swatch chart, by explicit
     request, accepting the accessibility trade-off documented in DESIGN-TOKENS.md: Morandi tones
     are deliberately low-chroma, so this set does NOT pass the dataviz-skill categorical validator
     (chroma floor / CVD separation both fail — see the doc for the actual numbers). Every chart on
     this site already ships a legend + hover tooltip, which is the relief this leans on. */
  --series-1: #A9504A;
  --series-2: #748764;
  --series-3: #5E7A85;
  --series-4: #C0973F;
  --series-5: #6E5F6C;
  --series-6: #94654A;
  --series-7: #A89873;
  --series-8: #909d86;
  --series-9: #566065;
  --series-10: #C57C6C;
  --series-11: #8FA283;
  --series-12: #849ea4;
  --series-13: #be9230;
  --series-14: #9C8B99;
  --series-15: #CC8264;
  --series-16: #b2956c;
  --series-17: #4E5850;
  --series-18: #3E5560;
  --series-19: #6B2530;
  --series-20: #9B7B2E;

  --font: Roboto, "Noto Sans TC", system-ui, -apple-system, "Segoe UI", sans-serif;

  --radius: 4px;
  --card-padding: 20px;
  --shadow-inset: rgba(30, 40, 44, 0.12) 0px -1px 0px 0px inset;
}

@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) {
    color-scheme: dark;

    --page-plane: #3c4538;
    --surface-1: #30372c;
    --surface-2: #2d3429;
    --surface-3: #434d3f;

    --header-bg: #8A9585;
    --on-header: #212a1d;

    --text-primary: #eff2ed;
    --text-secondary: #bbc2b7;
    --text-muted: #919c8b;

    --gridline: rgba(255, 255, 255, 0.12);
    --baseline: #71816a;
    --border: rgba(255, 255, 255, 0.12);

    --accent: #95b886;
    --accent-darken: #a4c695;   /* dark surfaces: hover brightens, doesn't darken, or the fill recedes */
    --pagination-selected: #95b886;
    --on-pagination-selected: #16211a;
    --hover-wash: rgba(255, 255, 255, 0.04);
    --on-accent: #16211a;       /* dark ink on a filled --accent button (7.48:1) */
    --accent-wash: rgba(149, 184, 134, 0.15);
    --on-mark: #1a2118;

    --status-good: #2ed4ac;
    --status-warning: #ffb46f;
    --status-critical: #ff6c7e;
    --status-good-bg: rgba(46, 212, 172, 0.16);
    --status-warning-bg: rgba(255, 180, 111, 0.16);
    --status-critical-bg: rgba(255, 108, 126, 0.16);

    --tag-free: #d18b86;      --tag-free-bg: rgba(192, 95, 89, 0.20);
    --tag-paid: #d2b679;      --tag-paid-bg: rgba(198, 161, 83, 0.20);
    --tag-existing: #a3c18b;  --tag-existing-bg: rgba(137, 175, 106, 0.20);
    --tag-new: #8bb1c1;       --tag-new-bg: rgba(106, 155, 175, 0.20);

    --series-1: #C57C6C;
    --series-2: #8FA283;
    --series-3: #8FA6AC;
    --series-4: #D2A94D;
    --series-5: #9C8B99;
    --series-6: #CC8264;
    --series-7: #CBB89C;
    --series-8: #98A48E;
    --series-9: #8D8D8A;
    --series-10: #bc6c66;
    --series-11: #768965;
    --series-12: #688793;
    --series-13: #C0973F;
    --series-14: #8f7d8c;
    --series-15: #ac7758;
    --series-16: #A89873;
    --series-17: #909d86;
    --series-18: #77858c;
    --series-19: #c96272;
    --series-20: #9f7e2f;
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;

  --page-plane: #3c4538;
  --surface-1: #30372c;
  --surface-2: #2d3429;
  --surface-3: #434d3f;

  --header-bg: #8A9585;
  --on-header: #212a1d;

  --text-primary: #eff2ed;
  --text-secondary: #bbc2b7;
  --text-muted: #919c8b;

  --gridline: rgba(255, 255, 255, 0.12);
  --baseline: #71816a;
  --border: rgba(255, 255, 255, 0.12);

  --accent: #95b886;
  --accent-darken: #a4c695;
  --pagination-selected: #95b886;
  --on-pagination-selected: #16211a;
  --hover-wash: rgba(255, 255, 255, 0.04);
  --on-accent: #16211a;
  --accent-wash: rgba(149, 184, 134, 0.15);
  --on-mark: #1a2118;

  --status-good: #2ed4ac;
  --status-warning: #ffb46f;
  --status-critical: #ff6c7e;
  --status-good-bg: rgba(46, 212, 172, 0.16);
  --status-warning-bg: rgba(255, 180, 111, 0.16);
  --status-critical-bg: rgba(255, 108, 126, 0.16);

  --tag-free: #d18b86;      --tag-free-bg: rgba(192, 95, 89, 0.20);
  --tag-paid: #d2b679;      --tag-paid-bg: rgba(198, 161, 83, 0.20);
  --tag-existing: #a3c18b;  --tag-existing-bg: rgba(137, 175, 106, 0.20);
  --tag-new: #8bb1c1;       --tag-new-bg: rgba(106, 155, 175, 0.20);

  --series-1: #C57C6C;
  --series-2: #8FA283;
  --series-3: #8FA6AC;
  --series-4: #D2A94D;
  --series-5: #9C8B99;
  --series-6: #CC8264;
  --series-7: #CBB89C;
  --series-8: #98A48E;
  --series-9: #8D8D8A;
  --series-10: #bc6c66;
  --series-11: #768965;
  --series-12: #688793;
  --series-13: #C0973F;
  --series-14: #8f7d8c;
  --series-15: #ac7758;
  --series-16: #A89873;
  --series-17: #909d86;
  --series-18: #77858c;
  --series-19: #c96272;
  --series-20: #9f7e2f;
}

* { box-sizing: border-box; }

/* subtle scrollbars that blend with the dark theme */
* { scrollbar-width: thin; scrollbar-color: var(--surface-3) transparent; }
*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb { background: var(--surface-3); border-radius: 4px; }
*::-webkit-scrollbar-thumb:hover { background: var(--baseline); }
*::-webkit-scrollbar-corner { background: transparent; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--page-plane);
  color: var(--text-primary);
  font-family: var(--font);
  font-size: 14px;
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-darken); text-decoration: underline; }

/* ---------- Topbar (Atlas light-blue app bar) ---------- */
.topbar {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 12px 24px;
  background: var(--header-bg);
  box-shadow: var(--shadow-inset);
  position: sticky;
  top: 0;
  z-index: 30;
}
.topbar .brand {
  display: flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
}
.brand-mark { height: 32px; width: auto; display: block; flex: none; }
.brand-text { display: flex; flex-direction: column; line-height: 1.2; }
.brand-name {
  font-size: 19px;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--on-header);
}
.brand-tagline {
  font-size: 10.5px;
  font-weight: 500;
  color: var(--on-header);
  opacity: 0.72;
}

/* ---------- Theme toggle (light/dark, persisted in localStorage) ---------- */
.theme-toggle {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  flex: none;
  border: none;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.08);
  color: var(--on-header);
  cursor: pointer;
}
.theme-toggle:hover { background: rgba(0, 0, 0, 0.16); }
.theme-toggle svg { width: 18px; height: 18px; display: block; }
.theme-toggle .icon-moon { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .icon-sun { display: none; }
  :root:not([data-theme="light"]) .theme-toggle .icon-moon { display: block; }
}
:root[data-theme="dark"] .theme-toggle .icon-sun { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: block; }

/* ---------- App shell: left sidemenu + main (Atlas sidemenu tokens) ---------- */
.app-shell {
  display: flex;
  align-items: stretch;
  min-height: calc(100vh - 48px);
}
.sidebar {
  width: 220px;
  flex: none;
  background: var(--surface-2);           /* sidemenu-group */
  padding: 16px 8px;
}
.sidebar nav { display: flex; flex-direction: column; gap: 4px; position: sticky; top: 64px; }
.side-link {
  display: block;
  padding: 10px 12px;
  border-radius: var(--radius);
  color: var(--text-secondary);
  font-size: 13px;
  font-weight: 500;
}
.side-link:hover { background: var(--hover-wash); color: var(--text-primary); text-decoration: none; }
.side-link.active {
  background: var(--pagination-selected);
  color: var(--on-pagination-selected);
}
.side-divider { height: 1px; background: var(--gridline); margin: 8px 4px; }
.side-section {
  padding: 10px 12px 4px;
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
}

.main-content { flex: 1; min-width: 0; }

/* ---------- Skeleton loading (v2.9.1, fixed v2.9.2) ----------
   Every chart/table/stat-tile container on the site is a bare `<div id="…"></div>` that JS fills
   in (charts.js's chartCard/statTile, or a page script's own innerHTML/appendChild) — so it's
   genuinely empty from first paint until that script finishes running (parsing this app's larger
   embedded CSVs — e.g. sales_report at ~38k rows — is not instant). :empty targets exactly that
   window with zero HTML/JS wiring: the shimmer applies for as long as the container has no
   children, and stops the instant any render function adds its first element — no "loading"
   flag to set or clear anywhere. min-height only kicks in when the element would otherwise be
   zero-height (an empty div has no intrinsic size), so it doesn't fight a container that already
   has an explicit height.
   v2.9.2: scoped from `[id]:empty` to `div[id]:empty` — the original selector also matched
   Customer List's filter `<input id="…">`/`<select id="…">` fields, which are *always* :empty
   (form controls hold a value, not child nodes) and so shimmered forever, never escaping the
   loading state no matter how long you waited. Every real container this rule needs to cover is
   already a plain <div>, so the div-only selector loses no coverage. */
.main-content div[id]:empty {
  display: block;
  min-height: 120px;
  border-radius: var(--radius);
  background: linear-gradient(100deg, var(--surface-2) 30%, var(--surface-3) 50%, var(--surface-2) 70%);
  background-size: 250% 100%;
  animation: skeleton-shimmer 1.5s ease-in-out infinite;
}
#kpi-row:empty, .grid-kpi-6:empty { min-height: 88px; }
@keyframes skeleton-shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -50% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .main-content div[id]:empty { animation: none; background-position: 0 0; }
}

.container {
  max-width: 1180px;
  margin: 0 auto;
  padding: 24px;
}

/* RWD: on wide screens let charts breathe */
@media (min-width: 1440px) {
  .container { max-width: 1560px; }
}
@media (min-width: 1920px) {
  .container { max-width: 1800px; }
}

@media (max-width: 900px) {
  .app-shell { flex-direction: column; }
  .sidebar { width: 100%; padding: 8px; }
  .sidebar nav { flex-direction: row; overflow-x: auto; position: static; }
  .side-link { white-space: nowrap; }
  .side-divider, .side-section { display: none; }
}

h1 { font-size: 20px; font-weight: 700; margin: 0 0 4px; }
h2 { font-size: 16px; font-weight: 700; margin: 0 0 12px; }
.page-subtitle { color: var(--text-secondary); font-size: 13px; margin: 0 0 24px; }

.card {
  background: var(--surface-1);
  border: none;
  border-radius: var(--radius);
  padding: var(--card-padding);
  box-shadow: var(--shadow-inset);
}

.grid { display: grid; gap: 16px; }
.grid-kpi { grid-template-columns: repeat(4, 1fr); }
.grid-kpi-6 { grid-template-columns: repeat(6, 1fr); }

.grid-2 { grid-template-columns: 1fr 1fr; }
.grid-2 > * { min-width: 0; }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-3 > * { min-width: 0; }

/* v2.5.30: Customer Flow's row (table + 2 pies) — the table needs more room than an even 3-way
   split gives it; own class instead of reusing grid-3 so this doesn't affect grid-3's other users
   (Customer Amount cards, Top 5 Product row, etc).
   v2.5.32: bottom edges didn't line up — same issue Platform Overview's summary row already had
   (see below): the two pie cells are Viz.pieChart()'s own nested wrapper-div + .card, and a plain
   nested .card doesn't stretch to fill the grid cell's full height on its own even though the grid
   cell itself does (grid default align-items:stretch). Same wrapper+card flex-fill fix applied. */
.customer-flow-row { grid-template-columns: 1.8fr 1fr 1fr; }
.customer-flow-row > * { min-width: 0; display: flex; flex-direction: column; }
.customer-flow-row > #customer-flow-pie-free-paid > .card,
.customer-flow-row > #customer-flow-pie-new-exist > .card { flex: 1; display: flex; flex-direction: column; }
/* v2.5.32: center the legend+pie group in the now-taller card — title stays pinned at top, the
   pie-layout row grows to fill the rest and centers within it both ways (was left-aligned at the
   top, reading as lopsided once the card got taller and wider than the chart itself). */
.customer-flow-row > #customer-flow-pie-free-paid > .card > .pie-layout,
.customer-flow-row > #customer-flow-pie-new-exist > .card > .pie-layout { flex: 1; justify-content: center; }

/* Customer Tier Amount cards (v2.5.18): two stacked Avg/Total rows in one tile. */
.amount-metric { margin-top: 10px; }
/* v2.5.28: Avg/Total labels switched to full white (were --text-muted) — scoped to the Customer
   Amount cards specifically since this is a deliberate emphasis choice, not a site-wide label
   convention change. v2.5.29: font-size reverted back to 10.5px (the v2.5.28 bump to 12px read as
   too large) — kept the white color/weight. */
#customer-tier-amount-row .amount-metric-label {
  color: var(--text-primary);
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.amount-metric-label {
  color: var(--text-muted);
  font-size: 10.5px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.amount-metric .stat-value { font-size: 18px; margin-top: 2px; }

/* Platform Overview's KPI / country overview / trend chart row (v2.1.2): column widths sized to
   each card's actual content instead of an even split. v2.6.8 swapped #chart-country-overview
   (now a pie chart) and #chart-login-trend's DOM order — Country Overview into the middle slot,
   User Login Trend last — but left the column width VALUES as they were, so the pie ended up in
   the wide track and the line chart in the narrow one, backwards from what each actually needs.
   v2.6.9 corrects this: the middle track is now the narrow one (a pie doesn't need much width)
   and the last track is the wide one (a 6-12 month line chart needs the room to stay readable).
   Column widths are positional (not per-ID), so this is just the two minmax() values swapped back
   relative to v2.6.7 — the DOM order from v2.6.8 is unchanged.
   Cards stretch to the row's tallest item (grid default align-items:stretch); all three cards are
   built by Viz.* into a nested wrapper div, so that wrapper + its card need to be set to flex so
   the inner .card actually fills the stretched height. */
.platform-summary-row { grid-template-columns: minmax(200px, 240px) minmax(200px, 1fr) minmax(320px, 1.6fr); }
.platform-summary-row > * { min-width: 0; display: flex; flex-direction: column; }
.platform-summary-row > #kpi-row { gap: 16px; } /* v2.6.8: space between the two stacked stat tiles */
.platform-summary-row > #kpi-row > .card,
.platform-summary-row > #chart-login-trend > .card,
.platform-summary-row > #chart-country-overview > .card { flex: 1; display: flex; flex-direction: column; }
.platform-summary-row > #kpi-row > .card.stat-tile { justify-content: center; }

@media (max-width: 1200px) {
  .grid-kpi-6 { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 900px) {
  .grid-kpi { grid-template-columns: repeat(2, 1fr); }
  .grid-kpi-6 { grid-template-columns: repeat(2, 1fr); }
  .grid-2 { grid-template-columns: 1fr; }
  .platform-summary-row { grid-template-columns: 1fr; }
}

.section { margin-bottom: 24px; }

/* ---------- Stat tile ---------- */
.stat-tile .stat-label {
  color: var(--text-muted);
  font-size: 12px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
/* v2.5.19: Customer Tier Amount cards (Paid/New/Total Customer) — labels white + bold */
#customer-tier-amount-row .stat-label { color: var(--text-primary); font-weight: 700; }
/* v2.5.21: the three cards sit on the same --surface-1 background as the outer "Customer Amount"
   card wrapping them, so without their own contrast they visually merge into one undifferentiated
   block.
   v2.5.22: a thin border read as too subtle — switched to a solid, differently-shaded fill
   (--surface-2, the same "one step darker" shade table.flow-table's own body cells use to read as
   their own distinct block against a --surface-1 card) instead of an outline. */
#customer-tier-amount-row .amount-tile { background: var(--surface-2); }
.stat-tile .stat-value {
  font-size: 28px;
  font-weight: 700;
  margin-top: 8px;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.stat-tile .stat-sub {
  color: var(--text-secondary);
  font-size: 12px;
  margin-top: 4px;
}
.stat-tile .stat-delta {
  font-size: 12px;
  font-weight: 500;
  margin-top: 6px;
  font-variant-numeric: tabular-nums;
}
.delta-up { color: var(--status-good); }
.delta-down { color: var(--status-critical); }
.delta-flat { color: var(--text-muted); }

/* Corner info icon (v2.5.5): sits top-right of the card instead of in a label row. */
.stat-tile { position: relative; }
.stat-tile > .info-icon { position: absolute; top: var(--card-padding); right: var(--card-padding); }
/* v2.5.5: rightmost tiles' tooltip would overflow past the page edge if centered under the icon;
   anchor those to the icon's right edge instead so the tooltip grows leftward. */
.info-icon.tip-align-right .info-tip { left: auto; right: 0; transform: none; }

/* ---------- Charts ---------- */
.chart-card .chart-title { font-size: 14px; font-weight: 700; color: var(--text-primary); margin-bottom: 2px; }
.chart-title-row { display: flex; align-items: center; gap: 6px; margin-bottom: 12px; }
.chart-title-row .chart-title { margin-bottom: 0; }
/* v2.5.26: a plain-text summary line under a chart-title-row, above the chart/table itself
   (e.g. "N SAP CNOs without an Atlas root org") */
.chart-sub { color: var(--text-secondary); font-size: 12px; margin: -6px 0 12px; }

/* Info icon + hover tooltip — replaces the old always-visible .chart-caption line (v2.0.1) */
.info-icon {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 15px;
  height: 15px;
  flex: 0 0 auto;
  border-radius: 50%;
  background: var(--surface-3);
  color: var(--text-muted);
  font-size: 10.5px;
  font-style: italic;
  font-family: Georgia, 'Times New Roman', serif;
  cursor: default;
}
.info-icon:hover, .info-icon:focus { color: var(--text-primary); background: var(--accent); outline: none; }
.info-icon .info-tip {
  display: none;
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  width: max-content;
  max-width: 280px;
  padding: 8px 10px;
  border-radius: var(--radius);
  background: var(--surface-3);
  color: var(--text-primary);
  font-size: 12px;
  font-style: normal;
  font-weight: 400;
  line-height: 1.4;
  text-align: left;
  white-space: pre-line;      /* v2.6.3: lets caption strings opt into line breaks via \n while
                                  still wrapping/collapsing runs of spaces like plain text did */
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
  z-index: 20;
}
.info-icon:hover .info-tip, .info-icon:focus .info-tip { display: block; }
/* v2.5.37: opens downward instead of upward — for icons near the top of the viewport (e.g. the
   customer dashboard's header badges), opening upward pushed the tip off the top of the screen. */
.info-icon.tip-align-down .info-tip { bottom: auto; top: calc(100% + 6px); }
.chart-empty { color: var(--text-muted); font-size: 13px; padding: 24px 0; text-align: center; }

.viz-tooltip {
  position: fixed;
  pointer-events: none;
  background: var(--surface-2);
  color: var(--text-primary);
  font-size: 12px;
  padding: 6px 9px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  z-index: 100;
  display: none;
  white-space: nowrap;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
}
/* per-segment breakdown table (e.g. percentColumnChart's hover) — swatch + name + right-aligned
   numeric columns so Pricing Plan Name / count / % actually line up row to row. */
.tooltip-table { border-collapse: collapse; margin-top: 4px; }
.tooltip-table td { padding: 1px 4px; vertical-align: middle; }
.tooltip-table td:first-child { padding-left: 0; }
.tooltip-table td.swatch { padding-right: 2px; }
.tooltip-table .swatch-dot { display: inline-block; width: 8px; height: 8px; border-radius: 2px; }
.tooltip-table td.num { text-align: right; font-variant-numeric: tabular-nums; color: var(--text-secondary); }

.bar-row-label { fill: var(--text-secondary); font-size: 12px; }
.bar-value-label { fill: var(--text-primary); font-size: 12px; font-weight: 500; font-variant-numeric: tabular-nums; }
.axis-label { fill: var(--text-muted); font-size: 11px; }
.gridline { stroke: var(--gridline); stroke-width: 1; }
.baseline { stroke: var(--baseline); stroke-width: 1; }
.hover-band { fill: var(--hover-wash); }

/* ---------- Filter bar (field wells: --surface-2) ---------- */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-bottom: 16px;
}
/* min-width (not just flex-basis) so a field never gets squeezed narrower than its content needs —
   flex-basis alone still lets flex-shrink squish it past that point; once the row runs out of room,
   flex-wrap on .filter-bar sends the whole field to the next line instead. */
.filter-field { display: flex; flex-direction: column; gap: 4px; flex: 1 1 160px; min-width: 160px; }
.filter-field:has(input[type="text"]) { min-width: 240px; }
/* pill-toggle's own content is nowrap (below), so let the flex-item default (min-width: auto) take
   over instead of the 160px floor — auto correctly sizes to the pills' un-wrapped content width,
   whatever that is for however many options a given page's toggle has. */
.filter-field:has(.pill-toggle) { min-width: auto; }
/* Reset always sits at the far right of its row — margin-left: auto pushes it there whether it's
   sharing the row with every other filter field or, once .filter-bar's wrap kicks in, alone on its
   own line (still right-aligned on that line, not stranded wherever it happened to land). */
.filter-field:has(> #reset-filters) { flex: 0 0 auto; min-width: auto; margin-left: auto; }
.filter-field .flabel {
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-muted);
}

.search-row { margin-bottom: 16px; }
.search-row input[type="text"] {
  width: 66.6667%;
  max-width: 100%;
  font-family: var(--font);
  font-size: 13px;
  padding: 8px 12px;
  border-radius: var(--radius);
  border: 1px solid transparent;
  background: var(--surface-2);
  color: var(--text-primary);
}
.search-row input[type="text"]::placeholder { color: var(--text-muted); }
.search-row input[type="text"]:focus { outline: none; border-color: var(--accent); }

.filter-bar input[type="text"],
.filter-bar input[type="month"],
.filter-bar input[type="date"],
.filter-bar select {
  font-family: var(--font);
  font-size: 13px;
  padding: 8px 12px;
  border-radius: var(--radius);
  border: 1px solid transparent;
  background: var(--surface-2);
  color: var(--text-primary);
}
.filter-field input[type="text"],
.filter-field input[type="month"],
.filter-field input[type="date"],
.filter-field select {
  width: 100%;
}
.filter-bar input[type="text"]::placeholder { color: var(--text-muted); }
.filter-bar input[type="text"]:focus,
.filter-bar input[type="month"]:focus,
.filter-bar input[type="date"]:focus,
.filter-bar select:focus {
  outline: none;
  border-color: var(--accent);
}
.filter-bar select option { background: var(--surface-2); color: var(--text-primary); }
.filter-bar input[type="text"] { min-width: 240px; flex: 1 1 240px; }
.filter-bar select { min-width: 140px; }
.filter-bar button {
  font-family: var(--font);
  font-size: 12px;
  font-weight: 500;
  padding: 8px 16px;
  border-radius: var(--radius);
  border: none;
  background: var(--accent);
  color: var(--on-accent);
  cursor: pointer;
}
.filter-bar button:hover { background: var(--accent-darken); color: var(--on-accent); }
.result-count { color: var(--text-muted); font-size: 12px; margin-bottom: 8px; }

/* ---------- Pill toggle (MTD/YTD mode switch) ---------- */
/* Hidden radio inputs behind each pill's <span>; :checked + span drives every visual state, so
   the on/off look works with zero JS — page JS only reads/sets which radio is checked. */
/* align-self: flex-start so it hugs its content width instead of being stretched to the full
   column width by .filter-field's default (stretch) cross-axis alignment, like a <select> would be. */
.pill-toggle { display: inline-flex; align-self: flex-start; gap: 4px; padding: 3px; background: var(--surface-2); border-radius: 999px; white-space: nowrap; }
.pill-option { position: relative; display: flex; cursor: pointer; }
.pill-option input {
  position: absolute;
  inset: 0;
  opacity: 0;
  margin: 0;
  cursor: pointer;
}
.pill-option span {
  display: block;
  padding: 6px 16px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  color: var(--text-muted);
  background: transparent;
  transform: scale(1);
  transition: background-color 0.25s ease, color 0.25s ease, transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
  user-select: none;
}
.pill-option input:checked + span {
  background: var(--accent);
  color: var(--on-accent);
  transform: scale(1.06);
}
.pill-option input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---------- Table (surface: --surface-1) ---------- */
table.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  background: var(--surface-1);
}
table.data-table th {
  text-align: left;
  color: var(--text-muted);
  font-weight: 500;
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 10px 12px;
  background: var(--surface-3);
  border-bottom: 1px solid var(--gridline);
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
table.data-table th:hover { color: var(--text-primary); }
table.data-table td {
  padding: 10px 12px;
  border-bottom: 1px solid var(--gridline);
  color: var(--text-primary);
  vertical-align: middle;
}
table.data-table tbody tr { cursor: pointer; }
table.data-table tbody tr:hover td { background: var(--hover-wash); }
table.data-table .num { font-variant-numeric: tabular-nums; text-align: right; }
table.data-table th.num { text-align: right; }
table.data-table .muted { color: var(--text-muted); }
table.data-table .note-label { color: var(--text-muted); }
table.data-table .note-value { color: var(--text-primary); }

/* v2.5.28: SAP CNO Without Atlas — table-layout: fixed + explicit column widths, same approach the
   site's pivot tables use (.w-d0/.w-d1/etc.) — without it, "Invoice Count"/"TWD Total" as HEADER
   TEXT is wider than the actual short numeric values below, so those columns stretch to fit the
   label and the right-aligned numbers end up with a large empty gap in front of them. */
table.no-atlas-cols { table-layout: fixed; }
table.no-atlas-cols .w-sap { width: 9%; }
table.no-atlas-cols .w-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; width: 21%; }
table.no-atlas-cols .w-country { width: 12%; }
table.no-atlas-cols .w-date { width: 11%; }
table.no-atlas-cols .w-num { width: 12%; }
table.no-atlas-cols .w-total { width: 12%; }

/* v2.5.28: same fixed-width fix applied to the per-tier Top 5 Product tables — header text (e.g.
   "Subscriptions") is wider than the actual short values below it.
   v2.5.29: "Subscriptions" was still sitting almost flush against the table's right edge — widened
   the column and added extra right padding so it keeps the same breathing room as the left side.
   v2.5.30: that extra right padding (20px) wasn't matched on the left ("#" column stayed at the
   base 12px), so the table read as lopsided — both outer edges now use the same 16px inset. */
table.top5-cols { table-layout: fixed; }
table.top5-cols .w-rank { width: 14%; padding-left: 16px; }
table.top5-cols .w-product { width: 52%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
table.top5-cols .w-sub { width: 34%; padding-right: 16px; }

/* v2.5.33: fixed-width headers (no-atlas-cols/top5-cols/flow-table) can still overflow past their
   own column/table edge at some zoom levels or narrower viewports. First tried wrap+break-word,
   but a forced mid-word break ("SUBSCRI"/"PTIONS" on two lines) reads worse than the ellipsis
   truncation the body cells (Product/Company Name) already use — switched to the SAME technique
   instead: nowrap + ellipsis, with a native `title` attribute (set in overview.js) so hovering
   reveals the full label, same as how truncated Product/Company Name cells now also work. Scoped
   to this page's own table classes, not the shared .data-table th rule other pages use. */
table.no-atlas-cols th,
table.top5-cols th,
table.flow-table th { overflow: hidden; text-overflow: ellipsis; }

/* Customer Flow roll-forward table (v2.5.14). v2.5.15: dropped the per-column/per-row shading.
   v2.5.17: body cells now use --surface-2 (darker than the card's --surface-1) so the table
   visibly reads as a distinct, deeper-toned block inside the card — matching Company Overview's
   actual rendering, not just its (identical-looking-on-paper but not-in-practice) CSS values. */
table.flow-table tbody tr { cursor: default; }
table.flow-table td { background: var(--surface-2); }
table.flow-table td.flow-label-cell { display: flex; align-items: center; gap: 6px; }
table.flow-table th .info-icon { margin-left: 6px; vertical-align: middle; }
/* v2.5.18: the icon's default background (--surface-3) is the SAME color as the th header row it
   sits on, so it visually disappeared into the header. Darken it specifically inside a th. */
table.flow-table th .info-icon { background: var(--surface-1); }
/* v2.5.21: the darkened background above (higher specificity than the base .info-icon:hover rule)
   was also winning on hover/focus, so the Free/Paid header icons never turned blue on hover like
   every other info icon on the site. Restore the accent hover state specifically here. */
table.flow-table th .info-icon:hover, table.flow-table th .info-icon:focus { background: var(--accent); color: var(--text-primary); }
/* v2.5.17: Balance c/f row and the Total column (+ its header) are bold — the two numbers that
   matter most when skimming the table. Balance b/f stays plain. */
table.flow-table tr.flow-cf-row td { font-weight: 700; }
table.flow-table th:last-child, table.flow-table td.ttl { font-weight: 700; }
/* v2.5.15: th text is uppercased by the base .data-table style — without this, the info icon's "i"
   and its tooltip text inherit that same uppercase transform (rendering as "I" and shouting text). */
table.flow-table th .info-icon, table.flow-table th .info-icon .info-tip { text-transform: none; }

/* ---------- Badges (Atlas semantic colors, dark surface) ---------- */
.badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: var(--radius);
  font-size: 11.5px;
  font-weight: 500;
}
.badge-good { background: var(--status-good-bg); color: var(--status-good); }
.badge-off { background: rgba(180, 180, 180, 0.14); color: var(--text-secondary); }
.badge-critical { background: var(--status-critical-bg); color: var(--status-critical); }
.badge-warning { background: var(--status-warning-bg); color: var(--status-warning); }
/* v2.5.36: Paid/Free/New/Existing badges (customer.html's dashboard) match Customer Overview's own
   Free/Paid/New/Existing colors instead of the generic gray badge-off, so the same concept reads as
   the same color across both pages. Churned still uses badge-critical.
   v2.8.0: switched from raw --series-N (a *mark* color, only guaranteed 3:1) to dedicated --tag-*
   tokens solved for 4.5:1 text contrast in both themes — see DESIGN-TOKENS.md. */
.badge-free { background: var(--tag-free-bg); color: var(--tag-free); }
.badge-paid { background: var(--tag-paid-bg); color: var(--tag-paid); }
.badge-new { background: var(--tag-new-bg); color: var(--tag-new); }
.badge-existing { background: var(--tag-existing-bg); color: var(--tag-existing); }

/* ---------- Pagination (Atlas table-pagination tokens) ---------- */
.pagination {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-top: 16px;
  flex-wrap: wrap;
}
.pagination button {
  font-family: var(--font);
  font-size: 12px;
  font-weight: 500;
  min-width: 32px;
  padding: 6px 8px;
  border-radius: var(--radius);
  border: none;
  background: var(--surface-2);
  color: var(--text-primary);
  cursor: pointer;
}
.pagination button:hover:not(:disabled):not(.active) { background: var(--surface-3); }
.pagination button.active {
  background: var(--pagination-selected);
  color: var(--on-pagination-selected);
}
.pagination button:disabled { opacity: 0.5; cursor: default; }

/* ---------- Detail page ---------- */
.detail-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  margin-bottom: 20px;
  flex-wrap: wrap;
}
.back-link { font-size: 13px; color: var(--accent); }
.profile-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 16px;
}
.profile-field .field-label { font-size: 11.5px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.03em; }
.profile-field .field-value { font-size: 14px; margin-top: 4px; font-weight: 500; color: var(--text-primary); }

.detail-badges { display: flex; gap: 8px; margin-top: 6px; }

/* v2.5.36: no longer sticky — it blocked the view when scrolling through the tabs below. */
.profile-card-sticky {
  margin-bottom: 20px;
}

/* ---------- Detail page tabs ---------- */
.tab-nav {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--gridline);
  margin-bottom: 20px;
}
.tab-btn {
  font-family: var(--font);
  font-size: 13px;
  font-weight: 500;
  padding: 10px 16px;
  border: none;
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.tab-btn:hover { color: var(--text-primary); }
.tab-btn.active { color: var(--accent); border-bottom-color: var(--accent); }

.empty-state {
  text-align: center;
  color: var(--text-muted);
  padding: 60px 20px;
}

/* ---------- Pie chart ---------- */
/* v2.6.9: legend moved above the pie (was side-by-side, legend left / pie right) — same layout
   for every Viz.pieChart() caller (Sales Report's Service Percentage, Platform Overview's Country
   Overview, Customer Overview's Free/Paid + New/Existing pies), so they all read consistently. */
.pie-layout {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}
.pie-layout .pie-svg { width: 100%; max-width: 260px; height: auto; flex: none; }
.pie-legend {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: center;
  gap: 4px 12px;
  width: 100%;
}
.legend-item {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  padding: 3px 6px;
  border-radius: var(--radius);
}
.legend-item.legend-hover { background: var(--hover-wash); }
.legend-swatch { width: 10px; height: 10px; border-radius: 2px; flex: none; }
.legend-label { color: var(--text-primary); flex: 1; }
.pie-legend .legend-label { flex: none; } /* top-row chips size to their text, not a stacked list */
.legend-value { color: var(--text-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* inline legend for two-series line charts */
.line-legend { display: flex; gap: 16px; margin-bottom: 8px; }
.line-legend .legend-item { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; padding: 0; }
.line-legend .legend-label { color: var(--text-secondary); }
/* .wrap modifier: for legends with more items than fit on one line (e.g. stacked column charts) */
.line-legend.wrap { flex-wrap: wrap; row-gap: 6px; gap: 12px 16px; }
/* v2.5.32: clickable legend items (multiLineChart) toggle their line on/off — dim + strike the
   label when off so it's clear at a glance which lines are currently hidden. */
.line-legend .legend-toggle { cursor: pointer; user-select: none; }
.line-legend .legend-toggle:hover .legend-label { color: var(--text-primary); }
.line-legend .legend-toggle.legend-off { opacity: 0.45; }
.line-legend .legend-toggle.legend-off .legend-label { text-decoration: line-through; }

/* horizontal scroll for charts sized wider than their card (e.g. many-category stacked bars) */
.chart-hscroll { overflow-x: auto; }
/* v2.5.22: Customer Product Interest only ever has 3 bars (Free/Paid/New) and never needs to
   scroll — force it off regardless of any width rounding, instead of relying on the width math to
   always come out exactly right. Scoped to this one chart's container, other pages unaffected. */
#customer-product-interest-chart .chart-hscroll { overflow-x: hidden; }

/* Trend line show/hide checkboxes (v2.5.7) */
.tier-trend-controls { display: flex; flex-wrap: wrap; gap: 8px 16px; margin-bottom: 12px; }
.tier-trend-controls label {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--text-primary); cursor: pointer;
}
.tier-trend-controls input[type="checkbox"] { accent-color: var(--accent); cursor: pointer; }
/* v2.5.9: select-all/none buttons, same filled-button look as the filter bar's Reset button */
.trend-select-btn {
  font-family: var(--font);
  font-size: 12px;
  font-weight: 500;
  padding: 4px 12px;
  border-radius: var(--radius);
  border: none;
  background: var(--accent);
  color: var(--on-accent);
  cursor: pointer;
}
/* Outlined "Download" button (v2.6.1, Sales Report Company Overview) — per design spec, an
   outlined pill (not the filled buttons above): 1px accent-color border, transparent fill, accent
   text/icon. margin-left: auto pushes it to the far right of its chart-title-row without needing
   to touch that row's own flex rules (which every other page's title row also uses). */
.download-btn {
  box-sizing: border-box;
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  gap: 4px;
  padding: 8px 12px;
  width: 107px;
  height: 36px;
  margin-left: auto;
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  background: transparent;
  color: var(--accent);
  font-family: var(--font);
  font-size: 12px;
  font-weight: 500;
  line-height: 18px;
  cursor: pointer;
}
.download-btn:hover { background: var(--accent-wash); }
.download-btn .download-icon { width: 20px; height: 20px; flex: none; color: var(--accent); }
.pie-slice-label {
  fill: var(--on-mark);        /* dark ink reads on all bright slice hues, both themes */
  font-size: 10.5px;
  font-weight: 700;
}

/* ---------- Rank table (Top N) ---------- */
table.data-table td.rank-num {
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  width: 36px;
}
table.data-table tr.static-row { cursor: default; }

/* v2.7.0: Customer Dashboard tables cap at ~10 visible rows then scroll (replaces the old
   Prev/Next pagination — same sticky-header approach as .pivot-wrap.pivot-scroll below, sized for
   plain .data-table rows: header ~41px + 10 rows * ~41px). */
.detail-table-scroll { max-height: 452px; overflow: auto; }
.detail-table-scroll thead th { position: sticky; top: 0; z-index: 2; }

/* ---------- Pivot table ---------- */
.pivot-wrap { overflow-x: auto; }
/* scroll-down variant: fixed height, sticky header, no paging */
.pivot-wrap.pivot-scroll { max-height: 520px; overflow: auto; }
.pivot-wrap.pivot-scroll thead th { position: sticky; top: 0; z-index: 3; }
.pivot-wrap.pivot-scroll thead th[class*="stick-d"] { z-index: 5; }
.pivot-wrap.pivot-scroll thead th.ttl-col { z-index: 4; }
/* v2.6.3: column-total row, frozen to the bottom of the pivot-scroll variant the same way the
   header freezes to the top (see buildPivotTable()'s optional footerRow / <tfoot>). */
.pivot-wrap.pivot-scroll tfoot td { position: sticky; bottom: 0; z-index: 3; }
.pivot-wrap.pivot-scroll tfoot td[class*="stick-d"] { z-index: 5; }
.pivot-wrap.pivot-scroll tfoot td.ttl-col { z-index: 4; }
table.pivot-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12.5px;
  background: var(--surface-1);
}
table.pivot-table th {
  text-align: right;
  color: var(--text-muted);
  font-weight: 500;
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  padding: 9px 12px;
  background: var(--surface-3);
  border-bottom: 1px solid var(--gridline);
  white-space: nowrap;
}
table.pivot-table th.dim { text-align: left; }
table.pivot-table td {
  padding: 8px 12px;
  border-bottom: 1px solid var(--gridline);
  color: var(--text-primary);
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
table.pivot-table td.dim {
  text-align: left;
  background: var(--surface-2);   /* row dimensions get a distinct base color */
}
table.pivot-table td.zero { color: var(--text-muted); }
table.pivot-table .ttl { font-weight: 700; }
table.pivot-table tbody tr:hover td:not(.dim):not(.ttl-col) { background: var(--hover-wash); }
/* v2.6.3: column-total row — same visual weight as the header (opaque background so it reads
   clearly once frozen over scrolled-past body rows) */
table.pivot-table tfoot td {
  font-weight: 700;
  color: var(--text-primary);
  background: var(--surface-3);
  border-top: 1px solid var(--gridline);
  border-bottom: none;
}
table.pivot-table tfoot td.dim { text-align: left; }
/* frozen row-dimension columns: fixed widths so sticky offsets line up
   (box-sizing: border-box — widths include the 12px cell padding) */
table.pivot-table .w-d0 { min-width: 200px; max-width: 200px; overflow: hidden; text-overflow: ellipsis; }
table.pivot-table .w-d1 { min-width: 84px;  max-width: 84px; }
table.pivot-table .w-d2 { min-width: 114px; max-width: 114px; overflow: hidden; text-overflow: ellipsis; }
table.pivot-table .w-d3 { min-width: 64px;  max-width: 64px; }
table.pivot-table .stick-d0 { position: sticky; left: 0;     z-index: 2; }
/* Country-keyed pivots: frozen column only needs to fit a short country code, not a name */
#company-login-pivot-wrap table.pivot-table .w-d0,
#user-login-pivot-wrap table.pivot-table .w-d0 { min-width: 96px; max-width: 96px; }
/* Company Overview pivot (Platform Overview): 4 frozen row dims — number, name, country, sales —
   need different proportions than the default (name is the longest field here, not the first column) */
#company-overview-pivot-wrap table.pivot-table .w-d0 { min-width: 180px; max-width: 180px; overflow: hidden; text-overflow: ellipsis; }
#company-overview-pivot-wrap table.pivot-table .w-d1 { min-width: 200px; max-width: 200px; overflow: hidden; text-overflow: ellipsis; }
#company-overview-pivot-wrap table.pivot-table .w-d2 { min-width: 70px;  max-width: 70px;  overflow: hidden; text-overflow: ellipsis; }
#company-overview-pivot-wrap table.pivot-table .w-d3 { min-width: 110px; max-width: 110px; overflow: hidden; text-overflow: ellipsis; }
#company-overview-pivot-wrap table.pivot-table .stick-d1 { left: 180px; }
#company-overview-pivot-wrap table.pivot-table .stick-d2 { left: 380px; }
#company-overview-pivot-wrap table.pivot-table .stick-d3 { left: 450px; }
/* User Overview pivot (Platform Overview, v2.1.2): only 3 frozen row dims — email, country, sales
   (Company Name dropped) — email is the longest field here, so it takes d0 instead of the default */
#user-overview-pivot-wrap table.pivot-table .w-d0 { min-width: 220px; max-width: 220px; overflow: hidden; text-overflow: ellipsis; }
#user-overview-pivot-wrap table.pivot-table .w-d1 { min-width: 70px;  max-width: 70px;  overflow: hidden; text-overflow: ellipsis; }
#user-overview-pivot-wrap table.pivot-table .w-d2 { min-width: 110px; max-width: 110px; overflow: hidden; text-overflow: ellipsis; }
#user-overview-pivot-wrap table.pivot-table .stick-d1 { left: 220px; }
#user-overview-pivot-wrap table.pivot-table .stick-d2 { left: 290px; }
table.pivot-table .stick-d1 { position: sticky; left: 200px; z-index: 2; }
table.pivot-table .stick-d2 { position: sticky; left: 284px; z-index: 2; }
table.pivot-table .stick-d3 { position: sticky; left: 398px; z-index: 2; }
table.pivot-table td[class*="stick-d"] { background: var(--surface-2); }
table.pivot-table th[class*="stick-d"] { background: var(--surface-3); }
/* TTL frozen as the last column */
table.pivot-table th.ttl-col,
table.pivot-table td.ttl-col {
  position: sticky;
  right: 0;
  z-index: 1;
  background: var(--surface-3);
  box-shadow: -1px 0 0 0 var(--gridline);
}

/* compact pager for pivot */
.pager {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 12px;
  font-size: 12px;
  color: var(--text-muted);
}
.pager button {
  font-family: var(--font);
  font-size: 12px;
  font-weight: 500;
  padding: 5px 12px;
  border-radius: var(--radius);
  border: none;
  background: var(--surface-2);
  color: var(--text-primary);
  cursor: pointer;
}
.pager button:hover:not(:disabled) { background: var(--surface-3); }
.pager button:disabled { opacity: 0.5; cursor: default; }
