/* ============================================================================
   KAASS Analytics — styles.css
   Modern financial-BI system (à la LawKPIs, cleaner): navy institutional chrome,
   solid-color KPI stat-tiles, charcoal dense data tables, gauges. KAASS gold is
   kept as the signature accent. Corporate sans, light + dark aware.
   ========================================================================== */
:root {
  --navy: #16304d; --navy-2: #1d3e60; --navy-deep: #0e2338; --navy-ink: #0b1b2c;
  --blue: #2b6cb0; --blue-ink: #1d4e86; --blue-wash: #e7f0f9;
  --gold: #E0A83A; --gold-deep: #b3860f; --gold-wash: #fbf1d4;
  --ink: #16202e; --ink-soft: #4b586b; --slate: #67748a; --faint: #94a1b3;
  --paper: #eef2f7; --card: #ffffff; --card-2: #f4f7fb; --line: #e1e7ef; --line-2: #edf1f6;
  --thead: #2c3a4f; --thead-ink: #eaeff5;
  --good: #2f8f5b; --good-wash: #e4f2ea; --warn: #cf8a2c; --warn-wash: #f8eede;
  --crit: #c24133; --crit-wash: #f7e3df; --teal: #2a8794; --teal-wash: #e2eff1;
  --shadow-sm: 0 1px 2px rgba(16,32,52,.06), 0 2px 8px -4px rgba(16,32,52,.10);
  --shadow: 0 1px 2px rgba(16,32,52,.05), 0 18px 40px -22px rgba(16,32,52,.30);
  --r: 12px; --r-sm: 10px; --r-xs: 7px;
  /* ---- Type scale -------------------------------------------------------
     Seven steps, and nothing in between. Every size on a page should be one of
     these: 13.5 beside 13 beside 12.5 reads as sloppiness, not as hierarchy.
       title   the page heading        base    body copy and table cells
       value   the number a card is    ctl     controls, buttons, small values
               built to show           note    notes, badges, sub-labels
       card    card headings           eyebrow the small caps labels
     -------------------------------------------------------------------- */
  --fs-title: clamp(21px, 2.6vw, 27px);
  --fs-stat: clamp(19px, 1.9vw, 23px); --fs-value: 17px; --fs-card: 13px; --fs-base: 12.5px;
  --fs-ctl: 11.5px; --fs-note: 10.5px; --fs-eyebrow: 9.5px;
  --sans: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --serif: 'Iowan Old Style', 'Palatino Linotype', Georgia, serif;
  --mono: ui-monospace, 'Cascadia Code', 'SF Mono', 'Roboto Mono', Menlo, monospace;
  --c1: #2b6cb0; --c2: #E0A83A; --c3: #2a8794; --c4: #6857b8; --c5: #4a5b73;
  --c6: #cf7a35; --c7: #2f8f5b; --c8: #c24133; --c9: #b3860f; --c10: #3f83b0;
  --c11: #8a6bd0; --c12: #2c8c99;
  --t-navy: #24476b; --t-blue: #2b6cb0; --t-teal: #2a8794; --t-green: #2f8f5b;
  --t-amber: #d7a327; --t-orange: #cf7a35; --t-purple: #6857b8; --t-red: #c24133;
  --t-slate: #47566d; --t-cyan: #2c8c99;
}
:root[data-theme="dark"] {
  --ink: #e8eef6; --ink-soft: #b3c0d1; --slate: #8695ab; --faint: #6b7a90;
  --paper: #0c1622; --card: #14212f; --card-2: #1b2a3b; --line: #26374d; --line-2: #1f2e40;
  --thead: #1c2c40; --thead-ink: #d6e0ec;
  --blue: #4f92d6; --blue-ink: #6aa6e2; --blue-wash: #16283c;
  --gold: #E0A83A; --gold-deep: #e0b23f; --gold-wash: #2b2412;
  --good: #47b07f; --good-wash: #14271d; --warn: #dc9a44; --warn-wash: #2a1f10;
  --crit: #db6653; --crit-wash: #2c1512; --teal: #4fb4bf; --teal-wash: #12282b;
  --shadow-sm: 0 1px 2px rgba(0,0,0,.4), 0 2px 10px -4px rgba(0,0,0,.6);
  --shadow: 0 1px 2px rgba(0,0,0,.4), 0 22px 48px -24px rgba(0,0,0,.8);
  --c1: #4f92d6; --c2: #E0A83A; --c3: #4fb4bf; --c4: #9080dd; --c5: #7f8ca3;
  --c6: #dc9a44; --c7: #47b07f; --c8: #db6653; --c9: #e0b23f; --c10: #6aa6e2;
  --c11: #a58ce8; --c12: #43aab7;
  --t-navy: #274a70; --t-blue: #2f6fb0; --t-teal: #2c8b98; --t-green: #2f9160;
  --t-amber: #c69324; --t-orange: #c8763a; --t-purple: #6a5ac0; --t-red: #bf4638;
  --t-slate: #3d4c63; --t-cyan: #2c8f9c;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ink: #e8eef6; --ink-soft: #b3c0d1; --slate: #8695ab; --faint: #6b7a90;
    --paper: #0c1622; --card: #14212f; --card-2: #1b2a3b; --line: #26374d; --line-2: #1f2e40;
    --thead: #1c2c40; --thead-ink: #d6e0ec; --blue: #4f92d6; --blue-wash: #16283c;
    --good: #47b07f; --good-wash: #14271d; --warn: #dc9a44; --warn-wash: #2a1f10;
    --crit: #db6653; --crit-wash: #2c1512; --teal: #4fb4bf; --teal-wash: #12282b;
    --c1: #4f92d6; --c3: #4fb4bf; --c4: #9080dd; --c5: #7f8ca3; --c7: #47b07f; --c8: #db6653;
  }
}

/* ---- Performance color schemes -------------------------------------------
   Classic (default, no attribute) keeps today's varied dashboard palette.
   The two SIGNAL schemes color every measure by its STATE instead — all good
   measures share one color, middling ones another, bad ones a third — so a
   page reads as a report card at a glance (financial traffic-light idiom).
     Signal      — green good · amber middling · red bad
     Signal Soft — teal good · slate middling · orange bad (colorblind-safe:
                   the teal/orange pair survives red-green blindness).
   The -2 variant is the light end of the stat-tile gradient. */
/* Good-green sits one step deeper than the chart green so white tile type
   clears 4.5:1. */
:root { --perf-good: #28814f; --perf-good-2: #319459; --perf-med: #d7a327; --perf-med-2: #e6b642; --perf-bad: #c24133; --perf-bad-2: #d0503f; }
/* In the Signal scheme the state colors run through the CHARTS too: every
   meaning-carrying token (good/bad/caution, the green–red chart tones, the
   funnel's signed stage, delta chips, badges) maps onto the state palette —
   and the categorical chart palette goes QUIET, a single navy-slate ramp, so
   color only ever appears where it is a verdict. "Who logs the leads" turns
   monochrome on purpose: people are not good or bad, numbers are. */
:root[data-scheme="signal"] {
  --good: var(--perf-good); --crit: var(--perf-bad); --warn: var(--perf-med);
  --t-green: var(--perf-good); --t-red: var(--perf-bad);
  --t-amber: var(--perf-med); --t-orange: var(--perf-bad);
  --good-wash: color-mix(in srgb, var(--perf-good) 14%, var(--card));
  --crit-wash: color-mix(in srgb, var(--perf-bad) 13%, var(--card));
  --warn-wash: color-mix(in srgb, var(--perf-med) 15%, var(--card));
  --c1: #3e5c7d; --c2: #6a7f97; --c3: #52708f; --c4: #8195aa; --c5: #2e4a66;
  --c6: #97a7b8; --c7: #46648a; --c8: #5d7793; --c9: #7c90a5; --c10: #35516f;
  --c11: #8ea0b2; --c12: #4a6884;
}

/* ---- Verdant — the firm's green-ledger ramp, applied to the WHOLE system.
   One sequential palette (deep teal-navy through emerald to gold) carries the
   sidebar, the chips, the table heads, the KPI tiles and every chart. Losses
   keep red — no ramp makes a loss look healthy. */
:root[data-scheme="verdant"] {
  --navy: #094752; --navy-2: #064e58; --navy-deep: #05323c; --navy-ink: #03272f;
  --thead: #083d46; --thead-ink: #d5e9e2;
  --gold: #d9c322; --gold-deep: #877712;
  --blue: #00745a; --blue-ink: #045a48;
  --teal: #007a5e;
  --good: #2f8b55;
  --warn: #98860f;
  /* Washes mixed from the hue against the card, so they stay a quiet tint in
     light mode and a deep tint in dark — never a light patch on a dark page. */
  --gold-wash: color-mix(in srgb, #d9c322 18%, var(--card));
  --blue-wash: color-mix(in srgb, #00745a 12%, var(--card));
  --teal-wash: color-mix(in srgb, #007a5e 12%, var(--card));
  --good-wash: color-mix(in srgb, #2f8b55 13%, var(--card));
  --warn-wash: color-mix(in srgb, #98860f 15%, var(--card));
  /* Canvas takes a quiet green-gray a step darker than the stock paper, so
     the page reads mossy rather than pale. Cards stay white for the data. */
  --paper: #e4ebe6; --card-2: #eef4ef; --line: #d8e2da; --line-2: #e4ece5;
  --c1: #05323c; --c2: #c9b427; --c3: #007a5e; --c4: #4f9c53; --c5: #004a51;
  --c6: #7fa23a; --c7: #2f8b55; --c8: #c24133; --c9: #877712; --c10: #00615b;
  --c11: #6d9640; --c12: #094752;
  --t-navy: #05323c; --t-blue: #00615b; --t-teal: #007a5e; --t-green: #2f8b55;
  --t-amber: #a89417; --t-orange: #7fa23a; --t-purple: #004a51; --t-cyan: #007a6c;
  --t-slate: #33565c;
}
/* ---- Model — the analyst's spreadsheet, as a scheme. The idiom every
   finance reader knows from Excel models: white paper, a dark slate title
   band, black tabular figures, GREEN for data series ("computed"), BLUE for
   inputs and assumptions, red only for losses. Color is scarce on purpose —
   in a model, ink is information. */
:root[data-scheme="model"] {
  --navy: #44546a; --navy-2: #4a5b72; --navy-deep: #37455a; --navy-ink: #2b3646;
  --thead: #44546a; --thead-ink: #eef2f7;
  --gold: #9fb1c9; --gold-deep: #51677f;
  --blue: #1f4e9c; --blue-ink: #17407f;
  --teal: #45818e;
  --good: #217346;
  --warn: #bf8f00;
  --crit: #b32318;
  --gold-wash: color-mix(in srgb, #9fb1c9 26%, var(--card));
  --blue-wash: color-mix(in srgb, #1f4e9c 10%, var(--card));
  --teal-wash: color-mix(in srgb, #45818e 11%, var(--card));
  --good-wash: color-mix(in srgb, #217346 11%, var(--card));
  --warn-wash: color-mix(in srgb, #bf8f00 13%, var(--card));
  --crit-wash: color-mix(in srgb, #b32318 10%, var(--card));
  /* Spreadsheet-white canvas; hairline grid rules. */
  --paper: #f2f4f7; --card: #ffffff; --card-2: #f6f8fa; --line: #d6dde5; --line-2: #e6ebf0;
  --c1: #44546a; --c2: #217346; --c3: #1f4e9c; --c4: #7f8b9b; --c5: #2b3646;
  --c6: #bf8f00; --c7: #3a875f; --c8: #b32318; --c9: #8497b0; --c10: #345b8e;
  --c11: #626f80; --c12: #4f8266;
  --t-navy: #44546a; --t-blue: #1f4e9c; --t-teal: #45818e; --t-green: #217346;
  --t-amber: #bf8f00; --t-orange: #c07817; --t-purple: #5a6b84; --t-red: #b32318;
  --t-slate: #626f80; --t-cyan: #45818e;
}
:root[data-scheme="model"] .nav-search { border-color: #55647a; background: #2e3a4c; color: #e8edf4; }
:root[data-scheme="model"] .nav-search::placeholder { color: #93a2b6; }
:root[data-scheme="model"] .nav-chip { border-color: #55647a; background: #3b4759; color: #c2cddc; }
:root[data-scheme="model"] .nav-chip.active { background: var(--gold); color: var(--navy-ink); border-color: transparent; }
:root[data-scheme="model"] .kpi.c-navy { background: linear-gradient(155deg, #51637c, var(--t-navy)); }
:root[data-scheme="model"] .kpi.c-blue { background: linear-gradient(155deg, #2a5eb4, var(--t-blue)); }
:root[data-scheme="model"] .kpi.c-teal { background: linear-gradient(155deg, #52929f, var(--t-teal)); }
:root[data-scheme="model"] .kpi.c-green { background: linear-gradient(155deg, #2b8454, var(--t-green)); }
:root[data-scheme="model"] .kpi.c-slate { background: linear-gradient(155deg, #6f7d8f, var(--t-slate)); }
:root[data-scheme="model"] .kpi.c-purple { background: linear-gradient(155deg, #67788f, var(--t-purple)); }
:root[data-scheme="model"] .kpi.c-cyan { background: linear-gradient(155deg, #52929f, var(--t-cyan)); }
:root[data-scheme="model"] .kpi.c-amber { background: linear-gradient(155deg, #d3a512, var(--t-amber)); }
:root[data-scheme="model"] .kpi.c-orange { background: linear-gradient(155deg, #d18a2b, var(--t-orange)); }
/* The spreadsheet's TABLE grammar. The dark band belongs to the page title,
   never the grid: the column-header row is white, bold ink, set between a
   hairline above and a strong accounting rule below — the Jan/Feb/Mar row.
   No zebra; rows separate on faint hairlines; and the label column is fenced
   from the figures by a vertical rule, the way column B meets the numbers. */
:root[data-scheme="model"] .ka-head th {
  background: var(--card); color: var(--ink); font-weight: 800;
  border-top: 1px solid #2b3646; border-bottom: 2px solid #2b3646;
}
:root[data-scheme="model"] .ka-head th.sortable:hover { background: var(--card-2); color: var(--ink); }
:root[data-scheme="model"] .ka-head th.sorted { background: var(--card-2); color: var(--ink); }
:root[data-scheme="model"] .ka-grip { color: #9aa7b8; }
:root[data-scheme="model"] .ka-sort { color: var(--blue); }
:root[data-scheme="model"] .ka-sort.idle { color: #b3bfcd; }
:root[data-scheme="model"] .ka-head th.sortable:hover .ka-sort.idle { color: var(--slate); }
:root[data-scheme="model"] .ka-sortn { background: var(--blue); color: #fff; }
:root[data-scheme="model"] .ka-head th.drop-l { box-shadow: inset 2px 0 0 var(--blue); }
:root[data-scheme="model"] .ka-head th.drop-r { box-shadow: inset -2px 0 0 var(--blue); }
:root[data-scheme="model"] .ka-t > tbody > tr:nth-child(even) > td { background: transparent; }
:root[data-scheme="model"] .ka-t > tbody > tr:not(.ka-drill) > td:first-child,
:root[data-scheme="model"] .ka-head th:first-child { border-right: 1px solid var(--line); }

/* The few sidebar colors written as fixed navy hexes follow the ramp too. */
:root[data-scheme="verdant"] .nav-search { border-color: #11565f; background: #032b33; color: #e2f2ed; }
:root[data-scheme="verdant"] .nav-search::placeholder { color: #79a4a0; }
:root[data-scheme="verdant"] .nav-chip { border-color: #11565f; background: #07454f; color: #b6d3cd; }
:root[data-scheme="verdant"] .nav-chip.active { background: var(--gold); color: var(--navy-ink); border-color: transparent; }
/* Tile gradients: the hard-coded light ends are navy-family, so give each
   tile a light end from the ramp instead. */
:root[data-scheme="verdant"] .kpi.c-navy { background: linear-gradient(155deg, #0a4c59, var(--t-navy)); }
:root[data-scheme="verdant"] .kpi.c-blue { background: linear-gradient(155deg, #0a746e, var(--t-blue)); }
:root[data-scheme="verdant"] .kpi.c-teal { background: linear-gradient(155deg, #108b6e, var(--t-teal)); }
:root[data-scheme="verdant"] .kpi.c-green { background: linear-gradient(155deg, #3a9c62, var(--t-green)); }
:root[data-scheme="verdant"] .kpi.c-slate { background: linear-gradient(155deg, #41666d, var(--t-slate)); }
:root[data-scheme="verdant"] .kpi.c-purple { background: linear-gradient(155deg, #0a5d68, var(--t-purple)); }
:root[data-scheme="verdant"] .kpi.c-cyan { background: linear-gradient(155deg, #0f8f7e, var(--t-cyan)); }
:root[data-scheme="verdant"] .kpi.c-amber { background: linear-gradient(155deg, #c4ad20, var(--t-amber)); }
/* The ramp's warning tone is a LIGHT yellow-green — white type dies on it
   (≈1.9:1), so these tiles carry dark type like the gold tile does. */
:root[data-scheme="verdant"] .kpi.c-orange { background: linear-gradient(155deg, #93b04a, var(--t-orange)); color: #1f2309; }
:root[data-scheme="verdant"] .kpi.c-orange .kpi-label,
:root[data-scheme="verdant"] .kpi.c-orange .kpi-sub { color: rgba(38, 41, 14, .72); }
:root[data-scheme="verdant"] .kpi.c-orange .kpi-delta.up { background: rgba(38, 41, 14, .16); color: #1f4b32; }
:root[data-scheme="verdant"] .kpi.c-orange .kpi-delta.down { background: rgba(38, 41, 14, .16); color: #6d2119; }

* { box-sizing: border-box; }
html, body { height: 100%; }
/* Hold the scrollbar's gutter whether the page needs one or not. Without it a
   report that grows past the window takes the scrollbar's width off the layout
   the moment it does, and every chart redraws that much narrower — which is
   also how an unrun report ended up a pixel short of the run one. */
html { scrollbar-gutter: stable; }
body {
  margin: 0; font-family: var(--sans); color: var(--ink); background: var(--paper);
  -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility;
  font-size: var(--fs-base); line-height: 1.5; font-variant-numeric: tabular-nums;
}
a { color: inherit; text-decoration: none; }
h1, h2, h3 { margin: 0; }
::selection { background: color-mix(in srgb, var(--blue) 40%, transparent); }

.app { display: grid; grid-template-columns: 252px 1fr; min-height: 100vh; }
.main { min-width: 0; display: flex; flex-direction: column; }

.sidebar {
  position: sticky; top: 0; height: 100vh; overflow-y: auto; padding: 14px 10px;
  background: linear-gradient(185deg, var(--navy-2), var(--navy-deep) 70%);
  border-right: 1px solid var(--navy-deep); display: flex; flex-direction: column; gap: 12px;
  color: #c6d2e2;
}
.side-brand { display: flex; align-items: center; gap: 10px; padding: 4px 8px 6px; }
.seal {
  width: 36px; height: 36px; border-radius: 9px; flex: none;
  background: linear-gradient(160deg, #b31414 6%, #6a0d0d); color: var(--gold);
  display: grid; place-items: center; font-family: var(--serif); font-weight: 700; font-size: 21px;
  box-shadow: inset 0 0 0 1px rgba(224,168,58,.5), 0 4px 12px -4px rgba(0,0,0,.6);
}
.side-brand .wm b { font-size: var(--fs-value); letter-spacing: .2px; display: block; color: #fff; font-weight: 700; }
.side-brand .wm b em { font-style: normal; color: var(--gold); }
.side-brand .wm .sub { font-size: var(--fs-eyebrow); letter-spacing: .2em; text-transform: uppercase; color: #7f92ab; margin-top: 2px; }

.nav-search {
  width: 100%; font: inherit; font-size: var(--fs-base); padding: 8px 11px; border-radius: 8px;
  border: 1px solid #2b466a; background: #0c1c2e; color: #e7eef7;
}
.nav-search::placeholder { color: #6d829c; }
.nav-search:focus { outline: none; border-color: var(--gold); box-shadow: 0 0 0 3px rgba(224,168,58,.18); }
.nav-filters { display: flex; gap: 5px; }
.nav-chip {
  flex: 1; font: inherit; font-size: var(--fs-ctl); font-weight: 600; padding: 6px 8px; border-radius: 7px;
  border: 1px solid #2b466a; background: #12283e; color: #a9bad0; cursor: pointer;
}
.nav-chip:hover { border-color: var(--gold); color: #fff; }
.nav-chip.active { background: var(--gold); color: var(--navy-ink); border-color: transparent; font-weight: 700; }

.nav { display: flex; flex-direction: column; gap: 1px; overflow-y: auto; }
/* Slim, quiet scrollbar in the sidebar's own palette — a thin soft pill on a
   bare track, no arrow buttons, instead of the stock chrome one. */
.nav { scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, .22) transparent; }
.nav-link {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 7px 10px; border-radius: 7px; color: #b9c6d8; font-size: var(--fs-base); cursor: pointer;
  border-left: 2px solid transparent;
}
.nav-link:hover { background: rgba(255,255,255,.05); color: #fff; }
/* Selection reads as a recess cut into the sidebar gradient — darker than the
   panel rather than a second accent colour — with the gold edge doing the
   pointing. The gradient runs #1d3e60 → #0e2338, so this sits below both. */
.nav-link.active {
  background: var(--navy-ink); color: #fff; border-left-color: var(--gold); font-weight: 600;
  box-shadow: inset 0 1px 3px rgba(0,0,0,.4);
}
.nav-link.active .nl-src { background: rgba(255,255,255,.22) !important; color: #fff !important; }
/* Collapsible parent entry grouping sibling reports. */
.nav-parent {
  display: flex; align-items: center; justify-content: space-between; gap: 8px; width: 100%;
  font: inherit; font-size: var(--fs-base); font-weight: 700; text-align: left; cursor: pointer;
  padding: 7px 10px; border-radius: 7px; border: 0; border-left: 2px solid transparent;
  background: none; color: #b9c6d8;
}
.nav-parent:hover { background: rgba(255,255,255,.05); color: #fff; }
.nav-parent.has-active { color: #fff; border-left-color: var(--gold); }
.nav-parent .nl-tags { margin-left: auto; }
.nav-caret { font-size: 9px; flex: none; opacity: .7; transition: transform .15s; transform: rotate(-90deg); }
.nav-parent.open .nav-caret { transform: rotate(0deg); }
.nav-sub { margin: 1px 0 3px 9px; padding-left: 7px; border-left: 1px solid rgba(255,255,255,.13); }
.nav-link.nested { font-size: var(--fs-base); padding: 6px 9px; }
.nl-title { line-height: 1.25; }
.nl-tags { display: flex; align-items: center; gap: 4px; flex: none; }
.nl-src { font-size: var(--fs-eyebrow); font-weight: 800; letter-spacing: .04em; text-transform: uppercase; padding: 2px 6px; border-radius: 999px; flex: none; }
/* One BETA mark across the app — the sidebar wears the same chip as the
   controls do, so "not final yet" always looks the same. Declared with
   .beta-tag further down; only the sidebar-specific bits live here. */
.nl-beta { flex: none; }
.src-grow { background: rgba(224,168,58,.18); color: var(--gold); }
.src-manage { background: rgba(79,180,191,.18); color: #6fd0da; }
.src-both { background: rgba(255,255,255,.14); color: #d6e0ec; }

.topbar {
  position: sticky; top: 0; z-index: 20; display: flex; align-items: center; justify-content: space-between;
  padding: 10px clamp(14px, 3vw, 28px); background: color-mix(in srgb, var(--card) 88%, transparent);
  backdrop-filter: saturate(1.2) blur(9px); border-bottom: 1px solid var(--line);
  /* The table's actions ride here now, so a narrow window drops the right-hand
     cluster onto its own line instead of crushing the report title. */
  flex-wrap: wrap; row-gap: 8px;
}
.tb-left { display: flex; align-items: center; gap: 12px; flex: 1 1 auto; min-width: 0; }
.tb-menu { display: none; background: var(--card); border: 1px solid var(--line); border-radius: 8px; padding: 7px; color: var(--ink); cursor: pointer; }
.tb-menu svg { width: 18px; height: 18px; display: block; }
.tb-eyebrow { font-size: var(--fs-note); font-weight: 800; letter-spacing: .16em; text-transform: uppercase; color: var(--blue); }
.tb-right { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }
/* Columns · CSV · Reset, hoisted out of the report toolbar. Ruled off from the
   standing chrome beside them — they belong to the report on screen, Palette
   and the theme switch belong to the whole app. */
.tb-tools { display: flex; align-items: center; }
.tb-tools:empty { display: none; }
.tb-tools:not(:empty) { padding-right: 12px; border-right: 1px solid var(--line); }
.tb-tools .ka-tt-actions { flex-wrap: nowrap; }
.tb-tools .ka-tbtn { background: var(--card-2); }
.tb-tools .ka-tbtn:hover { background: var(--card); }
/* All palettes behind one dropdown (settingsControl); each menu row previews its
   own gain/loss/trend trio, so they are still compared by eye, not by name. */
.scheme-opt-l { display: inline-flex; align-items: center; gap: 9px; min-width: 0; }
.scheme-dots { display: inline-flex; gap: 4px; flex: none; }
.scheme-dots i { width: 9px; height: 9px; border-radius: 50%; }
/* The report's controls, on their own row across the full width of the bar.
   Inside the bar they are no longer a card — the bar is the surface now, so the
   box, its shadow and its ground all come off and only the controls remain. */
.tb-bar { flex: 1 0 100%; min-width: 0; }
.tb-bar:empty { display: none; }
.tb-bar > .card-tools {
  background: none; border: 0; border-radius: 0; box-shadow: none;
  border-top: 1px solid var(--line); margin-top: 2px;
}
.tb-bar .ka-tt-detached { padding: 8px 0 2px; gap: 8px; }
.tb-bar .ka-search { background: var(--card-2); }
/* The export stamp, reduced to the light that says the data is loaded. The date
   itself is one press away — it is checked occasionally, not read constantly. */
.tb-asof-dot {
  width: 14px; height: 14px; flex: none; padding: 0; cursor: pointer;
  border: 0; border-radius: 50%; background: var(--good);
  box-shadow: 0 0 0 3px var(--good-wash); transition: box-shadow .12s;
}
.tb-asof-dot:hover, .tb-asof-dot:focus-visible { box-shadow: 0 0 0 5px var(--good-wash); outline: 0; }
.ka-asof-pop { padding: 10px 12px 11px; max-width: 300px; }
.ka-asof-pop .asof-date { font-size: var(--fs-card); font-weight: 800; color: var(--ink); margin: 2px 0 4px; }
.ka-asof-pop .asof-note { font-size: var(--fs-note); line-height: 1.5; color: var(--slate); }
/* Search rides the crumb row. It gives up its width first when the bar narrows,
   but never below the point where a typed word is still visible. */
/* The name and its badge hold their line; the search is what gives when the
   bar runs short. */
.tb-crumb { flex: none; white-space: nowrap; }
.tb-search { flex: 0 1 320px; min-width: 0; margin-left: auto; }
.tb-search:empty { display: none; }
.tb-search .ka-search { width: 100%; min-width: 120px; background: var(--card-2); }

.content { padding: clamp(14px, 2.2vw, 24px) clamp(14px, 3vw, 28px) 56px; }
.report { max-width: 1280px; margin: 0 auto; display: flex; flex-direction: column; gap: 16px; }

/* ---- Report banner -------------------------------------------------------
   A notice the report raises about ITSELF, first thing on the page and above
   every number it qualifies. Today it carries one message: the figures below
   are stand-ins, because Clio Grow exports no communications. Deliberately
   loud — a reader who has to hunt for that has already been misled. */
.rep-banner {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 12px 16px; border-radius: var(--r);
  border: 1px solid var(--warn); border-left-width: 5px;
  background: var(--warn-wash);
}
.rep-banner .rb-tag {
  flex: none; margin-top: 1px;
  font-size: var(--fs-eyebrow); font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  padding: 3px 9px; border-radius: 6px; background: var(--warn); color: var(--card);
}
.rep-banner .rb-txt { min-width: 0; font-size: var(--fs-base); line-height: 1.45; color: var(--ink); }
.rep-banner .rb-txt span { color: var(--ink-soft); }
/* Runs on rather than stacking: the headline and the explanation are one
   sentence of warning, not a title with a paragraph under it. A margin, not a
   generated space — pseudo-element content is invisible to anything reading
   the page as text. */
.rep-banner .rb-txt b { font-weight: 800; margin-right: 6px; }

/* ---- Nothing selected ------------------------------------------------------
   The report before it has been run. Deliberately quieter than .rep-banner —
   that one warns about the numbers on screen, this one explains why there are
   none — so it takes the brand gold as a hairline and a dashed edge rather
   than a solid warning rule. */
.rep-idle {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 11px 16px; border-radius: var(--r);
  border: 1px dashed var(--line); border-left: 3px solid var(--gold);
  background: var(--card);
}
.rep-idle .ri-tag {
  flex: none; margin-top: 1px;
  font-size: var(--fs-eyebrow); font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  padding: 3px 9px; border-radius: 6px; background: var(--gold-wash); color: var(--gold-deep);
  white-space: nowrap;
}
.rep-idle .ri-txt { min-width: 0; font-size: var(--fs-base); line-height: 1.45; color: var(--ink); }
.rep-idle .ri-txt b { font-weight: 700; margin-right: 6px; }
.rep-idle .ri-txt span { color: var(--ink-soft); }
/* The empty chart frame: the gridlines a drawn chart sits on and nothing else,
   filling whatever height the layout gave the card — an unrun report should be
   the same shape as a run one, so nothing jumps when the figures arrive. The
   top rule comes from the gradient's first line, so the border skips it. */
.ka-idle {
  position: relative; display: grid; place-items: center;
  height: 100%; min-height: 80px; border-radius: 8px;
  border: 1px solid var(--line); border-top: 0;
  background-image: linear-gradient(to bottom, var(--line) 1px, transparent 1px);
  background-size: 100% 25%;
}
/* Carries the card's own ground so it cuts the rule behind it rather than
   sitting on top of one. */
.ka-idle-t { font-size: var(--fs-base); font-weight: 600; color: var(--faint); background: var(--card); padding: 1px 10px; border-radius: 5px; }
.ka-idle.is-ring { border: 0; background: none; }
.ka-idle.is-ring::before {
  content: ''; position: absolute; width: 160px; height: 160px; border-radius: 50%;
  border: 18px solid var(--line);
}
/* The note holds its line — and its wrap — so a card is the same height unrun
   as run. Hidden rather than emptied: `visibility` keeps the box and takes the
   text out of both the accessibility tree and the selection. */
.is-idle .chart-card .card-note,
.is-idle .chart-card .chart-legend { visibility: hidden; }
/* Every dash the blanked page prints — tiles, list rows, totals, the count —
   sits back from the ink a real figure would carry. */
.is-idle .kpi-value, .is-idle .klv, .is-idle .ka-t tfoot .ka-total td, .is-idle .ka-count b { color: var(--faint); }
.is-idle .kpi .kpi-value { color: inherit; opacity: .6; }

.report-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 12px 20px; flex-wrap: wrap; }
/* Titleless pages: the head survives only as the toolbar's anchor — collapse
   it entirely so it leaves no gap above the controls. */
.report-head:empty { display: none; }
/* Let the text block shrink so the Group By control keeps its place on the
   first row instead of being pushed onto a line of its own. */
.rh-left { flex: 1 1 380px; min-width: 0; }
.rh-right { flex: 0 0 auto; }
.rh-tags { display: flex; align-items: center; gap: 8px; margin-bottom: 7px; }
/* Badge sits inline with the title; blurb and source share the row below. */
.rh-titleline { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* Pulled up under the title — the blurb reads as part of the heading block,
   not as a separate paragraph. */
.rh-meta { display: flex; align-items: baseline; gap: 8px 16px; flex-wrap: wrap; margin-top: 1px; }
.src-badge { font-size: var(--fs-eyebrow); font-weight: 800; letter-spacing: .05em; text-transform: uppercase; padding: 3px 9px; border-radius: 6px; }
.src-badge.src-grow { background: var(--gold-wash); color: var(--gold-deep); }
.src-badge.src-manage { background: var(--teal-wash); color: var(--teal); }
.src-badge.src-both { background: var(--blue-wash); color: var(--blue-ink); }
.asof-pill { font-size: var(--fs-ctl); font-weight: 600; color: var(--slate); background: var(--card-2); border: 1px solid var(--line); padding: 3px 9px; border-radius: 6px; }
.report-title { font-weight: 800; font-size: var(--fs-title); line-height: 1.15; letter-spacing: -.02em; color: var(--ink); }
.report-blurb { color: var(--ink-soft); font-size: var(--fs-base); margin-top: 0; }

.rh-right { display: flex; flex-direction: column; gap: 5px; align-items: flex-end; }
.seg-label { font-size: var(--fs-note); font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--slate); }
.seg { display: inline-flex; background: var(--card-2); border: 1px solid var(--line); border-radius: 9px; padding: 3px; gap: 2px; }
.tg-wrap { display: inline-flex; align-items: center; gap: 7px; padding: 6px 11px; border-radius: 9px; border: 1px solid var(--line); background: var(--card-2); cursor: pointer; font-size: var(--fs-base); font-weight: 600; color: var(--ink-soft); white-space: nowrap; }
.tg-wrap:hover { border-color: var(--blue); color: var(--blue); }
.tg-wrap.on { background: var(--blue-wash); border-color: var(--blue); color: var(--blue-ink); }
.tg-box { width: 14px; height: 14px; accent-color: var(--blue); cursor: pointer; }
/* Chart-scoped controls sit in that chart's own header. */
/* Must be shrinkable, not flex:none — at max-content the three chips are
   wider than the card and pushed the whole page into horizontal scroll. */
.card-ctl { display: flex; align-items: center; gap: 5px; flex: 1 1 auto; min-width: 0; flex-wrap: wrap; justify-content: flex-end; }
.card-ctl .tg-wrap { padding: 3px 7px; font-size: var(--fs-note); gap: 5px; }
.card-ctl .tg-box { width: 13px; height: 13px; }
.ctl-label { font-size: var(--fs-eyebrow); font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--slate); white-space: nowrap; }
/* Card-scoped select buttons (Period · Conversion) */
.ctl-drop {
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; cursor: pointer;
  font: inherit; padding: 4px 9px; border-radius: 8px;
  border: 1px solid var(--line); background: var(--card-2); color: var(--ink-soft);
}
.ctl-drop:hover { border-color: var(--blue); color: var(--blue); }
.ctl-drop-l { font-size: var(--fs-eyebrow); font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--slate); }
.ctl-drop:hover .ctl-drop-l { color: inherit; }
.ctl-drop-v { font-size: var(--fs-ctl); font-weight: 700; color: var(--ink); }
.ctl-drop:hover .ctl-drop-v { color: inherit; }
.ctl-caret { font-style: normal; font-size: 9px; opacity: .65; }
/* Fixed width: the period picker's groups, calendar row and compare list all
   fit in a hand-sized panel instead of growing to their widest line. */
/* ---- The Data control's menu --------------------------------------------
   Wider than a list of choices because it reports as well as offers: which
   export is loaded, over what dates, and what the last import made of the
   file. */
.ka-menu.ka-datamenu { width: 320px; max-width: 94vw; }
.db-now { display: flex; flex-direction: column; gap: 2px; padding: 4px 8px 8px; }
.db-now b { font-size: var(--fs-base); font-weight: 700; color: var(--ink); word-break: break-all; }
.db-now span { font-size: var(--fs-note); color: var(--faint); }
.db-now .db-kind { color: var(--slate); }
/* Generated figures say so in the warning colour. On a public build this is the
   only thing standing between a demo and someone reading invented numbers as
   the firm's own. */
.db-now .db-kind.warn { color: var(--warn); font-weight: 700; }
.db-hint { margin: 2px 8px 6px; font-size: var(--fs-note); color: var(--faint); line-height: 1.35; }
/* What the last attempt made of the file. Tone only on the two outcomes that
   need one — a plain "reading…" says enough on its own. */
.db-note { margin: 4px 8px 6px; padding: 6px 8px; border-radius: 6px; font-size: var(--fs-note); line-height: 1.4; background: var(--card-2); color: var(--ink-soft); }
.db-note.ok { background: var(--good-wash); color: var(--good-ink); }
.db-note.bad { background: var(--crit-wash); color: var(--crit-ink); }
.ka-ctlmenu { padding: 6px; width: 290px; max-width: 92vw; }
.ka-ctlmenu .ka-menu-row.opt {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 10px;
  font: inherit; font-size: var(--fs-base); text-align: left; border: 0; background: none;
  color: var(--ink); padding: 6px 8px; border-radius: 6px; cursor: pointer;
}
.ka-ctlmenu .ka-menu-row.opt:hover { background: var(--card-2); }
.ka-ctlmenu .ka-menu-row.opt.on { background: var(--blue-wash); color: var(--blue-ink); font-weight: 700; }
.ka-ctlmenu .ka-menu-row.opt .ok { font-style: normal; color: var(--blue); font-weight: 800; }
.ka-ctlmenu .ka-menu-row.self { opacity: .65; cursor: default; }
.ka-menu-h.sep { margin-top: 6px; padding-top: 8px; border-top: 1px solid var(--line); }
/* Carrying no title, it is a rule and nothing else — the heading's own padding
   would otherwise leave a band of empty space above the date fields. */
.ka-menu-h.sep:empty { margin-top: 8px; padding: 0; }
.dt-row { display: flex; gap: 8px; padding: 6px 8px 2px; }
.dt-row label { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.dt-row label span { font-size: var(--fs-eyebrow); font-weight: 800; letter-spacing: .05em; text-transform: uppercase; color: var(--slate); }
.dt-row .dt { font: inherit; font-size: var(--fs-ctl); padding: 4px 6px; border-radius: 6px; border: 1px solid var(--line); background: var(--card-2); color: var(--ink); width: 100%; }
.dt-row .dt:focus { outline: none; border-color: var(--blue); }
.dt-quick { display: flex; align-items: center; gap: 10px; padding: 6px 8px 8px; flex-wrap: wrap; }
.dt-quick .apply { margin-left: auto; font-weight: 800; }
.ka-ctlmenu .ka-menu-row.clear { color: var(--crit); justify-content: flex-start; }
/* Period menu: quarter buttons, the year select beside its heading, and the
   still-provisional compare picker. */
/* One row per group: name on the left, its choices behind a select on the
   right. The active group is washed so the current period is visible without
   opening anything. */
.grp-btn {
  width: 100%; display: flex; align-items: center; gap: 8px; padding: 6px 8px; margin-bottom: 1px;
  font: inherit; text-align: left; border: 1px solid transparent; border-radius: 6px;
  background: var(--card-2); color: var(--ink); cursor: pointer;
}
.grp-btn:hover { border-color: var(--line); }
.grp-btn.on { background: var(--blue-wash); }
.grp-btn.open { border-color: var(--blue); }
.grp-l { flex: none; font-size: var(--fs-eyebrow); font-weight: 800; letter-spacing: .07em; text-transform: uppercase; color: var(--slate); min-width: 44px; }
.grp-btn.on .grp-l { color: var(--blue-ink); }
.grp-v { flex: 1; min-width: 0; font-size: var(--fs-ctl); font-weight: 600; color: var(--ink-soft); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.grp-btn.on .grp-v { color: var(--blue-ink); font-weight: 700; }
.grp-btn .ctl-caret { transition: transform .12s; }
.grp-btn.open .ctl-caret { transform: rotate(180deg); }
/* The group's choices, in the menu's own idiom rather than the browser's. */
.grp-panel { padding: 2px 0 4px 8px; margin-left: 8px; border-left: 2px solid var(--line); }
.grp-panel .ka-menu-row.opt { font-size: var(--fs-base); }
.yr-row { display: flex; align-items: center; gap: 8px; padding: 2px 8px 6px; }
.yr-sel { flex: none; font: inherit; font-size: var(--fs-ctl); font-weight: 700; padding: 3px 4px; border-radius: 5px; border: 1px solid var(--line); background: var(--card-2); color: var(--ink); text-transform: none; letter-spacing: 0; cursor: pointer; }
/* Red on purpose — it marks a control whose behaviour is not settled yet. */
.beta-tag, .nl-beta {
  font-size: var(--fs-eyebrow); font-weight: 800; font-style: normal; letter-spacing: .08em; text-transform: uppercase;
  padding: 1px 5px; border-radius: 4px; border: 0;
  background: var(--crit-wash); color: var(--crit); vertical-align: middle;
}
.beta-tag { margin-left: 7px; }
/* Single-day picker, revealed by "Choose the day…". */
/* The weekday profile's own From/To. Indented under the Week group with the
   same neutral rule its choices use — it belongs to that group, not to the
   compare pickers, whose rule is the warning colour. */
.dow-box { padding: 2px 0 4px 8px; margin-left: 8px; border-left: 2px solid var(--line); }
.dow-box .cmp-hint { margin: 4px 8px 2px; }
.day-box { display: flex; align-items: center; gap: 8px; padding: 4px 8px 8px 16px; }
.day-l { flex: none; font-size: var(--fs-eyebrow); font-weight: 800; letter-spacing: .07em; text-transform: uppercase; color: var(--slate); }
.day-box .dt { flex: 1; font: inherit; font-size: var(--fs-ctl); padding: 4px 6px; border-radius: 6px; border: 1px solid var(--blue); background: var(--card); color: var(--ink); }
.cmp-box { border-left: 2px solid var(--crit-wash); margin: 2px 0 4px 10px; padding-left: 4px; max-height: 190px; overflow-y: auto; }
/* The pair picker is a form, not a list of ticks, so it keeps its full height
   and lets the scale buttons sit on one line. */
.dual-box { max-height: none; }
.dual-scale { display: flex; gap: 4px; flex-wrap: wrap; margin: 6px 0 8px; }
.dual-scale .ka-flink.on { background: var(--blue); color: #fff; border-color: var(--blue); }
.dual-row { display: flex; align-items: center; gap: 8px; margin: 0 0 6px; }
.dual-row .day-l { flex: 0 0 52px; }
.dual-row .yr-sel { flex: 1; min-width: 0; }
.cmp-hint { margin: 2px 8px 4px; font-size: var(--fs-note); color: var(--faint); line-height: 1.35; }
.cmp-box .ka-menu-row { font-size: var(--fs-base); }
.dt-quick .apply:disabled { color: var(--faint); cursor: default; text-decoration: none; }
.ka-ctlmenu .mc-lb { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ka-ctlmenu .mc-n { font-size: var(--fs-note); font-weight: 700; color: var(--faint); font-variant-numeric: tabular-nums; flex: none; }
.ka-ctlmenu .ka-fmenu-list { max-height: 300px; overflow-y: auto; padding: 4px 0 0; }
/* A type heading inside a picker: Pending, Hired, Did Not Hire. Sticky so the
   type a status belongs to stays on screen while the list is scrolled — a
   heading that scrolls away leaves the reader guessing again, which is the
   thing the grouping is there to stop. */
.ka-ctlmenu .mc-grp {
  position: sticky; top: 0; z-index: 1;
  display: flex; align-items: center; gap: 8px;
  margin-top: 6px; padding: 5px 8px 4px;
  background: var(--card); border-bottom: 1px solid var(--line);
}
.ka-ctlmenu .mc-grp:first-child { margin-top: 0; }
.ka-ctlmenu .mc-grp-t {
  flex: 1; font-size: var(--fs-eyebrow); font-weight: 800; letter-spacing: .07em;
  text-transform: uppercase; color: var(--slate);
}
/* Indented under its heading, so the nesting is visible and not just implied. */
.ka-ctlmenu .ka-menu-row.in-grp { padding-left: 16px; }
.tg-dot { width: 8px; height: 8px; border-radius: 2px; flex: none; }
.tg-wrap.self { background: var(--card-2); border-style: dashed; color: var(--slate); cursor: default; }
.tg-wrap.self:hover { border-color: var(--line); color: var(--slate); }
.tg-wrap.self .tg-box { cursor: default; }
.seg-btn { font: inherit; font-size: var(--fs-base); font-weight: 600; padding: 6px 13px; border-radius: 7px; border: none; background: none; color: var(--ink-soft); cursor: pointer; }
.seg-btn:hover { color: var(--ink); }
.seg-btn.active { background: var(--blue); color: #fff; box-shadow: var(--shadow-sm); }

.kpi-row { display: grid; gap: 11px; grid-template-columns: repeat(4, 1fr); }
.kpi-row.cols-6 { grid-template-columns: repeat(6, 1fr); }
.kpi-row.cols-5 { grid-template-columns: repeat(5, 1fr); }
.kpi {
  position: relative; border-radius: var(--r-sm); padding: 10px 12px 9px; min-width: 0;
  color: #fff; background: var(--t-navy); box-shadow: 0 10px 22px -14px rgba(16,32,52,.55), inset 0 0 0 1px rgba(255,255,255,.06);
  overflow: hidden;
}
.kpi::after { content: ""; position: absolute; right: -20px; top: -20px; width: 84px; height: 84px; border-radius: 50%; background: rgba(255,255,255,.07); }
.kpi.c-navy { background: linear-gradient(155deg, #2c527a, var(--t-navy)); }
.kpi.c-blue { background: linear-gradient(155deg, #357ec4, var(--t-blue)); }
.kpi.c-teal { background: linear-gradient(155deg, #319aa8, var(--t-teal)); }
.kpi.c-green { background: linear-gradient(155deg, #37a069, var(--t-green)); }
.kpi.c-orange { background: linear-gradient(155deg, #db8940, var(--t-orange)); }
.kpi.c-purple { background: linear-gradient(155deg, #7767c9, var(--t-purple)); }
.kpi.c-red { background: linear-gradient(155deg, #d0503f, var(--t-red)); }
.kpi.c-slate { background: linear-gradient(155deg, #566988, var(--t-slate)); }
.kpi.c-cyan { background: linear-gradient(155deg, #33a0ad, var(--t-cyan)); }
.kpi.c-amber { background: linear-gradient(155deg, #e6b642, var(--t-amber)); color: #2a2410; }
/* State-colored tiles for the Signal schemes. */
.kpi.c-perf-good { background: linear-gradient(155deg, var(--perf-good-2), var(--perf-good)); }
.kpi.c-perf-med { background: linear-gradient(155deg, var(--perf-med-2), var(--perf-med)); }
.kpi.c-perf-bad { background: linear-gradient(155deg, var(--perf-bad-2), var(--perf-bad)); }
/* Signal's middling amber is too light for white type — borrow the dark-text
   treatment the gold tile uses. */
.kpi.c-perf-med { color: #2a2410; }
.kpi.c-perf-med .kpi-label, .kpi.c-perf-med .kpi-sub { color: rgba(42, 36, 16, .72); }
.kpi.c-perf-med .kpi-delta.up { background: rgba(42, 36, 16, .16); color: #1f4b32; }
.kpi.c-perf-med .kpi-delta.down { background: rgba(42, 36, 16, .16); color: #6d2119; }
.kpi-label { position: relative; font-size: var(--fs-note); font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: rgba(255,255,255,.82); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.kpi.c-amber .kpi-label { color: rgba(42,36,16,.72); }
.kpi-line { position: relative; display: flex; align-items: baseline; gap: 7px; margin-top: 3px; flex-wrap: wrap; }
.kpi-value { position: relative; font-weight: 800; font-size: var(--fs-stat); line-height: 1.15; letter-spacing: -.02em; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.kpi-delta { font-size: var(--fs-ctl); font-weight: 800; padding: 1px 6px; border-radius: 999px; letter-spacing: .01em; white-space: nowrap; }
.kpi-delta.up { background: rgba(255,255,255,.20); color: #d8f5e4; }
.kpi-delta.down { background: rgba(0,0,0,.22); color: #ffd9d2; }
.kpi-delta.flat { background: rgba(255,255,255,.16); color: rgba(255,255,255,.9); }
.kpi.c-amber .kpi-delta.up { background: rgba(42,36,16,.16); color: #1f4b32; }
.kpi.c-amber .kpi-delta.down { background: rgba(42,36,16,.16); color: #6d2119; }
.kpi-foot { position: relative; display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: 5px; min-height: 14px; }
.kpi-sub { font-size: var(--fs-note); color: rgba(255,255,255,.8); line-height: 1.25; }
.kpi.c-amber .kpi-sub { color: rgba(42,36,16,.72); }
.kpi-foot .ka-spark { flex: none; }

.gauge-row { display: grid; gap: 11px; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
.gauge-card { background: var(--card); border: 1px solid var(--line); border-radius: var(--r-sm); box-shadow: var(--shadow-sm); padding: 12px 12px 8px; text-align: center; }
.gauge-card .gc-title { font-size: var(--fs-ctl); font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--slate); }
.gauge-card .gc-body { display: grid; place-items: center; }
.gauge-card .gc-foot { font-size: var(--fs-ctl); color: var(--ink-soft); margin-top: 2px; }
/* Hard cap: a lone gauge in an auto-fit row would otherwise take the whole
   width as a single 1fr track and render metres tall. */
.ka-gauge { width: 180px; max-width: 180px; height: auto; }
.gauge-card .gc-body { max-width: 100%; overflow: hidden; }
.ka-gtrack { fill: none; stroke: var(--card-2); }
.ka-gval { fill: var(--ink); font-weight: 800; font-size: 24px; }
.ka-gsub { fill: var(--slate); font-size: var(--fs-note); letter-spacing: .06em; text-transform: uppercase; }
.ka-gtarget { stroke: var(--ink); stroke-width: 2; opacity: .55; }

.card { background: var(--card); border: 1px solid var(--line); border-radius: var(--r); box-shadow: var(--shadow-sm); }
.card-h { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px 12px; padding: 13px 16px 4px; flex-wrap: wrap; }
.card-h h3 { font-size: var(--fs-card); font-weight: 700; color: var(--ink); letter-spacing: -.01em; }
.card-note { display: block; font-family: var(--mono); font-size: var(--fs-note); color: var(--faint); margin-top: 3px; }
.card-note:empty { display: none; }
/* ---- KPI list beside the chart ---- */
.kpi-viz { display: grid; gap: 14px; grid-template-columns: minmax(430px, 1.15fr) minmax(0, 1.2fr); align-items: stretch; }
/* Controls + metric list on the left, breakdown + time series on the right.
   Each side is a stack, so the columns line up at the top and bottom without
   the toolbar being stretched to the height of the card beside it. */
/* Wide enough for the toolbar to hold Report by + Period beside the table's
   buttons, and search beside the filter chips underneath. */
.report-quad { display: grid; gap: 14px; grid-template-columns: minmax(596px, 1.15fr) minmax(0, 1fr); align-items: stretch; }
/* Each side is a stack: a fixed card on top, a chart taking the rest. Both
   stacks stretch to the same height, so the two charts end on one line and the
   space a short toolbar leaves goes to the chart under it, not to a gap. */
.quad-col { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
/* Nothing stretches: a stretched card is a card whose height depends on the
   column, whose height depends on the card — measure one and you have already
   changed the other. Heights are set explicitly by balanceQuad instead. */
.quad-col > * { flex: 0 0 auto; }
.chart-card .chart-body { flex: 1 1 auto; }
/* Below this the left column can only hold its toolbar by starving the chart
   beside it, so the two stack instead. */
@media (max-width: 1180px) { .report-quad { grid-template-columns: 1fr; } }
/* Tight by intent: four rows of a ledger should not take the height of a
   chart. Row padding does the work — the type stays at its usual size. */
.kpi-list { padding: 6px 12px 4px; }
/* Single grid; rows are display:contents so every cell shares one column
   track and the value column lines up on a single vertical axis. */
.kl-grid {
  display: grid; height: 100%;
  /* The value column takes the room the progress bar used to, so the figure
     sits at the right edge of the card and reads as the end of the row. */
  grid-template-columns: minmax(120px, 1fr) max-content;
  column-gap: 12px; align-items: center;
}
/* Metric · Date · Value. The date column takes only what it needs, so the
   measure keeps the room and the figure stays at the right edge. */
.kl-grid.has-date { grid-template-columns: minmax(110px, 1fr) max-content max-content; }
.kl-grid.has-date > *:nth-last-child(-n+3) { border-bottom: 0; }
/* Comparing two periods puts a second date and value on every row. The pair is
   ruled off from the first so the eye reads two blocks rather than four loose
   columns, and the second is tinted to say which side it belongs to. */
.kl-grid.has-dual {
  /* Same shape as every other metric card: the measure column takes the slack
     and the readings sit to the right of it. Content-sizing this column was
     tried and pulled the whole card hard left, which read as a different kind
     of card rather than the standard one carrying a second period. */
  grid-template-columns: minmax(110px, 1fr) max-content max-content max-content max-content;
}
.kl-grid.has-dual > *:nth-last-child(-n+5) { border-bottom: 0; }
/* Air on BOTH sides of the rule, so the two periods read as two blocks with a
   gutter rather than four columns in a row. The air before it is padding on the
   first side's value, not a margin on the second's date — a margin would break
   the row's underline into segments.
   Selected by CLASS, not by position: `.kl-row` is display:contents, so its
   cells are grid items but DOM children of the row. `> *:nth-child(5n+4)` —
   what this was — therefore reached the header span and nothing else, and the
   rule that was meant to divide the two periods never appeared on a single
   data row. `.kl-b` is what actually marks the second side. */
.kl-grid.has-dual .kl-h.al-r:not(.kl-b),
.kl-grid.has-dual .kl-value:not(.kl-b) { padding-right: 10px; }
.kl-grid.has-dual .kl-h.kl-b:not(.al-r),
.kl-grid.has-dual .kl-date.kl-b { border-left: 1px solid var(--line); padding-left: 16px; }
/* The second period ran flush to the card's edge, which left it looking pinned
   there rather than set beside the first. A little room on its right sits it
   off the edge without moving the first period at all: the four columns are
   anchored right, so space added AFTER the last one is the only thing that
   shifts the second block left. */
.kl-grid.has-dual .kl-h.al-r.kl-b,
.kl-grid.has-dual .kl-value.kl-b { padding-right: 14px; }
/* No tint and no second heading colour: both periods are the same kind of
   reading and are shown the same way. Colour here said one side mattered more
   than the other, which is the opposite of what a comparison is for. The rule
   between them is what says where one ends and the other begins. */
/* Same ledger, one measure per column — months down, measures across. */
.km-grid {
  display: grid; height: 100%;
  grid-template-columns: minmax(96px, 1fr) max-content max-content max-content;
  column-gap: 10px; align-items: center;
}
.km-grid > *:nth-last-child(-n+4) { border-bottom: 0; }
.km-grid .klv { font-size: var(--fs-value); }
.kl-row { display: contents; }
/* Typography comes from the shared caps standard below; this is layout only. */
.kl-h { padding-bottom: 4px; border-bottom: 1px solid var(--line); align-self: end; }
.kl-h.al-r { text-align: right; }
.kl-cell { padding: 5px 0; border-bottom: 1px solid var(--line-2); min-width: 0; height: 100%; display: flex; align-items: center; }
/* Seven measures or more: the rows close up rather than the card growing past
   the chart it is read beside. Type size is untouched — only the air goes. */
.kpi-list.dense .kl-cell { padding: 1px 0; }
.kpi-list.dense .kl-i { width: 15px; height: 15px; font-size: 9px; }
.kpi-list.dense .kl-sec { margin: 3px 0 1px; }
.kl-grid:not(.has-date) > *:nth-last-child(-n+2) { border-bottom: 0; }
.kl-metric { gap: 8px; }
.kl-dot { width: 8px; height: 8px; border-radius: 3px; flex: none; background: var(--t-slate); }
/* The Date column. Monospaced so the periods line up down the column, and
   quiet enough that the measure and its figure still lead the row. */
.kl-date { font-family: var(--mono); font-size: var(--fs-note); color: var(--faint); white-space: nowrap; }
.kpi-list.dense .kl-date { font-size: 9.5px; }
.kl-names { min-width: 0; }
/* A row label is supporting text, not a headline — the number beside it is
   what the card exists to show. Same treatment for every row label on the
   page, in the metric card and in the bar boards alike. */
.kl-metric b { display: block; font-size: var(--fs-base); font-weight: 600; color: var(--ink-soft); line-height: 1.25; white-space: nowrap; }
/* Divider inside the list — spans every column so the rows below read as a
   second block rather than more of the same. */
.kl-sec {
  grid-column: 1 / -1; margin-top: 6px; padding: 8px 0 6px; border-bottom: 1px solid var(--line);
  font-size: var(--fs-eyebrow); font-weight: 800; letter-spacing: .07em; text-transform: uppercase; color: var(--slate);
}
.kl-value { justify-content: flex-end; gap: 7px; }
.klv { font-size: var(--fs-value); font-weight: 800; line-height: 1.15; letter-spacing: -.02em; color: var(--ink); font-variant-numeric: tabular-nums; white-space: nowrap; }
/* The "i" that opens a note — sized off the label, not the value, so it reads
   as an annotation rather than a control competing with the number. */
.kl-i {
  width: 14px; height: 14px; flex: none; padding: 0; margin: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--line); border-radius: 999px; background: transparent;
  font-family: var(--serif); font-size: var(--fs-note); font-style: italic; font-weight: 700;
  line-height: 1; color: var(--slate); cursor: pointer;
}
.kl-i:hover { border-color: var(--gold-deep); background: var(--card-2); color: var(--ink); }
.kl-i:focus-visible { outline: 2px solid var(--gold-deep); outline-offset: 1px; }
.kl-delta { font-size: var(--fs-note); font-weight: 800; padding: 1px 5px; border-radius: 999px; white-space: nowrap; }
.kl-delta.up { background: var(--good-wash); color: var(--good); }
.kl-delta.down { background: var(--crit-wash); color: var(--crit); }
.kl-delta.flat { background: var(--line-2); color: var(--slate); }
.kl-none { font-size: var(--fs-note); color: var(--faint); }
/* ---- The note behind an "i" ---- */
.kl-pop { width: 274px; padding: 10px 11px 11px; max-height: none; }
.kl-pop-h { display: flex; align-items: center; gap: 7px; font-size: var(--fs-ctl); font-weight: 800; color: var(--ink); padding-bottom: 7px; margin-bottom: 8px; border-bottom: 1px solid var(--line); }
.kl-pop-p { margin: 0; font-size: var(--fs-note); line-height: 1.45; color: var(--ink-soft); }
.kl-pop-row + .kl-pop-row { margin-top: 9px; padding-top: 9px; border-top: 1px solid var(--line-2); }
.kl-pop-kv { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.kl-pop-k { font-size: var(--fs-eyebrow); font-weight: 800; letter-spacing: .07em; text-transform: uppercase; color: var(--slate); }
.kl-pop-num { font-size: var(--fs-ctl); font-weight: 800; color: var(--ink); font-variant-numeric: tabular-nums; }
/* The live reading that used to sit under the metric name. */
.kl-pop-foot { margin-top: 9px; padding-top: 8px; border-top: 1px dashed var(--line); font-family: var(--mono); font-size: var(--fs-note); line-height: 1.4; color: var(--faint); }
/* Rows — and the note a row's "i" opens — carry the same tones the cards used.
   The dot selector is not scoped to .kl-row so the popover header picks up the
   colour of whichever row was clicked. */
.c-navy .kl-dot { background: var(--t-navy); }
.c-blue .kl-dot { background: var(--t-blue); }
.c-teal .kl-dot { background: var(--t-teal); }
.c-green .kl-dot { background: var(--t-green); }
.c-slate .kl-dot { background: var(--t-slate); }
.c-purple .kl-dot { background: var(--t-purple); }
.c-cyan .kl-dot { background: var(--t-cyan); }
.c-amber .kl-dot { background: var(--t-amber); }
.c-red .kl-dot { background: var(--t-red); }
.c-orange .kl-dot { background: var(--t-orange); }
.c-perf-good .kl-dot { background: var(--perf-good); }
.c-perf-med .kl-dot { background: var(--perf-med); }
.c-perf-bad .kl-dot { background: var(--perf-bad); }
@media (max-width: 980px) { .kpi-viz { grid-template-columns: 1fr; } }

/* ---- The tabbed visuals block ----------------------------------------------
   Tabs sit on the panels they open, in the ordinary tab idiom: the ones that
   are on carry the card's own ground and run into it, the ones that are off
   stay flat and muted. They are checkboxes, so more than one can be on — the
   panel grid below simply gets wider. */
.viz-block { display: flex; flex-direction: column; }
.viz-tabs { display: flex; align-items: flex-end; gap: 4px; flex-wrap: wrap; padding: 0 2px; }
.viz-tab {
  display: inline-flex; align-items: center; gap: 8px; min-width: 0; max-width: 300px;
  padding: 7px 14px 8px; border: 1px solid var(--line); border-bottom: 0;
  border-radius: 10px 10px 0 0; background: var(--card-2); cursor: pointer;
  font-size: var(--fs-ctl); font-weight: 700; color: var(--faint);
  /* Overlap the panel edge so an open tab reads as part of the card below. */
  margin-bottom: -1px;
}
.viz-tab span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The tab lights up as the button it is; the box keeps a ring of its own so
   it still reads as a second, separate control rather than part of the tab. */
.viz-tab:hover { color: var(--blue); border-color: var(--blue); }
.viz-tab:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.viz-tab input:hover { outline: 2px solid var(--blue-wash); outline-offset: 1px; }
.viz-tab.on { background: var(--card); color: var(--ink); padding-bottom: 10px; }
/* Present, named, and plainly not available yet. It keeps its place so the
   reader knows the chart exists and what it is called; the title says which
   setting brings it to life. */
.viz-tab.off { opacity: .45; cursor: not-allowed; }
.viz-tab.off:hover { color: var(--faint); border-color: var(--line); }
.viz-tab.off .viz-add { cursor: not-allowed; }
.viz-tab.off .viz-add:hover { background: none; }
.viz-tab.off input { cursor: not-allowed; }
/* The tick is the tab's own state, so it takes the tab's colour rather than
   the browser's blue. */
.viz-tab input { accent-color: var(--blue); width: 14px; height: 14px; flex: none; cursor: pointer; margin: 0; }
/* The pad around the tick. It reaches back into the tab's own padding, so the
   box sits exactly where it did and only its target grew. */
.viz-add { display: inline-flex; align-items: center; cursor: pointer;
  padding: 8px 7px 9px 14px; margin: -8px -3px -9px -14px; border-radius: 10px 0 0 0; }
.viz-add:hover { background: var(--blue-wash); }
/* The charts' own controls ride the tab bar rather than a card header — a
   picker that says what the whole page counts must not vanish with a card. */
.viz-ctl { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; margin: 0 2px 6px auto; }
.viz-panels { display: grid; gap: 14px; align-items: stretch; }
.viz-panels.cols-1 { grid-template-columns: minmax(0, 1fr); }
.viz-panels.cols-2 { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
/* Four panels go down the page, one to a row, rather than into a 2x2. Two of
   them are ranked charts that run to dozens of columns, and at half width they
   have to start dropping the names off their own bars — the width IS the
   readability. Stacked, every panel is the size it would be on its own; the
   only cost is scrolling, which is what the reader asked for by opening all
   four. Declared rather than left to the grid's default, so it stays true when
   another column count is added. */
.viz-panels.cols-4 { grid-template-columns: minmax(0, 1fr); }
/* Tiles inside a panel size themselves to the panel: six across at full width,
   folding to two or three when the panel is sharing the row. */
.metrics-pack { padding: 12px; display: flex; flex-direction: column; gap: 11px; }
.metrics-pack .kpi-row,
.metrics-pack .kpi-row.cols-5,
.metrics-pack .kpi-row.cols-6 { grid-template-columns: repeat(auto-fit, minmax(146px, 1fr)); }
.kpi-list .gauge-row { margin: 0 12px 12px; }
/* Three panels where the metrics are tiles: the band on top, the two charts
   sharing the row beneath it. */
.viz-panels.stack-3 { grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); }
.viz-panels.stack-3 > :first-child { grid-column: 1 / -1; }
@media (max-width: 900px) { .viz-panels.cols-2 { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 1080px) { .viz-panels.stack-3 { grid-template-columns: minmax(0, 1fr); } }

.viz-row { display: grid; gap: 14px; }
.viz-row.two { grid-template-columns: 1.55fr 1fr; }
.chart-card { display: flex; flex-direction: column; }
/* Charts are sized to read at a glance, not to fill the viewport — the SVG
   scales with card width, so the cap stops it ballooning on wide screens. */
.chart-body { padding: 4px 14px 8px; min-height: 0; }
/* No height cap: a chart is built at the size it is asked for, so capping it
   here would only scale its own text back down. */
.chart-card.is-donut .chart-body .ka-chart { max-height: 132px; }
.chart-card.is-donut.is-compact .chart-body .ka-chart { max-height: 84px; }
.chart-card .card-h { padding: 10px 14px 2px; }
.chart-card .card-h h3 { font-size: var(--fs-card); }
/* One caps standard, shared by the metric-list column heads and any card title
   that opts into caps (chart spec: caps) — so a report page has a single small
   uppercase voice rather than two competing ones. Declared here, after the
   13px chart-card title rule it has to beat at equal specificity. */
.kl-h, .card-h h3.caps { font-size: var(--fs-eyebrow); font-weight: 800; letter-spacing: .07em; text-transform: uppercase; color: var(--slate); }
.ka-refline { stroke-width: 1.5; stroke-dasharray: 5 4; }
/* Current period is still filling — shown faded so it is not read as a drop. */
.ka-bar.partial { opacity: .45; }

/* ---- trend / cardiogram chart ---- */
.ka-trend-wrap { position: relative; }
.ka-trendline { fill: none; stroke-width: 2.2; stroke-linejoin: round; stroke-linecap: round; }
.ka-trend-partial { stroke-dasharray: 4 3; opacity: .6; }
.ka-trenddot { stroke-width: 1.5; }
.ka-trenddot.hollow { fill: var(--card) !important; }
.ka-refpill { opacity: .95; }
.ka-refpill-t { fill: #fff; font-size: var(--fs-eyebrow); font-weight: 800; font-family: var(--sans); }
.ka-trenddot.key { stroke-width: 2.5; }

/* ---- funnel ---- */
.ka-funnel-wrap { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }
/* The funnel keeps a fixed drawing width, so it is the one chart still
   scaled to its box — capped in height so it cannot tower over the
   breakdown beside it. */
.ka-funnel-wrap .ka-chart { flex: 1 1 300px; min-width: 260px; max-height: 260px; }
.ka-funnel-seg { transition: opacity .12s; }
.ka-funnel-seg:hover { opacity: .85; }
.ka-funnel-lost { fill: var(--line-2); }
.ka-funnel-v { font-size: var(--fs-base); font-weight: 800; font-family: var(--sans); font-variant-numeric: tabular-nums; }
.ka-funnel-v.in { fill: #fff; }
.ka-funnel-v.out { fill: var(--ink); }
.ka-funnel-sub { font-size: var(--fs-eyebrow); font-weight: 700; font-family: var(--sans); }
.ka-funnel-sub.in { fill: rgba(255,255,255,.85); }
.ka-funnel-sub.out { fill: var(--slate); }
.ka-fl-step { display: block !important; padding: 1px 0 2px 18px !important; border-bottom: 1px solid var(--line-2); }
.ka-fl-split { display: flex; height: 5px; border-radius: 999px; overflow: hidden; background: var(--line-2); }
.ka-fl-split i.on { background: var(--good); }
.ka-fl-split i.off { background: var(--crit); opacity: .55; }
.ka-fl-txt { display: flex; justify-content: space-between; gap: 8px; margin-top: 1px; }
.ka-fl-txt b { font-size: var(--fs-note); font-weight: 700; font-variant-numeric: tabular-nums; }
.ka-fl-txt b.on { color: var(--good); }
.ka-fl-txt b.off { color: var(--crit); }
.ka-funnel-legend { flex: 1 1 240px; min-width: 220px; list-style: none; display: flex; flex-direction: column; gap: 0; }
.ka-funnel-legend li { display: flex; align-items: center; gap: 9px; padding: 1px 2px; border-bottom: 1px solid var(--line-2); }
.ka-funnel-legend li:last-child { border-bottom: 0; }
.ka-funnel-legend .sw { width: 9px; height: 9px; border-radius: 3px; flex: none; }
.ka-funnel-legend .lb { flex: 1; min-width: 0; }
.ka-funnel-legend .lb b { display: block; font-size: var(--fs-base); font-weight: 700; color: var(--ink); line-height: 1.15; }
.ka-funnel-legend .lb em { display: block; font-style: normal; font-size: var(--fs-note); color: var(--faint); line-height: 1.2; }
.ka-funnel-legend .vl { font-size: var(--fs-card); font-weight: 800; color: var(--ink); font-variant-numeric: tabular-nums; }
.ka-funnel-break { flex: 1 1 260px; min-width: 240px; border-left: 1px solid var(--line); padding-left: 18px; }
.ka-fb-h { font-size: var(--fs-eyebrow); font-weight: 800; letter-spacing: .07em; text-transform: uppercase; color: var(--slate); margin-bottom: 7px; }
.ka-fb-row { display: grid; grid-template-columns: minmax(0, 1fr) 58px max-content; gap: 9px; align-items: center; padding: 4px 0; }
.ka-fb-lb { font-size: var(--fs-ctl); color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ka-fb-bar { position: relative; height: 7px; border-radius: 999px; background: var(--line-2); overflow: hidden; }
.ka-fb-bar i { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 999px; }
.ka-fb-vl { font-size: var(--fs-ctl); font-weight: 700; color: var(--ink-soft); font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Stage label with its "i" beside it; the note keeps its own line below. */
.ka-funnel-legend .lb-t { display: flex; align-items: center; gap: 6px; }
/* The decomposition behind the "i" — same rows the bottom panel used, sized
   so the longest status still fits on one line. */
.ka-funnel-pop { width: 300px; padding: 10px 12px 11px; max-height: none; }
/* Overlay series render at full weight — they are real comparisons, not a
   backdrop. Told apart by colour, which matches their checkbox chip. */
.ka-ghostline { fill: none; stroke-width: 2.2; stroke-linejoin: round; stroke-linecap: round; opacity: .9; }
.ka-ghostdot { opacity: .9; }
.ka-tip i.ghost { color: rgba(255,255,255,.72); font-weight: 600; }
.ka-extremum { font-size: var(--fs-note); font-weight: 800; font-family: var(--sans); font-variant-numeric: tabular-nums; }
.ka-extremum.hi { fill: var(--ink); }
.ka-extremum.lo { fill: var(--slate); }
.ka-hitbox { fill: transparent; }
/* The column under the pointer, lit from behind. */
.ka-barband { fill: var(--ink); opacity: 0; transition: opacity .1s; pointer-events: none; }
.ka-barband.on { opacity: .07; }
.ka-hoverlayer { opacity: 0; transition: opacity .1s; pointer-events: none; }
.ka-hoverlayer.on { opacity: 1; }
.ka-guide { stroke: var(--slate); stroke-width: 1; stroke-dasharray: 3 3; opacity: .55; }
.ka-marker { fill: var(--card); stroke-width: 2.5; }
.ka-tip {
  position: absolute; z-index: 5; pointer-events: none; opacity: 0; transition: opacity .1s;
  transform: translate(-50%, calc(-100% - 12px)); white-space: nowrap;
  background: var(--navy-ink); color: #fff; border-radius: 8px; padding: 6px 9px;
  box-shadow: 0 10px 26px -12px rgba(16,32,52,.7); font-size: var(--fs-ctl); line-height: 1.45;
}
.ka-tip.on { opacity: 1; }
.ka-tip .ka-tip-h { display: block; font-size: var(--fs-eyebrow); font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: rgba(255,255,255,.6); }
.ka-tip b { font-size: 14px; font-weight: 800; }
.ka-tip i { display: block; font-style: normal; font-size: var(--fs-note); font-weight: 600; }
.ka-tip i.up { color: #8fe0b0; }
.ka-tip i.down { color: #ffb3a7; }
.ka-tip i.note { color: rgba(255,255,255,.6); font-weight: 500; }
.ka-reflabel { font-size: var(--fs-note); font-weight: 800; font-family: var(--sans); letter-spacing: .02em; }
.chart-card.is-donut .chart-body { display: grid; place-items: center; }
.chart-legend { display: flex; flex-wrap: wrap; gap: 12px; padding: 0 16px 14px; }
.chart-legend .lg { display: inline-flex; align-items: center; gap: 7px; font-size: var(--fs-ctl); color: var(--ink-soft); }
.chart-legend .lg i { width: 11px; height: 11px; border-radius: 3px; display: inline-block; }

.ka-chart { width: 100%; height: auto; display: block; overflow: visible; }
.ka-grid { stroke: var(--line); stroke-width: 1; }
.ka-axis { fill: var(--faint); font-size: var(--fs-note); font-weight: 500; font-family: var(--sans); }
.ka-bar { transition: opacity .15s; } .ka-bar:hover { opacity: .82; }
.ka-barval { fill: var(--ink); font-size: var(--fs-ctl); font-weight: 700; font-family: var(--sans); font-variant-numeric: tabular-nums; }
.ka-hlabel { fill: var(--ink-soft); font-size: var(--fs-base); font-weight: 600; font-family: var(--sans); }
.ka-htrack { fill: var(--card-2); }
.ka-line { fill: none; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.ka-dot { stroke: var(--card); stroke-width: 1.5; }
.ka-arc { stroke: var(--card); stroke-width: 2; transition: opacity .15s; } .ka-arc:hover { opacity: .85; }
.ka-donut-total { fill: var(--ink); font-weight: 800; font-size: 25px; }
.ka-donut-cap { fill: var(--slate); font-size: var(--fs-note); letter-spacing: .1em; text-transform: uppercase; }
.ka-donut-wrap { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; justify-content: center; }
.ka-donut-wrap .ka-chart { width: 180px; flex: none; }
.ka-legend { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 5px; min-width: 176px; }
.ka-legend li { display: grid; grid-template-columns: 12px 1fr auto; gap: 8px; align-items: center; font-size: var(--fs-base); }
.ka-legend .sw { width: 11px; height: 11px; border-radius: 3px; }
.ka-legend .lb { color: var(--ink-soft); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ka-legend .vl { color: var(--slate); }
.ka-spark { width: 94px; }

.table-card .card-h { padding-bottom: 0; }
.ka-table { display: flex; flex-direction: column; }
.ka-tt { display: flex; align-items: center; gap: 9px; padding: 11px 16px; flex-wrap: wrap; }
/* Toolbar hoisted above the card headline — everything stays on one line. */
.card-tools { background: var(--card-2); border-bottom: 1px solid var(--line); border-radius: var(--r) var(--r) 0 0; }
/* Standing on its own at the top of the page it is a card in its own right. */
.tools-top { border-radius: var(--r); border-bottom: 0; }
/* The column filters, lifted out of the table header and sat beside the search.
   Each is labelled and sized to its content, so they read as a row of chips
   rather than as headless boxes waiting for a column above them. */
.ka-fbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ka-fbar:empty { display: none; }
/* Toolbar filter chips read like the Period control: ONE bordered box holding
   the name, the value and the caret — not a bare label beside a field. */
.ka-fchip {
  display: inline-flex; align-items: center; gap: 6px; padding: 4px 9px;
  border: 1px solid var(--line); border-radius: 8px; background: var(--card); cursor: pointer;
}
.ka-fchip:hover { border-color: var(--blue); }
.ka-fchip:focus-within { border-color: var(--blue); box-shadow: 0 0 0 3px var(--blue-wash); }
/* An active filter washes the whole chip, the way the bare control used to. */
.ka-fchip:has(.ka-fmulti.has) { background: var(--blue-wash); border-color: var(--blue); }
.ka-fchip-l { font-size: var(--fs-eyebrow); font-weight: 800; letter-spacing: .05em; text-transform: uppercase; color: var(--slate); white-space: nowrap; }
.ka-fchip .ka-fmulti { width: auto; min-width: 56px; padding: 0; border: 0; background: none; font-weight: 700; color: var(--ink); }
.ka-fchip .ka-fmulti.has { background: none; border: 0; }
.ka-fchip .ka-fin { width: 96px; padding: 0; border: 0; border-radius: 0; background: none; }
.ka-fchip .ka-fin:focus { outline: none; box-shadow: none; }
/* Inapplicable to the view in force. It holds its place and its width so the
   strip beside it does not shift, and stops reacting to the pointer — a chip
   that vanished would take the knowledge that the filter exists with it. */
.ka-fchip.is-off { opacity: .45; background: var(--card-2); border-style: dashed; }
.ka-fchip.is-off:hover { border-color: var(--line); }
.ka-fchip.is-off:focus-within { border-color: var(--line); box-shadow: none; }
.ka-fchip.is-off .ka-fmulti, .ka-fchip.is-off .ka-fin { color: var(--faint); cursor: not-allowed; }
.ka-fchip.is-off .ka-fcaret { visibility: hidden; }
/* …which leaves the table flush against the top of its card, so the header row
   has to carry the rounded corners the toolbar used to. */
.table-card > .table-mount:first-child .ka-tscroll { border-top: 0; }
.table-card > .table-mount:first-child thead tr:first-child th:first-child { border-top-left-radius: var(--r); }
.table-card > .table-mount:first-child thead tr:first-child th:last-child { border-top-right-radius: var(--r); }
/* Search · filters · actions on one line. The search is capped rather than
   greedy so the filter chips sit next to it; actions stay pinned right, and
   the row wraps instead of scrolling when a report carries many filters. */
.ka-tt-detached { flex-wrap: wrap; padding: 9px 16px; }
.ka-tt-detached .ka-search { flex: 1 1 120px; min-width: 110px; background: var(--card); }
/* In the quad layout the toolbar lives in a narrow column, so the actions have
   to be able to fall onto a second line instead of running past the card. */
.ka-tt-detached .ka-tt-actions { flex-wrap: wrap; flex: 0 1 auto; margin-left: auto; justify-content: flex-end; }
/* Band 1: the report's own controls on the left, the table's buttons on the
   right. Band 2: search and the column filters. */
.ka-tt-r { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; flex: 1 0 100%; min-width: 0; }
.ka-tt-r .ka-tt-actions { margin-left: auto; }
.ka-tt-lead { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; flex: 0 1 auto; }
.ka-tt-lead:empty { display: none; }
.ka-tt-lead .ctl-drop { background: var(--card); }
/* Search and the column filters share a line — both narrow the same rows, and
   the search box has no business hogging a line of its own. */
.ka-tt-detached .ka-fbar { flex: 1 1 auto; min-width: 0; }
.table-card .card-h { padding-top: 12px; }
.ka-search { flex: 1; min-width: 180px; font: inherit; font-size: var(--fs-ctl); padding: 7px 11px; border-radius: 8px; border: 1px solid var(--line); background: var(--card-2); color: var(--ink); }
.ka-search:focus { outline: none; border-color: var(--blue); box-shadow: 0 0 0 3px var(--blue-wash); background: var(--card); }
.ka-tt-actions { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; }
.ka-tbtn { display: inline-flex; align-items: center; gap: 6px; font: inherit; font-size: var(--fs-ctl); font-weight: 600; padding: 6px 10px; border-radius: 8px; border: 1px solid var(--line); background: var(--card); color: var(--ink-soft); cursor: pointer; }
.ka-tbtn:hover { border-color: var(--blue); color: var(--blue); }
.ka-tbtn.on { background: var(--blue); color: #fff; border-color: transparent; }
.ka-tbtn.ghost { padding: 6px 8px; }
.ka-ic svg { width: 15px; height: 15px; display: block; }
/* Refresh + its reset menu read as one control: two buttons sharing a border,
   so the caret is clearly a second action on the same thing. */
.ka-refresh-more .ka-fcaret { font-style: normal; font-size: 9px; opacity: .65; }
.ka-refresh.spin .ka-ic svg { animation: ka-spin .7s ease-in-out; }
@keyframes ka-spin { from { transform: rotate(0); } to { transform: rotate(-360deg); } }
@media (prefers-reduced-motion: reduce) { .ka-refresh.spin .ka-ic svg { animation: none; } }
/* Reset menu: a label with the scope of the reset spelled out beneath it. */
.ka-resetmenu { min-width: 240px; }
.ka-resetmenu .ka-menu-row.opt { width: 100%; border: 0; background: none; font: inherit; text-align: left; color: var(--ink); }
.ka-reset-lab { display: flex; flex-direction: column; gap: 1px; font-weight: 600; }
.ka-reset-sub { font-style: normal; font-size: var(--fs-ctl); font-weight: 500; color: var(--slate); }
.ka-menuwrap { position: relative; }
.ka-menu { position: absolute; right: 0; top: calc(100% + 6px); z-index: 40; background: var(--card); border: 1px solid var(--line); border-radius: 10px; box-shadow: var(--shadow); padding: 8px; min-width: 190px; display: none; max-height: 340px; overflow-y: auto; }
.ka-menu.open { display: block; }
.ka-menu-h { font-size: var(--fs-eyebrow); font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--slate); padding: 4px 8px 6px; }
.ka-menu-row { display: flex; align-items: center; gap: 9px; padding: 5px 8px; border-radius: 6px; font-size: var(--fs-base); cursor: pointer; }
.ka-menu-row:hover { background: var(--card-2); }
.ka-menu-row input { accent-color: var(--blue); }
/* A choice that explains itself: the note wraps under its own label, and the
   checkbox holds the top line rather than floating beside a two-line block. */
.ka-menu-row.has-note { align-items: flex-start; padding: 6px 8px; }
.ka-menu-row.has-note input { margin-top: 3px; flex: 0 0 auto; }
.ka-menu-row.has-note > span { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.ka-opt-note { font-size: var(--fs-note); color: var(--faint); line-height: 1.35; white-space: normal; }
.ka-fmenu .ka-menu-row.has-note { max-width: 320px; }

/* ---- Drill-down --------------------------------------------------------
   Levels open in place, under the row that owns them. The nested block is
   inset and rests on a tinted ground so depth is read from the indent and the
   ground, not from a second window. Each level keeps its own columns. */
.ka-twisty {
  width: 15px; height: 15px; flex: none; margin-right: 7px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center; vertical-align: -2px;
  border: 1px solid var(--line); border-radius: 5px; background: var(--card);
  font: inherit; font-size: var(--fs-eyebrow); line-height: 1; color: var(--slate); cursor: pointer;
  transition: transform .12s;
}
.ka-twisty:hover { border-color: var(--blue); color: var(--blue); }
.ka-twisty.open { transform: rotate(90deg); border-color: var(--blue); color: var(--blue); background: var(--blue-wash); }
tr.drillable { cursor: pointer; }
/* Nested tables mark their own hovered row, and only that row. */
.ka-subt > tbody > tr:not(.ka-drill):hover > td { background: color-mix(in srgb, var(--blue-wash) 60%, transparent); border-bottom-color: var(--line); }
/* Scoped past `.ka-t td`'s own padding, which would otherwise flatten the
   indent that carries the hierarchy. */
.ka-t tr.ka-drill > td { padding: 0 0 0 40px; background: var(--card-2); border-bottom: 1px solid var(--line); }
/* One hue, deepening a step per level: the ground itself says how deep you
   are, so the reader never has to trace an indent back up to find out. */
/* Size containment, so a level's own columns can never widen the table above
   it. The block sits in a td that spans every column, so without this its
   declared widths feed back into the parent's auto layout: align the levels to
   the parent, the parent shifts a few pixels to fit them, and they no longer
   line up with what they were measured against. */
.ka-sub { border-left: 2px solid var(--blue); padding: 8px 10px 10px; background: var(--card); contain: inline-size; }
.ka-sub.lvl2 { background: color-mix(in srgb, var(--blue-wash) 40%, var(--card)); }
.ka-sub.lvl3 { background: color-mix(in srgb, var(--blue-wash) 85%, var(--card)); border-left-color: var(--blue-ink); }
/* Fixed layout on declared widths: the columns sit side by side at a readable
   distance instead of being stretched across the page, every block at a level
   shares one grid because the widths are absolute, and the filler column runs
   the block out to the edge. */
.ka-subt { table-layout: fixed; width: 100%; }
.ka-subt th.ka-fill, .ka-subt td.ka-fill { padding: 0; }
.ka-sub-h { display: flex; align-items: baseline; gap: 8px; padding-bottom: 6px; }
/* One heading style at every level — the ground and the indent carry the
   depth, so the label itself should not change from level to level. */
.ka-sub-t { font-size: var(--fs-eyebrow); font-weight: 800; letter-spacing: .07em; text-transform: uppercase; color: var(--blue-ink); }
.ka-sub-empty { font-size: var(--fs-note); color: var(--faint); padding: 2px 0 4px; }
.ka-subt { width: 100%; border-collapse: collapse; }
.ka-subt th {
  font-size: var(--fs-eyebrow); font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--slate);
  padding: 3px 8px; border-bottom: 1px solid var(--line); white-space: nowrap;
  /* A <th> centres by default, which pulls every heading off the column it
     names. Scoped overrides, since `.al-right` alone loses to this rule. */
  text-align: left;
}
.ka-subt th.al-right { text-align: right; }
.ka-subt th.al-center { text-align: center; }
/* A drill header does the same work as the one at the top of the card — sort,
   multi-sort, drag to reorder — so it carries the same marks. Only the colours
   change: these sit on the card's own ground, not on the navy head. */
.ka-subt th { user-select: none; }
.ka-subt th.sortable { cursor: pointer; }
.ka-subt th.sortable:hover { color: var(--ink); }
.ka-subt th.sorted { color: var(--blue-ink); }
.ka-subt .ka-grip { color: var(--faint); }
.ka-subt th:hover .ka-grip { opacity: 1; }
.ka-subt .ka-sort { color: var(--blue-ink); }
.ka-subt .ka-sort.idle { color: color-mix(in srgb, var(--slate) 45%, transparent); }
.ka-subt th.sortable:hover .ka-sort.idle { color: var(--slate); }
.ka-subt .ka-sortn { background: var(--blue-ink); color: var(--card); }
.ka-subt th.drop-l { box-shadow: inset 2px 0 0 var(--blue-ink); }
.ka-subt th.drop-r { box-shadow: inset -2px 0 0 var(--blue-ink); }
.ka-subt th.dragging { opacity: .5; }
.ka-subt td { font-size: var(--fs-base); padding: 5px 8px; color: var(--ink); }
/* Each level's rule is drawn against its OWN ground — `--line-2` disappears on
   the deeper wash, which is what made the third level read as one block. */
.ka-sub > .ka-subt > tbody > tr > td { border-bottom: 1px solid var(--line); }
.ka-sub.lvl3 > .ka-subt > tbody > tr > td { border-bottom-color: color-mix(in srgb, var(--blue-ink) 30%, transparent); }
.ka-subt > tbody > tr:last-child > td { border-bottom: 0; }
/* A third level indents again off the second, so the two never read as one. */
.ka-subt tr.ka-drill > td { padding: 0 0 0 34px; background: var(--card-2); }
.ka-subt td { overflow: hidden; text-overflow: ellipsis; }
.ka-tscroll { overflow-x: auto; border-top: 1px solid var(--line); }
/* Fixed layout, no declared widths: the columns divide the table's width evenly
   between them. Auto layout sizes each one to whatever its rows happen to hold,
   which leaves the gaps between columns all different and the right-hand ones
   stranded against the edge. A column that declares its own width still gets
   it, and the rest share what is left — equally. */
.ka-t { width: 100%; table-layout: fixed; border-collapse: collapse; font-size: var(--fs-base); }
/* Fixed layout will not grow a cell to fit, so a long word has to be allowed to
   break rather than run out under its neighbour. */
.ka-t td, .ka-t th { overflow-wrap: anywhere; }
.ka-t thead th { position: sticky; top: 0; z-index: 2; }
.ka-head th {
  background: var(--thead); color: var(--thead-ink); font-weight: 600; font-size: var(--fs-ctl); letter-spacing: .02em;
  text-align: left; padding: 8px 11px; border-bottom: 1px solid var(--navy-deep); white-space: nowrap; user-select: none;
}
.ka-head th.sortable { cursor: pointer; } .ka-head th.sortable:hover { color: #fff; background: #35455c; }
.ka-head th.sorted { color: #fff; background: #3a4c66; }
.ka-head th.al-right { text-align: right; } .ka-head th.al-center { text-align: center; }
.ka-grip { cursor: grab; color: rgba(255,255,255,.4); font-size: 10px; margin-right: 5px; opacity: 0; transition: opacity .12s; }
.ka-head th:hover .ka-grip { opacity: 1; }
.ka-sort { margin-left: 5px; font-size: 9px; color: var(--gold); display: inline-flex; align-items: center; gap: 2px; }
/* Idle affordance so every sortable column advertises that it sorts. */
.ka-sort.idle { color: rgba(234, 239, 245, .42); font-size: 10px; }
.ka-head th.sortable:hover .ka-sort.idle { color: rgba(234, 239, 245, .85); }
.ka-sortn { font-style: normal; font-size: 8px; background: var(--gold); color: var(--navy-ink); border-radius: 3px; padding: 0 3px; }
.ka-head th.drop-l { box-shadow: inset 2px 0 0 var(--gold); } .ka-head th.drop-r { box-shadow: inset -2px 0 0 var(--gold); }
.ka-head th.dragging { opacity: .5; }

/* Filter row is pinned above the column-label row. --ka-fh is the measured
   filter-row height, set by table.js; the fallbacks keep it right pre-measure. */
.ka-t thead tr.ka-filters th { background: var(--card-2); padding: 7px 9px; border-bottom: 1px solid var(--line); position: sticky; top: 0; z-index: 3; }
.ka-t thead tr.ka-head th { top: var(--ka-fh, 43px); z-index: 2; }
.density-compact .ka-t thead tr.ka-head th { top: var(--ka-fh, 39px); }
.ka-table:not(:has(.ka-filters)) .ka-t thead tr.ka-head th { top: 0; }
.ka-fin { width: 100%; font: inherit; font-size: var(--fs-ctl); padding: 5px 7px; border-radius: 6px; border: 1px solid var(--line); background: var(--card-2); color: var(--ink); }
.ka-fin:focus { outline: none; border-color: var(--blue); }

/* Multi-choice checkbox filter (Source, Practice Area, Stage, …) */
.ka-fmulti {
  display: flex; align-items: center; justify-content: space-between; gap: 6px; width: 100%;
  font: inherit; font-size: var(--fs-ctl); padding: 5px 7px; border-radius: 6px;
  border: 1px solid var(--line); background: var(--card-2); color: var(--ink-soft); cursor: pointer; text-align: left;
}
.ka-fmulti:hover { border-color: var(--blue); color: var(--blue); }
.ka-fmulti.has { background: var(--blue-wash); border-color: var(--blue); color: var(--blue-ink); font-weight: 600; }
.ka-fmulti-lab { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ka-fcaret { font-style: normal; font-size: 9px; flex: none; opacity: .7; }
/* .open must be matched here too — `.ka-menu.open { display: block }` carries
   two classes and would otherwise beat a plain `.ka-fmenu` flex declaration. */
.ka-fmenu, .ka-fmenu.open { padding: 0; overflow: hidden; display: flex; flex-direction: column; max-width: 300px; max-height: 340px; }
.ka-fmenu-h { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-bottom: 1px solid var(--line); background: var(--card-2); }
.ka-fmenu-t { flex: 1; font-size: var(--fs-note); font-weight: 800; text-transform: uppercase; letter-spacing: .04em; color: var(--slate); }
.ka-flink { font: inherit; font-size: var(--fs-ctl); font-weight: 600; color: var(--blue); background: none; border: 0; padding: 0 2px; cursor: pointer; }
.ka-flink:hover { text-decoration: underline; }
.ka-fmenu-search { margin: 8px 8px 4px; font: inherit; font-size: var(--fs-ctl); padding: 5px 7px; border-radius: 6px; border: 1px solid var(--line); background: var(--card-2); color: var(--ink); }
.ka-fmenu-search:focus { outline: none; border-color: var(--blue); }
/* min-height:0 is what lets a flex child shrink below its content and scroll —
   without it the list grows and the menu just clips the overflow. */
.ka-fmenu-list { overflow-y: auto; padding: 4px; min-height: 0; flex: 1 1 auto; }
.ka-fmenu-h, .ka-fmenu-search { flex: none; }
.ka-fmenu-empty { padding: 10px; font-size: var(--fs-ctl); color: var(--faint); text-align: center; }

.ka-t tbody td { padding: 7px 11px; font-size: var(--fs-base); border-bottom: 1px solid var(--line-2); color: var(--ink); vertical-align: middle; }
/* Direct children only. A drill row is a single cell spanning the whole nested
   block, and every nested row is also a `tr` inside this tbody — so an
   unscoped rule paints the row, its block, and every ancestor row at once the
   moment the pointer enters the expanded area. */
.ka-t > tbody > tr:nth-child(even) > td { background: color-mix(in srgb, var(--card-2) 55%, transparent); }
/* Light enough that the rule between rows still reads through it, and the
   hovered row's own separator firms up so the grid never dissolves. */
.ka-t > tbody > tr:not(.ka-drill):hover > td { background: color-mix(in srgb, var(--blue-wash) 55%, transparent); border-bottom-color: var(--line); }
.density-compact .ka-t tbody td { padding: 4px 11px; }
.density-compact .ka-head th { padding: 6px 11px; }
.al-right { text-align: right; } .al-center { text-align: center; }
.ka-t td.mono { font-family: var(--mono); font-size: var(--fs-ctl); }
.ka-cell-link { color: var(--blue); font-weight: 600; font-family: var(--mono); font-size: var(--fs-ctl); }
.ka-subcell { display: block; font-size: var(--fs-note); color: var(--faint); }
.txt-good { color: var(--good) !important; font-weight: 600; }
.txt-warn { color: var(--warn) !important; font-weight: 600; }
.txt-crit { color: var(--crit) !important; font-weight: 700; }
/* The search trail, drawn the same at every level. Gold rather than the blue
   the filters use: blue means "you narrowed to this", gold means "what you
   asked for is in here". Two states, one family —
     .ka-hit-deep  the match is another level down; the rule on the left points
                   at the twisty that opens it
     .ka-hit-self  this row is the match; the rule is solid and the text firms
                   up, so the trail visibly ends here. */
.ka-t > tbody > tr.ka-hit-deep > td,
.ka-subt > tbody > tr.ka-hit-deep > td { background: var(--gold-wash); }
.ka-t > tbody > tr.ka-hit-deep > td:first-child,
.ka-subt > tbody > tr.ka-hit-deep > td:first-child { box-shadow: inset 3px 0 0 var(--gold); }
.ka-t > tbody > tr.ka-hit-deep:hover > td,
.ka-subt > tbody > tr.ka-hit-deep:hover > td { background: color-mix(in srgb, var(--gold-wash) 70%, var(--card)); }

.ka-t > tbody > tr.ka-hit-self > td,
.ka-subt > tbody > tr.ka-hit-self > td { background: var(--gold-wash); color: var(--gold-deep); font-weight: 600; }
.ka-t > tbody > tr.ka-hit-self > td:first-child,
.ka-subt > tbody > tr.ka-hit-self > td:first-child { box-shadow: inset 3px 0 0 var(--gold-deep); }
.ka-t > tbody > tr.ka-hit-self:hover > td,
.ka-subt > tbody > tr.ka-hit-self:hover > td { background: color-mix(in srgb, var(--gold-wash) 70%, var(--card)); }
tr.clickable { cursor: pointer; }
.ka-empty { text-align: center; color: var(--faint); padding: 32px 12px !important; font-style: italic; }

.ka-badge { display: inline-block; font-size: var(--fs-note); font-weight: 700; padding: 2px 8px; border-radius: 5px; white-space: nowrap; letter-spacing: .01em; }
.tone-good { background: var(--good-wash); color: var(--good); }
.tone-warn { background: var(--warn-wash); color: var(--warn); }
.tone-crit { background: var(--crit-wash); color: var(--crit); }
.tone-gold { background: var(--gold-wash); color: var(--gold-deep); }
.tone-neutral { background: var(--card-2); color: var(--slate); border: 1px solid var(--line); }

.ka-t tfoot .ka-total td { padding: 8px 11px; border-top: 2px solid var(--line); font-weight: 700; color: var(--ink); background: var(--card-2); position: sticky; bottom: 0; }

.ka-tfoot { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 16px; flex-wrap: wrap; }
.ka-count { font-size: var(--fs-base); color: var(--slate); } .ka-count b { color: var(--ink); }
.ka-filtered { color: var(--gold-deep); }
.ka-foot-right { display: flex; align-items: center; gap: 9px; }
.ka-psize { font: inherit; font-size: var(--fs-base); padding: 6px 8px; border-radius: 7px; border: 1px solid var(--line); background: var(--card); color: var(--ink); }
.ka-pager { display: flex; align-items: center; gap: 3px; }
.ka-pbtn { font: inherit; min-width: 29px; height: 29px; padding: 0 7px; border-radius: 7px; border: 1px solid var(--line); background: var(--card); color: var(--ink-soft); cursor: pointer; }
.ka-pbtn:hover:not([disabled]) { border-color: var(--blue); color: var(--blue); }
.ka-pbtn[disabled] { opacity: .4; cursor: default; }
.ka-pageno { font-size: var(--fs-base); color: var(--ink-soft); padding: 0 8px; }
/* The page numbers sit in the same button as the arrows beside them — one
   control, not a readout wedged between two. The page you are on is filled so
   it reads as where you are rather than somewhere to go. */
.ka-pnum { font-variant-numeric: tabular-nums; }
.ka-pnum.on { background: var(--blue); border-color: transparent; color: #fff; font-weight: 700; }
.ka-pnum.on:hover { border-color: transparent; color: #fff; }
.ka-pgap { color: var(--faint); padding: 0 2px; user-select: none; }

@media (max-width: 1080px) {
  .kpi-row, .kpi-row.cols-6, .kpi-row.cols-5 { grid-template-columns: repeat(3, 1fr); }
  .viz-row.two { grid-template-columns: 1fr; }
}
@media (max-width: 860px) {
  .app { grid-template-columns: 1fr; }
  .sidebar { position: fixed; left: 0; top: 0; width: 262px; z-index: 60; transform: translateX(-100%); transition: transform .2s ease; box-shadow: var(--shadow); }
  .app.nav-open .sidebar { transform: none; }
  .tb-menu { display: grid; place-items: center; }
  .report-head { align-items: flex-start; }
  .rh-right { align-items: flex-start; }
}
/* The header carries the table's actions now, so as it narrows the standing
   chrome gives up its words a step at a time rather than wrapping onto a
   second line the moment a laptop screen is anything short of wide. */
@media (max-width: 1200px) {
  .tb-asof .lbl { display: none; }
}
@media (max-width: 980px) {
  /* Icons only. Each keeps its title, so the name is one hover away. */
  .tb-tools .ka-tbtn { padding: 6px 8px; gap: 0; font-size: 0; }
  .tb-tools .ka-tbtn .ka-ic { font-size: var(--fs-ctl); }
}
@media (max-width: 620px) {
  .kpi-row, .kpi-row.cols-6, .kpi-row.cols-5 { grid-template-columns: repeat(2, 1fr); }
  /* Last to go: the as-of stamp is the one thing up here that is not a control. */
  .tb-asof { display: none; }
}
@media (prefers-reduced-motion: reduce) { * { transition: none !important; } }

/* ---- Sign-in ---------------------------------------------------------------
   The gate in front of the app. The page has no chrome behind it — app.js does
   not mount until this resolves — so this is the whole document while it is up.
   ------------------------------------------------------------------------- */
body.signin-on { overflow: hidden; }
.signin-wrap {
  position: fixed; inset: 0; z-index: 200;
  display: flex; align-items: center; justify-content: center; padding: 24px;
  background: var(--bg);
}
.signin-card {
  width: 100%; max-width: 360px;
  display: flex; flex-direction: column;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r);
  padding: 22px 22px 20px; box-shadow: 0 12px 40px rgba(0, 0, 0, .10);
}
.signin-brand { display: flex; align-items: center; gap: 11px; margin-bottom: 20px; }
/* The same mark the favicon draws, so the page the reader lands on is visibly
   the one they were sent to. */
.signin-mark {
  flex: none; width: 38px; height: 38px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  background: var(--maroon, #A21010); color: var(--gold, #FDC427);
  font-family: Georgia, serif; font-weight: 700; font-size: 23px; line-height: 1;
}
.signin-brand b { display: block; font-size: 15px; font-weight: 800; color: var(--ink); letter-spacing: -.01em; }
/* `> div >` on purpose. Written as `.signin-brand span` this also matched the
   mark beside it — a span too — and at (0,1,1) it outranked `.signin-mark` at
   (0,1,0), so the K came out 10.5px, grey and block-displayed on its own maroon
   tile. It read as a broken image. Only the subtitle inside the text block is
   meant here. */
.signin-brand > div > span { display: block; font-size: var(--fs-note); color: var(--faint); }
.signin-l {
  font-size: var(--fs-eyebrow); font-weight: 800; letter-spacing: .06em;
  text-transform: uppercase; color: var(--slate); margin-bottom: 4px;
}
.signin-in {
  font: inherit; font-size: var(--fs-base); padding: 9px 10px; margin-bottom: 13px;
  border: 1px solid var(--line); border-radius: 8px;
  background: var(--card-2); color: var(--ink);
}
.signin-in:focus { outline: none; border-color: var(--blue); background: var(--card); }
.signin-show {
  display: flex; align-items: center; gap: 7px; margin-bottom: 14px; cursor: pointer;
  font-size: var(--fs-note); color: var(--ink-soft); user-select: none;
}
.signin-show input { cursor: pointer; }
.signin-err {
  margin: 0 0 13px; padding: 8px 10px; border-radius: 7px;
  background: var(--crit-wash); color: var(--crit-ink);
  font-size: var(--fs-note); line-height: 1.4;
}
.signin-go {
  font: inherit; font-size: var(--fs-base); font-weight: 800; cursor: pointer;
  padding: 10px; border: 0; border-radius: 8px;
  background: var(--blue); color: #fff;
}
.signin-go:hover { filter: brightness(1.06); }
.signin-go:disabled { opacity: .65; cursor: default; filter: none; }
