/* SCHRA brand type (Aug 24 2026): Public Sans variable — the govt-credible,
   tabular-figures UI face (SIL OFL; USWDS). One latin-subset woff2, one face,
   swap display; system stack remains the complete fallback. Revert = delete
   this block, the font-family line below, and app/fonts/. */
@font-face {
  font-family: "Public Sans";
  src: url("fonts/PublicSans-var.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* Newsreader (SIL OFL, Production Type via Google Fonts; self-hosted Sep 8
   2026) — the editorial serif for the "in words" sheets only. Variable
   weight + optical size; the italic carries the dateline. */
@font-face { font-family: "Newsreader"; src: url("fonts/Newsreader-var.woff2") format("woff2"); font-weight: 200 800; font-style: normal; font-display: swap; }
@font-face { font-family: "Newsreader"; src: url("fonts/Newsreader-italic-var.woff2") format("woff2"); font-weight: 200 800; font-style: italic; font-display: swap; }

/* Tokens — light default; dark via OS preference or the in-app toggle
   (data-theme wins in both directions, per the reference-palette pattern) */
:root {
  color-scheme: light;
  --page: #f5f5f2;
  --surface: #ffffff;
  --ink: #0b0b0b;
  --ink-2: #52514e;
  /* --muted carries small text (12px foots/notes, 10.5px ticks, "vs prior yr")
     in 45 rules, so it must clear WCAG AA 4.5:1 on its own: #6f6e69 = 4.98:1 on
     --surface, 4.85:1 on --page (the old #898781 was 3.5:1). Dark blocks set
     their own --muted below — they don't inherit this one. (Aug 2026 review) */
  --muted: #6f6e69;
  --hairline: #e1e0d9;
  --border: rgba(11, 11, 11, 0.10);
  --good: #006300;
  --bad: #d03b3b;
  --navy: #324473;           /* SCHRA brand navy (the district-SCHRA guidelines 2022) */
  --navy-ink: #ffffff;
  --chip-ops: #008300;
  --chip-blend: #eda100;
  --chip-fin: #324473;       /* brand navy — the money tone */
  --chip-riders: #4a3aa7;
  --chip-runs: #0e7490;
  --chip-flows: #b45309;
  --chip-cs: #a0407d;        /* community services (Okabe-Ito reddish purple, darkened for light UI) */
  --chip-agency: #b3262c;    /* SCHRA brand gold, darkened for light UI (raw #c49132 fails 3:1 on white) — the Whole-agency tone */
  --chip-ci: #206e5a;        /* Head Start (dept 04) — 5.9:1 on white */
  --chip-eu: #7c5295;        /* Workforce Development (dept 05) — 6.0:1 on white */
  /* Sidebar (Aug 23 2026, Monarch pass): light, on the page canvas, a hairline
     from the content — the department colour is the only colour in it. */
  --side: #fafaf8;
  --side-pop: #ffffff;     /* department-switcher menu */
  --side-ink: #3b3a37;
  --side-ink-strong: #0b0b0b;
  --side-ink-dim: #7a7972;
  --side-line: rgba(11, 11, 11, 0.09);
  --side-hover: rgba(11, 11, 11, 0.045);
  --side-active: #ebebe6;
  --shadow-card: 0 1px 2px rgba(11, 11, 11, 0.04), 0 0 0 1px rgba(11, 11, 11, 0.03);
  /* --accent doubles as link/label text (.ins-link, .jn, .askbtn, .badge):
     #2571cf = 4.71:1 on --surface (was #2a78d6 at 4.30:1). --ord4 keeps the
     original blue — it is a ramp step, never text. */
  --accent: #2571cf;
  --cat2: #eb6834;
  --cat3: #1baf7a;
  /* --cat4 is a data colour (goal lines, event markers, series): #b07600 =
     3.76:1 on --surface, clearing the 3:1 non-text floor (was #eda100 at 2.1:1).
     The bright amber survives as --chip-blend for chip/badge fills only. */
  --cat4: #b07600;
  /* the four transportation services, ucpublictransit.com's colours (John,
     Sep 9 2026): fixed routes = the site's maroon (#572931, its fixed routes headline colour);
     Intercity = the forest green of the Intercity East/Intercity West Intercity schedules (#044330);
     Micro-Transit = the Micro-Transit blue (#007ecb); Demand Response = the agency gold. The raw
     gold (#c29030) is 2.9:1 on white, so the light UI deepens it to #a8781c
     (3.9:1, the 3:1 data-colour floor) and the dark UI runs it raw. */
  --svc-ride: #a8781c;
  --svc-go: #572931;
  --svc-connect: #044330;
  --svc-pickup: #007ecb;
  --ord1: #cfe3f7; --ord2: #9cc4ee; --ord3: #5f9ade; --ord4: #2a78d6; --ord5: #17498f;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --page: #0b0f16;
    --surface: #161a22;
    --ink: #ffffff;
    --ink-2: #c3c2b7;
    /* #898781 was 4.85:1 on --surface — over the line, but with no headroom, so
     every tinted background (delta pills, .rankrow:hover, heat row hover) took
     the small text under AA. #9a988f is 6.02:1 on --surface and holds 5.3:1 on
     the darkest of those tints. (Aug 2026 dark-mode pass) */
  --muted: #9a988f;
    --hairline: #2c2c2a;
    --border: rgba(255, 255, 255, 0.10);
    --good: #0ca30c;
    --bad: #e66767;
    --navy: #4c5f93;           /* brand navy lifted for dark surfaces */
    --chip-fin: #8fa1cc;       /* brand slate (extended palette) — the dark money tone */
  /* .ins-cat renders this as 10px text, and the light purple #4a3aa7 sat at
     2.0:1 on --surface (and 2.3:1 as the .chip square on --page). The other
     four chip tokens are fill-only and clear 3:1 unchanged. (Aug 2026) */
  --chip-riders: #9b8ae0;
  --chip-cs: #d98ac0;
  --chip-agency: #f26b6b;    /* raw brand gold — 6.2:1 on the dark page */
  --chip-ci: #4fc0a0;
  --chip-eu: #b79ae0;
    --side: #10141b;
  --side-pop: #1c2129;
  --side-ink: #cfcec6;
  --side-ink-strong: #ffffff;
  --side-ink-dim: #8f8e86;
  --side-line: rgba(255, 255, 255, 0.10);
  --side-hover: rgba(255, 255, 255, 0.06);
  --side-active: rgba(255, 255, 255, 0.09);
  --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.3);
    --accent: #3987e5;
    --cat2: #d95926;
    --cat3: #199e70;
    --cat4: #c98500;
    --svc-ride: #c29030;     /* raw brand gold, 6.7:1 on the dark page */
    --svc-go: #a35566;       /* maroon lifted for dark surfaces, 3.7:1 */
    --svc-connect: #3a9a72;  /* forest green lifted, 5.5:1 */
    --svc-pickup: #3a9de0;   /* Micro-Transit blue lifted, 6.5:1 */
    --ord1: #2b3c52; --ord2: #2e5480; --ord3: #3470ae; --ord4: #3987e5; --ord5: #8ec0f5;
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --page: #0b0f16;
  --surface: #161a22;
  --ink: #ffffff;
  --ink-2: #c3c2b7;
  /* #898781 was 4.85:1 on --surface — over the line, but with no headroom, so
     every tinted background (delta pills, .rankrow:hover, heat row hover) took
     the small text under AA. #9a988f is 6.02:1 on --surface and holds 5.3:1 on
     the darkest of those tints. (Aug 2026 dark-mode pass) */
  --muted: #9a988f;
  --hairline: #2c2c2a;
  --border: rgba(255, 255, 255, 0.10);
  --good: #0ca30c;
  --bad: #e66767;
  --navy: #4c5f93;           /* brand navy lifted for dark surfaces */
  --chip-fin: #72879e;       /* brand slate (extended palette) — the dark money tone */
  /* .ins-cat renders this as 10px text, and the light purple #4a3aa7 sat at
     2.0:1 on --surface (and 2.3:1 as the .chip square on --page). The other
     four chip tokens are fill-only and clear 3:1 unchanged. (Aug 2026) */
  --chip-riders: #9b8ae0;
  --chip-cs: #d98ac0;
  --chip-agency: #f26b6b;    /* raw brand gold — 6.2:1 on the dark page */
  --chip-ci: #4fc0a0;
  --chip-eu: #b79ae0;
  --side: #10141b;
  --side-pop: #1c2129;
  --side-ink: #cfcec6;
  --side-ink-strong: #ffffff;
  --side-ink-dim: #8f8e86;
  --side-line: rgba(255, 255, 255, 0.10);
  --side-hover: rgba(255, 255, 255, 0.06);
  --side-active: rgba(255, 255, 255, 0.09);
  --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.3);
  --accent: #3987e5;
  --cat2: #d95926;
  --cat3: #199e70;
  --cat4: #c98500;
  --svc-ride: #c29030;     /* raw brand gold, 6.7:1 on the dark page */
  --svc-go: #a35566;       /* maroon lifted for dark surfaces, 3.7:1 */
  --svc-connect: #3a9a72;  /* forest green lifted, 5.5:1 */
  --svc-pickup: #3a9de0;   /* Micro-Transit blue lifted, 6.5:1 */
  --ord1: #2b3c52; --ord2: #2e5480; --ord3: #3470ae; --ord4: #3987e5; --ord5: #8ec0f5;
}

* { box-sizing: border-box; }
body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font-family: "Public Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  -webkit-font-smoothing: antialiased;
}
/* Tabular (fixed-width) figures wherever numbers stack or animate: card values
   and deltas, strip cells, drawer stats, table .num cells, chart ticks. Columns
   of money stop wobbling and CountUp holds its width mid-count. (Aug 2026) */
.card .value, .card .delta, .callout .v, .callout .delta, .strip .cell .v,
.drawer-stats .v, td.num, th.num, .tick, .card .bench, .strip .cell .b {
  font-variant-numeric: tabular-nums;
}

/* ---- shell: sidebar + content ---- */
.shell { display: flex; min-height: 100vh; }
.sidebar {
  width: 232px; flex: none; background: var(--side); color: var(--side-ink);
  border-right: 1px solid var(--side-line);
  display: flex; flex-direction: column; padding: 14px 10px;
  position: sticky; top: 0; height: 100vh;
}
.sidebar .brand { display: flex; align-items: center; justify-content: center; padding: 2px 4px 10px; }
.sidebar .logochip { background: #fff; border: 1px solid var(--side-line); border-radius: 10px; padding: 6px 12px; width: 100%; display: flex; justify-content: center; }
.sidebar .logochip img { display: block; height: 38px; width: auto; max-width: 100%; }
.sidebar nav { display: flex; flex-direction: column; gap: 2px; margin-top: 4px; }
.sidebar a.nav, .sidebar button.nav {
  display: flex; align-items: center; gap: 10px; padding: 6px 10px; border-radius: 8px; position: relative;
  color: var(--side-ink); text-decoration: none; font-size: 13.5px; border: none;
  background: none; cursor: pointer; font-family: inherit; text-align: left; width: 100%;
}
.sidebar a.nav:hover, .sidebar button.nav:hover { background: var(--side-hover); color: var(--side-ink-strong); }
.sidebar a.nav.active { background: var(--side-active); color: var(--side-ink-strong); font-weight: 600; }
.sidebar a.nav.active svg { color: var(--dept); opacity: 1; }
.sidebar a.nav svg, .sidebar button.nav svg { width: 16px; height: 16px; flex: none; opacity: 0.85; }
.sidebar .nav .soon {
  margin-left: auto; font-size: 10px; color: var(--side-ink-dim);
  border: 1px solid var(--side-line); border-radius: 20px; padding: 1px 7px;
}
.sidebar a.nav.disabled { pointer-events: none; color: var(--side-ink-dim); }
.sidebar > .grow { flex: none; min-height: 12px; }
/* The page list scrolls on short screens; the utility buttons and freshness
   note stay pinned at the bottom instead of clipping or overlapping. */
.sidebar nav.main { flex: 1 1 auto; overflow-y: auto; min-height: 0; scrollbar-width: thin;
  scrollbar-color: var(--side-line) transparent; margin-right: -6px; padding-right: 6px; }
.sidebar .sidefoot { display: flex; align-items: center; gap: 4px; }
.sidebar .sidefoot .foot-note { flex: 1; min-width: 0; padding: 4px 6px 2px 10px; }
.sidebar .iconbtn { flex: none; width: 26px; height: 26px; display: grid; place-items: center;
  background: none; border: none; border-radius: 7px; color: var(--side-ink-dim); cursor: pointer; }
.sidebar .iconbtn:hover { background: var(--side-hover); color: var(--side-ink-strong); }
.sidebar .iconbtn svg { width: 15px; height: 15px; }
.sidebar .foot-note { color: var(--side-ink-dim); font-size: 11px; line-height: 1.35; padding: 6px 6px 2px 10px; }

.content { flex: 1; min-width: 0; --dept: var(--accent); }
/* Area tabs (Aug 23 2026, Monarch pass): the pages of a sidebar area as a
   horizontal strip along the top of the content; active = the department
   colour as text + underline. Sticky so the strip stays while a page scrolls. */
.areatabs { position: sticky; top: 0; z-index: 6; background: var(--page); border-bottom: 1px solid var(--hairline); }
.areatabs .inner { max-width: 1080px; margin: 0 auto; padding: 0 24px; display: flex; align-items: center; gap: 10px; position: relative; }
/* the page's 💡 chip rides the strip immediately left of ✦ Ask (Aug 24 2026
   night). The strip must stay one line (its tabs scroll, never wrap), so the
   opened panel can't expand in place the way the appbar's does — instead it
   drops as a full-width sheet under the sticky strip, and the chip itself
   stays a pill. Clicking the pill again (or navigating) closes it. */
.areatabs .inner .takeaways { flex: none; margin: 0; }
.areatabs .inner .takeaways.open { display: inline-block; width: fit-content; border-radius: 999px; border-left-width: 1px; }
.areatabs .inner .takeaways.open .tk-head { padding: 3px 10px 3px 8px; border-radius: 999px; gap: 5px; }
.areatabs .inner .takeaways.open .tk-word { display: none; }
.areatabs .inner .takeaways.open .tk-body {
  position: absolute; top: 100%; left: 24px; right: 24px; margin: 0; z-index: 7;
  background: var(--surface); border: 1px solid var(--border); border-top: none;
  border-left: 3px solid var(--chip-blend); border-radius: 0 0 12px 12px;
  box-shadow: 0 14px 30px rgba(11, 11, 11, 0.16);
  padding: 12px 18px 12px 36px; max-height: 55vh; overflow: auto;
}
/* tabs scroll inside their own box so the ✦ Ask pinned at the strip's right
   edge never scrolls away (Aug 24 2026); the ≤700px fade rides the scroller,
   not the bar, so it sits under the pinned button */
.areatabs .tabscroll { flex: 1 1 auto; min-width: 0; display: flex; gap: 2px; overflow-x: auto; scrollbar-width: none; position: relative; }
/* the routed page's controls (FY picker, scope, view toggles): a slim
   right-aligned row sitting under the strip, first in the page flow — never
   ON the strip, where wide picker sets crushed the tab scroller (.inner
   doesn't wrap). Wraps on narrow screens; scrolls with the page. */
.ctlrow { display: flex; align-items: center; justify-content: flex-end; gap: 10px; flex-wrap: wrap; margin: 0 0 10px; }
.ctlrow select { max-width: 230px; }
.areatabs .inner .askbtn { flex: none; margin: 6px 0; }
.areatabs .tab {
  flex: none; padding: 13px 10px 11px; margin-bottom: -1px; font-size: 14px; color: var(--ink-2);
  text-decoration: none; border-bottom: 2px solid transparent; white-space: nowrap; border-radius: 6px 6px 0 0;
}
.areatabs .tab:hover { color: var(--ink); background: color-mix(in srgb, var(--ink) 4%, transparent); }
/* active text = the tone pulled toward the ink so it clears 4.5:1 in both
   themes (the raw fill tokens are 3:1 marks, not text); the underline is pure tone */
.areatabs .tab.on { color: color-mix(in srgb, var(--dept) 65%, var(--ink)); border-bottom-color: var(--dept); font-weight: 600; }
.areatabs .tab:focus-visible { outline: 2px solid var(--dept); outline-offset: -2px; }
/* 12px top (flush-top pass, Aug 25 2026): first content sits right under the
   strip, the Peers rhythm on every page. .topbar's negative top margin must
   mirror this value. */
.wrap { max-width: 1080px; margin: 0 auto; padding: 12px 24px 64px; }

/* wide-matrix phone strategy (review B-23, first slice): the county/account
   column stays pinned while the months scroll; a right-edge fade says
   "more →" on narrow tab strips. */
.tablewrap .heat td.rowhead, .tablewrap .heat th.rowhead { position: sticky; left: 0; background: var(--surface); z-index: 1; border-right: 1px solid var(--hairline); }
@media (max-width: 700px) {
  .areatabs { position: sticky; }
  .areatabs .tabscroll::after, .periodtabs::after { content: ""; position: absolute; right: 0; top: 0; bottom: 0; width: 26px;
    background: linear-gradient(90deg, transparent, var(--page)); pointer-events: none; }
  .periodtabs { position: relative; }
  /* a segmented control wider than the column scrolls in place */
  .seg { max-width: 100%; overflow-x: auto; }
}
/* wide-table detail columns fold away on phones (review B-23) — the pages
   mark secondary columns .ph-fold and say so in their foot; CSVs carry all */
@media (max-width: 560px) { .ph-fold { display: none; } }
/* the transportation home's four by-month service charts (John, Sep 9
   2026): two side by side, the other two beneath — never four across — and
   one column on a phone */
.svc-quad { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px 22px; margin-top: 16px; }
@media (max-width: 700px) { .svc-quad { grid-template-columns: 1fr; } }

/* Home period tabs (Aug 23 2026): the department homes' time-period pick in
   the same tab language as .areatabs — underline in the department tone. */
.periodtabs { display: flex; gap: 2px; margin: -6px 0 10px; border-bottom: 1px solid var(--hairline); overflow-x: auto; scrollbar-width: none; }
.periodtabs button {
  flex: none; font: inherit; font-size: 14px; color: var(--ink-2); background: none; border: none;
  border-bottom: 2px solid transparent; margin-bottom: -1px; padding: 11px 10px 9px; cursor: pointer;
  white-space: nowrap; border-radius: 6px 6px 0 0;
}
.periodtabs button:hover { color: var(--ink); background: color-mix(in srgb, var(--ink) 4%, transparent); }
.periodtabs button.on { color: color-mix(in srgb, var(--dept, var(--accent)) 65%, var(--ink)); border-bottom-color: var(--dept, var(--accent)); font-weight: 600; }
.periodtabs button:focus-visible { outline: 2px solid var(--dept, var(--accent)); outline-offset: -2px; }
/* One-line top bar, worn as the page's own tab strip (Aug 24 2026 night):
   pages without a shell area strip (the homes, Peers, Insights) render their
   period/mode/category tabs in this row, styled to the exact .areatabs
   geometry — sticky at the top, page background, hairline underneath, the
   active underline riding that hairline — with the page's controls and the
   💡 + ✦ Ask pinned at the right, so the top of every page reads as one
   system. The negative margins lift the row out of .wrap's padding to the
   same gutter .areatabs .inner uses. */
.topbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  position: sticky; top: 0; z-index: 6; background: var(--page);
  border-bottom: 1px solid var(--hairline);
  margin: -12px -24px 12px; padding: 0 24px; min-height: 47px; }
.topbar .periodtabs { flex: none; margin: 0; border-bottom: none; overflow-x: visible; }
.topbar .periodtabs button { padding: 13px 10px 11px; margin-bottom: -1px; }
.topbar .spacer { flex: 1; }
.topbar select { max-width: 180px; }
.topbar .askbtn { flex: none; margin: 6px 0; }
.topbar .takeaways.open { margin: 0 0 10px; }
/* on phones the topbar's tab strip gives up the no-scroll override above and
   scrolls in place like every other narrow tab strip (the 700px block up top
   already gives .periodtabs its right-edge "more →" fade) — the page body
   never scrolls sideways */
@media (max-width: 700px) {
  .topbar .periodtabs { flex: 0 1 auto; min-width: 0; overflow-x: auto; }
}
/* a category tab's open-item count, same pill as the jumpbar's */
.periodtabs .jn {
  font-size: 10.5px; font-weight: 650; color: var(--accent); margin-left: 6px;
  background: color-mix(in srgb, var(--accent) 12%, var(--surface));
  border-radius: 10px; padding: 1px 7px; vertical-align: 1px;
}
/* FY dropdown (Aug 24 2026): the six-tab year bar, folded to one control at
   the top right of every page's control row. */
.fysel { font: inherit; font-size: 13px; font-weight: 600; color: var(--ink);
  background: var(--card); border: 1px solid var(--hairline); border-radius: 8px;
  padding: 5px 8px; cursor: pointer; }
.fysel:hover { border-color: color-mix(in srgb, var(--ink) 25%, var(--hairline)); }
.fysel:focus-visible { outline: 2px solid var(--dept, var(--accent)); outline-offset: 1px; }

/* visually hidden, screen-reader available */
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
/* skip link (review A-34): first tab stop, visible only on focus */
.skiplink { position: fixed; top: 8px; left: 8px; z-index: 100; background: var(--surface); color: var(--ink);
  padding: 8px 14px; border-radius: 8px; border: 1px solid var(--border); transform: translateY(-200%); transition: transform 0.1s; }
.skiplink:focus { transform: none; outline: 2px solid var(--accent); }

/* screen-hidden, print-shown — for headings the screen no longer needs (the
   department picker already names the department) but a printed sheet does */
.printonly { display: none !important; }
@media print { .printonly { display: block !important; } }

/* content header — hugs the top (John, Aug 25 2026: cards and content sit as
   flush with the top of the page as looks right, on every page) */
.appbar { display: flex; align-items: center; gap: 14px; padding: 0 0 8px; margin-top: -6px; flex-wrap: wrap; }
.appbar h1 { font-size: 18px; font-weight: 650; margin: 0; }
.appbar .sub { color: var(--muted); font-size: 13px; }
.appbar .spacer { flex: 1; }
.appbar select {
  font: inherit; font-size: 13px; color: var(--ink);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 8px; padding: 6px 10px;
}

/* segmented FY control */
.seg { display: inline-flex; background: color-mix(in srgb, var(--ink) 6%, var(--page)); border: 1px solid transparent; border-radius: 9px; padding: 3px; gap: 2px; }
.seg button {
  font: inherit; font-size: 13px; padding: 5px 12px; border: none; border-radius: 7px;
  background: none; color: var(--ink-2); cursor: pointer;
}
.seg button.on { background: var(--surface); color: var(--ink); font-weight: 600; box-shadow: 0 1px 2px rgba(11,11,11,0.12); }

/* banners */
/* (Aug 23 2026, Monarch pass: the filled navy/green bar became a heading row —
   sentence case, a square in the section tone, a hairline under it) */
.banner {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  background: none; color: var(--ink); padding: 6px 0 9px; margin: 22px 0 12px;
  border-bottom: 1px solid var(--hairline);
  font-size: 15px; font-weight: 650; letter-spacing: 0;
}
.banner::before { content: ""; width: 10px; height: 10px; border-radius: 3px; background: var(--tone, var(--navy)); flex: none; }

/* sections + cards */
.section { margin: 18px 0 8px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.section .chip { width: 10px; height: 10px; border-radius: 3px; flex: none; }
.section h2 { font-size: 12px; font-weight: 650; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-2); margin: 0; }
.section .note { color: var(--muted); font-size: 12px; margin-left: 6px; }
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 10px; }
.card {
  background: var(--surface); border: 1px solid transparent; box-shadow: var(--shadow-card); border-radius: 12px;
  padding: 13px 15px 12px; min-height: 92px; color: inherit; text-decoration: none;
  display: flex; flex-direction: column; justify-content: space-between;
}
a.card, .card.clickable { cursor: pointer; transition: border-color 0.12s, transform 0.12s; }
a.card:hover, .card.clickable:hover { border-color: var(--accent); transform: translateY(-1px); }
a.card .label::after, .card.clickable .label::after { content: " ›"; color: var(--muted); }
.card .label { font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
.card .value { font-size: 28px; font-weight: 600; letter-spacing: -0.01em; line-height: 1.15; margin: 5px 0 3px; }
/* long figures shrink to stay inside the card — same treatment as the
   year-in-review cells (John, Aug 25 2026: "$10,584,600" spilled its card) */
.card .value.long { font-size: 23px; }
.card .value.xlong { font-size: 18.5px; }
.card .delta { font-size: 12px; color: var(--muted); display: flex; align-items: center; gap: 5px; }
.card .delta .arrow { font-size: 11px; }
.card .delta.good { color: var(--good); }
.card .delta.bad { color: var(--bad); }
.card .delta .vs { color: var(--muted); }
/* mode tag under a service card's label ("demand response" / "fixed route" /
   "commuter route") and the national-context line under the delta — the
   research review's items 2–3: a service is never shown without its mode, and
   a headline unit cost is never shown without its benchmark. */
.card .mode { font-size: 11px; color: var(--muted); margin-top: -1px; }
.card .bench { font-size: 11px; color: var(--muted); line-height: 1.35; margin-top: 5px;
  padding-top: 5px; border-top: 1px dashed var(--hairline); }

.strip { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; margin-top: 10px; }
.strip .cell {
  background: var(--surface); border: 1px solid transparent; box-shadow: var(--shadow-card); border-radius: 10px;
  padding: 8px 12px; display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  flex-wrap: wrap;
}
.strip .cell .k { font-size: 12px; color: var(--ink-2); }
.strip .cell .k .mode { color: var(--muted); font-size: 11px; }
.strip .cell .v { font-size: 15px; font-weight: 600; }
/* second line: the mode's rural benchmark (wraps under label + value) */
.strip .cell .b { flex-basis: 100%; font-size: 11px; color: var(--muted); line-height: 1.3; }

/* ---- trips heatmap ---- */
.callout {
  background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
  padding: 14px 18px; margin: 14px 0; display: flex; align-items: baseline; gap: 18px; flex-wrap: wrap;
}
.callout .big { font-size: 32px; font-weight: 650; }
/* the compact hero callout (trips): leads the page flow flush under the
   strip — kept small since the Aug 25 header-row pass */
.callout.hero, .appbar .callout { margin: 0 0 12px; padding: 7px 14px; gap: 14px; width: fit-content; }
.callout.hero .big, .appbar .callout .big { font-size: 26px; }
.callout .lbl { font-size: 12px; color: var(--ink-2); text-transform: uppercase; letter-spacing: 0.06em; }
.callout .delta { font-size: 13px; color: var(--muted); }
.callout .delta.good { color: var(--good); }
.callout .delta.bad { color: var(--bad); }

.tablewrap { overflow-x: auto; border: 1px solid var(--border); border-radius: 12px; background: var(--surface); }
table.heat { border-collapse: separate; border-spacing: 0; width: 100%; font-size: 12.5px; }
table.heat th, table.heat td { padding: 6px 8px; text-align: right; white-space: nowrap; }
table.heat thead th {
  position: sticky; top: 0; background: var(--surface); color: var(--muted);
  font-weight: 600; font-size: 11px; letter-spacing: 0.04em; border-bottom: 1px solid var(--hairline); z-index: 2;
}
table.heat td.rowhead, table.heat th.rowhead {
  position: sticky; left: 0; background: var(--surface); text-align: left;
  color: var(--ink-2); z-index: 1; min-width: 150px; border-right: 1px solid var(--hairline);
}
table.heat tr.sect td { padding-top: 10px; font-weight: 650; font-size: 11px; letter-spacing: 0.07em;
  text-transform: uppercase; color: var(--muted); text-align: left; }
table.heat tr.total td { font-weight: 650; border-top: 1px solid var(--hairline); }
table.heat td.num { font-variant-numeric: tabular-nums; }
table.heat td.annual { font-weight: 650; border-left: 1px solid var(--hairline); }
/* The heat fills are pale tints in light mode and dark muddy tones in dark
   (heatColor() in trips.js carries its own dark stops), so the cell text has
   to flip with the theme: the hardcoded #0b0b0b left every shaded figure at
   1.1-3.7:1 in dark mode. --ink is #0b0b0b in light (unchanged) and #fff in
   dark, which clears 5.3:1 on the darkest stop. (Aug 2026 dark-mode pass) */
table.heat td.heatcell { color: var(--ink); }
table.heat td.dim { color: var(--muted); }

.hovertip {
  position: fixed; pointer-events: none; z-index: 50; background: var(--ink); color: var(--page);
  border-radius: 8px; padding: 7px 10px; font-size: 12px; line-height: 1.5;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.25); max-width: 240px;
}
.hovertip .k { opacity: 0.7; }
/* The tooltip inverts with the theme (background: var(--ink)), so in dark it
   is a white box and the amber event label dropped to 2.2:1. The dark tooltip
   needs the light-surface amber. (Aug 2026 dark-mode pass) */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .hovertip .ev { color: #8a5a00; }
}
:root[data-theme="dark"] .hovertip .ev { color: #8a5a00; }

/* alerts (status = icon + text, never color alone) */
.alerts { display: flex; gap: 8px; flex-wrap: wrap; margin: 4px 0 2px; }
.pill {
  display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 20px;
  padding: 5px 12px 5px 9px; color: var(--ink-2);
}
.pill .dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.pill.ok .dot { background: #0ca30c; }
.pill.watch .dot { background: #fab219; }
.pill.act .dot { background: #d03b3b; }
.pill.act { border-color: rgba(208, 59, 59, 0.4); }

/* sparkline inside cards */
.card .spark { width: 100%; height: 22px; margin: 2px 0 3px; display: block; }

/* line chart */
.chartbox { background: var(--surface); border: 1px solid transparent; box-shadow: var(--shadow-card); border-radius: 12px; padding: 12px 14px; }
.chartbox .legend { display: flex; gap: 16px; margin: 2px 2px 8px; font-size: 12px; color: var(--ink-2); }
.chartbox .legend .key { display: inline-flex; align-items: center; gap: 6px; }
.chartbox .legend .swatch { width: 14px; height: 3px; border-radius: 2px; display: inline-block; }
/* Breakdown card (Aug 23 2026, Monarch pass) — eyebrow + signed total, a share
   bar, then the legend grid (dot · name / value (share)); rows are the drill */
.eyebrow { font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
.breakdown .bk-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 10px; }
.breakdown .bk-sub { font-size: 13px; color: var(--ink-2); margin-top: 2px; }
.breakdown .bk-total { text-align: right; line-height: 1.1; }
.breakdown .bk-total b { display: block; font-size: 22px; font-weight: 600; letter-spacing: -0.01em; font-variant-numeric: tabular-nums; }
.breakdown .bk-total small { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; }
.breakdown .bk-bar { display: flex; height: 14px; border-radius: 7px; overflow: hidden; gap: 2px; background: var(--hairline); margin: 2px 0 12px; }
.breakdown .bk-bar div { transition: opacity 120ms; min-width: 2px; }
.breakdown .bk-bar div.dim { opacity: 0.35; }
.breakdown .bk-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 2px 14px; }
.breakdown .bk-row { display: flex; align-items: flex-start; gap: 8px; padding: 5px 6px; border-radius: 8px; border: none;
  background: none; color: inherit; font: inherit; text-align: left; cursor: default; width: 100%; }
.breakdown .bk-row.link { cursor: pointer; }
.breakdown .bk-row.on { background: color-mix(in srgb, var(--ink) 5%, transparent); }
.breakdown .bk-row .sw { width: 9px; height: 9px; border-radius: 50%; flex: none; margin-top: 4px; }
.breakdown .bk-row .t { display: flex; flex-direction: column; min-width: 0; }
.breakdown .bk-row .nm { font-size: 12.5px; color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.breakdown .bk-row .nm small { color: var(--muted); }
.breakdown .bk-row .v { font-size: 13.5px; font-weight: 600; font-variant-numeric: tabular-nums; }
.breakdown .bk-row .v .pct { font-weight: 500; color: var(--muted); }
.breakdown .bk-neg { margin-top: 8px; padding-top: 8px; border-top: 1px dashed var(--hairline); font-size: 12px; color: var(--muted); display: flex; flex-wrap: wrap; gap: 4px 16px; }
.breakdown .bk-neg b { color: var(--ink-2); font-weight: 600; }
.linechart { width: 100%; height: auto; display: block; }
/* 10.5 SVG units (was 9.5): the box scales with its column, so ticks in a
   half-width chart render smaller still — the container-scaling fix (review
   item 10) is the real remedy; this is the floor until then. */
.linechart .tick { font-size: 10.5px; fill: var(--muted); }
/* An SVG <text> with no fill paints BLACK. Only .linechart ever set one, so
   every other chart's axis ticks and value labels (BucketBars, the runs and
   riders vizboxes) disappeared on the dark surface. The :not([fill]) guard
   leaves elements that name their own colour alone, and the rule above still
   wins inside .linechart on specificity. (Aug 2026 dark-mode pass) */
svg text:not([fill]) { fill: var(--ink); }

/* plain (non-heatmap) detail tables */
table.heat.plain td { border-bottom: 1px solid var(--hairline); }
table.heat.plain tr.sect td { border-bottom: none; }
table.heat.plain .code { color: var(--muted); font-variant-numeric: tabular-nums; margin-right: 2px; }
table.heat tr.hoverable:hover td { background: color-mix(in srgb, var(--accent) 7%, var(--surface)); }
table.heat tr.net td { border-top: 2px solid var(--ink-2); }

.grid2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(330px, 100%), 1fr)); gap: 14px; margin-top: 8px; }

/* takeaways — collapsed to a chip (💡 + count) by default; open = full panel */
.takeaways {
  background: var(--surface); border: 1px solid var(--border); border-left: 3px solid var(--chip-blend);
  border-radius: 12px; margin: 12px 0 4px;
}
.takeaways:not(.open) { display: inline-block; width: fit-content; border-radius: 999px; border-left-width: 1px; }
.takeaways .tk-head {
  display: flex; align-items: center; gap: 8px; width: 100%; min-width: 0;
  background: none; border: 0; font: inherit; text-align: left; cursor: pointer;
  padding: 10px 18px; border-radius: 12px;
}
.takeaways:not(.open) .tk-head { padding: 3px 10px 3px 8px; border-radius: 999px; gap: 5px; }
.takeaways:not(.open) .tk-word { display: none; }
.takeaways .tk-head:hover { background: color-mix(in srgb, var(--accent) 6%, transparent); }
.takeaways .tk-chev { font-size: 10px; color: var(--accent); flex: none; }
.takeaways .tk-title { font-size: 11px; font-weight: 650; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-2); flex: none; }
.takeaways .tk-count {
  flex: none; font-size: 10.5px; font-weight: 650; color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent); border-radius: 999px; padding: 1px 7px;
}
.takeaways ul { margin: 0; padding: 0 18px 12px 36px; }
.takeaways li { font-size: 13.5px; line-height: 1.55; color: var(--ink); margin: 3px 0; }
/* the chip rides the page's header row, in line with the FY picker, instead of
   its own line (John, Aug 24 2026 pm); opened, the panel wraps to a full-width
   line under the row's controls (.appbar/.topbar are flex-wrap) */
.appbar .takeaways, .topbar .takeaways { margin: 0; }
.appbar .takeaways.open, .topbar .takeaways.open { flex-basis: 100%; order: 99; }
/* threshold alerts as a chip (⚠️ + count) one spot left of 💡 — the same
   collapsed design language, amber-tinted (red when any alert is act-level);
   open = the pills on their own line under the header row (John, Aug 25 2026) */
.takeaways.warn { border-left-color: #fab219; }
.takeaways.warn .tk-count { color: color-mix(in srgb, #fab219 55%, var(--ink)); background: color-mix(in srgb, #fab219 20%, transparent); }
.takeaways.warn .tk-chev { color: color-mix(in srgb, #fab219 55%, var(--ink)); }
.takeaways.warn .tk-head:hover { background: color-mix(in srgb, #fab219 8%, transparent); }
.takeaways.warn.act { border-left-color: #d03b3b; }
.takeaways.warn.act .tk-count { color: color-mix(in srgb, #d03b3b 70%, var(--ink)); background: color-mix(in srgb, #d03b3b 12%, transparent); }
.takeaways.warn.act .tk-chev { color: color-mix(in srgb, #d03b3b 70%, var(--ink)); }
.takeaways.warn .tk-body { padding: 0 14px 10px; }
.takeaways.warn .tk-body .alerts { margin: 0; }
/* plain Cmd+P prints the full panel even when the chip is collapsed on screen */
@media print {
  .takeaways:not(.open) { display: block; width: auto; border-radius: 12px; border-left-width: 3px; }
  .takeaways:not(.open) .tk-head { padding: 10px 18px; border-radius: 12px; }
  .takeaways .tk-body[hidden] { display: block; }
  .takeaways .tk-chev { display: none; }
  .takeaways .tk-word { display: inline; }
  /* in-header chip prints as a full-width panel on its own line */
  .appbar .takeaways, .topbar .takeaways { flex-basis: 100%; order: 99; margin: 0 0 6px; }
}

/* drill-down drawer */
.backdrop { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.35); z-index: 60; }
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 61;
  width: min(500px, 94vw); background: var(--page); border-left: 1px solid var(--border);
  padding: 18px 20px; overflow-y: auto; box-shadow: -12px 0 32px rgba(0, 0, 0, 0.25);
}
.drawer.wide { width: min(820px, 94vw); }
.drawer-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; margin-bottom: 14px; }
.drawer-title { font-size: 16px; font-weight: 650; }
.drawer-sub { font-size: 12px; color: var(--muted); margin-top: 2px; }
.drawer-x { font: inherit; font-size: 14px; border: none; background: none; color: var(--muted); cursor: pointer; padding: 4px 6px; }
.drawer-x:hover { color: var(--ink); }
.drawer-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 14px; margin-bottom: 14px; }
/* Stacked label-over-value, mirroring the KPI cards: side-by-side flex broke
   whenever either span wrapped (labels colliding with values, mashed text). */
.drawer-stats > div {
  background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
  padding: 9px 12px 10px; display: flex; flex-direction: column; gap: 3px; min-width: 0;
}
.drawer-stats > div > span:first-child,
.drawer-stats .k { font-size: 11.5px; color: var(--ink-2); line-height: 1.35; }
.drawer-stats .v { font-size: 15.5px; font-weight: 600; line-height: 1.3; overflow-wrap: anywhere; }
.drawer table.mini { margin-top: 14px; width: 100%; }
td.clickable { cursor: pointer; }
td.clickable:hover { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }
.legend .swatch.bandkey { width: 14px; height: 10px; border-radius: 2px; background: var(--muted); opacity: 0.3; }

/* county map */
.mapgrid { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(230px, 1fr); gap: 14px; align-items: start; }
@media (max-width: 900px) { .mapgrid { grid-template-columns: 1fr; } }
.mapbox { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 10px; }
.countymap { width: 100%; height: auto; display: block; }
.countymap .county { cursor: pointer; transition: opacity 0.1s; }
.countymap .county:hover { opacity: 0.82; stroke: var(--ink); stroke-width: 2; }
.countymap .clabel { font-size: 11px; }
.countymap .clabel tspan:first-child { font-size: 9.5px; opacity: 0.85; }
.ranklist { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 6px; }
.rankrow {
  /* the trailing column grows for longer context strings (fleet drawers) but
     never shrinks below the width that keeps short percentages aligned */
  display: grid; grid-template-columns: 26px 1fr auto minmax(52px, auto); gap: 8px; align-items: baseline;
  padding: 6px 10px; border-radius: 8px; font-size: 13px; cursor: pointer;
}
.rankrow .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rankrow:hover, .rankrow.on { background: color-mix(in srgb, var(--accent) 9%, var(--surface)); }
.rankrow .rk { color: var(--muted); font-size: 11px; }
.rankrow .nm { color: var(--ink); }
.rankrow .vl { font-weight: 600; font-variant-numeric: tabular-nums; }
.rankrow .pc { color: var(--muted); font-size: 11px; text-align: right; font-variant-numeric: tabular-nums; }

.ranklist .rankhead { font-size: 11px; font-weight: 650; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); padding: 8px 10px 4px; }
.profile { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 4px 0; }
.profile .prow { display: flex; justify-content: space-between; gap: 12px; padding: 6px 14px; font-size: 13px; }
.profile .prow:not(:last-child) { border-bottom: 1px solid var(--hairline); }
.profile .k { color: var(--ink-2); }
.profile .v { font-weight: 600; font-variant-numeric: tabular-nums; }

/* county-vs-Tennessee profile: indicator | county | state | ratio. The
   denominator behind each rate rides under its label (evidence rules §14). */
.profile.compare .prow {
  display: grid; grid-template-columns: minmax(0, 1fr) 70px 70px 84px;
  gap: 10px; align-items: baseline;
}
.profile.compare .prow .v, .profile.compare .prow .d { text-align: right; }
.profile.compare .prow .tn { font-weight: 500; color: var(--ink-2); }
.profile .prow .k small {
  display: block; font-size: 10.5px; color: var(--muted); line-height: 1.3; margin-top: 1px;
}
.profile .prow.phead {
  font-size: 10.5px; font-weight: 650; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--muted);
}
/* .profile .k sets its own colour, so the header cells have to say it again */
.profile .prow.phead .k, .profile .prow.phead .v, .profile .prow.phead .d {
  color: var(--muted); font-weight: 650;
}
.profile .prow .d { font-size: 12.5px; font-variant-numeric: tabular-nums; color: var(--muted); }
/* the arrow carries the direction; colour only reinforces it */
.profile .prow .d.hi { color: var(--accent); font-weight: 650; }
.profile .prow .d.lo { color: var(--ink-2); }

/* actionable insights */
.jumpbar { display: flex; gap: 8px; flex-wrap: wrap; margin: 4px 0 18px; }
.jump {
  font: inherit; font-size: 12.5px; color: var(--ink-2); cursor: pointer;
  background: var(--surface); border: 1px solid var(--border); border-radius: 20px;
  padding: 6px 13px; display: inline-flex; align-items: center; gap: 7px;
}
.jump:hover { border-color: var(--accent); color: var(--ink); }
/* the My home quick links reuse the pill as anchors */
a.jump { text-decoration: none; }
.jump .jn {
  font-size: 10.5px; font-weight: 650; color: var(--accent);
  /* mixed against --surface, not transparent: as a transparent tint this
     composited onto whatever the parent painted, and the selected pill paints a
     solid fill — which made the count invisible against itself. (Aug 2026) */
  background: color-mix(in srgb, var(--accent) 12%, var(--surface));
  border-radius: 10px; padding: 1px 7px;
}
/* Selected domain pill. Was an inline background:var(--accent);color:#fff on the
   button, which left the nested count unstyled and put the label at 3.6:1 in
   dark. Navy is what .seg button.on already uses for a selected pill. */
.jump.on { background: var(--navy); border-color: var(--navy); color: #fff; font-weight: 600; }
.jump.on:hover { color: #fff; }
.jump.on .jn { background: rgba(255, 255, 255, 0.9); color: var(--navy); }
.ins-group { margin-bottom: 26px; scroll-margin-top: 14px; }
.ins-group-head { display: flex; align-items: baseline; gap: 10px; margin: 0 0 10px; border-bottom: 1px solid var(--hairline); padding-bottom: 7px; }
.ins-group-head h2 { font-size: 15px; font-weight: 650; margin: 0; }
.ins-group-head .aud { font-size: 12px; color: var(--muted); }
.insights { display: grid; gap: 10px; }
/* Insight cards wear their area's tone via --tone (set inline by InsightCard;
   Aug 27 2026 — the uniform purple list read "blah"). The fallback is the old
   riders purple, so untinted callers (tools.js) look as they always did. The
   wash fades out by ~150px so the card body stays a clean surface; every
   colour mixes THROUGH the theme tokens, so dark mode follows on its own. */
.insight {
  --instone: var(--tone, var(--chip-riders));
  background: linear-gradient(90deg, color-mix(in srgb, var(--instone) 5%, var(--surface)), var(--surface) 150px);
  border: 1px solid var(--border);
  border-left: 3px solid var(--instone); border-radius: 12px; padding: 13px 18px;
  transition: border-color 0.12s, box-shadow 0.12s;
}
.insight:hover {
  border-color: color-mix(in srgb, var(--instone) 40%, var(--border));
  box-shadow: 0 2px 10px -6px color-mix(in srgb, var(--instone) 45%, transparent);
}
.ins-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 5px; }
.ins-cat {
  font-size: 10px; font-weight: 650; letter-spacing: 0.07em; text-transform: uppercase;
  /* filled tint, no outline — text pulled toward ink so 10px type keeps
     contrast on the tint in both themes (amber and gold tones especially) */
  color: color-mix(in srgb, var(--instone) 55%, var(--ink));
  background: color-mix(in srgb, var(--instone) 11%, transparent);
  border-radius: 7px; padding: 3px 9px; flex: none;
}
.ins-title { font-size: 14.5px; font-weight: 650; }
/* insight cards open on the headline (Aug 24 2026): the title is the toggle */
.ins-toggle {
  display: inline-flex; align-items: baseline; gap: 6px; min-width: 0;
  background: none; border: 0; padding: 0; font: inherit; text-align: left; cursor: pointer;
}
.ins-toggle:hover .ins-title { color: var(--accent); }
.ins-toggle:hover .ins-chev { transform: translateX(2px); }
.ins-chev { font-size: 10px; color: color-mix(in srgb, var(--instone) 70%, var(--ink)); flex: none; transition: transform 0.12s; display: inline-block; }
/* plain Cmd+P prints every card's numbers even when collapsed on screen */
@media print {
  .ins-more[hidden] { display: block; }
  .ins-chev { display: none; }
}
.ins-link { margin-left: auto; font-size: 12px; color: var(--accent); text-decoration: none; flex: none; }
.ins-link:hover { text-decoration: underline; text-underline-offset: 3px; }
.ins-body { font-size: 13.5px; line-height: 1.55; color: var(--ink-2); }
.ins-rec { font-size: 13.5px; line-height: 1.5; margin-top: 7px; color: var(--ink); }
.ins-rec span {
  font-size: 10px; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--good); margin-right: 7px;
}

/* events */
.eventform { display: grid; grid-template-columns: 150px 1.2fr 1.6fr auto; gap: 8px; }
@media (max-width: 800px) { .eventform { grid-template-columns: 1fr; } }
.eventform input {
  font: inherit; font-size: 13px; padding: 8px 10px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--surface); color: var(--ink);
}
.eventform button {
  font: inherit; font-size: 13px; font-weight: 600; padding: 8px 16px; border: none;
  border-radius: 8px; background: var(--navy); color: #fff; cursor: pointer;
}
button.linkish { font: inherit; font-size: 12px; color: var(--muted); background: none; border: none; cursor: pointer; }
button.linkish.danger:hover { color: var(--bad); }
.hovertip .ev { color: var(--chip-blend); }

/* login + misc */
.login { max-width: 340px; margin: 12vh auto; background: var(--surface); border: 1px solid var(--border); border-radius: 14px; padding: 26px; }
.login h1 { font-size: 17px; margin: 0 0 4px; }
.login p { color: var(--muted); font-size: 13px; margin: 0 0 18px; }
.login label { display: block; font-size: 12px; color: var(--ink-2); margin: 12px 0 4px; }
.login input { width: 100%; font: inherit; padding: 9px 10px; border-radius: 8px; border: 1px solid var(--border); background: var(--page); color: var(--ink); }
.login button { width: 100%; margin-top: 18px; font: inherit; font-weight: 600; font-size: 14px; padding: 10px; border: none; border-radius: 9px; background: var(--navy); color: #fff; cursor: pointer; }
.login .err { color: var(--bad); font-size: 13px; margin-top: 12px; }
.login button.linkish { width: auto; margin: 12px auto 0; display: block; padding: 2px 6px; background: none; border: none; color: var(--muted); font-weight: 500; font-size: 12px; }
.login button.linkish:hover { color: var(--ink); text-decoration: underline; }
.loading, .fatal { margin: 16vh auto; text-align: center; color: var(--muted); font-size: 14px; }
.fatal { color: var(--bad); max-width: 480px; }
.foot { margin-top: 34px; color: var(--muted); font-size: 12px; border-top: 1px solid var(--hairline); padding-top: 12px; }

@media (max-width: 840px) {
  .sidebar { width: 56px; padding: 14px 6px; }
  /* (selectors carry .deptsw / .sidebar so they outrank the base rules that
     follow later in the file) */
  .sidebar .brand, .sidebar .nav .soon, .sidebar .foot-note, .sidebar .navsec .navlabel,
  .sidebar .deptsw .deptbtn .t, .sidebar .deptsw .deptbtn .chev, .sidebar .deptsw .deptbtn .dot { display: none; }
  /* labels clip instead of display:none (review A-14): ~10 icon links kept
     their accessible names for screen readers at rail width */
  .sidebar .nav span.lbl { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  /* the switcher becomes the department chip (initials on the department colour) */
  .sidebar .deptsw .deptbtn { justify-content: center; padding: 0; border: none; background: none; }
  .sidebar .deptsw .deptbtn .chip { display: grid; }
  .sidebar .deptsw .deptmenu { right: auto; width: 200px; }
  .navsec + .navsec { border-top: 1px solid var(--side-line); margin-top: 6px; padding-top: 6px; }
  .sidebar a.nav, .sidebar button.nav { justify-content: center; padding: 10px 0; }
  .attbtn .attword { display: none; }
  .attbtn { padding: 6px 10px; }
  /* the rail footer stacks (Sep 8 2026): four 26px buttons in one row overran
     the 56px rail and painted over the page; Present is a projector feature
     with no job on a phone */
  .sidebar .sidefoot { flex-direction: column; gap: 2px; }
  .sidebar .sidefoot .iconbtn.present { display: none; }
}

/* ---- motion (all gated by prefers-reduced-motion at the bottom) ---- */
@keyframes rise { from { opacity: 0; transform: translateY(7px); } to { opacity: 1; transform: none; } }
.rise { animation: rise 0.4s cubic-bezier(0.2, 0.7, 0.3, 1) both; }
@keyframes draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
.linechart .drawin { stroke-dasharray: 1; animation: draw 0.9s ease-out both; }
.card .spark polyline { stroke-dasharray: none; }
@keyframes slidein { from { transform: translateX(40px); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes fadein { from { opacity: 0; } to { opacity: 1; } }
.drawer { animation: slidein 0.22s ease-out both; }
.backdrop { animation: fadein 0.18s ease-out both; }
.countymap .county { transition: fill 0.45s ease; }
/* Bars entrance (Aug 28 2026 wow pass): rects grow from their own baseline —
   the old class="drawin" was dead on fills (stroke-dashoffset animates
   strokes only). Per-bar stagger rides inline animation-delay from Bars. */
@keyframes growbar { from { transform: scaleY(0); } to { transform: none; } }
rect.grow { transform-box: fill-box; transform-origin: 50% 100%; animation: growbar 0.5s cubic-bezier(0.2, 0.7, 0.3, 1) both; }
.bars .blabel { animation: fadein 0.35s ease-out both; }
.bars .bghost { animation: fadein 0.4s ease-out 0.5s both; }
/* Overview map entrance: counties fade in with a light stagger (inline
   delay), labels follow, then the corridor arcs draw themselves. The classes
   ride only maps that ask for them — other choropleths are untouched.
   (Unscoped from .countymap Aug 28 pm: the agency home's county-in-region
   sheet wears them too and its svg is not a .countymap.) */
.cofade { animation: fadein 0.45s ease-out both; }
.lfade { animation: fadein 0.5s ease-out 0.35s both; }
.countymap .arcdraw { stroke-dasharray: 1; animation: draw 0.8s ease-out 0.55s both; }
.banner .badge {
  display: inline-block; margin-left: 12px; padding: 2px 10px; border-radius: 20px;
  background: var(--chip-blend); color: #1e1a0a; font-size: 10.5px; font-weight: 650;
  letter-spacing: 0.02em; text-transform: none; vertical-align: 2px;
}

/* skeleton shimmer */
@keyframes shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
.sk {
  border-radius: 12px;
  background: linear-gradient(100deg, var(--surface) 40%, var(--hairline) 50%, var(--surface) 60%);
  background-size: 200% 100%; animation: shimmer 1.4s linear infinite;
}
.sk-title { height: 26px; width: 240px; margin: 12px 0 18px; }
.sk-banner { height: 44px; margin-bottom: 14px; }
.sk-card { height: 100px; }

/* ranked-list proportional bars */
.rankrow { position: relative; overflow: hidden; }
.rankrow .bar {
  position: absolute; left: 0; top: 0; bottom: 0; z-index: 0; border-radius: 8px;
  background: color-mix(in srgb, var(--accent) 13%, transparent);
}
.rankrow .bar.neg { background: color-mix(in srgb, var(--bad) 14%, transparent); }
/* below the state benchmark — not a failure, so not the --bad red */
.rankrow .bar.below { background: color-mix(in srgb, var(--muted) 16%, transparent); }
.rankrow > :not(.bar) { position: relative; z-index: 1; }

/* region / Tennessee reference rows, pinned under the county ranking */
.rankref { margin-top: 4px; padding-top: 4px; border-top: 1px solid var(--hairline); }
.rankrow.ref { cursor: default; }
.rankrow.ref .nm { color: var(--ink-2); font-weight: 600; }
.rankrow.ref .rk { font-size: 9.5px; letter-spacing: 0.04em; }
.rankrow.ref:hover { background: none; }
.rankrow.ref.state .nm, .rankrow.ref.state .vl { color: var(--muted); }

/* delta pills */
.card .delta {
  align-self: flex-start; padding: 2.5px 9px; border-radius: 20px;
  background: color-mix(in srgb, var(--muted) 10%, transparent);
}
.card .delta.good { background: color-mix(in srgb, var(--good) 11%, transparent); }
.card .delta.bad { background: color-mix(in srgb, var(--bad) 11%, transparent); }

/* login branding */
.loginlogo { display: block; width: 190px; margin: 0 auto 6px; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .loginlogo { background: #fff; border-radius: 10px; padding: 8px 12px; }
}
:root[data-theme="dark"] .loginlogo { background: #fff; border-radius: 10px; padding: 8px 12px; }
.login p { text-align: center; }

/* ---- MOTION INVENTORY (Sep 8 2026) — the complete list; add nothing to it
   without adding it here and to the reduce-motion rule below:
   .rise 0.4s (drawers, cards, login) · .linechart .drawin · CountUp 650ms
   (components.js) · rect.grow / .bars .blabel · .cofade/.lfade + .countymap
   .arcdraw 0.8s (maps) · .yearend .paper section stagger (screen only) ·
   .sk shimmer (loading) · presfocus 1.6s ring · .pres-title 0.15s fade ·
   the 120ms hover lifts (a.card, .thumb).
   Sep 8 2026 (John: "if movement is possible, add that"): .empty-glyph .flag
   wave 3.2s loop · .deptbtn:hover .pennant wave ×2 · .ovhero .spark path.sl
   draw 0.9s · .sbseg share-bar segments grow 0.55s staggered · .pt-contour
   .ridge draw 2.4s on the title slide · .loginart-img breathe 9s alternate
   (scale 1→1.04) · .pagebody rise 0.35s, backwards fill only (see the rule) on every route change (the body is
   keyed by route). The sidebar spot tile (rise + float) was retired the same
   night for Option C — the pieces sit in the editorial sheet, on the title
   slide and beside empty states, all still. Everything still stops
   under prefers-reduced-motion; no MP4/GIF exports. ---- */
@media (prefers-reduced-motion: reduce) {
  .rise, .drawer, .backdrop, .linechart .drawin, .sk,
  rect.grow, .bars .blabel, .bars .bghost,
  .cofade, .lfade, .countymap .arcdraw, .yearend .paper section,
  .empty-glyph .flag, .sidebar .deptbtn:hover .pennant path:last-child, .ovhero .spark path.sl, .sbseg,
  .pt-contour .ridge, .loginart-img { animation: none; }
  .countymap .county { transition: none; }
}

/* Year-in-review entrance (Aug 28 2026 wow pass): the sheet's sections rise
   in with a light stagger ON SCREEN ONLY — the @media screen wrapper keeps
   print untouched, so the Letter sheet stays byte-faithful on paper. Nested
   columns restart nth-of-type numbering, which reads as a natural cascade. */
@media screen {
  .yearend .paper section { animation: rise 0.4s cubic-bezier(0.2, 0.7, 0.3, 1) both; }
  .yearend .paper section:nth-of-type(2) { animation-delay: 70ms; }
  .yearend .paper section:nth-of-type(3) { animation-delay: 140ms; }
  .yearend .paper section:nth-of-type(4) { animation-delay: 210ms; }
  .yearend .paper section:nth-of-type(5) { animation-delay: 280ms; }
  .yearend .paper section:nth-of-type(n+6) { animation-delay: 350ms; }
}

/* ---- Overview hero + "what changed" digest (Aug 28 2026 wow pass) ---- */
/* One board-quotable number leads the sheet; everything else is subordinate.
   The number is CSS-fluid (viewBox charts scale, so must the hero) and wears
   tabular figures; the unit and window sit small and muted beside it. */
.ovhero { margin: 2px 0 12px; }
.ovhero .row { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.ovhero .n { font-size: clamp(34px, 4.8vw, 48px); font-weight: 720; letter-spacing: -0.025em; line-height: 1.05; font-variant-numeric: tabular-nums lining-nums; }
.ovhero .u { font-size: 13px; color: var(--ink-2); font-weight: 500; }
.ovhero .delta { font-size: 12.5px; padding: 2.5px 9px; border-radius: 20px; font-variant-numeric: tabular-nums;
  background: color-mix(in srgb, var(--muted) 10%, transparent); }
.ovhero .delta.good { color: var(--good); background: color-mix(in srgb, var(--good) 11%, transparent); }
.ovhero .delta.bad { color: var(--bad); background: color-mix(in srgb, var(--bad) 11%, transparent); }
.ovhero .delta .vs { color: var(--muted); margin-left: 5px; }
.ovhero .story { margin-top: 6px; font-size: 14px; font-weight: 500; line-height: 1.45; color: var(--ink); max-width: 56ch; }
.ovhero .spark { width: 132px; height: 24px; align-self: center; }
/* the digest: the top movers since a year earlier, each row a door to its
   deep page — answers "what's new since I last looked" before the detail */
.digest { display: flex; flex-direction: column; gap: 6px; margin-top: 12px; }
.digest .drow { display: flex; align-items: center; gap: 8px; font-size: 12.5px; padding: 6px 11px;
  border: 1px solid var(--border); border-radius: 10px; background: var(--surface);
  color: var(--ink); text-decoration: none; }
.digest a.drow { transition: transform 0.12s ease, box-shadow 0.12s ease; }
.digest a.drow:hover { transform: translateY(-1px); box-shadow: var(--shadow-card); }
.digest .arrow { font-size: 11px; }
.digest .arrow.good { color: var(--good); }
.digest .arrow.bad { color: var(--bad); }
.digest .go { margin-left: auto; color: var(--muted); }
/* one-line spatial finding under the map's section header */
.mapstory { font-size: 12.5px; line-height: 1.4; color: var(--ink-2); margin: 2px 0 4px; }


/* ---- viz primitives (slope, sharebars, dotplot, dumbbell, scatter) ---- */
.vizbox { position: relative; background: var(--surface); border: 1px solid var(--border);
  border-radius: 12px; padding: 14px 16px 10px; }
.vizbox svg { display: block; width: 100%; height: auto; }
.vizbox .legend { display: flex; gap: 14px; flex-wrap: wrap; margin-bottom: 8px; }
/* legend keys inside a vizbox were unstyled (swatches rendered 0 wide on
   ShareBars in Flows/Riders/Peers) — same look as the chartbox legend */
.vizbox .legend { font-size: 12px; color: var(--ink-2); }
.vizbox .legend .key { display: inline-flex; align-items: center; gap: 6px; }
.vizbox .legend .swatch { width: 14px; height: 10px; border-radius: 2px; display: inline-block; }
.cellbar { position: relative; display: inline-block; height: 8px; border-radius: 4px;
  background: var(--accent); opacity: 0.75; vertical-align: middle; margin-right: 7px; }
.cellbar.div-neg { background: var(--bad); }
.cellbar.div-pos { background: var(--good); }

/* ---- "Ask about this page" chat (v1 prototype) ---- */
.askbtn {
  font: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer;
  color: var(--accent); background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
  border-radius: 8px; padding: 5px 12px; transition: border-color 0.12s;
}
.askbtn:hover { border-color: var(--accent); }
.chatpanel { display: flex; flex-direction: column; height: calc(100vh - 92px); }
.chatlog { flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 10px; padding: 2px 2px 12px; }
.msg { max-width: 92%; border-radius: 12px; padding: 9px 13px; font-size: 13.5px; line-height: 1.5; }
.msg.user { align-self: flex-end; background: color-mix(in srgb, var(--accent) 12%, var(--surface)); border: 1px solid color-mix(in srgb, var(--accent) 25%, transparent); }
.msg.assistant { align-self: flex-start; background: var(--surface); border: 1px solid var(--border); }
.msg.assistant p { margin: 0 0 8px; }
.msg.assistant p:last-child { margin-bottom: 0; }
.msg.dim { color: var(--muted); }
.chatempty { color: var(--ink-2); font-size: 13.5px; }
.chatsuggs { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.sugg {
  font: inherit; font-size: 13px; text-align: left; cursor: pointer;
  color: var(--ink); background: var(--surface); border: 1px solid var(--border);
  border-radius: 10px; padding: 9px 13px; transition: border-color 0.12s;
}
.sugg:hover { border-color: var(--accent); }
.chatin { display: flex; gap: 8px; padding-top: 10px; }
.chatin input {
  flex: 1; font: inherit; font-size: 13.5px; color: var(--ink);
  background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 9px 12px;
}
.chatin input:focus { outline: 2px solid var(--accent); outline-offset: -1px; border-color: var(--accent); }
/* --accent lightens in dark (#2571cf -> #3987e5), taking this button's white
   label from 4.84:1 to 3.64:1. Every other primary button in the app sits on
   --navy; in dark this one joins them. (Aug 2026 dark-mode pass) */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .chatin button { background: var(--navy); }
}
:root[data-theme="dark"] .chatin button { background: var(--navy); }
.chatin button {
  font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
  color: var(--navy-ink); background: var(--accent); border: none; border-radius: 10px; padding: 9px 16px;
}
.chatin button:disabled { opacity: 0.45; cursor: default; }
.chaterr { color: var(--bad); font-size: 12.5px; }
.chatkey p { font-size: 13.5px; color: var(--ink-2); line-height: 1.5; }
.chatfoot { font-size: 11.5px; color: var(--muted); padding-top: 8px; line-height: 1.5; }
.chatfoot a { color: var(--muted); }
.unverified { border-bottom: 1.5px dotted var(--bad); cursor: help; }
.chatlbl { display: block; font-size: 12px; color: var(--ink-2); margin: 10px 0 4px; }
.chatsel {
  width: 100%; font: inherit; font-size: 13.5px; color: var(--ink);
  background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 9px 12px;
}

/* ---- Sidebar: department switcher + flat sections (John's pick, Aug 21 2026) ----
   One department at a time: the switcher under the logo picks Whole agency /
   Transportation / Community services / (any department added later); the list
   below is that department's pages under plain section labels — two tiers,
   nothing collapses, so the sidebar never grows with the department count.
   Manage sinks to the bottom. --dept carries the department colour (same tokens
   as the Home bands) into the switcher dot, the rail chip and the active bar. */
.sidebar { --dept: var(--accent); }
.sidebar .deptsw { position: relative; margin: 0 0 6px; }
.sidebar .deptbtn {
  display: flex; align-items: center; gap: 9px; width: 100%; padding: 7px 9px; border-radius: 9px;
  border: 1px solid var(--side-line); background: var(--side-pop); color: var(--side-ink-strong);
  cursor: pointer; font-family: inherit; text-align: left;
}
.sidebar .deptbtn:hover { background: var(--side-hover); }
.sidebar .deptbtn:focus-visible { outline: 2px solid var(--dept); outline-offset: 1px; }
/* single-department workspaces: a label, not a control */
.sidebar .deptbtn.static { cursor: default; border-color: transparent; background: none; }
.sidebar .deptbtn .dot { width: 10px; height: 10px; border-radius: 50%; background: var(--dept); flex: none; }
.sidebar .deptbtn .chip { display: none; place-items: center; width: 30px; height: 30px; border-radius: 8px;
  background: var(--dept); color: #fff; font-weight: 800; font-size: 12px; letter-spacing: 0.02em; }
.sidebar .deptbtn .t { flex: 1; min-width: 0; line-height: 1.2; }
.sidebar .deptbtn .t small { display: block; font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--side-ink-dim); font-weight: 500; }
.sidebar .deptbtn .t b { display: block; font-size: 13.5px; font-weight: 650; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sidebar .deptbtn .chev { color: var(--side-ink-dim); flex: none; width: 12px; height: 12px; transition: transform 120ms ease; }
.sidebar .deptbtn[aria-expanded="true"] .chev { transform: rotate(180deg); }
.sidebar .deptmenu {
  position: absolute; left: 0; right: 0; top: calc(100% + 4px); z-index: 30; margin: 0; padding: 6px; list-style: none;
  background: var(--side-pop); border: 1px solid var(--side-line); border-radius: 10px;
  box-shadow: 0 10px 28px rgba(0,0,0,0.14); display: flex; flex-direction: column; gap: 1px;
}
.sidebar .deptmenu button {
  display: flex; align-items: center; gap: 9px; width: 100%; padding: 6px 8px; border-radius: 7px; border: none;
  background: none; color: var(--side-ink); font-family: inherit; font-size: 13px; text-align: left; cursor: pointer;
}
.sidebar .deptmenu button:hover, .sidebar .deptmenu button:focus-visible { background: var(--side-hover); color: var(--side-ink-strong); outline: none; }
.sidebar .deptmenu button[aria-current="true"] { background: var(--side-active); color: var(--side-ink-strong); font-weight: 650; box-shadow: inset 3px 0 0 var(--dept, var(--accent)); }
.sidebar .deptmenu .dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.navsec { display: flex; flex-direction: column; gap: 2px; }
.navsec .navlabel {
  font-size: 11px; font-weight: 650; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--side-ink-dim); padding: 14px 10px 4px;
}
.navsec.manage { margin-top: auto; padding-top: 8px; }
/* (the Aug 21 left bar is retired: the pill + the icon in the department colour carry "active") */
@media (prefers-reduced-motion: reduce) { .sidebar .deptbtn .chev { transition: none; } }

/* ---- Last week strip (weekly.js) ---- */
.weekstrip { margin-bottom: 18px; }
.weekstrip .banner { line-height: 1.75; }
.weekstrip .banner .badge { margin-left: 8px; }
.weekline { margin-top: 8px; font-size: 13px; color: var(--ink-2); line-height: 1.45; }
.weekline .muted { color: var(--muted); }
.weekdet { margin-top: 6px; }
.weekdet summary { cursor: pointer; font-size: 12.5px; color: var(--muted); user-select: none; }
.weekdet summary:hover { color: var(--ink-2); }
/* (the print-hide is gone, Aug 24 2026: the strip is now the Last week tab's
   whole body on the transportation home — printing there should print it) */

/* ---- command palette ---- */
.palette-back { position: fixed; inset: 0; z-index: 80; background: rgba(0,0,0,0.35); display: flex; justify-content: center; padding-top: 12vh; }
.palette { width: min(560px, 92vw); height: fit-content; background: var(--page); border: 1px solid var(--border); border-radius: 14px; box-shadow: 0 18px 50px rgba(0,0,0,0.35); overflow: hidden; }
/* In dark the page is already #0d0d0d, so the 0.35 scrim darkens it to #080808
   and a --page panel with a --border edge and a black shadow has no visible
   boundary at all (1.03:1). Give it the surface tone and an edge that survives
   the scrim. (Aug 2026 dark-mode pass) */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .palette { background: var(--surface); border-color: var(--muted); }
}
:root[data-theme="dark"] .palette { background: var(--surface); border-color: var(--muted); }
.palette input { width: 100%; font: inherit; font-size: 15px; color: var(--ink); background: var(--surface); border: none; border-bottom: 1px solid var(--border); padding: 14px 16px; }
.palette input:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.palette-list { max-height: 46vh; overflow-y: auto; padding: 6px; }
.palette-row { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 8px; cursor: pointer; font-size: 13.5px; }
.palette-row.on { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.palette-row .pk { flex: none; font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); width: 74px; }
.palette-row .pl { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.palette-row .ph { color: var(--muted); font-size: 12px; }
.palette-empty { padding: 16px; color: var(--muted); font-size: 13px; }
.palette-foot { padding: 8px 14px; font-size: 11.5px; color: var(--muted); border-top: 1px solid var(--border); }
.kbd { font-size: 10px; border: 1px solid var(--side-ink-dim); border-radius: 4px; padding: 0 4px; margin-left: 4px; opacity: 0.8; }

.attention { background: var(--surface); border: 1px solid var(--border); border-left: 3px solid var(--chip-blend); border-radius: 12px; padding: 12px 18px; margin: 10px 0 14px; }
.attention .att-title { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.07em; color: var(--chip-blend); margin-bottom: 6px; }
.attention ul { margin: 0; padding-left: 18px; font-size: 13.5px; line-height: 1.55; }

.chartbox, .vizbox { position: relative; }
.pngbtn { position: absolute; top: 6px; right: 6px; z-index: 3; width: 24px; height: 24px; border-radius: 6px; border: 1px solid var(--border); background: var(--surface); color: var(--ink-2); font-size: 13px; line-height: 1; cursor: pointer; opacity: 0; transition: opacity 0.15s; }
.chartbox:hover .pngbtn, .vizbox:hover .pngbtn { opacity: 1; }
.pngbtn:hover { color: var(--accent); border-color: var(--accent); }

.linkbtn { border: 1px solid var(--border); background: var(--surface); color: var(--ink-2); border-radius: 7px; padding: 4px 10px; font-size: 12px; cursor: pointer; }
.linkbtn:hover { color: var(--accent); border-color: var(--accent); }

.goalchips { display: flex; flex-wrap: wrap; gap: 8px; margin: 2px 0 12px; }
.goalchip { display: inline-flex; align-items: baseline; gap: 8px; padding: 5px 12px; border-radius: 999px; border: 1px solid var(--border); background: var(--surface); font-size: 12.5px; text-decoration: none; color: var(--ink-2); }
.goalchip .gc-name { font-weight: 600; }
.goalchip .gc-target { color: var(--muted); font-size: 11.5px; }
.goalchip.met { border-color: color-mix(in srgb, var(--good) 45%, var(--border)); }
.goalchip.met .gc-val { color: var(--good); font-weight: 700; }
.goalchip.miss { border-color: color-mix(in srgb, var(--bad) 45%, var(--border)); }
.goalchip.miss .gc-val { color: var(--bad); font-weight: 700; }
.goalform { display: grid; grid-template-columns: 2fr 1fr 1fr 2fr auto; gap: 8px; margin-top: 10px; }
/* min-width: 0 — a text/number input's intrinsic minimum (~170px) otherwise
   forces its grid column wider than a phone's content column, and the page
   scrolls sideways */
.goalform select, .goalform input, .eventform input { min-width: 0; }
.goalform select, .goalform input { padding: 8px 10px; border-radius: 8px; border: 1px solid var(--border); background: var(--surface); color: var(--ink); font-size: 13px; }
@media (max-width: 760px) { .goalform { grid-template-columns: 1fr 1fr; } }
@media (max-width: 480px) { .goalform { grid-template-columns: 1fr; } }

/* General ledger: let the year fit without horizontal scrolling. The page
   escapes the 1080px column and the table compacts its type and padding. */
.wrap:has(.gl-full) { max-width: none; }
/* Money flow (#/fflow): the Sankey escapes the column too and fills the
   viewport, so the ribbon labels draw at a readable size. */
.wrap:has(.flowpage) { max-width: none; }
.gl-full table.heat td, .gl-full table.heat th { padding: 4px 5px; font-size: 11px; }
.gl-full table.heat td.rowhead { font-size: 11.5px; max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gl-full table.heat { width: 100%; }
/* Total + vs-prior columns lead the ledger and freeze with the account column
   (John, Aug 27 2026) — the months scroll beneath the summary trio. Offsets
   assume the fixed border-box widths below; if a width changes, the next
   column's left must move with it. The account cell gains width (a floor the
   ellipsis rule above never set) so its edge — and the offsets — hold. */
.gl-full table.heat td.rowhead { width: 200px; min-width: 200px; }
.gl-full table.heat th.gltot, .gl-full table.heat td.gltot,
.gl-full table.heat th.glvs, .gl-full table.heat td.glvs {
  position: sticky; background: var(--surface); }
.gl-full table.heat td.gltot, .gl-full table.heat td.glvs { z-index: 1; }
.gl-full table.heat th.gltot, .gl-full table.heat td.gltot { left: 200px; width: 104px; min-width: 104px; }
.gl-full table.heat th.glvs, .gl-full table.heat td.glvs {
  left: 304px; width: 100px; min-width: 100px; border-right: 1px solid var(--border); }
/* the rowhead's own border-right is now an interior line of the frozen trio,
   and .annual's border-left would double it */
.gl-full table.heat td.annual { border-left: none; }
/* Under 700px the frozen trio would out-span the viewport, so only the account
   column stays pinned; Total + vs still lead, they just scroll with the months.
   (Media queries add no specificity — this must sit after the base rules.) */
@media (max-width: 700px) {
  .gl-full table.heat th.gltot, .gl-full table.heat td.gltot,
  .gl-full table.heat th.glvs, .gl-full table.heat td.glvs {
    position: static; width: auto; min-width: 88px; }
  .gl-full table.heat td.rowhead { width: auto; min-width: 150px; }
}
@supports not (selector(:has(*))) { /* older browsers keep the scroll fallback */ }

/* ---- plain-English layer: tappable terms + explainers (explain.js) ---- */
.term { border-bottom: 1px dotted var(--muted); cursor: help; }
.term:hover { color: var(--accent); border-bottom-color: var(--accent); }
.explain { display: grid; gap: 8px; margin: 2px 0 14px; }
.explain .erow { display: grid; grid-template-columns: 128px 1fr; gap: 10px; font-size: 13.5px; line-height: 1.5; }
.explain .ek { color: var(--muted); font-weight: 650; font-size: 11.5px; text-transform: uppercase; letter-spacing: .05em; padding-top: 2px; }
.explain.compact { padding: 10px 12px; border: 1px solid var(--hairline); border-radius: 10px; }

/* ---- superlative badges (runs league) ---- */
.badge { font-size: 10px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  padding: 1.5px 7px; border-radius: 999px; white-space: nowrap;
  background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent); }
/* a long badge (fpacket's banner booked-through line) wraps on a phone
   instead of forcing a sideways page scroll — must sit after the nowrap rule
   above, and .banner .badge needs naming to outrank its own rule */
@media (max-width: 700px) { .badge, .banner .badge { white-space: normal; } }
/* Both of these write --accent over a tint of --accent. In dark that self-tinted
   ground costs enough to drop 10px/700 text to 4.0-4.2:1, so the ink lifts a
   step. (Aug 2026 dark-mode pass) */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .badge,
  :root:not([data-theme="light"]) .jump:not(.on) .jn { color: #6fa8ea; }
}
:root[data-theme="dark"] .badge,
:root[data-theme="dark"] .jump:not(.on) .jn { color: #6fa8ea; }
/* Banner badges sit on the amber --chip-blend fill, not the accent tint, so
   the dark-mode ink lift above must NOT apply to them (light blue on amber
   was ~2:1; Aug 19 2026). Keep the dark ink. */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .banner .badge { color: #1e1a0a; } }
:root[data-theme="dark"] .banner .badge { color: #1e1a0a; }
.badge.gold { background: color-mix(in srgb, #d99a06 20%, transparent); color: #a87503; }
.badge.warn { background: color-mix(in srgb, #c93636 13%, transparent); color: #c93636; }
/* Both badge inks are tuned for the pale light-mode tint; on the dark tint
   they fell to 4.3:1 (gold) and 3.4:1 (warn) at 10px/700. (Aug 2026) */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .badge.gold { color: #e6b23c; }
  :root:not([data-theme="light"]) .badge.warn { color: var(--bad); }
}
:root[data-theme="dark"] .badge.gold { color: #e6b23c; }
:root[data-theme="dark"] .badge.warn { color: var(--bad); }

/* ---- corridor arcs (county map, Corridors mode) ---- */
.corridor { cursor: pointer; transition: opacity .12s; }
.corridor:hover { opacity: 1 !important; }
.corlabel { font-size: 11px; fill: var(--ink); paint-order: stroke; stroke: var(--page); stroke-width: 3px; }

/* ---- "Worth your attention" — compact amber button + drawer list ---- */
.attbtn { display: inline-flex; align-items: center; gap: 7px; font: inherit;
  font-size: 13px; font-weight: 650; color: #8a5a00; cursor: pointer;
  background: color-mix(in srgb, #f5b301 16%, transparent);
  border: 1.5px solid color-mix(in srgb, #f5b301 55%, transparent);
  border-radius: 999px; padding: 6px 14px; transition: background .12s; }
.attbtn:hover { background: color-mix(in srgb, #f5b301 30%, transparent); }
.attbtn svg { width: 15px; height: 15px; flex: none; }
.attcount { background: #f5b301; color: #231a00; border-radius: 999px;
  padding: 0 7px; font-size: 11.5px; font-weight: 750; line-height: 1.5; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .attbtn { color: #f2c14e; }
}
:root[data-theme="dark"] .attbtn { color: #f2c14e; }
.attlist { margin: 0 0 12px; padding-left: 18px; font-size: 13.5px; line-height: 1.7; }
.attlist li { margin: 6px 0; }

/* ---- print: the county packet (and any page) prints clean ---- */
@media print {
  .sidebar, .areatabs, .askbtn, .attbtn, .noprint, select, .backdrop, .drawer { display: none !important; }
  .shell { display: block; }
  .content { padding: 0; overflow: visible; }
  .wrap { max-width: none; padding-left: 0; padding-right: 0; }
  body { background: #fff; }
  .card, .mapbox, .ranklist, .tablewrap { break-inside: avoid; box-shadow: none; }
  .appbar h1::after { content: " — " attr(data-print-note); font-size: 12px; color: #666; }
  /* overflow-x CLIPS in print — anything scrolled out of view simply never
     renders on paper. Wide tables (the county packet's 14-column trips-by-month)
     must overflow visibly and get the full single-column page width. */
  .tablewrap { overflow: visible !important; }
  .grid2 { grid-template-columns: 1fr !important; }
  /* ...and visible overflow alone only moves the problem to the paper edge: at
     screen metrics that table's natural width is 850px against ~739px of Letter
     content. Tightened to ~693px, which clears 0.5in margins. Matches the
     .gl-full dense-table treatment above. */
  .tablewrap table.heat { font-size: 11px; }
  .tablewrap table.heat th, .tablewrap table.heat td { padding: 4px; }
}

/* ---- print: the no-show policy list as a follow-up sheet ----
   The "⎙ Print list" button flips html.print-nslist for the duration of the
   print dialog: charts, cards and the reasons section drop out, the segmented
   pickers hide, and a blank notes column appears so staff can write against
   each name. Off-screen the notes column doesn't exist at all. */
.nslist-only { display: none; }
@media print {
  html.print-nslist .nslist-hide, html.print-nslist .seg,
  html.print-nslist .takeaways { display: none !important; }
  html.print-nslist .noshows .section { margin-top: 12px !important; }
  html.print-nslist .noshows .delta { font-size: 11.5px; }
  html.print-nslist .nslist-only { display: table-cell; }
  html.print-nslist th.nslist-only.notes { text-align: left; }
  html.print-nslist td.nslist-only.notes { width: 34%; border-bottom: 1px solid #bbb; }
  html.print-nslist .noshows table.heat td { padding-top: 9px; padding-bottom: 9px; }
  html.print-nslist .noshows tr.sect td { padding-top: 5px; padding-bottom: 5px; }
  /* a long list may run past one page: let the TABLE break (the general
     .tablewrap rule above would shove it whole onto page 2), keep ROWS whole */
  html.print-nslist .noshows .tablewrap { break-inside: auto; }
  html.print-nslist .noshows tr { break-inside: avoid; }
  html.print-nslist .noshows thead { display: table-header-group; }
  /* the rate bar is a tinted background — it usually won't print; the number
     next to it carries the value */
  html.print-nslist .noshows .cellbar { display: none; }
}

/* ---- print: the driver roster ----
   "⎙ Print roster" (Drivers page) flips html.print-drroster: everything but the
   page header and the paper-only .drroster-only block drops out. That block
   (roster by county with tenure + blank notes, then the year's roster changes)
   is never shown on screen — the cards and drawers are the screen view. */
.drroster-only { display: none; }
@media print {
  html.print-drroster .drivers > *:not(.appbar):not(.drroster-only) { display: none !important; }
  html.print-drroster .drivers .drroster-only { display: block; }
  html.print-drroster .seg { display: none !important; }
  html.print-drroster .drivers th.notes { text-align: left; }
  html.print-drroster .drivers td.notes { width: 30%; border-bottom: 1px solid #bbb; }
  html.print-drroster .drivers table.heat td { padding-top: 8px; padding-bottom: 8px; }
  html.print-drroster .drivers tr.sect td { padding-top: 5px; padding-bottom: 5px; }
  html.print-drroster .drivers .delta { font-size: 11.5px; }
  html.print-drroster .drivers .tablewrap { break-inside: auto; }
  html.print-drroster .drivers tr { break-inside: avoid; }
  html.print-drroster .drivers thead { display: table-header-group; }
}

/* ---- print: the league table ----
   "⎙ Print league" flips html.print-drleague: only the league section header,
   the table (as sorted on screen — the sort is named in a paper-only note since
   the sort seg hides) and the definitions foot print. */
.drleague-sortnote { display: none; }
@media print {
  html.print-drleague .drivers > *:not(.appbar):not(.drleague-keep) { display: none !important; }
  html.print-drleague .seg { display: none !important; }
  html.print-drleague .drleague-sortnote { display: inline; }
  html.print-drleague .drivers .section { margin-top: 12px !important; }
  html.print-drleague .drivers .cellbar { display: none; }
  html.print-drleague .drivers .tablewrap { break-inside: auto; }
  html.print-drleague .drivers tr { break-inside: avoid; }
  html.print-drleague .drivers thead { display: table-header-group; }
}

/* ---- Revenue match page ---- */
/* Rule text under each program heading: the grant terms, stated where the
   numbers are, so nobody has to trust the arithmetic on faith. */
table.heat tr.sect .rulenote {
  display: block; text-transform: none; letter-spacing: 0; font-weight: 400;
  font-size: 11px; color: var(--muted); margin-top: 2px;
}
/* Shortfalls carry parentheses from the formatter AND colour — never colour
   alone (evidence rules §14: ~8% of men can't separate the hues). */
table.heat td.shortcell { color: var(--bad); }

/* Setup panel: shown when a page ships ahead of its database function, so a
   nav link is never a dead end. The base .callout is a baseline-aligned flex
   row (built for big-number stats) — prose needs a column. */
.callout.setup { display: block; max-width: 66ch; }
.callout.setup p { margin: 0 0 10px; line-height: 1.55; }
.callout.setup p:last-child { margin-bottom: 0; }
.callout.setup .muted { color: var(--muted); font-size: 13px; }
.callout.setup code {
  font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 0.92em;
  background: var(--hairline); padding: 1px 5px; border-radius: 4px;
}
.callout.setup pre {
  font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 12.5px;
  background: var(--hairline); border: 1px solid var(--border); border-radius: 8px;
  padding: 10px 12px; margin: 0 0 12px; overflow-x: auto; white-space: pre;
}

/* Revenue match: rate chip on each future-code row — the match rate stated
   where it is applied, so the arithmetic is auditable in place. */
.ratechip {
  font-size: 10.5px; color: var(--muted); border: 1px solid var(--border);
  border-radius: 99px; padding: 0 6px; margin-left: 4px;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
/* BALANCE row tint — paired with signed parentheses and the row label,
   never color alone. */
table.heat tr.match-balance td { background: color-mix(in srgb, var(--good) 10%, var(--surface)); }
table.heat tr.match-balance.short td { background: color-mix(in srgb, var(--bad) 10%, var(--surface)); }
/* Running-position strip: monthly bars around a zero baseline (ported from
   the review page John liked). Direction encodes sign; values sit under bars. */
.mstrip {
  background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
  padding: 14px 16px 10px; margin-top: 14px;
}
.mstrip-head { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; flex-wrap: wrap; margin-bottom: 12px; }
.mstrip-title { font-size: 11px; font-weight: 650; letter-spacing: 0.07em; text-transform: uppercase; }
.mstrip-note { font-size: 12px; color: var(--muted); }
.mstrip-bars { position: relative; display: grid; grid-template-columns: repeat(12, 1fr); gap: 6px; height: 110px; }
.mstrip-zero { position: absolute; left: 0; right: 0; border-top: 1px dashed var(--border); pointer-events: none; }
.mcol { display: flex; flex-direction: column; height: 100%; }
.mbar { background: var(--good); border-radius: 2px; }
.mbar.dn { background: var(--bad); }
.mstrip-labels { display: grid; grid-template-columns: repeat(12, 1fr); gap: 6px; margin-top: 6px; }
.mstrip-labels .mlab { font-size: 10px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); text-align: center; }
.mstrip-labels .mval { font-size: 10px; color: var(--muted); text-align: center; font-variant-numeric: tabular-nums; }
/* Bar hover: the month's own surplus/(short) plus the running total —
   CSS-only via data-tip, full-height columns as the hit target. */
.mcol { position: relative; }
.mcol[data-tip]:hover::after {
  content: attr(data-tip);
  position: absolute; left: 50%; top: -6px; transform: translate(-50%, -100%);
  background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
  padding: 4px 9px; font-size: 11.5px; white-space: nowrap;
  font-variant-numeric: tabular-nums; box-shadow: 0 4px 14px rgba(0, 0, 0, 0.14);
  z-index: 6; pointer-events: none;
}
/* keep the first/last months' tooltips inside the card */
.mcol:first-child[data-tip]:hover::after { left: 0; transform: translate(0, -100%); }
.mcol:last-child[data-tip]:hover::after { left: auto; right: 0; transform: translate(0, -100%); }

/* ---- Year in review: the one-page year-end sheet (yearend.js) ----
   The .paper is a Letter sheet drawn on screen exactly as it prints — always
   light, its own ink, no theme tokens inside it (a dark-mode screen shows a
   white sheet on the dark page, on purpose: what you see is what prints).
   Fonts run 10.5–12px so a full year fits one page; the print block below
   drops the toolbar and lets the sheet take the whole printable width. */
.yearend .paper {
  background: #fff; color: #0b0b0b; max-width: 736px; margin: 4px auto 0;
  padding: 24px 26px 20px; border: 1px solid var(--border); border-radius: 6px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.10); font-size: 11.5px; line-height: 1.35;
}
.ye-head { display: flex; align-items: center; gap: 14px; padding-bottom: 8px; border-bottom: 2px solid #1e3a5f; }
.ye-logo { height: 36px; width: auto; flex: none; max-width: 100%; object-fit: contain; object-position: left center; }
.ye-titles { flex: 1; min-width: 0; }
.ye-title { font-size: 21px; font-weight: 700; letter-spacing: -0.01em; line-height: 1.1; color: #1e3a5f; }
.ye-sub { font-size: 11.5px; color: #52514e; margin-top: 3px; }
.ye-meta { font-size: 10px; color: #6f6e69; text-align: right; line-height: 1.35; flex: none; }
.ye-flag { margin: 8px 0 0; padding: 5px 9px; font-size: 10.5px; color: #7a4b00; background: #fff5df; border: 1px solid #f1d59a; border-radius: 6px; }
.ye-hero { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; margin: 10px 0 8px; }
.ye-hero .ye-stat { padding: 6px 10px 6px; border: 1px solid #e1e0d9; border-radius: 8px; background: #fbfbf9; }
.ye-hero .ye-v { font-size: 21px; font-weight: 720; letter-spacing: -0.02em; }
.ye-stat { min-width: 0; }
.ye-k { font-size: 10.5px; color: #52514e; line-height: 1.2; }
.ye-v { font-size: 17px; font-weight: 650; line-height: 1.15; margin: 2px 0 1px; font-variant-numeric: tabular-nums; }
/* long figures ($10,584,603) step down so they never clip their cell — the
   Stat component measures the string and adds long/xlong (Aug 24 2026 night) */
.ye-v.long { font-size: 14.5px; }
.ye-v.xlong { font-size: 13px; }
.ye-hero .ye-v.long { font-size: 16px; }
.ye-hero .ye-v.xlong { font-size: 14px; }
.ye-s { font-size: 10px; color: #52514e; line-height: 1.25; }
.ye-d { white-space: nowrap; }
.ye-d.good { color: #006300; }
.ye-d.bad { color: #b32d2d; }
/* The paper sheet is always light, so this grey is measured against white:
   #898781 was 3.59:1. #6f6e69 (the light --muted) is 5.11:1 and prints
   better too. (Aug 2026 contrast pass) */
.ye-d .dim, .paper .dim { color: #6f6e69; }
.ye-cols { display: grid; grid-template-columns: 1.3fr 1fr; gap: 16px; align-items: start; }
.ye-col { min-width: 0; }
.ye-block { margin-top: 8px; }
.ye-col > .ye-block:first-child { margin-top: 0; }
.ye-h { display: flex; align-items: baseline; gap: 8px; margin: 0 0 4px; padding-bottom: 2px; border-bottom: 1px solid #e1e0d9; }
.ye-h span:first-child { font-size: 10.5px; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase; color: #1e3a5f; }
.ye-note { font-size: 10px; color: #6f6e69; }
.ye-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 12px; }
.ye-grid .ye-stat { padding: 3px 0 2px; }
.paper table.ye-tbl { width: 100%; font-size: 10.5px; color: #0b0b0b; }
.paper table.ye-tbl th, .paper table.ye-tbl td { padding: 2px 4px; }
.paper table.ye-tbl thead th { color: #52514e; font-weight: 600; background: none; border-bottom: 1px solid #e1e0d9; }
.paper table.ye-tbl td { border-bottom: 1px solid #edece6; }
.paper table.ye-tbl td.rowhead, .paper table.ye-tbl th.rowhead { color: #0b0b0b; background: none; }
.paper table.ye-tbl tr.total td { font-weight: 650; border-top: 1px solid #52514e; border-bottom: none; }
.paper table.ye-tbl .ye-d { font-size: 10px; }
.ye-fine { font-size: 9.5px; color: #6f6e69; margin-top: 4px; line-height: 1.3; }
/* The community-services sheet (csyearend.js) carries wider tables than the
   transportation one — six columns by county, four by program — so its
   rowheads give up the app table's 150px sticky minimum and wrap instead,
   and the columns split closer to even. (Aug 23 2026: the two columns were
   overprinting each other.) */
.yearend.cs .ye-cols { grid-template-columns: 1.15fr 1fr; }
.yearend.cs table.ye-tbl td.rowhead, .yearend.cs table.ye-tbl th.rowhead {
  position: static; min-width: 0; border-right: none; white-space: normal; line-height: 1.2; }
.yearend.cs table.ye-tbl thead th { position: static; white-space: normal; line-height: 1.2; vertical-align: bottom; }
.yearend.cs table.ye-tbl tr.sect td { padding-top: 6px; }
.ye-lines { margin-top: 10px; }
.ye-lines ul { margin: 2px 0 0; padding-left: 16px; }
.ye-lines li { margin: 2px 0; font-size: 11.5px; line-height: 1.35; }
.ye-foot { margin-top: 10px; padding-top: 5px; border-top: 1px solid #e1e0d9; font-size: 9px; line-height: 1.35; color: #52514e; }
.ye-foot b { color: #0b0b0b; }
@media (max-width: 720px) {
  .ye-hero { grid-template-columns: repeat(2, 1fr); }
  .ye-cols { grid-template-columns: 1fr; }
  .yearend.cs .ye-cols { grid-template-columns: 1fr; }   /* outranks :1402 (Sep 8 2026) */
  /* the sheet reflows on a phone: the masthead wraps, and a table wider than
     the sheet scrolls inside its own block — the page never scrolls sideways */
  .ye-head { flex-wrap: wrap; }
  .ye-block { overflow-x: auto; }
}
@media print {
  /* the sheet is the page: no frame, no shadow, full printable width; nothing
     else on the route prints (the toolbar is .noprint). Same at ⌘P as at the
     button. Kept to one Letter page by the sizes above, not by scaling. */
  .yearend .paper { max-width: none; margin: 0; padding: 0; border: 0; border-radius: 0; box-shadow: none; }
  .ye-hero { grid-template-columns: repeat(5, 1fr) !important; }
  .ye-cols { grid-template-columns: 1.3fr 1fr !important; }
  .yearend.cs .ye-cols { grid-template-columns: 1.15fr 1fr !important; }
  .yearend .paper, .ye-block, .ye-hero, .ye-lines, .ye-foot { break-inside: avoid; }
  .ye-hero .ye-stat, .ye-flag { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  /* the entrance stagger is screen-only: a print caught mid-fade printed a
     washed-out sheet (Sep 9 2026) */
  .yearend .paper section, .pagebody { animation: none !important; opacity: 1 !important; }
  /* the page wrapper's 12/64 px paddings and the skip link (a fixed element,
     it printed "Skip to content" at the foot of every sheet) are not part of
     the sheet — the sheet is the page (Sep 9 2026 print proof) */
  .wrap:has(.yearend) { padding: 0; }
  .skiplink { display: none !important; }
}
/* the sheet laid out as print does, on screen, for the one synchronous frame
   in which yearend.js usePrintFit measures it (width = Letter minus 0.45 in
   margins; must match PRINT_W there). Then, if the year ran long, the sheet
   prints zoomed down to one page. */
html.ye-measure .yearend .paper { width: 729.6px; max-width: none !important; margin: 0; padding: 0 !important; border: 0; box-sizing: content-box; }
html.ye-measure .ye-hero { grid-template-columns: repeat(5, 1fr) !important; }
html.ye-measure .ye-cols { grid-template-columns: 1.3fr 1fr !important; }
html.ye-measure .yearend.cs .ye-cols { grid-template-columns: 1.15fr 1fr !important; }
html.ye-measure .ye-head { flex-wrap: nowrap !important; }
html.ye-measure .noprint { display: none !important; }

/* ---- Sep 9 2026: the editorial sheet on paper (Year in review ×3, John:
   "similar to our polished editorial look on the home pages") ----
   The year's paragraph wears the home pages' editorial look at sheet sizes:
   serif body, drop cap in the department's tone, two columns with a hairline
   between, a rule above and below. Paper law: its own ink, no theme tokens
   (the tone is the one exception, as the old boxed block already made). */
/* the department tones pinned to their light values inside the sheet — a dark
   screen still shows a white sheet, and the drop cap must read on white */
.paper { --chip-ops: #008300; --chip-cs: #a0407d; --chip-agency: #8a6516; }
.paper .narr.editorial { margin: 10px 0 2px; padding: 8px 0 5px; border-top: 1.5px solid #0b0b0b; border-bottom: 1px solid #d9d7d0; }
.paper .narr.editorial .ed-kicker { margin-bottom: 6px; gap: 7px; }
.paper .narr.editorial .ed-head { font-size: 10.5px; letter-spacing: 0.08em; color: #1e3a5f; }
.paper .narr.editorial .ed-date { font-size: 12px; color: #6f6e69; }
.paper .narr.editorial .ed-body { column-count: 2; column-gap: 28px; column-rule: 1px solid #e1e0d9; }
.paper .narr.editorial .narr-p { font-size: 12.5px; line-height: 1.5; color: #0b0b0b; margin: 0 0 7px; max-width: none; }
.paper .narr.editorial .narr-p:first-of-type::first-letter { font-size: 3em; line-height: 0.8; padding: 4px 6px 0 0; }
.paper .narr.editorial .narr-foot { margin-top: 0; font-size: 9px; color: #6f6e69; }
@media print { .paper .narr.editorial .ed-body { column-count: 2; } .paper .narr.editorial .narr-p { font-size: 12.5px; } }

/* ---- fixed-route stop map (gomap.js, Aug 2026): OSM town basemap + graduated stop symbols ---- */
.mapgrid.go { grid-template-columns: minmax(0, 2.1fr) minmax(250px, 1fr); }
.gomap svg.gostopmap { width: 100%; height: auto; max-height: 640px; display: block; }
/* basemap strokes stay hairline-thin at any zoom (screen px, not viewBox units) */
.gostopmap .base path { fill: none; stroke: var(--ink); stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.gostopmap .base .water { fill: var(--accent); fill-opacity: 0.10; stroke: none; }
.gostopmap .base .stream { stroke: var(--accent); stroke-opacity: 0.25; stroke-width: 1; }
.gostopmap .base .rd.minor { stroke-opacity: 0.10; stroke-width: 0.6; }
.gostopmap .base .rd.mid { stroke-opacity: 0.16; stroke-width: 1; }
.gostopmap .base .rd.major { stroke-opacity: 0.22; stroke-width: 1.8; }
.gostopmap .base .rail { stroke-opacity: 0.25; stroke-width: 0.8; stroke-dasharray: 5 3; }
.gostopmap .town { letter-spacing: 0.14em; }
.gostopmap .stop { cursor: default; }
.gostopmap .stop.on circle:first-child { stroke: var(--ink); }
.gomap-foot { margin-top: 8px; }

/* Department bands on Home (Aug 21 2026): each department's cards sit on a
   faint tint of its own chip colour with a matching top rule on every card;
   the first card leads (two columns, larger figure). Colour groups, it never
   encodes good/bad (DATAVIZ §14.6) — the deltas still carry sign + arrow.
   Compact pass (John, Aug 24 2026): more department snapshots are coming, so
   each band tightens — same cards, same figures, a size smaller and packed a
   column denser. Nothing is removed, and the department home link rides the
   band's own header row instead of a row of its own. */
.deptband { --tone: var(--accent); margin-top: 12px; padding: 10px 12px 11px; border-radius: 14px;
  background: color-mix(in srgb, var(--tone) 6%, var(--surface)); border: 1px solid color-mix(in srgb, var(--tone) 22%, var(--border)); }
.deptband.ops { --tone: var(--chip-ops); }
.deptband.cs { --tone: var(--chip-cs); }
.deptband .section { margin-top: 0; margin-bottom: 6px; }
.deptband .section h2 { color: var(--ink); }
.deptband .section .jump, .cs-strip .section .jump { margin-left: auto; font-size: 11.5px; padding: 2px 9px; }
/* (card top rule retired in the Monarch pass — the tint groups, the cards stay white) */
.deptband .cs-strip { margin-top: 0; }
.deptband .cards { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; }
.deptband .card { min-height: 60px; padding: 9px 11px 8px; border-radius: 10px; }
.deptband .card .value { font-size: 20px; margin: 3px 0 2px; }
.deptband .card .value.long { font-size: 17px; }
.deptband .card .value.xlong { font-size: 15px; }
.deptband .card .spark { height: 15px; margin: 1px 0 2px; }
.deptband .card .delta, .deptband .card .bench { font-size: 11px; }
.cards.lead-first .card:first-child { grid-column: span 2; }
.cards.lead-first .card:first-child .value { font-size: 34px; }
.deptband .cards.lead-first .card:first-child .value { font-size: 24px; }
@media (max-width: 560px) { .cards.lead-first .card:first-child { grid-column: span 1; } .cards.lead-first .card:first-child .value { font-size: 28px; }
  .deptband .cards.lead-first .card:first-child .value { font-size: 22px; } }
/* Overview department bands (John, Aug 28 2026): dense = the same cards at
   about two-thirds size — every number and note kept, less screen; closed =
   the ▾ chevron folds everything under the band's header away (the section
   row keeps the window label and badges). Print always gets the cards back —
   a folded screen must not thin the printed sheet. These rules sit AFTER the
   base .deptband .card rules on purpose (same specificity class chain). */
.deptband.dense .cards { grid-template-columns: repeat(auto-fill, minmax(116px, 1fr)); gap: 6px; }
.deptband.dense .card { min-height: 44px; padding: 6px 9px 5px; border-radius: 9px; }
.deptband.dense .card .label { font-size: 9.5px; letter-spacing: 0.05em; }
.deptband.dense .card .value { font-size: 18px; margin: 3px 0 2px; }
.deptband.dense .card .value.long { font-size: 15.5px; }
.deptband.dense .card .value.xlong { font-size: 13px; }
.deptband.dense .card .delta { font-size: 10.5px; gap: 4px; }
.deptband.dense .card .bench { font-size: 10px; margin-top: 3px; }
.deptband.dense .card .spark { height: 16px; }
.deptband.dense .cards.lead-first .card:first-child .value { font-size: 21px; }
.deptband.closed .cards, .deptband.closed .cs-strip .foot, .deptband.closed .ovhero { display: none; }
@media print { .deptband.closed .cards { display: grid; } .deptband.closed .ovhero { display: block; } }
/* agency-Overview department heroes (Aug 28 2026 wow pass): two heroes sit
   side by side in the dense bands, so they run a step smaller than a page
   hero; the digest's dept dot carries each row's department tint (the name
   is written too — colour is never the only cue) */
.deptband.dense .ovhero { margin: 2px 0 10px; }
.deptband.dense .ovhero .n { font-size: clamp(26px, 3.4vw, 36px); }
.digest .dot { width: 10px; height: 10px; border-radius: 3px; flex: none; }
.section .bandtoggle { margin-left: auto; border: 1px solid var(--hairline); background: none;
  color: var(--muted); border-radius: 7px; width: 22px; height: 22px; line-height: 1;
  font-size: 11px; cursor: pointer; padding: 0; flex: none; }
.section .bandtoggle:hover { color: var(--ink); border-color: var(--muted); }
.section .jump ~ .bandtoggle { margin-left: 8px; }
@media print { .deptband { background: none; border-color: #ddd; } }

/* Department homes (Aug 21 2026, "addition through subtraction" pass): the
   explanatory section subtext is gone and the department's own tone carries
   the page instead — a tinted banner, the toggle in the tone, a tone rule on
   every card (the SECTION's chip colour, set as --tone by Section's wrapper),
   and section titles darkened into their tone. Colour groups, it never encodes
   good/bad (DATAVIZ §14.6). Banner gradients stay ≥4.95:1 under white text at
   their lightest end (#008300, #a0407d) in both themes. */
.depthome { --tone: var(--accent); --band-from: var(--navy); --band-to: var(--navy); }
.depthome.tone-ops { --tone: var(--chip-ops); --band-from: #0a5c26; --band-to: #008300; }
.depthome.tone-cs { --tone: var(--chip-cs); --band-from: #7d2a5f; --band-to: #a0407d; }
.depthome.tone-fin { --tone: var(--chip-fin); --band-from: #14283f; --band-to: #1e3a5f; }
.depthome.tone-ci { --tone: var(--chip-ci); --band-from: #174f41; --band-to: #206e5a; }
.depthome.tone-eu { --tone: var(--chip-eu); --band-from: #5a3a70; --band-to: #7c5295; }
/* wireframe pages (depts.js): the layout is real, the figures are not — dashed
   card rules and a muted banner keep a placeholder from reading as a zero */
.wire .card { border-style: dashed; }
.wire .card .value.dim { color: var(--muted); }
.wire .jump { pointer-events: none; border-style: dashed; color: var(--muted); }
.wire table.heat.plain td.dim { color: var(--muted); }
.depthome .appbar h1 { border-left: 4px solid var(--tone); padding-left: 10px; line-height: 1.1; }
.depthome .banner { --tone: var(--band-to); }
/* (the 3px tone rule on cards is retired — white cards, colour in the section title and number) */
.depthome .section h2 { color: color-mix(in srgb, var(--tone) 60%, var(--ink)); }  /* .secblock re-sets --tone per section */
.depthome .section .badge { vertical-align: 0; }

/* Counties area (Aug 31 2026): the thirteen-county tab strip on #/counties —
   the agency department picker's county dive. Compact type so all fourteen
   names fit a desktop window; the row scrolls in place when they can't, with
   the right-edge fade saying "more →" (only visible once the tabs actually
   reach the edge). Sticky like every other page's one top row (Sep 4 2026):
   the county sheet below lost its own period topbar — one quarter-stepped
   window, no tabs — so this strip is the page's single sticky row (until
   then it was static, because two sticky rows would have stacked).
   These rules must sit AFTER the .topbar block (equal specificity — later
   wins; the Aug 25 mobile-pass lesson). */
/* zero flex-basis: the tab scroller fills leftover width but never forces the
   ask cluster onto a second line (basis auto would claim all 14 tabs' width
   first and wrap the row); the opened 💡 panel still wraps to its own
   full-width line via the .topbar .takeaways.open rule */
.topbar.cotabs .periodtabs { flex: 1 1 0; min-width: 0; overflow-x: auto; position: relative; }
.topbar.cotabs .periodtabs::after { content: ""; position: absolute; right: 0; top: 0; bottom: 0; width: 26px;
  background: linear-gradient(90deg, transparent, var(--page)); pointer-events: none; }
.topbar.cotabs .periodtabs button { font-size: 11.5px; padding: 12px 7px 10px; }

/* ---- Aug 31 2026 ease-of-use pass: mobile overflow fixes ----
   (sit at file end so equal-specificity overrides win — the Aug 25 lesson) */
/* insights band headers: the "all … insights ›" link must never force the row
   wide — wrap the head and let the link drop to its own line on phones */
.ins-group-head { flex-wrap: wrap; }
.ins-group-head .ins-link { min-width: 0; }
/* revenue-match running-position strip: 12 fixed columns out-span a phone —
   scroll inside the strip, never the page */
@media (max-width: 700px) {
  .mstrip { overflow-x: auto; }
  .mstrip-bars, .mstrip-labels { min-width: 520px; }
}
/* chart exact-value table (LineChart xt prop): compact, scrolls in place */
.chart-xt { overflow-x: auto; margin-top: 4px; }
.chart-xt table { border-collapse: collapse; width: 100%; font-variant-numeric: tabular-nums; }
.chart-xt th, .chart-xt td { font-size: 10.5px; padding: 3px 6px; text-align: right; white-space: nowrap; border-top: 1px solid var(--hairline); }
.chart-xt thead th { color: var(--muted); font-weight: 600; border-top: none; }
.chart-xt tbody th { text-align: left; color: var(--muted); font-weight: 600; }

/* ---- ✦ on every card and headline (Sep 2 2026) ----
   A small ask-glyph in each card's top-right corner (and beside each hero's
   spark) opens the Ask drawer already asking about that figure. Quiet until
   the card is hovered or focused; always faintly present where there is no
   hover (touch); gone in print. */
.card { position: relative; }
html:not(.askhost) .askc { display: none; }
.askc {
  position: absolute; top: 7px; right: 7px; width: 22px; height: 22px;
  display: grid; place-items: center; padding: 0; border: none; border-radius: 6px;
  font: inherit; font-size: 12px; line-height: 1; color: var(--accent); background: none;
  cursor: pointer; opacity: 0; transition: opacity 0.12s, background 0.12s;
}
.card:hover .askc, .card:focus-within .askc, .askc:focus-visible { opacity: 0.8; }
.askc:hover, .askc:focus-visible { opacity: 1; background: color-mix(in srgb, var(--accent) 12%, transparent); outline: none; }
.askc:focus-visible { box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 45%, transparent); }
@media (hover: none) { .askc { opacity: 0.5; } }
.ovhero .askc.hero { position: static; align-self: center; opacity: 0.55; margin-left: -2px; }
.ovhero:hover .askc.hero, .askc.hero:focus-visible { opacity: 1; }
/* the glyph rides right after the delta pill (markup order), so when the row wraps only the spark drops to the next line — never a lone ✦ */
.msg.user { white-space: pre-line; }
.chattip { font-size: 12px; color: var(--muted); margin: -4px 0 8px; }
.chattip::before { content: ""; }

/* ---- presentation mode (Sep 2 2026) ----
   html.present = the meeting-room view. The sidebar leaves, the content
   column scales up with CSS zoom (type, charts and tables grow together so
   the layout is the same one staff know), and the keyboard walks the page's
   sections (main.js usePresent). The pill is the only added chrome. */
html.present .sidebar { display: none; }
html.present .content { zoom: var(--present-zoom, 1.35); }
html.present .wrap { max-width: 1180px; padding-bottom: 96px; }
.pres-focus { animation: presfocus 1.6s ease-out both; border-radius: 12px; }
@keyframes presfocus {
  0% { box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 40%, transparent); }
  100% { box-shadow: 0 0 0 0 transparent; }
}
.presentbar {
  position: fixed; left: 50%; bottom: 16px; transform: translateX(-50%); z-index: 70;
  display: flex; align-items: center; gap: 8px; padding: 6px 8px 6px 14px;
  background: var(--surface); color: var(--ink-2); border: 1px solid var(--border);
  border-radius: 24px; box-shadow: 0 8px 28px rgba(0, 0, 0, 0.22); font-size: 12.5px; white-space: nowrap;
}
.presentbar .pb-word { font-weight: 650; color: var(--ink); }
.presentbar .pb-hint { color: var(--muted); }
.presentbar .pb-zoom { font-variant-numeric: tabular-nums; min-width: 38px; text-align: center; color: var(--ink); }
.presentbar .pb-btn {
  font: inherit; font-size: 13px; font-weight: 600; color: var(--ink); background: none;
  border: 1px solid var(--border); border-radius: 16px; padding: 3px 10px; cursor: pointer;
}
.presentbar .pb-btn:hover { border-color: var(--accent); color: var(--accent); }
.presentbar .pb-btn.exit { background: var(--accent); color: #fff; border-color: var(--accent); }
.presentbar .pb-btn.exit:hover { opacity: 0.9; color: #fff; }
.presentbar kbd { font: inherit; font-size: 11px; opacity: 0.8; margin-left: 4px; }
@media (max-width: 700px) { .presentbar .pb-hint { display: none; } }
@media (prefers-reduced-motion: reduce) { .pres-focus { animation: none; } }
@media print { .presentbar { display: none !important; } html.present .content { zoom: 1; } }
/* the meeting-room surround (Sep 8 2026): the page ground outside the column
   turns navy with the gold contour pinned bottom-right, and the column
   becomes a sheet — the same layout staff know, framed like a slide */
html.present body { background: #0d182b; }
html.present body::after { content: ""; position: fixed; right: 0; bottom: 0; width: 58vw; height: 26vw;
  background: url(art/contour-1160.webp) right bottom / contain no-repeat; opacity: 0.6; pointer-events: none; z-index: 0; }
html.present .content { background: transparent; position: relative; z-index: 1; }
html.present .areatabs { background: var(--page); max-width: 1180px; margin: 26px auto 0; border-radius: 22px 22px 0 0; }
html.present .wrap { background: var(--page); border-radius: 22px; padding: 28px 32px 96px; margin: 26px auto; box-shadow: 0 30px 80px rgba(0, 0, 0, 0.45); }
html.present .areatabs + .wrap { margin-top: 0; border-radius: 0 0 22px 22px; }
/* the title slide: dusk over the ridgelines, the page's name, the window, no figures */
.pres-title { position: fixed; inset: 0; z-index: 90; background: #03162c url(art/dusk-1920.webp) center / cover no-repeat;
  color: #f3efe6; padding: 9vh 8vw; cursor: pointer; animation: ptfade 0.15s ease-out both; }
.pres-title .pt-logo { height: 40px; width: auto; display: block; background: #fff; border-radius: 10px; padding: 8px 12px; margin-bottom: 7vh; }
.pres-title .pt-name { font-size: clamp(36px, 5vw, 64px); font-weight: 700; letter-spacing: -0.02em; line-height: 1.05; max-width: 22ch; }
.pres-title .pt-win { font-size: clamp(16px, 1.7vw, 24px); font-weight: 500; margin-top: 18px; opacity: 0.92; max-width: 60ch; }
.pres-title .pt-hint { position: absolute; left: 8vw; bottom: 7vh; font-size: 13px; letter-spacing: 0.08em; text-transform: uppercase; opacity: 0.6; }
@keyframes ptfade { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .pres-title { animation: none; } }
@media print { .pres-title, html.present body::after { display: none !important; }
  html.present .wrap, html.present .areatabs { box-shadow: none; background: none; padding: 0; margin: 0; border-radius: 0; } }

/* ---- the month in words (Sep 2 2026) ----
   narratives.js: the approved paragraph on a home page / year-in-review sheet
   (.narr) and the admin review queue on the Upload pages (.narrq). */
.narr { margin-top: 12px; background: var(--surface); border: 1px solid var(--border); border-left: 3px solid var(--tone, var(--accent)); border-radius: 12px; padding: 10px 14px 9px; }
.narr .narr-p { margin: 4px 0 6px; font-size: 14.5px; line-height: 1.6; color: var(--ink); max-width: 62ch; }
.narr .narr-foot { font-size: 11px; color: var(--muted); }
.paper .narr { margin: 10px 0 0; }
.narrq { margin: 0 0 14px; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 12px 14px; }
.narrq .nq-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.narrq .nq-title { font-size: 12px; font-weight: 650; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-2); }
.narrq .nq-sub { font-size: 12px; color: var(--muted); }
.narrq .nq-item { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--hairline); }
.narrq .nq-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 12.5px; }
.narrq .nq-row b { font-weight: 650; }
.narrq .nq-pill { font-size: 11px; padding: 2px 8px; border-radius: 12px; background: color-mix(in srgb, var(--accent) 12%, transparent); color: var(--ink-2); }
.narrq .nq-pill.warn { background: color-mix(in srgb, var(--bad) 14%, transparent); color: var(--bad); }
.narrq textarea { width: 100%; box-sizing: border-box; min-height: 120px; margin-top: 8px; font: inherit; font-size: 13px; line-height: 1.5; color: var(--ink); background: var(--page); border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; resize: vertical; }
.narrq .nq-preview { font-size: 13px; line-height: 1.5; margin: 6px 0 0; color: var(--ink-2); max-width: 80ch; }
.narrq .nq-preview p { margin: 0 0 6px; }
.narrq .nq-btns { display: flex; gap: 8px; margin-top: 8px; flex-wrap: wrap; }
.narrq .nq-btns button { font: inherit; font-size: 12.5px; font-weight: 600; padding: 5px 12px; border-radius: 8px; border: 1px solid var(--border); background: var(--surface); color: var(--ink); cursor: pointer; }
.narrq .nq-btns button:hover { border-color: var(--accent); }
.narrq .nq-btns button.primary { background: var(--accent); color: #fff; border-color: var(--accent); }
.narrq .nq-btns button:disabled { opacity: 0.5; cursor: default; }
.narrq .nq-err { color: var(--bad); font-size: 12px; margin-top: 6px; }
@media print { .narrq { display: none !important; } }

/* ---- proposed insights (Sep 2 2026, insightscan.js) ---- */
.ins-group.proposed .insight { border-left: 3px solid var(--tone, var(--accent)); }
.ins-group.proposed .ins-more { display: block; }
.ins-arith { font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; margin-top: 4px; line-height: 1.4; }
.ins-group.proposed .nq-btns { margin-top: 8px; }
.ins-group.proposed .nq-btns button { font: inherit; font-size: 12.5px; font-weight: 600; padding: 5px 12px; border-radius: 8px; border: 1px solid var(--border); background: var(--surface); color: var(--ink); cursor: pointer; }
.ins-group.proposed .nq-btns button.primary { background: var(--accent); color: #fff; border-color: var(--accent); }
.ins-group.proposed .nq-btns button:disabled { opacity: 0.5; cursor: default; }
@media print { .ins-group.proposed { display: none !important; } }
.ins-dropped { margin-top: 8px; font-size: 12px; color: var(--muted); }
.ins-dropped ul { margin: 6px 0 0 18px; padding: 0; line-height: 1.5; }
.ins-dropped li b { font-weight: 600; color: var(--ink-2); }

/* ---- workbook-check marks (Sep 4 2026): a figure the source itself disputes.
   The chip rides a hero row or a card under the delta; the mark rides a table
   cell. Icon + words, never colour alone (§14.6); both carry the check's text
   on hover, and the list lives under Workbook checks on Insights. ---- */
.checkchip { text-decoration: none; line-height: 1.7; }
.ovhero .row .checkchip { align-self: center; }
.card .checkchip { display: inline-block; margin-top: 6px; }
.ckmark { font-size: 10px; font-weight: 700; color: var(--bad); margin-left: 2px; cursor: help; }

/* ---- small multiples on Programs over the years (Sep 4 2026): one bar chart
   per program line on the same years; the unit toggle sits at the section's
   right edge; tiles are cards so the grid reads like the rest of the page ---- */
.smsec .seg { margin-left: auto; }
.smgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr)); gap: 14px; margin-top: 10px; }
.smtile { background: var(--surface); border: 1px solid transparent; box-shadow: var(--shadow-card); border-radius: 12px; padding: 10px 12px 6px; min-width: 0; }
.smtile .section { margin: 0 0 4px; }
.smtile h3 { font-size: 12.5px; font-weight: 650; margin: 0; color: var(--ink); }
.smtile .section .note { font-size: 11.5px; margin-left: 2px; }
.smtile .chartbox { margin: 0; }

/* ---- wide community-services tables: edge shadows say "more to the right"
   (Toolbox mobile rule; review Aug 23 B.23). The classic local/scroll trick:
   two surface-coloured covers scroll with the content and two soft shadows
   stay put, so a shadow shows only on an edge with more table beyond it. The
   frozen first column (table.heat .rowhead, sticky) keeps its own surface. ---- */
.cs .tablewrap { background:
  linear-gradient(90deg, var(--surface) 45%, transparent) left / 40px 100% no-repeat local,
  linear-gradient(270deg, var(--surface) 45%, transparent) right / 40px 100% no-repeat local,
  radial-gradient(farthest-side at 0 50%, color-mix(in srgb, var(--ink) 16%, transparent), transparent) left / 14px 100% no-repeat scroll,
  radial-gradient(farthest-side at 100% 50%, color-mix(in srgb, var(--ink) 16%, transparent), transparent) right / 14px 100% no-repeat scroll,
  var(--surface); }

/* ==== Finance analysis (#/fanalysis, Sep 4 2026) + the key-tile strip ==== */
/* Year hues — colour belongs to the YEAR (FY21 → --yr0 … FY27 → --yr6, then
   it wraps), so a year keeps its colour whichever year is in focus. Order
   validated with the dataviz palette checker Sep 4 2026 (adjacent-pair CVD
   ΔE ≥ 8, normal-vision ΔE ≥ 15, lightness band, chroma floor) for light and
   dark separately — the skill's reference categorical order, reversed so the
   newest years wear blue / orange. Light aqua sits at 2.8:1 on white (relief
   rule: every line is direct-labeled, the legend + exact tables carry
   identity). Tone-neutral: no agency strings here. */
:root {
  --yr0: #4a3aa7; --yr1: #008300; --yr2: #c2508a; --yr3: #b07600; --yr4: #1baf7a; --yr5: #eb6834; --yr6: #2571cf;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --yr0: #9085e9; --yr1: #008300; --yr2: #d55181; --yr3: #c98500; --yr4: #199e70; --yr5: #d95926; --yr6: #3987e5;
  }
}
:root[data-theme="dark"] {
  --yr0: #9085e9; --yr1: #008300; --yr2: #d55181; --yr3: #c98500; --yr4: #199e70; --yr5: #d95926; --yr6: #3987e5;
}
/* key tiles: label · big figure · one plain line (finance draw-gap + analysis) */
.ktiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 10px; margin: 2px 0 12px; }
.ktile { background: var(--surface); border: 1px solid transparent; box-shadow: var(--shadow-card); border-radius: 12px; padding: 10px 14px 9px; min-width: 0; }
.ktile .k { font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
.ktile .v { font-size: 24px; font-weight: 650; letter-spacing: -0.01em; margin-top: 2px; line-height: 1.15; }
.ktile.bad .v { color: var(--bad); }
.ktile.good .v { color: var(--good); }
.ktile .s { font-size: 12px; color: var(--ink-2); margin-top: 3px; line-height: 1.35; }
/* the page column widens for the big chart (the flowpage trick, capped) */
.wrap:has(.anlpage) { max-width: 1320px; }
.anlpage .anl-spacer { flex: 1 1 auto; }
.anlpage .ctlrow { justify-content: flex-start; }
.anlpage .ctlrow .fysel:last-child { margin-left: auto; }
.anl-sel { font-weight: 500; max-width: 240px; text-overflow: ellipsis; }
.anl-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 18px; flex-wrap: wrap; margin: 2px 0 12px; }
.anl-title h2 { font-size: 26px; font-weight: 650; letter-spacing: -0.015em; margin: 2px 0 0; line-height: 1.1; }
.anl-title .sub { font-size: 13px; color: var(--ink-2); margin-top: 3px; }
.anl-now { text-align: right; }
.anl-now .k { font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
.anl-now .v { font-size: 34px; font-weight: 650; letter-spacing: -0.02em; line-height: 1.05; margin-top: 2px; }
.anl-now .s { font-size: 12.5px; color: var(--ink-2); margin-top: 3px; }
.anl-delta { font-weight: 650; color: var(--ink); }
.anl-tiles { margin-bottom: 14px; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.anl-box { padding: 12px 10px 8px; }
.anlchart { width: 100%; height: auto; display: block; cursor: crosshair; outline: none; border-radius: 8px; }
.anlchart:focus-visible { outline: 2px solid var(--dept, var(--accent)); outline-offset: 3px; }
.anlchart .flag { font-size: 10.5px; font-weight: 650; fill: var(--page); }
.anlchart .dimmed { opacity: 0.18; }
.anlchart path, .anlchart circle, .anlchart g { transition: opacity 160ms ease; }
.anlchart .focusline { filter: drop-shadow(0 1px 2.5px color-mix(in srgb, var(--fc, var(--ink)) 45%, transparent)); }
.anlchart .anl-fill { pointer-events: none; }
.anl-stale { opacity: 0.55; transition: opacity 200ms; }
.anl-legend { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 4px; margin: 8px 2px 0; font-size: 12px; }
.anl-legend button {
  font: inherit; font-size: 12px; color: var(--ink-2); background: none; border: 1px solid transparent; border-radius: 999px;
  padding: 3px 10px 3px 8px; display: inline-flex; align-items: center; gap: 7px; cursor: pointer; line-height: 1.4;
}
.anl-legend button:hover { background: color-mix(in srgb, var(--ink) 5%, transparent); color: var(--ink); }
.anl-legend button:focus-visible { outline: 2px solid var(--dept, var(--accent)); outline-offset: 1px; }
.anl-legend button.off { color: var(--muted); }
.anl-legend button.off .lk { background: var(--hairline) !important; }
.anl-legend button.focus { font-weight: 650; color: var(--ink); }
.anl-legend button.focus .lk { height: 4px; }
.anl-legend button.aux { color: var(--muted); }
.anl-legend button.aux.on { color: var(--ink); background: color-mix(in srgb, var(--ink) 6%, transparent); }
.anl-legend .lk.band { height: 9px; width: 14px; border-radius: 2px; background: var(--muted); opacity: 0.3; }
.anl-legend .sep { width: 1px; height: 16px; background: var(--hairline); margin: 0 5px; }
.anlpage .lk, .hovertip .lk { width: 16px; height: 3px; border-radius: 2px; display: inline-block; vertical-align: middle; }
.anlpage td.rowhead .lk { margin-right: 8px; }
.hovertip.anl-tip { max-width: 260px; }
.hovertip .anl-row { white-space: nowrap; }
.hovertip .anl-row .lk { width: 12px; margin-right: 6px; }
.hovertip .anl-row.focus { font-weight: 650; }
.anl-details { margin-top: 12px; }
.anl-details summary { cursor: pointer; font-size: 13px; color: var(--ink-2); padding: 6px 0; }
.anl-details summary:hover { color: var(--ink); }
@media (max-width: 720px) {
  .anl-title h2 { font-size: 22px; }
  .anl-now { text-align: left; }
  .anl-now .v { font-size: 28px; }
  .anlchart { cursor: default; }
}
@media print {
  .anl-legend { display: none; }
}

/* ---- print: the general ledger (John, Sep 4 2026) ----
   "⎙ Print ledger" (gl.js) flips html.print-gl for the print dialog and adds a
   temporary landscape @page: the ledger table alone — cards, pickers, the
   shading note and the CSV row drop out; the header row repeats on every
   sheet; the frozen summary trio goes static so the columns share the page. */
.glprintline { display: none; }
@media print {
  .glprintline { display: block; margin: -2px 0 8px; font-size: 11px; color: #52514e; }
  html.print-gl .gl-full .grid2, html.print-gl .gl-full .sub, html.print-gl .takeaways,
  html.print-gl .printonly .takeaways { display: none !important; }
  html.print-gl .gl-full .tablewrap { break-inside: auto; border: none; }
  html.print-gl .gl-full table.heat { font-size: 8.5px; }
  html.print-gl .gl-full table.heat td, html.print-gl .gl-full table.heat th { font-size: 8.5px; padding: 2px 3px; }
  html.print-gl .gl-full table.heat td.rowhead { width: auto; min-width: 0; max-width: 175px; font-size: 9px; }
  html.print-gl .gl-full table.heat th.gltot, html.print-gl .gl-full table.heat td.gltot,
  html.print-gl .gl-full table.heat th.glvs, html.print-gl .gl-full table.heat td.glvs {
    position: static; width: auto; min-width: 0; }
  html.print-gl .gl-full table.heat thead { display: table-header-group; }
  html.print-gl .gl-full table.heat tr { break-inside: avoid; }
  html.print-gl .gl-full table.heat tr.sect td { padding-top: 6px; }
  html.print-gl .gl-full table.heat td.glvs > div { display: none; }   /* the tiny bars — the sign is written */
  html.print-gl .foot { font-size: 9px; }
}

/* ---- "how this number is found" tips (howtips.js, Sep 4 2026): the same
   dotted cue the Term explainer uses says "there is a how here"; the tip
   itself borrows the chart hover-tip; printing drops both. ---- */
[data-how] { text-decoration: underline dotted; text-decoration-color: var(--muted); text-underline-offset: 3px; cursor: help; }
[data-how]:hover, [data-how]:focus-visible { text-decoration-color: var(--accent); outline: none; }
.card .label[data-how] { align-self: flex-start; }   /* the card is a column flex box (inline-block would blockify): shrink the label to its words so the dotted cue underlines only them */
.hovertip.howtip { max-width: 330px; white-space: normal; }
.hovertip.howtip .k { display: block; font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; margin-bottom: 3px; opacity: 0.7; }
@media print { .howtip { display: none; } [data-how] { text-decoration: none; } }

/* ---- county rows are doors to the trace drawer (provenance, Sep 4 2026):
   the county name is a button that reads as a name, with the app's " ›"
   door cue; print drops the cue ---- */
.rowtrace { all: unset; cursor: pointer; color: inherit; font: inherit; }
.rowtrace::after { content: " ›"; color: var(--muted); font-size: 11px; }
.rowtrace:hover, .rowtrace:focus-visible { color: var(--accent); text-decoration: underline; }
@media print { .rowtrace::after { content: ""; } }

/* ---- program-year goal lines under community heroes and cards (Sep 4 2026):
   a neutral bullet while the year runs, met/missed colour only when it is
   complete; the bullet scales to the card ---- */
.goalline { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 6px; font-size: 12px; color: var(--ink-2); line-height: 1.35; }
.goalline svg.bullet { width: 150px; height: auto; max-width: 100%; }
.card .goalline { font-size: 11.5px; margin-top: 5px; }
.card .goalline svg.bullet { width: 120px; }

/* ---- Sep 7 2026 "addition by subtraction" pass ----
   (append-only, agency-string-free; equal-specificity overrides sit after
   their base rules per the Aug 25 lesson) */
/* the whole-agency Home's one grid: the department bands and the window's
   paragraph as EQUAL cells — same footprint each, stretched to one height,
   wrapping 3 → 2 → 1 as the window narrows; a new department = one more cell */
.homegrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); gap: 14px; margin-top: 8px; align-items: stretch; }
.homegrid > .deptband, .homegrid > .narr { margin-top: 0; }
/* the paragraph as a band: the agency tone, the same section header as the
   department bands, the text at reading size, an honest empty state */
.deptband.words { --tone: var(--chip-agency); display: flex; flex-direction: column; }
.deptband.words .narr-p { margin: 6px 0 8px; font-size: 14px; line-height: 1.6; color: var(--ink); }
.deptband.words .narr-foot { margin-top: auto; font-size: 10.5px; color: var(--muted); line-height: 1.4; }
.deptband.words .narr-empty { margin-top: 6px; font-size: 12.5px; line-height: 1.5; color: var(--muted); max-width: 46ch; }
/* agency Insights = a department index: one tinted card per department,
   the open count as a badge, the top headlines as plain doors — no card
   chrome, no bodies (those live on the department page) */
.insdex { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); gap: 14px; margin-top: 8px; align-items: start; }
.insdex .insdex-card { margin-top: 0; }
.insdex .insdex-sub { font-size: 12px; color: var(--muted); margin: -2px 0 8px; }
.insdex .insdex-empty { font-size: 13px; color: var(--ink-2); line-height: 1.5; padding: 8px 10px; background: var(--surface); border: 1px solid var(--border); border-radius: 9px; }
.insdex .lead-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.insdex .lead-list a { display: flex; align-items: baseline; gap: 8px; text-decoration: none; color: var(--ink);
  font-size: 13px; line-height: 1.4; padding: 7px 10px; border-radius: 9px; background: var(--surface); border: 1px solid var(--border);
  transition: border-color 0.12s, transform 0.12s, box-shadow 0.12s; }
.insdex .lead-list a:hover { border-color: color-mix(in srgb, var(--tone) 45%, var(--border)); transform: translateY(-1px); box-shadow: var(--shadow-card); }
.insdex .lead-list .cat { flex: none; font-size: 9.5px; font-weight: 650; letter-spacing: 0.06em; text-transform: uppercase;
  color: color-mix(in srgb, var(--tone) 55%, var(--ink)); background: color-mix(in srgb, var(--tone) 11%, transparent); border-radius: 7px; padding: 2px 7px; }
.insdex .lead-list .t { min-width: 0; }
.insdex .lead-list .go { margin-left: auto; color: var(--muted); flex: none; }
.insdex .insdex-more { margin-top: 6px; font-size: 12px; }
.insdex .insdex-more a { color: var(--accent); text-decoration: none; }
.insdex .insdex-more a:hover { text-decoration: underline; text-underline-offset: 3px; }
@media print { .insdex .lead-list a { border-color: #ddd; } }
/* three cells share the row on a desktop, so the dense bands pack a size
   tighter than the old two-across grid: three cards per row from ~340px
   of band width (the 116px floor gave two) */
.homegrid .deptband.dense .cards { grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); }

/* ---- Sep 8 2026 fix pass (shell) ---- */
/* fixed-route stop map stacks on a phone: .mapgrid.go (0,2,0) outranked the .mapgrid
   stacking rule at max-width 900px (0,1,0), so the map collapsed to 7px */
@media (max-width: 900px) { .mapgrid.go { grid-template-columns: 1fr; } }
/* dark theme: the rail's department chip (white initials on the lifted dark
   tokens) sat at 2.2–2.8:1; near-black ink on those tokens clears 8:1. The
   transportation green is the one token dark enough that white (4.9:1) beats
   black (3.9:1), so it keeps white — the aside carries data-dept. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .sidebar .deptbtn .chip { color: var(--page); }
  :root:not([data-theme="light"]) .sidebar[data-dept="transit"] .deptbtn .chip { color: #fff; }
}
:root[data-theme="dark"] .sidebar .deptbtn .chip { color: var(--page); }
:root[data-theme="dark"] .sidebar[data-dept="transit"] .deptbtn .chip { color: #fff; }

/* Sep 8 2026: native file/month inputs are wider than a phone card in Chrome (sweep: #/upload +61px at 375) */
.card input[type="file"], .card input[type="month"] { max-width: 100%; box-sizing: border-box; }

/* Sep 8 2026: a segmented control inside an inline wrapper could not honour its phone max-width (sweep: #/finance "Waiting on draws" department segment +133px at 375 once the mock grew more departments) */
span.noprint:has(> .seg) { display: block; max-width: 100%; min-width: 0; }
.card input[type="month"] { min-width: 0; flex: 1 1 0; width: 0; }

/* ---- the sign-in wall (Sep 8 2026) ---- */
.loginwall { min-height: 100vh; display: grid; grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
.loginart { display: none; }
.loginpane { display: flex; align-items: flex-start; justify-content: center; padding: 0 16px; }
@media (min-width: 900px) {
  .loginwall { grid-template-columns: 46% 1fr; grid-template-rows: 1fr; }
  .loginart { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 26px; background: #24303f; padding: 40px; }
  .loginart-img { width: min(420px, 82%); height: auto; display: block; }
  .loginart-cap { color: #f3efe6; font-size: 12.5px; font-weight: 500; letter-spacing: 0.12em; text-transform: uppercase; text-align: center; }
  .loginpane { align-items: center; padding: 24px; }
  .loginpane .login { margin: 0; width: 100%; }
}
@media (max-width: 899px) {
  .loginart { display: block; height: 108px; background: #24303f url(art/arch-440.webp) center 42% / auto 240% no-repeat; }
  .loginart picture, .loginart-cap { display: none; }
  .loginpane .login { margin: 22px auto 10vh; }
}

/* ---- the paper masthead (Sep 8 2026): hairline + a short gold rule ---- */
.ye-head.masthead { border-bottom: 1px solid #d9d7d0; padding-bottom: 10px; position: relative; }
.ye-head.masthead::after { content: ""; position: absolute; left: 0; bottom: -2px; width: 56px; height: 3px; background: #c49132;
  print-color-adjust: exact; -webkit-print-color-adjust: exact; }

/* ---- Sep 8 2026: editorial "in words" type (#5), empty states (#6),
   hero step in presentation (#7), sidebar whisper (#9), dark sign-in (#10a) ---- */
.narr .narr-p .lede, .deptband.words .narr-p .lede { font-weight: 600; }
.narr .narr-p:first-of-type::before, .deptband.words .narr-p:first-of-type::before { content: ""; display: block; width: 28px; height: 2px; background: var(--tone, var(--accent)); margin: 2px 0 8px; }
.paper .narr .narr-p { font-size: 13.5px; line-height: 1.55; max-width: 76ch; }
.paper .narr .narr-p::before { display: none; }
html.present .narr .narr-p, html.present .deptband.words .narr-p { font-size: 16px; }
html.present .ovhero .n { font-size: 56px; }
.empty { display: flex; align-items: flex-start; gap: 12px; padding: 14px 6px; color: var(--muted); }
.empty-glyph { flex: none; margin-top: 1px; }
.empty-t { font-size: 13.5px; color: var(--ink-2); line-height: 1.4; }
.empty-why { font-size: 12px; color: var(--muted); margin-top: 2px; line-height: 1.4; }
.sidebar .deptbtn .dot.pennant, .sidebar .deptmenu .dot.pennant { width: 10px; height: 12px; border-radius: 0; background: none; color: var(--side-ink-dim); }
.sidebar::after { content: ""; position: absolute; right: 0; bottom: 0; width: 240px; height: 108px;
  background: url(art/contour-480.webp) right bottom / 240px auto no-repeat; opacity: 0.06; pointer-events: none; }
@media (max-width: 1100px) { .sidebar::after { display: none; } }
@media print { .sidebar::after { display: none; } }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .sidebar::after { opacity: 0.12; }
  :root:not([data-theme="light"]) .loginart { background-image: url(art/dusk-1280.webp); background-size: cover; background-position: center; }
  :root:not([data-theme="light"]) .loginart picture { display: none; }
}
:root[data-theme="dark"] .sidebar::after { opacity: 0.12; }
:root[data-theme="dark"] .loginart { background-image: url(art/dusk-1280.webp); background-size: cover; background-position: center; }
:root[data-theme="dark"] .loginart picture { display: none; }
:root[data-theme="light"] .loginart picture { display: block; }

/* ==== Sep 8 2026 polish pass (John's page-by-page notes): bundles on the transportation home, ledger summary columns to the right, Analysis axis fit, Facilities + Finance-departments at-a-glance bands ==== */

/* ---- Sep 8 2026 polish pass (home.js, Transportation home) ---- */
/* Money bundles (John, Sep 8 2026): the Cost & efficiency / Revenues /
   Expenses cards regrouped into three deptband bundles in the glance band's
   language, sharing one .homegrid row under the Overview. The dense band
   rules already size the hero (.deptband.dense .ovhero); these only fit the
   story line to a third-width cell and give the no-books-yet state one
   muted line. The tone is set inline per bundle (--tone), so the tint,
   border and title colour follow the chip with no colour named here. */
.deptband.bundle .ovhero .story { font-size: 12.5px; max-width: 48ch; }
.deptband.bundle .ovhero .u { font-size: 12px; }
.deptband.bundle .bundle-empty { margin: 2px 0 4px; font-size: 12.5px; line-height: 1.5; color: var(--muted); }
@media print { .deptband.bundle .ovhero .story { font-size: 12px; } }

/* Trips year by year (John, Sep 8 2026): "more distinct and differentiated
   than the actual table data" — the header row wears a tint of the ops
   chip, upper-case dark type and a heavier rule beneath; the sticky FY
   rowhead in the header takes the same tint (it carries its own surface at
   (0,3,1) via .tablewrap .heat th.rowhead, so these sit at (0,3,3)); the
   body's FY cells go a step bolder so the year column reads as a header
   column too. color-mix against var(--surface) adapts to dark mode. */
table.heat.yrtbl thead th {
  background: color-mix(in srgb, var(--chip-ops) 12%, var(--surface));
  color: var(--ink); font-weight: 700; font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase;
  border-bottom: 2px solid color-mix(in srgb, var(--chip-ops) 45%, var(--hairline));
}
table.heat.yrtbl thead th.rowhead { background: color-mix(in srgb, var(--chip-ops) 12%, var(--surface)); color: var(--ink); }
table.heat.yrtbl tbody td.rowhead { font-weight: 600; }

/* ---- General ledger: Total + vs-prior move to the RIGHT of the table (John,
   Sep 8 2026 — "it looks better that way"). Reverses the Aug 27 frozen trio
   above: the account column stays pinned on its own, the months read Jul …
   Jun, and the summary pair closes the row. Widths keep the Aug 27 values
   (and the ≤700px fallback still sets them to auto) — only the offsets and
   the interior borders change. Appended after the gl-full block, so equal
   specificity wins here. */
.gl-full table.heat td.gltot, .gl-full table.heat td.glvs {
  position: static; left: auto; z-index: auto; background: transparent; }
/* header cells keep the sticky TOP that every thead th has; only the left
   pin goes */
.gl-full table.heat th.gltot, .gl-full table.heat th.glvs { position: sticky; left: auto; top: 0; }
/* the Total column regains .annual's left divider (the frozen trio had
   dropped it because the rowhead's border-right already drew that line) and
   the vs column loses the frozen-edge border-right — the table edge closes it */
.gl-full table.heat th.gltot, .gl-full table.heat td.gltot { border-left: 1px solid var(--hairline); }
.gl-full table.heat th.glvs, .gl-full table.heat td.glvs { border-right: none; }
/* unfrozen, the pair takes the row hover like every other cell (the old
   surface background used to mask it) */
.gl-full table.heat tr.hoverable:hover td.gltot, .gl-full table.heat tr.hoverable:hover td.glvs {
  background: color-mix(in srgb, var(--accent) 7%, var(--surface)); }

/* Analysis tab — fit-the-axis rule (Sep 8 2026): the Auto · On · Off
   control in the legend row, and the honesty marks on a fitted axis
   (axis-break glyph + caption drawn in the SVG). */
.anl-legend .anl-fit { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); font-size: 12px; }
.anl-legend .anl-fit .seg { padding: 2px; border-radius: 7px; }
.anl-legend .anl-fit .seg button { padding: 1px 8px; border-radius: 5px; font-size: 11.5px; gap: 0; }
.anlchart .anl-fitnote { font-size: 10.5px; fill: var(--muted); font-style: italic; }
.anlchart .anl-break { pointer-events: none; }

/* Facilities at-a-glance panel (Sep 8 2026): the map and the glance band
   share a grid2; the band stacks three blocks (account split · costliest ·
   movers), so its later section heads need the spacing the deptband rule
   removes, and the account-split legend fits five parts in two columns */
.facglance .deptband .section { margin-top: 14px; margin-bottom: 6px; }
.facglance .deptband .section:first-child { margin-top: 0; }
.facglance .breakdown { padding: 10px 12px; }
.facglance .breakdown .bk-total b { font-size: 18px; }
.facglance .breakdown .bk-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
.facglance .ranklist .rankrow { font-size: 12.5px; padding: 5px 10px; }
.facglance .ranklist .rankrow:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.depthome .sub.faclead { display: block; margin: 16px 0 6px; font-size: 13px; color: var(--ink-2); }

/* ---- #/fdepts Departments view: the at-a-glance band (Sep 8 2026) ----
   John: "is this page represented in the most easy to understand way … unique
   and useful insights at a glance?" The band sits between the hero and the
   exact-figures table in the finance tone, two columns: where the money goes
   (ShareBars, expenses vs revenues on one scale + a swatch/name/dollars key
   line so colour never stands alone, §14.6) and what moved vs the prior year's
   same months (a rankrow list; the proportional bar tints --bad for spent-more
   and --good for spent-less, the ▲/▼ glyph and the printed sign carry the
   direction for everyone). A one-line surplus/deficit count closes the band. */
.fd-glance .fd-glance-grid { margin-top: 2px; }
.fd-glance .fd-glance-sub { color: var(--muted); font-size: 12px; margin: 2px 0 6px; }
.fd-glance .vizbox { padding: 6px 10px 4px; }
.fd-key { display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 6px 0 0 2px; font-size: 12px; }
.fd-key-item { white-space: nowrap; }
.fd-key-item b { font-weight: 600; color: var(--ink); }
.fd-key-item .fd-key-v { color: var(--muted); margin-left: 5px; font-variant-numeric: tabular-nums; }
.fd-move .rankrow { grid-template-columns: 18px 1fr auto minmax(72px, auto); }
.fd-move .rankrow .rk { font-size: 10px; }
.fd-move .rankrow.up .vl { color: var(--bad); }
.fd-move .rankrow.down .vl { color: var(--good); }
.fd-move .rankrow .bar.up { background: color-mix(in srgb, var(--bad) 13%, transparent); }
.fd-move .rankrow .bar.down { background: color-mix(in srgb, var(--good) 14%, transparent); }
.fd-glance-empty { color: var(--muted); font-size: 12.5px; padding: 10px 2px; }
.fd-net { margin-top: 10px; padding-top: 8px; border-top: 1px solid color-mix(in srgb, var(--tone) 22%, var(--hairline));
  color: var(--ink-2); font-size: 12.5px; }
.fd-net b { color: var(--ink); }
.fd-tablelead { color: var(--muted); font-size: 12.5px; margin: 16px 0 6px 2px; }
@media print { .fd-move .rankrow { break-inside: avoid; } }
/* Roster & retention as its own Our People tab (John, Sep 8 2026): the roster
   + roster-changes tables were paper-only on the Drivers page; on the new tab
   they are the page, so they show on screen too. The print flip still works
   (html.print-drroster hides everything else, and this block stays visible). */
.drivers.drivers-roster .drroster-only { display: block; }

/* ---- Sep 8 2026: maintenance vendor split (#/maint, maint.js) ---- */
.mv-tag { display: inline-block; margin-left: 6px; padding: 0 6px; border-radius: 8px; font-size: 10px; font-weight: 600; letter-spacing: 0.03em;
  color: var(--ink-2); background: color-mix(in srgb, var(--c, var(--muted)) 16%, var(--surface)); border: 1px solid color-mix(in srgb, var(--c, var(--muted)) 40%, transparent); vertical-align: 1px; }
.maintsplit .rankrow:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
@media print { .mv-tag { border: none; background: none; } }

/* ---- Sep 8 2026: movement + the Canva spots (see the MOTION INVENTORY) ---- */
@keyframes flagwave { 0%, 100% { transform: skewY(0); } 50% { transform: skewY(-7deg); } }
.empty-glyph .flag { transform-box: fill-box; transform-origin: 0 50%; animation: flagwave 3.2s ease-in-out infinite; }
.sidebar .deptbtn:hover .pennant path:last-child, .sidebar .deptbtn:focus-visible .pennant path:last-child {
  transform-box: fill-box; transform-origin: 0 50%; animation: flagwave 1.1s ease-in-out 2; }
.ovhero .spark path.sl { stroke-dasharray: 1; animation: draw 0.9s ease-out both; }
@keyframes growx { from { transform: scaleX(0); } to { transform: none; } }
.sbseg { transform-origin: 0 50%; animation: growx 0.55s cubic-bezier(0.2, 0.7, 0.3, 1) both; animation-delay: calc(var(--i, 0) * 45ms); }
.pres-title .pt-contour { position: absolute; left: 0; right: 0; bottom: 0; width: 100%; height: 34vh; pointer-events: none; }
.pres-title .pt-contour .ridge { stroke-dasharray: 1; animation: draw 2.4s cubic-bezier(0.3, 0.6, 0.2, 1) 0.2s both; }
.pres-title .pt-contour .ridge.r2 { animation-delay: 0.6s; }
@keyframes breathe { from { transform: scale(1); } to { transform: scale(1.025); } }
.loginart-img { animation: breathe 16s ease-in-out infinite alternate; }
/* the spot on a cream tile beside an empty state; the words cell centers it */
.empty.with-art { align-items: center; }
.empty-art { flex: none; margin-left: auto; width: 160px; height: auto; border-radius: 10px; background: #fff3dc; }
.deptband.words .narr-empty { max-width: none; }
.deptband.words .narr-empty .empty { flex-direction: column; align-items: flex-start; gap: 10px; padding: 10px 2px 4px; }
.deptband.words .narr-empty .empty-art { margin: 4px 0 0; width: min(100%, 300px); }
@media (max-width: 520px) { .empty-art { width: 112px; } }
@media print { .empty-art { display: none; } }

/* ---- Sep 8 2026: page-enter rise (the sidebar spot tile of the same hour was retired for Option C) ---- */
/* backwards, NOT both (Sep 9 2026, John: the home drawers stopped scrolling):
   a forwards-filled transform animation leaves the finished element with a
   computed transform (Chrome reports the identity matrix, not none), which
   makes it the containing block for every position:fixed descendant — the
   drill-down drawer was sized to the page body, not the viewport. Anything
   that wraps a drawer must never carry a filled transform animation. */
.pagebody { animation: rise 0.35s cubic-bezier(0.2, 0.7, 0.3, 1) backwards; }
@media (prefers-reduced-motion: reduce) { .pagebody { animation: none; } }
/* the sign-in arch breath, made visible (16 s → 9 s, 1.025 → 1.04) */
.loginart-img { animation: breathe 9s ease-in-out infinite alternate; }
@keyframes breathe { from { transform: scale(1); } to { transform: scale(1.04); } }

/* ---- Sep 8 2026 (night): the editorial "in words" sheet (narratives.js editorial) ---- */
.narr.editorial { margin: 18px 0 4px; padding: 14px 0 10px; background: transparent; border: none; border-radius: 0;
  border-top: 1.5px solid var(--ink); border-bottom: 1px solid var(--hairline); }
.narr.editorial .ed-kicker { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.narr.editorial .ed-head { font-size: 11.5px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink); }
.narr.editorial .ed-date { font-family: "Newsreader", Georgia, "Times New Roman", serif; font-style: italic; font-size: 14px; color: var(--muted); margin-left: 2px; }
.narr.editorial .ed-body { column-count: 2; column-gap: 48px; column-rule: 1px solid var(--hairline); }
.narr.editorial .narr-p { font-family: "Newsreader", Georgia, "Times New Roman", serif; font-size: 18px; line-height: 1.55; color: var(--ink);
  max-width: none; margin: 0 0 12px; text-wrap: pretty; hyphens: auto; }
.narr.editorial .narr-p:first-of-type::before { display: none; }
.narr.editorial .narr-p:first-of-type::first-letter { font-family: "Newsreader", Georgia, serif; font-weight: 500; font-size: 3.6em; line-height: 0.8;
  float: left; padding: 7px 9px 0 0; color: var(--tone, var(--accent)); }
.narr.editorial .narr-p .lede { font-weight: 600; }
.narr.editorial .narr-foot { margin-top: 2px; font-size: 11px; color: var(--muted); }
.narr.editorial .narr-empty .empty { padding: 6px 0 4px; }
@media (max-width: 900px) { .narr.editorial .ed-body { column-count: 1; } .narr.editorial .narr-p { font-size: 17px; } }
html.present .narr.editorial .narr-p { font-size: 21px; line-height: 1.5; }
@media print { .narr.editorial .ed-body { column-count: 1; } .narr.editorial .narr-p { font-size: 13.5px; } }
/* phone: the kicker wraps and long words break inside the sheet (sweep, Sep 8 night) */
.narr.editorial { min-width: 0; overflow-wrap: anywhere; }
.narr.editorial .ed-kicker { flex-wrap: wrap; row-gap: 2px; }
.narr.editorial .narr-p { overflow-wrap: anywhere; }
/* presentation mode on a phone: the 56 px hero number out-spanned a 375 px
   sheet (sweep, Sep 8 night) — cap it under 520 px */
@media (max-width: 520px) { html.present .ovhero .n { font-size: 34px; } }

/* ---- Sep 9 2026: art round three (John picked D + E) ----
   D · the END-MARK: the page's piece, knocked out of its ground, right-aligned
   under the last foot note — the reader's stopping point, smaller than any
   figure, kept in print; gone in presentation (it would be a stray section).
   E · the COVER: the piece as a wide band across the top of the paper sheets
   (Year in review ×3, Finance packet), a white fade into the masthead. */
.endmark { display: flex; justify-content: flex-end; margin-top: 10px; }
.endmark .em-art { display: block; width: 170px; height: auto; opacity: 0.94; }
@media (max-width: 700px) { .endmark .em-art { width: 120px; } }
@media print { .endmark { break-inside: avoid; margin-top: 6px; } .endmark .em-art { width: 130px; } }
html.present .endmark { display: none; }
.ye-cover { height: 150px; overflow: hidden; background: #fff3dc; border-radius: 8px; margin-bottom: 12px;
  display: flex; justify-content: flex-end; align-items: flex-end; padding-right: 22px; box-sizing: border-box; }
.ye-cover img { display: block; height: 150px; width: auto; }        /* the whole piece, 4:3, on its own cream */
.yearend .paper .ye-cover { margin: -24px -26px 12px; border-radius: 6px 6px 0 0; }   /* bleeds to the sheet's edges */
.fpacket .ye-cover { height: 120px; } .fpacket .ye-cover img { height: 120px; }
@media (max-width: 720px) { .ye-cover { height: 110px; padding-right: 12px; } .ye-cover img { height: 110px; } }
@media print {
  .ye-cover { height: 120px; border-radius: 0; print-color-adjust: exact; -webkit-print-color-adjust: exact; }
  .ye-cover img { height: 120px; }
  .yearend .paper .ye-cover { margin: 0 0 10px; }
  .ye-mast { break-inside: avoid; }
}
}

/* ---- Sep 8 2026 (night, 5): Option C — the piece inside the editorial sheet ---- */
.narr.editorial .ed-grid { display: grid; grid-template-columns: 260px minmax(0, 1fr); gap: 28px; align-items: start; }
.narr.editorial .ed-art { display: block; width: 100%; height: auto; border-radius: 10px; background: #fff3dc; }
.narr.editorial .ed-text { min-width: 0; }
@media (max-width: 900px) { .narr.editorial .ed-grid { grid-template-columns: 1fr; gap: 12px; } .narr.editorial .ed-art { width: min(100%, 260px); } }
html.present .narr.editorial .ed-grid { grid-template-columns: 320px minmax(0, 1fr); }
@media print { .narr.editorial .ed-grid { grid-template-columns: 1fr; } .narr.editorial .ed-art { display: none; } }
/* the page's piece on the presentation title slide */
.pres-title .pt-spot { position: absolute; right: 8vw; top: 50%; transform: translateY(-50%); width: min(30vw, 420px); height: auto;
  border-radius: 14px; background: #fff3dc; box-shadow: 0 24px 70px rgba(0, 0, 0, 0.45); }
@media (max-width: 900px) { .pres-title .pt-spot { display: none; } }

/* ---- Sep 8 2026 (night, 5): the editorial look on every Insights page ----
   The card chrome (tint wash, rounded box, accent rail) goes; each insight is
   an article: category as a small-caps kicker in its area's tone, the
   headline and body in Newsreader, hairline rules between, the area's name as
   a serif section head. Proposed (assistant) findings keep a thin rule in
   their tone so they still read as proposals. */
.insights { gap: 0; }
.insight { background: none; border: none; border-top: 1px solid var(--hairline); border-radius: 0; padding: 16px 2px 14px; transition: none; }
.insights .insight:first-child { border-top: none; }
.insight:hover { border-color: var(--hairline); box-shadow: none; }
.ins-group-head { border-bottom: 1.5px solid var(--ink); padding-bottom: 8px; margin-bottom: 4px; align-items: baseline; }
.ins-group-head h2 { font-family: "Newsreader", Georgia, "Times New Roman", serif; font-size: 24px; font-weight: 600; letter-spacing: -0.01em; line-height: 1.1; }
.ins-group-head .aud { font-family: "Newsreader", Georgia, serif; font-style: italic; font-size: 14px; }
.ins-head { margin-bottom: 6px; gap: 10px 12px; }
.ins-cat { background: none; padding: 0; border-radius: 0; font-size: 10.5px; letter-spacing: 0.1em; font-weight: 700; color: color-mix(in srgb, var(--instone) 70%, var(--ink)); }
.ins-title { font-family: "Newsreader", Georgia, "Times New Roman", serif; font-size: 20px; font-weight: 600; line-height: 1.25; letter-spacing: -0.01em; color: var(--ink); text-wrap: pretty; }
.ins-chev { font-size: 11px; align-self: center; }
.ins-body { font-family: "Newsreader", Georgia, "Times New Roman", serif; font-size: 16.5px; line-height: 1.55; color: var(--ink); max-width: 70ch; text-wrap: pretty; }
.ins-rec { font-family: "Newsreader", Georgia, "Times New Roman", serif; font-size: 16px; line-height: 1.5; max-width: 70ch; margin-top: 8px; }
.ins-rec span { font-family: "Public Sans", system-ui, sans-serif; font-size: 10.5px; letter-spacing: 0.1em; }
.ins-more { margin-top: 4px; }
.ins-link { font-size: 12.5px; }
.ins-group.proposed .insight { border-left: 2px solid var(--tone, var(--accent)); padding-left: 14px; }
.insdex .lead-list a, .insdex .lead-list li { font-family: "Newsreader", Georgia, serif; font-size: 16px; line-height: 1.4; }
html.present .ins-title { font-size: 24px; } html.present .ins-body, html.present .ins-rec { font-size: 19px; }
@media print { .insight { break-inside: avoid; } .ins-body, .ins-rec { font-size: 13px; } }
