/* ===========================================================================
 * vanshOS — design system v1.0
 *
 * Translates the Brand Book tokens onto every class already used by the
 * 42 Jinja templates. No template markup changes required.
 *
 * Sections:
 *   1.  @font-face        — self-hosted Geist / Spectral / Geist Mono
 *   2.  Tokens            — palette, type, rhythm
 *   3.  Reset + base typo
 *   4.  Brand mark        — the vanshOS logotype
 *   5.  Layout            — topbar / subnav / main / page-wide / two-col
 *   6.  Buttons           — .btn / .btn--primary / .btn--ghost
 *   7.  Forms             — .form / .form-grid / inputs / textareas
 *   8.  Cards             — .auth-card / .error-card / .dashboard
 *   9.  Flash messages
 *  10.  Tables            — .data-table / .admin-table / .bulk-table / matrix
 *  11.  KPI grid
 *  12.  Filter bar
 *  13.  Pagination
 *  14.  Direction badges  — inflow / outflow / other
 *  15.  Wizard progress
 *  16.  Misc utilities    — .muted / .kv / .color-chip / .preferred-banks
 * ===========================================================================
 */

/* ---------------------------------------------------------------------------
 * 1. @font-face — Latin subset only. Other Unicode ranges fall back to the
 *    OS-provided sans/serif stack via the var(--sans) / var(--serif) chain.
 * --------------------------------------------------------------------------- */
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("/static/fonts/geist-300.woff2") format("woff2");
}
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/static/fonts/geist-400.woff2") format("woff2");
}
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/static/fonts/geist-500.woff2") format("woff2");
}
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/static/fonts/geist-600.woff2") format("woff2");
}
@font-face {
  font-family: "Geist Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/static/fonts/geist-mono-400.woff2") format("woff2");
}
@font-face {
  font-family: "Geist Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/static/fonts/geist-mono-500.woff2") format("woff2");
}
@font-face {
  font-family: "Spectral";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("/static/fonts/spectral-300.woff2") format("woff2");
}
@font-face {
  font-family: "Spectral";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/static/fonts/spectral-400.woff2") format("woff2");
}
@font-face {
  font-family: "Spectral";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/static/fonts/spectral-500.woff2") format("woff2");
}
@font-face {
  font-family: "Spectral";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/static/fonts/spectral-600.woff2") format("woff2");
}
@font-face {
  font-family: "Spectral";
  font-style: italic;
  font-weight: 300;
  font-display: swap;
  src: url("/static/fonts/spectral-300-italic.woff2") format("woff2");
}
@font-face {
  font-family: "Spectral";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("/static/fonts/spectral-400-italic.woff2") format("woff2");
}
@font-face {
  font-family: "Spectral";
  font-style: italic;
  font-weight: 500;
  font-display: swap;
  src: url("/static/fonts/spectral-500-italic.woff2") format("woff2");
}

/* ---------------------------------------------------------------------------
 * 2. Tokens — straight from the Brand Book.
 * --------------------------------------------------------------------------- */
:root {
  /* Surface — warm paper */
  --ivory:  #f6f4ef;
  --paper:  #fbfaf6;
  --sand:   #ece6d8;
  --bone:   #e6e0d1;
  /* Elevated surface for floating cards, dropdowns, input backgrounds.
     Same tone as --paper in the light themes; per-theme overrides
     adjust this for dark themes (where it needs to be brighter than
     --paper so floating popovers read cleanly above the page). */
  --card:   #ffffff;

  /* Foreground "on dark" — always the SAME light cream regardless of
     theme. Use this for text that sits on an intrinsically dark
     background like the .btn--primary forest fill or the matrix
     header band. NOT redefined in any [data-theme=...] block — that's
     the whole point: it stays light so contrast doesn't break when
     the page tokens flip to a dark palette.
     The bug pattern this fixes: ``color: var(--paper)`` on a
     forest-bg button gives cream text in light theme (good) but
     dark-grey-near-black text in ink theme (invisible). */
  --on-dark: #f6f4ef;

  /* Ink — primary text + alpha ladder for muted/dividers */
  --ink:     #181a17;
  --ink-80:  rgba(24, 26, 23, 0.80);
  --ink-65:  rgba(24, 26, 23, 0.65);
  --ink-45:  rgba(24, 26, 23, 0.45);
  --ink-25:  rgba(24, 26, 23, 0.25);
  --ink-12:  rgba(24, 26, 23, 0.12);
  --ink-07:  rgba(24, 26, 23, 0.07);

  /* Forest — primary brand (green) */
  --forest:       #1a2e1f;
  --forest-deep:  #0f1d13;
  --forest-mid:   #2a4631;
  --forest-pale:  #d6dcd2;

  /* Bronze — secondary brand (warm tan) */
  --bronze:       #7a6648;
  --bronze-mid:   #a08868;
  --bronze-pale:  #d9cdb7;

  /* State */
  --positive: #406b48;
  --warn:     #a47428;
  --negative: #8a3a2e;
  --positive-bg: #e3ebdb;
  --warn-bg:     #f4ebda;
  --negative-bg: #f0dfd9;

  /* Type stacks */
  --serif: "Spectral", "Times New Roman", Georgia, serif;
  --sans:  "Geist", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  --mono:  "Geist Mono", ui-monospace, "SF Mono", Menlo, monospace;

  /* Rhythm */
  --rule:       1px solid var(--ink-12);
  --rule-soft:  1px solid var(--ink-07);
  --pad-page:   clamp(24px, 4vw, 56px);
  --col-max:    1160px;
  --radius-sm:  4px;
  --radius:     6px;
  --radius-lg:  10px;
}

/* ---------------------------------------------------------------------------
 * 3. Reset + base typography
 * --------------------------------------------------------------------------- */
* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--ivory);
  color: var(--ink);
  font-family: var(--sans);
  font-weight: 400;
  font-size: 14.5px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-feature-settings: "ss01", "cv01";
}

h1, h2, h3, h4 {
  font-family: var(--serif);
  font-weight: 400;
  color: var(--ink);
  letter-spacing: -0.005em;
  margin: 0;
}
h1 { font-size: 2.05rem; line-height: 1.15; font-weight: 300; letter-spacing: -0.015em; }
h2 { font-size: 1.55rem; line-height: 1.2;  font-weight: 400; }
h3 { font-size: 1.2rem;  line-height: 1.25; font-weight: 500; }
h4 { font-size: 1rem;    line-height: 1.3;  font-weight: 500; }

p   { margin: 0 0 0.65em; }
a   { color: var(--forest); text-decoration: none; border-bottom: 1px solid var(--ink-12); transition: border-color 0.1s ease; }
a:hover { border-bottom-color: var(--forest); }
em, i { font-family: var(--serif); font-style: italic; font-weight: 400; }
code, pre, .mono { font-family: var(--mono); font-size: 0.92em; }

::selection { background: var(--bronze-pale); color: var(--ink); }

/* ---------------------------------------------------------------------------
 * 4. Brand mark — the vanshOS logotype, used in the topbar
 * --------------------------------------------------------------------------- */
.brand-mark {
  font-family: var(--serif);
  font-weight: 300;
  font-size: 1.55rem;
  line-height: 1;
  letter-spacing: -0.02em;
  border-bottom: none;
  display: inline-flex;
  align-items: baseline;
}
/* Lock the casing of every brand-mark span explicitly. Without these
   rules, an ancestor with ``text-transform: uppercase`` (e.g. the
   dashboard-hero eyebrow or any sectioned label) collapses the brand
   into "VANSHOS". The per-span text-transform overrides the inherited
   transform so the brand always reads as "vanshOS" — lowercase "v" +
   lowercase "ansh" + uppercase "OS" — no matter where it's mounted. */
.brand-mark__v    { color: var(--ink); text-transform: lowercase; }
.brand-mark__ansh { color: var(--forest); font-style: italic; text-transform: lowercase; }
.brand-mark__os   { color: var(--bronze); text-transform: uppercase; }

/* Beta pill — small bronze chip pinned to the right of the brand mark.
   Sized via em + relative top offset so it scales with the brand wherever
   it's rendered (sidebar logo at 1.55rem, home hero at the larger hero
   font size, etc.) and sits visually attached to the "OS" letters. */
.brand-mark__beta {
  display: inline-block;
  margin-left: 0.45em;
  padding: 0.15em 0.55em;
  font-size: 0.42em;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: lowercase;
  font-style: normal;
  border-radius: 999px;
  background: var(--bronze);
  color: #fff;
  vertical-align: middle;
  position: relative;
  top: -0.55em;
  line-height: 1.4;
  white-space: nowrap;
}
/* In the sidebar's dark column the bronze pill still reads well, but
   bump the contrast a touch with a softer translucent backdrop. */
.sidebar .brand-mark__beta {
  background: rgba(184, 130, 60, 0.95);  /* bronze, slightly translucent */
  color: #fff;
}

/* Inline variant — used inside text runs (e.g. eyebrows, footers) where
   the brand should size with surrounding text instead of behaving like
   a logo block. The .brand-mark base class sets font-size: 1.55rem
   (logo size); .brand-mark--inline drops that override so the brand
   inherits its parent's font-size. */
.brand-mark--inline {
  font-size: inherit;
  letter-spacing: normal;
  line-height: inherit;
}

/* ---------------------------------------------------------------------------
 * 5. Layout — sidebar-beside-main (Astra Personal-style)
 * --------------------------------------------------------------------------- */

/* The signed-in layout: 240px fixed sidebar + fluid main column. On mobile
 * the sidebar slides in from the left when `.layout--nav-open` is set by
 * Alpine. The overlay (under the sidebar) catches clicks to close it. */
.layout {
  display: grid;
  grid-template-columns: 240px 1fr;
  min-height: 100vh;
  background: var(--ivory);
}

.layout__hamburger {
  display: none;  /* shown only on narrow screens via media query */
  position: fixed;
  top: 14px;
  left: 14px;
  z-index: 50;
  width: 40px;
  height: 40px;
  align-items: center;
  justify-content: center;
  background: var(--paper);
  border: var(--rule);
  border-radius: var(--radius);
  color: var(--ink);
  cursor: pointer;
  transition: background 0.1s ease;
}
.layout__hamburger:hover { background: var(--ink-07); }

.layout__overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(24, 26, 23, 0.4);
  z-index: 35;
}

/* Signed-out layout: thin top bar holding just the brand mark, then a
 * centered auth card via the existing .auth-card styles. */
.auth-topbar {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 32px 24px 8px;
}

.main {
  padding: 32px var(--pad-page) 80px;
  /* Constrain the inner column to a comfortable reading width, but the
   * main element itself fills the grid cell so the page bg extends fully. */
  /* position: relative so the absolute-positioned super-admin tenant
     switcher (.tenant-switcher) anchors to the main column's top-right
     instead of escaping to the viewport. */
  position: relative;
}
.main > * { max-width: var(--col-max); margin-left: auto; margin-right: auto; }
.main--auth > * { max-width: 100%; margin: 0; }
.main--auth { padding-top: 0; padding-bottom: 64px; }

/* ---------------------------------------------------------------------------
 * 5a. Sidebar — dark forest theme (per the v1.1 sidebar reference)
 *
 * Tokens scoped to the sidebar so the rest of the app stays on the
 * warm-paper palette. ``--sb-ink`` etc. are local-only.
 * --------------------------------------------------------------------------- */
.sidebar {
  /* Local palette — dark forest base + warm bronze accents */
  --sb-bg:          #131b14;             /* near forest-deep with a slight olive tilt */
  --sb-bg-2:        #1a2620;             /* hover/active background a touch lighter */
  --sb-rule:        rgba(214, 220, 210, 0.08);
  --sb-ink:         #e8e5dc;             /* primary text on dark */
  --sb-ink-muted:   rgba(232, 229, 220, 0.55);
  --sb-ink-faint:   rgba(232, 229, 220, 0.35);
  --sb-brand-os:    #c1a173;             /* lighter bronze for OS — reads better on dark */

  display: flex;
  flex-direction: column;
  background: var(--sb-bg);
  color: var(--sb-ink);
  border-right: none;
  padding: 26px 0 20px;
  min-height: 100vh;
  position: sticky;
  top: 0;
  align-self: start;
  max-height: 100vh;
  overflow-y: auto;
  z-index: 40;
  scrollbar-color: rgba(232, 229, 220, 0.18) transparent;
}

/* Brand mark adjustments inside the dark sidebar:
 *   - 'v' becomes light paper instead of ink
 *   - 'ansh' stays italic but in lighter forest tint
 *   - 'OS' uses the bumped-up bronze for legibility
 */
.sidebar .brand-mark__v    { color: var(--sb-ink); }
.sidebar .brand-mark__ansh { color: rgba(232, 229, 220, 0.78); }
.sidebar .brand-mark__os   { color: var(--sb-brand-os); }

.sidebar__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 24px 22px;
  margin-bottom: 8px;
  border-bottom: 1px solid var(--sb-rule);
}
.sidebar__brand { font-size: 1.55rem; line-height: 1; }

/* Brand + tenant name as a vertical stack (Phase D2). The wrapper
   exists so the close-button on mobile keeps its right-edge position
   while the brand + tenant occupy a unified left column. */
.sidebar__brand-stack {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.sidebar__tenant {
  font-size: 11.5px;
  letter-spacing: 0.06em;
  color: var(--sb-ink-70, rgba(232, 229, 220, 0.75));
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  /* A subtle line so the tenant name reads as "this is the workspace
     I'm in" rather than "this is part of the product name". */
  border-left: 2px solid var(--bronze);
  padding-left: 8px;
}

.sidebar__close {
  display: none;  /* visible only on mobile */
  background: transparent;
  border: none;
  cursor: pointer;
  color: var(--sb-ink-muted);
  padding: 6px;
}
.sidebar__close:hover { color: var(--sb-ink); }

/* Desktop-only collapse toggle — pinned to the right edge of the
   sidebar header on >900px. Hidden on mobile (the hamburger +
   overlay pattern already handles small-screen show/hide). The
   chevron icon flips horizontally when the sidebar is collapsed
   so the affordance reads as "expand" instead of "collapse". */
.sidebar__collapse-btn {
  background: transparent;
  border: none;
  cursor: pointer;
  color: var(--sb-ink-muted);
  padding: 6px;
  border-radius: var(--radius-sm);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 0.12s ease, color 0.12s ease;
}
.sidebar__collapse-btn:hover {
  background: var(--sb-bg-2);
  color: var(--sb-ink);
}
.sidebar__collapse-icon {
  transition: transform 0.18s ease;
}
html.sidebar-collapsed .sidebar__collapse-icon {
  transform: rotate(180deg);
}

.sidebar__nav {
  flex: 1;
  display: flex;
  flex-direction: column;
  /* Phase Sidebar-Density (2026-05-27): tighter between-section gap.
     Was 20px; user reported the nav felt sparse + ran off short
     viewports. Halved to 10px — see docs/mockups/sidebar-density.html
     for the A/B preview that drove this number. */
  gap: 10px;
  padding: 4px 14px 0;
}

.sidebar__section {
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.sidebar__section-title {
  font-family: var(--sans);
  font-weight: 500;
  /* Phase Sidebar-Density (2026-05-27): font 10.5 → 12, track-out
     0.16em → 0.14em (bigger letters look stretched at the old track).
     Vertical margin reduced 4/8 → 2/4 to keep static H3 sections
     (Overview, Messages, Account) in rhythm with the collapsible
     ones. The collapsible button variant below mirrors the same
     numbers — both styles must stay typographically identical. */
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--sb-ink-faint);
  margin: 2px 12px 4px;
}

/* ---------------------------------------------------------------------------
 * Collapsible nav-section variant (sidebar Option A).
 *
 * Static sections (Overview / Messages / Account) keep the original
 * <h3 class="sidebar__section-title"> styling — these aren't worth
 * collapsing at 1-2 items.
 *
 * Big sections (Money flow / Assets / Reports / Admin / System +
 * the SA Catalog/System variants) wrap their title in a button that
 * toggles aria-expanded; the chevron rotates and the body
 * (.sidebar__section-body) is display:none when closed. State
 * persists in localStorage per group key — see the collapse script
 * in _partials/sidebar.html. The section containing the
 * currently-active nav item is ALWAYS force-expanded regardless of
 * localStorage so the user can see where they are.
 *
 * The count chip ("Assets · 7") gives a "what's in here" hint
 * without expanding — preserves discoverability for first-time
 * visitors who land with everything collapsed.
 * --------------------------------------------------------------------------- */
.sidebar__section--collapsible .sidebar__section-title--toggle {
  /* Reset the <button> defaults */
  background: transparent;
  border: 0;
  cursor: pointer;
  font-family: inherit;
  text-align: left;

  /* Same typography as the static .sidebar__section-title — keeps
     all section labels visually identical except for the chevron.
     Phase Sidebar-Density (2026-05-27): font 10.5 → 12, track-out
     0.16em → 0.14em, padding 5/10 → 6/10 (extra px so larger text
     still has breathing room), margin 4/4/6 → 2/4/4 (tighter top
     + bottom so the new font height doesn't grow the row). */
  font-weight: 500;
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--sb-ink-faint);

  /* Layout: title — count chip — chevron, with the chevron pinned
     to the right edge via margin-left:auto. */
  display: flex;
  align-items: center;
  gap: 8px;
  width: calc(100% - 8px);
  margin: 2px 4px 4px;
  padding: 6px 10px;
  border-radius: var(--radius);

  transition: background 0.12s, color 0.12s;
}
.sidebar__section--collapsible .sidebar__section-title--toggle:hover {
  color: var(--sb-ink);
  background: var(--sb-bg-hover, rgba(255,255,255,0.06));
}
.sidebar__section--collapsible .sidebar__section-title--toggle:focus-visible {
  outline: 2px solid var(--sb-bronze, #C9A56F);
  outline-offset: 1px;
}

/* Item-count chip. Sits next to the section title text with a slim
 * dark pill background. Subtle but high enough contrast to be
 * legible even when the group is collapsed (the only cue available
 * in that state). */
.sidebar__section-count {
  background: rgba(255, 255, 255, 0.08);
  color: var(--sb-ink-muted);
  padding: 1px 7px;
  border-radius: 999px;
  /* Phase Sidebar-Density (2026-05-27): font 9.5 → 11, proportional
     bump to match the new section-title size. The chip looked
     postage-stamp-tiny next to 12px title text otherwise. */
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  /* Override the parent's all-caps */
  text-transform: none;
}

/* Chevron — points DOWN when expanded, rotates to point right when
 * collapsed. SVG colour follows currentColor so it inherits the
 * title's text colour (faint by default, brighter on hover). */
.sidebar__section-chevron {
  margin-left: auto;
  width: 10px;
  height: 10px;
  opacity: 0.55;
  transition: transform 0.18s ease, opacity 0.12s;
  flex-shrink: 0;
}
.sidebar__section--collapsible .sidebar__section-title--toggle:hover
  .sidebar__section-chevron { opacity: 0.85; }
.sidebar__section--collapsible
  .sidebar__section-title--toggle[aria-expanded="false"]
  .sidebar__section-chevron { transform: rotate(-90deg); }

/* The collapsing body — display:none when the toggle is closed.
 * Using display rather than a max-height animation because the
 * navigation lists are short enough that a slide is unnecessary
 * (and feels heavy in repeated use). */
.sidebar__section--collapsible
  .sidebar__section-title--toggle[aria-expanded="false"]
  + .sidebar__section-body { display: none; }

/* Collapsed-rail variant (html.sidebar-collapsed) — when the WHOLE
 * sidebar is collapsed to the icon-only rail, the group titles
 * already hide (existing rule below) — but we also want the
 * collapsible chevron + count chip to disappear. */
html.sidebar-collapsed .sidebar__section--collapsible
  .sidebar__section-title--toggle { display: none; }
html.sidebar-collapsed .sidebar__section--collapsible
  .sidebar__section-body { display: block !important; }

.sidebar__item {
  display: flex;
  align-items: center;
  gap: 12px;
  /* Phase Sidebar-Density (2026-05-27): vertical padding 9 → 7 and
     font 13.5 → 14. The slight font bump keeps the row visually
     comfortable even as the row gets shorter — net effect ~25%
     shorter list in the typical expanded-Assets case. The
     ::before active-rail below mirrors the same 2px shrink so it
     stays vertically centred inside the row. */
  padding: 7px 12px;
  border-radius: var(--radius);
  text-decoration: none;
  color: var(--sb-ink-muted);
  font-size: 14px;
  font-weight: 400;
  border-bottom: none;
  transition: background 0.12s ease, color 0.12s ease;
}
.sidebar__item:hover {
  background: var(--sb-bg-2);
  color: var(--sb-ink);
  border-bottom: none;
}
.sidebar__item--active {
  background: var(--sb-bg-2);
  color: var(--sb-ink);
  position: relative;
}
.sidebar__item--active::before {
  content: "";
  position: absolute;
  left: -14px;
  /* Phase Sidebar-Density (2026-05-27): rail inset shrunk 8 → 6
     to stay proportional to the new 7px row padding (was 9px).
     Keeps the bronze rail visually centred inside the row. */
  top: 6px;
  bottom: 6px;
  width: 3px;
  background: var(--bronze-mid);
  border-radius: 0 2px 2px 0;
}

/* "Return to system view" entry — visible to a super-admin while they
   are impersonating a tenant (Phase K). It's a <form><button> instead
   of an <a> because we need a POST to /sa/stop-impersonating (CSRF-
   protected). We strip the native button chrome so it sits flush with
   the other .sidebar__item nav links above it, and add a bronze
   accent tint so the SA's way-out is visually distinguishable from
   the regular tenant menu items that surround it. */
.sidebar__return-form {
  margin: 0;
  padding: 0;
}
.sidebar__item--return {
  background: transparent;
  border: 0;
  width: 100%;
  text-align: left;
  cursor: pointer;
  font-family: inherit;
  color: var(--sb-brand-os, var(--bronze-mid));
  font-weight: 500;
}
.sidebar__item--return:hover {
  background: var(--sb-bg-2);
  color: var(--sb-ink);
}

/* Sidebar nav icons — bronze on the dark forest backdrop. */
.nav__icon {
  flex-shrink: 0;
  width: 17px;
  height: 17px;
  color: #b89968;                      /* slightly muted bronze for icon line */
  transition: color 0.12s ease;
}
.sidebar__item:hover .nav__icon  { color: var(--sb-brand-os); }
.sidebar__item--active .nav__icon { color: var(--sb-brand-os); }

.sidebar__label { flex: 1; }

/* Sidebar footer: user card with avatar (top row) + version (bottom
 * line) — pinned to the bottom of the sidebar. The version line uses
 * a much smaller font and the bronze tone so it doesn't compete with
 * the user info above it. */
.sidebar__footer {
  margin-top: auto;
  padding: 16px 20px 14px;
  border-top: 1px solid var(--sb-rule);
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.sidebar__footer-row {
  display: flex;
  align-items: center;
  gap: 11px;
}
.sidebar__version {
  font-size: 10.5px;
  letter-spacing: 0.04em;
  color: var(--sb-ink-50, rgba(232, 229, 220, 0.55));
  text-align: center;
  line-height: 1.3;
  user-select: text;  /* let people copy the version for bug reports */
}
.sidebar__version-num {
  font-variant-numeric: tabular-nums;
  color: var(--sb-ink-70, rgba(232, 229, 220, 0.75));
}
.sidebar__version-env {
  margin-left: 4px;
  padding: 1px 6px;
  border-radius: 3px;
  background: var(--bronze);
  color: #2a2009;
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.sidebar__user-avatar {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: linear-gradient(135deg, #8a7350, #6a5638);
  color: #f3eddd;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--serif);
  font-weight: 500;
  font-size: 14px;
  letter-spacing: 0;
}
.sidebar__user {
  flex: 1;
  min-width: 0;
}
.sidebar__user-name {
  font-size: 13px;
  font-weight: 500;
  color: var(--sb-ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sidebar__user-meta {
  font-size: 11px;
  font-weight: 400;
  color: var(--sb-ink-faint);
  letter-spacing: 0.04em;
}
.sidebar__signout {
  background: transparent;
  border: none;
  cursor: pointer;
  color: var(--sb-ink-muted);
  padding: 6px;
  border-radius: var(--radius-sm);
  transition: background 0.12s ease, color 0.12s ease;
}
.sidebar__signout:hover { background: var(--sb-bg-2); color: var(--sb-ink); }

/* Small-size button variant — used in the sidebar footer */
.btn--sm {
  padding: 5px 9px;
  font-size: 12px;
  gap: 4px;
}

/* ---------------------------------------------------------------------------
 * 5b. Responsive sidebar (hamburger on mobile)
 * --------------------------------------------------------------------------- */
@media (max-width: 900px) {
  .layout {
    grid-template-columns: 1fr;  /* sidebar overlays instead of co-occupying */
  }
  .layout__hamburger { display: inline-flex; }
  .sidebar {
    position: fixed;
    top: 0; left: 0; bottom: 0;
    width: 280px;
    transform: translateX(-100%);
    transition: transform 0.22s cubic-bezier(0.2, 0.7, 0.2, 1);
    box-shadow: 0 10px 40px rgba(24, 26, 23, 0.18);
  }
  .layout--nav-open .sidebar { transform: translateX(0); }
  .layout--nav-open .layout__overlay { display: block; }
  .sidebar__close { display: inline-flex; }
  .main { padding-top: 72px;  /* leave room for the fixed hamburger */ }
  /* Hide the collapse toggle on mobile — the hamburger / overlay
     pattern handles small-screen show/hide already, and a "collapse
     to rail" mode would just confuse on a 380px viewport. */
  .sidebar__collapse-btn { display: none; }
}

/* ---------------------------------------------------------------------------
 * 5c. Sidebar collapsed rail (desktop only)
 *
 * When the user clicks the chevron in the sidebar header, we shrink the
 * sidebar to a ~64px icon-only rail and hide labels / section titles /
 * the tenant chip / the user card + version line. Toggled by adding the
 * class ``sidebar-collapsed`` to <html> — see the first-paint primer in
 * base.html for the initial value (read from localStorage) and the
 * inline onclick on .sidebar__collapse-btn for the runtime toggle.
 *
 * Putting the class on <html> instead of inside Alpine's x-data lets
 * the initial paint pick the right width without waiting for Alpine to
 * boot — no flash-of-expanded-sidebar on slow connections.
 * --------------------------------------------------------------------------- */
@media (min-width: 901px) {
  html.sidebar-collapsed .layout {
    grid-template-columns: 64px 1fr;
  }
  html.sidebar-collapsed .sidebar {
    padding-left: 0;
    padding-right: 0;
  }
  html.sidebar-collapsed .sidebar__header {
    padding: 0 8px 14px;
    flex-direction: column;
    gap: 8px;
    align-items: center;
  }
  /* Hide the brand text + tenant chip — the rail is identity-free
     when collapsed. Bringing the sidebar back expands them again. */
  html.sidebar-collapsed .sidebar__brand-stack { display: none; }
  /* Section titles are useless when there's only one icon per row. */
  html.sidebar-collapsed .sidebar__section-title { display: none; }
  /* Item label text — hidden, but the title attribute on the SVG /
     <a> wrapper would be nice. For now we rely on the destination
     page title + the active-state highlight to orient the user. */
  html.sidebar-collapsed .sidebar__label { display: none; }
  html.sidebar-collapsed .sidebar__badge { display: none; }
  /* Center the icons in their 64px-wide column. */
  html.sidebar-collapsed .sidebar__nav { padding-left: 4px; padding-right: 4px; }
  html.sidebar-collapsed .sidebar__item {
    justify-content: center;
    padding: 9px 0;
  }
  html.sidebar-collapsed .sidebar__item--active::before {
    left: -4px;
  }
  /* Footer collapses to just the avatar + sign-out — the name /
     role / version lines drop. */
  html.sidebar-collapsed .sidebar__footer {
    padding: 12px 8px 12px;
    align-items: center;
  }
  html.sidebar-collapsed .sidebar__footer-row {
    flex-direction: column;
    gap: 6px;
  }
  html.sidebar-collapsed .sidebar__user { display: none; }
  html.sidebar-collapsed .sidebar__version { display: none; }
}

.page-wide {
  /* The new sidebar layout already constrains width + padding via .main and
   * .main > * (above). page-wide becomes a semantic wrapper — no extra
   * padding/max-width so we don't double-pad. */
  width: 100%;
}
.page-header { margin-bottom: 24px; }
.page-header h1 { margin: 0 0 6px; }
.page-header p, .page-header .muted { color: var(--ink-65); font-size: 0.95rem; }

/* Page heading with sidebar-matched icon (added 2026-05-20).
   The icon mirrors the sidebar row's glyph so module identity carries
   from sidebar -> page. Slightly larger than the H1 text height so it
   reads as a "module badge" without dominating the title. Bronze
   stroke matches every other accent on the page.

   .page-header__h1 stands on its own — works whether or not it's
   wrapped in <header class="page-header"> (some pages render the H1
   directly inside <section class="page-wide"> without the wrapping
   header). */
.page-header__h1 {
  display: flex;
  align-items: center;
  gap: 0.55em;
  margin: 0 0 6px;
}
.page-header__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--bronze);
  flex: 0 0 auto;
  /* slightly larger than the H1 cap-height */
  width:  1.35em;
  height: 1.35em;
  line-height: 1;
}
.page-header__icon-svg {
  width: 100%;
  height: 100%;
  display: block;
}
.page-header__title {
  display: inline-block;
  line-height: 1.15;
}

.two-col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 28px;
  margin-bottom: 28px;
}
@media (max-width: 760px) { .two-col { grid-template-columns: 1fr; gap: 18px; } }

/* Sub-navigation — sits just under the topbar on dashboard / admin sections */
.subnav {
  display: flex;
  gap: 2px;
  align-items: center;
  padding: 8px var(--pad-page);
  background: var(--paper);
  border-bottom: var(--rule);
  font-size: 13.5px;
  font-weight: 500;
  overflow-x: auto;
}
.subnav__item {
  padding: 8px 14px;
  text-decoration: none;
  color: var(--ink-80);
  border-bottom: 2px solid transparent;
  white-space: nowrap;
  letter-spacing: 0.005em;
  transition: color 0.1s ease, border-color 0.1s ease;
}
.subnav__item:hover { color: var(--forest); border-bottom: 2px solid transparent; }
.subnav__item.active,
.subnav__item--active { color: var(--ink); border-bottom-color: var(--bronze); }
.subnav__item--right  { margin-left: auto; }
.subnav__sep { color: var(--ink-25); margin: 0 4px; }

/* ---------------------------------------------------------------------------
 * Module / Masters sub-navigation strips.
 *
 * Two class names exist for historical reasons:
 *   - ``.masters-subnav``  →  FD, CC, Admin masters (older modules)
 *   - ``.module-subnav``   →  RE, MA, LI, DW, SUB    (newer modules)
 *
 * They get identical visual treatment so the system reads as one
 * consistent product. Style is deliberately subtle — a soft pill
 * shape per tab, a slightly darker hover, and a filled forest accent
 * for the active tab. Goal: clearly clickable + clearly a tab strip,
 * without shouting.
 *
 * If you're adding a third subnav family, prefer ``.module-subnav``
 * going forward and add the class to the shared selector list below.
 * --------------------------------------------------------------------------- */
.masters-subnav,
.module-subnav {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  padding: 0 0 14px;
  margin-bottom: 20px;
  border-bottom: var(--rule);
  /* Tiny baseline cue — even when no tab is active, the strip reads
     as a navigation row instead of body text. */
  align-items: center;
}

.masters-subnav__item,
.module-subnav__item {
  display: inline-block;
  padding: 6px 14px;
  text-decoration: none;        /* drop the default underline — the
                                    pill background carries the cue */
  color: var(--ink-80);
  background: transparent;
  border: 1px solid transparent;
  border-bottom: none;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.01em;
  line-height: 1.4;
  transition: background 0.12s ease,
              color      0.12s ease,
              border-color 0.12s ease;
}

/* Idle hover — a faint paper-tinted pill so the mouse-over makes it
   obvious which tab is targetable. The 1px ivory border keeps the
   shape readable on the page background without adding weight. */
.masters-subnav__item:hover,
.module-subnav__item:hover {
  background: var(--ink-07);
  border-color: var(--ink-12);
  color: var(--ink);
  text-decoration: none;
}

/* Active tab — filled forest pill with paper text. The cue is
   unmistakable but the size is small enough that it doesn't
   dominate the page header. Hover on the active tab nudges to
   forest-deep so users get feedback on a return click. */
.masters-subnav__item--active,
.module-subnav__item--active {
  background: var(--forest);
  color: var(--on-dark);
  border-color: var(--forest);
}
.masters-subnav__item--active:hover,
.module-subnav__item--active:hover {
  background: var(--forest-deep);
  border-color: var(--forest-deep);
  color: var(--on-dark);
}

/* Keyboard focus — bronze outline so tab navigation is obvious.
   Outline (not box-shadow) so it doesn't shift layout. */
.masters-subnav__item:focus-visible,
.module-subnav__item:focus-visible {
  outline: 2px solid var(--bronze);
  outline-offset: 2px;
}

/* Phase DetailTabs (2026-05-26): attention-count badge on a subnav
 * tab. The route hands each detail page a `attention` dict of
 * pending+overdue counts per tab (overdue rent / unpaid premium /
 * expiring insurance). When a tab has >0 attention items we render
 * a small pill next to its label so the user sees at a glance which
 * tab their attention is needed on. The "highest attention" tab
 * also becomes the default tab (see detail-tabs.js) so the user
 * lands directly on it.
 *
 * Sized + coloured to look like the sidebar unread-message badge
 * (see .sidebar__badge) for visual consistency across the app —
 * but uses --danger so the urgency reads instantly. On the active
 * tab the badge inverts (white text on a translucent dark bg) so
 * it still pops against the dark forest-green active fill. */
.masters-subnav__badge,
.module-subnav__badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 6px;
  margin-left: 6px;
  border-radius: 9px;
  font-size: 0.72rem;
  font-weight: 600;
  line-height: 1;
  background: var(--danger, #c0392b);
  color: #fff;
  vertical-align: 1px;
}
.masters-subnav__item--active .masters-subnav__badge,
.module-subnav__item--active .module-subnav__badge {
  background: rgba(255, 255, 255, 0.25);
  color: #fff;
}

/* Phase ExpenseAnnotations (2026-05-26): pills + segmented control.
 *
 * .pay-pill renders a small uppercase badge (CASH / CARD / UPI / etc)
 * next to a paid row's status. Visually neutral — not a warning, just
 * an annotation of HOW the row was paid. The default 'bank' payment
 * method is intentionally NOT rendered as a pill (it's the silent
 * default); only non-bank methods get a pill so the user's eye finds
 * the non-bank rows at a glance.
 *
 * .paid-via-group is the inline radio row on the Paid form ("Paid
 * via: ( ) Bank  ( ) Cash  ( ) Card  ( ) UPI  ( ) Other"). Plain
 * radio inputs with cursor:pointer labels — no custom segmented-
 * control widget needed.
 */
.pay-pill {
  display: inline-block;
  padding: 1px 7px;
  margin-left: 6px;
  border-radius: 4px;
  background: var(--ink-12, #e0e2e5);
  color: var(--ink-65, #555);
  font-size: 0.65rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  vertical-align: middle;
  text-transform: uppercase;
}
.pay-pill--cash   { background: #e8f4ea; color: #2d6a3e; }
.pay-pill--card   { background: #ecedf6; color: #4a5293; }
.pay-pill--upi    { background: #e8f1f8; color: #2e5a86; }
.pay-pill--wallet { background: #fdf2e3; color: #8a5a00; }
.pay-pill--other  { background: var(--ink-12, #e0e2e5); color: var(--ink-65, #555); }
/* Phase Payment-Methods (2026-05-27): NEFT, RTGS, DD pills. All
 * three are bank-backed (settle through a bank account + post a
 * ledger entry) so they sit in the same blue/indigo family as UPI
 * to read as "another bank rail" rather than a different category. */
.pay-pill--neft   { background: #e0eafc; color: #1f3b78; }
.pay-pill--rtgs   { background: #d8e2f8; color: #1a3066; }
.pay-pill--dd     { background: #efe6f5; color: #553088; }

.paid-via-group {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  font-size: 0.85rem;
}
.paid-via-group > label {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  cursor: pointer;
  user-select: none;
}
.paid-via-group input[type="radio"] {
  margin: 0;
}

/* ---------------------------------------------------------------------------
 * Page-section anchor strip — used inside a detail page to jump to
 * #overview / #holders / #schedule / etc. Lighter weight than the
 * module-subnav since it doesn't change pages — it just scrolls.
 *
 * Visual cue:
 *   - Inactive: muted text, NO underline, sits on a soft baseline
 *   - Hover:    bronze underline (animates in) + ink-colour text
 *
 * Add ``class="page-section-nav"`` on the wrapping <nav> and forget
 * the inline ``style="..."`` so every detail page gets identical
 * treatment.
 * --------------------------------------------------------------------------- */
.page-section-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 4px;
  padding: 0 0 10px;
  margin-bottom: 22px;
  border-bottom: var(--rule);
  font-size: 0.9rem;
}
.page-section-nav a {
  display: inline-block;
  padding: 4px 10px;
  border-radius: 999px;
  color: var(--ink-65);
  text-decoration: none;
  border-bottom: none;
  font-weight: 500;
  letter-spacing: 0.01em;
  transition: background 0.12s ease,
              color 0.12s ease;
}
.page-section-nav a:hover {
  background: var(--bronze-pale);
  color: var(--forest-deep);
  text-decoration: none;
}
.page-section-nav a:focus-visible {
  outline: 2px solid var(--bronze);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------------------
 * 6. Buttons
 * --------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px 16px;
  border: 1px solid var(--ink-12);
  border-radius: var(--radius);
  background: var(--paper);
  color: var(--ink);
  cursor: pointer;
  text-decoration: none;
  font-family: var(--sans);
  font-size: 13.5px;
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: 0.005em;
  transition: background 0.1s ease, border-color 0.1s ease, color 0.1s ease, transform 0.05s ease;
}
.btn:hover  { background: var(--ink-07); border-color: var(--ink-25); }
.btn:active { transform: translateY(1px); }
.btn:focus-visible {
  outline: 2px solid var(--bronze);
  outline-offset: 2px;
}

.btn--primary {
  background: var(--forest);
  /* --on-dark stays light cream in every theme; --paper would flip
     to a dark surface colour on the ink theme and make the button
     text unreadable. */
  color: var(--on-dark);
  border-color: var(--forest);
}
.btn--primary:hover  { background: var(--forest-deep); border-color: var(--forest-deep); }

.btn--ghost {
  background: transparent;
  border-color: transparent;
  color: var(--ink-80);
}
.btn--ghost:hover { background: var(--ink-07); color: var(--ink); border-color: transparent; }

/* Dark-theme: ghost buttons need a visible border because the
   transparent background blends into the dark page surface — without
   the border the buttons read as plain bold text rather than
   interactive elements (Phase combobox bug report). */
[data-theme="forest"] .btn--ghost,
[data-theme="ink"] .btn--ghost {
  border-color: var(--ink-25);
}
[data-theme="forest"] .btn--ghost:hover,
[data-theme="ink"] .btn--ghost:hover {
  border-color: var(--bronze-mid);
  background: rgba(192, 161, 115, 0.10);
}
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] .btn--ghost {
    border-color: var(--ink-25);
  }
  [data-theme="auto"] .btn--ghost:hover {
    border-color: var(--bronze-mid);
    background: rgba(192, 161, 115, 0.10);
  }
}

.btn--danger {
  color: var(--negative);
  border-color: var(--ink-12);
}
.btn--danger:hover { background: var(--negative-bg); border-color: var(--negative); }

.inline-form { display: inline; }

/* ---------------------------------------------------------------------------
 * 7. Forms
 * --------------------------------------------------------------------------- */
.form {
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.form__field { display: flex; flex-direction: column; gap: 6px; }
.form__label {
  font-size: 12.5px;
  color: var(--ink-65);
  font-weight: 500;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

/* Form-field input/select/textarea baseline.
   Background uses a subtle ink overlay (rgba(0,0,0,0.04)) instead of
   ``--paper`` so the field is always "slightly darker than my parent"
   — regardless of whether the parent is the page, a .filter-card,
   or another nested form group. Previously the field used --paper
   and merged with surrounding cards. Dark-theme variants below use
   a deeper overlay for the same relative effect.
   Border bumped from --ink-12 → --ink-25 for clearer edge definition
   in light themes (--ink-12 was almost invisible against cream). */
.form input[type="text"],
.form input[type="password"],
.form input[type="email"],
.form input[type="number"],
.form input[type="date"],
.form select,
.form textarea {
  padding: 10px 12px;
  border: 1px solid var(--ink-25);
  border-radius: var(--radius);
  background: rgba(0, 0, 0, 0.04);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 400;
  line-height: 1.4;
  transition: border-color 0.1s ease, background 0.1s ease, box-shadow 0.1s ease;
}
.form input:focus,
.form select:focus,
.form textarea:focus {
  outline: none;
  border-color: var(--forest);
  background: var(--card);             /* "snap" to bright on focus */
  box-shadow: 0 0 0 3px var(--forest-pale);
}
.form input::placeholder,
.form textarea::placeholder { color: var(--ink-45); }

.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 16px 20px;
  margin-bottom: 20px;
}

.account-form textarea,
.form textarea {
  resize: vertical;
  min-height: 84px;
}

.data-entry-form { max-width: 720px; }

/* ---------------------------------------------------------------------------
 * 8. Cards — auth / error / dashboard placeholder
 * --------------------------------------------------------------------------- */
.auth-card,
.error-card,
.dashboard {
  background: var(--paper);
  border: var(--rule);
  border-radius: var(--radius-lg);
  padding: 32px 36px;
  max-width: 440px;
  margin: 72px auto;
  box-shadow: 0 2px 24px var(--ink-07);
}
/* 2026-05-24: trimmed top margin (32→14) so the card sits closer to the
   top of the main column. Bottom margin preserved at 32px so the next
   section below doesn't crowd. Final padding-top is set further down in
   the dashboard section (line ~7994) and was bumped 4→22 in the same
   pass so the title isn't flush with the card's top border. */
.dashboard { max-width: 720px; padding: 28px 32px; margin: 14px auto 32px; }

.auth-card__title {
  font-family: var(--serif);
  font-weight: 300;
  font-size: 1.8rem;
  letter-spacing: -0.02em;
  margin: 0 0 8px;
}
.auth-card + .muted,
.auth-card__title + .muted { margin-bottom: 24px; }

/* Phase F5 (2026-05-26): supporting copy + footer links inside an
   .auth-card. Used by /forgot-password, /reset-password (live + invalid).
   Same paper background; just adds vertical rhythm + muted footer copy. */
.auth-card__lead   { margin: 0 0 16px; color: var(--ink-80); line-height: 1.55; }
.auth-card__small  { margin: 18px 0 0; font-size: 0.92rem; color: var(--ink-65); }
.auth-card__small a { color: var(--ink-80); }
.auth-card__small a:hover { color: var(--ink); }

/* ---------------------------------------------------------------------------
 * 9. Flash messages
 * --------------------------------------------------------------------------- */
.flash-region { padding: 12px var(--pad-page) 0; }
.flash {
  padding: 11px 16px;
  border-radius: var(--radius);
  margin-bottom: 8px;
  border: 1px solid transparent;
  font-size: 13.5px;
  font-weight: 500;
}
.flash--error   { background: var(--negative-bg); border-color: var(--negative); color: var(--negative); }
.flash--success { background: var(--positive-bg); border-color: var(--positive); color: var(--positive); }
.flash--warn    { background: var(--warn-bg);     border-color: var(--warn);     color: var(--warn); }
/* Info — muted neutral. Used for login welcome + "nothing changed"
   style low-key acknowledgements. Was forest-pale green which read
   too close to "success". Switched to a paper/bronze-pale tint with
   ink text so it reads as a calm hint, not an achievement banner. */
.flash--info    {
  background: color-mix(in srgb, var(--paper) 70%, var(--bronze-pale) 30%);
  border-color: var(--bronze-pale);
  color: var(--ink);
  font-weight: 400;
}

/* ---------------------------------------------------------------------------
 * 10. Tables
 * --------------------------------------------------------------------------- */
.table-wrap {
  overflow-x: auto;
  margin-bottom: 24px;
  border: var(--rule);
  border-radius: var(--radius);
  background: var(--paper);
}
.table-wrap--narrow { max-width: 520px; }

.data-table,
.admin-table,
.bulk-table {
  border-collapse: collapse;
  width: 100%;
  font-size: 13.5px;
  background: var(--paper);
}

.data-table th,
.data-table td,
.admin-table th,
.admin-table td,
.bulk-table th,
.bulk-table td {
  padding: 10px 14px;
  vertical-align: top;
  text-align: left;
  border-bottom: 1px solid var(--ink-07);
}
.data-table tr:last-child td,
.admin-table tr:last-child td,
.bulk-table tr:last-child td { border-bottom: none; }

.data-table th,
.admin-table th,
.bulk-table th {
  background: transparent;
  font-weight: 500;
  font-size: 11.5px;
  color: var(--ink-65);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border-bottom: var(--rule);
  padding-top: 12px;
  padding-bottom: 10px;
}

.data-table tr:hover td,
.admin-table tr:hover td { background: var(--ink-07); }

.data-table .num,
.admin-table .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 400;
  color: var(--ink);
}
.data-table .num--total {
  font-weight: 500;
  background: var(--bone);
  color: var(--ink);
}
.data-table .totals-row td {
  background: var(--bone);
  border-top: var(--rule);
  font-weight: 500;
}

.data-table--matrix .sticky {
  position: sticky;
  left: 0;
  background: var(--paper);
  z-index: 1;
  border-right: var(--rule);
}

/* Distinct forest-tinted header band on the balance matrix. The plain
 * .data-table th rule above renders a faint uppercase label on a
 * transparent background, which made the matrix's "HOLDER / Bank /
 * Bank / …" row blend into the data. The matrix has many columns and
 * its own visual weight, so we give it a tighter contrast band.
 * Sticky-left cell ("Holder") sits on top of the same colour. */
.data-table--matrix thead th,
.data-table--matrix thead th.sticky {
  background: var(--forest);
  /* --on-dark = light cream regardless of theme. On ink theme,
     --paper is dark, so using it as text colour against forest bg
     produced a dark-on-dark unreadable header. */
  color: var(--on-dark);
  font-weight: 600;
  letter-spacing: 0.07em;
  border-bottom: 0;
  /* Round the band's corners only on the outer cells. */
}
.data-table--matrix thead tr th:first-child { border-top-left-radius:  8px; }
.data-table--matrix thead tr th:last-child  { border-top-right-radius: 8px; }
/* Stronger separation between header and data — a hairline of bronze
 * underneath the forest band, picking up the brand accent. */
.data-table--matrix thead tr { box-shadow: inset 0 -2px 0 var(--bronze); }

.admin-table { font-size: 13.5px; }
.admin-table input[type="text"],
.admin-table input[type="password"],
.admin-table input[type="number"],
.admin-table input[type="date"],
.admin-table input[type="email"],
.admin-table select,
.admin-table textarea {
  padding: 6px 8px;
  border: 1px solid var(--ink-25);
  border-radius: var(--radius-sm);
  background: rgba(0, 0, 0, 0.04);
  /* Without this explicit colour, inputs fall back to OS-default
     black — which becomes black-on-dark and invisible under the
     forest / ink dark themes (paper is dark there). --ink flips to
     paper-cream on dark themes so the text stays readable in every
     theme. */
  color: var(--ink);
  font: inherit;
}
.admin-table .inline-form { display: inline-block; margin-right: 6px; }

.bulk-table { font-size: 12.5px; }
.bulk-table input,
.bulk-table select,
.bulk-table textarea {
  padding: 5px 7px;
  border: 1px solid var(--ink-25);
  border-radius: var(--radius-sm);
  font: inherit;
  width: 100%;
  background: rgba(0, 0, 0, 0.04);
  color: var(--ink);
}
.bulk-actions {
  display: flex;
  gap: 14px;
  align-items: center;
  margin-top: 16px;
}

/* ---------------------------------------------------------------------------
 * 11. KPI grid
 * --------------------------------------------------------------------------- */
.kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 14px;
  margin-bottom: 28px;
}
.kpi {
  background: var(--paper);
  border: var(--rule);
  border-radius: var(--radius);
  padding: 16px 18px;
  transition: border-color 0.1s ease;
}
.kpi:hover { border-color: var(--ink-25); }
.kpi__label {
  color: var(--ink-65);
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin-bottom: 6px;
}
.kpi__value {
  font-family: var(--serif);
  font-size: 1.6rem;
  font-weight: 400;
  line-height: 1.1;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

/* ---------------------------------------------------------------------------
 * 12. Filter bar
 * --------------------------------------------------------------------------- */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: end;
  padding: 14px 16px;
  background: var(--paper);
  border: var(--rule);
  border-radius: var(--radius);
  margin-bottom: 18px;
}
.filter-bar label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 11.5px;
  color: var(--ink-65);
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.filter-bar select,
.filter-bar input[type="text"],
.filter-bar input[type="date"] {
  padding: 7px 10px;
  border: 1px solid var(--ink-25);
  border-radius: var(--radius-sm);
  background: rgba(0, 0, 0, 0.04);
  font: 400 13.5px/1.4 var(--sans);
  color: var(--ink);
  min-width: 150px;
}
.filter-bar select:focus,
.filter-bar input:focus {
  outline: none;
  border-color: var(--forest);
  box-shadow: 0 0 0 2px var(--forest-pale);
}
.filter-bar button { align-self: end; }

/* Window picker — segmented control for 7d / 30d / MTD / etc. */
.window-picker { display: inline-flex; gap: 4px; margin-bottom: 18px; }
.window-picker .btn { padding: 6px 12px; font-size: 12.5px; }
.window-picker .btn.active,
.window-picker .btn--active {
  background: var(--forest);
  color: var(--on-dark);
  border-color: var(--forest);
}

/* ---------------------------------------------------------------------------
 * 13. Pagination
 * --------------------------------------------------------------------------- */
.pagination {
  display: flex;
  gap: 14px;
  align-items: center;
  margin-top: 16px;
  padding-top: 14px;
  border-top: var(--rule-soft);
}
.pagination__pos { color: var(--ink-65); font-size: 13px; font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------------------
 * 14. Direction badges — inflow / outflow / other
 * --------------------------------------------------------------------------- */
.dir {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border: 1px solid transparent;
  font-feature-settings: "tnum";
}
.dir--inflow  { background: var(--positive-bg); color: var(--positive); border-color: var(--positive); }
.dir--outflow { background: var(--negative-bg); color: var(--negative); border-color: var(--negative); }
.dir--other   { background: var(--ink-07);     color: var(--ink-65);   border-color: var(--ink-12); }

/* ---------------------------------------------------------------------------
 * 15. Wizard progress
 * --------------------------------------------------------------------------- */
.wizard-progress {
  display: flex;
  gap: 6px;
  margin-bottom: 22px;
  font-size: 12.5px;
}
.wizard-progress__step {
  padding: 6px 14px;
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink-65);
  border: 1px solid var(--ink-12);
  font-weight: 500;
  font-feature-settings: "tnum";
}
.wizard-progress__step--current {
  background: var(--forest);
  color: var(--on-dark);
  border-color: var(--forest);
}
.wizard-progress__step--done {
  background: var(--forest-pale);
  color: var(--forest-deep);
  border-color: var(--forest-pale);
}

/* ---------------------------------------------------------------------------
 * 16. Misc utilities
 * --------------------------------------------------------------------------- */
.muted { color: var(--ink-65); font-size: 0.92em; }

.kv {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 8px 22px;
  font-size: 14px;
}
.kv dt {
  color: var(--ink-65);
  font-size: 12.5px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-weight: 500;
}
.kv dd { margin: 0; font-variant-numeric: tabular-nums; }

.color-chip {
  display: inline-block;
  width: 14px;
  height: 14px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--ink-12);
  vertical-align: middle;
  margin-left: 6px;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.5);
}

.preferred-banks {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 8px 18px;
  margin: 14px 0 18px;
}
.preferred-banks label {
  display: flex;
  gap: 8px;
  align-items: center;
  font-size: 13.5px;
}

.export-menu {
  display: flex;
  gap: 8px;
  align-items: center;
  margin: 14px 0;
  font-size: 12.5px;
  color: var(--ink-65);
}

/* HTMX swap indicator — show a tiny pulse on elements being updated */
.htmx-request { opacity: 0.55; pointer-events: none; transition: opacity 0.1s ease; }

/* ---------------------------------------------------------------------------
 * Transactions filters — pill multi-selects + period pills + KPI strip.
 * Replaces the old single-dropdown filter bar with the streamlit-style
 * "Group by · Holder / Bank / Time" interface.
 * --------------------------------------------------------------------------- */
.txn-filters {
  background: var(--paper);
  border: var(--rule);
  border-radius: var(--radius);
  padding: 18px 20px 14px;
  margin-bottom: 18px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.filter-group {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.filter-group--row {
  flex-direction: row;
  flex-wrap: wrap;
  gap: 12px;
  align-items: flex-end;
}
/* Card-bordered variant. Wraps each Group-by section (Holder / Bank /
   Time / the secondary input row) in its own subtle inset border so the
   user reads the filter region as a series of discrete bins instead of
   a flat blob. The outer ``.txn-filters`` already has its own outer
   border — these are the *inner* dividers. */
.filter-group--card {
  border: 1px solid var(--ink-12);
  border-radius: 10px;
  padding: 12px 14px;
  background: rgba(255, 255, 255, 0.02);
}
/* On dark themes the 2% white inset is barely visible against the
   already-dark .txn-filters; bump the contrast a touch. */
[data-theme="forest"] .filter-group--card,
[data-theme="ink"] .filter-group--card {
  background: rgba(0, 0, 0, 0.18);
  border-color: rgba(255, 255, 255, 0.08);
}

/* ── Per-section colour accents ────────────────────────────────────────
 * Each filter-group--card variant carries a thin 4px coloured left-rule
 * + a faint tint of the same hue, so the user can visually anchor
 * "which filter family is this" at a glance without reading the label.
 *
 * Same intensity recipe as ``.saved-reports-hero``: subtle background
 * tint + a coloured left border. The four accent colours all live in
 * the existing palette so the page reads as one cohesive system, not
 * a Christmas tree.
 *
 *   👥 Holder  → forest      (primary green — people = primary subject)
 *   🏦 Bank    → bronze      (banking/money associations)
 *   📅 Time    → leaf        (lighter green — calendar/period)
 *   🔍 Search  → clay        (warm red — "search/scope" intensity)
 *
 * The dark-theme overrides flip the background to a brighter rgba()
 * so the tint stays visible against the already-dark card-surface;
 * the left-rule colour itself doesn't flip (forest/bronze/leaf/clay
 * are fixed tokens that read on every theme).
 */
.filter-group--card--holder {
  border-left: 4px solid var(--forest);
  background: color-mix(in srgb, var(--forest-pale) 18%, var(--paper));
}
[data-theme="forest"] .filter-group--card--holder,
[data-theme="ink"] .filter-group--card--holder {
  background: rgba(45, 90, 55, 0.18);
}

.filter-group--card--bank {
  border-left: 4px solid var(--bronze);
  background: color-mix(in srgb, var(--bronze-pale) 18%, var(--paper));
}
[data-theme="forest"] .filter-group--card--bank,
[data-theme="ink"] .filter-group--card--bank {
  background: rgba(160, 136, 104, 0.18);
}

.filter-group--card--time {
  /* Use leaf — distinct enough from forest to differentiate at a
     glance, still in the green family so it doesn't fight the rest. */
  border-left: 4px solid #2d5a37;
  background: color-mix(in srgb, #2d5a37 8%, var(--paper));
}
[data-theme="forest"] .filter-group--card--time,
[data-theme="ink"] .filter-group--card--time {
  background: rgba(105, 175, 120, 0.14);
}

.filter-group--card--search {
  /* Clay — the same warm-red token used for negative-direction
     amounts and the destructive data-tools button. Here it's just
     an accent rule, no danger semantics; the colour reads as "this
     is a focused-search/inputs zone" against the cooler greens
     above. */
  border-left: 4px solid #a4452f;
  background: color-mix(in srgb, #a4452f 6%, var(--paper));
}
[data-theme="forest"] .filter-group--card--search,
[data-theme="ink"] .filter-group--card--search {
  background: rgba(204, 110, 90, 0.12);
}
/* The card itself owns the leading label, so squeeze the gap-to-content
   a touch — pills sit closer to their group title. */
.filter-group--card > .filter-group__label:first-child {
  margin-bottom: 8px;
}
/* When the card hosts the secondary row of mixed inputs, switch to a
   CSS grid so every field gets the same column width (instead of the
   flexbox-with-min-width arrangement that left Category orphaned on
   its own row at certain breakpoints). auto-fit + minmax means the row
   wraps cleanly without leaving ragged trailing whitespace. */
.filter-group--card.filter-group--grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 12px 14px;
  align-items: end;
}
/* The free-text search field is the one input that benefits from extra
   breathing room — let it span two grid tracks where space allows. */
.filter-group--card.filter-group--grid > .filter-field--grow {
  grid-column: span 2;
  min-width: 0;          /* override default 240 inside the grid */
}
.filter-group__label {
  font-family: var(--sans);
  font-weight: 500;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-65);
}
.filter-group__sub {
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-45);
  font-weight: 500;
  margin: 6px 0 -2px 2px;
}

/* Compact inline field used in the secondary filter row.
   ``min-width: 0`` lets the field shrink inside a CSS grid track so the
   grid's minmax() floor wins (otherwise the 140px min would conflict
   with auto-fit and cause overflow at narrow widths). The legacy
   flex-row layout still gets the visual width via the grid's minmax. */
.filter-field {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}
.filter-field--grow { flex: 1; min-width: 240px; }
/* Inputs inside the grid card fill their track width — without this
   they default to UA intrinsic width (e.g. ``e.g. 10000`` placeholder
   width) and look uneven. */
.filter-group--grid .filter-field input,
.filter-group--grid .filter-field select {
  width: 100%;
  box-sizing: border-box;
}
.filter-field__label {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-65);
}
.filter-field input[type="text"],
.filter-field input[type="date"],
.filter-field select {
  padding: 7px 10px;
  border: 1px solid var(--ink-25);
  border-radius: var(--radius-sm);
  background: rgba(0, 0, 0, 0.04);
  font: 400 13.5px/1.4 var(--sans);
  color: var(--ink);
}
.filter-field input:focus,
.filter-field select:focus {
  outline: none;
  border-color: var(--forest);
  box-shadow: 0 0 0 2px var(--forest-pale);
}

.filter-actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  margin-top: 2px;
}

/* ---- Pill grid ---- */
.pills {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.pill {
  /* Hide the underlying checkbox; the <label> IS the pill */
  display: inline-flex;
  align-items: center;
  padding: 5px 12px;
  border: 1px solid var(--ink-12);
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink-80);
  font-size: 12.5px;
  font-weight: 500;
  cursor: pointer;
  user-select: none;
  transition: background 0.1s ease, color 0.1s ease, border-color 0.1s ease;
  line-height: 1.3;
}
.pill input[type="checkbox"] {
  /* Visually hide but keep keyboard accessible */
  position: absolute;
  opacity: 0;
  pointer-events: none;
  width: 0; height: 0;
}
.pill:hover {
  background: var(--ink-07);
  border-color: var(--ink-25);
  color: var(--ink);
}
/* Pill selected-state styling.
 *
 * Two trigger rules per pill type — comma-OR'd:
 *   .pill--active        — class added at server render time
 *   .pill:has(input:checked)
 *                        — applied as soon as the user clicks the
 *                          checkbox, even before HTMX returns the new
 *                          HTML (HTMX only swaps #txn-rows, not the
 *                          filter form itself, so the server-rendered
 *                          class wouldn't update without this rule).
 *
 * :has() supported in Chrome 105+ / Edge 105+ / Safari 15.4+ /
 * Firefox 121+ — covers ~98% of users today. Older browsers fall
 * back to the .pill--active behaviour (only correct on server-render).
 */
.pill--active,
.pill:has(input[type="checkbox"]:checked) {
  background: var(--forest);
  color: var(--on-dark);
  border-color: var(--forest);
}
.pill--active:hover,
.pill:has(input[type="checkbox"]:checked):hover {
  background: var(--forest-deep);
  border-color: var(--forest-deep);
  color: var(--on-dark);
}

/* HomeAccess-7 (2026-06-08): semantic status pill variants. Used by
   the SA access-requests queue today; safe to use anywhere a row
   needs a one-word state badge. Each variant pairs a tinted
   background with a darker matching text colour for AA contrast. */
.pill--bronze  { background: rgba(122, 102, 72, 0.12); color: #4a3c25; border-color: rgba(122, 102, 72, 0.28); }
.pill--success { background: rgba(26, 46, 31, 0.10); color: #1a2e1f;  border-color: rgba(26, 46, 31, 0.28); }
.pill--warn    { background: #fceec3; color: #6b4a00; border-color: #ead08a; }
.pill--danger  { background: rgba(180, 60, 40, 0.10); color: #7a2f1c; border-color: rgba(180, 60, 40, 0.30); }

/* Year pills use bronze tone, month pills use sand-bronze — visual
 * variety for the time strip without overwhelming the eye. */
.pill--year.pill--active,
.pill--year:has(input[type="checkbox"]:checked) {
  background: var(--bronze);
  border-color: var(--bronze);
  color: var(--on-dark);
}
.pill--year.pill--active:hover,
.pill--year:has(input[type="checkbox"]:checked):hover {
  background: #66553c;
  border-color: #66553c;
}
.pill--month.pill--active,
.pill--month:has(input[type="checkbox"]:checked) {
  background: var(--bronze-mid);
  border-color: var(--bronze-mid);
  color: var(--on-dark);
}
.pill--month.pill--active:hover,
.pill--month:has(input[type="checkbox"]:checked):hover {
  background: var(--bronze);
  border-color: var(--bronze);
}

/* Subtle indicator on the un-selected pill state too — so people see
 * the cluster is interactive even at rest. The active state's strong
 * tint then reads as the answer to "what did I pick". */
.pill { position: relative; }

/* Keyboard focus indicator on the wrapping label (since the checkbox is hidden) */
.pill input[type="checkbox"]:focus-visible + span {
  outline: 2px solid var(--bronze);
  outline-offset: 3px;
  border-radius: 999px;
}

/* ---- Transactions export card ---- */
.export-card {
  background: var(--paper);
  border: var(--rule);
  border-radius: var(--radius);
  padding: 16px 20px;
  margin: 14px 0 18px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.export-card__row {
  display: flex;
  gap: 18px;
  align-items: flex-start;
  flex-wrap: wrap;
}
.export-card__label {
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--ink-65);
  min-width: 90px;
  padding-top: 6px;     /* baseline-align with the radios + buttons */
}
.export-card__styles {
  border: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 6px 14px;
  flex: 1;
}
.export-style {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 6px 10px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 13.5px;
  color: var(--ink-80);
  transition: background 0.1s ease;
}
.export-style:hover { background: var(--ink-07); }
.export-style input[type="radio"] {
  accent-color: var(--forest);
  flex-shrink: 0;
  margin-top: 2px;
}
.export-style em {
  font-family: var(--serif);
  font-style: italic;
  color: var(--ink-65);
  font-size: 12.5px;
  margin-left: 2px;
}
/* Subtle indicator on the chosen style (uses :has() for the checked
 * radio; the rest of the row stays plain).  */
.export-style:has(input[type="radio"]:checked) {
  background: var(--forest-pale);
  color: var(--forest-deep);
}
.export-card__formats {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

/* ============================================================================
   Shared export-button system (see _partials/_export_buttons.html)

   One visual treatment for every "download as X" button in the app —
   FD detail, FD masters, transactions, reports, anywhere. Each format
   pill has a thick coloured left edge in its brand-tonal accent, a
   paper body, and the format name in caps. Hover flips the body to
   the accent colour so the button reads as primary on intent. Active
   state mirrors the hover for clicky feedback.

   Mapping (see also the macro's _format_meta dict):
     PDF   → clay red   (#A4452F) — print-ready / official document
     XLSX  → forest     (#1A2E1F) — spreadsheet / data
     DOCX  → bronze     (#7A6648) — narrative / text
     HTML  → bronze-mid (#A08868) — web preview / save-as-pdf
     CSV   → forest-mid (#2A4631) — raw data
   ============================================================================ */
.export-row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin: 6px 0;
}
.export-row__label {
  font-size: 0.82rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  color: var(--ink-65);
  white-space: nowrap;
}
.export-row__chips {
  display: inline-flex;
  gap: 6px;
  flex-wrap: wrap;
}

.export-chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  padding: 5px 12px 5px 16px;
  border: 1px solid var(--ink-12);
  background: var(--paper);
  color: var(--ink);
  font: 500 0.78rem/1 var(--sans, "Geist", -apple-system, BlinkMacSystemFont, Arial, sans-serif);
  letter-spacing: 0.05em;
  text-decoration: none;
  border-radius: 3px;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease,
              transform 0.08s ease, box-shadow 0.12s ease;
}
.export-chip:hover {
  transform: translateY(-1px);
  box-shadow: 0 2px 4px rgba(24, 26, 23, 0.08);
  text-decoration: none;
}
.export-chip:active {
  transform: translateY(0);
  box-shadow: none;
}

/* Left accent rail — solid 4-px bar in the format's accent colour. */
.export-chip__accent {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 4px;
  border-radius: 3px 0 0 3px;
  background: var(--ink-65);    /* default; per-format rules override */
}
.export-chip__label {
  margin-left: 0;
}

/* Per-format accents. ``__accent`` paints the left rail; ``:hover``
 * flips the whole chip into the accent colour for the click affordance. */
.export-chip--pdf .export-chip__accent  { background: #A4452F; }
.export-chip--pdf:hover {
  background: #A4452F;
  color: #FBFAF6;
  border-color: #A4452F;
}
.export-chip--pdf:hover .export-chip__accent { background: #6F2C1E; }

.export-chip--xlsx .export-chip__accent { background: #1A2E1F; }
.export-chip--xlsx:hover {
  background: #1A2E1F;
  color: #FBFAF6;
  border-color: #1A2E1F;
}
.export-chip--xlsx:hover .export-chip__accent { background: #0F1D13; }

.export-chip--docx .export-chip__accent { background: #7A6648; }
.export-chip--docx:hover {
  background: #7A6648;
  color: #FBFAF6;
  border-color: #7A6648;
}
.export-chip--docx:hover .export-chip__accent { background: #5A4A33; }

.export-chip--html .export-chip__accent { background: #A08868; }
.export-chip--html:hover {
  background: #A08868;
  color: #FBFAF6;
  border-color: #A08868;
}
.export-chip--html:hover .export-chip__accent { background: #7A6648; }

.export-chip--csv .export-chip__accent  { background: #2A4631; }
.export-chip--csv:hover {
  background: #2A4631;
  color: #FBFAF6;
  border-color: #2A4631;
}
.export-chip--csv:hover .export-chip__accent { background: #1A2E1F; }

/* Focus state for keyboard users — bronze ring, format-agnostic. */
.export-chip:focus-visible {
  outline: 2px solid var(--bronze, #7A6648);
  outline-offset: 2px;
}

/* ── Submit-lock visual ─────────────────────────────────────────────
   The global double-submit guard in base.html adds ``is-submitting``
   to every disabled submit button. We dim + cursor-wait it so the
   user understands their click was received and the form is in
   flight (rather than thinking nothing happened and clicking
   again — which is exactly what produces the double-submit). */
.btn.is-submitting,
button.is-submitting,
input[type="submit"].is-submitting,
.export-chip.is-submitting {
  opacity: 0.65;
  cursor: progress !important;
  pointer-events: none;          /* belt + braces against any stray click */
}

/* Compact variant — used in dense tables where the regular chip
 * would crowd. Smaller padding + font, same accent strip. */
.export-row--compact .export-chip {
  padding: 3px 9px 3px 12px;
  font-size: 0.72rem;
}
.export-row--compact .export-chip__accent { width: 3px; }

/* "visually-hidden" — hide from sight but keep for screen readers */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0);
  white-space: nowrap; border: 0;
}

/* ---- Transactions KPI strip ---- */
.txn-kpis {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  margin-bottom: 14px;
}
@media (max-width: 760px) {
  .txn-kpis { grid-template-columns: repeat(2, 1fr); }
}
.txn-kpi {
  background: var(--paper);
  border: var(--rule);
  border-radius: var(--radius);
  padding: 14px 18px;
  border-left: 3px solid var(--ink-12);
}
.txn-kpi--in  { border-left-color: var(--positive); }
.txn-kpi--out { border-left-color: var(--negative); }
.txn-kpi--net { border-left-color: var(--bronze); }
.txn-kpi__label {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--ink-65);
  margin-bottom: 6px;
}
.txn-kpi__value {
  font-family: var(--serif);
  font-size: 1.45rem;
  font-weight: 400;
  line-height: 1.1;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}
.txn-kpi__caption {
  font-size: 11.5px;
  color: var(--ink-65);
  margin-top: 3px;
}
.txn-kpi--in  .txn-kpi__value { color: var(--positive); }
.txn-kpi--out .txn-kpi__value { color: var(--negative); }

/* ---------------------------------------------------------------------------
 * Dashboard hero (Balance Matrix landing page)
 * Visual reference: vanshOS Brand Book v1.0 + family-office dashboard mock.
 * --------------------------------------------------------------------------- */
.dashboard-hero {
  padding: 8px 0 28px;
  margin-bottom: 12px;
  border-bottom: var(--rule);
}
.dashboard-hero__eyebrow {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-65);
  margin-bottom: 16px;
}
.dashboard-hero__sep { margin: 0 4px; }

.dashboard-hero__row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
}
.dashboard-hero__greeting {
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(2.2rem, 4vw, 3.4rem);
  line-height: 1.05;
  letter-spacing: -0.025em;
  color: var(--ink);
  margin: 0;
}
.dashboard-hero__greeting em {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  color: var(--forest);
}
.dashboard-hero__actions {
  display: flex;
  gap: 10px;
  flex-shrink: 0;
}
.muted-on-dark { color: rgba(255, 255, 255, 0.55); font-weight: 400; }

/* ---- KPI strip ---- */
.dash-kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 14px;
  margin: 28px 0 28px;
}
.dash-kpi {
  background: var(--paper);
  border: var(--rule);
  border-radius: var(--radius);
  padding: 20px 22px;
}
.dash-kpi__label {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-65);
  margin-bottom: 10px;
}
.dash-kpi__value {
  font-family: var(--serif);
  font-size: 2rem;
  font-weight: 300;
  line-height: 1.05;
  color: var(--ink);
  letter-spacing: -0.015em;
  font-variant-numeric: tabular-nums;
  margin-bottom: 4px;
}
/* Full-precision rupee figure sitting under the compact headline.
   Audit-value line — small + muted so the eye reads the headline
   first, but anyone reconciling against a bank statement can still
   see the exact paise without leaving the page. */
.dash-kpi__full {
  font-size: 12px;
  color: var(--ink-65);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  margin-bottom: 6px;
}
.dash-kpi__caption {
  font-size: 12px;
  color: var(--ink-65);
}

/* ── Impersonation banner ────────────────────────────────────────────
 * Pinned strip at the top of every page when a super-admin has started
 * impersonating a tenant. High-contrast warm bronze so the user
 * cannot miss "I am viewing X tenant's data, not the system view".
 * The "Stop impersonating" button sits on the right edge for one-click
 * exit.
 */
.impersonate-banner {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 18px;
  background: var(--bronze);
  color: var(--on-dark);
  border-bottom: 2px solid #5a4d36;
  font-size: 0.92rem;
  letter-spacing: 0.01em;
  position: sticky;
  top: 0;
  z-index: 50;
}
.impersonate-banner__icon { font-size: 1.2rem; line-height: 1; }
.impersonate-banner__text { flex: 1; }
.impersonate-banner__text strong { color: var(--on-dark); font-weight: 600; }
.impersonate-banner__text code {
  background: rgba(255, 255, 255, 0.15);
  padding: 1px 5px;
  border-radius: 3px;
  font-size: 0.85em;
}
.impersonate-banner .muted {
  color: rgba(246, 244, 239, 0.75);
}
.impersonate-banner .btn {
  background: var(--on-dark);
  color: var(--bronze);
  border-color: var(--on-dark);
}
.impersonate-banner .btn:hover {
  background: rgba(246, 244, 239, 0.85);
}

/* Admin → team-member impersonation variant. Visually distinct from
   the SA tenant-impersonation banner (forest instead of bronze) so a
   tenant admin who's previewing as another user doesn't mistake the
   strip for a super-admin context. Same layout + button-on-right
   shape so muscle memory carries over. */
.impersonate-banner--user {
  background: var(--forest);
  border-bottom-color: #0e1b13;
}

/* ============================================================
   Scope banner (Phase PRO-2) — Chartered Accountant safety belt
   --------------------------------------------------------------
   Pinned to the top of <main> while a CA is scoped into a client
   (membership scope != 'full'). Bronze band so it reads as
   "you are working inside someone else's books" — distinct from
   the impersonation banner's role. Matches Mockup D5 / B.
   ============================================================ */
.scope-banner {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  margin: 0 0 18px;
  padding: 10px 16px;
  background: rgba(160, 107, 48, 0.12);
  border: 1px solid rgba(160, 107, 48, 0.30);
  border-radius: 8px;
  font-size: 13px;
  color: var(--ink, #181a17);
}
.scope-banner__pill {
  flex-shrink: 0;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #fbfaf6;
  background: #a06b30;
  padding: 3px 9px;
  border-radius: 4px;
}
.scope-banner__text { flex: 1; min-width: 240px; }
.scope-banner__text strong { font-weight: 600; }
.scope-banner__text em { font-style: italic; color: #a06b30; }
.scope-banner__actions { display: flex; gap: 16px; flex-shrink: 0; }
.scope-banner__actions a {
  font-size: 12.5px;
  font-weight: 600;
  color: #a06b30;
  text-decoration: none;
}
.scope-banner__actions a:hover { color: var(--ink, #181a17); }

/* CA sidebar footnote — the demoted "not in your scope" line. */
.sidebar__scope-note {
  margin: 14px 20px 0;
  padding-top: 12px;
  border-top: 1px dashed var(--ink-12, rgba(24, 26, 23, 0.12));
  font-size: 11px;
  line-height: 1.45;
  color: var(--ink-65, rgba(24, 26, 23, 0.55));
}

/* ============================================================
   Super-admin tenant switcher (Phase E2)
   --------------------------------------------------------------
   Pinned to the top-right of <main> for every super-admin page
   render. Self-contained dropdown — Alpine.js handles open/close,
   the CSS just paints. Sits ABOVE the impersonation banner in
   z-index so the dropdown menu never gets clipped by it.
   ============================================================ */
.tenant-switcher {
  position: absolute;
  top: 14px;
  right: 22px;
  z-index: 60;
  /* Right-align under any sticky banner so the dropdown panel
     opens flush with the column edge regardless of viewport. */
}
.tenant-switcher__button {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  border-radius: 6px;
  background: var(--paper);
  border: 1px solid var(--bronze);
  color: var(--ink);
  font: inherit;
  font-size: 0.88rem;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease;
  box-shadow: 0 1px 2px rgba(0,0,0,0.04);
}
.tenant-switcher__button:hover {
  background: var(--forest-pale, rgba(122, 102, 72, 0.08));
  border-color: var(--forest, #1a2e1f);
}
.tenant-switcher__icon {
  font-size: 1rem;
  line-height: 1;
}
.tenant-switcher__label {
  font-weight: 500;
  letter-spacing: 0.01em;
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tenant-switcher__chevron {
  flex-shrink: 0;
  color: var(--bronze);
}
.tenant-switcher__menu {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  min-width: 280px;
  max-width: 360px;
  background: var(--paper);
  border: 1px solid var(--bronze);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 70vh;
  overflow-y: auto;
}
.tenant-switcher__hint {
  font-size: 0.78rem;
  color: var(--bronze);
  padding: 6px 10px 8px;
  border-bottom: 1px solid rgba(122, 102, 72, 0.18);
  margin-bottom: 4px;
}
.tenant-switcher__row {
  display: block;
  margin: 0;
}
.tenant-switcher__item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  width: 100%;
  text-align: left;
  background: transparent;
  border: none;
  padding: 8px 10px;
  border-radius: 4px;
  cursor: pointer;
  color: var(--ink);
  font: inherit;
  font-size: 0.9rem;
  transition: background 0.1s ease;
}
.tenant-switcher__item:hover {
  background: var(--forest-pale, rgba(26, 46, 31, 0.06));
}
.tenant-switcher__item--current {
  background: var(--forest-pale, rgba(26, 46, 31, 0.10));
  font-weight: 600;
}
.tenant-switcher__item--current::after {
  content: " ✓";
  color: var(--forest, #1a2e1f);
}
.tenant-switcher__item--system {
  color: var(--bronze);
  font-style: italic;
  border-bottom: 1px solid rgba(122, 102, 72, 0.18);
  margin-bottom: 4px;
  border-radius: 0;
}
.tenant-switcher__row-name {
  display: block;
  line-height: 1.25;
}
.tenant-switcher__row-slug {
  display: block;
  font-family: var(--mono, monospace);
  font-size: 0.75rem;
  line-height: 1.2;
}
.tenant-switcher__row-status {
  display: inline-block;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 1px 5px;
  border-radius: 3px;
  margin-top: 2px;
  background: rgba(122, 102, 72, 0.15);
  color: var(--bronze);
}

/* Bank scope badge — used on /admin/masters/banks (Phase G4) +
   /sa/masters/banks (Phase G3) to mark each row global vs tenant.
   Forest accent for global (this is the SA-managed canonical
   catalog), neutral muted for tenant-private rows. */
.scope-badge {
  display: inline-block;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 2px 7px;
  border-radius: 3px;
  white-space: nowrap;
}
.scope-badge--global {
  background: var(--forest-pale, rgba(26, 46, 31, 0.10));
  color: var(--forest);
  border: 1px solid rgba(26, 46, 31, 0.20);
}
.scope-badge--tenant {
  background: rgba(122, 102, 72, 0.10);
  color: var(--bronze);
  border: 1px solid rgba(122, 102, 72, 0.18);
}

/* PRE-BOOKS badge — used on the FD ledger to mark FD-side rows
   that have no bank counterpart. Triggered by ``paired_txn_id IS
   NULL`` (every "normal" FD-ledger row is paired with a bank-side
   leg; the unpaired ones are either legacy-FD creation credits or
   skip-bank-posting interest receives — both flavours of
   pre-books / historical data the user back-filled).

   Same visual shape as ``.scope-badge`` (same dimensions, same
   uppercase styling, sibling block) so the two badges read as the
   same kind of UI element. Bronze accent matches the "historical /
   pre-books" semantic already established by ``.pill--year`` and
   ``matured_unreceived`` status styling — quiet, doesn't dominate
   the row, but visible at a glance when scanning the ledger.

   See ``app/templates/fixed_deposits/ledger_tab.html`` +
   ``detail.html`` for the consumers. */
.txn-badge {
  display: inline-block;
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 1px 6px;
  border-radius: 3px;
  white-space: nowrap;
  margin-left: 6px;
  vertical-align: middle;
  cursor: help;  /* surfaces the title= tooltip on hover */
}
.txn-badge--pre-books {
  background: rgba(122, 102, 72, 0.10);
  color: var(--bronze);
  border: 1px solid rgba(122, 102, 72, 0.18);
}

/* Phase ReceiveDeepLink (2026-05-25): flash highlight applied to
   the matching schedule <tbody id="sched-XYZ"> when the page loads
   with a #sched-XYZ hash. JS adds the class for ~2.5s then removes
   it; the keyframes do a brief bronze fade. Keeps the user oriented
   when they're deep-linked in from a dashboard reminder or masters
   row Receive button. */
.sched-row--flash {
  animation: schedRowFlash 2.5s ease-out forwards;
}
@keyframes schedRowFlash {
  0%   { background-color: rgba(122, 102, 72, 0.22); box-shadow: inset 3px 0 0 var(--bronze); }
  60%  { background-color: rgba(122, 102, 72, 0.18); box-shadow: inset 3px 0 0 var(--bronze); }
  100% { background-color: transparent;              box-shadow: inset 3px 0 0 transparent; }
}

.tenant-switcher__empty {
  padding: 12px 10px;
  font-size: 0.85rem;
  text-align: center;
}

/* On narrow screens drop the switcher's anchor a touch lower so
   the hamburger icon (also top-left/right region) doesn't crowd it. */
@media (max-width: 720px) {
  .tenant-switcher {
    top: 14px;
    right: 12px;
  }
  .tenant-switcher__label { max-width: 120px; }
}

/* OD-additional sub-line on the Net Balance tile. Sits between the
   audit-precision figure and the caption — calls out the OD line of
   credit as available headroom without folding it into the headline
   net number. Bronze accent to visually distinguish "credit
   available" from "money owned" (the figures above it). */
.dash-kpi__od {
  font-size: 12.5px;
  color: var(--bronze);
  font-variant-numeric: tabular-nums;
  margin: -2px 0 6px;
  line-height: 1.3;
}
.dash-kpi__od strong { font-weight: 600; }
[data-theme="forest"] .dash-kpi__od,
[data-theme="ink"]    .dash-kpi__od { color: var(--bronze-mid); }

/* ---- Two-card row ---- */
.dash-grid {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: 18px;
  margin-bottom: 18px;
}
@media (max-width: 920px) { .dash-grid { grid-template-columns: 1fr; } }

.dash-card {
  background: var(--paper);
  border: var(--rule);
  border-radius: var(--radius);
  padding: 22px 24px;
}
.dash-card--wide { grid-column: 1 / -1; margin-bottom: 18px; }

.dash-card__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 16px;
}
.dash-card__title {
  font-family: var(--serif);
  font-weight: 400;
  font-size: 1.1rem;
  letter-spacing: -0.005em;
  color: var(--ink);
  margin: 0;
}
.dash-card__sub {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-45);
}
.dash-card__legend {
  font-size: 12px;
  color: var(--ink-65);
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.dash-card__legend-dot {
  display: inline-block;
  width: 8px; height: 8px;
  border-radius: 50%;
}
.dash-card__legend-dot--ink { background: var(--forest); }

.dash-card__empty {
  padding: 36px 8px;
  text-align: center;
  color: var(--ink-45);
  font-size: 13px;
}

/* ---- Net-worth chart axis ---- */
.dash-card__chart { position: relative; }
.dash-card__chart-axis {
  display: flex;
  justify-content: space-between;
  font-size: 11px;
  color: var(--ink-45);
  margin-top: 6px;
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
}

/* ---- Allocation donut + legend ---- */
.dash-allocation {
  display: flex;
  align-items: center;
  gap: 22px;
  flex-wrap: wrap;
}
.dash-donut {
  position: relative;
  width: 132px;
  height: 132px;
  border-radius: 50%;
  flex-shrink: 0;
}
.dash-donut__hole {
  position: absolute;
  inset: 22px;
  background: var(--paper);
  border-radius: 50%;
}
.dash-allocation__legend {
  list-style: none;
  margin: 0;
  padding: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 7px;
  min-width: 160px;
}
.dash-allocation__legend li {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 13px;
  color: var(--ink-80);
}
.dash-allocation__swatch {
  display: inline-block;
  width: 10px; height: 10px;
  border-radius: 2px;
  flex-shrink: 0;
}
.dash-allocation__name { flex: 1; }
.dash-allocation__pct {
  font-variant-numeric: tabular-nums;
  font-weight: 500;
  color: var(--ink);
  font-feature-settings: "tnum";
}

/* ---- Activity feed ---- */
.dash-activity {
  list-style: none;
  margin: 0;
  padding: 0;
}
.dash-activity__row {
  display: grid;
  grid-template-columns: 32px 1fr auto auto;
  gap: 14px;
  align-items: center;
  padding: 12px 0;
  border-bottom: var(--rule-soft);
  font-size: 13.5px;
}
.dash-activity__row:last-child { border-bottom: none; }

.dash-activity__icon {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.dash-activity__icon--in {
  background: var(--positive-bg);
  color: var(--positive);
}
.dash-activity__icon--out {
  background: var(--negative-bg);
  color: var(--negative);
}

.dash-activity__body { min-width: 0; }
.dash-activity__title {
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-family: var(--serif);
  font-size: 0.95rem;
}
.dash-activity__meta {
  font-size: 11px;
  color: var(--ink-45);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin-top: 2px;
}
.dash-activity__sep { margin: 0 4px; }

.dash-activity__account {
  font-size: 12.5px;
  color: var(--ink-65);
  text-align: right;
  white-space: nowrap;
}
.dash-activity__amount {
  font-family: var(--mono);
  font-size: 13.5px;
  font-weight: 500;
  text-align: right;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}
.dash-activity__amount--in  { color: var(--positive); }
.dash-activity__amount--out { color: var(--negative); }

/* ---------------------------------------------------------------------------
 * Import-wizard "Importing into …" card
 * Sits at the top of each wizard step so the user can confirm the account
 * context before committing. See app/templates/imports/_account_header.html.
 * --------------------------------------------------------------------------- */
.import-account-card {
  background: var(--paper);
  border: var(--rule);
  border-left: 3px solid var(--forest);
  border-radius: var(--radius);
  padding: 14px 18px;
  margin: 0 0 20px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.import-account-card--warn {
  border-left-color: var(--warn);
  background: var(--warn-bg);
}
.import-account-card__label {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-65);
}
.import-account-card__primary {
  font-family: var(--serif);
  font-size: 1.25rem;
  font-weight: 400;
  line-height: 1.25;
  color: var(--ink);
  letter-spacing: -0.005em;
}
.import-account-card__primary .mono {
  font-family: var(--mono);
  font-size: 0.92em;
  font-weight: 500;
  color: var(--ink);
  font-feature-settings: "tnum";
}
.import-account-card__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 18px;
  font-size: 13px;
  color: var(--ink-65);
  margin-top: 4px;
}
.import-account-card__meta strong {
  font-weight: 500;
  color: var(--ink-80);
}
.import-account-card__meta .mono {
  font-family: var(--mono);
  font-size: 0.92em;
}

/* ---------------------------------------------------------------------------
 * Scrollbars — make the OS-default chrome match the warm palette on
 * WebKit. Firefox uses scrollbar-color (color/track pair).
 * --------------------------------------------------------------------------- */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--ink-25) transparent;
}
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb { background: var(--ink-12); border-radius: 999px; border: 2px solid transparent; background-clip: padding-box; }
*::-webkit-scrollbar-thumb:hover { background: var(--ink-25); background-clip: padding-box; border: 2px solid transparent; }

/* ============================================================================
 * Reports builder — /reports
 *
 * Streamlit-style ad-hoc report builder with search chips, 3-level groupby,
 * treemap + bar visualisations, and a collapsible drill-down tree.
 * ============================================================================ */

/* Chip multiselect for search terms ---------------------------------------- */
.report-builder__terms {
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  padding: 6px 8px;
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-radius: 10px;
  min-height: 40px;
}
.chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 4px 4px 10px;
  background: var(--bronze-pale);
  border-radius: 999px;
  font-size: 0.875rem; color: var(--ink);
}
.chip input[name="terms"] {
  background: transparent; border: 0; outline: 0;
  font: inherit; color: inherit;
  min-width: 80px; width: 14ch;
  padding: 0; margin: 0;
}
.chip__x {
  background: transparent; border: 0;
  color: var(--bronze); cursor: pointer;
  width: 22px; height: 22px; border-radius: 999px;
  font-size: 1.05rem; line-height: 1; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background 0.1s ease;
}
.chip__x:hover { background: rgba(0,0,0,0.08); }

.btn--small { padding: 4px 10px; font-size: 0.85rem; }

/* ============================================================================
 * Reports builder — two-box AND-of-OR search-term layout
 * Two side-by-side chip-input boxes with a visible "AND" badge
 * between them. Each box behaves like the old single-box (OR within
 * the box); rows must hit BOTH boxes to be kept.
 * ============================================================================ */
.report-builder__terms-pair {
  /* Wider than the legacy single-box layout — the two boxes need
     breathing room. */
  width: 100%;
}
.report-builder__terms-row {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 16px;
  align-items: stretch;
  margin-top: 6px;
}
.report-builder__terms-box {
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-radius: 10px;
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.report-builder__terms-box-label {
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-65);
}
.report-builder__terms-and {
  align-self: center;
  font-family: var(--serif);
  font-size: 0.95rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  color: var(--bronze);
  padding: 6px 10px;
  border: 1px dashed var(--bronze-pale);
  border-radius: 999px;
  background: var(--card);
}
@media (max-width: 720px) {
  .report-builder__terms-row {
    grid-template-columns: 1fr;
  }
  .report-builder__terms-and {
    justify-self: center;
  }
}

/* ============================================================================
 * Generic bordered "filter card" — same look as the AND/OR term boxes
 * above, applied to other filter clusters (holder pills, bank pills,
 * grouping + date/direction row). Gives the builder a clear visual
 * hierarchy where each filter family is its own card.
 * ============================================================================ */
.filter-card {
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-radius: 10px;
  padding: 10px 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 12px;
}
.filter-card > .filter-group__label {
  /* The label inside a card hugs the top edge — overrides the default
     ``.filter-group__label`` margin so cards look tight. */
  margin-bottom: 2px;
}
/* Row variant — children flow left-to-right and wrap if the viewport
   gets tight. Used for the grouping-and-date card where 6 fields
   share one line on a wide screen but stack gracefully below ~960px. */
.filter-card--row {
  flex-direction: column;
}
.filter-card--row .filter-card__items {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 14px 18px;
}
.filter-card--row .filter-field {
  /* Each select / date input takes its natural width but doesn't
     squeeze below a usable minimum. */
  flex: 0 1 auto;
  min-width: 140px;
}

/* Stacked action buttons living at the right edge of a row-card.
   Pushes itself to the extreme right via auto-margin (works even
   when the flex container wraps), anchors to the bottom of the
   row so the buttons line up with the inputs' baselines. */
.filter-card__actions {
  margin-left: auto;
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-self: flex-end;
  min-width: 110px;
}
.filter-card__actions .btn {
  width: 100%;
}

@media (max-width: 720px) {
  .filter-card--row .filter-field {
    flex: 1 1 calc(50% - 9px);
  }
  /* On narrow viewports the action stack moves to its own row at
     the end of the card; full width buttons read better there. */
  .filter-card__actions {
    margin-left: 0;
    width: 100%;
  }
}

/* ============================================================================
 * Reports — Saved-reports hero + contextual save-current strip
 * ============================================================================
 *
 * Two distinct affordances on /reports, intentionally NOT side-by-side:
 *
 *   .saved-reports-hero   ENTRY point at the TOP of /reports. Accent-
 *                         highlighted card with one-tap chips for every
 *                         saved report + a dropdown fallback. The front
 *                         door for power users who reach /reports
 *                         already knowing which view they want.
 *
 *   .save-current-strip   EXIT point after the builder. Muted by
 *                         default; switches to an accent-highlighted
 *                         state via .save-current-strip--ready when the
 *                         server-side "dirty" flag detects any non-
 *                         default filter.
 *
 * Together they replace the legacy .saved-reports 2-column grid that
 * sat below the builder and gave equal visual weight to two actions
 * with very different intents.
 * ============================================================================ */

/* ── Top hero: Apply a saved report ──────────────────────────────────────── */
.saved-reports-hero {
  background: color-mix(in srgb, var(--forest-pale) 35%, var(--paper));
  border: 1px solid color-mix(in srgb, var(--forest) 30%, var(--ink-12));
  border-left: 4px solid var(--forest);
  border-radius: 12px;
  padding: 16px 20px;
  margin: 0 0 20px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
[data-theme="forest"] .saved-reports-hero,
[data-theme="ink"] .saved-reports-hero {
  background: rgba(255, 255, 255, 0.04);
  border-color: rgba(255, 255, 255, 0.16);
  border-left-color: var(--bronze);
}

.saved-reports-hero__head {
  display: flex;
  align-items: center;
  gap: 10px;
}
.saved-reports-hero__icon { font-size: 1.1rem; line-height: 1; }
.saved-reports-hero__title {
  font-family: var(--serif);
  font-size: 1.05rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  color: var(--ink);
}
.saved-reports-hero__count {
  margin-left: auto;
  font-size: 0.8rem;
  letter-spacing: 0.04em;
}

/* Chip grid — one-tap apply per saved report. */
.saved-reports-hero__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.saved-reports-hero__chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border: 1px solid var(--ink-12);
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink);
  font-size: 0.86rem;
  font-weight: 500;
  text-decoration: none;
  transition: background 0.1s ease, border-color 0.1s ease, color 0.1s ease;
  line-height: 1.3;
}
.saved-reports-hero__chip:hover {
  background: var(--forest);
  border-color: var(--forest);
  color: var(--on-dark);
}
.saved-reports-hero__chip-arrow {
  font-size: 0.7rem;
  opacity: 0.7;
  transition: opacity 0.1s ease;
}
.saved-reports-hero__chip:hover .saved-reports-hero__chip-arrow { opacity: 1; }

/* Dropdown fallback for browsing the full list. */
.saved-reports-hero__pick {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 2px;
}
.saved-reports-hero__pick-label {
  font-size: 0.82rem;
  color: var(--ink-65);
  font-weight: 500;
  letter-spacing: 0.04em;
}
.saved-reports-hero__pick-select {
  min-width: 240px;
  padding: 6px 10px;
  border: 1px solid var(--ink-12);
  border-radius: 8px;
  background: var(--paper);
  color: var(--ink);
  font: 400 13.5px/1.4 var(--sans);
}

/* Manage row inside a <details> — collapsed by default. */
.saved-reports-hero__manage {
  margin-top: 2px;
  border-top: 1px dashed var(--ink-12);
  padding-top: 10px;
}
[data-theme="forest"] .saved-reports-hero__manage,
[data-theme="ink"] .saved-reports-hero__manage {
  border-top-color: rgba(255, 255, 255, 0.10);
}
.saved-reports-hero__manage > summary {
  cursor: pointer;
  font-size: 0.85rem;
  letter-spacing: 0.04em;
  padding: 4px 0;
}
.saved-reports-hero__manage-list {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 4px 16px;
}
.saved-reports-hero__manage-list .inline-form {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 0;
  /* Keep name + Delete clustered at the start of the row so the
     Delete button sits immediately after the report name rather
     than getting pushed to the far right of the grid cell — that
     gap of empty space made it unclear which Delete belongs to
     which name when there are multiple saved reports. */
  justify-content: flex-start;
}
.saved-reports-hero__manage-name {
  /* No flex:1 — let the span take its content width so the
     adjacent Delete sits right next to the text. The grid cell
     stays as wide as the auto-fit dictates; any leftover space
     simply remains empty to the right of the Delete button. */
  font-size: 0.88rem;
  color: var(--ink);
}

.saved-reports-hero__empty {
  margin: 4px 0 0;
  font-size: 0.92rem;
  line-height: 1.5;
}

/* ── Save-current strip ─────────────────────────────────────────────────── */
.save-current-strip {
  margin-top: 16px;
  padding: 12px 16px;
  border: 1px dashed var(--ink-12);
  border-radius: 10px;
  background: rgba(0, 0, 0, 0.02);
  transition: background 0.15s ease, border-color 0.15s ease,
              box-shadow 0.15s ease;
}
[data-theme="forest"] .save-current-strip,
[data-theme="ink"] .save-current-strip {
  background: rgba(255, 255, 255, 0.02);
  border-color: rgba(255, 255, 255, 0.10);
}

/* Dirty state — filters set, save is meaningful. Accent highlight so
   the primary action catches the eye exactly when there's something
   worth saving. */
.save-current-strip--ready {
  border: 1px solid var(--bronze);
  border-left: 4px solid var(--bronze);
  background: color-mix(in srgb, var(--bronze-pale) 28%, var(--paper));
  box-shadow: 0 1px 6px -2px rgba(122, 102, 72, 0.25);
}
[data-theme="forest"] .save-current-strip--ready,
[data-theme="ink"] .save-current-strip--ready {
  background: rgba(255, 255, 255, 0.06);
  border-color: var(--bronze);
  border-left-color: var(--bronze);
}

.save-current-strip__form {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.save-current-strip__lead {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 0 1 320px;
  min-width: 0;
}
.save-current-strip__icon { font-size: 1.4rem; line-height: 1; }
.save-current-strip__copy { line-height: 1.3; min-width: 0; }
.save-current-strip__title {
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--ink);
}
.save-current-strip__hint {
  font-size: 0.78rem;
  letter-spacing: 0.01em;
  margin-top: 2px;
}
.save-current-strip__name {
  flex: 1 1 240px;
  min-width: 200px;
  padding: 8px 12px;
  border: 1px solid var(--ink-12);
  border-radius: 8px;
  background: var(--paper);
  color: var(--ink);
  font: 400 13.5px/1.4 var(--sans);
}
.save-current-strip__name:disabled {
  opacity: 0.55;
  cursor: not-allowed;
  background: rgba(0, 0, 0, 0.03);
}
[data-theme="forest"] .save-current-strip__name:disabled,
[data-theme="ink"] .save-current-strip__name:disabled {
  background: rgba(0, 0, 0, 0.20);
}
.save-current-strip__form .btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

@media (max-width: 760px) {
  .save-current-strip__form { flex-direction: column; align-items: stretch; }
  .save-current-strip__lead { flex: 0 0 auto; }
  .save-current-strip__name { width: 100%; }
}

/* Chart wrappers ----------------------------------------------------------- */
.report-charts {
  display: grid; grid-template-columns: 1fr 1fr; gap: 20px;
}
@media (max-width: 980px) {
  .report-charts { grid-template-columns: 1fr; }
}
.report-chart {
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-radius: 12px;
  padding: 14px 16px;
}
.report-chart > summary {
  font-family: var(--serif); font-weight: 600;
  color: var(--forest); cursor: pointer;
  padding: 2px 0 10px 0;
  list-style: none;
}
.report-chart > summary::-webkit-details-marker { display: none; }
.report-chart > summary::before {
  content: "▸"; display: inline-block; width: 18px;
  color: var(--bronze); transition: transform 0.15s ease;
}
.report-chart[open] > summary::before { transform: rotate(90deg); }

/* Drill-down tree --------------------------------------------------------- */
.report-tree {
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-radius: 12px;
  padding: 6px 10px;
}
.report-node { margin: 4px 0; padding-left: 6px; border-left: 2px solid var(--forest-pale); }
.report-node[open] { border-left-color: var(--bronze); }
.report-node > summary {
  cursor: pointer;
  padding: 6px 4px;
  border-radius: 6px;
  list-style: none;
  display: flex; align-items: center; gap: 10px;
}
.report-node > summary:hover { background: var(--ivory); }
.report-node > summary::-webkit-details-marker { display: none; }
.report-node > summary::before {
  content: "▸"; display: inline-block; width: 14px;
  color: var(--bronze);
}
.report-node[open] > summary::before { content: "▾"; }
.report-node__axis {
  text-transform: uppercase; letter-spacing: 0.05em;
  font-size: 0.7rem; color: var(--bronze);
  background: var(--bronze-pale);
  padding: 2px 8px; border-radius: 4px;
  flex-shrink: 0;
}
/* Label takes whatever width it needs and `flex-grow: 1` makes it
   expand to fill the remaining row width — this pushes the totals
   cluster to the right edge of the row, where the user expects them. */
.report-node__label {
  font-weight: 500; color: var(--ink);
  flex-grow: 1;
}
.report-node__totals {
  display: inline-flex; gap: 14px; align-items: baseline;
  font-size: 0.85rem; font-variant-numeric: tabular-nums;
}
/* Each total cell is a fixed-width [sign][amount] flexbox: sign
   sticks to the LEFT edge, amount snaps to the RIGHT edge. Combined
   with the same min-width across all three cells AND across all
   rows, the numbers line up vertically — easy to scan a drill-down
   column. ``min-width`` chosen so a typical 8-digit Indian-formatted
   amount (e.g. ₹1,89,407.00) fits without ever overflowing.

   Use theme-aware tokens instead of hardcoded earth-tone hex.
   --positive / --negative are bumped to bright leaf-green / coral
   under dark themes (see lines ~2879-2892), so the drill-down
   amounts stay readable on forest + ink + auto-dark. */
.report-node__inflow,
.report-node__outflow,
.report-node__net {
  display: inline-flex;
  justify-content: space-between;
  align-items: baseline;
  min-width: 13ch;
  gap: 4px;
}
.report-node__inflow  { color: var(--positive); }
.report-node__outflow { color: var(--negative); }
.report-node__net     { font-weight: 600; color: var(--forest); }
.report-node__sign {
  flex-shrink: 0;
  font-weight: 600;
}
.report-node__amt {
  flex-shrink: 0;
}
.report-node__body { padding: 4px 0 4px 22px; }

.data-table--compact th,
.data-table--compact td { padding: 4px 8px; font-size: 0.85rem; }

/* ============================================================================
 * Data entry — /entry add-transaction page
 * ============================================================================ */

/* 2-column grid for date/cheque + amount/direction rows */
.form-grid--2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px 20px;
  margin-bottom: 16px;
}
@media (max-width: 600px) {
  .form-grid--2 { grid-template-columns: 1fr; }
}
/* Grid items default to min-width: auto, which lets a <select> with long
   <option> text (e.g. transaction particulars) blow out its 1fr track and
   shove the second column off-screen. Forcing min-width: 0 on the items
   and width: 100% on the inputs/selects inside keeps each column inside
   its 1fr slot regardless of intrinsic content width. */
.form-grid--2 > * { min-width: 0; }
.form-grid--2 .form__field > select,
.form-grid--2 .form__field > input { width: 100%; max-width: 100%; }

.form__field--radio-group {
  border: 0; padding: 0; margin: 0;
  display: flex; flex-direction: column;
}
.form__field--radio-group > legend.form__label { padding: 0; margin-bottom: 6px; }
.form__field--radio-group > .radio-pill + .radio-pill { margin-top: 6px; }

.radio-pill {
  display: inline-flex; align-items: center;
  gap: 10px; padding: 8px 14px;
  border: 1px solid var(--ink-12);
  border-radius: 10px;
  background: var(--paper); cursor: pointer;
  transition: border-color 0.1s ease, background 0.1s ease;
  font-size: 0.95rem;
}
.radio-pill:hover { border-color: var(--bronze); }
.radio-pill input[type="radio"] { margin: 0; accent-color: var(--forest); }
.radio-pill em { color: var(--ink-65); font-style: normal; font-size: 0.85rem; }
.radio-pill:has(input[type="radio"]:checked) {
  background: var(--forest-pale); border-color: var(--forest);
  /* --forest-pale is a fixed light sage in every theme (never redefined
     in any [data-theme=...] block), but --ink flips to light cream on
     dark themes. Without an explicit color, the checked-pill text reads
     light-on-light-sage → invisible. Pin the text to the dark ink value
     so the checked pill is always legible regardless of theme. */
  color: #181a17;
}
.radio-pill:has(input[type="radio"]:checked) em { color: rgba(24, 26, 23, 0.65); }

.data-entry-tabs { gap: 4px; flex-wrap: wrap; }
.data-entry-help { margin-top: 10px; max-width: 760px; }
.data-entry-picker { margin: 16px 0 12px 0; gap: 12px; align-items: flex-end; }
.data-entry-balance {
  padding: 8px 12px;
  background: var(--bronze-pale);
  border-radius: 8px;
  display: inline-flex; gap: 10px;
  margin: 8px 0 16px 0;
  font-size: 0.95rem;
}
.data-entry-empty { padding: 32px 0; font-size: 1.05rem; }

.data-entry-recent {
  margin-top: 32px;
  padding: 18px 22px;
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-radius: 12px;
}
.data-entry-recent__title {
  font-family: var(--serif);
  font-size: 1.1rem; font-weight: 600;
  color: var(--forest); margin: 0 0 12px 0;
}
.data-entry-recent__title .muted { font-weight: 400; font-size: 0.9rem; }

.form__hint { font-size: 0.85rem; }
.form__actions { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }

/* When .form__actions sits as a final direct child of a .form (the
   common "submit row at the bottom of a vertical form" pattern), give
   it real breathing room from the last input + a dashed top divider
   so the primary CTA reads as a distinct zone instead of crowding the
   text box above it. The 18px gap from .form alone wasn't enough —
   users were perceiving the button as visually stuck to the last field.
   The :last-child guard keeps mid-form action rows (rare but possible)
   from getting the divider. */
.form > .form__actions:last-child {
  margin-top: 6px;
  padding-top: 18px;
  border-top: 1px dashed var(--ink-12);
}
/* Dashed dividers in dark themes need a brighter rule color or they
   disappear into the card surface. */
[data-theme="forest"] .form > .form__actions:last-child,
[data-theme="ink"] .form > .form__actions:last-child {
  border-top-color: rgba(255, 255, 255, 0.10);
}

/* ============================================================================
 * Bank-wise summary cards — /overview Balance Matrix page
 *
 * Ports the streamlit "Total bank-wise · summary cards" grid (app.py:1659).
 * Each card has:
 *   - a 4px coloured top ribbon driven by the matched BankAlertTier
 *     (the colour is set via the inline `--ribbon` custom property so the
 *     template can data-bind without us emitting one class per tier).
 *   - a small tier-label pill in the top-right with the same colour.
 *   - the bank name in serif (Spectral), the balance in large sans
 *     (Geist), and a tiny holder-count footer.
 *   - an optional pulse animation on cards in the highest tier
 *     (`.bank-card--pulse`) — draws the eye to the most-urgent ones.
 * ============================================================================ */
.bank-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 18px;
  margin: 16px 0 32px 0;
}

.bank-card {
  position: relative;
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-top: 4px solid var(--ribbon, var(--bronze));
  border-radius: 12px;
  padding: 18px 20px 14px 20px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.bank-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 20px rgba(24, 26, 23, 0.08);
}

.bank-card__head {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 10px; margin-bottom: 4px;
}
.bank-card__name {
  font-family: var(--serif); font-weight: 600;
  font-size: 1.05rem; color: var(--forest-deep);
  margin: 0; line-height: 1.2;
  /* Long bank names ("STANDARD CHARTERED") get to wrap rather than
     overflow the card; CHF is intentional. */
  word-break: break-word;
}
.bank-card__tier-badge {
  font-size: 0.65rem; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--on-dark);
  padding: 3px 8px; border-radius: 4px;
  flex-shrink: 0; line-height: 1.2;
  white-space: nowrap;
}
.bank-card__pref {
  font-size: 0.7rem; color: var(--bronze);
  font-weight: 500; flex-shrink: 0;
  white-space: nowrap;
}

.bank-card__amount {
  font-family: var(--sans);
  font-size: 1.5rem; font-weight: 600;
  color: var(--ink); letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  margin-top: 4px;
}
/* Sibling line carrying the exact rupee total for the bank card.
   Matches the KPI strip's audit-value pattern. Only renders when
   the balance is ≥ ₹1 L (below that, the compact filter already
   shows the full number, so a sibling line would be redundant). */
.bank-card__full {
  font-size: 0.78rem;
  color: var(--ink-65);
  font-variant-numeric: tabular-nums;
  margin-top: 2px;
  line-height: 1.2;
}
.bank-card__usd {
  font-size: 0.85rem; line-height: 1.4;
  margin-top: -2px;
}
.bank-card__usd-equiv {
  margin-left: 6px; font-size: 0.78rem;
  color: var(--ink-45);
}

.bank-card__foot {
  margin-top: auto; padding-top: 8px;
  font-size: 0.8rem;
  border-top: 1px solid var(--ink-07);
}

/* Pulse animation for top-tier cards. Subtle — just enough to draw the
 * eye without becoming distracting. Respects prefers-reduced-motion. */
.bank-card--pulse {
  animation: bank-card-pulse 2.4s ease-in-out infinite;
}
@keyframes bank-card-pulse {
  0%, 100% { box-shadow: 0 0 0 0 var(--ribbon, transparent); }
  50%      { box-shadow: 0 0 0 6px rgba(0, 0, 0, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .bank-card--pulse { animation: none; }
}

/* ============================================================================
 * Bank card click-to-drill (extends the .bank-card grid above)
 *
 * The cards are now <button>s so the keyboard + screen-reader story is
 * built-in (Enter/Space + aria-expanded). Click toggles an Alpine.js
 * ``active`` state on the wrapper; one drill panel per bank lives in
 * the DOM and only the active one is visible.
 * ============================================================================ */

/* Make the card behave like a real card while remaining a <button> */
.bank-card--btn {
  font: inherit; color: inherit; text-align: left;
  width: 100%; cursor: pointer;
  appearance: none;
  /* Override default button paddings — .bank-card already has its own */
}
.bank-card--btn:focus-visible {
  outline: 2px solid var(--forest);
  outline-offset: 2px;
}
.bank-card--open {
  /* Make the active card visually anchored — bronze ring + slight
     lift so it's obvious which card's data is shown below. */
  box-shadow: 0 0 0 2px var(--bronze), 0 6px 20px rgba(24, 26, 23, 0.10);
  transform: translateY(-2px);
}

.bank-card__chevron {
  font-size: 0.95rem; color: var(--bronze);
  transition: transform 0.12s ease;
  margin-left: auto;  /* push to the right inside the footer flex */
  display: inline-block;
}
.bank-card__chevron--open { transform: rotate(180deg); }
.bank-card__foot {
  display: flex; justify-content: space-between; align-items: center;
}

[x-cloak] { display: none !important; }

/* Drill panel ------------------------------------------------------------- */
.bank-drill {
  margin: 16px 0 32px 0;
  padding: 18px 22px 22px 22px;
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-left: 3px solid var(--bronze);
  border-radius: 12px;
}
.bank-drill__head {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 14px;
}
.bank-drill__title {
  font-family: var(--serif); font-weight: 600;
  font-size: 1.15rem; color: var(--forest-deep);
  margin: 0;
}
.bank-drill__icon { margin-right: 4px; }
.bank-drill__close {
  background: transparent; border: 0; cursor: pointer;
  width: 32px; height: 32px; border-radius: 999px;
  color: var(--bronze); font-size: 1.4rem; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background 0.1s ease;
}
.bank-drill__close:hover { background: var(--bronze-pale); }

.bank-drill__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 14px;
}

/* Category section inside the drill panel.
   Each section gets a thin top-rule + a header line carrying the
   category name and its section subtotal, then the existing holder
   card grid sits below. Stacks of sections separate visually without
   reading as separate cards — same panel, just labelled bands. */
.bank-drill__section {
  margin-top: 18px;
}
.bank-drill__section:first-child {
  margin-top: 8px;
}
.bank-drill__section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 6px 0 10px;
  margin-bottom: 6px;
  border-bottom: 1px solid var(--ink-12);
}
.bank-drill__section-name {
  font-family: var(--sans);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  color: var(--bronze);
}
.bank-drill__section-meta {
  font-size: 0.82rem;
  font-variant-numeric: tabular-nums;
}

/* Holder mini-card inside the drill panel --------------------------------- */
.holder-card {
  position: relative;
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-top: 4px solid var(--ribbon, var(--bronze));
  border-radius: 10px;
  padding: 14px 16px 12px 16px;
  display: flex; flex-direction: column; gap: 4px;
}
.holder-card__tier-badge {
  position: absolute; top: -8px; right: 10px;
  font-size: 0.62rem; font-weight: 600;
  letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--on-dark);
  padding: 3px 7px; border-radius: 4px;
  line-height: 1; white-space: nowrap;
}
.holder-card__name {
  font-family: var(--serif); font-weight: 600;
  font-size: 0.95rem; color: var(--forest-deep);
  line-height: 1.2;
}
.holder-card__amount {
  font-family: var(--sans);
  font-size: 1.2rem; font-weight: 600;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  margin-top: 2px;
}
.holder-card__sub {
  font-size: 0.78rem;
  line-height: 1.35;
  margin-top: 2px;
}
.holder-card__sep { color: var(--ink-25); margin: 0 4px; }

.holder-card--pulse {
  animation: bank-card-pulse 2.4s ease-in-out infinite;
}

/* ============================================================================
 * Holder mini-cards — account-type colouring
 *
 * Each holder card now carries a typed chip ("SAVING" / "CURRENT" / "OD"
 * / "OTHER") with a colour that matches a faint background wash on the
 * card. The colours are picked from the brand palette:
 *
 *   SAVING   — forest tint  (long-term, "growth" mood)
 *   CURRENT  — bronze tint  (operating capital, "working" mood)
 *   OD       — clay tint    (debit, "attention" mood)
 *   OTHER    — neutral grey (fallback for unknown types)
 *
 * The card's top ribbon (alert tier) still wins the eye — the type
 * colour is a secondary signal layered on top of paper. This keeps the
 * alert hierarchy intact while giving an instant read of the kind of
 * account.
 * ============================================================================ */

/* Base chip — a small uppercase pill. */
.holder-card__type {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  line-height: 1.4;
  white-space: nowrap;
}

/* Saving — forest green */
.holder-card__type--saving {
  background: var(--forest-pale);
  color: var(--forest-deep);
}
.holder-card--type-saving {
  background:
    linear-gradient(
      to bottom,
      color-mix(in srgb, var(--forest-pale) 40%, transparent) 0%,
      transparent 80%
    ),
    var(--paper);
}

/* Current — bronze warm */
.holder-card__type--current {
  background: var(--bronze-pale);
  color: var(--bronze);
}
.holder-card--type-current {
  background:
    linear-gradient(
      to bottom,
      color-mix(in srgb, var(--bronze-pale) 35%, transparent) 0%,
      transparent 80%
    ),
    var(--paper);
}

/* OD — clay (red-brown) — picked up automatically when the helper
   surfaces an "OD" account type in the future. */
.holder-card__type--od {
  background: #f3d6c8;
  color: #6e2e1d;
}
.holder-card--type-od {
  background:
    linear-gradient(
      to bottom,
      rgba(243, 214, 200, 0.40) 0%,
      transparent 80%
    ),
    var(--paper);
}

/* Other — neutral fallback */
.holder-card__type--other {
  background: var(--ink-07);
  color: var(--ink-65);
}

/* ─── AccountType badge colours ──────────────────────────────────────────
 * The badge now reflects the holder's real entity shape from
 * ``AccountType`` (Individual / Company / HUF / Partnership / Trust)
 * — set per-account in masters. Category sits in the section header
 * above the card, so it doesn't need to repeat on the badge.
 *
 * Each chip class colours the badge text; the corresponding
 * ``--type-<slug>`` class paints a faint tint on the whole card so
 * a glance separates personal vs company vs trust without reading.
 * ─────────────────────────────────────────────────────────────────────── */

/* Individual — most common, leans warm-green to feel personal. */
.holder-card__type--individual {
  background: var(--forest-pale);
  color: var(--forest-deep);
}
.holder-card--type-individual {
  background:
    linear-gradient(
      to bottom,
      color-mix(in srgb, var(--forest-pale) 40%, transparent) 0%,
      transparent 80%
    ),
    var(--paper);
}

/* Company — bronze, signals the entity side of the book. */
.holder-card__type--company {
  background: var(--bronze-pale);
  color: var(--bronze);
}
.holder-card--type-company {
  background:
    linear-gradient(
      to bottom,
      color-mix(in srgb, var(--bronze-pale) 35%, transparent) 0%,
      transparent 80%
    ),
    var(--paper);
}

/* HUF — golden sand; sits between Individual and Company shape. */
.holder-card__type--huf {
  background: #f0e3c4;
  color: #6b5b2e;
}
.holder-card--type-huf {
  background:
    linear-gradient(
      to bottom,
      rgba(240, 227, 196, 0.45) 0%,
      transparent 80%
    ),
    var(--paper);
}

/* Partnership — clay (warm red-brown). Reuses the same hue family
   the old --od class used; partnerships are joint commercial entities,
   feels right to lean warmer. */
.holder-card__type--partnership {
  background: #f3d6c8;
  color: #6e2e1d;
}
.holder-card--type-partnership {
  background:
    linear-gradient(
      to bottom,
      rgba(243, 214, 200, 0.40) 0%,
      transparent 80%
    ),
    var(--paper);
}

/* Trust — formal, cool grey-blue tone. */
.holder-card__type--trust {
  background: #d9def0;
  color: #2c3a5e;
}
.holder-card--type-trust {
  background:
    linear-gradient(
      to bottom,
      rgba(217, 222, 240, 0.45) 0%,
      transparent 80%
    ),
    var(--paper);
}

/* Tighten the sub-line spacing once the chip replaces the plain text. */
.holder-card__sub {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  font-size: 0.78rem;
  line-height: 1.35;
  margin-top: 4px;
}

/* ============================================================================
 * Transaction row actions — Phase 2 of the access model.
 * The pencil + trash buttons in the last column of /transactions.
 * Compact + low-contrast at rest; pop on hover.
 * ============================================================================ */
.txn-row-actions {
  white-space: nowrap;
  text-align: right;
}

/* Narration cell on /transactions + the recent-entries panel.
   Narration can be very long (multi-sentence notes); cap the column
   at ~24 chars and let the rest spill to a ``title`` tooltip on hover.
   Muted colour + smaller line-height so the narration reads as
   subordinate context to the bolder Particulars in the column beside
   it. */
.txn-narration {
  max-width: 240px;
  font-size: 0.85rem;
  color: var(--ink-65);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ============================================================================
 * Data tools — admin-only destructive bulk-mutation wizards
 * Lives under /admin/data-tools/*. The visual language leans cautious:
 * card surfaces are slightly recessed, the typed-CONFIRM gate uses
 * mono-spaced inputs + a red Execute button so the action's gravity
 * is unmissable.
 * ============================================================================ */
.data-tools-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
  gap: 18px;
  margin-top: 18px;
}
.data-tools-card {
  background: var(--card);
  border: 1px solid var(--ink-12);
  border-radius: 12px;
  padding: 18px 20px;
  display: flex;
  flex-direction: column;          /* so the CTA can pin to the bottom */
}
/* Push the action button to the bottom of every card so all three line up
   on the same row regardless of differing copy length. */
.data-tools-card .btn {
  margin-top: auto;
  align-self: flex-start;          /* keep natural width, not full-bleed */
}
.data-tools-card h2 {
  margin: 0 0 8px;
  font-size: 1.15rem;
}
.data-tools-card__bullets {
  margin: 12px 0 14px 0;
  padding-left: 18px;
  font-size: 0.88rem;
  line-height: 1.55;
}
.data-tools-card__bullets li { margin-bottom: 2px; }

/* Confirmation panel — last step before the destructive POST. */
.data-tools-confirm {
  max-width: 720px;
  margin-top: 18px;
  padding: 20px 24px;
  background: var(--card);
  border: 2px solid var(--negative);
  border-radius: 12px;
  box-shadow: 0 4px 22px -6px rgba(138, 58, 46, 0.20);
}
.data-tools-confirm__head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
  padding-bottom: 12px;
  border-bottom: 1px dashed var(--ink-12);
}
.data-tools-confirm__icon {
  font-size: 1.3rem;
  color: var(--negative);
}
.data-tools-confirm__title {
  font-family: var(--serif);
  font-size: 1.2rem;
  font-weight: 500;
  color: var(--ink);
}
.data-tools-confirm__details {
  display: grid;
  grid-template-columns: 140px 1fr;
  gap: 8px 16px;
  margin: 0;
  font-size: 0.92rem;
}
.data-tools-confirm__details dt {
  color: var(--ink-65);
  font-weight: 500;
  text-transform: uppercase;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  padding-top: 3px;
}
.data-tools-confirm__details dd { margin: 0; }
.data-tools-confirm__chip {
  display: inline-block;
  padding: 3px 10px;
  margin: 2px 4px 2px 0;
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-radius: 6px;
  font-family: var(--mono);
  font-size: 0.85rem;
  color: var(--ink);
}
.data-tools-confirm__chip--target {
  background: var(--bronze-pale);
  border-color: var(--bronze);
  color: var(--bronze);
  font-weight: 600;
}
.data-tools-confirm__notes {
  margin: 16px 0 0;
  padding: 12px 14px 12px 32px;
  background: var(--paper);
  border-radius: 8px;
  font-size: 0.88rem;
  color: var(--ink-80);
  line-height: 1.5;
}
.data-tools-confirm__warning {
  margin-top: 18px;
  padding: 12px 16px;
  background: var(--negative-bg);
  border-left: 4px solid var(--negative);
  border-radius: 4px;
  font-size: 0.92rem;
  color: var(--ink);
}
.data-tools-confirm__form {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px dashed var(--ink-12);
}

/* Disabled Execute button: muted + no-cursor. Re-uses .btn--danger
   tokens elsewhere. */
.data-tools-confirm__form .btn--danger[disabled] {
  opacity: 0.35;
  cursor: not-allowed;
  pointer-events: none;
}

/* Very faint hint above a DataGrid table — used to mention things
   like "Narration is hidden by default". Deliberately low-contrast:
   visible if you're looking for it, ignorable if you're not. */
.datagrid-faint-hint {
  margin: 4px 0 8px;
  font-size: 0.72rem;
  color: var(--ink-45);
  font-style: italic;
  letter-spacing: 0.01em;
}
.datagrid-faint-hint em {
  font-style: normal;
  font-weight: 500;
  color: var(--ink-65);
}
.txn-row-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px; height: 26px;
  border-radius: 6px;
  border: 0; background: transparent;
  color: var(--bronze);
  font-size: 14px; line-height: 1; cursor: pointer;
  text-decoration: none;
  transition: background 0.1s ease, color 0.1s ease;
}
.txn-row-action:hover {
  background: var(--bronze-pale);
  color: var(--forest-deep);
}
.txn-row-action--danger { color: #a4452f; }   /* clay */
.txn-row-action--danger:hover {
  background: #f3d6c8;
  color: #6e2e1d;
}
.txn-row-actions .inline-form {
  display: inline-block;
  margin-left: 2px;
}

/* ============================================================================
 * Matrix-extras cells on /overview Balance Matrix
 * Signed-amount columns get coloured per direction: green for credits
 * (positive — broker owes us), red for debits (negative — we owe).
 * ============================================================================ */
.matrix-extra-cell      { font-variant-numeric: tabular-nums; }
.matrix-extra-cell--pos { color: var(--positive); }
.matrix-extra-cell--neg { color: var(--negative); }

/* ============================================================================
 * View-toggle — segmented control on /overview's Balance Matrix header.
 * Three pills (Bank balances / Holdings & limits / Full matrix). The
 * active one fills with forest; inactive ones sit in bronze-pale.
 * Plain <a> links: clicking is a real navigation to /overview?view=...
 * so the URL stays bookmarkable.
 * ============================================================================ */
.view-toggle {
  display: inline-flex;
  gap: 0;
  padding: 3px;
  margin: 12px 0 0 0;
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-radius: 999px;
  /* Sits inline so it doesn't push the page-header description down too far */
  vertical-align: middle;
}
.view-toggle__pill {
  /* Reset anchor underline (inherited from base `a`) */
  border-bottom: 0;
  padding: 7px 16px;
  border-radius: 999px;
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--ink-65);
  text-decoration: none;
  letter-spacing: 0.01em;
  white-space: nowrap;
  transition: background 0.1s ease, color 0.1s ease;
}
.view-toggle__pill:hover { background: var(--bronze-pale); color: var(--ink); }
.view-toggle__pill--active {
  background: var(--forest);
  color: var(--on-dark);
}
.view-toggle__pill--active:hover {
  background: var(--forest-deep);
  color: var(--on-dark);
}
@media (max-width: 640px) {
  /* On narrow screens the pills stack into a column rather than overflow */
  .view-toggle { flex-direction: column; gap: 2px; }
  .view-toggle__pill { width: 100%; text-align: center; }
}

/* ============================================================================
 * Theme tokens — per-user theme via data-theme attribute on <html>.
 *
 * Paper is the :root default (already defined at the top of this file).
 * Sand / Forest / Ink override the surface + ink tokens; the brand
 * accents (--forest, --bronze) stay the same in every theme so logos
 * + tier badges keep their identity.
 *
 * "auto" follows the OS prefers-color-scheme media query — light = Paper,
 * dark = Forest. Users who explicitly pick paper/sand/forest/ink always
 * get their pick regardless of OS.
 *
 * See app/services/auth_service.py::VALID_THEMES + the picker at
 * /profile.
 * ============================================================================ */

/* ─── Sand: warmer paper.  Surface gets warmer, ink stays dark. ─── */
[data-theme="sand"] {
  --ivory:  #ece6d8;
  --paper:  #f3eede;
  --sand:   #ddd1ba;
  --bone:   #d2c6a9;
  /* Card surface stays solid (slightly off the sand paper). */
  --card:   #fbf6ea;
  /* Ink + alpha ladder stay default; forest + bronze stay default. */
}

/* ─── Dark theme token overrides shared by Forest + Ink ─── */
[data-theme="forest"],
[data-theme="ink"] {
  /* Surfaces → dark green / black; cards lift slightly with a +1
     shade so the layered hierarchy is still legible. */
  --ink:     #f6f4ef;          /* text + foreground flips to paper */
  --ink-80:  rgba(246, 244, 239, 0.85);
  --ink-65:  rgba(246, 244, 239, 0.70);
  --ink-45:  rgba(246, 244, 239, 0.50);
  --ink-25:  rgba(246, 244, 239, 0.28);
  --ink-12:  rgba(246, 244, 239, 0.14);
  --ink-07:  rgba(246, 244, 239, 0.08);
  /* Rules use ink alpha already, so they automatically lighten too. */
}

[data-theme="forest"] {
  --ivory:  #1a2e1f;            /* page = forest */
  --paper:  #233c2a;            /* cards a touch lighter */
  --sand:   #2a4631;
  --bone:   #2e4b35;
  /* Card surface (floating popovers, inputs, dropdowns) — a notch
     brighter than --paper so it pops above the page even when it
     overlaps another --paper panel. Solid colour, not rgba, so the
     dropdown doesn't bleed through to whatever sits beneath. */
  --card:   #2e4a36;
}

[data-theme="ink"] {
  --ivory:  #181a17;            /* near-black page */
  --paper:  #232520;            /* card surface */
  --sand:   #2a2c26;
  --bone:   #2e302b;
  --card:   #2c2e28;
}

/* ─── Auto: follow OS preference. Light OS = Paper (no override
        needed); Dark OS = Forest. ─── */
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] {
    --ivory:  #1a2e1f;
    --paper:  #233c2a;
    --sand:   #2a4631;
    --bone:   #2e4b35;
    --card:   #2e4a36;
    --ink:     #f6f4ef;
    --ink-80:  rgba(246, 244, 239, 0.85);
    --ink-65:  rgba(246, 244, 239, 0.70);
    --ink-45:  rgba(246, 244, 239, 0.50);
    --ink-25:  rgba(246, 244, 239, 0.28);
    --ink-12:  rgba(246, 244, 239, 0.14);
    --ink-07:  rgba(246, 244, 239, 0.08);
  }
}

/* ─── Dark-mode tweaks for individual components ─── */

/* Brand mark: "v" + "ansh" both pick up the dark-text colour by
   default. On dark themes we want them in paper so they're visible
   against the dark surface. ".os" stays bronze in every theme. */
[data-theme="forest"] .brand-mark__v,
[data-theme="ink"] .brand-mark__v,
[data-theme="forest"] .brand-mark__ansh,
[data-theme="ink"] .brand-mark__ansh {
  color: var(--ink);
  font-style: normal;  /* dropping the italic on dark — improves legibility */
}
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] .brand-mark__v,
  [data-theme="auto"] .brand-mark__ansh {
    color: var(--ink);
    font-style: normal;
  }
}

/* Balance Matrix header band uses --forest as its background — on a
   forest theme that'd be invisible (forest-on-forest). Swap to bronze
   so the band still pops. Ink theme keeps forest since the page is
   actually black, not green. */
[data-theme="forest"] .data-table--matrix thead th,
[data-theme="forest"] .data-table--matrix thead th.sticky {
  background: var(--bronze);
}
[data-theme="forest"] .data-table--matrix thead tr {
  box-shadow: inset 0 -2px 0 var(--forest-mid);
}

/* totals-row in tables uses --bone for background. On dark themes
   that's already a darker shade, so contrast is fine — no override
   needed. The num--total cells inherit the same. */

/* Bank card pulse animation uses --ribbon (data-bound) as a shadow.
   In dark themes the card itself is dark, so the box-shadow is barely
   visible against the surrounding ivory which is also dark. Boost
   the pulse intensity on dark themes. */
[data-theme="forest"] .bank-card--pulse,
[data-theme="ink"] .bank-card--pulse {
  animation-name: bank-card-pulse-dark;
}
@keyframes bank-card-pulse-dark {
  0%, 100% { box-shadow: 0 0 0 0 var(--ribbon, transparent); }
  50%      { box-shadow: 0 0 0 8px rgba(255, 255, 255, 0.04); }
}

/* Input fields — the default uses bone-coloured borders which work
   light or dark. But the input background was paper which now
   matches the card surface. Slightly darken so they read as
   "interactive" against the card. */
[data-theme="forest"] .form input[type="text"],
[data-theme="forest"] .form input[type="date"],
[data-theme="forest"] .form input[type="number"],
[data-theme="forest"] .form input[type="email"],
[data-theme="forest"] .form input[type="password"],
[data-theme="forest"] .form select,
[data-theme="forest"] .form textarea,
[data-theme="forest"] .admin-table input[type="text"],
[data-theme="forest"] .admin-table input[type="date"],
[data-theme="forest"] .admin-table input[type="number"],
[data-theme="forest"] .admin-table input[type="email"],
[data-theme="forest"] .admin-table input[type="password"],
[data-theme="forest"] .admin-table select,
[data-theme="forest"] .admin-table textarea,
[data-theme="forest"] .filter-bar select,
[data-theme="forest"] .filter-bar input[type="text"],
[data-theme="forest"] .filter-bar input[type="date"],
[data-theme="forest"] .filter-field input[type="text"],
[data-theme="forest"] .filter-field input[type="date"],
[data-theme="forest"] .filter-field select,
[data-theme="forest"] .bulk-table input,
[data-theme="forest"] .bulk-table select,
[data-theme="forest"] .bulk-table textarea,
[data-theme="ink"] .form input[type="text"],
[data-theme="ink"] .form input[type="date"],
[data-theme="ink"] .form input[type="number"],
[data-theme="ink"] .form input[type="email"],
[data-theme="ink"] .form input[type="password"],
[data-theme="ink"] .form select,
[data-theme="ink"] .form textarea,
[data-theme="ink"] .admin-table input[type="text"],
[data-theme="ink"] .admin-table input[type="date"],
[data-theme="ink"] .admin-table input[type="number"],
[data-theme="ink"] .admin-table input[type="email"],
[data-theme="ink"] .admin-table input[type="password"],
[data-theme="ink"] .admin-table select,
[data-theme="ink"] .admin-table textarea,
[data-theme="ink"] .filter-bar select,
[data-theme="ink"] .filter-bar input[type="text"],
[data-theme="ink"] .filter-bar input[type="date"],
[data-theme="ink"] .filter-field input[type="text"],
[data-theme="ink"] .filter-field input[type="date"],
[data-theme="ink"] .filter-field select,
[data-theme="ink"] .bulk-table input,
[data-theme="ink"] .bulk-table select,
[data-theme="ink"] .bulk-table textarea {
  background: rgba(0, 0, 0, 0.22);
  color: var(--ink);
  border-color: rgba(192, 161, 115, 0.30);   /* bronze @ 30% */
}
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] .form input[type="text"],
  [data-theme="auto"] .form input[type="date"],
  [data-theme="auto"] .form input[type="number"],
  [data-theme="auto"] .form input[type="email"],
  [data-theme="auto"] .form input[type="password"],
  [data-theme="auto"] .form select,
  [data-theme="auto"] .form textarea,
  [data-theme="auto"] .admin-table input[type="text"],
  [data-theme="auto"] .admin-table input[type="date"],
  [data-theme="auto"] .admin-table input[type="number"],
  [data-theme="auto"] .admin-table input[type="email"],
  [data-theme="auto"] .admin-table input[type="password"],
  [data-theme="auto"] .admin-table select,
  [data-theme="auto"] .admin-table textarea,
  [data-theme="auto"] .filter-bar select,
  [data-theme="auto"] .filter-bar input[type="text"],
  [data-theme="auto"] .filter-bar input[type="date"],
  [data-theme="auto"] .filter-field input[type="text"],
  [data-theme="auto"] .filter-field input[type="date"],
  [data-theme="auto"] .filter-field select,
  [data-theme="auto"] .bulk-table input,
  [data-theme="auto"] .bulk-table select,
  [data-theme="auto"] .bulk-table textarea {
    background: rgba(0, 0, 0, 0.22);
    color: var(--ink);
    border-color: rgba(192, 161, 115, 0.30);
  }
}

/* Native <option> elements inside an open <select> popup are rendered by
   the OS, not the page. Chrome on Windows draws the popup with a light
   system background; the option text inherits the <select>'s color which
   on our dark themes (forest/ink) is near-white → invisible light-on-light.
   Force a safe dark-on-light scheme on every <option> so dropdowns are
   readable regardless of theme. (The closed-select display, which IS
   page-DOM, still uses the theme color via the rule above.) */
.form select option,
select option {
  color: #1a1a1a;
  background: #ffffff;
}

/* ============================================================================
 * Theme picker on /profile
 * ============================================================================ */
.theme-picker {
  display: flex; flex-wrap: wrap; gap: 12px;
  margin: 12px 0 24px 0;
}
.theme-swatch {
  display: flex; flex-direction: column; align-items: stretch;
  width: 132px;
  border: 2px solid var(--ink-12);
  border-radius: 10px;
  background: var(--paper);
  cursor: pointer;
  padding: 0;
  overflow: hidden;
  transition: border-color 0.1s ease, transform 0.1s ease, box-shadow 0.1s ease;
}
.theme-swatch:hover {
  border-color: var(--bronze);
  transform: translateY(-1px);
}
.theme-swatch--active {
  border-color: var(--forest);
  box-shadow: 0 0 0 3px var(--forest-pale);
}
.theme-swatch__preview {
  height: 60px;
  display: grid;
  grid-template-columns: 1fr 1fr;
}
.theme-swatch__half { display: block; }
.theme-swatch__label {
  font-family: var(--serif);
  font-weight: 500;
  font-size: 0.95rem;
  padding: 8px 10px 4px;
  color: var(--ink);
}
.theme-swatch__sub {
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  color: var(--ink-65);
  padding: 0 10px 8px;
  text-transform: uppercase;
}

/* Per-theme preview colours — these don't depend on the active theme
   because we want all 5 swatches to always look the same. */
.theme-swatch--paper  .theme-swatch__half:first-child  { background: #f6f4ef; }
.theme-swatch--paper  .theme-swatch__half:last-child   { background: #1a2e1f; }
.theme-swatch--sand   .theme-swatch__half:first-child  { background: #ece6d8; }
.theme-swatch--sand   .theme-swatch__half:last-child   { background: #7a6648; }
.theme-swatch--forest .theme-swatch__half:first-child  { background: #1a2e1f; }
.theme-swatch--forest .theme-swatch__half:last-child   { background: #7a6648; }
.theme-swatch--ink    .theme-swatch__half:first-child  { background: #181a17; }
.theme-swatch--ink    .theme-swatch__half:last-child   { background: #7a6648; }
.theme-swatch--auto   .theme-swatch__half:first-child  { background: linear-gradient(135deg, #f6f4ef 50%, #1a2e1f 50%); }
.theme-swatch--auto   .theme-swatch__half:last-child   { background: linear-gradient(135deg, #f6f4ef 50%, #7a6648 50%); }

/* ============================================================================
 * Dark-theme readability overrides (forest / ink / auto-dark)
 *
 * The Paper theme's state colours (#406b48 olive-green, #8a3a2e clay)
 * read as muddy on dark backgrounds. We brighten them to fully-saturated
 * leaf-green + coral-red so they stay readable in low-light themes,
 * AND swap the bg tokens from light tints to translucent overlays so
 * flash/badge backgrounds stay subtle.
 *
 * We also flip a handful of component-level text colours that were
 * hard-coded to --forest / --forest-deep — invisible on a forest page.
 * ============================================================================ */

/* Shared state-colour overrides across both dark themes. */
[data-theme="forest"],
[data-theme="ink"] {
  --positive:    #7fc78a;                       /* bright leaf green */
  --negative:    #f47a6a;                       /* bright coral red */
  --warn:        #e9b25a;                       /* honey */
  --positive-bg: rgba(127, 199, 138, 0.10);
  --warn-bg:     rgba(233, 178, 90, 0.10);
  --negative-bg: rgba(244, 122, 106, 0.10);
}

/* And mirror the same overrides under auto (OS-dark) so all three
   dark cases share one ruleset. */
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] {
    --positive:    #7fc78a;
    --negative:    #f47a6a;
    --warn:        #e9b25a;
    --positive-bg: rgba(127, 199, 138, 0.10);
    --warn-bg:     rgba(233, 178, 90, 0.10);
    --negative-bg: rgba(244, 122, 106, 0.10);
  }
}

/* ─── Active view-toggle pill ────────────────────────────────────
   Default fill = --forest. On the Forest theme the page IS forest,
   so the active pill becomes invisible. Bronze instead — same brand
   palette, full contrast on both forest and ink. */
[data-theme="forest"] .view-toggle__pill--active,
[data-theme="ink"] .view-toggle__pill--active {
  background: var(--bronze);
  color: var(--on-dark);
}
[data-theme="forest"] .view-toggle__pill--active:hover,
[data-theme="ink"] .view-toggle__pill--active:hover {
  background: var(--bronze-mid);
}
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] .view-toggle__pill--active {
    background: var(--bronze);
    color: var(--on-dark);
  }
  [data-theme="auto"] .view-toggle__pill--active:hover {
    background: var(--bronze-mid);
  }
}

/* ─── Section headings that hard-code --forest as text ─────────── */
/* On dark themes those text colours are forest-on-forest = invisible.
   Flip to --ink, which is paper-coloured under the dark token map. */
[data-theme="forest"] h2,
[data-theme="forest"] h3,
[data-theme="ink"] h2,
[data-theme="ink"] h3,
[data-theme="forest"] .bank-card__name,
[data-theme="ink"]    .bank-card__name,
[data-theme="forest"] .holder-card__name,
[data-theme="ink"]    .holder-card__name,
[data-theme="forest"] .bank-drill__title,
[data-theme="ink"]    .bank-drill__title,
[data-theme="forest"] .data-entry-recent__title,
[data-theme="ink"]    .data-entry-recent__title,
[data-theme="forest"] .dashboard-hero__greeting,
[data-theme="ink"]    .dashboard-hero__greeting,
[data-theme="forest"] .report-chart > summary,
[data-theme="ink"]    .report-chart > summary,
[data-theme="forest"] .report-node__net,
[data-theme="ink"]    .report-node__net {
  color: var(--ink);
}
/* The italic "<em>name</em>" inside the greeting uses --forest as a
   brand accent. On dark themes that's the same colour family as the
   page, so the name becomes nearly invisible. Swap to bronze-mid —
   warmer brand accent that pops against both forest-deep and ink
   backgrounds. */
[data-theme="forest"] .dashboard-hero__greeting em,
[data-theme="ink"]    .dashboard-hero__greeting em {
  color: var(--bronze-mid);
}
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] h2,
  [data-theme="auto"] h3,
  [data-theme="auto"] .bank-card__name,
  [data-theme="auto"] .holder-card__name,
  [data-theme="auto"] .bank-drill__title,
  [data-theme="auto"] .data-entry-recent__title,
  [data-theme="auto"] .dashboard-hero__greeting,
  [data-theme="auto"] .report-chart > summary,
  [data-theme="auto"] .report-node__net {
    color: var(--ink);
  }
  [data-theme="auto"] .dashboard-hero__greeting em {
    color: var(--bronze-mid);
  }
}

/* ─── Sidebar token corrections for sand theme ─────────────────────
   The sidebar uses its own --sb-* token scope (dark always); the page
   tokens we flipped don't affect it. But Sand has a slightly warmer
   page colour that creates a thin contrast band against the sidebar —
   harmless. No override needed here, but logged for future tweaks. */

/* ─── Matrix header band: tighten text contrast on Forest ──────── */
/* Already bronze background. Force the text to ivory (always light)
   so it doesn't pick up a low-contrast `--paper` that varies per
   theme. Same for the totals row's first cell. */
[data-theme="forest"] .data-table--matrix thead th,
[data-theme="forest"] .data-table--matrix thead th.sticky {
  color: #f6f4ef;       /* hard-coded ivory; readable on any bronze */
  font-weight: 700;
  letter-spacing: 0.08em;
}

/* ============================================================================
 * Dark-theme activity icon visibility
 *
 * The chevron-up / chevron-down circles next to each activity row use
 * the --positive-bg / --negative-bg tokens. On dark themes those are
 * rgba overlays at 10% opacity — almost invisible against dark
 * surfaces. Bump to 22% so the coloured ring around the arrow is
 * actually a ring, not a ghost. Also thicken the SVG stroke from
 * 1.5px to 2px so the chevron itself stays crisp at small sizes.
 * ============================================================================ */
[data-theme="forest"] .dash-activity__icon--in,
[data-theme="ink"]    .dash-activity__icon--in {
  background: rgba(127, 199, 138, 0.22);
}
[data-theme="forest"] .dash-activity__icon--out,
[data-theme="ink"]    .dash-activity__icon--out {
  background: rgba(244, 122, 106, 0.22);
}
[data-theme="forest"] .dash-activity__icon svg,
[data-theme="ink"]    .dash-activity__icon svg {
  stroke-width: 2;
}

/* Same set under prefers-color-scheme:dark for the auto theme. */
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] .dash-activity__icon--in {
    background: rgba(127, 199, 138, 0.22);
  }
  [data-theme="auto"] .dash-activity__icon--out {
    background: rgba(244, 122, 106, 0.22);
  }
  [data-theme="auto"] .dash-activity__icon svg {
    stroke-width: 2;
  }
}

/* ============================================================================
 * Matrix-extras GRID data entry
 * Recorder types new closing balances into a holder × column grid that
 * mirrors the Balance Matrix on /overview. Each cell shows the current
 * latest balance as muted text above an empty input — recorder reads
 * the current value, types only what changed today, submits the whole
 * grid in one POST.
 * ============================================================================ */
.matrix-grid-form {
  /* Wider than the single-row form — the grid can have many columns. */
  max-width: none;
}

.matrix-grid-toolbar {
  display: flex;
  align-items: flex-end;
  gap: 24px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}
.matrix-grid-toolbar .form__field {
  max-width: 200px;
}
.matrix-grid-toolbar__hint {
  flex: 1 1 320px;
  margin: 0;
  font-size: 0.88rem;
  line-height: 1.45;
}

.matrix-grid-wrap {
  /* Horizontal scroll if many columns — date column stays sticky-left. */
  overflow-x: auto;
  margin-bottom: 16px;
}

.matrix-grid-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
}
.matrix-grid-table th,
.matrix-grid-table td {
  vertical-align: top;
}
.matrix-grid-table thead th {
  font-weight: 600;
  font-size: 0.88rem;
  padding: 10px 12px;
  border-bottom: 1px solid var(--ink-12);
  white-space: nowrap;
}
.matrix-grid-table__col-sub {
  font-weight: 400;
  font-size: 0.72rem;
  color: var(--ink-65);
  margin-top: 2px;
  white-space: nowrap;
}
.matrix-grid-table__holder-col,
.matrix-grid-table__holder-cell {
  text-align: left;
  position: sticky;
  left: 0;
  /* Phase EntryTabs (2026-06-08): bumped z-index from 1 → 5 + added a
     right-edge box-shadow so scrolled-under cell inputs can't bleed
     across visually. The shadow doubles as a visual cue that the
     column is frozen. The header row uses z-index: 6 so it wins over
     the row holder cells when both stick at the same offset. */
  background: var(--card);
  z-index: 5;
  min-width: 180px;
  padding: 12px 14px;
  font-weight: 500;
  border-right: 1px solid var(--ink-12);
  box-shadow: 2px 0 4px -2px rgba(0, 0, 0, 0.08);
}
.matrix-grid-table thead .matrix-grid-table__holder-col {
  /* Phase EntryTabs (2026-06-08): the generic ``.data-table th`` rule
     forces ``background: transparent`` with higher specificity than
     ``.matrix-grid-table__holder-col`` alone — that's why the HOLDER
     header was see-through while body rows were fine. Re-asserting an
     opaque card background here under a more specific selector wins
     the cascade. z-index: 6 keeps the header above body holder cells
     when both stick at the same left offset. */
  z-index: 6;
  background: var(--card);
}
/* Re-assert the holder cell background on every row (odd + even) so
   the zebra-stripe rule below doesn't accidentally make the sticky
   column see-through. Both --card and --paper are fully opaque hex,
   so this just guarantees the explicit win. */
.matrix-grid-table tbody tr:nth-child(odd)  .matrix-grid-table__holder-cell {
  background: var(--card);
}
.matrix-grid-table tbody tr:nth-child(even) .matrix-grid-table__holder-cell {
  background: var(--paper);
}
.matrix-grid-table__od-col {
  border-left: 2px solid var(--ink-12);
}

.matrix-grid-cell {
  padding: 8px 10px;
  min-width: 140px;
  border-bottom: 1px solid var(--ink-07);
}
.matrix-grid-cell--od {
  border-left: 2px solid var(--ink-12);
  background: var(--paper);
}
.matrix-grid-cell__current {
  font-size: 0.82rem;
  color: var(--ink-65);
  font-variant-numeric: tabular-nums;
  text-align: right;
  margin-bottom: 4px;
  min-height: 1.1em;
}
.matrix-grid-cell__input {
  width: 100%;
  padding: 6px 8px;
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
  text-align: right;
  border: 1px solid var(--ink-12);
  border-radius: 6px;
  background: var(--card);
  color: var(--ink);
}
.matrix-grid-cell__input:focus {
  outline: none;
  border-color: var(--bronze);
  box-shadow: 0 0 0 2px rgba(122, 102, 72, 0.18);
}
.matrix-grid-cell__input::placeholder {
  color: var(--ink-45);
  font-style: italic;
}

/* Zebra-stripe the rows so a recorder filling 10+ holders doesn't lose
   their place when scanning across many columns. */
.matrix-grid-table tbody tr:nth-child(even) th,
.matrix-grid-table tbody tr:nth-child(even) td {
  background: var(--paper);
}
.matrix-grid-table tbody tr:nth-child(even) .matrix-grid-cell--od {
  /* Re-darken the OD column relative to the row's base */
  background: var(--ink-07);
}

/* Dark-theme tweaks: borders and the sticky holder column need to use
   ink-on-dark colours so the grid stays legible. */
[data-theme="forest"] .matrix-grid-cell--od,
[data-theme="ink"]    .matrix-grid-cell--od {
  background: rgba(255, 255, 255, 0.04);
}
[data-theme="forest"] .matrix-grid-table tbody tr:nth-child(even) th,
[data-theme="forest"] .matrix-grid-table tbody tr:nth-child(even) td,
[data-theme="ink"]    .matrix-grid-table tbody tr:nth-child(even) th,
[data-theme="ink"]    .matrix-grid-table tbody tr:nth-child(even) td {
  background: rgba(255, 255, 255, 0.025);
}
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] .matrix-grid-cell--od {
    background: rgba(255, 255, 255, 0.04);
  }
  [data-theme="auto"] .matrix-grid-table tbody tr:nth-child(even) th,
  [data-theme="auto"] .matrix-grid-table tbody tr:nth-child(even) td {
    background: rgba(255, 255, 255, 0.025);
  }
}

/* ============================================================================
 * Messaging — inbox / sent / compose / broadcast / view
 * Internal peer-to-peer messages + admin broadcast. Visual model is
 * email-inbox-lite: bold-on-unread rows in a tight table, with a
 * pulled-back single-message view for reading + delete.
 * ============================================================================ */

/* Sub-nav strip — uses the masters-subnav base style but adds an
   ``.messages-badge`` chip for the unread count beside "Inbox". */
.messages-subnav {
  margin-top: 8px;
}
.messages-badge {
  display: inline-block;
  padding: 1px 8px;
  margin-left: 4px;
  font-size: 0.72rem;
  font-weight: 600;
  background: var(--bronze);
  color: var(--on-dark);
  border-radius: 999px;
  font-variant-numeric: tabular-nums;
}

/* Inbox / sent rows -------------------------------------------------------- */
.messages-table {
  width: 100%;
}
.messages-table__from { width: 200px; }
.messages-table__when { width: 160px; }
.messages-table__actions { width: 90px; text-align: right; }

.messages-row a {
  /* Inbox table rows lean on existing data-table styling; reset the
     border-bottom on anchors so the row doesn't get a dashed underline
     under every clickable cell. */
  border-bottom: 0;
  color: inherit;
}
.messages-row a:hover {
  color: var(--bronze);
}
.messages-row__from {
  font-weight: 500;
}
.messages-row__subject {
  display: block;
  font-weight: 400;
}
.messages-row--unread .messages-row__from,
.messages-row--unread .messages-row__subject {
  font-weight: 600;
  color: var(--ink);
}
.messages-row__broadcast {
  margin-left: 4px;
  font-size: 0.85em;
  vertical-align: middle;
}
.messages-row__actions {
  text-align: right;
}

/* Compose / broadcast form ------------------------------------------------- */
.messages-form {
  max-width: 720px;
  margin-top: 18px;
}
.messages-form textarea {
  width: 100%;
  padding: 10px 12px;
  font-family: var(--sans);
  font-size: 0.92rem;
  line-height: 1.5;
  border: 1px solid var(--ink-12);
  border-radius: 6px;
  background: var(--card);
  color: var(--ink);
  resize: vertical;
}
.messages-form textarea:focus {
  outline: none;
  border-color: var(--bronze);
  box-shadow: 0 0 0 2px rgba(122, 102, 72, 0.18);
}

/* Broadcast recipient preview banner --------------------------------------- */
.messages-broadcast-banner {
  margin-top: 18px;
  padding: 12px 16px;
  background: var(--paper);
  border: 1px dashed var(--bronze-pale);
  border-radius: 8px;
  font-size: 0.88rem;
  line-height: 1.6;
}
.messages-recipient-chip {
  display: inline-block;
  padding: 2px 10px;
  margin: 2px 4px 2px 0;
  background: var(--card);
  border: 1px solid var(--ink-12);
  border-radius: 999px;
  font-size: 0.8rem;
  white-space: nowrap;
}

/* Single-message view ------------------------------------------------------ */
.messages-view {
  max-width: 760px;
  padding: 20px 24px;
  background: var(--card);
  border: 1px solid var(--ink-12);
  border-radius: 12px;
}
.messages-view__head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
}
.messages-view__subject {
  margin: 0;
  font-size: 1.4rem;
  font-weight: 500;
  color: var(--ink);
}
.messages-view__broadcast {
  font-size: 0.78rem;
  padding: 3px 10px;
  background: var(--bronze-pale);
  color: var(--bronze);
  border-radius: 999px;
  font-weight: 500;
}
.messages-view__meta {
  margin: 14px 0 18px;
  font-size: 0.85rem;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 4px 24px;
  padding: 10px 12px;
  background: var(--paper);
  border-radius: 8px;
}
.messages-view__role-chip {
  display: inline-block;
  margin-left: 4px;
  padding: 1px 8px;
  background: var(--bronze-pale);
  color: var(--bronze);
  font-size: 0.7rem;
  font-weight: 500;
  border-radius: 999px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.messages-view__body {
  white-space: pre-wrap;     /* preserve newlines from the textarea */
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--ink);
  margin: 0 0 24px;
}
.messages-view__foot {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-top: 14px;
  border-top: 1px solid var(--ink-12);
}

/* Sidebar unread badge ----------------------------------------------------- */
.sidebar__badge {
  display: inline-block;
  margin-left: auto;
  padding: 1px 7px;
  font-size: 0.7rem;
  font-weight: 600;
  background: var(--bronze);
  color: var(--on-dark);
  border-radius: 999px;
  font-variant-numeric: tabular-nums;
}

/* ============================================================================
 * Broadcast banners on /overview
 *
 * One announcement card per pending broadcast. The visual language
 * intentionally departs from the rest of the page — saffron-amber
 * gradient + saturated left edge + filled-pill label + a one-shot
 * attention pulse — so the eye locks onto it the moment the page
 * paints. The pulse fades to nothing after ~5 seconds so the card
 * doesn't become a permanent distraction.
 *
 * Colour anchor: ``--saffron`` warm gold, distinct from the bronze /
 * forest used elsewhere. Locally scoped — defined inside the block
 * so an admin retheme of the whole app doesn't accidentally pick it
 * up.
 * ========================================================================== */
.broadcast-banners {
  --saffron:      #d4922a;
  --saffron-deep: #a76d18;
  --saffron-pale: #fbe9c6;
  --saffron-tint: #fff7e3;

  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 18px 0 4px;
}
.broadcast-banner {
  position: relative;
  background:
    linear-gradient(
      135deg,
      var(--saffron-tint)  0%,
      color-mix(in srgb, var(--saffron-pale) 55%, var(--card)) 100%
    );
  border: 1px solid var(--saffron-pale);
  border-left: 6px solid var(--saffron);
  border-radius: 10px;
  padding: 14px 18px 14px 22px;
  box-shadow:
    0 1px 0 rgba(0, 0, 0, 0.04),
    0 2px 18px -8px rgba(212, 146, 42, 0.45);
  /* One-shot attention pulse on first paint. Fades out after the
     animation so the card sits quiet once the user has registered it. */
  animation: broadcast-pulse 1.4s ease-out 0s 3;
}
@keyframes broadcast-pulse {
  0%   { box-shadow: 0 1px 0 rgba(0, 0, 0, 0.04),
                     0 0 0  0   rgba(212, 146, 42, 0.55); }
  60%  { box-shadow: 0 1px 0 rgba(0, 0, 0, 0.04),
                     0 0 0 12px rgba(212, 146, 42, 0.00); }
  100% { box-shadow: 0 1px 0 rgba(0, 0, 0, 0.04),
                     0 2px 18px -8px rgba(212, 146, 42, 0.45); }
}
/* Respect user-set "reduce motion" preference — no pulse for them. */
@media (prefers-reduced-motion: reduce) {
  .broadcast-banner { animation: none; }
}

.broadcast-banner__head {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 6px;
  font-size: 0.82rem;
  color: var(--saffron-deep);
}
.broadcast-banner__icon {
  font-size: 1.1em;
}
/* Filled saffron pill — the visual anchor that screams "announcement".
   Pulls the eye even at thumbnail scale. */
.broadcast-banner__label {
  display: inline-block;
  padding: 2px 10px;
  background: var(--saffron);
  color: #fff;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-radius: 999px;
  font-size: 0.7rem;
}
.broadcast-banner__sent {
  margin-left: 4px;
  color: var(--saffron-deep);
  opacity: 0.75;
}
.broadcast-banner__close {
  margin-left: auto;
  background: transparent;
  border: 0;
  color: var(--saffron-deep);
  font-size: 1.2rem;
  line-height: 1;
  width: 28px;
  height: 28px;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.1s ease, color 0.1s ease;
}
.broadcast-banner__close:hover {
  background: rgba(167, 109, 24, 0.12);
  color: var(--saffron-deep);
}
.broadcast-banner__subject {
  font-family: var(--serif);
  font-size: 1.2rem;
  font-weight: 500;
  line-height: 1.3;
  color: var(--ink);
  margin-bottom: 4px;
}
.broadcast-banner__body {
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--ink-80);
  white-space: pre-wrap;
  margin-bottom: 12px;
}
.broadcast-banner__foot {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.broadcast-banner__foot .btn--primary {
  /* Override the global forest-green primary with a saffron variant
     so the CTA sits inside the banner's colour family. */
  background: var(--saffron);
  border-color: var(--saffron);
  color: #fff;
}
.broadcast-banner__foot .btn--primary:hover {
  background: var(--saffron-deep);
  border-color: var(--saffron-deep);
}
.broadcast-banner__hint {
  font-size: 0.78rem;
  color: var(--saffron-deep);
  opacity: 0.85;
}
.broadcast-banner__hint a {
  color: var(--saffron-deep);
  border-bottom-color: var(--saffron-deep);
}

/* Dark themes — softer saffron tint so it still pops against an ink
   background without burning the retina. Text colour flips light so
   contrast stays AA. */
[data-theme="forest"] .broadcast-banner,
[data-theme="ink"]    .broadcast-banner {
  background:
    linear-gradient(
      135deg,
      rgba(212, 146, 42, 0.18) 0%,
      rgba(212, 146, 42, 0.07) 100%
    );
  border-color: rgba(212, 146, 42, 0.40);
  border-left-color: var(--saffron);
  box-shadow:
    0 2px 22px -6px rgba(212, 146, 42, 0.30);
}
[data-theme="forest"] .broadcast-banner__head,
[data-theme="ink"]    .broadcast-banner__head,
[data-theme="forest"] .broadcast-banner__hint,
[data-theme="ink"]    .broadcast-banner__hint,
[data-theme="forest"] .broadcast-banner__sent,
[data-theme="ink"]    .broadcast-banner__sent {
  color: #f3c879;
}
[data-theme="forest"] .broadcast-banner__hint a,
[data-theme="ink"]    .broadcast-banner__hint a {
  color: #f3c879;
  border-bottom-color: #f3c879;
}
[data-theme="forest"] .broadcast-banner__close,
[data-theme="ink"]    .broadcast-banner__close {
  color: #f3c879;
}
[data-theme="forest"] .broadcast-banner__close:hover,
[data-theme="ink"]    .broadcast-banner__close:hover {
  background: rgba(243, 200, 121, 0.18);
}
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] .broadcast-banner {
    background:
      linear-gradient(
        135deg,
        rgba(212, 146, 42, 0.18) 0%,
        rgba(212, 146, 42, 0.07) 100%
      );
    border-color: rgba(212, 146, 42, 0.40);
    border-left-color: var(--saffron);
  }
  [data-theme="auto"] .broadcast-banner__head,
  [data-theme="auto"] .broadcast-banner__hint,
  [data-theme="auto"] .broadcast-banner__sent,
  [data-theme="auto"] .broadcast-banner__close {
    color: #f3c879;
  }
}

/* ============================================================================
 * Audit log — date-grouped drill-down
 * One ``.audit-day`` per yyyy-mm-dd; the header is a button that
 * toggles ``open`` in its own Alpine scope. Closed by default for
 * older days; today expanded. Visual model mirrors the bank-drill
 * panel on /overview — same paper-card-on-paper feel.
 * ============================================================================ */
.audit-day {
  margin-top: 14px;
  border: 1px solid var(--ink-12);
  border-radius: 10px;
  background: var(--card);
  overflow: hidden;
}
.audit-day__head {
  /* Full-width clickable header; the entire bar toggles open/close. */
  display: flex;
  align-items: baseline;
  gap: 16px;
  flex-wrap: wrap;
  width: 100%;
  padding: 12px 16px;
  background: var(--paper);
  border: 0;
  border-bottom: 1px solid transparent;
  cursor: pointer;
  text-align: left;
  font-family: var(--sans);
  font-size: 0.95rem;
  color: var(--ink);
  transition: background 0.1s ease, border-color 0.1s ease;
}
.audit-day__head:hover {
  background: var(--ink-07);
}
.audit-day__head--open {
  /* Bottom border returns when expanded so the body reads as a
     joined section below the header rather than a disconnected
     panel. */
  border-bottom-color: var(--ink-12);
}
.audit-day__chevron {
  display: inline-block;
  width: 1em;
  color: var(--bronze);
  font-size: 0.9em;
  transition: transform 0.12s ease;
}
.audit-day__chevron--open {
  transform: rotate(90deg);
}
.audit-day__date {
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--ink);
}
.audit-day__count {
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}
.audit-day__breakdown {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-left: auto;          /* pushes the breakdown chips to the right */
  font-size: 0.78rem;
}
.audit-day__cat-chip {
  background: var(--bronze-pale);
  color: var(--bronze);
  padding: 2px 8px;
  border-radius: 999px;
  font-weight: 500;
  white-space: nowrap;
}
.audit-day__body {
  padding: 4px 4px 8px;
}
.audit-day__table {
  width: 100%;
  margin: 0;
}
.audit-day__table thead th {
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-65);
  font-weight: 500;
  padding: 8px 12px;
}
.audit-day__table tbody td {
  padding: 8px 12px;
  vertical-align: top;
  border-top: 1px solid var(--ink-07);
}
.audit-day__col-time { width: 90px; font-variant-numeric: tabular-nums; }
.audit-day__col-user { width: 140px; }
.audit-day__col-cat  { width: 110px; }

.audit-row__time {
  font-family: var(--mono, monospace);
  font-size: 0.85rem;
  color: var(--ink-80);
}
.audit-row__user {
  font-weight: 500;
  font-size: 0.88rem;
}
.audit-row__cat {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  background: var(--ink-07);
  color: var(--ink-65);
}
/* Per-category chip colours so the eye can pick out exports etc. */
.audit-row__cat--exports { background: #e3f0e0; color: #2d5d2a; }
.audit-row__cat--entry,
.audit-row__cat--data    { background: var(--bronze-pale); color: var(--bronze); }
.audit-row__cat--masters { background: #f0e3c4; color: #6b5b2e; }
.audit-row__cat--reports { background: #d9def0; color: #2c3a5e; }
.audit-row__cat--auth    { background: #f3d6c8; color: #6e2e1d; }

.audit-row__summary {
  line-height: 1.4;
  font-size: 0.92rem;
}
.audit-row__raw {
  font-size: 0.72rem;
  margin-top: 4px;
}
.audit-row__raw code {
  font-family: var(--mono, monospace);
  background: var(--ink-07);
  padding: 1px 6px;
  border-radius: 4px;
}

/* Dark-theme tweaks — flip backgrounds to ink so the audit cards
   don't glow against a dark page. */
[data-theme="forest"] .audit-day,
[data-theme="ink"]    .audit-day {
  background: rgba(255, 255, 255, 0.04);
}
[data-theme="forest"] .audit-day__head,
[data-theme="ink"]    .audit-day__head {
  background: rgba(255, 255, 255, 0.06);
}
[data-theme="forest"] .audit-day__head:hover,
[data-theme="ink"]    .audit-day__head:hover {
  background: rgba(255, 255, 255, 0.10);
}
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] .audit-day {
    background: rgba(255, 255, 255, 0.04);
  }
  [data-theme="auto"] .audit-day__head {
    background: rgba(255, 255, 255, 0.06);
  }
  [data-theme="auto"] .audit-day__head:hover {
    background: rgba(255, 255, 255, 0.10);
  }
}

/* ============================================================================
 * DataGrid v0 — progressive table enhancement
 * Styles for the JS module in static/js/data-grid.js. Applies to any
 * <table data-grid-key="…"> the module finds; adds:
 *   • sortable header affordance + sort indicator
 *   • drag-to-reorder visual states
 *   • inline per-column filter input row beneath the headers
 *   • dropdown of column checkboxes (Columns ⌄ button)
 *   • toolbar styling (Columns + Reset buttons sitting above the table)
 * ============================================================================ */

/* Tinted header zone for DataGrid-enabled tables — scoped via the
   ``[data-grid-key]`` attribute so we don't change every other table
   in the app. Uses the per-theme ``--sand`` token (one step warmer
   than --paper), which already adapts cleanly across paper / sand /
   forest / ink / auto themes:
       paper   #ece6d8   warm cream tint over paper-white
       sand    #ddd1ba   denser cream
       forest  #2a4631   slightly lighter than forest paper (#233c2a)
       ink     #2a2c26   slightly lighter than ink paper (#232520)
   The filter row below keeps the existing ``--paper`` background, so
   the thead becomes a 2-step staircase: header (sand) → filter
   (paper) → data rows (no fill). Reads as a clear "header zone". */
table[data-grid-key] thead tr:first-child th {
  background: var(--sand);
  color: var(--ink);
  font-weight: 600;
}
/* The sortable hover is overridden on the column-header row so the
   sand background doesn't get clobbered to ink-07 on mouseover —
   instead we darken the sand slightly. */
table[data-grid-key] thead tr:first-child th.data-grid__sortable:hover {
  background: var(--bone);
}

/* Header cells become clickable + draggable. */
.data-grid__sortable {
  user-select: none;
  position: relative;
}
.data-grid__sortable:hover {
  background: var(--ink-07);
}
.data-grid__sort-ind {
  font-size: 0.78em;
  color: var(--bronze);
  margin-left: 4px;
  font-weight: 600;
}

/* Drag states. */
.data-grid__dragging {
  opacity: 0.4;
}
.data-grid__drag-target {
  outline: 2px dashed var(--bronze);
  outline-offset: -2px;
  background: rgba(122, 102, 72, 0.10);
}

/* Filter row injected by the JS module — second row of <thead>. */
.data-grid__filter-row > th {
  padding: 4px 6px;
  background: var(--paper);
  border-bottom: 1px solid var(--ink-12);
}
.data-grid__filter-input {
  width: 100%;
  padding: 4px 8px;
  font-size: 0.82rem;
  font-family: var(--sans);
  border: 1px solid var(--ink-12);
  border-radius: 4px;
  background: var(--card);
  color: var(--ink);
  font-weight: 400;
}
.data-grid__filter-input:focus {
  outline: none;
  border-color: var(--bronze);
  box-shadow: 0 0 0 2px rgba(122, 102, 72, 0.18);
}
.data-grid__filter-input::placeholder {
  color: var(--ink-45);
  font-style: italic;
}

/* Columns dropdown — JS-positioned via getBoundingClientRect on the
   anchor button + position:fixed. Lives at document.body root so no
   flex / overflow ancestor can squish it (avoids the v1 alignment
   bug where it was a flex child of .data-grid-toolbar). The ``top``
   and ``right`` come from JS inline styles; the rule below only
   handles visuals. */
.data-grid__cols-dropdown {
  z-index: 1000;
  min-width: 200px;
  max-height: 60vh;
  overflow-y: auto;
  background: var(--card);
  border: 1px solid var(--ink-12);
  border-radius: 8px;
  padding: 8px 12px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.14);
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 0.88rem;
}
.data-grid__cols-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 0;
  cursor: pointer;
  user-select: none;
}
.data-grid__cols-item:hover {
  color: var(--bronze);
}

/* Toolbar wrapper around the Columns + Reset buttons sitting above
   each DataGrid-enabled table. The dropdown's absolute-positioning
   needs a relative anchor so set position:relative here. */
.data-grid-toolbar {
  position: relative;
  display: flex;
  gap: 8px;
  align-items: center;
  margin: 12px 0 8px;
}
.data-grid-toolbar__spacer {
  flex: 1;
}

/* Dark-theme tweaks for the filter row.
   Dropdown background is no longer overridden here — it inherits
   --card from the per-theme token blocks above, which now defines a
   SOLID per-theme value (forest = #2e4a36, ink = #2c2e28). The old
   rgba-on-white overrides made the floating dropdown nearly
   transparent and unreadable; the solid token is what we want for
   a popover. */
[data-theme="forest"] .data-grid__filter-row > th,
[data-theme="ink"]    .data-grid__filter-row > th {
  background: rgba(255, 255, 255, 0.04);
}
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] .data-grid__filter-row > th {
    background: rgba(255, 255, 255, 0.04);
  }
}

/* ===========================================================================
   Public home page (Phase E3) — marketing surface + embedded login.
   ---------------------------------------------------------------------------
   Mounted at GET / for signed-out visitors. Self-contained: home.html does
   NOT extend base.html, so none of the app-shell classes (.sidebar, .main,
   .auth-topbar) are in the DOM here. Every rule below is scoped under
   .home-* to keep this surface decoupled from in-app templates.
   =========================================================================== */
.home-body {
  background: var(--paper);
  color: var(--ink);
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  line-height: 1.55;
}
.home-body a { color: inherit; text-decoration: none; }
.home-body .wrap {
  width: min(1120px, calc(100% - 40px));
  margin-left: auto;
  margin-right: auto;
}

/* Flash strip on the public surface — sits at the top, full-width, no
   page padding so the messages span edge to edge like the rest of the
   site's chrome. */
.home-flash {
  padding: 12px 0;
  background: transparent;
}
.home-flash .flash {
  width: min(1120px, calc(100% - 40px));
  margin: 0 auto 8px;
}

/* ─── Header / nav ──────────────────────────────────────────────────── */
.home-header {
  position: sticky;
  top: 0;
  z-index: 10;
  background: rgba(251, 250, 246, 0.86);
  backdrop-filter: blur(16px);
  border-bottom: 1px solid rgba(24, 26, 23, 0.13);
}
.home-nav {
  height: 76px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.home-brand {
  /* The brand-mark__* spans paint themselves; this just resizes the
     mark for the home-page nav (slightly larger than the sidebar's). */
  font-size: 1.75rem;
}
.home-nav__links {
  display: flex;
  align-items: center;
  gap: 26px;
  font-size: 13px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(24, 26, 23, 0.62);
}
.home-nav__links a:hover { color: var(--ink); }

/* ─── Pill buttons ──────────────────────────────────────────────────── */
.home-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  padding: 13px 22px;
  border: 1px solid rgba(24, 26, 23, 0.13);
  background: transparent;
  color: var(--ink);
  font-weight: 600;
  font-size: 14px;
  cursor: pointer;
  transition: transform 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
}
.home-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 12px 28px rgba(24, 26, 23, 0.08);
}
/* Phase HomeSlim (2026-06-08): paint the dark variant with a
   compound-class selector + cover :link / :visited / :hover / :focus
   states explicitly. The global ``a { color: var(--forest) }`` rule
   on line 224 has type specificity that some browsers / extensions
   / tenant theme overrides can sneak past a single-class rule,
   leaving the "Begin quietly" button as dark text on a dark-green
   background. Compound selector (0,2,0) + per-state coverage closes
   that gap. */
.home-btn.home-btn--dark,
.home-btn.home-btn--dark:link,
.home-btn.home-btn--dark:visited {
  background: var(--forest);
  color: #fbfaf6;
  border-color: var(--forest);
}
.home-btn.home-btn--dark:hover,
.home-btn.home-btn--dark:focus {
  background: #142519;
  color: #ffffff;
  border-color: #142519;
}

/* ─── Hero ─────────────────────────────────────────────────────────── */
.home-main { padding: 0; }
.home-hero {
  padding: 64px 0 56px;
  display: grid;
  grid-template-columns: 1.08fr 0.92fr;
  gap: 54px;
  /* Phase HomeSlim (2026-06-08): align-items shifted from ``center``
     to ``start`` so the sign-in card sits at the TOP of the hero
     row, level with the eyebrow. Previously the card slid down to
     the vertical middle of a tall left column. */
  align-items: start;
}
.home-eyebrow {
  /* Phase HomeAccess polish (2026-06-08): brand thesis "Wealth
     follows clarity." iterated 12 → 14 → 17 → 15px. Settled at
     15 — 17 had presence but felt a notch too loud above the h1;
     15 is the comfortable middle that still reads as a real line.
     Letter-spacing opened slightly (0.10 → 0.12em) to match the
     smaller size. */
  font-size: 15px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--bronze);
  font-weight: 700;
  margin-bottom: 18px;
}
.home-h1 {
  font-family: var(--serif);
  font-weight: 400;
  letter-spacing: -0.025em;
  /* Phase HomeSlim (2026-06-08): reduced from clamp(46px, 7vw, 78px).
     Old size dominated the page + pushed the login card down via
     align-items: center. Smaller headline + start-aligned hero
     now puts the sign-in form at the top of the visible viewport. */
  font-size: clamp(28px, 3.6vw, 42px);
  line-height: 1.15;
  margin: 0 0 18px;
}
.home-lead {
  font-size: 17px;
  color: #444139;
  max-width: 600px;
  margin: 0 0 18px;
  line-height: 1.5;
}
.home-quiet {
  color: rgba(24, 26, 23, 0.62);
  max-width: 580px;
  margin: 0 0 28px;
  font-size: 14.5px;
  line-height: 1.55;
}
.home-hero__actions { display: flex; gap: 14px; flex-wrap: wrap; }

/* ─── Login card (right column of the hero) ────────────────────────── */
.home-login {
  background: rgba(251, 250, 243, 0.84);
  border: 1px solid rgba(24, 26, 23, 0.13);
  border-radius: 22px;
  box-shadow: 0 28px 70px rgba(24, 26, 23, 0.10);
  padding: 38px;
}
.home-login__title {
  font-family: var(--serif);
  font-weight: 500;
  letter-spacing: -0.02em;
  /* Phase HomeSlim (2026-06-08): reduced from 42px so the sign-in
     card sits comfortably alongside the now-smaller home-h1
     instead of competing with it as the largest type on the page. */
  font-size: 30px;
  margin: 0 0 4px;
}
.home-login__form { display: block; }
.home-login__label {
  display: block;
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(24, 26, 23, 0.62);
  font-weight: 700;
  margin: 18px 0 8px;
}
.home-login__input {
  width: 100%;
  height: 54px;
  border: 1px solid rgba(24, 26, 23, 0.13);
  border-radius: 12px;
  background: #f8f6ee;
  padding: 0 16px;
  font-size: 16px;
  color: var(--ink);
  outline: none;
  font-family: inherit;
}
.home-login__input:focus {
  border-color: rgba(26, 46, 31, 0.45);
  box-shadow: 0 0 0 4px rgba(26, 46, 31, 0.08);
}
.home-login__submit {
  width: 100%;
  height: 58px;
  margin-top: 22px;
  border: 0;
  border-radius: 12px;
  background: var(--forest);
  color: #fff;
  font-size: 17px;
  font-weight: 700;
  cursor: pointer;
  font-family: inherit;
}
.home-login__submit:hover { background: #142519; }
.home-login__small {
  font-size: 13px;
  color: rgba(24, 26, 23, 0.62);
  text-align: center;
  margin: 18px 0 0;
}

/* Phase HomeSlim (2026-06-08) — additions to support the slim home:
   sub-headline, "Access by invitation" footer, bronze accent crown
   on the login card, and the left-column quiet stat strip + peek
   thumbnail + know-more pill. All scoped under .home-* so they
   can't bleed into the authed app shell. */
.home-login__sub {
  margin: -10px 0 22px;
  font-size: 14.5px;
  color: rgba(24, 26, 23, 0.62);
}
.home-login__invite {
  text-align: center;
  /* Phase HomeAccess clarity pass (2026-06-08): bumped from 12.5px
     to 14px and tightened from 0.04em to 0.02em letter-spacing so
     the "Request access" verb reads as a real CTA, not legal-style
     muted copy. Same shape as "Don't have an account? Sign up"
     under every standard sign-in card. */
  font-size: 14px;
  letter-spacing: 0.02em;
  color: rgba(24, 26, 23, 0.7);
  margin: 22px 0 0;
  padding-top: 18px;
  border-top: 1px solid rgba(24, 26, 23, 0.09);
}
.home-login__invite a {
  /* Stronger contrast + solid underline so the verb is the first
     thing the eye lands on after the Sign in button. Bronze keeps
     it brand-aligned; ink-on-hover gives the standard interactive
     affordance. */
  color: var(--bronze);
  text-decoration: none;
  border-bottom: 1.5px solid var(--bronze);
  font-weight: 600;
  padding-bottom: 1px;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.home-login__invite a:hover {
  color: var(--ink);
  border-bottom-color: var(--ink);
}
.home-login__invite-sub {
  display: block;
  font-size: 12px;
  color: rgba(24, 26, 23, 0.5);
  letter-spacing: 0.04em;
  margin-top: 6px;
}
.home-login__crown {
  position: absolute;
  top: -1px; left: 28px; right: 28px;
  height: 3px;
  background: linear-gradient(90deg, var(--bronze) 0%, var(--bronze-pale) 100%);
  border-radius: 0 0 3px 3px;
}
/* The crown is positioned absolutely so its container needs to be
   the positioning root. The existing .home-login already has
   border-radius + padding; we just add relative here. */
.home-login { position: relative; }

/* ── Quiet stat strip on the left column ────────────────────── */
.home-stats {
  /* HomeAccess-9 polish v2 (2026-06-08): scoped accent variables.
     The global --bronze and --forest are intentionally muted for
     the brand voice. The stat strip is the one place we want more
     pop, so we override locally — richer saturated versions that
     read as "premium accent" without changing the brand tokens
     everywhere else. Cards + keywords both inherit these via
     descendant rules below. */
  --stat-warm: #a06b30;   /* deeper, more saturated than --bronze */
  --stat-cool: #2c6e44;   /* vivid forest — brighter than --forest */

  display: flex;
  align-items: center;
  gap: 14px;
  margin: 4px 0 28px;
  flex-wrap: wrap;
}
.home-stats__lead {
  /* HomeAccess-9 polish (2026-06-08): bumped 15 → 18px so the
     lead "Less effort. / Richer reports." carries the same
     visual weight as the cards beside it. Slightly darker text
     too (0.62 → 0.72 alpha) to balance the now-larger cards. */
  font-family: var(--serif);
  font-style: italic;
  color: rgba(24, 26, 23, 0.72);
  font-size: 18px;
  line-height: 1.4;
  max-width: 240px;
}
.home-stat-card {
  /* Phase HomeAccess-9 (2026-06-08): two-tone variants. Each card
     gets a 3px top stripe — bronze for the "less" axis (Effort,
     warm), forest for the "more" axis (Insight, cool). The "to"
     number + arrow inherit the same accent, so the eye reads
     "muted past → coloured future" twice without us having to
     spell it out. Brand consistency: the stripe pattern mirrors
     the existing bronze stripe on the sign-in card.

     HomeAccess-9 polish (2026-06-08): bumped padding (9/11 → 14/16)
     + min-width (104 → 132) so the cards carry the same visual
     weight as the now-bigger lead beside them. */
  position: relative;
  background: rgba(255, 255, 255, 0.55);
  border: 1px solid rgba(24, 26, 23, 0.10);
  border-radius: 8px;
  padding: 14px 18px 12px;
  min-width: 132px;
  overflow: hidden;
}
.home-stat-card::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: var(--stat-warm);       /* warm — Effort (richer than --bronze) */
}
.home-stat-card--cool::before {
  background: var(--stat-cool);       /* cool — Insight (vivid forest) */
}
.home-stat-card__label {
  /* Bumped 10 → 11.5px so the label scales with the bigger card. */
  font-size: 11.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(24, 26, 23, 0.55);
  font-weight: 600;
  margin-bottom: 5px;
}
.home-stat-card__nums {
  /* Bumped 16 → 20px so the headline numbers carry. */
  font-family: var(--serif);
  font-size: 20px;
  font-weight: 500;
  display: flex;
  align-items: baseline;
  gap: 7px;
  font-variant-numeric: tabular-nums;
}
.home-stat-card__from  { color: rgba(24, 26, 23, 0.40); text-decoration: line-through; }
.home-stat-card__arrow { color: var(--stat-warm); font-size: 17px; }
.home-stat-card__to    { color: var(--stat-warm); font-weight: 700; }

/* Cool-tone overrides — Insight card. The arrow + "to" number take
   the vivid forest accent so the per-card story is consistent
   edge-to-edge. */
.home-stat-card--cool .home-stat-card__arrow { color: var(--stat-cool); }
.home-stat-card--cool .home-stat-card__to    { color: var(--stat-cool); }

/* Lead-line key words — "Less" carries the warm accent, "Richer"
   the cool. HomeAccess-9 v3 polish (2026-06-08): underline dropped
   (felt fussy next to the bigger card stripes); colours pull from
   the same scoped accent variables so a single tweak retones the
   whole strip. Weight bumped to 800 so the keyword carries without
   the underline crutch. */
.home-stats__key {
  font-style: normal;        /* lead is italic; keywords pull straight */
  font-weight: 800;
  letter-spacing: -0.01em;
}
.home-stats__key--warm { color: var(--stat-warm); }
.home-stats__key--cool { color: var(--stat-cool); }

/* ── "Peek inside" dashboard thumbnail ───────────────────────── */
.home-peek {
  border: 1px solid rgba(24, 26, 23, 0.13);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.5);
  padding: 12px;
  max-width: 460px;
  box-shadow: 0 4px 18px rgba(122, 102, 72, 0.08);
  margin: 0 0 22px;
}
.home-peek__label {
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(24, 26, 23, 0.45);
  font-weight: 600;
  margin-bottom: 8px;
  display: flex;
  align-items: center;
  gap: 6px;
}
.home-peek__img {
  width: 100%;
  display: block;
  border-radius: 5px;
}
.home-peek__fallback {
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 2px dashed var(--bronze-pale);
  background: var(--bronze-faint, #f1ebde);
  border-radius: 5px;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 6px;
  color: var(--bronze);
  font-size: 13px;
  text-align: center;
  padding: 16px;
}
.home-peek__fallback strong { font-family: var(--serif); font-weight: 500; font-size: 15px; }
.home-peek__fallback code {
  background: rgba(0,0,0,0.06);
  padding: 1px 5px; border-radius: 3px;
  font-size: 11px;
}

/* ── "Know more about vanshOS →" CTA pill ────────────────────── */
.home-knowmore {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 11px 20px;
  border: 1px solid var(--bronze-pale);
  border-radius: 999px;
  color: var(--forest);
  font-weight: 600;
  font-size: 14.5px;
  background: var(--bronze-faint, #f1ebde);
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
.home-knowmore:hover {
  background: var(--bronze-pale);
  border-color: var(--bronze);
  transform: translateY(-1px);
  text-decoration: none;
}
.home-knowmore__arrow {
  font-size: 18px;
  line-height: 1;
  transition: transform 0.15s ease;
}
.home-knowmore:hover .home-knowmore__arrow { transform: translateX(3px); }

/* ── CTA sign-in escape link on the /about page footer ───────── */
.home-cta__signin {
  margin: 22px 0 0;
  font-size: 14px;
  color: rgba(24, 26, 23, 0.62);
}
.home-cta__signin a {
  color: var(--forest);
  font-weight: 600;
  border-bottom: 1px solid rgba(24, 26, 23, 0.13);
  padding-bottom: 1px;
}
.home-cta__signin a:hover { border-bottom-color: var(--forest); }

/* ── Phase HomeBoxes-1 (2026-06-12): three square discovery boxes below the
   home hero. Signed-out visitors → the public cold-share pages (/why,
   /honest-answers, /for-cas). The hero above is unchanged. ─────────────── */
.home-explore {
  border-top: var(--rule);
  background: var(--bronze-faint, #f1ebde);
  padding: 56px 0 60px;
}
.home-explore__head { text-align: center; margin-bottom: 28px; }
.home-explore__ey {
  font-size: 10.5px; font-weight: 700;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--bronze);
}
.home-explore__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  max-width: 920px;
  margin: 0 auto;
}
.home-box {
  aspect-ratio: 1 / 1;                 /* square */
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: var(--rule);
  border-top: 3px solid var(--bronze-mid);
  border-radius: 14px;
  padding: 28px 26px;
  color: var(--ink);
  transition: transform 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.home-box:hover {
  transform: translateY(-4px);
  border-color: var(--bronze-pale);
  box-shadow: 0 16px 40px var(--ink-07);
  text-decoration: none;
}
.home-box--ca { border-top-color: var(--forest-mid); }
.home-box__tag {
  font-size: 10px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--bronze);
  margin-bottom: auto;                 /* push title/desc/go to the lower half */
}
.home-box--ca .home-box__tag { color: var(--forest-mid); }
.home-box__h {
  font-family: var(--serif);
  font-weight: 500; font-size: 23px;
  letter-spacing: -0.01em; line-height: 1.15;
  margin: 0 0 10px;
  color: var(--ink);
}
.home-box__p {
  font-size: 14px; line-height: 1.5;
  color: var(--ink-65);
  margin: 0 0 16px;
}
.home-box__go {
  font-size: 13px; font-weight: 600;
  color: var(--forest);
}
.home-box:hover .home-box__go { color: var(--bronze); }
@media (max-width: 760px) {
  .home-explore__grid { grid-template-columns: 1fr; }
  .home-box { aspect-ratio: auto; }   /* don't force full-width squares on mobile */
}

/* ── About-page extras: hero strip + "By the numbers" card ───── */
.about-hero {
  padding: 88px 0 56px;
  text-align: center;
  border-bottom: 1px solid rgba(24, 26, 23, 0.09);
}
.about-hero__eyebrow {
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--bronze);
  font-weight: 700;
  margin-bottom: 18px;
}
.about-hero__h1 {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(36px, 5vw, 56px);
  line-height: 1.1;
  letter-spacing: -0.025em;
  margin: 0 auto;
  max-width: 800px;
}
.about-hero__sub {
  font-family: var(--serif);
  font-style: italic;
  color: rgba(24, 26, 23, 0.62);
  margin-top: 18px;
  font-size: 19px;
}

.numbers-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 32px;
  padding: 40px;
  background: linear-gradient(135deg, #f4eedb 0%, #ebe2c4 100%);
  border-radius: 12px;
  margin-top: 24px;
  max-width: 760px;
  margin-left: auto;
  margin-right: auto;
}
@media (max-width: 640px) { .numbers-grid { grid-template-columns: 1fr; } }
.number-card {
  text-align: center;
}
.number-card__label {
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--bronze);
  font-weight: 700;
  margin-bottom: 10px;
}
.number-card__big {
  font-family: var(--serif);
  font-size: 44px;
  font-weight: 500;
  color: var(--ink);
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 12px;
  font-variant-numeric: tabular-nums;
}
.number-card__from  { color: rgba(24, 26, 23, 0.45); text-decoration: line-through; font-size: 28px; }
.number-card__arrow { color: var(--bronze); }
.number-card__to    { color: var(--bronze); font-weight: 700; }
.number-card__sub {
  font-family: var(--serif);
  font-style: italic;
  color: rgba(24, 26, 23, 0.62);
  margin-top: 10px;
  font-size: 15.5px;
}

/* About-page additions (Phase HomeSlim repositioning v2, 2026-06-08) */
.about-numbers-lead {
  font-family: var(--serif);
  font-style: italic;
  color: rgba(24, 26, 23, 0.62);
  text-align: center;
  margin: -8px auto 0;
  max-width: 600px;
  font-size: 17px;
  line-height: 1.5;
}
.about-whom {
  display: grid;
  gap: 14px;
  margin-top: 28px;
  /* Lives as the 3rd child inside .home-section__grid (a 0.8fr 1.2fr
     2-column grid). Without this, the persona list would only occupy
     the LEFT column of the next row and the right column would sit
     empty. Spanning both columns gives the persona cards the full
     content width they need to read comfortably. */
  grid-column: 1 / -1;
}
.about-whom__row {
  background: rgba(255, 255, 255, 0.5);
  border: 1px solid rgba(24, 26, 23, 0.10);
  border-left: 3px solid var(--bronze-pale);
  border-radius: 4px;
  padding: 16px 20px;
  display: grid;
  grid-template-columns: minmax(220px, 0.85fr) 1.15fr;
  gap: 24px;
  align-items: baseline;
}
@media (max-width: 720px) {
  .about-whom__row { grid-template-columns: 1fr; gap: 4px; }
}
.about-whom__row strong {
  font-family: var(--serif);
  font-weight: 500;
  color: var(--bronze);
  font-size: 18px;
}
.about-whom__row span {
  color: rgba(24, 26, 23, 0.75);
  font-size: 15.5px;
  line-height: 1.55;
}

/* Phase E3 (2026-05-26): per-card login banner. Sits between the
   .home-login__title and the form so any message bouncing back here
   (login errors, forgot-password confirmation, session-expired
   notices) lands in the user's eyeline immediately — the only
   feedback used to be a top-of-body flash that scrolled out of view
   above the hero whenever the browser jumped to the #login anchor.

   ForgotPwd-Fix (2026-05-27): expanded from .home-login__error
   (error-only) to .home-login__flash-region + per-level modifiers.
   The forgot-password "If that email is on file..." info message
   now renders here too, so users see their submission was accepted. */
.home-login__flash-region { margin: 0 0 16px; }
.home-login__flash {
  border-left: 3px solid;
  border-radius: 0 5px 5px 0;
  padding: 10px 14px;
  font-size: 13.5px;
  line-height: 1.5;
  font-weight: 500;
}
.home-login__flash + .home-login__flash { margin-top: 6px; }
.home-login__flash--error {
  background: var(--negative-bg, #f0dfd9);
  color:      var(--negative,    #8a3a2e);
  border-color: var(--negative,  #8a3a2e);
}
.home-login__flash--success {
  background: var(--positive-bg, #dfeae0);
  color:      var(--positive,    #2f5d3a);
  border-color: var(--positive,  #2f5d3a);
}
.home-login__flash--info {
  background: rgba(231, 220, 200, 0.55);
  color:      #4a3e22;
  border-color: #7a6648;
}
.home-login__flash--warning {
  background: #f5ead0;
  color:      #6b5210;
  border-color: #b8860b;
}

/* Back-compat alias: the old single-class banner. Old templates that
   still emit .home-login__error get the same visual treatment as the
   new error variant. Drop in v1.40+ once all templates migrated. */
.home-login__error {
  background: var(--negative-bg, #f0dfd9);
  color: var(--negative, #8a3a2e);
  border-left: 3px solid var(--negative, #8a3a2e);
  border-radius: 0 5px 5px 0;
  padding: 10px 14px;
  margin: 0 0 16px;
  font-size: 13.5px;
  line-height: 1.5;
  font-weight: 500;
}
.home-login__error > div + div { margin-top: 4px; }

/* ─── Marketing sections ───────────────────────────────────────────── */
.home-section {
  padding: 72px 0;
  border-top: 1px solid rgba(24, 26, 23, 0.13);
}
.home-section__grid {
  display: grid;
  grid-template-columns: 0.8fr 1.2fr;
  gap: 54px;
}
.home-section__title {
  font-family: var(--serif);
  font-weight: 400;
  letter-spacing: -0.035em;
  font-size: 42px;
  line-height: 1.06;
  margin: 0;
}
.home-section__body p {
  /* Phase HomeSlim repositioning v2 (2026-06-08): bumped from the
     inherited Inter 16px to Spectral 21px/1.72 — matches the
     ``.home-manifesto__copy`` style which the user explicitly
     called the "perfect" reading size. Every body paragraph on
     the about page now reads in the same generous serif rhythm,
     not just the manifesto block. */
  font-family: var(--serif);
  font-size: 21px;
  line-height: 1.72;
  color: #38352f;
  margin: 0 0 20px;
}
.home-section__body p:last-child { margin-bottom: 0; }
.home-list {
  display: grid;
  gap: 14px;
  margin-top: 10px;
}
.home-list > div {
  padding: 22px 0;
  border-bottom: 1px solid rgba(24, 26, 23, 0.13);
  /* Phase HomeSlim typography pass (2026-06-08): adopt the same
     Spectral serif body treatment used by .home-section__body p
     and the manifesto. The /about "What it does" list reads as
     substantial paragraphs, not tiny captions. */
  font-family: var(--serif);
  font-size: 18px;
  line-height: 1.6;
  color: #38352f;
}
.home-list > div strong {
  display: inline;
  color: var(--forest);
  font-weight: 600;
  letter-spacing: -0.005em;
}

/* ─── Manifesto card ──────────────────────────────────────────────── */
.home-manifesto {
  background: rgba(251, 250, 243, 0.74);
  border: 1px solid rgba(24, 26, 23, 0.13);
  border-radius: 22px;
  box-shadow: 0 24px 64px rgba(24, 26, 23, 0.07);
  padding: 46px;
}
.home-manifesto__kicker {
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--bronze);
  font-weight: 800;
  margin-bottom: 12px;
}
.home-manifesto__h2 {
  font-family: var(--serif);
  font-weight: 400;
  letter-spacing: -0.035em;
  font-size: 46px;
  line-height: 1.05;
  margin: 0 0 26px;
}
.home-manifesto__copy {
  max-width: 820px;
  color: #38352f;
  font-family: var(--serif);
  font-size: 21px;
  line-height: 1.72;
}
.home-manifesto__copy p { margin: 0 0 20px; }
.home-manifesto__closing {
  font-size: 26px;
  color: var(--forest);
  margin-top: 30px;
}

/* ─── Philosophy tiles ─────────────────────────────────────────────── */
.home-philosophy {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 14px;
  margin-top: 34px;
}
.home-tile {
  background: rgba(251, 250, 243, 0.7);
  border: 1px solid rgba(24, 26, 23, 0.13);
  border-radius: 16px;
  padding: 24px 22px;
  /* Phase HomeSlim repositioning v2 (2026-06-08): subtle lift on
     hover gives the philosophy tiles a touch of life without
     compromising the quiet brand register. transform + shadow
     transition softly; border darkens to the bronze accent. */
  transition: transform 0.2s ease,
              box-shadow 0.2s ease,
              border-color 0.2s ease,
              background 0.2s ease;
  cursor: default;
}
.home-tile:hover {
  transform: translateY(-3px);
  box-shadow: 0 14px 32px rgba(24, 26, 23, 0.08);
  border-color: var(--bronze-pale);
  background: rgba(255, 255, 255, 0.85);
}
.home-tile strong {
  display: block;
  margin-bottom: 10px;
  color: var(--forest);
  /* Bigger, serif — matches the brand voice on the about page. */
  font-family: var(--serif);
  font-weight: 500;
  font-size: 22px;
  letter-spacing: -0.01em;
  line-height: 1.2;
}
.home-tile p {
  font-size: 16px;
  color: rgba(24, 26, 23, 0.7);
  margin: 0;
  line-height: 1.55;
}

/* ─── CTA + footer ─────────────────────────────────────────────────── */
.home-cta {
  padding: 86px 0;
  text-align: center;
  border-top: 1px solid rgba(24, 26, 23, 0.13);
}
.home-cta__h2 {
  font-family: var(--serif);
  font-weight: 400;
  letter-spacing: -0.035em;
  font-size: 52px;
  margin: 0 0 16px;
}
.home-cta__sub {
  color: rgba(24, 26, 23, 0.62);
  margin: 0 0 28px;
}
.home-footer {
  border-top: 1px solid rgba(24, 26, 23, 0.13);
  padding: 28px 0;
  color: rgba(24, 26, 23, 0.62);
  font-size: 13px;
}
.home-footer__row {
  display: flex;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
  align-items: baseline;
}
.home-footer__brand { font-size: 1.4rem; }
.home-footer__tag { flex: 1; min-width: 260px; }
.home-footer__version { font-size: 12px; }

/* ─── Phase HomeAccess (2026-06-08) — videos grid + request form ────
   Rebuilds the bottom of /about. The walkthrough mailto CTA is gone;
   in its place: a 4-tile videos-coming-soon grid (placeholders until
   the films are recorded) and a faceless request-access form that
   posts to /request-access. Both sit in the same paper register as
   the rest of the marketing surface — no app-shell chrome bleeds in.
*/
.home-videos {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
  margin-top: 28px;
}
.home-video-card {
  position: relative;
  background: rgba(251, 250, 243, 0.7);
  border: 1px solid rgba(24, 26, 23, 0.13);
  border-radius: 18px;
  padding: 28px 22px;
  min-height: 180px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  transition: transform 0.2s ease,
              box-shadow 0.2s ease,
              border-color 0.2s ease,
              background 0.2s ease;
}
.home-video-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 14px 32px rgba(24, 26, 23, 0.08);
  border-color: var(--bronze-pale);
  background: rgba(255, 255, 255, 0.85);
}
.home-video-card__badge {
  position: absolute;
  top: 18px;
  right: 18px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--bronze);
  background: rgba(122, 102, 72, 0.08);
  border: 1px solid rgba(122, 102, 72, 0.18);
  padding: 4px 10px;
  border-radius: 999px;
}
.home-video-card__title {
  font-family: var(--serif);
  font-weight: 500;
  font-size: 22px;
  color: var(--forest);
  letter-spacing: -0.01em;
  line-height: 1.2;
  margin-bottom: 8px;
}
.home-video-card__sub {
  font-size: 14.5px;
  color: rgba(24, 26, 23, 0.7);
  line-height: 1.5;
  margin: 0;
}

/* Request-access form card.
   Two-column on desktop: lead copy on the left, form card on the right.
   Stacks to single-column at the same 860px breakpoint as the rest of
   the page so the form stays comfortable on tablets / phones. */
.home-access {
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  gap: 56px;
  align-items: start;
  margin-top: 28px;
}
.home-access__lead {
  padding-top: 16px;
}
.home-access__eyebrow {
  font-size: 12px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--bronze);
  margin-bottom: 14px;
}
.home-access__h2 {
  font-family: var(--serif);
  font-weight: 400;
  letter-spacing: -0.03em;
  font-size: 40px;
  line-height: 1.15;
  margin: 0 0 18px;
  color: var(--ink);
}
.home-access__sub {
  font-family: var(--serif);
  font-size: 19px;
  line-height: 1.6;
  color: #38352f;
  margin: 0;
}
.home-access__form {
  background: #ffffff;
  border: 1px solid rgba(24, 26, 23, 0.13);
  border-radius: 22px;
  box-shadow: 0 24px 64px rgba(24, 26, 23, 0.07);
  padding: 40px 36px 32px;
  /* Bronze accent stripe — same chrome cue as the sign-in card on /. */
  position: relative;
  overflow: hidden;
}
.home-access__form::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 4px;
  background: linear-gradient(90deg, var(--bronze-pale), var(--bronze));
}
.home-access__label {
  display: block;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(24, 26, 23, 0.6);
  margin-bottom: 6px;
  margin-top: 18px;
}
.home-access__label:first-of-type { margin-top: 0; }
.home-access__input {
  width: 100%;
  box-sizing: border-box;
  border: 1px solid rgba(24, 26, 23, 0.18);
  border-radius: 10px;
  background: var(--paper);
  padding: 12px 14px;
  font-size: 16px;
  font-family: inherit;
  color: var(--ink);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.home-access__input:focus {
  outline: none;
  border-color: var(--bronze);
  box-shadow: 0 0 0 3px rgba(122, 102, 72, 0.16);
  background: #ffffff;
}
.home-access__select {
  appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path fill='%2338352f' d='M0 0l5 6 5-6z'/></svg>");
  background-repeat: no-repeat;
  background-position: right 14px center;
  padding-right: 36px;
}
.home-access__textarea {
  resize: vertical;
  min-height: 80px;
  font-family: inherit;
  line-height: 1.5;
}
.home-access__submit {
  margin-top: 22px;
  width: 100%;
  background: var(--ink);
  color: var(--paper);
  border: none;
  border-radius: 10px;
  padding: 14px 18px;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: 0.01em;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.1s ease;
}
.home-access__submit:hover {
  background: #2a2c28;
}
.home-access__submit:active { transform: scale(0.99); }
.home-access__small {
  text-align: center;
  font-size: 12.5px;
  margin: 14px 0 0;
}
.home-access__err {
  background: rgba(180, 60, 40, 0.08);
  border: 1px solid rgba(180, 60, 40, 0.25);
  color: #7a2f1c;
  padding: 10px 14px;
  border-radius: 8px;
  font-size: 14px;
  margin-bottom: 18px;
}
/* Honeypot — visually hidden, still in the DOM so bots find it. */
.home-access__honeypot {
  position: absolute;
  left: -10000px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Success state — replaces the form when ?ok=1 lands back. */
.home-access__form--ok {
  text-align: center;
  padding: 56px 36px 44px;
}
.home-access__ok-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: rgba(26, 46, 31, 0.08);
  color: var(--forest);
  font-size: 28px;
  margin-bottom: 18px;
}
/* HomeAccess-7 (2026-06-08): info-tone success card for dedup
   outcomes (request already on file). Bronze instead of forest so
   the visual distinction reads as "noted" rather than "success". */
.home-access__form--info .home-access__ok-mark {
  background: rgba(122, 102, 72, 0.1);
  color: var(--bronze);
}
.home-access__form--info::before {
  background: linear-gradient(90deg, var(--bronze-pale), var(--bronze));
  opacity: 0.7;
}
.home-access__ok-title {
  font-family: var(--serif);
  font-weight: 400;
  font-size: 32px;
  letter-spacing: -0.02em;
  margin: 0 0 12px;
  color: var(--ink);
}
.home-access__ok-body {
  font-family: var(--serif);
  font-size: 18px;
  line-height: 1.6;
  color: #38352f;
  margin: 0 0 18px;
}
.home-access__ok-foot {
  font-size: 14px;
  color: rgba(24, 26, 23, 0.62);
  margin: 0;
}

/* ─── Responsive ───────────────────────────────────────────────────── */
@media (max-width: 860px) {
  .home-hero,
  .home-section__grid,
  .home-access { grid-template-columns: 1fr; }
  .home-nav__links a:not(.home-btn) { display: none; }
  .home-philosophy { grid-template-columns: 1fr 1fr; }
  .home-videos { grid-template-columns: 1fr 1fr; }
  .home-login { padding: 28px; }
  .home-section { padding: 54px 0; }
  .home-access { gap: 32px; }
  .home-access__h2 { font-size: 32px; }
}
@media (max-width: 520px) {
  .home-body .wrap { width: min(100% - 24px, 1120px); }
  .home-philosophy { grid-template-columns: 1fr; }
  .home-videos { grid-template-columns: 1fr; }
  .home-hero { padding-top: 54px; }
  .home-h1 { font-size: 44px; }
  .home-cta__h2 { font-size: 38px; }
  .home-access__form { padding: 28px 22px 24px; }
}

/* ===========================================================================
   Activity console (Phase L2) — terminal-style live admin feed.
   ---------------------------------------------------------------------------
   Two surfaces use these styles (/admin/activity-console + /sa/activity-
   console). The design intent: looks like a Windows-terminal / Chrome-
   DevTools console — near-black background, monospace font, bronze and
   forest accent text. Newest line at the top; HTMX polling prepends
   fresh rows every 5s.
   =========================================================================== */
.activity-console-page {
  /* The page itself uses the standard .page-wide layout. Just give the
     console more vertical breathing room. */
}
.activity-console {
  margin-top: 16px;
  background: #0e1410;          /* near-black with a faint forest tilt */
  border: 1px solid var(--bronze);
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.16);
}

/* ─── Toolbar (sticky to top of the console block) ─────────────────── */
.activity-console__toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  padding: 10px 14px;
  background: #161e19;
  border-bottom: 1px solid rgba(192, 161, 115, 0.20);
  font-family: var(--mono);
  font-size: 0.85rem;
  color: rgba(232, 229, 220, 0.78);
}
.activity-console__toolbar-left,
.activity-console__toolbar-right {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.activity-console__btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: rgba(192, 161, 115, 0.10);
  color: rgba(232, 229, 220, 0.92);
  border: 1px solid rgba(192, 161, 115, 0.30);
  border-radius: 4px;
  padding: 5px 10px;
  font-family: var(--mono);
  font-size: 0.82rem;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.activity-console__btn:hover {
  background: rgba(192, 161, 115, 0.18);
  border-color: var(--bronze);
}
.activity-console__btn--paused {
  background: rgba(122, 102, 72, 0.30);
  border-color: var(--bronze);
}
.activity-console__btn--popout {
  /* Slight emphasis — pop-out is the discoverable "park this on a
     second monitor" affordance. */
  background: rgba(122, 102, 72, 0.18);
}

/* Live/paused status badge. The dot pulses on every successful poll
   so the admin can see the stream is alive. */
.activity-console__status {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: #88c98a;               /* forest-pale-on-dark */
  font-weight: 600;
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 4px 10px;
  border-radius: 4px;
  background: rgba(26, 46, 31, 0.45);
  border: 1px solid rgba(136, 201, 138, 0.30);
  transition: background 0.12s ease;
}
.activity-console__status--paused {
  color: rgba(232, 229, 220, 0.60);
  background: rgba(232, 229, 220, 0.06);
  border-color: rgba(232, 229, 220, 0.18);
}
.activity-console__status--pulse {
  background: rgba(136, 201, 138, 0.28);
}

/* Filter form (User + optional Tenant dropdowns). */
.activity-console__filter {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.activity-console__label {
  color: rgba(232, 229, 220, 0.62);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.activity-console__filter select {
  background: #0e1410;
  color: rgba(232, 229, 220, 0.92);
  border: 1px solid rgba(192, 161, 115, 0.30);
  border-radius: 4px;
  padding: 4px 8px;
  font-family: var(--mono);
  font-size: 0.82rem;
}
.activity-console__filter select:focus {
  outline: none;
  border-color: var(--bronze);
}

/* Phase ActivityConsole-ComboboxDark (2026-05-29).
   The User picker is the typeahead combobox (not a native <select>),
   so the .activity-console__filter select rules above don't apply.
   Without these the combobox renders with the default light-theme
   background (rgba(0, 0, 0, 0.04) — a 4% black overlay designed for
   cream-card backgrounds) which is invisible against the dark
   #0e1410 toolbar. Mirror the native-select styling here so the
   input box is visible in its resting state on the dark band.
   Width override: the base combobox uses width: 100% which would
   stretch the toolbar pill across the entire row; clamp to a
   reasonable picker width that matches the native select look. */
.activity-console__filter .combobox {
  width: auto;
}
.activity-console__filter .combobox__input {
  background: #0e1410;
  color: rgba(232, 229, 220, 0.92);
  border: 1px solid rgba(192, 161, 115, 0.30);
  border-radius: 4px;
  padding: 4px 8px;
  font-family: var(--mono);
  font-size: 0.82rem;
  min-width: 16ch;
}
.activity-console__filter .combobox__input::placeholder {
  color: rgba(232, 229, 220, 0.45);
}
.activity-console__filter .combobox__input:focus {
  outline: none;
  border-color: var(--bronze);
  /* Stay on the dark band on focus — don't snap to the light card
     background the base combobox uses (that's designed for forms
     INSIDE a cream filter-card, not a dark toolbar). The bronze
     border + matching select :focus rule above keeps the focus
     affordance without a jarring colour flash. */
  background: #0e1410;
  box-shadow: none;
}

/* Tenant-stats grid (Phase R follow-up). Pill tiles on the
   /sa/tenants/{id} detail page — pure numeric counts for the SA's
   capacity-planning view. One row per "logical group" of stats:
   seats / masters / ledger / automation / engagement. Auto-fit so
   the layout reflows responsively on narrow viewports. */
.tenant-stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 10px;
  margin-top: 4px;
}
.tenant-stats-tile {
  background: var(--paper-tint, rgba(0, 0, 0, 0.025));
  border: 1px solid var(--ink-12);
  border-radius: 6px;
  padding: 10px 12px;
  min-width: 0;
}
[data-theme="forest"] .tenant-stats-tile,
[data-theme="ink"]    .tenant-stats-tile {
  background: rgba(255, 255, 255, 0.04);
  border-color: rgba(255, 255, 255, 0.10);
}
.tenant-stats-tile__label {
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-65);
  margin-bottom: 4px;
}
.tenant-stats-tile__value {
  font-size: 1.4rem;
  font-weight: 600;
  line-height: 1.2;
  font-family: var(--mono);
}
.tenant-stats-tile__sub {
  font-size: 0.78rem;
  margin-top: 2px;
}

/* Quiet link — used in tabular listings (e.g. /sa/tenants) where the
   row content should LOOK like text but be clickable. No underline,
   inherits colour from surrounding cell, hover hint via cursor. */
.link-quiet {
  text-decoration: none;
  color: inherit;
}
.link-quiet:hover {
  text-decoration: underline;
  text-decoration-color: var(--bronze);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

/* Presence dot (Phase R) — small inline indicator on /sa/tenants
   list + tenant detail user roster. Green = user touched the app
   in the last ONLINE_WINDOW_MINUTES (default 5 min). Pulse animation
   makes "live now" visually distinct from a static green pill. */
.presence-dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  vertical-align: middle;
  margin-right: 4px;
}
.presence-dot--online {
  background: #2ecc71;
  box-shadow: 0 0 0 0 rgba(46, 204, 113, 0.55);
  animation: presence-pulse 1.6s ease-in-out infinite;
}
.presence-dot--offline {
  background: rgba(0, 0, 0, 0.15);
}
[data-theme="forest"] .presence-dot--offline,
[data-theme="ink"]    .presence-dot--offline {
  background: rgba(255, 255, 255, 0.20);
}
@keyframes presence-pulse {
  0%   { box-shadow: 0 0 0 0   rgba(46, 204, 113, 0.55); }
  70%  { box-shadow: 0 0 0 6px rgba(46, 204, 113, 0.00); }
  100% { box-shadow: 0 0 0 0   rgba(46, 204, 113, 0.00); }
}

/* Refresh-interval number input (Phase L3 — runtime-tunable poll
   cadence). Compact terminal-styled box; matches the filter select
   but narrower since it only holds 1–3 digits. */
.activity-console__refresh-input {
  width: 4ch;
  background: #0e1410;
  color: rgba(232, 229, 220, 0.92);
  border: 1px solid rgba(192, 161, 115, 0.30);
  border-radius: 4px;
  padding: 3px 6px;
  font-family: var(--mono);
  font-size: 0.82rem;
  text-align: right;
}
.activity-console__refresh-input:focus {
  outline: none;
  border-color: var(--bronze);
}
/* Hide the browser-default spinner — the input is for typing a
   target number, not nudging up/down. */
.activity-console__refresh-input::-webkit-inner-spin-button,
.activity-console__refresh-input::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.activity-console__refresh-input { -moz-appearance: textfield; }

/* ─── Stream (the actual terminal area) ────────────────────────────── */
.activity-stream {
  font-family: var(--mono);
  font-size: 0.85rem;
  line-height: 1.55;
  padding: 12px 16px;
  max-height: 68vh;
  overflow-y: auto;
  color: rgba(232, 229, 220, 0.90);
  /* Scrollbar tuned to the dark surface. */
  scrollbar-color: rgba(192, 161, 115, 0.32) #0e1410;
  scrollbar-width: thin;
}
.activity-stream::-webkit-scrollbar { width: 8px; }
.activity-stream::-webkit-scrollbar-track { background: #0e1410; }
.activity-stream::-webkit-scrollbar-thumb {
  background: rgba(192, 161, 115, 0.32);
  border-radius: 4px;
}
.activity-stream__line {
  padding: 4px 0;
  border-bottom: 1px dotted rgba(192, 161, 115, 0.10);
}
.activity-stream__line:first-child {
  /* Subtle highlight on the topmost line so newly-prepended rows
     are easy to spot at a glance. Fades to nothing after a few
     seconds via CSS animation. */
  animation: activity-flash 1.4s ease-out 1;
}
@keyframes activity-flash {
  0%   { background: rgba(136, 201, 138, 0.15); }
  100% { background: transparent; }
}
.activity-stream__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
}
.activity-stream__ts {
  color: rgba(232, 229, 220, 0.52);
}
.activity-stream__user {
  color: #c1a173;               /* lighter bronze for the actor name */
  font-weight: 600;
}
.activity-stream__role {
  color: rgba(232, 229, 220, 0.48);
  font-weight: 400;
  font-size: 0.78em;
}
.activity-stream__tenant {
  margin-left: auto;
  color: #88c98a;               /* forest-pale */
  font-size: 0.78em;
  font-style: italic;
}
.activity-stream__tenant--system {
  color: rgba(232, 229, 220, 0.42);
}
.activity-stream__body {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
  padding-left: 4px;
}
.activity-stream__arrow {
  color: rgba(192, 161, 115, 0.55);
}
.activity-stream__summary {
  color: rgba(232, 229, 220, 0.95);
}
.activity-stream__target,
.activity-stream__url {
  color: rgba(232, 229, 220, 0.42);
  font-size: 0.88em;
}

/* Subtle per-kind tint on the body row so glance-scanning is faster.
   Bronze for writes, salmon for deletes, forest for downloads/exports/
   reports, neutral muted for nav. */
.activity-stream__body--kind-write    .activity-stream__summary { color: #d7c39f; }
.activity-stream__body--kind-delete   .activity-stream__summary { color: #e7a89a; }
.activity-stream__body--kind-download .activity-stream__summary { color: #b9d8b8; }
.activity-stream__body--kind-report   .activity-stream__summary { color: #b9d8b8; }
.activity-stream__body--kind-auth     .activity-stream__summary { color: #ddc2e0; }
.activity-stream__body--kind-nav      .activity-stream__summary { color: rgba(232, 229, 220, 0.74); }

/* Empty-state placeholder when no events exist yet. */
.activity-stream__empty {
  padding: 28px 12px;
  color: rgba(232, 229, 220, 0.55);
  font-style: italic;
  text-align: center;
}
.activity-stream__empty-icon {
  display: block;
  font-size: 1.6rem;
  margin-bottom: 8px;
  color: rgba(192, 161, 115, 0.40);
}

/* Cross-tenant variant gets a touch more horizontal breathing room
   because each line carries an extra tenant tag. */
.activity-stream--cross-tenant .activity-stream__head { gap: 10px; }

/* When the console is loaded in a popped-out window the .layout
   wrapper still wraps it. Stretch the console to fill the small
   viewport so it feels like a true terminal. */
@media (max-width: 960px) {
  .activity-stream { max-height: 78vh; }
  .activity-console__toolbar {
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
  }
  .activity-console__toolbar-left,
  .activity-console__toolbar-right,
  .activity-console__filter { justify-content: flex-start; }
}

/* ---------------------------------------------------------------------------
   Pop-out window — bare layout, no sidebar, no app chrome.
   ---------------------------------------------------------------------------
   The popout template (_partials/activity_console_popout.html) is
   self-contained: it does NOT extend base.html, so none of the
   .layout/.sidebar/.main styles apply. We rebuild a minimal
   full-window shell here that just hosts the terminal block.
   --------------------------------------------------------------------------- */
.activity-popout-body {
  background: #0e1410;
  color: var(--ink);
  margin: 0;
  padding: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
}

/* The tiny pop-out hint strip at the very top — gives the user a
   visual cue that this is a focused secondary window. */
.activity-popout__hint {
  background: #161e19;
  border-bottom: 1px solid rgba(192, 161, 115, 0.20);
  padding: 6px 12px;
  font-family: var(--mono);
  font-size: 0.75rem;
  color: rgba(232, 229, 220, 0.55);
  letter-spacing: 0.04em;
  text-align: right;
}
.activity-popout__hint-text { white-space: nowrap; }

/* The popout variant of .activity-console drops the rounded corners
   + shadow — they don't make sense when the console fills the entire
   window. Also lets the stream area grow to the bottom of the window
   instead of the 68vh cap the in-app version uses. */
.activity-console--popout {
  margin: 0;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;       /* lets the inner flex stream scroll */
}
.activity-console--popout .activity-console__toolbar {
  flex-shrink: 0;
}
.activity-stream--popout {
  flex: 1;
  max-height: none;    /* no cap inside the popout — fill the window */
  min-height: 0;
}

/* ---------------------------------------------------------------------------
   Per-user colour palette (Phase M2).
   ---------------------------------------------------------------------------
   Twelve hues tuned to read clearly against the #0e1410 console
   background. The server emits ``data-user-color="N"`` (0..11) on
   every line; activating the palette is a single class flip
   (.activity-stream--colored) on the stream container, controlled by
   the "Colour by user" checkbox in the toolbar.

   When the class is absent (toggle OFF), .activity-stream__user
   falls back to its default bronze — same look as before this phase.
   --------------------------------------------------------------------------- */
.activity-stream--colored [data-user-color="0"]  .activity-stream__user { color: #b9d8b8; } /* forest pale */
.activity-stream--colored [data-user-color="1"]  .activity-stream__user { color: #d7c39f; } /* bronze warm */
.activity-stream--colored [data-user-color="2"]  .activity-stream__user { color: #e7a89a; } /* salmon */
.activity-stream--colored [data-user-color="3"]  .activity-stream__user { color: #ddc2e0; } /* lavender */
.activity-stream--colored [data-user-color="4"]  .activity-stream__user { color: #9bc8d6; } /* sky */
.activity-stream--colored [data-user-color="5"]  .activity-stream__user { color: #f0c98a; } /* peach */
.activity-stream--colored [data-user-color="6"]  .activity-stream__user { color: #a3d9be; } /* mint */
.activity-stream--colored [data-user-color="7"]  .activity-stream__user { color: #d4b7e2; } /* rose-lilac */
.activity-stream--colored [data-user-color="8"]  .activity-stream__user { color: #b6c79e; } /* sage */
.activity-stream--colored [data-user-color="9"]  .activity-stream__user { color: #ecc56b; } /* gold */
.activity-stream--colored [data-user-color="10"] .activity-stream__user { color: #c4a07e; } /* terra-cotta */
.activity-stream--colored [data-user-color="11"] .activity-stream__user { color: #8fbac7; } /* dusty cyan */

/* Toolbar group for the filter checkboxes (Phase M1) + colour toggle
   (Phase M2). Sits next to the user/tenant filter forms; uses
   monospace + muted styling consistent with the rest of the bar. */
.activity-console__display-prefs {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px 14px;
  padding: 4px 0;
}
.activity-console__display-prefs label {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--mono);
  font-size: 0.78rem;
  color: rgba(232, 229, 220, 0.78);
  cursor: pointer;
  user-select: none;
}
.activity-console__display-prefs input[type="checkbox"] {
  width: 13px;
  height: 13px;
  accent-color: var(--bronze);
  cursor: pointer;
}
.activity-console__display-prefs-divider {
  width: 1px;
  height: 16px;
  background: rgba(192, 161, 115, 0.20);
}

/* ─────────────────────────────────────────────────────────────────────
   Audit-log details (added 2026-05-20).

   A "show details ▾" toggle per audit row reveals the full details
   string, formatted as monospace with field-pair colouring. Closes
   the gap left by the previous summary-only view where the
   key=value fields (old=… new=…) were invisible.
   ───────────────────────────────────────────────────────────────── */
.audit-row__details-toggle {
  background: transparent;
  border: 0;
  color: var(--bronze-mid);
  cursor: pointer;
  font: 500 11px var(--sans);
  padding: 0 4px;
  margin-left: 8px;
  letter-spacing: 0.02em;
}
.audit-row__details-toggle:hover { color: var(--bronze); }
.audit-row__details {
  margin: 6px 0 0 0;
  padding: 8px 10px;
  background: rgba(0, 0, 0, 0.04);
  border-left: 3px solid var(--bronze);
  border-radius: 4px;
  font: 400 12px/1.5 var(--mono);
  color: var(--ink);
  white-space: pre-wrap;
  word-break: break-word;
  max-width: 100%;
  overflow-x: auto;
}
[data-theme="forest"] .audit-row__details,
[data-theme="ink"] .audit-row__details {
  background: rgba(0, 0, 0, 0.18);
}
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] .audit-row__details {
    background: rgba(0, 0, 0, 0.18);
  }
}

/* ─────────────────────────────────────────────────────────────────────
   Dashboard customise (added 2026-05-20).

   Hides individual tiles on /overview. The "×" button is injected
   into the tile's heading by static/js/dashboard-customise.js;
   the bottom "Hidden tiles" tray shows chips to restore them.
   ───────────────────────────────────────────────────────────────── */
.dash-tile-hide {
  float: right;
  margin-left: 8px;
  background: transparent;
  border: 0;
  color: var(--ink-45);
  cursor: pointer;
  font-size: 18px;
  line-height: 1;
  padding: 0 6px;
  border-radius: 4px;
  transition: background 0.1s ease, color 0.1s ease;
}
.dash-tile-hide:hover {
  background: rgba(192, 161, 115, 0.15);
  color: var(--bronze);
}
.dash-hidden-tray {
  margin-top: 24px;
  padding: 12px 16px;
  border-top: 1px dashed var(--ink-12);
}
.dash-hidden-tray__title {
  font: 500 12px/1.2 var(--sans);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-65);
  margin: 0 0 8px 0;
}
.dash-hidden-tray__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.dash-hidden-tray__chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  border: 1px solid var(--ink-25);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.03);
  font: 500 12px var(--sans);
  color: var(--ink-80);
  cursor: pointer;
  transition: background 0.1s ease, border-color 0.1s ease;
}
.dash-hidden-tray__chip:hover {
  background: rgba(192, 161, 115, 0.12);
  border-color: var(--bronze-mid);
  color: var(--ink);
}
.dash-hidden-tray__plus {
  color: var(--bronze);
  font-weight: 700;
}

/* ─────────────────────────────────────────────────────────────────────
   Form wizard / stepper (added 2026-05-20).

   Rendered by static/js/form-wizard.js on forms marked
   ``data-wizard="1"``. Visual progress bar at the top + back/next
   buttons alongside the existing submit button.
   ───────────────────────────────────────────────────────────────── */
.wizard-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 18px 0;
  padding: 10px 14px;
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.03);
  border: 1px solid var(--ink-12);
  font-size: 13px;
  flex-wrap: wrap;
}
.wizard-bar__step {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--ink-65);
}
.wizard-bar__num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--ink-12);
  color: var(--ink);
  font-weight: 600;
  font-size: 12px;
}
.wizard-bar__step--active .wizard-bar__num {
  background: var(--bronze);
  color: #ffffff;
}
.wizard-bar__step--done .wizard-bar__num {
  background: var(--forest);
  color: #ffffff;
}
.wizard-bar__step--active { color: var(--ink); font-weight: 500; }
.wizard-bar__step--done   { color: var(--forest); }
.wizard-bar__sep {
  color: var(--ink-45);
  font-size: 16px;
  user-select: none;
}
[data-theme="forest"] .wizard-bar,
[data-theme="ink"] .wizard-bar {
  background: rgba(0, 0, 0, 0.18);
  border-color: rgba(192, 161, 115, 0.30);
}
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] .wizard-bar {
    background: rgba(0, 0, 0, 0.18);
    border-color: rgba(192, 161, 115, 0.30);
  }
}

/* ─────────────────────────────────────────────────────────────────────
   Inline sparklines (added 2026-05-20).

   Tiny line charts emitted by _partials/_sparkline.html. The macro
   adds a modifier class for the trend direction so we can colour
   the stroke + area without inline styles. Up = forest, down =
   terracotta-ish, flat = bronze.
   ───────────────────────────────────────────────────────────────── */
.sparkline {
  display: inline-block;
  vertical-align: middle;
}
.sparkline__stroke {
  stroke: var(--bronze);
  stroke-width: 1.5;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.sparkline__area {
  fill: rgba(192, 161, 115, 0.18);  /* bronze, faded */
}
.sparkline--up   .sparkline__stroke { stroke: var(--forest); }
.sparkline--up   .sparkline__area   { fill: rgba(58, 90, 71, 0.15); }
.sparkline--down .sparkline__stroke { stroke: #c0392b; }
.sparkline--down .sparkline__area   { fill: rgba(192, 57, 43, 0.12); }

/* ─────────────────────────────────────────────────────────────────────
   Keyboard-shortcut toast (added 2026-05-20).

   A small notification rendered in the lower-right corner when the
   user hits "?" or a "g X" navigation chord. Auto-dismisses.
   ───────────────────────────────────────────────────────────────── */
.kbd-toast {
  position: fixed;
  bottom: 20px;
  right: 20px;
  z-index: 200;
  max-width: 480px;
  padding: 12px 16px;
  background: var(--ink);
  color: var(--paper);
  border-radius: 8px;
  box-shadow: 0 12px 32px -8px rgba(0, 0, 0, 0.40);
  font: 400 13px/1.5 var(--sans);
  opacity: 0;
  transform: translateY(8px);
  pointer-events: none;
  transition: opacity 0.15s ease, transform 0.15s ease;
}
.kbd-toast--visible {
  opacity: 1;
  transform: translateY(0);
}
.kbd-toast code {
  font: 500 11.5px var(--mono);
  padding: 1px 5px;
  background: rgba(255, 255, 255, 0.18);
  border-radius: 3px;
  margin: 0 1px;
}

/* ─────────────────────────────────────────────────────────────────────
   Empty-state placeholder (added 2026-05-20).

   Rendered by _partials/_empty_state.html when a list page has no
   rows. Replaces the old bare "No data" message with a friendly
   layout: large bronze icon → title → body → CTA button.
   ───────────────────────────────────────────────────────────────── */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 48px 24px;
  margin: 24px 0;
  border: 1px dashed var(--ink-25);
  border-radius: 12px;
  background: rgba(0, 0, 0, 0.02);
}
.empty-state__icon {
  width: 48px;
  height: 48px;
  color: var(--bronze);
  margin-bottom: 14px;
  opacity: 0.7;
}
.empty-state__icon svg {
  width: 100%; height: 100%; display: block;
}
.empty-state__title {
  font: 600 18px/1.3 var(--sans);
  color: var(--ink);
  margin: 0 0 6px 0;
}
.empty-state__body {
  font: 400 14px/1.5 var(--sans);
  max-width: 480px;
  margin: 0 0 18px 0;
}
.empty-state__actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
}
.empty-state--compact {
  padding: 24px 16px;
  margin: 12px 0;
}
.empty-state--compact .empty-state__icon { width: 32px; height: 32px; margin-bottom: 8px; }
.empty-state--compact .empty-state__title { font-size: 15px; }
.empty-state--compact .empty-state__body  { font-size: 13px; margin-bottom: 10px; }

[data-theme="forest"] .empty-state,
[data-theme="ink"] .empty-state {
  background: rgba(0, 0, 0, 0.12);
  border-color: rgba(192, 161, 115, 0.30);
}
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] .empty-state {
    background: rgba(0, 0, 0, 0.12);
    border-color: rgba(192, 161, 115, 0.30);
  }
}

/* ─────────────────────────────────────────────────────────────────────
   Print stylesheet (added 2026-05-20).

   When the user prints any page, we want a clean documenty output:
     * Sidebar + topbar + footers hidden.
     * Backgrounds stripped so the printer doesn't waste toner.
     * Tables full-width with explicit borders for the paper read.
     * Buttons / form actions / nav hidden — printout is read-only.
     * Page-header icons hidden (decorative on print).
     * Links shown as black text (no underline / colour).
     * Page-break-inside avoided inside cards + table rows.

   Use with the browser's native Print > Save as PDF for a one-click
   printable report on any list page or detail page.
   ───────────────────────────────────────────────────────────────── */
@media print {
  /* Page setup — narrow margins, A4 portrait by default. Override
     to landscape on any specific page via a CSS class if needed. */
  @page { margin: 12mm; size: A4; }

  /* Reset surface colours — the rest of the cascade still applies,
     but we override the dark themes so prints come out clean. */
  body, .layout, .layout__main, .main {
    background: #ffffff !important;
    color: #000000 !important;
  }
  * {
    text-shadow: none !important;
    box-shadow: none !important;
    background-color: transparent !important;
  }

  /* Hide chrome — navigation, action surfaces, anything interactive. */
  .sidebar,
  .layout__hamburger,
  .topbar,
  .flash,
  .flash-messages,
  .data-grid-toolbar,
  .filter-bar,
  .filter-card,
  .filter-actions,
  .form__actions,
  .btn,
  .btn-group,
  .pagination,
  .window-picker,
  .sidebar__footer,
  .cmdpalette,
  .reorder-handle,
  .date-chips,
  nav[aria-label="Module subnav"],
  .module-subnav,
  .tabs,
  footer {
    display: none !important;
  }

  /* Layout — drop the sidebar grid, let main fill the page. */
  .layout {
    display: block !important;
  }
  .layout__main, .main, .page-wide {
    margin: 0 !important;
    padding: 0 !important;
    max-width: 100% !important;
    width: 100% !important;
  }

  /* Page heading — keep the title, drop the icon. */
  .page-header__icon { display: none !important; }
  .page-header__h1 {
    color: #000 !important;
    border-bottom: 1px solid #000 !important;
    padding-bottom: 4px !important;
    margin-bottom: 12px !important;
  }

  /* Tables — explicit borders + collapse, no zebra. */
  table, .admin-table, .data-table {
    width: 100% !important;
    border-collapse: collapse !important;
    page-break-inside: auto !important;
  }
  th, td {
    border: 1px solid #000 !important;
    padding: 4px 6px !important;
    color: #000 !important;
    background: #fff !important;
  }
  thead { display: table-header-group; }  /* repeat headers across pages */
  tr { page-break-inside: avoid; }

  /* Links — stripped to plain black; no URL appended (would be
     visual noise for prints destined to be read on paper). */
  a, a:visited {
    color: #000 !important;
    text-decoration: none !important;
  }

  /* KPI tiles + cards — flat, no fill. */
  .dash-kpi, .dash-card, .kpi, .kpi-grid, .bank-card {
    background: #fff !important;
    border: 1px solid #000 !important;
    page-break-inside: avoid;
  }

  /* Form inputs — show as text in their box, no fill or border-radius. */
  input, select, textarea {
    background: transparent !important;
    border: 1px solid #888 !important;
    border-radius: 0 !important;
    color: #000 !important;
  }
}

/* ─────────────────────────────────────────────────────────────────────
   Amount-calc hint (added 2026-05-20).

   A small "fx" affordance shown on hover for inputs the calculator
   is bound to. Pure cosmetic — the actual evaluation is in
   static/js/amount-calc.js. */
input[data-amount-calc]:not(:disabled):hover {
  cursor: text;
}

/* ─────────────────────────────────────────────────────────────────────
   Amount-words live readback (added 2026-05-26, Phase AmountWords-1).

   Sibling <small> inserted directly after any input[inputmode="decimal"]
   by static/js/amount-input.js. Reads the input value live and renders
   "Rupees X Only" using Indian lakh/crore grouping. Helps users
   sanity-check whether they typed the right number of zeros on a
   7-figure amount.

   Sits in the layout regardless of content via min-height so the
   form doesn't jump when the field goes from empty → typed → empty.
   Italic + muted so it reads as helper text, not form data. */
.amount-words {
  display: block;
  margin-top: 4px;
  min-height: 1.15em;
  font-size: 0.78rem;
  font-style: italic;
  line-height: 1.4;
  letter-spacing: 0.01em;
  color: var(--muted, #6b7280);
}

/* ─────────────────────────────────────────────────────────────────────
   Command palette (added 2026-05-20).

   Full-page modal overlay triggered by Ctrl+K / Cmd+K / "/" from
   anywhere in the app. Rendered into base.html via
   _partials/_command_palette.html (only when current_user is set).
   See app/static/js/command-palette.js for the Alpine component.
   ───────────────────────────────────────────────────────────────── */
.cmdpalette {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 12vh 16px 16px;
  background: rgba(0, 0, 0, 0.45);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}
.cmdpalette__panel {
  width: 100%;
  max-width: 640px;
  max-height: 70vh;
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: 1px solid var(--ink-25);
  border-radius: 12px;
  box-shadow: 0 24px 64px -16px rgba(0, 0, 0, 0.45);
  overflow: hidden;
}
.cmdpalette__inputrow {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--ink-12);
}
.cmdpalette__icon {
  color: var(--ink-65);
  flex: 0 0 auto;
  display: inline-flex;
}
.cmdpalette__input {
  flex: 1;
  border: 0;
  outline: none;
  background: transparent;
  color: var(--ink);
  font: 400 15px/1.4 var(--sans);
  padding: 2px 0;
}
.cmdpalette__input::placeholder { color: var(--ink-45); }
.cmdpalette__kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  padding: 1px 6px;
  border: 1px solid var(--ink-25);
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.04);
  color: var(--ink-65);
  font: 500 11px/1.2 var(--mono);
  letter-spacing: 0.02em;
}
.cmdpalette__list {
  list-style: none;
  margin: 0;
  padding: 6px;
  overflow-y: auto;
  flex: 1;
}
.cmdpalette__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 10px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 14px;
  color: var(--ink);
  line-height: 1.35;
  user-select: none;
}
.cmdpalette__item--active,
.cmdpalette__item:hover {
  background: var(--bronze);
  color: #ffffff;
}
.cmdpalette__item-label  { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cmdpalette__item-group  { font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; flex: 0 0 auto; }
.cmdpalette__item--active .cmdpalette__item-group,
.cmdpalette__item:hover .cmdpalette__item-group {
  color: rgba(255, 255, 255, 0.85);
}
.cmdpalette__empty {
  padding: 16px 10px;
  text-align: center;
  font-size: 13px;
}
.cmdpalette__footer {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 8px 14px;
  border-top: 1px solid var(--ink-12);
  font-size: 11.5px;
  letter-spacing: 0.02em;
  flex-wrap: wrap;
}
.cmdpalette__footer-spacer { flex: 1; }
[data-theme="forest"] .cmdpalette__panel,
[data-theme="ink"] .cmdpalette__panel {
  border-color: rgba(192, 161, 115, 0.30);
}
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] .cmdpalette__panel {
    border-color: rgba(192, 161, 115, 0.30);
  }
}

/* ─────────────────────────────────────────────────────────────────────
   Quick-date filter chips (added 2026-05-20).

   Pill-style buttons rendered above a start_date+end_date pair of
   <input type="date"> fields. Click → JS computes the appropriate
   range and writes ISO dates into the inputs (optionally autosubmits).
   See app/static/js/date-chips.js and _partials/_date_chips.html.
   ───────────────────────────────────────────────────────────────── */
.date-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 4px 0 10px 0;
  align-items: center;
}
.date-chip {
  font: 500 12px/1 var(--sans);
  letter-spacing: 0.02em;
  padding: 6px 10px;
  border: 1px solid var(--ink-25);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.03);
  color: var(--ink-80);
  cursor: pointer;
  user-select: none;
  transition: background 0.1s ease, border-color 0.1s ease, color 0.1s ease;
}
.date-chip:hover {
  background: rgba(192, 161, 115, 0.12);
  border-color: var(--bronze-mid);
  color: var(--ink);
}
.date-chip:focus-visible {
  outline: 2px solid var(--bronze);
  outline-offset: 2px;
}
.date-chip--active {
  background: var(--bronze);
  border-color: var(--bronze);
  color: #ffffff;
}
.date-chip--active:hover {
  background: var(--bronze);
  color: #ffffff;
}
[data-theme="forest"] .date-chip,
[data-theme="ink"] .date-chip {
  background: rgba(0, 0, 0, 0.18);
  border-color: rgba(192, 161, 115, 0.30);
}
[data-theme="forest"] .date-chip:hover,
[data-theme="ink"] .date-chip:hover {
  background: rgba(192, 161, 115, 0.18);
}
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] .date-chip {
    background: rgba(0, 0, 0, 0.18);
    border-color: rgba(192, 161, 115, 0.30);
  }
  [data-theme="auto"] .date-chip:hover {
    background: rgba(192, 161, 115, 0.18);
  }
}

/* ─────────────────────────────────────────────────────────────────────
   Drag-reorder handle for admin tables (added 2026-05-20).

   Used by /admin/masters/matrix-columns with Sortable.js. The handle
   is a "grip" character (⋮⋮) sitting in a narrow leftmost column on
   each row. cursor=grab signals interactivity; the ghost / chosen /
   drag classes give visual feedback during the drag operation.
   ───────────────────────────────────────────────────────────────── */
.reorder-handle {
  cursor: grab;
  user-select: none;
  text-align: center;
  vertical-align: middle;
  padding: 6px 4px;
  color: var(--ink-45);
}
.reorder-handle:hover { color: var(--bronze); }
.reorder-handle:active { cursor: grabbing; }
.reorder-grip {
  font-size: 16px;
  letter-spacing: -2px;        /* tighten the two ⋮ glyphs together */
  font-weight: 700;
}

/* Sortable.js applies these classes during the drag lifecycle:
   * ghost   = the placeholder row left behind in the original spot
   * chosen  = the row being dragged
   * drag    = the dragged clone that follows the cursor */
.reorder-ghost {
  opacity: 0.35;
  background: var(--forest-pale);
}
.reorder-chosen {
  background: rgba(192, 161, 115, 0.08);
}
.reorder-drag {
  opacity: 0.95;
  box-shadow: 0 8px 24px -8px rgba(0, 0, 0, 0.25);
}
[data-theme="forest"] .reorder-ghost,
[data-theme="ink"] .reorder-ghost {
  background: rgba(192, 161, 115, 0.15);
}
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] .reorder-ghost {
    background: rgba(192, 161, 115, 0.15);
  }
}

/* ─────────────────────────────────────────────────────────────────────
   Combobox (added 2026-05-20).

   Type-ahead replacement for <select>. The visible input mimics the
   look of a normal text input in .form / .filter-field contexts so
   pages that swap select->combobox don't visibly shift.

   The dropdown <ul> floats absolutely positioned under the input.
   The wrapping <div class="combobox"> uses position:relative so the
   list anchors correctly even inside flex / grid layouts.

   [x-cloak] hides Alpine-bound elements until the JS runs — prevents
   the list flashing visible on initial render.
   ───────────────────────────────────────────────────────────────── */
[x-cloak] { display: none !important; }

.combobox {
  position: relative;
  width: 100%;
}
/* Universal input style — a subtle ink overlay that creates a
   "slightly darker than my parent" effect against ANY context. In
   light themes (paper/sand/bone) the 4% overlay on top of cream
   page OR cream filter-card gives ~4 RGB units of darkening — enough
   to read as a distinct field without looking like a coloured
   surface. In dark themes the [data-theme=...] block below replaces
   this with a deeper 22% overlay for the same relative effect. */
.combobox__input {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--ink-25);
  border-radius: var(--radius);
  background: rgba(0, 0, 0, 0.04);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 400;
  line-height: 1.4;
  transition: border-color 0.1s ease, background 0.1s ease, box-shadow 0.1s ease;
  box-sizing: border-box;
}
.combobox__input:focus {
  outline: none;
  border-color: var(--forest);
  background: var(--card);            /* "snap" to bright white on focus */
  box-shadow: 0 0 0 3px var(--forest-pale);
}
.combobox__input::placeholder { color: var(--ink-45); }
.combobox__input:disabled {
  background: var(--ink-07);
  color: var(--ink-65);
  cursor: not-allowed;
}

/* Floating dropdown list — uses --card (a notch brighter than
   --paper in dark themes) so the list pops above the page surface
   instead of merging with it. Border is --ink-25 (stronger than
   --ink-12) and the shadow gives a real edge. */
.combobox__list {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 30;
  max-height: 280px;
  overflow-y: auto;
  margin: 0;
  padding: 4px;
  list-style: none;
  background: var(--card);
  border: 1px solid var(--ink-25);
  border-radius: var(--radius);
  box-shadow: 0 12px 28px -8px rgba(0, 0, 0, 0.30);
}
.combobox__item {
  padding: 7px 10px;
  border-radius: calc(var(--radius) - 2px);
  cursor: pointer;
  font-size: 14px;
  color: var(--ink);
  line-height: 1.35;
  user-select: none;
}
.combobox__item--active,
.combobox__item:hover {
  background: var(--forest-pale);
  color: var(--ink);
}
.combobox__empty {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 30;
  margin: 0;
  padding: 10px 12px;
  background: var(--card);
  border: 1px solid var(--ink-25);
  border-radius: var(--radius);
  font-size: 13px;
  font-style: italic;
}

/* ── Category Mapper grid — Phase CatMapper-1 ───────────────────────────
   Roomier rows + zebra striping for easy line-scanning of a long list. */
.cat-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}
.cat-table thead th {
  text-align: left;
  padding: 12px 14px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-65);
  /* Phase CatMapper-3 (2026-06-13): slight dark tint on the header bar so the
     column titles read as a distinct title row above the transaction rows. */
  background: rgba(0, 0, 0, 0.05);
  border-bottom: 1px solid var(--ink-25);
}
.cat-table tbody td {
  padding: 9px 14px;                  /* comfortable density — not cramped, not tall */
  border-bottom: 1px solid var(--ink-07);
  vertical-align: middle;
  line-height: 1.35;
}
.cat-table tbody tr:nth-child(even) { background: rgba(0, 0, 0, 0.028); }
.cat-table tbody tr:hover { background: var(--forest-pale); }

/* ── Multi-select combobox (chips + type-ahead) — Phase CatMapper-1 ──────
   Reuses .combobox (positioning) + .combobox__list/__item (dropdown). The
   control is a wrapping box that holds removable chips and a borderless
   growing text input. One hidden <input> per chosen value is emitted by the
   macro, all sharing the field name (so the form posts repeated keys). */
.multiselect__control {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  min-height: 40px;
  padding: 5px 8px;
  border: 1px solid var(--ink-25);
  border-radius: var(--radius);
  background: rgba(0, 0, 0, 0.04);
  cursor: text;
  transition: border-color 0.1s ease, background 0.1s ease, box-shadow 0.1s ease;
}
.multiselect__control:focus-within {
  outline: none;
  border-color: var(--forest);
  background: var(--card);
  box-shadow: 0 0 0 3px var(--forest-pale);
}
.multiselect__chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 6px 3px 10px;
  background: var(--forest-pale);
  color: var(--ink);
  border-radius: 999px;
  font-size: 12.5px;
  line-height: 1.3;
  white-space: nowrap;
}
.multiselect__x {
  border: 0;
  background: transparent;
  color: var(--ink-65);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  padding: 0 2px;
}
.multiselect__x:hover { color: var(--ink); }
.multiselect__input {
  flex: 1 1 80px;
  min-width: 80px;
  border: 0;
  background: transparent;
  color: var(--ink);
  font-family: var(--sans);
  font-size: 14px;
  padding: 4px 2px;
}
.multiselect__input:focus { outline: none; }
.multiselect__input::placeholder { color: var(--ink-45); }

/* When the combobox sits inside .filter-field (the /entry-style
   top filter row), inherit the field's compact padding. The
   .filter-field provides its own label/spacing — the combobox just
   needs to fit. */
.filter-field .combobox__input {
  padding: 7px 10px;
  font-size: 14px;
}

/* Dark-theme contrast fixes for the combobox active row.
   --forest-pale (#d6dcd2) is a LIGHT colour. In light themes the
   text on top is dark --ink, so the pale-on-dark-text contrast
   reads. In forest/ink themes --ink flips to a CREAM colour, so
   we end up with cream-on-pale-green = invisible. Force the active
   row to use a deeper-bronze background with explicit ink-dark
   text, matching the bronze accent vocabulary used elsewhere in
   dark themes (e.g. sidebar active row, kpi accents). */
[data-theme="forest"] .combobox__item--active,
[data-theme="forest"] .combobox__item:hover,
[data-theme="ink"] .combobox__item--active,
[data-theme="ink"] .combobox__item:hover {
  background: var(--bronze);
  color: #ffffff;
}
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] .combobox__item--active,
  [data-theme="auto"] .combobox__item:hover {
    background: var(--bronze);
    color: #ffffff;
  }
}

/* Dark-theme: the combobox INPUT background needs to read as
   "darker than whatever I'm sitting on" regardless of parent —
   page background (--ivory) OR a nested .filter-card (--paper)
   would otherwise be visually identical to a --card input.
   Mirror the pattern .form input[type="text"] uses for the same
   reason: a semi-transparent BLACK overlay creates a relative
   darkening against any parent.

   The dropdown LIST stays solid --card because it must occlude
   the content beneath it — see .combobox__list above. */
[data-theme="forest"] .combobox__input,
[data-theme="ink"] .combobox__input {
  background: rgba(0, 0, 0, 0.22);
  color: var(--ink);
  border-color: rgba(192, 161, 115, 0.30);   /* bronze @ 30% */
}
[data-theme="forest"] .combobox__input:focus,
[data-theme="ink"] .combobox__input:focus {
  background: rgba(0, 0, 0, 0.30);
  border-color: var(--bronze-mid);
  box-shadow: 0 0 0 3px rgba(192, 161, 115, 0.25);
}
[data-theme="forest"] .combobox__list,
[data-theme="forest"] .combobox__empty,
[data-theme="ink"] .combobox__list,
[data-theme="ink"] .combobox__empty {
  border-color: rgba(192, 161, 115, 0.30);
}
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] .combobox__input {
    background: rgba(0, 0, 0, 0.22);
    color: var(--ink);
    border-color: rgba(192, 161, 115, 0.30);
  }
  [data-theme="auto"] .combobox__input:focus {
    background: rgba(0, 0, 0, 0.30);
    border-color: var(--bronze-mid);
    box-shadow: 0 0 0 3px rgba(192, 161, 115, 0.25);
  }
  [data-theme="auto"] .combobox__list,
  [data-theme="auto"] .combobox__empty {
    border-color: rgba(192, 161, 115, 0.30);
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   /transactions — Option A filter UI (toolbar + chip strip + drawer)
   ───────────────────────────────────────────────────────────────────────
   Replaces the 5-card stacked filter region (~480px tall) with a
   single-row toolbar + chip strip + slide-in drawer that keeps the
   transactions table above the fold even with several filters active.
   Long-tail filters (multi-select pill groups, amount range, period
   browser) live in the drawer. ═══════════════════════════════════════ */

/* ---- Single-row toolbar (always visible). */
.txn-toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  background: var(--paper);
  border: var(--rule);
  border-radius: var(--radius);
  padding: 8px 10px;
  margin-bottom: 8px;
  position: sticky;
  top: 0;
  z-index: 12;
  box-shadow: 0 1px 4px rgba(24, 26, 23, 0.04);
}
.txn-toolbar__search {
  flex: 1 1 220px;
  min-width: 200px;
  padding: 7px 10px;
  border: var(--rule);
  border-radius: var(--radius-sm);
  font-size: 13px;
  background: var(--paper);
}
.txn-toolbar__btn {
  background: var(--paper);
  border: var(--rule);
  border-radius: var(--radius-sm);
  padding: 7px 12px;
  font-size: 13px;
  cursor: pointer;
  color: var(--ink);
  white-space: nowrap;
  transition: background 0.1s ease, border-color 0.1s ease;
}
.txn-toolbar__btn:hover {
  background: var(--ink-07);
  border-color: var(--ink-30, var(--ink-12));
}
.txn-toolbar__btn--accent {
  background: var(--bronze-pale, #f5ebd6);
  border-color: var(--bronze, #8a7350);
}
.txn-toolbar__btn--accent:hover { background: #ecdfc4; }
.txn-toolbar__btn .badge {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  background: var(--bronze, #8a7350);
  color: white;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
}
.txn-toolbar__select {
  padding: 7px 10px;
  border: var(--rule);
  border-radius: var(--radius-sm);
  font-size: 13px;
  background: var(--paper);
}
.txn-toolbar__ledger {
  min-width: 220px;
  flex: 0 1 280px;
}
.txn-toolbar__reset {
  color: var(--bronze, #8a7350);
  text-decoration: none;
  font-size: 13px;
  padding: 7px 10px;
}
.txn-toolbar__reset:hover { text-decoration: underline; border-bottom: none; }

/* ---- Date-range popover (anchored to the date button). */
.txn-toolbar__date-wrap {
  position: relative;
}
.txn-date-popover {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 30;
  width: 320px;
  background: var(--paper);
  border: var(--rule);
  border-radius: var(--radius);
  padding: 14px;
  box-shadow: 0 8px 24px rgba(24, 26, 23, 0.15);
}
.txn-date-popover__lbl {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-65);
  margin: 0 0 6px;
}
.txn-date-popover .date-chips {
  margin-bottom: 10px;
}
.txn-date-popover__dates {
  display: flex;
  gap: 8px;
}
.txn-date-popover__dates input {
  /* Phase TxnFieldStyle-1 (2026-06-14): the two custom-range date inputs now
     carry .combobox__input (the report-search field look). Keep only the flex
     sizing here — border/padding/font come from .combobox__input so they match
     the Report Builder's date fields. */
  flex: 1;
}

/* ---- Active-filter chip strip (renders when any filter is set). */
.txn-chips-row {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  background: var(--paper);
  border: var(--rule);
  border-left: 4px solid var(--bronze, #8a7350);
  border-radius: var(--radius-sm);
  padding: 8px 12px;
  margin-bottom: 10px;
}
.txn-chips-row__label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-65);
  margin-right: 4px;
}
.txn-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--bronze-pale, #f5ebd6);
  border: 1px solid var(--bronze, #8a7350);
  border-radius: 999px;
  padding: 3px 6px 3px 11px;
  font-size: 12px;
  color: var(--ink);
  text-decoration: none;
  transition: background 0.1s ease;
}
.txn-chip:hover {
  background: #ecdfc4;
  text-decoration: none;
  border-bottom: 1px solid var(--bronze);
}
.txn-chip__x {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.10);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  line-height: 1;
}
.txn-chip:hover .txn-chip__x { background: rgba(0, 0, 0, 0.20); }
.txn-chip__clear {
  margin-left: auto;
  color: var(--bronze, #8a7350);
  font-size: 12px;
  text-decoration: none;
}
.txn-chip__clear:hover { text-decoration: underline; border-bottom: none; }

/* ---- Drawer overlay + panel. */
.txn-drawer-overlay {
  position: fixed;
  inset: 0;
  background: rgba(24, 26, 23, 0.42);
  z-index: 50;
}
.txn-drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(380px, 92vw);
  background: var(--paper);
  border-left: var(--rule);
  box-shadow: -8px 0 28px rgba(24, 26, 23, 0.18);
  z-index: 51;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
}
.txn-drawer__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 18px 10px;
  border-bottom: var(--rule);
  position: sticky;
  top: 0;
  background: var(--paper);
  z-index: 1;
}
.txn-drawer__title {
  margin: 0;
  font-family: var(--serif);
  font-size: 18px;
  line-height: 1.2;
}
.txn-drawer__close {
  background: transparent;
  border: 0;
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  color: var(--ink-65);
  padding: 4px 8px;
}
.txn-drawer__close:hover { color: var(--ink); }
.txn-drawer__body {
  padding: 14px 18px 20px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.txn-drawer__footer {
  padding: 12px 18px;
  border-top: var(--rule);
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  background: var(--paper);
  position: sticky;
  bottom: 0;
}

/* When the drawer is open, override the filter-group/card spacing
   inside it so things fit a narrow vertical column. */
.txn-drawer .filter-group {
  margin: 0;
}
.txn-drawer .filter-group--card {
  padding: 10px 12px;
}
.txn-drawer .filter-group__label {
  font-size: 12px;
  margin-bottom: 4px;
}

/* ---- Dark-mode variants. ──────────────────────────────────────── */
[data-theme="forest"] .txn-toolbar,
[data-theme="ink"]    .txn-toolbar,
[data-theme="forest"] .txn-drawer,
[data-theme="ink"]    .txn-drawer,
[data-theme="forest"] .txn-date-popover,
[data-theme="ink"]    .txn-date-popover {
  background: var(--paper);
  border-color: rgba(192, 161, 115, 0.30);
}
[data-theme="forest"] .txn-chip,
[data-theme="ink"]    .txn-chip {
  background: rgba(192, 161, 115, 0.18);
  border-color: rgba(192, 161, 115, 0.55);
  color: var(--ink);
}
[data-theme="forest"] .txn-chips-row,
[data-theme="ink"]    .txn-chips-row {
  background: var(--paper);
  border-color: rgba(192, 161, 115, 0.30);
  border-left-color: var(--bronze-mid, #c1a173);
}

/* ═══════════════════════════════════════════════════════════════════════
   /transactions — Option D saved-view tabs strip
   ───────────────────────────────────────────────────────────────────────
   Sits ABOVE the Option A toolbar. Each tab is one saved filter
   preset; clicking navigates to /transactions?<saved_qs>. The active
   tab is the one whose canonical qs matches the current URL.
   ═══════════════════════════════════════════════════════════════════ */
.txn-views-tabs {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  flex-wrap: wrap;
  margin-bottom: 4px;
  border-bottom: 1px solid var(--ink-12, #d8d6cf);
  padding: 0 4px;
}
.txn-views-tab-wrap {
  position: relative;
  display: inline-flex;
  align-items: stretch;       /* let the kebab share full tab height */
}
/* When a tab is wrapped (i.e. has a kebab sibling), flatten its
   top-right corner so it merges seamlessly with the kebab to its
   right. Drop the right border too — the kebab owns that edge. */
.txn-views-tab-wrap > .txn-views-tab {
  border-top-right-radius: 0;
  border-right: none;
}
.txn-views-tab {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 7px 14px 8px;
  background: var(--paper);
  border: 1px solid var(--ink-12, #d8d6cf);
  border-bottom: none;
  border-radius: 6px 6px 0 0;
  font-size: 13px;
  color: var(--ink-65, #5a5d56);
  text-decoration: none;
  cursor: pointer;
  font-family: inherit;
  font-weight: 400;
  white-space: nowrap;
  margin-bottom: -1px;       /* overlap the strip's bottom rule */
  position: relative;
  z-index: 1;
  transition: background 0.1s ease, color 0.1s ease;
}
.txn-views-tab:hover {
  background: var(--ink-07, #ece9e0);
  color: var(--ink);
  border-bottom: none;
}
.txn-views-tab--active {
  background: var(--bronze-pale, #f5ebd6);
  border-color: var(--bronze, #8a7350);
  color: var(--ink);
  font-weight: 500;
  z-index: 2;
}
.txn-views-tab--active:hover {
  background: var(--bronze-pale, #f5ebd6);
}
.txn-views-tab__star {
  color: var(--bronze, #8a7350);
  font-size: 12px;
  line-height: 1;
}
.txn-views-tab--add {
  background: transparent;
  border-style: dashed;
  color: var(--bronze, #8a7350);
  font-weight: 500;
}
.txn-views-tab--add:hover {
  background: var(--bronze-pale, #f5ebd6);
  color: var(--ink);
}

/* Per-tab kebab menu (⋮ dot). Always visible (was hover-only — but
   the hover-only treatment was hopelessly undiscoverable + invisible
   on touch devices, so users couldn't find the delete/rename actions
   at all). Keeps a low resting opacity to stay quiet but hints at
   itself; brightens fully on hover/focus. */
.txn-views-tab__kebab {
  /* Sits AFTER the anchor (not absolutely positioned over it) so
     it doesn't squish the tab label and is part of the natural tab
     hit area. Inline-flex pushes it neatly to the right of the
     label text. */
  background: transparent;
  border: 0;
  cursor: pointer;
  color: var(--ink-65, #5a5d56);
  font-size: 15px;
  line-height: 1;
  padding: 6px 6px 7px;
  margin-left: -2px;       /* tuck up against the tab */
  border-top-right-radius: 6px;
  /* Sit on the same baseline as the tab anchor so the bottom edge
     aligns cleanly with the tab strip's bottom rule. */
  align-self: stretch;
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--ink-12, #d8d6cf);
  border-left: none;
  border-bottom: none;
  background: var(--paper);
  margin-bottom: -1px;     /* match the .txn-views-tab overlap trick */
  opacity: 0.55;
  transition: opacity 0.1s ease, background 0.1s ease, color 0.1s ease;
}
.txn-views-tab__kebab:hover,
.txn-views-tab__kebab:focus {
  opacity: 1;
  background: var(--ink-07, #ece9e0);
  color: var(--ink);
  outline: none;
}
/* When the parent tab is the active one, brighten the kebab too so
   the visual grouping reads as "this tab is selected, and these are
   its actions". */
.txn-views-tab-wrap:has(.txn-views-tab--active) .txn-views-tab__kebab {
  background: var(--bronze-pale, #f5ebd6);
  border-color: var(--bronze, #8a7350);
  color: var(--ink);
  opacity: 1;
}
.txn-views-tab__menu {
  position: absolute;
  top: 100%;
  right: 0;
  z-index: 20;
  min-width: 200px;
  background: var(--paper);
  border: 1px solid var(--ink-12, #d8d6cf);
  border-radius: var(--radius-sm, 4px);
  box-shadow: 0 6px 18px rgba(24, 26, 23, 0.14);
  padding: 4px;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.txn-views-tab__menu form { margin: 0; }
.txn-views-tab__menu-item {
  display: block;
  width: 100%;
  text-align: left;
  background: transparent;
  border: 0;
  padding: 7px 12px;
  font-size: 13px;
  cursor: pointer;
  color: var(--ink);
  border-radius: 3px;
  font-family: inherit;
}
.txn-views-tab__menu-item:hover {
  background: var(--ink-07, #ece9e0);
}
.txn-views-tab__menu-item--danger {
  color: var(--danger, #c0392b);
}
.txn-views-tab__menu-item--danger:hover {
  background: rgba(192, 57, 43, 0.10);
}

/* Inline save-as-view form, anchored to the "+ Save current view" tab. */
.txn-views-save-form {
  position: absolute;
  top: 100%;
  right: 0;
  z-index: 20;
  background: var(--paper);
  border: 1px solid var(--bronze, #8a7350);
  border-radius: var(--radius-sm, 4px);
  box-shadow: 0 6px 18px rgba(24, 26, 23, 0.14);
  padding: 10px;
  display: flex;
  gap: 6px;
  min-width: 320px;
}
.txn-views-save-form input[type="text"] {
  flex: 1;
  min-width: 0;
  padding: 6px 8px;
  border: 1px solid var(--ink-12, #d8d6cf);
  border-radius: 3px;
  font-size: 13px;
}

/* Dark-mode variants. */
[data-theme="forest"] .txn-views-tabs,
[data-theme="ink"]    .txn-views-tabs {
  border-bottom-color: rgba(192, 161, 115, 0.25);
}
[data-theme="forest"] .txn-views-tab,
[data-theme="ink"]    .txn-views-tab {
  background: var(--paper);
  border-color: rgba(192, 161, 115, 0.30);
  color: var(--ink-65);
}
[data-theme="forest"] .txn-views-tab--active,
[data-theme="ink"]    .txn-views-tab--active {
  background: rgba(192, 161, 115, 0.18);
  border-color: rgba(192, 161, 115, 0.55);
  color: var(--ink);
}
[data-theme="forest"] .txn-views-tab__menu,
[data-theme="ink"]    .txn-views-tab__menu,
[data-theme="forest"] .txn-views-save-form,
[data-theme="ink"]    .txn-views-save-form {
  background: var(--paper);
  border-color: rgba(192, 161, 115, 0.30);
}

/* ═══════════════════════════════════════════════════════════════════════
   FD form — payout schedule mode picker + pro-rata preview
   ───────────────────────────────────────────────────────────────────────
   Two side-by-side radio cards (anniversary vs calendar) with a live
   schedule preview table that appears when calendar is picked. See
   app/templates/fixed_deposits/_form.html for the markup that drives
   these styles. ═══════════════════════════════════════════════════ */

/* Two-card radio group for picking payout mode. */
.payout-mode-cards {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.payout-mode-card {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px 12px;
  border: var(--rule);
  border-radius: var(--radius);
  background: var(--paper);
  cursor: pointer;
  transition: border-color 0.1s ease, background 0.1s ease, box-shadow 0.1s ease;
}
.payout-mode-card:hover {
  border-color: var(--bronze, #8a7350);
  background: var(--ink-07, #ece9e0);
}
.payout-mode-card--on {
  border-color: var(--bronze, #8a7350);
  background: var(--bronze-pale, #f5ebd6);
  box-shadow: 0 0 0 1px var(--bronze, #8a7350);
}
.payout-mode-card input[type="radio"] {
  position: absolute;
  width: 1px; height: 1px;
  opacity: 0;
  pointer-events: none;
}
.payout-mode-card__title {
  display: flex;
  align-items: baseline;
  gap: 8px;
}

/* Implied-schedule one-liner above the preview table. */
.payout-implied {
  margin-top: 12px;
  padding: 8px 12px;
  background: var(--bronze-pale, #f5ebd6);
  border-left: 3px solid var(--bronze, #8a7350);
  border-radius: 0 var(--radius-sm, 4px) var(--radius-sm, 4px) 0;
  font-size: 13px;
}

/* Pro-rata preview table. */
.payout-preview {
  margin-top: 14px;
  border: var(--rule);
  border-radius: var(--radius);
  overflow: hidden;
}
.payout-preview__title {
  padding: 8px 12px;
  background: var(--ink-07, #ece9e0);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-65);
  font-weight: 500;
}
.payout-preview__table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  background: var(--paper);
}
.payout-preview__table th,
.payout-preview__table td {
  padding: 6px 12px;
  text-align: left;
  border-bottom: 1px solid var(--ink-07, #ece9e0);
}
.payout-preview__table thead { font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-65); }
.payout-preview__table td.num,
.payout-preview__table th.num { text-align: right; font-variant-numeric: tabular-nums; }
.payout-preview__table tfoot td {
  background: var(--ink-07, #ece9e0);
  font-weight: 500;
  border-bottom: none;
}

/* Dark-mode variants. */
[data-theme="forest"] .payout-mode-card,
[data-theme="ink"]    .payout-mode-card {
  background: var(--paper);
  border-color: rgba(192, 161, 115, 0.30);
}
[data-theme="forest"] .payout-mode-card--on,
[data-theme="ink"]    .payout-mode-card--on {
  background: rgba(192, 161, 115, 0.18);
}
[data-theme="forest"] .payout-preview,
[data-theme="ink"]    .payout-preview,
[data-theme="forest"] .payout-preview__table,
[data-theme="ink"]    .payout-preview__table {
  background: var(--paper);
  border-color: rgba(192, 161, 115, 0.25);
}


/* ============================================================================
 * Reports — Option C layout (compact toolbar + visible axes).
 *
 * The /reports page was rebuilt around a /transactions-style toolbar +
 * chip strip pattern, but with one extra panel — the group-by axes —
 * kept visible (not buried in a drawer) because axes are the SHAPE of
 * the report, not a filter. See docs/mockups/reports-redesign-options
 * .html for the design that landed.
 *
 * Visual goals (in order):
 *   1. Chart sits near the top of the viewport — typical first-paint
 *      lands a chart marker ~200 px from the page header, vs. ~700 px
 *      in the pre-refactor layout.
 *   2. Every active filter visible as a removable chip so users see
 *      "what's currently constraining this report".
 *   3. Box 2 (AND-joined OR-group) keeps its visible AND-relationship
 *      cue via an inline expander rather than disappearing into a drawer.
 *   4. Saved reports are one click from any state.
 * ============================================================================ */

/* ── Saved-reports tab strip ─────────────────────────────────────── */
.reports-saved-tabs {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  padding: 8px 0 12px;
  margin-bottom: 12px;
  border-bottom: var(--rule);
}
.reports-saved-tabs__label {
  font-size: 11px;
  color: var(--ink-65);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-right: 6px;
}
/* Single-select "load a saved report" picker — a sensible-width field
   rather than a sprawling chip strip. */
.reports-saved-tabs__pick {
  flex: 1 1 320px;
  max-width: 460px;
  margin-right: auto;            /* keep + Save current / Manage to the right */
}
.reports-saved-tabs__plus {
  padding: 4px 12px;
  font-size: 12px;
  color: var(--bronze);
  border: 1px dashed var(--bronze-mid, #A08868);
  border-radius: 999px;
  background: transparent;
  text-decoration: none;
  font-weight: 500;
}
.reports-saved-tabs__plus:hover {
  background: var(--bronze-pale);
  color: var(--bronze);
  text-decoration: none;
}
.reports-saved-tabs__manage {
  position: relative;            /* sits next to "+ Save current", not shoved
                                   to the far edge — the picker's margin-right
                                   already pushes this action group right. */
}
.reports-saved-tabs__manage > summary {
  list-style: none;
  cursor: pointer;
}
.reports-saved-tabs__manage > summary::-webkit-details-marker { display: none; }
/* Match the "+ Save current" pill (same height/shape) so the two right-side
   actions read as a paired, aligned group rather than mismatched controls. */
.reports-saved-tabs__manage-btn {
  padding: 4px 12px;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-65);
  border: 1px solid var(--ink-25);
  border-radius: 999px;
  background: transparent;
}
.reports-saved-tabs__manage-btn:hover {
  background: var(--ink-07);
  color: var(--ink);
}
.reports-saved-tabs__manage[open] > summary {
  background: var(--ink-07);
  color: var(--ink);
}
.reports-saved-tabs__manage-list {
  list-style: none;
  margin: 8px 0 0;
  padding: 8px;
  background: var(--paper);
  border: var(--rule);
  border-radius: var(--radius);
  position: absolute;
  right: 0;
  top: 100%;
  min-width: 240px;
  max-height: 280px;
  overflow-y: auto;
  z-index: 5;
  box-shadow: 0 4px 12px rgba(24, 26, 23, 0.08);
}
.reports-saved-tabs__manage-list .inline-form {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 4px 0;
}
.reports-saved-tabs__manage-name {
  font-size: 12.5px;
  color: var(--ink);
  flex: 1;
}

/* ── Compact toolbar (search + dropdowns + direction) ────────────── */
.reports-toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 10px 14px;
  background: var(--paper);
  border: var(--rule);
  border-radius: var(--radius);
  margin-bottom: 8px;
}
.reports-toolbar__search {
  /* Phase ReportToolbar-2 (2026-06-13): Box 1 now lives on its own full-width
     row below the controls toolbar, mirroring Box 2's full-width treatment.
     It's no longer a flex child, so it stretches to the form width. */
  display: block;
  width: 100%;
  margin-top: 10px;
  /* Match the combobox/multiselect field look so the toolbar reads as one
     consistent set of inputs (the bare .input class has no styling). */
  padding: 10px 12px;
  border: 1px solid var(--ink-25);
  border-radius: var(--radius);
  background: rgba(0, 0, 0, 0.04);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.4;
  box-sizing: border-box;
  transition: border-color 0.1s ease, background 0.1s ease, box-shadow 0.1s ease;
}
.reports-toolbar__search:focus {
  outline: none;
  border-color: var(--forest);
  background: var(--card);
  box-shadow: 0 0 0 3px var(--forest-pale);
}
.reports-toolbar__search::placeholder { color: var(--ink-45); }
.reports-toolbar__acct {
  flex: 1 1 240px;
  min-width: 220px;
  max-width: 360px;
}
.reports-toolbar select.input {
  min-width: 140px;
  /* Match the search box + combobox field look (the bare .input class has
     no styling) so the whole toolbar reads as one consistent set. */
  padding: 10px 12px;
  border: 1px solid var(--ink-25);
  border-radius: var(--radius);
  background: rgba(0, 0, 0, 0.04);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.4;
  box-sizing: border-box;
  cursor: pointer;
  transition: border-color 0.1s ease, background 0.1s ease, box-shadow 0.1s ease;
}
.reports-toolbar select.input:focus {
  outline: none;
  border-color: var(--forest);
  background: var(--card);
  box-shadow: 0 0 0 3px var(--forest-pale);
}

/* Dropdown buttons inside the toolbar use native <details> for
 * open/close. The data-active attribute lights the chip up when the
 * dropdown owns at least one active filter (e.g. 2 holders selected). */
.reports-toolbar__dd {
  position: relative;
}
.reports-toolbar__dd-summary {
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  font-size: 12.5px;
  color: var(--ink-80);
  background: var(--paper);
  border: var(--rule);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-weight: 500;
  transition: background 0.12s, border-color 0.12s;
}
.reports-toolbar__dd-summary::-webkit-details-marker { display: none; }
.reports-toolbar__dd-summary::after {
  content: "▾";
  font-size: 10px;
  margin-left: 4px;
  color: var(--ink-45);
}
.reports-toolbar__dd-summary:hover {
  background: var(--ink-07);
}
.reports-toolbar__dd[data-active] > .reports-toolbar__dd-summary {
  background: var(--forest-pale);
  border-color: var(--forest-pale);
  color: var(--forest-deep);
}
.reports-toolbar__dd-count {
  color: var(--forest);
  font-weight: 600;
}
.reports-toolbar__dd-panel {
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: 4px;
  min-width: 260px;
  max-width: 420px;
  padding: 12px;
  background: var(--paper);
  border: var(--rule);
  border-radius: var(--radius);
  box-shadow: 0 6px 16px rgba(24, 26, 23, 0.10);
  z-index: 8;
}
.reports-toolbar__dd-panel .pills {
  max-height: 280px;
  overflow-y: auto;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

/* ── Box 2 inline expander (replaces the giant AND-joined card) ──── */
.reports-box2 {
  margin-bottom: 8px;
  border: 1px dashed var(--bronze-mid, #A08868);
  border-radius: var(--radius);
  background: rgba(239, 230, 210, 0.35);
}
.reports-box2[open] {
  background: var(--paper);
  border-style: solid;
  border-color: var(--bronze-mid);
}
.reports-box2__summary {
  list-style: none;
  cursor: pointer;
  padding: 8px 14px;
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--bronze);
  font-size: 13px;
  border-radius: var(--radius);
}
.reports-box2__summary::-webkit-details-marker { display: none; }
.reports-box2__summary:hover {
  background: rgba(239, 230, 210, 0.5);
}
.reports-box2__arrow {
  transition: transform 0.15s ease;
  font-size: 10px;
  color: var(--bronze);
}
.reports-box2[open] > .reports-box2__summary > .reports-box2__arrow {
  transform: rotate(90deg);
}
.reports-box2__count {
  margin-left: auto;
  font-size: 11px;
  color: var(--forest);
  background: var(--forest-pale);
  padding: 2px 8px;
  border-radius: 999px;
  font-weight: 600;
}
.reports-box2__panel {
  padding: 10px 14px 14px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  border-top: 1px solid var(--ink-12);
}
.reports-box2__input {
  flex: 1 1 240px;
  min-width: 220px;
  /* Match the Box-1 search field / comboboxes (the bare .input has no style). */
  padding: 10px 12px;
  border: 1px solid var(--ink-25);
  border-radius: var(--radius);
  background: rgba(0, 0, 0, 0.04);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.4;
  box-sizing: border-box;
  transition: border-color 0.1s ease, background 0.1s ease, box-shadow 0.1s ease;
}
.reports-box2__input:focus {
  outline: none;
  border-color: var(--forest);
  background: var(--card);
  box-shadow: 0 0 0 3px var(--forest-pale);
}
.reports-box2__input::placeholder { color: var(--ink-45); }

/* ── Active filter chip strip ───────────────────────────────────── */
.reports-active-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  padding: 8px 0 12px;
}
.reports-active-chips .label-tiny {
  font-size: 11px;
  color: var(--ink-65);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-right: 4px;
}
.reports-active-chips__clear {
  margin-left: 6px;
}

/* The chip + chip--active styles already exist for the rest of the
 * system; we just need the anchors to feel right and the cross icon
 * to read clearly. */
.reports-active-chips a.chip {
  text-decoration: none;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
}
.reports-active-chips a.chip:hover {
  background: var(--forest);
  color: var(--on-dark);
  border-color: var(--forest);
}
.reports-active-chips a.chip:hover .chip__x {
  color: var(--on-dark);
}

/* ── Group-by axes + view-toggle panel ───────────────────────────── */
.reports-axes-panel {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 10px 14px;
  background: var(--paper);
  border: var(--rule);
  border-radius: var(--radius);
  margin-bottom: 18px;
}
.reports-axes-panel .label-tiny {
  font-size: 11px;
  color: var(--ink-65);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.reports-axes-panel__arrow {
  color: var(--ink-45);
  font-size: 14px;
  font-weight: 500;
}
.reports-axes-panel .btn--primary {
  margin-left: 4px;
}

/* View-toggle button group — buttons share borders so they read as
 * one segmented control. is-active flips to a forest fill. */
.reports-view-toggle {
  margin-left: auto;
  display: inline-flex;
  gap: 0;
}
.reports-view-toggle .btn {
  border-radius: 0;
  border-right-width: 0;
}
.reports-view-toggle .btn:first-child { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
.reports-view-toggle .btn:last-child  { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; border-right-width: 1px; }
.reports-view-toggle .btn.is-active {
  background: var(--forest);
  color: var(--on-dark);
  border-color: var(--forest);
}

/* Responsive — collapse the toolbar to stack on phones; the dropdowns
 * keep popping over so they don't shove the chart further down. */
@media (max-width: 700px) {
  .reports-toolbar {
    flex-direction: column;
    align-items: stretch;
  }
  .reports-toolbar__search,
  .reports-toolbar select.input {
    min-width: 100%;
  }
  .reports-axes-panel {
    align-items: stretch;
  }
  .reports-view-toggle {
    margin-left: 0;
  }
}


/* ============================================================================
 * Dashboard (Phase Dash1, 2026-05-23)
 *
 * Family-office command center landing page. Layout: member tabs → KPI
 * strip → two-column grid (timeline + breakdown) → activity feed.
 *
 * Class-name convention: ``dashboard-*`` for the top-level wrapper and
 * its direct sections; ``dashboard-panel`` / ``dashboard-reminder`` /
 * ``dashboard-kpi`` / ``dashboard-tab`` for the repeated building blocks.
 * Mirrors docs/mockups/dashboard-concept.html so the UI users approved
 * looks the same in production.
 * ========================================================================== */

.dashboard {
  /* Container for the whole dashboard — slight top spacing because the
   * page header doesn't use the standard page-header__h1 chrome.
   *
   * The dashboard is wider than the standard 1160px reading column
   * because the 2-column grid (timeline + breakdown) needs room to
   * breathe. Override the global ``.main > * { max-width: var(--col-max) }``
   * cap so it uses the full available column. We still keep some breathing
   * room via .main's outer padding.
   *
   * 2026-05-24: padding-top bumped 4 → 22 so the H1 isn't flush with the
   * card's top border. Paired with the margin trim at line ~1220 (32→14)
   * the card now sits higher AND breathes from the top edge. The two
   * changes are deliberate counterweights — one moves the card up, the
   * other pushes the content down inside it. */
  padding-top: 22px;
  max-width: none !important;
}

/* Page head: title + sub + reminder pill */
.dashboard__head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  margin-bottom: 18px;
  padding-bottom: 14px;
  border-bottom: var(--rule);
}
.dashboard__title {
  font-family: var(--font-serif, Georgia, serif);
  font-size: 24px;
  font-weight: 700;
  color: var(--forest-deep);
  margin: 0 0 4px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.dashboard__title-icon {
  /* Same sizing recipe as .page-header__icon — keep the SVG bounded so
   * it reads as a "module badge" next to the H1 instead of flooding the
   * column. The inner <svg> has no intrinsic size on its own; without
   * this it grows to fill the parent. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--bronze);
  flex: 0 0 auto;
  width: 1.2em;
  height: 1.2em;
  line-height: 1;
}
.dashboard__title-icon svg {
  width: 100%;
  height: 100%;
  display: block;
}
.dashboard__sub {
  color: var(--ink-65);
  font-size: 13px;
  margin: 0;
}
.dashboard__reminder-pill {
  background: var(--bronze-pale);
  color: var(--bronze);
  padding: 6px 12px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 500;
  white-space: nowrap;
}

/* Member tabs (family / individual holder) */
.dashboard__tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 20px;
  padding-bottom: 12px;
  border-bottom: 1px dashed var(--ink-12);
}
.dashboard-tab {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-radius: 6px;
  color: var(--ink);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  border-bottom: 1px solid var(--ink-12);
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.dashboard-tab:hover {
  background: var(--ink-07);
  border-color: var(--ink-25);
  border-bottom-color: var(--ink-25);
  color: var(--ink);
}
.dashboard-tab.is-active {
  background: var(--forest);
  border-color: var(--forest);
  color: var(--on-dark);
  border-bottom-color: var(--forest);
}
.dashboard-tab__icon { font-size: 15px; }
.dashboard-tab__name { font-weight: 500; }
.dashboard-tab__code {
  font-size: 10.5px;
  background: var(--ink-07);
  color: var(--ink-65);
  padding: 2px 7px;
  border-radius: 999px;
  font-weight: 500;
}
.dashboard-tab.is-active .dashboard-tab__code {
  background: rgba(255, 255, 255, 0.18);
  color: var(--on-dark);
}

/* KPI hero strip — 4 tiles across (collapse to 2x2 on phones) */
.dashboard__kpis {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
  margin-bottom: 22px;
}

/* ── Net Worth widget (Phase NetWorth, 2026-05-25) ──
   Sits between the KPI strip and the main grid. Collapsed by default
   showing the headline + two chips; click to expand the per-module
   breakdown table. Uses <details>/<summary> so no JS needed. */
.dashboard-networth {
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-radius: 10px;
  padding: 14px 18px;
  margin-bottom: 22px;
}
.dashboard-networth__summary {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 14px 24px;
  cursor: pointer;
  list-style: none;
  /* Hide the default disclosure triangle; we render our own ▾ hint. */
}
.dashboard-networth__summary::-webkit-details-marker { display: none; }
.dashboard-networth__headline {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.dashboard-networth__label {
  font-size: 11.5px;
  color: var(--ink-65);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 600;
}
.dashboard-networth__value {
  font-family: var(--font-serif, Georgia, serif);
  font-size: 28px;
  font-weight: 700;
  color: var(--forest-deep);
  line-height: 1.05;
}
.dashboard-networth__value.is-negative {
  color: var(--danger, #c0392b);
}
.dashboard-networth__split {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 12px;
  align-items: center;
  margin-left: auto;
  font-size: 12.5px;
}
.dashboard-networth__chip {
  padding: 4px 12px;
  border-radius: 999px;
  border: 1px solid var(--ink-12);
  background: var(--ink-03);
  color: var(--ink-65);
  white-space: nowrap;
}
.dashboard-networth__chip strong {
  color: var(--ink);
  margin-left: 4px;
  font-variant-numeric: tabular-nums;
}
.dashboard-networth__chip--assets {
  background: rgba(45, 134, 89, 0.06);
  border-color: rgba(45, 134, 89, 0.20);
  color: var(--success, #2d8659);
}
.dashboard-networth__chip--liabilities {
  background: rgba(192, 57, 43, 0.06);
  border-color: rgba(192, 57, 43, 0.20);
  color: var(--danger, #c0392b);
}
.dashboard-networth__expand-hint {
  font-size: 11px;
  color: var(--ink-40);
  font-style: italic;
}
.dashboard-networth[open] .dashboard-networth__expand-hint { display: none; }

.dashboard-networth__body {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--ink-07);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px 32px;
}
@media (max-width: 720px) {
  .dashboard-networth__body { grid-template-columns: 1fr; }
}
.dashboard-networth__col-title {
  font-size: 11.5px;
  color: var(--ink-65);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 600;
  margin: 0 0 8px;
}
.dashboard-networth__rows {
  list-style: none;
  padding: 0;
  margin: 0;
}
.dashboard-networth__row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  padding: 6px 0;
  border-bottom: 1px solid var(--ink-03);
  font-size: 13px;
}
.dashboard-networth__row:last-child { border-bottom: none; }
.dashboard-networth__row--total {
  border-top: 1px solid var(--ink-12);
  margin-top: 4px;
  padding-top: 8px;
}
.dashboard-networth__row-label { color: var(--ink-80); }
.dashboard-networth__row-value {
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.dashboard-networth__row-note {
  color: var(--ink-40);
  cursor: help;
  margin-left: 4px;
  font-size: 11px;
}
.dashboard-networth__note {
  margin: 14px 0 0;
  padding-top: 10px;
  border-top: 1px solid var(--ink-03);
  font-size: 11px;
  color: var(--ink-65);
  font-style: italic;
}
.dashboard-kpi {
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-radius: 8px;
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.dashboard-kpi__label {
  font-size: 11.5px;
  color: var(--ink-65);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 500;
}
.dashboard-kpi__value {
  font-family: var(--font-serif, Georgia, serif);
  font-size: 22px;
  font-weight: 700;
  color: var(--forest-deep);
  line-height: 1.1;
}
.dashboard-kpi__delta {
  font-size: 11.5px;
  color: var(--ink-65);
  margin-top: 2px;
}
.dashboard-kpi--up   .dashboard-kpi__delta { color: var(--success, #2f7a4f); }
.dashboard-kpi--down .dashboard-kpi__delta { color: var(--clay, #a8493a); }

/* Main grid: timeline (left) + breakdown (right) */
.dashboard__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
  gap: 20px;
  margin-bottom: 22px;
}

/* Generic panel chrome */
.dashboard-panel {
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-radius: 8px;
  padding: 16px 18px;
}
.dashboard-panel--full { /* full-width below the grid */ }
.dashboard-panel__head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--ink-12);
}
.dashboard-panel__title {
  font-family: var(--font-serif, Georgia, serif);
  font-size: 16px;
  font-weight: 600;
  color: var(--forest-deep);
  margin: 0;
}
.dashboard-panel__aux {
  font-size: 12px;
  color: var(--ink-65);
}

/* Filter chips above the timeline */
.dashboard-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-bottom: 12px;
  padding-bottom: 10px;
  border-bottom: 1px dashed var(--ink-12);
}
.dashboard-chip {
  padding: 3px 10px;
  border: 1px solid var(--ink-12);
  background: var(--paper);
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 500;
  color: var(--ink-65);
  cursor: pointer;
  transition: background 0.1s, color 0.1s;
  font-family: inherit;
  border-bottom: 1px solid var(--ink-12);
}
.dashboard-chip:hover {
  background: var(--ink-07);
  color: var(--ink);
}
.dashboard-chip.is-active {
  background: var(--forest);
  color: var(--on-dark);
  border-color: var(--forest);
}
.dashboard-chips__spacer { flex: 1; }

/* Timeline groups (Today / This week / This month / Later) */
.dashboard-timeline-group { margin-bottom: 16px; }
.dashboard-timeline-group__label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-65);
  margin: 12px 0 8px;
  padding-left: 4px;
}
.dashboard-timeline-group__label.today { color: var(--clay, #a8493a); }
.dashboard-timeline-group__label.week  { color: var(--bronze); }
.dashboard-timeline-group__label.month { color: var(--ink-65); }
.dashboard-timeline-group__label.later { color: var(--ink-45); }

/* Phase Dashboard-Months-Strict (2026-05-26): new label classes for
   the calendar-month-strict chip nav. Overdue gets the same red as
   .today's clay (urgent-attention vocabulary). this_month stays neutral
   (the default view); near/far month muted to signal "later". */
.dashboard-timeline-group__label.overdue    { color: var(--danger, #c0392b); }
.dashboard-timeline-group__label.near-month { color: var(--ink-65); }
.dashboard-timeline-group__label.far-month  { color: var(--ink-45); }

/* Single reminder row */
.dashboard-reminder {
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr) auto auto auto;
  align-items: center;
  gap: 12px;
  padding: 10px 4px;
  border-bottom: 1px solid var(--ink-12);
  transition: background 0.12s;
}
.dashboard-reminder:hover { background: var(--row-alt, var(--ink-07)); border-radius: 4px; }
.dashboard-reminder:last-child { border-bottom: 0; }

.dashboard-reminder__icon {
  font-size: 18px;
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bronze-pale);
  border-radius: 6px;
}
.dashboard-reminder__icon--fd  { background: #E5EFE3; }
.dashboard-reminder__icon--li  { background: #F2DAD3; }
.dashboard-reminder__icon--cc  { background: #F6EBD0; }
.dashboard-reminder__icon--re  { background: var(--bronze-pale); }
.dashboard-reminder__icon--sub { background: #E1DCCF; }
.dashboard-reminder__icon--ma  { background: #D6DCD2; }
.dashboard-reminder__icon--dw  { background: #E8E0D0; }

.dashboard-reminder__main { min-width: 0; }
.dashboard-reminder__title {
  font-size: 13.5px;
  font-weight: 500;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dashboard-reminder__meta {
  font-size: 11.5px;
  color: var(--ink-65);
  margin-top: 1px;
}

.dashboard-reminder__amount {
  font-family: var(--font-serif, Georgia, serif);
  font-weight: 600;
  font-size: 14px;
  color: var(--forest-deep);
  white-space: nowrap;
}
.dashboard-reminder__amount--out { color: var(--clay, #a8493a); }
.dashboard-reminder__amount--in  { color: var(--success, #2f7a4f); }

.dashboard-reminder__holder {
  background: var(--ink-07);
  color: var(--ink-65);
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 500;
  white-space: nowrap;
}

.dashboard-reminder__action {
  padding: 4px 10px;
  background: var(--forest);
  color: var(--on-dark);
  border: 0;
  border-radius: 4px;
  font-size: 11.5px;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
  min-width: 70px;
  text-align: center;
  border-bottom: 0;
  transition: background 0.12s;
}
.dashboard-reminder__action:hover {
  background: var(--forest-deep);
  color: var(--on-dark);
}

/* Empty state in panel */
.dashboard-empty {
  padding: 32px 16px;
  text-align: center;
  color: var(--ink-65);
  font-size: 13px;
  font-style: italic;
}

/* Asset breakdown rows (collapsible via details) */
.dashboard-breakdown-row {
  border-bottom: 1px solid var(--ink-12);
}
.dashboard-breakdown-row:last-of-type { border-bottom: 0; }
.dashboard-breakdown-row__summary {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  padding: 9px 4px;
  cursor: pointer;
  list-style: none;
  transition: background 0.1s;
}
.dashboard-breakdown-row__summary::-webkit-details-marker { display: none; }
.dashboard-breakdown-row__summary:hover { background: var(--row-alt, var(--ink-07)); border-radius: 4px; }
.dashboard-breakdown-row__icon { font-size: 16px; }
.dashboard-breakdown-row__name {
  font-size: 13px;
  font-weight: 500;
  color: var(--ink);
}
.dashboard-breakdown-row__count {
  font-size: 11.5px;
  color: var(--ink-65);
  font-weight: 400;
}
.dashboard-breakdown-row__amount {
  font-family: var(--font-serif, Georgia, serif);
  font-weight: 600;
  font-size: 14.5px;
  color: var(--forest-deep);
  text-align: right;
  white-space: nowrap;
}
.dashboard-breakdown-row__expand {
  padding: 10px 14px 8px 38px;
  background: var(--ink-07);
  border-radius: 6px;
  margin: 4px 0;
}
.dashboard-breakdown-row__expand-item {
  display: flex;
  justify-content: space-between;
  padding: 3px 0;
  font-size: 12px;
  color: var(--ink-80);
}
.dashboard-breakdown-row__expand-item .amt {
  font-family: var(--font-serif, Georgia, serif);
  font-weight: 500;
  color: var(--forest-deep);
}
.dashboard-breakdown-row__seemore {
  display: inline-block;
  font-size: 11px;
  color: var(--bronze);
  font-weight: 500;
  margin-top: 4px;
  cursor: pointer;
  border-bottom: 0;
}
.dashboard-breakdown-row__seemore:hover {
  color: var(--bronze-mid);
  border-bottom: 0;
}

/* Recent-activity feed */
.dashboard-activity-row {
  display: grid;
  grid-template-columns: 80px minmax(0, 1fr) auto;
  gap: 14px;
  align-items: center;
  padding: 7px 4px;
  border-bottom: 1px solid var(--ink-12);
  font-size: 12.5px;
}
.dashboard-activity-row:last-child { border-bottom: 0; }
.dashboard-activity-row__date {
  color: var(--ink-65);
  font-size: 11px;
}
.dashboard-activity-row__particulars { color: var(--ink-80); }
.dashboard-activity-row__holder {
  font-size: 10.5px;
  color: var(--bronze);
  background: var(--bronze-pale);
  padding: 1px 6px;
  border-radius: 999px;
  margin-left: 4px;
}
.dashboard-activity-row__amount {
  font-family: var(--font-serif, Georgia, serif);
  font-weight: 500;
  color: var(--forest-deep);
  white-space: nowrap;
}
.dashboard-activity-row__amount--in  { color: var(--success, #2f7a4f); }
.dashboard-activity-row__amount--out { color: var(--clay, #a8493a); }

/* Responsive: phone collapse */
@media (max-width: 900px) {
  .dashboard__kpis {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .dashboard__grid {
    grid-template-columns: 1fr;
  }
  .dashboard-reminder {
    grid-template-columns: 30px minmax(0, 1fr) auto;
    gap: 10px;
  }
  /* Hide holder pill + drop action button to its own row on phones */
  .dashboard-reminder__holder,
  .dashboard-reminder__action {
    grid-column: 2 / -1;
    justify-self: start;
  }
}
@media (max-width: 600px) {
  .dashboard__head {
    flex-direction: column;
    align-items: flex-start;
  }
  .dashboard-tab__code { display: none; }
}


/* ============================================================================
 * FD Interest Calendar (Phase Cal1, 2026-05-23)
 *
 * Class namespace: ``fd-cal-*``. Three view modes (table, pivot, calendar)
 * share the same toolbar + KPI strip + chip styling.
 * ========================================================================== */

/* KPI strip — same shape as the reports tab strip */
.fd-cal-kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 14px;
  margin: 18px 0 22px;
}

/* Toolbar — compact, Option C style */
.fd-cal-toolbar {
  background: var(--paper);
  border: var(--rule);
  border-radius: 8px;
  padding: 14px 16px;
  margin-bottom: 12px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.fd-cal-toolbar__row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: flex-end;
}
.fd-cal-toolbar__field {
  display: flex;
  flex-direction: column;
  gap: 3px;
  font-size: 11.5px;
  color: var(--ink-65);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 500;
}
.fd-cal-toolbar__field .input {
  font-size: 13px;
  padding: 5px 8px;
  min-width: 140px;
}
.fd-cal-toolbar__view-toggle {
  margin-left: auto;
  display: inline-flex;
  gap: 0;
}
.fd-cal-toolbar__view-toggle .btn {
  border-radius: 0;
  border-right-width: 0;
  font-size: 12px;
  padding: 6px 12px;
}
.fd-cal-toolbar__view-toggle .btn:first-child { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
.fd-cal-toolbar__view-toggle .btn:last-child  { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; border-right-width: 1px; }

.fd-cal-toolbar__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  padding-top: 8px;
  border-top: 1px dashed var(--ink-12);
}
.fd-cal-toolbar__chips-label {
  font-size: 11.5px;
  color: var(--ink-65);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 500;
  margin-right: 4px;
}
.fd-cal-toolbar__hint {
  font-size: 11.5px;
  margin-left: 6px;
}

/* The filter-chip class is reused from reports / dashboard. Add
 * the status-chip variant tints used in both the toolbar (where the
 * chip is a filter) and the table (where it's a status badge). */
.status-chip {
  display: inline-block;
  font-size: 11px;
  font-weight: 500;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--ink-07);
  color: var(--ink-65);
  border: 1px solid var(--ink-12);
  text-transform: none;
  letter-spacing: 0;
}
.status-chip--pending      { background: #fef3e0; color: #8a5a00; border-color: #efd4a8; }
.status-chip--received     { background: #e5efe3; color: #2f6c3b; border-color: #c3d8c0; }
.status-chip--partial      { background: #fff4d0; color: #8a6500; border-color: #ead6a0; }
.status-chip--not_received { background: #f6dad3; color: #a4452f; border-color: #dfb8ad; }
.status-chip--delayed      { background: #f3e7d3; color: #8a6f44; border-color: #d9c7a8; }
.status-chip--cancelled    { background: #e7e3da; color: #6e6457; border-color: #d0c8b8; }

/* Group block — one per primary group (month / holder / etc.) */
.fd-cal-group {
  margin-bottom: 22px;
  border: var(--rule);
  border-radius: 8px;
  overflow: hidden;
  background: var(--paper);
}
.fd-cal-group__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 10px 16px;
  background: var(--ink-07);
  border-bottom: var(--rule);
}
.fd-cal-group__label {
  margin: 0;
  font-family: var(--font-serif, Georgia, serif);
  font-size: 15px;
  color: var(--forest-deep);
}
.fd-cal-group__totals {
  font-size: 12px;
  color: var(--ink-65);
}

/* Table */
.fd-cal-table {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
  font-size: 13px;
}
.fd-cal-table th,
.fd-cal-table td {
  padding: 7px 10px;
  border-bottom: 1px solid var(--ink-07);
  text-align: left;
  vertical-align: top;
}
.fd-cal-table th {
  background: var(--paper);
  font-weight: 600;
  font-size: 11.5px;
  color: var(--ink-65);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.fd-cal-table .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.fd-cal-table__row:hover { background: var(--row-alt, var(--ink-07)); }
.fd-cal-table__row--realized td { color: var(--ink); }
.fd-cal-table__row--future td   { color: var(--ink-80); }

/* Subgroup header row inside the table */
.fd-cal-table__subhead td {
  background: var(--bronze-pale);
  font-size: 12px;
  padding: 6px 12px;
  color: var(--forest-deep);
}

/* Realized → Projected divider */
.fd-cal-table__divider td {
  text-align: center;
  background: var(--forest-pale);
  color: var(--forest-deep);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  padding: 6px 0;
  font-family: ui-monospace, Menlo, monospace;
}

/* Pivot view */
.fd-cal-pivot-wrap {
  overflow-x: auto;
  border: var(--rule);
  border-radius: 8px;
  background: var(--paper);
}
.fd-cal-pivot {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.fd-cal-pivot th,
.fd-cal-pivot td {
  padding: 7px 12px;
  border-bottom: 1px solid var(--ink-07);
  border-right: 1px solid var(--ink-07);
}
.fd-cal-pivot th {
  background: var(--ink-07);
  font-weight: 600;
  font-size: 12px;
  color: var(--forest-deep);
  text-align: left;
}
.fd-cal-pivot tbody th {
  background: var(--paper);
  border-right: 2px solid var(--ink-12);
}
.fd-cal-pivot__num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.fd-cal-pivot__num.is-zero { color: var(--ink-25); }
.fd-cal-pivot__total {
  text-align: right;
  background: var(--ink-07);
  font-weight: 600;
  color: var(--forest-deep);
}
.fd-cal-pivot__grand {
  text-align: right;
  background: var(--forest);
  color: var(--on-dark);
  font-weight: 700;
}
.fd-cal-pivot tbody tr:hover {
  background: var(--row-alt, var(--ink-07));
}

/* Calendar view — 12-cell grid (3 rows x 4 cols on desktop) */
.fd-cal-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
  margin-bottom: 14px;
}
.fd-cal-grid__cell {
  background: var(--paper);
  border: var(--rule);
  border-left: 3px solid var(--forest);
  border-radius: 6px;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-height: 90px;
}
.fd-cal-grid__cell--empty {
  background: var(--ink-07);
  border-left-color: var(--ink-25);
  color: var(--ink-45);
}
.fd-cal-grid__month {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-65);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.fd-cal-grid__amount {
  font-family: var(--font-serif, Georgia, serif);
  font-size: 18px;
  font-weight: 700;
  color: var(--forest-deep);
}
.fd-cal-grid__cell--empty .fd-cal-grid__amount { color: var(--ink-45); }
.fd-cal-grid__count {
  font-size: 11.5px;
  color: var(--ink-65);
}
.fd-cal-grid__total {
  margin-top: 8px;
  padding: 10px 14px;
  background: var(--forest);
  color: var(--on-dark);
  border-radius: 6px;
  font-size: 14px;
}

/* Responsive collapse */
@media (max-width: 900px) {
  .fd-cal-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 700px) {
  .fd-cal-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .fd-cal-toolbar__view-toggle { margin-left: 0; }
}
@media (max-width: 600px) {
  .fd-cal-grid { grid-template-columns: 1fr; }
  .fd-cal-toolbar__field .input { min-width: 100px; }
}

/* ============================================================================
 * FD interest-receive form — Recv-v2 (Phase Recv-v2, 2026-05-23).
 *
 * Three-field ratio-derive form: Net + TDS = Gross. Used by both
 * schedule_tab.html (tenant-wide schedule view) and detail.html (per-FD
 * detail page). Originally lived inline in schedule_tab.html; promoted
 * to app.css when detail.html needed the same widget.
 * ========================================================================== */
.receive-grid {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 10px;
  padding: 12px 14px;
  background: var(--ink-07, #f3f0e8);
  border-radius: 6px;
  margin-bottom: 6px;
}
.receive-grid__field {
  flex: 1 1 140px;
  min-width: 140px;
  margin: 0;
  display: flex;
  flex-direction: column;
}
.receive-grid__field input {
  font-family: ui-monospace, Menlo, monospace;
  text-align: right;
  font-size: 14px;
}
.receive-grid__op {
  font-family: var(--font-serif, Georgia, serif);
  font-size: 22px;
  font-weight: 700;
  color: var(--forest-deep, #1a2e1f);
  padding-bottom: 10px;
  align-self: flex-end;
}
.receive-grid__reset {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: 8px 2px 0;
  gap: 12px;
  flex-wrap: wrap;
}
@media (max-width: 700px) {
  .receive-grid__op { display: none; }
  .receive-grid__field { flex: 1 1 100%; }
}

/* ============================================================================
 * Modal — shared overlay for masters pages (banks, families, lookups,
 * institutions, categories, …) so the "+ Add X" entry point lives at
 * the top of the page instead of scrolling past every existing row.
 *
 * Pattern: ``_partials/_modal.html`` macro + Alpine dispatch-event
 * coupling. See the macro's header comment for usage docs.
 *
 * Phase Masters-modal-1 (2026-05-23).
 * ========================================================================== */

/* Backdrop — covers the viewport, semi-opaque so the page underneath
 * stays partially visible (helps users orient themselves). Click on
 * backdrop closes the modal (handled in the macro via @click.self). */
.modal-wrap {
  position: fixed;
  inset: 0;
  background: rgba(15, 29, 19, 0.55);   /* var(--forest-deep) with alpha */
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 7vh 16px 16px;
  z-index: 1000;
  overflow-y: auto;
}

/* Panel — the white card that actually holds the form. Different
 * widths via .modal-panel--sm/md/lg. ``max-width: 100%`` so it
 * never overflows narrow viewports; ``max-height: 86vh`` + scrollable
 * body so very long forms don't push the close button off-screen. */
.modal-panel {
  background: var(--paper);
  border-radius: 10px;
  box-shadow: 0 14px 50px rgba(0, 0, 0, 0.25);
  width: 640px;
  max-width: 100%;
  max-height: 86vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  animation: modal-panel-in 0.16s ease-out;
}
.modal-panel--sm { width: 440px; }
.modal-panel--md { width: 640px; }
.modal-panel--lg { width: 880px; }

@keyframes modal-panel-in {
  from { opacity: 0; transform: translateY(-10px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Head — title + close button. Stays pinned at the top while body
 * scrolls, so the user always has an obvious dismiss target. */
.modal-panel__head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 14px 20px;
  border-bottom: var(--rule);
  background: var(--paper);
  flex: 0 0 auto;
}
.modal-panel__title {
  margin: 0;
  font-family: var(--font-serif, Georgia, serif);
  font-size: 18px;
  font-weight: 600;
  color: var(--forest-deep);
}
.modal-panel__close {
  background: transparent;
  border: 0;
  font-size: 24px;
  line-height: 1;
  color: var(--ink-65);
  cursor: pointer;
  padding: 0 8px;
  border-radius: 4px;
  transition: background 0.1s, color 0.1s;
}
.modal-panel__close:hover {
  background: var(--ink-07);
  color: var(--ink);
}

/* Body — scrollable when content exceeds max-height. Padding matches
 * what the existing .form macros expect, so form fields render at
 * their natural spacing without overrides. */
.modal-panel__body {
  padding: 18px 20px 20px;
  overflow-y: auto;
  flex: 1 1 auto;
}
/* Make the form's submit button (typically inside .modal-panel__body)
 * full-width-friendly on phone but normal on desktop. The form macros
 * already handle this; this is just a polish nudge. */
.modal-panel__body .form {
  margin: 0;
}

/* Header-row action — the [+ Add X] button living at the top-right
 * of a masters page. Used in tandem with .page-header__h1 so the
 * button sits beside the title. */
.page-header-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}
.page-header-actions__title {
  flex: 1 1 auto;
  min-width: 0;
}

@media (max-width: 600px) {
  .modal-wrap { padding: 4vh 10px 10px; align-items: stretch; }
  .modal-panel { max-height: 92vh; }
  .modal-panel__head { padding: 12px 14px; }
  .modal-panel__body { padding: 14px; }
}

/* ============================================================================
 * Masters card-grid landing (Phase Masters-nav-A, 2026-05-23).
 *
 * /admin/masters lands here instead of redirecting to /families. Each
 * master gets a card with row count + last-edit timestamp, grouped
 * under section labels (Entities / Institutions / Accounting /
 * Categorisation / Admin tools). Mockup at
 * docs/mockups/masters-nav-redesign.html.
 * ========================================================================== */
.masters-landing__group {
  margin: 18px 0 22px;
}
.masters-landing__group-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--bronze, #7a6648);
  margin: 4px 0 12px;
  padding-left: 2px;
}
.masters-landing__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 12px;
}
.master-card {
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-radius: 8px;
  padding: 14px 16px;
  cursor: pointer;
  transition: border-color 0.12s, box-shadow 0.12s, transform 0.12s;
  display: flex;
  flex-direction: column;
  gap: 6px;
  text-decoration: none;
  color: var(--ink);
  border-bottom: 1px solid var(--ink-12);  /* override the default <a> underline */
}
.master-card:hover {
  border-color: var(--bronze, #7a6648);
  border-bottom-color: var(--bronze, #7a6648);
  box-shadow: 0 4px 14px rgba(122, 102, 72, 0.18);
  transform: translateY(-1px);
}
.master-card__head {
  display: flex;
  align-items: center;
  gap: 8px;
}
.master-card__icon {
  font-size: 18px;
  width: 28px;
  height: 28px;
  background: var(--ink-07);
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.master-card__name {
  font-family: var(--font-serif, Georgia, serif);
  font-size: 15px;
  font-weight: 600;
  color: var(--forest-deep);
}
.master-card__count {
  font-family: ui-monospace, Menlo, monospace;
  font-size: 22px;
  font-weight: 700;
  color: var(--ink);
  line-height: 1.1;
}
.master-card__count-label {
  font-size: 11.5px;
  color: var(--ink-65);
}
.master-card__meta {
  font-size: 11px;
  color: var(--ink-45);
  margin-top: 2px;
}
.master-card__meta--good    { color: var(--success, #2f7a4f); }
.master-card__meta--neutral { color: var(--ink-65); }
.master-card__meta--stale   { color: var(--clay, #a8493a); font-weight: 500; }

/* ============================================================================
 * Masters subnav — grouped variant (Phase Masters-nav-B, 2026-05-23).
 *
 * Adds section dividers + group labels + per-item icons to the existing
 * .masters-subnav strip. Used on every admin/masters/* page so users
 * can lateral-jump between related masters without going back to the
 * card-grid landing.
 * ========================================================================== */
.masters-subnav--grouped {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
  align-items: center;
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-radius: 8px;
  padding: 6px 12px;
}
.masters-subnav--grouped .masters-subnav__item {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 10px;
  font-size: 12.5px;
  border-radius: 999px;
  border-bottom: 0;   /* override the global <a> bottom-border */
  color: var(--ink-80);
}
.masters-subnav--grouped .masters-subnav__item:hover {
  background: var(--ink-07);
  color: var(--ink);
  border-bottom: 0;
}
.masters-subnav--grouped .masters-subnav__item--active {
  background: var(--forest);
  color: var(--on-dark);
  font-weight: 500;
}
.masters-subnav--grouped .masters-subnav__item--active:hover {
  background: var(--forest-deep);
  color: var(--on-dark);
}
.masters-subnav__icon {
  font-size: 13px;
  line-height: 1;
}
.masters-subnav__divider {
  width: 1px;
  align-self: stretch;
  background: var(--ink-12);
  margin: 4px 4px;
}
.masters-subnav__group-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--bronze, #7a6648);
  padding: 0 4px 0 0;
  white-space: nowrap;
}

/* Responsive — on narrow screens drop the dividers but keep the
   group labels for vertical scanning. */
@media (max-width: 800px) {
  .masters-subnav__divider { display: none; }
  .masters-subnav--grouped {
    padding: 8px 10px;
  }
  .masters-subnav__group-label {
    flex-basis: 100%;
    padding-top: 4px;
  }
}


/* ============================================================================
 * Users admin (Phase Users-admin-D, 2026-05-23).
 *
 * /admin/users redesigned with avatar-prefixed rows, role + status pills,
 * filter chips, last-login column, and a right-side drawer for per-user
 * edits (replacing the previous 5-inline-forms-per-row chaos). Mockup:
 * docs/mockups/users-admin-redesign.html.
 * ========================================================================== */

/* Top header bits */
.users-admin__related {
  display: flex;
  gap: 16px;
  font-size: 12.5px;
  color: var(--ink-65);
  margin-bottom: 16px;
  margin-top: 6px;
}
.users-admin__related a {
  color: var(--bronze, #7a6648);
  text-decoration: none;
  border-bottom: 0;
}
.users-admin__related a:hover { text-decoration: underline; border-bottom: 0; }

.seat-pill {
  background: var(--ink-07);
  padding: 6px 12px;
  border-radius: 999px;
  font-size: 12px;
  color: var(--ink-80);
  font-weight: 500;
  white-space: nowrap;
}
.seat-pill strong { color: var(--forest-deep); }
.seat-pill--near  { background: rgba(168, 73, 58, 0.10); color: var(--clay, #a8493a); }
.seat-pill--near strong { color: var(--clay, #a8493a); }

/* Filter bar */
.users-filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  margin-bottom: 16px;
  padding: 10px 12px;
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-radius: 8px;
}
.users-filter-bar .chip-group {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.users-filter-bar .filter-chip {
  padding: 5px 12px;
  border: 1px solid var(--ink-12);
  background: var(--paper);
  border-radius: 999px;
  font-size: 12px;
  color: var(--ink-65);
  cursor: pointer;
  font-family: inherit;
  transition: background 0.1s, color 0.1s, border-color 0.1s;
}
.users-filter-bar .filter-chip:hover { background: var(--ink-07); color: var(--ink); }
.users-filter-bar .filter-chip--active {
  background: var(--forest);
  border-color: var(--forest);
  color: var(--on-dark);
}
.users-filter-bar .filter-chip__count {
  font-size: 10.5px;
  margin-left: 4px;
  opacity: 0.7;
}
.users-filter-bar__search {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 6px;
  background: var(--ink-07);
  padding: 5px 10px;
  border-radius: 6px;
  min-width: 220px;
}
.users-filter-bar__search input {
  background: transparent;
  border: 0;
  outline: 0;
  font-size: 12.5px;
  font-family: inherit;
  flex: 1;
  color: var(--ink);
}

/* Users table */
.users-table-wrap {
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-radius: 8px;
  overflow: hidden;
}
.users-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
}
.users-table th {
  background: var(--ink-07);
  text-align: left;
  padding: 10px 14px;
  font-size: 11px;
  font-weight: 600;
  color: var(--ink-65);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.users-table td {
  padding: 10px 14px;
  border-bottom: 1px solid var(--ink-07);
  vertical-align: middle;
}
.users-table tr.user-row {
  cursor: pointer;
  transition: background 0.1s;
}
.users-table tr.user-row:hover { background: var(--ink-07); }
.users-table tr.user-row:last-child td { border-bottom: 0; }
.users-table__levels { font-size: 12px; color: var(--ink-80); }
.users-table__empty {
  text-align: center;
  padding: 32px;
  color: var(--ink-45);
}

/* Avatar circle */
.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  background: var(--bronze-pale);
  color: var(--bronze);
  border-radius: 50%;
  font-weight: 600;
  font-size: 13px;
  margin-right: 10px;
  vertical-align: middle;
  flex-shrink: 0;
}

.user-cell { display: flex; align-items: center; }
.user-cell__main { display: flex; flex-direction: column; }
.user-cell__id {
  font-family: ui-monospace, Menlo, monospace;
  font-size: 12.5px;
  color: var(--ink);
}
.user-cell__name {
  font-size: 11.5px;
  color: var(--ink-65);
}

/* Role pill */
.role-pill {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
}
.role-pill--principal    { background: rgba(15, 29, 19, 0.15);    color: var(--forest-deep); }
.role-pill--supervisor   { background: rgba(42, 70, 49, 0.15);    color: var(--forest); }
.role-pill--staff        { background: rgba(122, 102, 72, 0.15);  color: var(--bronze, #7a6648); }
.role-pill--family       { background: rgba(24, 26, 23, 0.07);    color: var(--ink-65); }
.role-pill--professional { background: rgba(107, 84, 163, 0.16);  color: #6b54a3; }

.status-pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 500;
}
.status-pill--active   { background: rgba(47, 122, 79, 0.15); color: var(--success, #2f7a4f); }
.status-pill--inactive { background: var(--ink-07); color: var(--ink-45); }

.last-login { font-size: 12.5px; color: var(--ink-80); }
.last-login__sub { font-size: 10.5px; color: var(--ink-45); margin-left: 4px; }
.last-login--good    { color: var(--success, #2f7a4f); }
.last-login--neutral { color: var(--ink-80); }
.last-login--stale   { color: var(--clay, #a8493a); font-weight: 500; }

/* Drawer */
.user-drawer-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(15, 29, 19, 0.45);
  z-index: 900;
}
.user-drawer {
  position: fixed;
  top: 0; right: 0; bottom: 0;
  width: 460px;
  max-width: 95vw;
  background: var(--paper);
  box-shadow: -8px 0 32px rgba(0, 0, 0, 0.18);
  transform: translateX(100%);
  transition: transform 0.22s ease-out;
  z-index: 901;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}
.user-drawer--open { transform: translateX(0); }

.user-drawer__head {
  padding: 16px 22px;
  border-bottom: 1px solid var(--ink-12);
  display: flex;
  justify-content: space-between;
  align-items: center;
  background: var(--paper);
  position: sticky;
  top: 0;
  z-index: 10;
}
.user-drawer__title {
  font-family: var(--font-serif, Georgia, serif);
  font-size: 17px;
  font-weight: 600;
  color: var(--forest-deep);
  display: flex;
  align-items: center;
  gap: 8px;
}
.user-drawer__close {
  background: transparent;
  border: 0;
  font-size: 24px;
  color: var(--ink-65);
  cursor: pointer;
  padding: 2px 10px;
  border-radius: 4px;
  line-height: 1;
}
.user-drawer__close:hover { background: var(--ink-07); color: var(--ink); }

.user-drawer__body {
  padding: 18px 22px;
  flex: 1 1 auto;
  overflow-y: auto;
}
.user-drawer__form { margin: 0; }
.user-drawer__section {
  margin-bottom: 18px;
  padding-bottom: 18px;
  border-bottom: 1px dashed var(--ink-12);
}
.user-drawer__section:last-child { border-bottom: 0; }
.user-drawer__section--danger {
  border-top: 1px dashed rgba(168, 73, 58, 0.30);
  padding-top: 14px;
  margin-top: 4px;
}
.user-drawer__section-label {
  font-size: 10.5px;
  font-weight: 700;
  color: var(--bronze, #7a6648);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-bottom: 10px;
}
.user-drawer__section--danger .user-drawer__section-label {
  color: var(--clay, #a8493a);
}
.user-drawer__field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: 12px;
}
.user-drawer__field label {
  font-size: 12px;
  color: var(--ink-65);
}
.user-drawer__field input,
.user-drawer__field select {
  padding: 7px 10px;
  border: 1px solid var(--ink-12);
  border-radius: 5px;
  font-family: inherit;
  font-size: 13px;
  background: var(--paper);
  color: var(--ink);
}
.user-drawer__field input:focus,
.user-drawer__field select:focus {
  border-color: var(--bronze, #7a6648);
  outline: 0;
}

/* Multi-select access-level chips */
.level-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 4px;
}
.level-chip {
  padding: 4px 10px;
  border: 1px solid var(--ink-12);
  background: var(--paper);
  border-radius: 999px;
  font-size: 11.5px;
  color: var(--ink-65);
  cursor: pointer;
  font-family: inherit;
  transition: background 0.1s, color 0.1s, border-color 0.1s;
}
.level-chip:hover { background: var(--ink-07); }
.level-chip--on {
  background: var(--bronze, #7a6648);
  color: var(--on-dark);
  border-color: var(--bronze, #7a6648);
}

.user-drawer__actions {
  display: flex;
  gap: 10px;
  margin-top: 6px;
  padding-bottom: 6px;
}

.btn--danger {
  background: rgba(168, 73, 58, 0.10);
  color: var(--clay, #a8493a);
  border-color: rgba(168, 73, 58, 0.30);
}
.btn--danger:hover { background: rgba(168, 73, 58, 0.18); }

.session-list { font-size: 12px; }
.session-item {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 5px 0;
  border-bottom: 1px solid var(--ink-07);
  gap: 8px;
}
.session-item:last-child { border-bottom: 0; }
.session-item__when { color: var(--ink); }
.session-item__open {
  color: var(--success, #2f7a4f);
  font-weight: 500;
  margin-left: 4px;
}
.session-item__ip {
  color: var(--ink-65);
  font-family: ui-monospace, Menlo, monospace;
  font-size: 11px;
  text-align: right;
}
.session-item__ua {
  color: var(--ink-45);
  font-family: inherit;
  font-size: 11px;
}

@media (max-width: 700px) {
  .users-filter-bar__search { margin-left: 0; min-width: 100%; }
  .user-drawer { width: 100vw; max-width: 100vw; }
}


/* ============================================================================
 * Settings card-grid landing (Phase Settings-nav-B, 2026-05-23).
 *
 * /admin/settings landing — like the masters landing but each card shows
 * the CURRENT VALUE (not a row count). Mockup at
 * docs/mockups/settings-nav-redesign.html. Reuses .masters-subnav--grouped
 * + .page-header-actions + .group-label conventions already defined for
 * masters.
 * ========================================================================== */
.settings-landing__group {
  margin: 18px 0 22px;
}
.settings-landing__group-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--bronze, #7a6648);
  margin: 4px 0 12px;
  padding-left: 2px;
}
.settings-landing__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 12px;
}

/* Card — value-headlined (vs masters' count-headlined .master-card) */
.setting-card {
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-radius: 8px;
  padding: 16px 18px;
  cursor: pointer;
  transition: border-color 0.12s, box-shadow 0.12s, transform 0.12s;
  display: flex;
  flex-direction: column;
  gap: 8px;
  text-decoration: none;
  color: var(--ink);
  border-bottom: 1px solid var(--ink-12);
}
.setting-card:hover {
  border-color: var(--bronze, #7a6648);
  border-bottom-color: var(--bronze, #7a6648);
  box-shadow: 0 4px 14px rgba(122, 102, 72, 0.18);
  transform: translateY(-1px);
}
.setting-card__head {
  display: flex;
  align-items: center;
  gap: 10px;
}
.setting-card__icon {
  font-size: 18px;
  width: 32px;
  height: 32px;
  background: var(--ink-07);
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.setting-card__name {
  font-family: var(--font-serif, Georgia, serif);
  font-size: 15px;
  font-weight: 600;
  color: var(--forest-deep);
}
.setting-card__value {
  font-family: ui-monospace, Menlo, monospace;
  font-size: 17px;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.25;
  word-break: break-word;
}
.setting-card__value--ok      { color: var(--success, #2f7a4f); }
.setting-card__value--missing { color: var(--clay, #a8493a); font-weight: 500; }
.setting-card__value--neutral { color: var(--ink); }
.setting-card__sub {
  font-size: 11.5px;
  color: var(--ink-65);
  line-height: 1.4;
}
.setting-card__sub code {
  font-size: 11px;
  background: var(--ink-07);
  padding: 1px 5px;
  border-radius: 3px;
}
.setting-card__meta {
  font-size: 11px;
  color: var(--ink-45);
  margin-top: auto;
  padding-top: 6px;
  border-top: 1px dashed var(--ink-12);
}
.setting-card__meta--good    { color: var(--success, #2f7a4f); }
.setting-card__meta--stale   { color: var(--clay, #a8493a); font-weight: 500; }
.setting-card__meta--neutral { color: var(--ink-45); }

/* Small inline badge inside a setting card's sub-line — flags state
   like "Active" / "Off" / "read-only" without taking a whole row. */
.card-badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 500;
  margin-left: 6px;
  vertical-align: middle;
}
.card-badge--ok      { background: rgba(47, 122, 79, 0.15);  color: var(--success, #2f7a4f); }
.card-badge--warn    { background: rgba(168, 73, 58, 0.12);  color: var(--clay, #a8493a); }
.card-badge--neutral { background: var(--ink-07); color: var(--ink-65); }

/* ============================================================================
   TRANSACTIONS — Reconciliation grid (Phase Txn-redesign A, 2026-05-23)

   Visual upgrade to /transactions: date chips, debit/credit colour split,
   month group rows with totals, alternating day-block tints, category
   pills, density variants, segmented toolbar controls (View / Group-by
   / Density), hover row-actions toolbar, "needs attention" left border
   for uncategorised, and a statement-view sibling style.

   All additive — existing .data-table / .txn-toolbar / .txn-chips-row
   styles continue to apply. The new classes are namespaced under
   `.txn-grid` so toggling the table class switches between legacy and
   upgraded look.
   ========================================================================= */

/* --- Toolbar: segmented control (View / Group-by / Density) ------------ */
.txn-seg {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--ink-12);
  border-radius: 6px;
  overflow: hidden;
  background: var(--paper);
  margin-right: 6px;
  font-size: 12px;
}
.txn-seg__label {
  background: var(--ink-07);
  color: var(--ink-65);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding: 0 10px;
  display: inline-flex;
  align-items: center;
  border-right: 1px solid var(--ink-12);
}
.txn-seg__btn {
  background: transparent;
  border: 0;
  padding: 6px 11px;
  font-size: 12.5px;
  cursor: pointer;
  color: var(--ink-65);
  font-family: inherit;
  border-right: 1px solid var(--ink-12);
}
.txn-seg__btn:last-child { border-right: 0; }
.txn-seg__btn:hover { background: var(--ink-07); color: var(--ink); }
.txn-seg__btn--active {
  background: var(--forest, #1a2e1f);
  color: var(--on-dark, #f4ede0);
}
.txn-seg__btn--active:hover {
  background: var(--forest-deep, #0f1d13);
  color: var(--on-dark, #f4ede0);
}

/* Toolbar controls row (View / Group-by / Density) below the search strip. */
.txn-controls-row {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  padding: 8px 0 4px;
  margin-bottom: 4px;
  border-top: 1px solid var(--ink-07);
}
.txn-controls-row__spacer { flex: 1; }

/* --- Date chip (left column) ------------------------------------------ */
.txn-grid .date-chip {
  display: flex;
  flex-direction: column;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  min-width: 44px;
}
.txn-grid .date-chip__day {
  font-weight: 700;
  font-size: 14px;
  color: var(--forest-deep, #0f1d13);
}
.txn-grid .date-chip__rest {
  font-size: 10.5px;
  color: var(--ink-45);
  margin-top: 2px;
  white-space: nowrap;
}

/* --- Counterparty + narration stacked --------------------------------- */
.txn-grid .cp {
  display: flex;
  flex-direction: column;
  min-width: 0;
  max-width: 360px;
}
.txn-grid .cp__name {
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.txn-grid .cp__narr {
  font-size: 11.5px;
  color: var(--ink-65);
  margin-top: 1px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* --- Account label cell (Holder + Bank stacked) ----------------------- */
.txn-grid .acct-cell {
  font-size: 11.5px;
  color: var(--ink-65);
  line-height: 1.25;
}
.txn-grid .acct-cell strong {
  color: var(--ink);
  font-weight: 500;
  display: block;
  font-size: 12px;
}

/* --- Amount cells: debit vs credit ------------------------------------ */
.txn-grid .amt-cell {
  text-align: right;
  font-family: "SF Mono", "Consolas", "Menlo", monospace;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.txn-grid .amt-debit  { color: var(--clay, #a8493a); }
.txn-grid .amt-credit { color: var(--success, #2f7a4f); font-weight: 600; }
.txn-grid .amt-blank  { color: var(--ink-25); }
.txn-grid .bal-cell {
  text-align: right;
  font-family: "SF Mono", "Consolas", "Menlo", monospace;
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  color: var(--ink-65);
  white-space: nowrap;
}

/* --- Category pill (color cycling by name-hash) ----------------------- */
/* Category colour pills — shared by the /transactions reconciliation grid
   (.txn-grid) and the Data Tools → Category Mapper grid (.cat-table) so the
   same name-hashed colour reads consistently in both (Phase CatMapper-5). */
.txn-grid .cat-pill,
.cat-table .cat-pill {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 11px;
  font-size: 11px;
  font-weight: 500;
  white-space: nowrap;
  max-width: 140px;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: middle;
}
.txn-grid .cat-pill--0, .cat-table .cat-pill--0 { background: #e3efe6; color: #2f7a4f; }
.txn-grid .cat-pill--1, .cat-table .cat-pill--1 { background: #f2e7c8; color: #8a6a1f; }
.txn-grid .cat-pill--2, .cat-table .cat-pill--2 { background: #e9e4f3; color: #6b54a3; }
.txn-grid .cat-pill--3, .cat-table .cat-pill--3 { background: #fce4d6; color: #b35a26; }
.txn-grid .cat-pill--4, .cat-table .cat-pill--4 { background: #f3dcd5; color: #a8493a; }
.txn-grid .cat-pill--5, .cat-table .cat-pill--5 { background: #dcebf3; color: #3a6b8a; }
.txn-grid .cat-pill--6, .cat-table .cat-pill--6 { background: #d6e8d8; color: #2a5c3e; }
.txn-grid .cat-pill--7, .cat-table .cat-pill--7 { background: #f5ebd6; color: #7a6648; }
.txn-grid .cat-pill--8, .cat-table .cat-pill--8 { background: #e4ede2; color: #4a6b3e; }
.txn-grid .cat-pill--9, .cat-table .cat-pill--9 { background: #f0e1ea; color: #8a3a6b; }
.txn-grid .cat-pill--10, .cat-table .cat-pill--10 { background: #dde6ef; color: #3a548a; }
.txn-grid .cat-pill--11, .cat-table .cat-pill--11 { background: #ede4d0; color: #6a5a2a; }
.txn-grid .cat-pill--none,
.cat-table .cat-pill--none {
  background: var(--ink-07);
  color: var(--ink-65);
  font-style: italic;
}

/* Holder colour dot — a small solid dot before a holder name. A lighter,
   per-axis cue (distinct, more-saturated palette) so it never reads as a
   category pill. Hash-cycled by name in transactions_service._holder_idx_for.
   Phase HolderColour-1 (2026-06-14). Piloted in the Category Mapper grid. */
.holder-dot {
  display: inline-block;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  margin-right: 7px;
  vertical-align: baseline;
  flex-shrink: 0;
}
.holder-dot--0  { background: #3f7a52; } /* green   */
.holder-dot--1  { background: #c08a2e; } /* gold    */
.holder-dot--2  { background: #6b54a3; } /* violet  */
.holder-dot--3  { background: #c2683a; } /* orange  */
.holder-dot--4  { background: #b14a3c; } /* clay    */
.holder-dot--5  { background: #3a7d99; } /* teal    */
.holder-dot--6  { background: #2f6b8a; } /* blue    */
.holder-dot--7  { background: #9a3f73; } /* magenta */
.holder-dot--8  { background: #4a6b3e; } /* olive   */
.holder-dot--9  { background: #7a5cc0; } /* purple  */
.holder-dot--none, .holder-dot---1 { background: var(--ink-25, #c9c6bd); }

/* --- Month group header row ------------------------------------------- */
.txn-grid .month-row td {
  background: var(--forest, #1a2e1f);
  color: var(--on-dark, #f4ede0);
  font-weight: 600;
  font-size: 12.5px;
  padding: 7px 12px;
  letter-spacing: 0.3px;
  border-bottom: none;
}
.txn-grid .month-row__totals {
  float: right;
  font-family: "SF Mono", "Consolas", "Menlo", monospace;
  font-weight: 400;
  font-size: 12px;
  opacity: 0.88;
}
.txn-grid .month-row__totals span + span { margin-left: 14px; }
.txn-grid .month-row__totals b { font-weight: 600; }
.txn-grid .month-row__totals .pos { color: #b6e0c2; }
.txn-grid .month-row__totals .neg { color: #f3c8c0; }

/* --- Alternating day-block tints -------------------------------------- */
.txn-grid tr.day-block-b > td { background: rgba(122, 102, 72, 0.035); }

/* --- Needs-attention left border (uncategorised, etc.) ---------------- */
.txn-grid tr.row--needs-attention > td:first-child {
  box-shadow: inset 3px 0 0 #b58a2a;
}

/* --- Hover row-actions toolbar ---------------------------------------- */
.txn-grid .row-actions-cell { position: relative; padding-right: 8px; }
.txn-grid .row-actions {
  display: inline-flex;
  gap: 2px;
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-radius: 6px;
  padding: 2px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
  opacity: 0;
  transition: opacity 0.12s ease;
}
.txn-grid tbody tr:hover .row-actions { opacity: 1; }
.txn-grid .row-actions a,
.txn-grid .row-actions button {
  background: transparent;
  border: 0;
  cursor: pointer;
  padding: 4px 7px;
  border-radius: 4px;
  font-size: 12.5px;
  line-height: 1;
  color: var(--ink-65);
  text-decoration: none;
}
.txn-grid .row-actions a:hover,
.txn-grid .row-actions button:hover {
  background: var(--bronze-pale, #f5ebd6);
  color: var(--bronze, #8a7350);
}
.txn-grid .row-actions button.danger:hover {
  background: rgba(192, 57, 43, 0.12);
  color: var(--danger, #c0392b);
}

/* --- Density variants: Compact / Comfort (default) / Tall ------------- */
.txn-grid--compact td { padding: 4px 8px !important; font-size: 12px; }
.txn-grid--compact .date-chip__day { font-size: 12.5px; }
.txn-grid--compact .date-chip__rest { font-size: 10px; }
.txn-grid--compact .cp__narr { display: none; }
.txn-grid--tall td { padding: 14px 12px !important; }
.txn-grid--tall .cp__narr { font-size: 12.5px; margin-top: 3px; }

/* --- Reconciliation-grid table base ----------------------------------- */
.txn-grid {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.txn-grid thead th {
  background: var(--paper-2, #f6f1e6);
  text-align: left;
  padding: 9px 10px;
  font-weight: 600;
  font-size: 11px;
  color: var(--ink-65);
  text-transform: uppercase;
  letter-spacing: 0.4px;
  border-bottom: 2px solid var(--ink-12);
  position: sticky;
  top: 0;
  z-index: 3;
}
.txn-grid thead th.num { text-align: right; }
.txn-grid tbody tr { border-bottom: 1px solid var(--ink-07); }
.txn-grid tbody tr:hover > td { background: rgba(122, 102, 72, 0.06); }
.txn-grid td { padding: 9px 10px; vertical-align: top; }

/* ============================================================================
   STATEMENT VIEW — bank-statement-style alternative rendering
   ========================================================================= */
.txn-stmt {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 13.5px;
}
.txn-stmt__month {
  background: var(--forest-deep, #0f1d13);
  color: var(--on-dark, #f4ede0);
  padding: 12px 18px;
  border-radius: 6px 6px 0 0;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-top: 16px;
}
.txn-stmt__month-name { font-size: 16px; font-weight: 600; }
.txn-stmt__month-meta { font-size: 11.5px; opacity: 0.75; margin-top: 2px; }
.txn-stmt__month-bal {
  font-size: 12.5px; opacity: 0.85;
  font-family: "SF Mono", "Consolas", "Menlo", monospace;
}
.txn-stmt__table {
  width: 100%;
  border-collapse: collapse;
  background: #fffefb;
  border: 1px solid var(--ink-12);
  border-top: 0;
}
.txn-stmt__table th {
  text-align: left;
  padding: 9px 14px;
  font-size: 11px;
  font-family: -apple-system, system-ui, sans-serif;
  font-weight: 600;
  color: var(--ink-65);
  text-transform: uppercase;
  border-bottom: 1px solid var(--ink-12);
  letter-spacing: 0.5px;
}
.txn-stmt__table th.r,
.txn-stmt__table td.r {
  text-align: right;
  font-family: "SF Mono", "Consolas", "Menlo", monospace;
  white-space: nowrap;
}
.txn-stmt__table td {
  padding: 9px 14px;
  border-bottom: 1px solid var(--ink-07);
  vertical-align: top;
}
.txn-stmt__date {
  font-family: "SF Mono", "Consolas", "Menlo", monospace;
  font-size: 12px;
  color: var(--ink-65);
  white-space: nowrap;
  width: 100px;
}
.txn-stmt__desc-main { font-weight: 600; color: var(--forest-deep, #0f1d13); }
.txn-stmt__desc-sub {
  font-size: 11.5px;
  color: var(--ink-65);
  margin-top: 2px;
  font-family: -apple-system, system-ui, sans-serif;
}
.txn-stmt__amt-debit  { color: var(--clay, #a8493a); }
.txn-stmt__amt-credit { color: var(--success, #2f7a4f); font-weight: 600; }
.txn-stmt__balance { color: var(--ink-65); font-size: 12px; }
.txn-stmt__totals-row td {
  background: var(--paper-2, #f6f1e6);
  font-weight: 700;
  font-size: 12px;
  font-family: -apple-system, system-ui, sans-serif;
}

/* ============================================================================
   EXPORT DRAWER — column picker + presets (Phase Txn-redesign F)
   ========================================================================= */
.export-drawer-overlay {
  position: fixed;
  inset: 0;
  background: rgba(24, 26, 23, 0.35);
  z-index: 60;
}
.export-drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: 480px;
  max-width: 100vw;
  background: var(--paper);
  box-shadow: -8px 0 22px rgba(0, 0, 0, 0.12);
  z-index: 61;
  display: flex;
  flex-direction: column;
}
.export-drawer__head {
  padding: 14px 18px;
  border-bottom: 1px solid var(--ink-12);
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.export-drawer__head h2 {
  font-family: Georgia, "Times New Roman", serif;
  color: var(--forest-deep, #0f1d13);
  font-size: 17px;
  margin: 0;
}
.export-drawer__close {
  background: transparent;
  border: 0;
  cursor: pointer;
  font-size: 20px;
  color: var(--ink-45);
}
.export-drawer__body {
  padding: 16px 18px;
  flex: 1;
  overflow-y: auto;
}
.export-drawer__foot {
  padding: 12px 18px;
  border-top: 1px solid var(--ink-12);
  background: var(--paper-2, #f6f1e6);
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
}
.export-section { margin-bottom: 18px; }
.export-section h3 {
  font-size: 11px;
  color: var(--ink-45);
  text-transform: uppercase;
  letter-spacing: 0.6px;
  margin: 0 0 8px;
  font-weight: 600;
}
.export-format-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 6px;
}
.export-format-chip {
  border: 1px solid var(--ink-12);
  background: var(--paper);
  padding: 9px 4px;
  border-radius: 6px;
  text-align: center;
  cursor: pointer;
  font-size: 11.5px;
  font-family: inherit;
  color: var(--ink-65);
}
.export-format-chip:hover { background: var(--paper-2, #f6f1e6); color: var(--ink); }
.export-format-chip--active {
  background: var(--forest, #1a2e1f);
  color: var(--on-dark, #f4ede0);
  border-color: var(--forest, #1a2e1f);
}
.export-format-chip__icon { font-size: 18px; display: block; margin-bottom: 2px; }

.export-preset-row { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 8px; }
.export-preset {
  border: 1px solid var(--ink-12);
  background: var(--paper);
  padding: 5px 11px;
  border-radius: 14px;
  font-size: 11.5px;
  cursor: pointer;
  font-family: inherit;
  color: var(--ink-65);
}
.export-preset:hover { background: var(--paper-2, #f6f1e6); color: var(--ink); }
.export-preset--active {
  background: var(--bronze, #8a7350);
  color: var(--on-dark, #f4ede0);
  border-color: var(--bronze, #8a7350);
}
.export-preset--save {
  background: transparent;
  color: var(--bronze, #8a7350);
  border-style: dashed;
}

.export-col-shuttle {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  border: 1px solid var(--ink-12);
  border-radius: 6px;
  overflow: hidden;
}
.export-col-pane {
  background: var(--paper);
  border-right: 1px solid var(--ink-12);
}
.export-col-pane:last-child { border-right: 0; }
.export-col-pane h4 {
  font-size: 11px;
  text-transform: uppercase;
  color: var(--ink-45);
  padding: 7px 10px;
  background: var(--paper-2, #f6f1e6);
  border-bottom: 1px solid var(--ink-12);
  margin: 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  letter-spacing: 0.4px;
}
.export-col-pane h4 small {
  color: var(--ink-65);
  text-transform: none;
  font-weight: 400;
  letter-spacing: 0;
}
.export-col-list {
  max-height: 220px;
  overflow-y: auto;
  padding: 4px 0;
}
.export-col-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 10px;
  font-size: 12.5px;
  cursor: pointer;
  user-select: none;
}
.export-col-item:hover { background: var(--paper-2, #f6f1e6); }
.export-col-item input { margin: 0; }
.export-col-item--selected { background: rgba(47, 122, 79, 0.08); }
.export-col-handle {
  cursor: grab;
  color: var(--ink-25);
  margin-right: 4px;
  font-size: 11px;
}
.export-col-item.dragging { opacity: 0.4; }
.export-col-item.drag-over { border-top: 2px solid var(--bronze, #8a7350); }

.export-opt-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 6px 0;
  font-size: 13px;
  gap: 10px;
}
.export-opt-row + .export-opt-row { border-top: 1px solid var(--ink-07); }
.export-toggle {
  width: 32px;
  height: 18px;
  background: var(--ink-12);
  border-radius: 10px;
  position: relative;
  cursor: pointer;
  flex-shrink: 0;
}
.export-toggle::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 14px;
  height: 14px;
  background: white;
  border-radius: 50%;
  transition: 0.15s;
}
.export-toggle--on { background: var(--forest, #1a2e1f); }
.export-toggle--on::after { left: 16px; }

.export-filename {
  width: 100%;
  border: 1px solid var(--ink-12);
  padding: 6px 10px;
  border-radius: 4px;
  font-size: 12.5px;
  font-family: "SF Mono", "Consolas", "Menlo", monospace;
}
.export-preview {
  font-size: 11.5px;
  color: var(--ink-65);
  margin-top: 4px;
}

/* Split-button: left = run last preset, right = open drawer. */
.export-split-btn {
  display: inline-flex;
  border: 1px solid var(--forest, #1a2e1f);
  border-radius: 6px;
  overflow: hidden;
  background: var(--forest, #1a2e1f);
  color: var(--on-dark, #f4ede0);
  font-family: inherit;
  font-size: 13px;
}
.export-split-btn > * {
  background: transparent;
  border: 0;
  color: inherit;
  padding: 7px 13px;
  cursor: pointer;
  font-family: inherit;
  font-size: inherit;
}
.export-split-btn > * + * { border-left: 1px solid rgba(255, 255, 255, 0.18); }
.export-split-btn > *:hover { background: var(--forest-deep, #0f1d13); }

/* ============================================================================
   ADD-TRANSACTION — Smart single form (Phase Add-Txn A.4, 2026-05-23)

   Sidebar layout (form + context cards), template chip strip, particulars
   typeahead dropdown, segmented direction toggle, live duplicate banner,
   three-way submit bar, keyboard hint chips.

   All additive. Existing /entry layout for bulk / matrix modes uses
   .data-entry-form alone and inherits no new rules unless paired with
   .entry-grid (the 2-col wrapper).
   ========================================================================= */

/* --- Template chip strip --------------------------------------------- */
.tmpl-chip-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  padding: 10px 0 14px;
  margin-bottom: 12px;
  border-bottom: 1px solid var(--ink-07);
}
.tmpl-chip-strip__label {
  font-size: 11.5px;
  color: var(--ink-65);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  font-weight: 600;
  margin-right: 6px;
}
.tmpl-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-radius: 16px;
  font-size: 12.5px;
  cursor: pointer;
  font-family: inherit;
  color: var(--ink);
  transition: background 0.1s ease, border-color 0.1s ease;
}
.tmpl-chip:hover {
  background: var(--bronze-pale, #f5ebd6);
  border-color: var(--bronze, #8a7350);
}
.tmpl-chip--user {
  border-color: var(--bronze, #8a7350);
}
.tmpl-chip__icon { font-size: 14px; line-height: 1; }
.tmpl-chip__name { font-weight: 500; }
.tmpl-chip__amt {
  font-family: "SF Mono", "Consolas", "Menlo", monospace;
  font-size: 11px;
  color: var(--ink-65);
  margin-left: 4px;
}

/* --- 2-column form + sidebar layout ---------------------------------- */
.entry-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 22px;
  align-items: start;
}
@media (max-width: 980px) {
  .entry-grid { grid-template-columns: 1fr; }
}
.entry-grid__main { min-width: 0; }
.entry-grid__side { min-width: 0; }

/* --- Sidebar cards --------------------------------------------------- */
.entry-side { display: flex; flex-direction: column; gap: 12px; }
.entry-side__card {
  background: var(--paper);
  border: 1px solid var(--ink-12);
  border-radius: 8px;
  padding: 14px;
}
.entry-side__card h4 {
  font-size: 11.5px;
  color: var(--ink-65);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin-bottom: 10px;
  font-weight: 600;
}
.entry-side__card--last {
  background: linear-gradient(135deg, var(--forest-pale, #d6dcd2), var(--paper));
}
.entry-side__hint { font-size: 12px; color: var(--ink-65); line-height: 1.5; margin-bottom: 8px; }
.entry-side__btn { width: 100%; justify-content: center; }
.entry-side__save-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.entry-side__name-input {
  width: 100%;
  padding: 6px 10px;
  border: 1px solid var(--ink-12);
  border-radius: 4px;
  font-size: 12.5px;
  font-family: inherit;
}

.last-entry__row { font-size: 13px; color: var(--ink); line-height: 1.4; }
.last-entry__row--meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 4px;
  font-size: 12px;
  color: var(--ink-65);
}
.last-entry__row--bank { font-size: 11.5px; color: var(--ink-45); margin-top: 2px; margin-bottom: 10px; }
.last-entry__particulars { font-weight: 600; color: var(--forest-deep, #0f1d13); }
.last-entry__amount { font-family: "SF Mono", "Consolas", "Menlo", monospace; font-weight: 600; }
.last-entry__amount--in  { color: var(--success, #2f7a4f); }
.last-entry__amount--out { color: var(--clay, #a8493a); }

/* --- Particulars typeahead ------------------------------------------- */
.entry-suggest { position: relative; }
.entry-suggest__list {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  background: white;
  border: 1px solid var(--ink-12);
  border-radius: 5px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.08);
  z-index: 20;
  max-height: 240px;
  overflow-y: auto;
  margin-top: 2px;
}
.entry-suggest__item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  font-size: 13px;
  cursor: pointer;
  border-bottom: 1px solid var(--ink-07);
}
.entry-suggest__item:last-child { border-bottom: 0; }
.entry-suggest__item:hover,
.entry-suggest__item.is-focused {
  background: var(--bronze-pale, #f5ebd6);
}
.entry-suggest__text { font-weight: 500; color: var(--ink); }
.entry-suggest__meta { color: var(--ink-65); margin-left: 8px; font-size: 11.5px; }
.entry-suggest__freq { color: var(--ink-45); font-size: 11.5px; }

/* --- Segmented direction toggle -------------------------------------- */
.direction-toggle {
  display: inline-flex;
  border: 1px solid var(--ink-12);
  border-radius: 6px;
  overflow: hidden;
  width: fit-content;
  background: white;
}
.direction-toggle button {
  background: transparent;
  border: 0;
  padding: 8px 16px;
  font-size: 13px;
  cursor: pointer;
  font-family: inherit;
  color: var(--ink-65);
  border-right: 1px solid var(--ink-12);
  transition: background 0.1s ease, color 0.1s ease;
}
.direction-toggle button:last-child { border-right: 0; }
.direction-toggle button:hover { background: var(--paper-2, #f6f1e6); color: var(--ink); }
.direction-toggle button.is-active.outflow {
  background: var(--clay, #a8493a);
  color: white;
}
.direction-toggle button.is-active.inflow {
  background: var(--success, #2f7a4f);
  color: white;
}

/* --- Live duplicate banner ------------------------------------------- */
/* Style for the banner served by /entry/check-duplicate as inline HTML. */
.dup-banner {
  background: #fff8e0;
  border: 1px solid var(--gold, #b58a2a);
  color: #6a5018;
  padding: 10px 14px;
  border-radius: 6px;
  font-size: 12.5px;
  margin-bottom: 14px;
  display: flex;
  gap: 10px;
  align-items: center;
}
.dup-banner b { color: #4a3508; }

/* --- Three-way submit bar -------------------------------------------- */
.entry-submit-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--ink-12);
  flex-wrap: wrap;
}
.entry-submit-bar__btns { display: flex; gap: 6px; flex-wrap: wrap; }
.kbd-hints { font-size: 11px; color: var(--ink-45); }
.kbd {
  background: var(--paper-2, #f6f1e6);
  border: 1px solid var(--ink-12);
  border-radius: 3px;
  padding: 1px 6px;
  font-family: "SF Mono", "Consolas", "Menlo", monospace;
  font-size: 10.5px;
}

/* ============================================================================
   ADD-TRANSACTION — Spreadsheet grid (Phase Add-Txn B, 2026-05-23)

   /entry?mode=grid layout. Wide multi-row table with cell-edit inputs
   that look invisible until focused, sticky header, row-state tints
   (invalid red, dup yellow, saved-and-removed transparent), paste
   modal, and a sticky toolbar with counts + action buttons.
   ========================================================================= */

/* --- Toolbar (counts + action buttons) -------------------------------- */
.grid-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  padding: 12px 14px;
  margin: 14px 0;
  background: var(--paper-2, #f6f1e6);
  border: 1px solid var(--ink-12);
  border-radius: 8px;
  position: sticky;
  top: 0;
  z-index: 5;
}
.grid-toolbar__stats {
  font-size: 13px;
  color: var(--ink-65);
}
.grid-toolbar__actions { display: flex; gap: 6px; flex-wrap: wrap; }
.grid-toolbar__hint {
  width: 100%;
  font-size: 11px;
  color: var(--ink-45);
  padding-top: 4px;
  border-top: 1px dashed var(--ink-12);
}

/* --- Errors banner (after partial-success save) ---------------------- */
.grid-errors {
  background: #fff7f5;
  border-left: 3px solid var(--clay, #a8493a);
  padding: 10px 14px;
  margin-bottom: 12px;
  font-size: 12.5px;
  color: var(--clay, #a8493a);
  border-radius: 4px;
}
.grid-errors b { color: #6b2516; }
.grid-errors ul { margin: 6px 0 6px 20px; }

/* --- The grid table -------------------------------------------------- */
.grid-wrap {
  border: 1px solid var(--ink-12);
  border-radius: 8px;
  overflow: auto;
  background: white;
}
.grid-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.grid-table thead th {
  background: var(--paper-2, #f6f1e6);
  padding: 8px 10px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  text-align: left;
  color: var(--ink-65);
  border-bottom: 2px solid var(--ink-12);
  font-weight: 600;
  position: sticky;
  top: 0;
  z-index: 4;
}
.grid-table thead th.num { text-align: right; }
.grid-table tbody tr {
  border-bottom: 1px solid var(--ink-07);
}
.grid-table tbody tr:hover { background: rgba(122, 102, 72, 0.04); }
.grid-table td {
  padding: 3px 5px;
  vertical-align: top;
}
/* Cell inputs — invisible until focused, like Excel. */
.grid-table input,
.grid-table select {
  width: 100%;
  border: 1px solid transparent;
  background: transparent;
  padding: 7px 8px;
  font-size: 13px;
  font-family: inherit;
  border-radius: 4px;
  color: inherit;
}
.grid-table input:hover,
.grid-table select:hover {
  background: white;
  border-color: var(--ink-12);
}
.grid-table input:focus,
.grid-table select:focus {
  background: white;
  outline: 2px solid var(--bronze-mid, #a08868);
  outline-offset: -1px;
  border-color: var(--bronze-mid, #a08868);
  position: relative;
  z-index: 2;
}
.grid-table .num input {
  text-align: right;
  font-family: "SF Mono", "Consolas", "Menlo", monospace;
  font-variant-numeric: tabular-nums;
}
.grid-table .row-debit input  { color: var(--clay, #a8493a); }
.grid-table .row-credit input { color: var(--success, #2f7a4f); font-weight: 600; }

/* Row state tints */
.grid-table tr.row--invalid > td { background: #fff7f5; }
.grid-table tr.row--invalid:hover > td { background: #fff1ee; }
.grid-table tr.row--dup > td { background: #fff8e0; }
.grid-table tr.row--dup:hover > td { background: #fff4d2; }

/* Per-row action buttons */
.grid-table .row-actions-cell {
  white-space: nowrap;
  padding-right: 8px;
  text-align: right;
}
.grid-table .row-act {
  background: transparent;
  border: 0;
  padding: 5px 7px;
  cursor: pointer;
  font-size: 14px;
  color: var(--ink-45);
  border-radius: 4px;
  line-height: 1;
}
.grid-table .row-act:hover {
  background: var(--bronze-pale, #f5ebd6);
  color: var(--bronze, #8a7350);
}
.grid-table .row-act.row-act--danger:hover {
  background: var(--clay-pale, #f3dcd5);
  color: var(--clay, #a8493a);
}

/* --- Footer (counts + save button echoed below for long grids) ----- */
.grid-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 12px;
  padding: 10px 0;
  gap: 12px;
  flex-wrap: wrap;
}

/* --- Paste modal --------------------------------------------------- */
.grid-paste-modal {
  background: var(--paper);
  border-radius: 8px;
  width: 720px;
  max-width: 92vw;
  padding: 22px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25);
}
.grid-paste-modal h3 {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 18px;
  color: var(--forest-deep, #0f1d13);
  margin-bottom: 8px;
}
.grid-paste-modal p {
  font-size: 12.5px;
  color: var(--ink-65);
  margin-bottom: 12px;
  line-height: 1.5;
}
.grid-paste-modal textarea {
  width: 100%;
  font-family: "SF Mono", "Consolas", "Menlo", monospace;
  font-size: 12.5px;
  border: 1px solid var(--ink-12);
  border-radius: 5px;
  padding: 10px;
  background: #fffefb;
  resize: vertical;
}
.grid-paste-modal__foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 14px;
  gap: 10px;
}

/* Modal overlay reused from elsewhere if not already defined */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(24, 26, 23, 0.45);
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* ============================================================================
   ADD-TRANSACTION — Paste & reconcile (Phase Add-Txn C, 2026-05-23)

   /entry?mode=paste — drop-zone textarea + sample chips + parser cascade.
   Reuses grid CSS (.grid-wrap, .grid-table, .grid-errors, .grid-foot) for
   the preview table; only the paste-specific bits live below.
   ========================================================================= */

/* --- Drop zone (big bordered card at top of page) ---------------------- */
.paste-zone {
  border: 2px dashed var(--bronze-mid, #a08868);
  border-radius: 10px;
  background: var(--paper-2, #f6f1e6);
  padding: 24px 22px;
  margin-top: 14px;
  text-align: center;
}
.paste-zone__icon { font-size: 40px; opacity: 0.55; }
.paste-zone h3 {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 18px;
  color: var(--forest-deep, #0f1d13);
  margin-top: 8px;
}
.paste-zone p {
  font-size: 12.5px;
  color: var(--ink-65);
  margin: 6px 0 12px;
}
.paste-zone textarea {
  width: 100%;
  font-family: "SF Mono", "Consolas", "Menlo", monospace;
  font-size: 12.5px;
  border: 1px solid var(--ink-12);
  border-radius: 5px;
  padding: 10px 12px;
  background: white;
  text-align: left;
  resize: vertical;
  min-height: 140px;
}
.paste-zone textarea:focus {
  outline: 2px solid var(--bronze-mid);
  outline-offset: -1px;
  border-color: var(--bronze-mid);
}

.paste-zone__samples {
  display: flex;
  gap: 8px;
  justify-content: center;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

/* Reuse `.sample-chip` shape from mockup-flavoured zones. */
.sample-chip {
  background: white;
  border: 1px solid var(--ink-12);
  padding: 6px 13px;
  border-radius: 18px;
  font-size: 12px;
  cursor: pointer;
  font-family: inherit;
  color: var(--ink-65);
}
.sample-chip:hover {
  background: var(--bronze-pale, #f5ebd6);
  border-color: var(--bronze, #8a7350);
  color: var(--bronze, #8a7350);
}

.paste-zone__controls {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  margin-top: 12px;
  flex-wrap: wrap;
}

/* --- Preview-section header ------------------------------------------ */
.paste-preview-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 10px;
  gap: 12px;
  flex-wrap: wrap;
}
.paste-preview-head__title {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 17px;
  color: var(--forest-deep, #0f1d13);
}

/* --- Confidence pills (per-row in the preview table) ----------------- */
.confidence-pill {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 11px;
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.3px;
}
.confidence-pill--high { background: var(--success-pale, #e3efe6); color: var(--success, #2f7a4f); }
.confidence-pill--med  { background: var(--gold-pale,    #f2e7c8); color: var(--gold,    #b58a2a); }
.confidence-pill--low  { background: var(--clay-pale,    #f3dcd5); color: var(--clay,    #a8493a); }


/* ============================================================================
   ADMIN — Accounts table polish (2026-05-24)
   * .btn--icon          — single-glyph buttons keep Edit/Delete on one line
   * .btn--icon-danger   — clay tint on the delete bin
   * .acct-no            — monospace + tabular-nums so 4-digit groups align
   ========================================================================= */

.btn--icon {
  width: 30px;
  height: 30px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  line-height: 1;
  border-radius: 5px;
  vertical-align: middle;
}
.btn--icon + .btn--icon,
.btn--icon + .inline-form > .btn--icon,
.inline-form > .btn--icon { margin-left: 4px; }

.btn--icon-danger { color: var(--clay, #a8493a); }
.btn--icon-danger:hover {
  background: var(--clay-pale, #f3dcd5);
  color: var(--clay, #a8493a);
  border-color: var(--clay, #a8493a);
}

/* Account-number cell — monospace + 4-digit grouping (via digit_group
   Jinja filter). Tabular-nums ensures rows line up vertically. */
.acct-no {
  font-family: "SF Mono", "Consolas", "Menlo", monospace;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

/* ====================================================================
   Filter chips + category pills — /admin/masters/accounts (and any
   future master list that wants the same coloured-bucket UX). The
   accounts page mixes 7 different "kinds" of account (bank · FD · CC
   · DW · RE · MA · LI) and a flat plain-text Category column made
   them hard to scan. The chips at the top let you narrow to one
   bucket in one click; the coloured pill in the table makes each
   row's bucket recognisable at a glance.

   The seven colours match the palette established in the
   docs/mockups/accounts-categorization.html mockup. They're inlined
   here (not tokenised) because they're single-use semantic accents,
   not part of the global brand system — every new colour token has
   to earn its keep across multiple surfaces.
   ==================================================================== */
.filter-chips {
  display: flex; gap: 8px; flex-wrap: wrap;
  align-items: center;
  padding: 12px 0;
  margin: 8px 0 4px;
  border-top: 1px solid var(--ink-07);
  border-bottom: 1px solid var(--ink-07);
}
.filter-chips__label {
  font-size: 11px; color: var(--ink-65);
  text-transform: uppercase; letter-spacing: 0.5px;
  margin-right: 4px; font-weight: 600;
}
.filter-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 12px; border-radius: 16px;
  font-size: 12.5px; line-height: 1.2;
  background: var(--paper);
  border: 1px solid var(--ink-12);
  color: var(--ink-65);
  text-decoration: none;
  cursor: pointer;
  transition: background 0.1s ease, color 0.1s ease, border-color 0.1s ease;
}
.filter-chip:hover {
  background: var(--ink-07);
  color: var(--ink);
  border-bottom-color: var(--ink-12); /* override global a:hover rule */
}
.filter-chip.is-active {
  background: var(--forest);
  color: var(--on-dark);
  border-color: var(--forest);
}
.filter-chip.is-active:hover {
  background: var(--forest-deep);
  color: var(--on-dark);
  border-color: var(--forest-deep);
}
.filter-chip__icon  { font-size: 13px; line-height: 1; }
.filter-chip__label { font-weight: 500; }
.filter-chip__count {
  font-family: "SF Mono", "Consolas", "Menlo", monospace;
  font-size: 11px;
  background: rgba(0,0,0,0.08);
  padding: 1px 7px;
  border-radius: 10px;
  font-variant-numeric: tabular-nums;
}
.filter-chip.is-active .filter-chip__count {
  background: rgba(255,255,255,0.18);
}

/* Category pill — one coloured chip per account category group.
   Background is a tinted pale of the foreground colour so the pill
   stays legible against the white table row. The dot-separated
   sub-label (the specific category, e.g. "Savings" vs the group
   "Bank") keeps the detail readable for users who care about it
   without taking up an extra column. */
.cat-pill {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px; border-radius: 11px;
  font-size: 11px; font-weight: 500;
  white-space: nowrap;
  line-height: 1.4;
}
.cat-pill__sub   { opacity: 0.7; font-weight: 400; }
.cat-pill__label { font-weight: 500; }

/* The seven category-group colours. Pale background + saturated
   foreground = a soft pill that doesn't shout but is still
   instantly distinguishable from its neighbours. */
.cat-pill--bank { background: #e3ebdb; color: #406b48; } /* forest green  */
.cat-pill--fd   { background: #f5e9c8; color: #8a6914; } /* gold          */
.cat-pill--cc   { background: #e9e4f3; color: #6b54a3; } /* purple        */
.cat-pill--dw   { background: #dcebf3; color: #3a6b8a; } /* steel-blue    */
.cat-pill--re   { background: #f0dfd9; color: #8a3a2e; } /* clay          */
.cat-pill--ma   { background: #d9cdb7; color: #6b5530; } /* bronze        */
.cat-pill--li   { background: #d6e9e3; color: #2a6b5c; } /* teal          */

/* ===========================================================================
 * FD Option B — shared primitives for masters / add / open
 * Phase FDOptB-1 (2026-05-26)
 *
 * "Option B" is the visual language picked over the FD-detail Option A
 * (the rolled-back tabbed app-shell). Linear scroll, but each section
 * is a clean card with paired metadata (primary value + small muted
 * secondary). Same vocabulary across all three FD surfaces so the
 * system reads as one product:
 *
 *   .tbl-opt-b           — two-line-cell tables (used by masters + the
 *                          schedule table on /fixed-deposits/{id})
 *   .opt-b-card          — section card (used by add + open)
 *   .cell-primary /      — the recurring two-line-cell primitive
 *     .cell-secondary
 *   .meta-pair           — paired label + value blocks inside cards
 *   .field-grid /        — Add-FD form layout (2-col field pairs)
 *     .field
 *   .opt-b-hero          — Open-FD hero strip (title + 4 metric tiles)
 *   .opt-b-alert         — "What's next" amber strip for overdue receipts
 *
 * Scoped to FD for now. If this language survives review, the same
 * classes can spread to LI / RE / MA detail pages — at which point
 * we'll generalise the names (drop the .opt-b- prefix).
 * =========================================================================== */

/* ── Card primitive — used by Add form sections + Open FD blocks ───── */
.opt-b-card {
  background: var(--card, white);
  border: var(--rule);
  border-radius: 8px;
  padding: 20px 24px;
  margin-bottom: 18px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.03);
}
.opt-b-card__title {
  margin: 0 0 4px 0;
  font-size: 1rem;
  font-weight: 600;
}
.opt-b-card__sub {
  margin: 0 0 16px 0;
  font-size: 0.85rem;
  color: var(--ink-65);
}

/* ── Two-line cell primitive ───────────────────────────────────────── */
/* Used inside .tbl-opt-b cells AND inside Open-FD form rows. Primary
   reads as the headline value; secondary is muted detail beneath. */
.cell-primary {
  font-weight: 600;
  color: var(--ink);
  line-height: 1.35;
}
.cell-secondary {
  font-size: 0.78rem;
  color: var(--ink-65);
  margin-top: 2px;
  line-height: 1.35;
}

/* ── Option-B table (paired-cell, generous row height) ─────────────── */
.tbl-opt-b {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  background: var(--card, white);
  border: var(--rule);
  border-radius: 8px;
  overflow: hidden;
  font-size: 0.92rem;
}
.tbl-opt-b thead th {
  background: var(--ink-04, rgba(0,0,0,0.04));
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--ink-45);
  font-weight: 600;
  padding: 11px 16px;
  text-align: left;
  border-bottom: var(--rule);
  white-space: nowrap;
}
.tbl-opt-b thead th.num { text-align: right; }
.tbl-opt-b tbody tr { transition: background 0.08s; }
.tbl-opt-b tbody tr:hover { background: rgba(0,0,0,0.025); }
.tbl-opt-b tbody td {
  padding: 14px 16px;
  border-bottom: var(--rule);
  vertical-align: middle;
  line-height: 1.35;
}
.tbl-opt-b tbody td.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.tbl-opt-b tbody tr:last-child td { border-bottom: none; }
.tbl-opt-b .actions-cell { text-align: right; }
/* Compact pill variant used inside the Option-B table */
.tbl-opt-b .pill { font-size: 0.7rem; padding: 2px 8px; }

/* ── Meta-pair (label + value blocks inside cards) ─────────────────── */
/* Two-column grid used to render Holders / Linked banks / Tax-TDS info
   inside Open-FD cards. The label is small + muted; the value is the
   bold readable line; an optional sub adds further muted context. */
.meta-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px 24px;
}
.meta-pair--3col { grid-template-columns: repeat(3, 1fr); }
.meta-pair__label {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ink-45);
  font-weight: 500;
}
.meta-pair__value {
  font-size: 0.95rem;
  margin-top: 3px;
  font-weight: 500;
}
.meta-pair__sub {
  font-size: 0.78rem;
  color: var(--ink-65);
  margin-top: 1px;
}

/* ── Field grid (Add-FD form sections) ─────────────────────────────── */
.field-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px 22px;
}
.field-grid--3col { grid-template-columns: 1fr 1fr 1fr; }
.field-grid--full { grid-template-columns: 1fr; }
.field-grid .field { display: flex; flex-direction: column; }
.field-grid .field__label {
  font-size: 0.78rem;
  color: var(--ink-65);
  margin-bottom: 5px;
  font-weight: 500;
}
.field-grid .field__label .req { color: var(--danger); margin-left: 2px; }
.field-grid .field input[type="text"],
.field-grid .field input[type="date"],
.field-grid .field input[type="number"],
.field-grid .field select,
.field-grid .field textarea {
  padding: 8px 11px;
  border: var(--rule);
  border-radius: 5px;
  font: inherit;
  font-size: 0.9rem;
  background: var(--card, white);
  color: var(--ink);
  width: 100%;
}
.field-grid .field input:focus,
.field-grid .field select:focus { outline: 2px solid var(--forest-pale); outline-offset: 1px; }
.field-grid .field__hint {
  font-size: 0.74rem;
  color: var(--ink-45);
  margin-top: 4px;
  line-height: 1.45;
}
.field-grid .field__check {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 0;
  font-size: 0.9rem;
}

/* Numbered section badge (①②③ on Add-FD form section headers) */
.opt-b-section-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--forest-pale);
  color: var(--forest);
  font-size: 0.78rem;
  font-weight: 600;
  margin-right: 8px;
}

/* ── Open-FD hero strip ────────────────────────────────────────────── */
.opt-b-hero {
  background: var(--card, white);
  border: var(--rule);
  border-radius: 10px;
  padding: 22px 26px;
  margin-bottom: 18px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.03);
}
.opt-b-hero__top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 14px;
}
.opt-b-hero__title {
  margin: 0;
  font-size: 1.5rem;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  line-height: 1.25;
}
.opt-b-hero__title-id {
  color: var(--ink-45);
  font-weight: 400;
  font-size: 1.05rem;
}
.opt-b-hero__title-status {
  font-size: 0.7rem;
  padding: 3px 10px;
}
.opt-b-hero__meta {
  margin: 4px 0 0 0;
  font-size: 0.88rem;
  color: var(--ink-65);
}
.opt-b-hero__cta {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-shrink: 0;
}
.opt-b-hero__metrics {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 18px 24px;
  padding: 16px 0 0;
  border-top: var(--rule-soft);
}
@media (max-width: 720px) {
  .opt-b-hero__metrics { grid-template-columns: repeat(2, 1fr); }
  .opt-b-hero__top { flex-direction: column; }
}
.opt-b-hero__metric { min-width: 0; }
.opt-b-hero__metric-label {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ink-45);
  margin-bottom: 4px;
  font-weight: 500;
}
.opt-b-hero__metric-value {
  font-size: 1.3rem;
  font-weight: 600;
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
}
.opt-b-hero__metric-sub {
  font-size: 0.78rem;
  color: var(--ink-65);
  margin-top: 2px;
  line-height: 1.4;
}

/* ── "What's next" alert strip ─────────────────────────────────────── */
.opt-b-alert {
  display: flex;
  align-items: center;
  gap: 14px;
  background: linear-gradient(180deg, #fffaee 0%, #fff5dd 100%);
  border: 1px solid #e8d49a;
  border-left: 4px solid var(--bronze);
  border-radius: 8px;
  padding: 14px 18px;
  margin-bottom: 18px;
}
.opt-b-alert__icon { font-size: 1.35rem; line-height: 1; }
.opt-b-alert__body { flex: 1; min-width: 0; }
.opt-b-alert__body strong { display: block; font-size: 0.95rem; }
.opt-b-alert__body .meta { color: var(--ink-65); font-size: 0.82rem; margin-top: 2px; }

/* ── 2-column row of cards (Holders + Banks side-by-side, etc.) ────── */
.opt-b-cols {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
  margin-bottom: 18px;
}
.opt-b-cols .opt-b-card { margin-bottom: 0; }
@media (max-width: 720px) {
  .opt-b-cols { grid-template-columns: 1fr; }
}

/* ── Add-FD 2-column layout (form + preview rail) ──────────────────── */
.opt-b-form-layout {
  display: grid;
  grid-template-columns: 1fr 340px;
  gap: 22px;
  align-items: start;
}
.opt-b-form-preview {
  position: sticky;
  top: 90px;
  background: var(--card, white);
  border: var(--rule);
  border-radius: 8px;
  padding: 18px 20px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.03);
}
.opt-b-form-preview__title {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-45);
  font-weight: 600;
  margin-bottom: 10px;
}
.opt-b-form-preview__row {
  padding: 10px 0;
  border-top: var(--rule-soft);
}
.opt-b-form-preview__row:first-of-type {
  border-top: none;
  padding-top: 0;
}
.opt-b-form-preview__label {
  font-size: 0.72rem;
  color: var(--ink-45);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: 3px;
}
.opt-b-form-preview__value {
  font-size: 0.92rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}
@media (max-width: 980px) {
  .opt-b-form-layout { grid-template-columns: 1fr; }
  .opt-b-form-preview { position: static; }
}
.opt-b-form-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  padding-top: 20px;
  border-top: var(--rule);
  margin-top: 10px;
}

/* ── Add-FD form: re-style the existing <fieldset> blocks ────────────
 *
 * The _form.html partial uses <fieldset> + <legend> for each of its 8
 * sections (FD identity, Holders, Money & tenure, Tax/TDS, Payout
 * config, Nominee, Linked banks, Other). Each fieldset has inline
 * styles applied directly in the template — to keep the partial
 * untouched (1700 lines of wired Alpine + combobox state, risky to
 * rewrite), we override its visual treatment via descendant
 * selectors under .opt-b-form-shell.
 *
 * Result: fieldsets read as Option-B cards (white bg, soft shadow,
 * generous padding) and legends get the bronze numbered badge (①②③…)
 * via a CSS counter — purely presentational, the underlying form
 * markup is unchanged.
 * --------------------------------------------------------------- */
.opt-b-form-shell {
  counter-reset: opt-b-section;
}
.opt-b-form-shell fieldset {
  /* Override the inline border/padding from _form.html with the
     Option-B card treatment. ``!important`` because the source
     uses inline ``style=""`` attributes that would otherwise win. */
  background: var(--card, white) !important;
  border: var(--rule) !important;
  border-radius: 8px !important;
  padding: 22px 26px 18px !important;
  margin-bottom: 18px !important;
  box-shadow: 0 1px 2px rgba(0,0,0,0.03);
}
.opt-b-form-shell fieldset > legend {
  counter-increment: opt-b-section;
  /* Wipe the inline padding from the template — we use our own. */
  padding: 0 !important;
  margin: 0 0 12px 0;
  font-size: 1rem !important;
  font-weight: 600 !important;
  color: var(--ink) !important;
  letter-spacing: 0 !important;
  text-transform: none !important;
  display: flex;
  align-items: center;
  gap: 0;
}
/* The numbered ①②③ badge — pseudo-element so we don't have to edit
   the template. Counter resets at .opt-b-form-shell, increments on
   each <fieldset>'s legend. */
.opt-b-form-shell fieldset > legend::before {
  content: counter(opt-b-section);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--forest-pale);
  color: var(--forest);
  font-size: 0.78rem;
  font-weight: 600;
  margin-right: 10px;
  flex-shrink: 0;
}

/* ============================================================================
   Watchlist (Phase WL-1, 2026-06-07)
   ----------------------------------------------------------------------------
   Per-check panel on /watchlist. WL-4 will add a severity-grouped landing
   header above this; the panels themselves stay the same shape.
   ============================================================================ */
/* Phase WL-Polish (2026-06-07): per-check panel reworked to match
   the FD-masters white/grey card design. Key changes:
     * Pure white card with 1px border + tiny shadow (was paper-tinted
       with a 4px coloured left border — too heavy for browsing 8+
       module sections in a row).
     * Severity moved from a big left-bar to a small pill on the
       title row, so colour is a cue, not the dominant element.
     * Rows use the established ``.cell-primary`` / ``.cell-secondary``
       two-line idiom so finding labels read like other masters lists.
     * Dropped ``var(--amber)`` (undefined token — the warning
       border-left used to render transparent).  */
.wl-check-panel {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 16px 20px;
  margin: 10px 0 14px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
}
/* Severity is now indicated by the pill on the right of the title row
   only — we keep the rule selectors for future tints but render no
   border-left here. If you want a return to coloured rails, set
   ``border-left: 4px solid <colour>; padding-left: 16px;`` per class. */
.wl-check-panel--info,
.wl-check-panel--warning,
.wl-check-panel--critical { /* intentional no-op — colour lives on the pill */ }

.wl-check-panel__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 4px;
  gap: 10px;
}
.wl-check-panel__title {
  font-size: 1.0rem;
  margin: 0;
  font-weight: 600;
  flex: 1;
}
.wl-check-panel__count {
  font-weight: 400;
  color: var(--ink-65);
  margin-left: 4px;
  font-size: 0.92rem;
}
.wl-check-panel__severity {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.68rem;
  font-weight: 700;
  padding: 3px 9px;
  border-radius: 999px;
  white-space: nowrap;
}
.wl-check-panel__severity--info     { background: #e6ede7;  color: var(--forest); }
.wl-check-panel__severity--warning  { background: #fceec3;  color: #6b4a00;       }
.wl-check-panel__severity--critical { background: #fde8e4;  color: #8a2418;       }

.wl-check-panel__desc {
  margin: 4px 0 10px 0;
  font-size: 0.86rem;
}

.wl-finding-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
.wl-finding {
  display: flex;
  gap: 12px;
  align-items: center;
  padding: 10px 0;
  border-top: 1px solid var(--border);
}
.wl-finding:first-child { border-top: 0; padding-top: 6px; }
.wl-finding__main { flex: 1; min-width: 0; }
/* Two-line cell idiom — borrowed from .cell-primary / .cell-secondary
   so finding rows read like the FD masters list. */
.wl-finding__label {
  font-weight: 600;
  color: var(--ink);
  line-height: 1.35;
}
.wl-finding__why {
  font-size: 0.82rem;
  color: var(--ink-65);
  margin-top: 2px;
  line-height: 1.4;
}

.wl-registry {
  margin-top: 28px;
  font-size: 0.86rem;
}
.wl-registry summary { cursor: pointer; }
.wl-registry__list {
  margin-top: 8px;
  padding-left: 18px;
  line-height: 1.55;
}
.wl-registry__severity {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-left: 4px;
}

/* Phase WL-3 (2026-06-07) — Dismiss + Snooze buttons on finding rows. */
.wl-finding__actions {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  align-items: center;
}
.wl-inline-form { display: inline; margin: 0; }
.wl-btn--danger {
  color: #7a2018;
  border-color: #f4d3ce;
  background: #fff;
}
.wl-btn--danger:hover {
  background: #f4d3ce;
}

/* Phase WL-4 (2026-06-07) — Sidebar badge + summary header + filter chips. */
.sidebar__badge {
  margin-left: auto;
  background: #b13f30;
  color: #fff;
  font-size: 0.72rem;
  font-weight: 600;
  padding: 1px 8px;
  border-radius: 999px;
  min-width: 22px;
  text-align: center;
  line-height: 1.4;
}

.wl-summary {
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 18px 22px;
  margin: 10px 0 18px;
}
.wl-summary__h2 {
  font-size: 1.2rem;
  margin: 0 0 12px;
}
.wl-summary__tiles {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}
.wl-summary__tile {
  flex: 1 0 120px;
  background: #fff;
  border: 1px solid var(--border);
  border-left-width: 4px;
  border-radius: 6px;
  padding: 10px 14px;
  display: flex;
  flex-direction: column;
}
.wl-summary__tile--critical { border-left-color: #b13f30; }
.wl-summary__tile--warning  { border-left-color: #b8860b; }
.wl-summary__tile--info     { border-left-color: var(--bronze); }
.wl-summary__count {
  font-size: 1.8rem;
  font-weight: 600;
  line-height: 1;
}
.wl-summary__label {
  font-size: 0.82rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-65);
  margin-top: 4px;
}
.wl-summary__sub {
  margin: 12px 0 8px;
  font-size: 0.88rem;
}
.wl-summary__clear {
  margin-left: 8px;
  font-weight: 500;
}
.wl-summary__filters {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 6px;
}
.wl-chip {
  display: inline-block;
  padding: 3px 12px;
  border-radius: 999px;
  background: #fff;
  border: 1px solid var(--border);
  font-size: 0.84rem;
  text-decoration: none;
  color: var(--ink);
  text-transform: capitalize;
}
.wl-chip:hover    { border-color: var(--forest); }
.wl-chip--active  { background: var(--forest); color: #fff; border-color: var(--forest); }
.wl-chip--critical { color: #7a2018; }
.wl-chip--warning  { color: #7a5500; }
.wl-chip--info     { color: var(--forest); }
.wl-chip--active.wl-chip--critical,
.wl-chip--active.wl-chip--warning,
.wl-chip--active.wl-chip--info { color: #fff; }

/* Phase WL-5 (2026-06-07) — builder UI rows + saved-checks list. */
.wl-cond-row {
  display: grid;
  grid-template-columns: 1.5fr 1fr 2fr auto;
  gap: 8px;
  margin: 6px 0;
  align-items: center;
}
.wl-saved-list {
  list-style: none;
  padding: 0;
  margin: 8px 0;
}
.wl-saved-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: 6px;
  margin-bottom: 6px;
  background: var(--paper);
}

/* Phase WL-Report-Skin (2026-06-07) — landing-page chrome.
   Re-skin of /watchlist to the polished scheduled-report look:
   white "paper" panel inside the body backdrop, serif hero with
   bronze underline accent, soft pastel KPI tiles, sectioned blocks,
   muted footer with the brand-mark right-aligned.

   None of the previous .wl-check-panel / .wl-mod-section / .wl-finding
   rules are replaced — they're nested INSIDE these new section blocks
   so their styling carries over with the polish from the last pass. */
.wl-report {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 32px 40px 24px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
}
@media (max-width: 720px) {
  .wl-report { padding: 22px 18px 18px; }
}

/* Hero — serif title with bronze rule accent + muted subtitle + CTA. */
.wl-report-hero {
  padding-bottom: 22px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 26px;
}
.wl-report-hero__title {
  font-family: var(--serif);
  font-size: 2.4rem;
  font-weight: 600;
  line-height: 1.15;
  margin: 0;
  color: var(--ink);
  display: inline-block;
  border-bottom: 3px solid var(--bronze);
  padding-bottom: 4px;
}
.wl-report-hero__subtitle {
  font-size: 0.95rem;
  margin: 14px 0 0;
  max-width: 720px;
}
.wl-report-hero__actions {
  margin-top: 14px;
}

/* Section block — serif h2 + small icon. */
.wl-report-section {
  margin: 26px 0;
}
.wl-report-section__title {
  font-family: var(--serif);
  font-size: 1.3rem;
  font-weight: 600;
  margin: 0 0 14px;
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--ink);
}
.wl-report-section__icon {
  display: inline-flex;
  width: 20px;
  height: 20px;
  color: var(--forest);
}
.wl-report-section__icon .icon-glyph { width: 100%; height: 100%; }
.wl-report-section__clear {
  margin-left: auto;
  font-family: var(--sans, system-ui);
  font-size: 0.82rem;
  font-weight: 500;
}

/* KPI tile grid — soft pastel circular icon + label + value. */
.wl-kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px;
}
.wl-kpi-tile {
  display: flex;
  align-items: center;
  gap: 12px;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 14px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
}
.wl-kpi-tile__icon {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.wl-kpi-tile__icon .icon-glyph { width: 18px; height: 18px; }
.wl-kpi-tile--all      .wl-kpi-tile__icon { background: #e6ede7; color: var(--forest); }
.wl-kpi-tile--critical .wl-kpi-tile__icon { background: #fde8e4; color: #8a2418; }
.wl-kpi-tile--warning  .wl-kpi-tile__icon { background: #fceec3; color: #6b4a00; }
.wl-kpi-tile--info     .wl-kpi-tile__icon { background: #e6ede7; color: var(--forest); }
.wl-kpi-tile--modules  .wl-kpi-tile__icon { background: #f5ebd2; color: #8a6b1f; }
.wl-kpi-tile--checks   .wl-kpi-tile__icon { background: #e8eaef; color: #44557a; }
.wl-kpi-tile__body { min-width: 0; }
.wl-kpi-tile__label {
  font-size: 0.78rem;
  color: var(--ink-65);
  margin-bottom: 1px;
  font-weight: 500;
}
.wl-kpi-tile__value {
  font-size: 1.45rem;
  font-weight: 700;
  color: var(--ink);
  line-height: 1.1;
}

/* Filter chip row — re-uses .wl-chip but lives inside a section block. */
.wl-filter-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

/* By-Module summary table — green header + alternating rows + dot
   indicators per severity column. Mirrors the report-design grid. */
.wl-report-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 0.9rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
}
.wl-report-table thead th {
  background: var(--forest);
  color: #fff;
  text-align: left;
  padding: 9px 12px;
  font-weight: 600;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.wl-report-table tbody td {
  padding: 9px 12px;
  border-top: 1px solid var(--border);
  vertical-align: middle;
}
.wl-report-table tbody tr:nth-child(even) td { background: #fbfaf6; }
.wl-report-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.wl-report-table__mod {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 500;
}
.wl-report-table__icon {
  display: inline-flex;
  width: 16px;
  height: 16px;
  color: var(--forest);
}
.wl-report-table__icon .icon-glyph { width: 100%; height: 100%; }
.wl-report-table__total { font-weight: 700; }
.wl-report-table__link { color: var(--forest); font-weight: 500; text-decoration: none; }
.wl-report-table__link:hover { text-decoration: underline; }
.wl-report-table tfoot td {
  background: #f3f1e9;
  border-top: 2px solid var(--border);
  padding: 10px 12px;
  font-weight: 700;
}

/* Severity dots — tiny coloured circles next to counts. */
.wl-sev-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  margin-right: 6px;
  vertical-align: 1px;
}
.wl-sev-dot--critical { background: #b13f30; }
.wl-sev-dot--warning  { background: #b8860b; }
.wl-sev-dot--info     { background: var(--forest); }

/* Report footer — generation stamp + brand mark, two-column. */
.wl-report-footer {
  margin-top: 32px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
}
.wl-report-footer__stamp { font-size: 0.82rem; }
.wl-report-footer__brand .brand-mark { font-size: 0.95rem; }

/* Phase WL-9 (2026-06-07) — Module-grouped landing sections.
   Each section header carries the module icon + label + total count
   + an "Open module" deep-link. Per-check panels nest underneath. */
.wl-mod-section {
  margin: 18px 0 0;
}
.wl-mod-section__head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 6px;
  padding: 6px 4px 6px 0;
  border-bottom: 2px solid var(--border);
}
.wl-mod-section__icon {
  display: inline-flex;
  width: 22px;
  height: 22px;
  color: var(--forest);
}
.wl-mod-section__icon .icon-glyph { width: 100%; height: 100%; }
.wl-mod-section__title {
  font-size: 1.15rem;
  margin: 0;
  flex: 1;
  font-weight: 600;
}
.wl-mod-section__count {
  color: var(--ink-65);
  font-weight: 400;
  font-size: 0.95rem;
}
.wl-mod-section__link {
  flex-shrink: 0;
}
/* The wl-check-panel inside a section indents slightly so the
   hierarchy reads visually as section → per-check group → rows. */
.wl-mod-section .wl-check-panel {
  margin-left: 8px;
}

/* Module chip with inline icon (used in the summary filter row). */
.wl-chip__icon {
  display: inline-flex;
  width: 14px;
  height: 14px;
  vertical-align: -2px;
  margin-right: 4px;
}
.wl-chip__icon .icon-glyph { width: 100%; height: 100%; }
.wl-chip--mod {
  text-transform: none;
}

/* Phase WL-8.2 (2026-06-07) — Builder pills (subject + severity) +
   smart value affixes. The pill row replaces both the subject and
   severity dropdowns with iconed buttons; the value-affix wraps the
   single ``name="value"`` input with a ₹ prefix or "days" suffix. */
.wl-pill-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 4px 0 0;
}
.wl-mod-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: #fff;
  color: var(--ink);
  font-size: 0.88rem;
  cursor: pointer;
  transition: border-color 0.12s, background 0.12s, color 0.12s;
}
.wl-mod-pill:hover {
  border-color: var(--forest);
}
.wl-mod-pill__icon {
  display: inline-flex;
  width: 16px;
  height: 16px;
}
.wl-mod-pill__icon .icon-glyph {
  width: 100%;
  height: 100%;
}
.wl-mod-pill--active {
  background: var(--forest);
  color: #fff;
  border-color: var(--forest);
}
.wl-mod-pill--active .wl-mod-pill__icon { color: #fff; }

/* Phase WL-Pill-Fix (2026-06-07): severity pills.
   - Inactive: solid background tint + dark contrast text, so the
     label is clearly readable even when not selected (the previous
     "tinted text on white" pass had a contrast problem — Warning
     in light amber on white was nearly invisible).
   - Active: solid colour + bold white text + a 2px ring so the
     selected pill genuinely pops vs. the inactive ones.
   The hardcoded hex pair (text + bg) avoids the unresolved
   ``var(--amber)`` token that previously broke the active Warning
   pill entirely. */
.wl-sev-pill {
  padding: 6px 16px;
  border-radius: 999px;
  border: 1px solid transparent;
  font-size: 0.88rem;
  font-weight: 600;
  cursor: pointer;
  text-transform: capitalize;
  transition: background 0.12s, color 0.12s, box-shadow 0.12s;
}
.wl-sev-pill--critical { background: #fde8e4; color: #8a2418; border-color: #f3c8c0; }
.wl-sev-pill--warning  { background: #fceec3; color: #6b4a00; border-color: #ead08a; }
.wl-sev-pill--info     { background: #e6ede7; color: var(--forest); border-color: #c8d3ca; }
.wl-sev-pill:hover     { filter: brightness(0.97); }
.wl-sev-pill--active.wl-sev-pill--critical { background: #b13f30; color: #fff; border-color: #b13f30; box-shadow: 0 0 0 2px rgba(177, 63, 48, 0.18); }
.wl-sev-pill--active.wl-sev-pill--warning  { background: #b8860b; color: #fff; border-color: #b8860b; box-shadow: 0 0 0 2px rgba(184, 134, 11, 0.18); }
.wl-sev-pill--active.wl-sev-pill--info     { background: var(--forest); color: #fff; border-color: var(--forest); box-shadow: 0 0 0 2px rgba(26, 46, 31, 0.18); }

/* Smart value slot — wraps the single ``name="value"`` input with a
   ₹ prefix or "days" suffix span. The input keeps its full width
   minus the affix; layout uses inline-flex so the affix sits next to
   the box instead of stacking above. */
.wl-cond-value {
  display: inline-flex;
  align-items: stretch;
  gap: 0;
}
.wl-cond-value__input {
  flex: 1;
}
.wl-cond-value__prefix,
.wl-cond-value__suffix {
  display: inline-flex;
  align-items: center;
  padding: 0 10px;
  background: var(--paper);
  border: 1px solid var(--border);
  font-size: 0.92rem;
  color: var(--ink-65);
  font-weight: 500;
}
.wl-cond-value--prefix .wl-cond-value__input {
  border-left: none;
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}
.wl-cond-value--prefix .wl-cond-value__prefix {
  border-right: none;
  border-top-left-radius: 6px;
  border-bottom-left-radius: 6px;
}
.wl-cond-value--suffix .wl-cond-value__input {
  border-right: none;
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}
.wl-cond-value--suffix .wl-cond-value__suffix {
  border-left: none;
  border-top-right-radius: 6px;
  border-bottom-right-radius: 6px;
}
.wl-cond-value--nullary .wl-cond-value__input {
  background: var(--paper);
  color: var(--ink-65);
  font-style: italic;
}

/* Phase WL-Builder-Fix (2026-06-07) — Searchable field combobox for
   the conditions row. Mirrors the existing /combobox visual idiom
   (typeahead input + dropdown list with hover/active rows) but lives
   inline inside the watchlistBuilder Alpine scope so each condition
   row keeps its own open/search state on the condition object. */
.wl-field-combo {
  position: relative;
}
.wl-field-combo > input[type="text"] {
  width: 100%;
}
.wl-field-combo__list {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 30;
  margin: 2px 0 0;
  padding: 4px 0;
  list-style: none;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 6px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.08);
  max-height: 240px;
  overflow-y: auto;
}
.wl-field-combo__item {
  padding: 6px 12px;
  cursor: pointer;
  font-size: 0.92rem;
}
.wl-field-combo__item:hover,
.wl-field-combo__item--active {
  background: var(--paper);
  color: var(--forest);
}
.wl-field-combo__empty {
  padding: 6px 12px;
  font-size: 0.88rem;
}

/* Phase WL-5-Preview (2026-06-07) — Builder "Run now" results panel. */
.wl-preview-panel {
  background: var(--paper);
  border: 1px solid var(--border);
  border-left: 4px solid var(--forest);
  border-radius: 10px;
  padding: 14px 18px;
}
.wl-preview-panel__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 6px;
}
.wl-preview-panel__title {
  font-size: 1.0rem;
  margin: 0;
  font-weight: 600;
}
.wl-preview-panel__error {
  color: #b13f30;
  font-size: 0.92rem;
  margin: 4px 0 0;
}
.wl-preview-list {
  list-style: none;
  padding: 0;
  margin: 6px 0 8px;
  max-height: 360px;
  overflow-y: auto;
}
.wl-preview-row {
  padding: 6px 0;
  border-bottom: 1px dashed var(--border);
  font-size: 0.92rem;
}
.wl-preview-row:last-child { border-bottom: none; }
.wl-preview-row__label { font-weight: 500; }
.wl-preview-row__why   { margin-left: 6px; }

/* Phase WL-6 (2026-06-07) — Watchlist alert tile on /overview.
   Slimmer, single-row aesthetic vs. the /watchlist summary card —
   the dashboard tile is meant to be a nudge, not the whole story. */
.wl-tile {
  background: var(--paper);
  border: 1px solid var(--border);
  border-left: 4px solid #b13f30;
  border-radius: 10px;
  padding: 14px 18px;
  margin: 10px 0 18px;
}
.wl-tile__head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.wl-tile__title {
  font-size: 1.05rem;
  margin: 0;
  font-weight: 600;
}
.wl-tile__pills {
  list-style: none;
  padding: 0;
  margin: 10px 0 0;
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}
