:root {
  --bg-app: #0b0d10;
  --bg-panel: #13161b;
  --bg-panel-hi: #181c22;
  --border: rgba(255, 255, 255, 0.06);
  --border-strong: rgba(255, 255, 255, 0.12);
  /* Quiet neutral wash for nav hover. Translucent rather than a fixed step
     because the nav sits on --bg-app while its mobile dropdown sits on
     --bg-panel, and this has to read correctly on both. */
  --nav-wash: rgba(255, 255, 255, 0.07);
  /* Active nav state — brass, concept A's chrome accent. Deliberately NOT
     --accent: that blue is the same family as the dashboards' "under budget"
     data colour, so an accent-blue pill would compete with the encoding.
     Brass measures dE 32 from under-budget blue and dE 16 from over-budget
     red, so it can't be mistaken for a data mark. */
  --nav-active: #d9a441;
  --nav-active-ink: #0b0d10;
  --text: #e6e9ef;
  --text-dim: #8a93a3;
  --text-muted: #5b6371;
  --accent: #4ea1ff;
  --accent-dim: #2a3340;
  --accent-2: #9b6bff;
  --accent-glow: rgba(78, 161, 255, 0.30);
  --accent-haze: rgba(78, 161, 255, 0.16);
  --auth-card-bg: rgba(19, 22, 27, 0.72);
  --pos: #22c55e;
  --pos-bg: rgba(34, 197, 94, 0.10);
  --pos-bg-subtle: rgba(34, 197, 94, 0.04);
  --neg: #ef4444;
  --neg-bg: rgba(239, 68, 68, 0.10);
  --shadow-overlay: 0 10px 40px rgba(0, 0, 0, 0.6);

  --font-sans: 'Inter', -apple-system, 'Segoe UI', system-ui, sans-serif;
  --font-mono: ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, Consolas, monospace;
}

:root[data-theme="light"] {
  --bg-app: #f4f5f8;
  --bg-panel: #ffffff;
  --bg-panel-hi: #f7f8fb;
  --border: rgba(0, 0, 0, 0.08);
  --border-strong: rgba(0, 0, 0, 0.14);
  --nav-wash: rgba(0, 0, 0, 0.055);
  /* #8a6413, not the darker brass used for chart ink: white on it measures
     5.37:1, which keeps AA headroom. */
  --nav-active: #8a6413;
  --nav-active-ink: #ffffff;
  --text: #1a1d23;
  --text-dim: #5b6371;
  --text-muted: #9aa3b2;
  --accent: #2563eb;
  --accent-dim: #dbeafe;
  --accent-2: #7c3aed;
  --accent-glow: rgba(37, 99, 235, 0.22);
  --accent-haze: rgba(37, 99, 235, 0.12);
  --auth-card-bg: rgba(255, 255, 255, 0.82);
  --pos: #16a34a;
  --pos-bg: rgba(22, 163, 74, 0.10);
  --pos-bg-subtle: rgba(22, 163, 74, 0.04);
  --neg: #dc2626;
  --neg-bg: rgba(220, 38, 38, 0.10);
  --shadow-overlay: 0 10px 40px rgba(15, 23, 42, 0.18);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg-app);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 13px;
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}

.num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum';
}

.app {
  display: grid;
  gap: 12px;
  padding: 12px;
  max-width: 1600px;
  margin: 0 auto;
}

/* ─────────── global nav bar ───────────
   Styled after the Verdict dashboard (concept A): the bar sits on the page
   ground beneath a hairline rather than reading as a filled panel, is given
   room to breathe, and carries a wordmark with a muted tail.

   Its links wear a quiet neutral wash instead of the old accent-blue pill,
   deliberately: --accent is the same blue family as the dashboards' "under
   budget" data colour (--d4-under / --d5-under), so an accent-blue nav pill
   competed with the encoding. Chrome stays neutral here so blue means "under
   budget" and nothing else — the same rule concept A applied to its brass. */
.navbar {
  position: sticky;
  top: 0;
  z-index: 90;
  /* The ground colour, not a panel — but opaque, so content scrolling under a
     sticky bar can't show through. */
  background: var(--bg-app);
  border-bottom: 1px solid var(--border);
}
.navbar-inner {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  height: 60px;
  padding: 0 16px;
  max-width: 1600px;
  margin: 0 auto;
}
.navbar-toggle {
  display: none;
  flex: 0 0 auto;
}
.navbar-brand {
  font-size: 15px;
  font-weight: 620;
  letter-spacing: -0.01em;
  color: var(--text);
  text-decoration: none;
  white-space: nowrap;
}
.navbar-brand-tail {
  /* --text-dim, not --text-muted: muted measures 2.33:1 on the light ground,
     under the 3:1 floor. Still clearly recessive against --text beside it. */
  color: var(--text-dim);
  font-weight: 450;
}
.navbar-links {
  display: flex;
  align-items: center;
  gap: 2px;
  list-style: none;
  margin: 0 0 0 18px;
  padding: 0;
}
.navbar-links a {
  display: inline-flex;
  align-items: center;
  height: 30px;
  padding: 0 11px;
  border-radius: 5px;
  font-size: 13px;
  font-weight: 500;
  /* Resting links stay on --text-dim (6.3:1 dark / 5.6:1 light). Concept A's
     mockup used a quieter ink here, but measured against these grounds it fell
     to 2.3:1 in light mode — below the 3:1 floor for interactive text. The
     quiet character comes from the neutral wash and the hue restraint, not
     from under-contrasting the labels. */
  color: var(--text-dim);
  text-decoration: none;
  transition: background 90ms, color 90ms;
}
.navbar-links a:hover {
  color: var(--text);
  background: var(--nav-wash);
}
/* Solid brass fill, not a tint: a tinted pill measured only dE 1.7 from the
   neutral hover wash in light mode — active and hover were near-identical. The
   fill lands dE 53 (dark) / 38 (light) clear of hover, so the current page is
   unmistakable. Ink passes AA on both (8.65:1 dark, 5.37:1 light). */
.navbar-links a.active {
  color: var(--nav-active-ink);
  font-weight: 600;
  background: var(--nav-active);
}
.navbar-links a.active:hover {
  color: var(--nav-active-ink);
  background: var(--nav-active);
  filter: brightness(1.06);
}

.navbar-right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
}
.nav-cog { margin-left: 0; }
.icon-btn.active {
  color: var(--nav-active-ink);
  background: var(--nav-active);
  border-color: var(--nav-active);
}
/* Needs the extra class: .icon-btn:hover is declared further down the file at
   the same specificity as .icon-btn.active, so without this the active cog
   loses its fill the moment you hover it. */
.icon-btn.active:hover {
  color: var(--nav-active-ink);
  background: var(--nav-active);
  border-color: var(--nav-active);
  filter: brightness(1.06);
}
.navbar-account {
  position: relative;
}
.account-trigger {
  margin-left: 0;
  border-radius: 50%;
}
.account-menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: 240px;
  padding: 6px;
  background: var(--bg-panel);
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  box-shadow: var(--shadow-overlay);
  z-index: 95;
}
.account-id {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 10px;
}
.account-name {
  font-weight: 600;
  color: var(--text);
}
.account-email {
  font-size: 11px;
  color: var(--text-dim);
  word-break: break-all;
}
.account-menu-sep {
  height: 1px;
  margin: 6px 0;
  background: var(--border);
}
.account-item {
  display: block;
  width: 100%;
  padding: 8px 10px;
  appearance: none;
  background: transparent;
  border: 0;
  border-radius: 4px;
  font: inherit;
  font-size: 13px;
  text-align: left;
  color: var(--text);
  cursor: pointer;
}
.account-item:hover {
  background: var(--bg-panel-hi);
}
.account-note {
  margin: 6px 10px 4px;
  font-size: 11px;
  line-height: 1.5;
  color: var(--text-dim);
}

/* ─────────── header ─────────── */
.header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 16px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 4px;
}

.brand {
  display: flex;
  align-items: baseline;
  gap: 10px;
}
.brand h1 {
  font-size: 16px;
  font-weight: 600;
  letter-spacing: 0.02em;
  margin: 0;
  text-transform: uppercase;
}
.brand .dot {
  color: var(--text-muted);
}
.brand .sub {
  color: var(--text-dim);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.seg-switch {
  display: flex;
  gap: 2px;
  background: var(--bg-app);
  padding: 3px;
  border: 1px solid var(--border);
  border-radius: 4px;
}
.seg-switch button {
  appearance: none;
  background: transparent;
  border: 0;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.05em;
  padding: 5px 10px;
  border-radius: 3px;
  cursor: pointer;
  transition: background 90ms, color 90ms;
}
.seg-switch button:hover {
  color: var(--text);
  background: var(--bg-panel-hi);
}
.seg-switch button.active {
  background: var(--accent-dim);
  color: var(--accent);
}

.month-picker {
  display: flex;
  align-items: stretch;
  background: var(--bg-app);
  border: 1px solid var(--border);
  border-radius: 4px;
  overflow: hidden;
}
.month-picker .month-step {
  appearance: none;
  background: transparent;
  border: 0;
  color: var(--text-dim);
  font-size: 16px;
  line-height: 1;
  width: 28px;
  cursor: pointer;
  transition: background 90ms, color 90ms;
  padding: 0;
}
.month-picker .month-step:hover:not(:disabled) {
  color: var(--text);
  background: var(--bg-panel-hi);
}
.month-picker .month-step:disabled {
  color: var(--text-muted);
  cursor: not-allowed;
  opacity: 0.5;
}
.month-picker select {
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  border: 0;
  border-left: 1px solid var(--border);
  border-right: 1px solid var(--border);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  padding: 6px 10px;
  cursor: pointer;
  min-width: 110px;
  text-align: center;
  text-align-last: center;
}
.month-picker select:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
.month-picker select option {
  background: var(--bg-panel);
  color: var(--text);
}

.meta {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  font-size: 11px;
}
.meta .label {
  color: var(--text-muted);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.meta .value {
  color: var(--text-dim);
  font-family: var(--font-mono);
}

/* ─────────── KPI strip ─────────── */
.kpi-strip {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 8px;
}
@media (max-width: 1500px) {
  .kpi-strip {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}
.kpi {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 12px 16px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  position: relative;
  overflow: hidden;
}
.kpi .label {
  font-size: 10px;
  color: var(--text-muted);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.kpi .value {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.kpi .sub {
  font-size: 11px;
  color: var(--text-dim);
  font-family: var(--font-mono);
}
.kpi.pos .value { color: var(--pos); }
.kpi.neg .value { color: var(--neg); }
.kpi .accent-bar {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 2px;
  background: var(--accent);
}
.kpi.pos .accent-bar { background: var(--pos); }
.kpi.neg .accent-bar { background: var(--neg); }

/* ─────────── panels ─────────── */
.panel {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 4px;
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;   /* grid items default to min-width: auto — without this, a
                     wide table inside (e.g. Budget vs. Actuals) stretches the
                     panel instead of scrolling within .budget-scroll */
}

.panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 16px;
  border-bottom: 1px solid var(--border);
}
.panel-header h2 {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin: 0;
}
.panel-header .legend {
  display: flex;
  gap: 12px;
  font-size: 11px;
  color: var(--text-dim);
}
.panel-header .legend .swatch {
  display: inline-block;
  width: 10px;
  height: 10px;
  margin-right: 6px;
  vertical-align: -1px;
  border-radius: 2px;
  background: var(--text-muted);
}
.panel-header .legend .swatch.budget {
  width: 18px;
  height: 0;
  margin-right: 6px;
  border: 0;
  border-top: 1.5px dashed var(--accent);
  background: transparent;
  border-radius: 0;
  vertical-align: 3px;
}
.panel-header .legend .swatch.actual {
  width: 18px;
  height: 2px;
  background: var(--text);
  border-radius: 0;
  vertical-align: 3px;
}
#stack-legend {
  flex-wrap: wrap;
  gap: 6px 14px;
  max-width: 70%;
  justify-content: flex-end;
}
#stack-legend .legend-item {
  white-space: nowrap;
}

.panel-body {
  padding: 12px 16px;
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.chart-host {
  position: relative;
  height: clamp(320px, 42vh, 480px);
}

/* ─────────── category table ─────────── */
.cat-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}
.cat-table thead th {
  text-align: right;
  padding: 8px 12px;
  font-weight: 600;
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
.cat-table thead th:first-child { text-align: left; }
.cat-table thead th:hover { color: var(--text-dim); }
.cat-table thead th.sorted { color: var(--accent); }
.cat-table thead th .sort-ind {
  display: inline-block;
  width: 8px;
  color: var(--accent);
  margin-left: 4px;
}

.cat-table tbody tr {
  border-bottom: 1px solid var(--border);
  transition: background 90ms;
}
.cat-table tbody tr:hover {
  background: var(--bg-panel-hi);
}
.cat-table tbody td {
  padding: 9px 12px;
  text-align: right;
  white-space: nowrap;
}
.cat-table tbody td.name {
  text-align: left;
  color: var(--text);
  font-weight: 500;
}
/* Content-fit the Name column (no dead space); the Progress column above takes
   the slack. min-width: max-content on the group label overrides the global
   .grp-label { min-width: 0 } so the group header's width is counted. */
.cat-table thead th:first-child,
.cat-table tbody td.name { width: 1px; }
.cat-table .grp-head .grp-label { flex: 0 0 auto; min-width: max-content; white-space: nowrap; }
.cat-table tbody td.figure {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.cat-table tbody td.muted {
  color: var(--text-dim);
}
.cat-table tbody tr.over .var,
.cat-table tbody tr.over .var-pct {
  color: var(--neg);
}
.cat-table tbody tr.over {
  background: linear-gradient(to right, var(--neg-bg), transparent 60%);
}
.cat-table tbody tr.under .var,
.cat-table tbody tr.under .var-pct {
  color: var(--pos);
}
.cat-table tbody tr.under {
  background: linear-gradient(to right, var(--pos-bg), transparent 60%);
}
.cat-table .arrow {
  display: inline-block;
  width: 10px;
  margin-right: 4px;
}

/* closing subtotal row at the bottom of each group */
.cat-table tbody tr.grp-foot td {
  background: var(--bg-panel-hi);
  border-top: 2px solid var(--border-strong);
  border-bottom: 2px solid var(--border-strong);
}
.cat-table tbody tr.grp-foot td.figure {
  font-weight: 700;
  font-size: 14px;
  color: var(--text);
}
.bva-grid tr.grp-foot td { border-top: 2px solid var(--border-strong); background: var(--bg-panel-hi); }
.grp-foot-label {
  color: var(--text-dim);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* budget group headers — collapsible, carry the group's subtotals */
.cat-table tbody tr.grp-row {
  background: var(--bg-panel-hi);
  border-bottom: 5px solid var(--border-strong);
  cursor: pointer;
}
.cat-table tbody tr.grp-row:hover { background: var(--bg-app); }
.cat-table tbody tr.grp-row td.figure { font-weight: 700; }
.cat-table .grp-head {
  display: flex;
  align-items: center;
  gap: 8px;
}
.cat-table .grp-caret {
  display: inline-block;
  width: 12px;
  font-size: 10px;
  color: var(--text-muted);
}
.cat-table .grp-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text);
}
.cat-table tbody tr.grp-member.grp-collapsed { display: none; }

/* group reorder (drag handle) + drag feedback — shared by dashboard + budgets */
.grp-drag {
  cursor: grab;
  color: var(--text-muted);
  font-size: 12px;
  line-height: 1;
  user-select: none;
  padding: 0 2px;
}
.grp-drag:active { cursor: grabbing; }
.grp-drag:hover { color: var(--text); }
tr.grp-dragging { opacity: 0.45; }
tr.grp-drop-target td { box-shadow: inset 0 2px 0 0 var(--accent); }
.cat-table .grp-caret { cursor: pointer; }

/* progress bar cell — shows actual / budget ratio */
.cat-table td.progress {
  width: 100%;          /* greedy: soaks up the table's leftover width so Name can be content-fit */
  min-width: 260px;
  padding-right: 16px;
}
.progress-bar {
  position: relative;
  height: 6px;
  background: var(--bg-app);
  border: 1px solid var(--border);
  border-radius: 2px;
  overflow: hidden;
}
.progress-bar .fill {
  position: absolute;
  inset: 0 auto 0 0;
  background: var(--text-dim);
  transition: width 180ms ease-out;
}
.progress-bar .target {
  position: absolute;
  top: -2px;
  bottom: -2px;
  width: 1px;
  background: var(--text-dim);
  opacity: 0.6;
}
tr.over .progress-bar .fill  { background: var(--neg); }
tr.under .progress-bar .fill { background: var(--pos); }
.progress-bar.capped::after {
  content: '';
  position: absolute;
  right: 0; top: 0; bottom: 0;
  width: 3px;
  background: repeating-linear-gradient(
    -45deg,
    rgba(255,255,255,0.35) 0 2px,
    transparent 2px 4px
  );
}

/* ─────────── footer panel (stacked) ─────────── */
.footer-panel {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 4px;
  display: flex;
  flex-direction: column;
}
.footer-panel .panel-body {
  padding: 12px 16px;
}
.footer-panel .chart-host {
  height: 220px;
}

/* ─────────── responsive ─────────── */
@media (max-width: 1100px) {
  .kpi-strip {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* Global nav bar: the six links no longer fit once the window drops below
   ~1000px, well before phone width, so collapse into a hamburger dropdown. */
@media (max-width: 860px) {
  .navbar-toggle { display: inline-flex; }
  .navbar-links {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    margin: 0;
    padding: 8px;
    background: var(--bg-panel);
    border-bottom: 1px solid var(--border-strong);
    box-shadow: var(--shadow-overlay);
    z-index: 95;
  }
  .navbar-links.is-open { display: flex; }
  .navbar-links a { height: 40px; padding: 0 12px; }
}

@media (max-width: 640px) {
  /* Dashboard header: brand + settings stay on one row; the period switcher
     and month picker each take their own full-width row underneath, which
     reads far better than letting justify-content: space-between scatter
     them across wrapped lines. */
  .header {
    flex-wrap: wrap;
    gap: 10px;
  }
  .header .brand { flex: 1 1 auto; }
  .header #settings-trigger,
  .header .icon-btn { order: 1; margin-left: 0; }
  .header .meta { display: none; }
  .header .period-switcher {
    order: 3;
    flex: 1 1 100%;
    overflow-x: auto;
  }
  .header .month-picker {
    order: 4;
    flex: 1 1 100%;
  }
  .header .month-picker select { flex: 1 1 auto; }

  .kpi-strip {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Wide tables (budget grid, transactions) already scroll horizontally via
     .budget-scroll; just trim padding so more columns are visible at once. */
  .budget-grid th,
  .budget-grid td {
    padding: 6px 8px;
  }

  /* Panel headers with multiple control groups (e.g. Budget vs. Actuals' view
     switch + month nav + legend) would otherwise force the row — and the
     whole page — wider than the viewport. Let each group wrap onto its own
     line instead of overflowing sideways. */
  .panel-header {
    flex-wrap: wrap;
    row-gap: 10px;
  }
  .panel-header .bva-controls {
    flex: 1 1 100%;
    flex-wrap: wrap;
    row-gap: 10px;
  }
  .panel-header .legend {
    flex-wrap: wrap;
    row-gap: 6px;
  }
}

/* Chart.js tooltip overrides via dark palette baked into JS options */

/* ─────────── icon button ─────────── */
.icon-btn {
  appearance: none;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 4px;
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-dim);
  cursor: pointer;
  transition: background 90ms, color 90ms, border-color 90ms;
  padding: 0;
  margin-left: 12px;
}
.icon-btn:hover {
  color: var(--text);
  background: var(--bg-panel-hi);
  border-color: var(--border-strong);
}
.icon-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.icon-btn svg {
  width: 16px;
  height: 16px;
  display: block;
}

/* ─────────── settings drawer ─────────── */
.settings-overlay {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 100;
}
.settings-overlay .settings-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  opacity: 0;
  transition: opacity 180ms ease;
}
.settings-overlay .settings-drawer {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 320px;
  max-width: 92vw;
  background: var(--bg-panel);
  border-left: 1px solid var(--border-strong);
  box-shadow: var(--shadow-overlay);
  transform: translateX(100%);
  transition: transform 180ms ease;
  display: flex;
  flex-direction: column;
}
.settings-overlay.is-open {
  pointer-events: auto;
}
.settings-overlay.is-open .settings-backdrop {
  opacity: 1;
}
.settings-overlay.is-open .settings-drawer {
  transform: translateX(0);
}
body.has-overlay {
  overflow: hidden;
}

/* 1M view: the trend chart isn't useful with one data point. */
body.single-month #panel-combo {
  display: none;
}

.settings-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border);
}
.settings-header h2 {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin: 0;
}
.settings-close {
  appearance: none;
  background: transparent;
  border: 0;
  color: var(--text-dim);
  font-size: 18px;
  width: 28px;
  height: 28px;
  border-radius: 3px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  padding: 0;
}
.settings-close:hover {
  color: var(--text);
  background: var(--bg-panel-hi);
}

.settings-body {
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 18px;
  overflow-y: auto;
}
.settings-group {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.settings-group .group-label {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.settings-group .group-hint {
  font-size: 11px;
  color: var(--text-muted);
  line-height: 1.5;
}
.settings-group .seg-switch {
  align-self: stretch;
}
.settings-group .seg-switch button {
  flex: 1;
  padding: 7px 10px;
}

/* home sections: show/hide + reorder list (settings drawer) */
.module-hidden { display: none !important; }
.module-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-self: stretch;
}
.module-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  background: var(--bg-app);
  border: 1px solid var(--border);
  border-radius: 4px;
}
.module-row.module-dragging { opacity: 0.45; }
.module-row.module-drop { box-shadow: inset 0 2px 0 0 var(--accent); }
.module-drag {
  cursor: grab;
  color: var(--text-muted);
  font-size: 12px;
  line-height: 1;
  user-select: none;
  flex: 0 0 auto;
}
.module-drag:active { cursor: grabbing; }
.module-drag:hover { color: var(--text); }
.module-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  min-width: 0;
  font-size: 13px;
  color: var(--text);
  cursor: pointer;
}
.module-toggle input { flex: 0 0 auto; cursor: pointer; }

/* ─────────── buttons ─────────── */
.btn-primary {
  appearance: none;
  border: 0;
  border-radius: 4px;
  background: var(--accent);
  color: #fff;
  font: inherit;
  font-weight: 600;
  font-size: 13px;
  padding: 8px 16px;
  cursor: pointer;
  transition: filter 90ms;
}
.btn-primary:hover { filter: brightness(1.08); }
.btn-primary:disabled { opacity: 0.5; cursor: default; filter: none; }

.btn-ghost {
  appearance: none;
  border: 1px solid var(--border-strong);
  border-radius: 4px;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 13px;
  padding: 7px 14px;
  cursor: pointer;
  transition: background 90ms;
}
.btn-ghost:hover { background: var(--bg-panel-hi); }

.btn-danger {
  background: var(--neg);
  color: #fff;
}
.btn-danger:hover { filter: brightness(1.08); }

.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;
}

/* row delete button (uploaded statements) */
.row-del {
  appearance: none;
  background: transparent;
  border: 0;
  padding: 4px;
  border-radius: 4px;
  color: var(--text-muted);
  cursor: pointer;
  display: inline-flex;
  transition: color 90ms, background 90ms;
}
.row-del:hover { color: var(--neg); background: var(--neg-bg); }
.row-del:disabled { opacity: 0.5; cursor: default; }
.row-del svg { width: 15px; height: 15px; display: block; }

/* multi-select + bulk actions (transactions table) */
.bulk-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}
.bulk-actions[hidden] { display: none; }   /* author display:flex would otherwise defeat [hidden] */
.bulk-count {
  font-size: 11px;
  color: var(--text-dim);
}
.btn-sm {
  padding: 5px 10px;
  font-size: 12px;
}
.cat-table th.sel-col,
.cat-table td.sel-col {
  width: 34px;
  text-align: center;
  padding-left: 12px;
  padding-right: 0;
}
.cat-table input[type="checkbox"] {
  accent-color: var(--accent);
  width: 14px;
  height: 14px;
  cursor: pointer;
  vertical-align: middle;
}

/* transactions filter bar */
.txn-filters {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 14px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
}
.filter-field {
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.filter-field > label {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.filter-field select,
.filter-field input {
  appearance: none;
  -webkit-appearance: none;
  background: var(--bg-panel-hi);
  border: 1px solid var(--border-strong);
  border-radius: 4px;
  color: var(--text);
  font: inherit;
  font-size: 12px;
  padding: 6px 8px;
  min-width: 140px;
}
.filter-field select:focus,
.filter-field input:focus {
  border-color: var(--accent);
  outline: none;
}
.filter-field select option { background: var(--bg-panel); color: var(--text); }
.filter-range {
  display: flex;
  align-items: center;
  gap: 6px;
}
.filter-range input {
  min-width: 0;
  width: 88px;
  text-align: right;
}
.filter-range .range-sep { color: var(--text-muted); }
.txn-filters #filter-clear { align-self: center; margin-left: auto; }
.filter-count {
  align-self: center;
  font-size: 11px;
  color: var(--text-dim);
}
.txn-filters #filter-clear + .filter-count { margin-left: 0; }
.txn-filters #filter-clear[hidden] + .filter-count { margin-left: auto; }

/* ─────────── confirm modal ─────────── */
.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}
.modal-overlay[hidden] { display: none; }   /* author display:flex would defeat [hidden] otherwise */
.modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
}
.modal-card {
  position: relative;
  width: 380px;
  max-width: 100%;
  padding: 20px;
  background: var(--bg-panel);
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  box-shadow: var(--shadow-overlay);
}
.modal-card h3 {
  margin: 0 0 8px;
  font-size: 15px;
  font-weight: 600;
  color: var(--text);
}
.modal-text {
  margin: 0 0 18px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-dim);
}
.modal-name { color: var(--text); font-weight: 600; }
.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}

/* ─────────── manage transactions ─────────── */
.page-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 2px 2px 0;
}
.page-head h1 {
  margin: 0;
  font-size: 18px;
  font-weight: 600;
  color: var(--text);
}
.page-head .sub {
  font-size: 13px;
  color: var(--text-dim);
}

.upload-zone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 28px 16px;
  border: 1.5px dashed var(--border-strong);
  border-radius: 6px;
  background: var(--bg-app);
  text-align: center;
  cursor: pointer;
  transition: border-color 120ms, background 120ms;
}
.upload-zone:hover { border-color: var(--accent); }
.upload-zone.dragover {
  border-color: var(--accent);
  background: var(--accent-dim);
}
.upload-zone svg {
  width: 28px;
  height: 28px;
  color: var(--text-dim);
}
.upload-zone .upload-file {
  font-weight: 500;
  color: var(--text);
}
.upload-zone .upload-hint {
  font-size: 12px;
  color: var(--text-muted);
}

.upload-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 12px;
}
.upload-status {
  font-size: 12px;
  color: var(--text-dim);
  min-height: 1em;
}
.upload-status.ok   { color: var(--pos); }
.upload-status.err  { color: var(--neg); }
.upload-status.warn { color: #d97706; }

/* ---- review table: category cell wrapper + pick button ---- */
.rv-cat-wrap {
  display: flex;
  align-items: center;
  gap: 3px;
}
.rv-pick-btn {
  flex-shrink: 0;
  padding: 2px 6px;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 3px;
  color: var(--text-muted);
  cursor: pointer;
  font-size: 11px;
  line-height: 1.4;
  transition: border-color 0.1s, color 0.1s;
}
.rv-pick-btn:hover,
.rv-pick-btn.open { border-color: var(--accent); color: var(--accent); }

/* pills row */
.rv-pills-row td {
  padding: 6px 10px !important;
  background: color-mix(in srgb, var(--accent-haze) 50%, var(--bg-panel));
  border-top: 1px solid var(--border) !important;
  border-bottom: 1px solid var(--border) !important;
}
.rv-pills-wrap {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.rv-pills-letter {
  flex-basis: 100%;
  padding: 6px 0 2px;
  font-size: 12px;
  color:#000;
  font-weight: 700;
  letter-spacing: 0.06em;
  border-bottom: 1px solid var(--border);
  text-align:left;
}
.rv-pill {
  padding: 3px 11px;
  background: var(--bg-app);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text);
  font: inherit;
  font-size: 11px;
  cursor: pointer;
  white-space: nowrap;
  font-weight:bold;
  transition: border-color 0.1s, color 0.1s, background 0.1s;
}
.rv-pill:hover { border-color: var(--accent); color: var(--accent); }
.rv-pill.rv-pill-active {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

/* inline category editor in the transactions table */
.cat-edit {
  width: 100%;
  max-width: 180px;
  padding: 4px 6px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  color: var(--text);
  font: inherit;
  font-size: 12px;
  text-align: left;
}
.cat-edit::placeholder { color: var(--text-muted); }
.cat-edit:hover { border-color: var(--border-strong); }
.cat-edit:focus {
  border-color: var(--accent);
  outline: none;
  background: var(--bg-app);
}

.cat-table tbody tr.empty-row td {
  text-align: center;
  color: var(--text-muted);
  font-style: italic;
  padding: 18px 12px;
}
.cat-table tbody tr.empty-row:hover { background: transparent; }

/* credits / refunds (stored negative under the expense-positive convention) */
.cat-table td.figure.pos { color: var(--pos); }

/* The review panel stacks several .panel-body blocks; the dashboard's
   default flex:1 would split the panel height equally and overflow the
   table. Size each body to its own content instead. */
#review-panel .panel-body,
#rules-panel .panel-body,
#budget-panel .panel-body,
#income-panel .panel-body,
#recurring-panel .panel-body { flex: 0 0 auto; }

/* ---- recurring transactions ---- */
.rec-add { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.rec-add .rec-amt { width: 110px; }
.rec-add .rec-start { width: 160px; }
.rec-cell {
  width: 100%;
  padding: 5px 7px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  color: var(--text);
  font: inherit;
  font-size: 12px;
}
.rec-cell:hover { border-color: var(--border-strong); }
.rec-cell:focus { border-color: var(--accent); outline: none; background: var(--bg-app); }
#rec-table .cat-freq { width: 52px; }
#rec-table .rec-start { width: 150px; }
.rec-badge { color: var(--accent); font-size: 11px; margin-left: 4px; }
/* omit-keyword: transaction excluded from totals (still shown, dimmed + badge) */
.omit-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 0 6px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  background: var(--bg-app);
  border: 1px solid var(--border);
  border-radius: 999px;
  vertical-align: 1px;
}
.cat-table tbody tr.is-omitted td.figure,
.cat-table tbody tr.is-omitted td.name { color: var(--text-muted); }
.cat-table tbody tr.is-omitted td.figure { text-decoration: line-through; }

/* ---- import review: format-mapping summary ---- */
.review-file { text-transform: none; letter-spacing: 0; font-weight: 600; color: var(--text); }
.review-flag {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.review-flag.ok   { color: var(--pos); }
.review-flag.warn { color: var(--neg); }

.map-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.map-chip {
  display: inline-flex;
  flex-direction: column;
  gap: 1px;
  padding: 6px 10px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--bg-app);
}
.map-chip-missing { border-color: var(--neg); }
.map-chip .map-field {
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.map-chip .map-col { font-size: 12px; color: var(--text); }

/* ---- import review: per-row category source badge ---- */
.src-badge {
  display: inline-block;
  padding: 2px 7px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}
.badge-rule    { background: var(--accent-dim); color: var(--accent); }
.badge-file    { background: rgba(34, 197, 94, 0.12); color: var(--pos); }
.badge-mcc     { background: rgba(168, 85, 247, 0.14); color: #a855f7; }
.badge-llm     { background: rgba(251, 191, 36, 0.14); color: #d97706; }
.badge-llm-new { background: rgba(251, 191, 36, 0.22); color: #b45309; }
.badge-none    { background: var(--bg-panel-hi); color: var(--text-muted); }
.badge-dup  { background: var(--bg-panel-hi); color: var(--text-dim); }

/* already-imported rows in the review table */
.cat-table tbody tr.is-dup td.name,
.cat-table tbody tr.is-dup td.figure { color: var(--text-muted); }
.cat-table tbody tr.is-dup .cat-edit { color: var(--text-muted); }
.cat-table tbody tr.rv-row-active td { background: var(--accent-haze); }

/* Cashflow row — always visible (not grp-member), so it shows even when group is collapsed */
.cat-table tbody tr.grp-cashflow td {
  background: var(--bg-panel-hi);
  border-top: 1px solid var(--border);
  border-bottom: 2px solid var(--border-strong);
}
.cat-table tbody tr.grp-cashflow .grp-foot-label { color: var(--text-muted); }
.cat-table tbody tr.grp-cashflow .grp-cashflow-total { font-weight: 700; color: var(--text); }
.cat-table tbody tr.grp-cashflow .grp-cashflow-total.neg { color: var(--neg); }
.grp-savings-input {
  width: 100%;
  max-width: 140px;
  padding: 2px 6px;
  background: transparent;
  border: 1px solid var(--border-strong);
  border-radius: 4px;
  color: var(--text-dim);
  font: inherit;
  font-size: 11px;
  text-align: right;
}
.grp-savings-input:focus { outline: 2px solid var(--accent); outline-offset: -1px; border-color: transparent; }

@keyframes rv-row-flash {
  0%   { background-color: rgba(34, 197, 94, 0.45); }
  25%  { background-color: rgba(34, 197, 94, 0.45); }
  100% { background-color: transparent; }
}
.cat-table tbody tr.rv-row-flash td { animation: rv-row-flash 3.5s ease-out forwards; }

.review-note {
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-dim);
}
.review-note strong { color: var(--text); font-weight: 600; }

/* Review action bar — sticks to the bottom of the viewport while you scroll
   the review rows, but stays inside the Review import panel (it doesn't break
   out to full width). Settles into place at the panel's bottom edge. */
.review-actions {
  position: sticky;
  bottom: 0;
  z-index: 20;
  background: var(--bg-panel);
  border-top: 1px solid var(--border);
  border-bottom-left-radius: 4px;
  border-bottom-right-radius: 4px;
}

/* ---- category rules config ---- */
.rules-hint {
  font-size: 11px;
  color: var(--text-muted);
  text-transform: none;
  letter-spacing: 0;
}
.rules-help {
  margin: 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-dim);
}
.rules-help strong { color: var(--text); font-weight: 600; }
.rules-add {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
.rules-arrow { color: var(--text-muted); }
.rule-input {
  min-width: 170px;
  padding: 7px 9px;
  background: var(--bg-app);
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--text);
  font: inherit;
  font-size: 12px;
}
.rule-input:focus { border-color: var(--accent); outline: none; }
.rule-cell {
  width: 100%;
  max-width: 240px;
  padding: 5px 7px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  color: var(--text);
  font: inherit;
  font-size: 12px;
}
.rule-cell:hover { border-color: var(--border-strong); }
.rule-cell:focus { border-color: var(--accent); outline: none; background: var(--bg-app); }

.rules-hint.ok-text  { color: var(--pos); }
.rules-hint.err-text { color: var(--neg); }

/* ---- budgets grid (categories × months, horizontal scroll) ---- */
.budget-scroll { overflow-x: auto; }
/* sticky months header: bound the container's height so it scrolls vertically
   on its own, and pin the header row to the top within that container (not the
   page). Top-left cell sits above both sticky axes. */
.budget-scroll.sticky-head { overflow: auto; max-height: 70vh; }
.sticky-head .budget-grid thead th { position: sticky; top: 0; z-index: 3; }
.sticky-head .budget-grid thead th.cat-col { z-index: 4; }
.budget-grid {
  border-collapse: separate;
  border-spacing: 0;
  width: max-content;
  min-width: 100%;
  font-size: 12px;
}
.budget-grid th,
.budget-grid td {
  padding: 7px 10px;
  border-bottom: 1px solid #aaaaaa;
  white-space: nowrap;
}
.budget-grid thead th {
  background: var(--bg-panel-hi);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  text-align: right;
}
.budget-grid thead th.is-current { color: var(--accent); }
.budget-grid th.cat-col,
.budget-grid td.cat-col {
  position: sticky;             /* keep the category column visible while scrolling months */
  left: 0;
  z-index: 2;
  background: var(--bg-panel);
  text-align: left;
  min-width: 300px;
  border-right: 1px solid var(--border-strong);
}
.budget-grid thead th.cat-col { background: var(--bg-panel-hi); }
.budget-grid tbody tr:hover td.cat-col { background: var(--bg-panel-hi); }
.budget-grid tbody tr:hover td { background: var(--bg-panel-hi); }
.budget-grid td.cat-col.is-member { padding-left: 24px; }   /* indent group members */

/* group header rows + subtotals */
.budget-grid tr.grp-row {
  cursor: pointer;
}
/* 5px separator under each group header — on the cells, since with
   border-collapse: separate a border on the <tr> itself isn't rendered. */
.budget-grid tr.grp-row td { background: var(--bg-panel-hi); border-bottom: 5px solid #000; }
.budget-grid tr.grp-row td.cat-col { background: var(--bg-panel-hi); z-index: 2; }
/* 10px gap before each group (except the first) to separate groups. Coloured
   like the panel so it reads as empty space; on the header cells via border-top
   so it survives a collapsed group (whose members are display:none). */
.budget-grid tbody tr.grp-row:not(:first-child) td { border-top: 10px solid var(--bg-panel); }
.budget-grid .cat-cell.grp-head { display: flex; flex-direction: row; align-items: center; gap: 6px; }
.budget-grid .grp-head .grp-caret {
  flex: 0 0 auto;
  color: var(--text-muted);
  font-size: 10px;
  width: 12px;
  text-align: center;
}
.budget-grid tr.grp-member.grp-collapsed { display: none; }
.bva-grid tr.grp-cashflow td { border-top: 1px solid var(--border); border-bottom: 2px solid var(--border-strong); }
.bva-grid tr.grp-cashflow .grp-foot-label { color: var(--text-muted); }

/* Budget vs. Actuals (table): the first column only holds plain names/labels
   (no inline editors like the budgets grid), so keep it tight and let the group
   label hug its count instead of stretching the badge to the far right. */
.bva-grid th.cat-col,
.bva-grid td.cat-col { min-width: 0; width: 1px; white-space: nowrap; }
.bva-grid .cat-cell.grp-head { gap: 8px; flex-wrap: nowrap; }
/* min-width: max-content overrides the global .grp-label { min-width: 0 } so the
   label's full width (plus the caret) is counted into the content-fit column —
   otherwise the arrow space is excluded and the name wraps. */
.bva-grid .grp-head .grp-label { flex: 0 0 auto; min-width: max-content; white-space: nowrap; }

/* Budget vs. Actuals (table): each cell stacks actual over budget */
.bva-grid td.bva-cell { text-align: right; padding: 6px 12px; }
.bva-grid .bva-actual {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  color: var(--text);
  line-height: 1.25;
}
.bva-grid .bva-budget {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 10px;
  color: var(--text-dim);
  line-height: 1.2;
}
.bva-grid .bva-none { color: var(--text-muted); }
.bva-grid td.bva-cell.bva-sub .bva-actual { font-weight: 700; }
.bva-grid td.bva-cell.bva-sub .bva-budget { font-weight: 600; }
/* actual vs budget: over (red), under (green), on budget (neutral) */
.bva-grid td.bva-cell.over  { background: var(--neg-bg); }
.bva-grid td.bva-cell.over  .bva-actual { color: var(--neg); font-weight: 600; }
.bva-grid td.bva-cell.under { background: var(--pos-bg); }
.bva-grid td.bva-cell.under .bva-actual { color: var(--pos); font-weight: 600; }
.bva-grid td.bva-cell.even  .bva-actual { color: var(--text); font-weight: 600; }
/* Category (member) rows: no background, keep coloured text */
.bva-grid td.bva-cell.over:not(.bva-sub)  { background: transparent; }
.bva-grid td.bva-cell.under:not(.bva-sub) { background: transparent; }
.bva-grid thead th.month-col.is-current,
.bva-grid td.bva-cell { white-space: nowrap; }
.legend .swatch.bva-over-sw  { background: var(--neg); }
.legend .swatch.bva-under-sw { background: var(--pos); }
.legend .swatch.bva-even-sw  { background: var(--text); }
/* grand total row at the bottom */
.bva-grid tr.bva-total td { border-top: 2px solid var(--border-strong); background: var(--bg-panel-hi); }
.bva-grid tr.bva-total td.cat-col {
  background: var(--bg-panel-hi);
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
/* Budget vs. Actuals: month nav (‹ range ›) in the panel header */
.bva-controls { display: flex; align-items: center; gap: 16px; }
.bva-nav {
  display: flex;
  align-items: center;
  gap: 2px;
  background: var(--bg-app);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 2px;
}
.bva-nav .month-step {
  appearance: none;
  background: transparent;
  border: 0;
  color: var(--text-dim);
  font-size: 16px;
  line-height: 1;
  width: 26px;
  height: 22px;
  cursor: pointer;
  border-radius: 3px;
  transition: background 90ms, color 90ms;
}
.bva-nav .month-step:hover:not(:disabled) { color: var(--text); background: var(--bg-panel-hi); }
.bva-nav .month-step:disabled { color: var(--text-muted); cursor: not-allowed; opacity: 0.5; }
.bva-range {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-dim);
  min-width: 120px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

/* group header rows + subtotals (budgets page) */
.grp-name,
.grp-label {
  flex: 1;
  min-width: 0;
  padding: 4px 6px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text);
}
.grp-name {
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  font-family: inherit;
}
.grp-name:hover { border-color: var(--border-strong); }
.grp-name:focus { border-color: var(--accent); outline: none; background: var(--bg-app); }
.grp-subtotal {
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  color: var(--text);
}

.cat-grp {
  width: 92px;
  padding: 4px 6px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  color: var(--text-dim);
  font: inherit;
  font-size: 11px;
}
.cat-grp::placeholder { color: var(--text-muted); }
.cat-grp:hover { border-color: var(--border-strong); }
.cat-grp:focus { border-color: var(--accent); outline: none; background: var(--bg-app); color: var(--text); }
.cat-mode {
  appearance: none;
  padding: 4px 6px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  color: var(--text-dim);
  font: inherit;
  font-size: 11px;
  cursor: pointer;
}
.cat-mode:hover { border-color: var(--border-strong); }
.cat-mode:focus { border-color: var(--accent); outline: none; background: var(--bg-app); color: var(--text); }
.cat-mode option { background: var(--bg-panel); color: var(--text); }
.cat-autopay {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  color: var(--text-dim);
  cursor: pointer;
  white-space: nowrap;
}
.cat-autopay input { cursor: pointer; margin: 0; }

.cat-cell { display: flex; flex-direction: column; gap: 2px; }
.cat-line { display: flex; align-items: center; gap: 6px; }
.cat-meta { gap: 8px; }
.cat-name {
  flex: 1;
  min-width: 0;
  padding: 4px 6px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  color: var(--text);
  font: inherit;
  font-size: 12px;
  font-weight: 500;
}
.freq-ctl {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 10px;
  color: var(--text-muted);
  white-space: nowrap;
}
.cat-freq {
  width: 38px;
  padding: 2px 4px;
  text-align: center;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--text-dim);
  font: inherit;
  font-size: 11px;
}
.cat-freq:focus { border-color: var(--accent); outline: none; background: var(--bg-app); color: var(--text); }
.budget-cell.off-cycle { background: transparent; cursor: not-allowed; }
.budget-cell:disabled { opacity: 0.45; cursor: not-allowed; }
.cat-name:hover { border-color: var(--border-strong); }
.cat-name:focus { border-color: var(--accent); outline: none; background: var(--bg-app); }

.budget-cell {
  width: 84px;
  padding: 4px 6px;
  text-align: right;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  color: var(--text-dim);
  font: inherit;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}
.budget-cell:hover { border-color: var(--border-strong); }
.budget-cell:focus { border-color: var(--accent); outline: none; background: var(--bg-app); color: var(--text); }
.budget-cell.is-set { color: var(--text); font-weight: 600; }
.budget-cell.is-carried { color: var(--text-muted); }

/* explicit column alignment helpers (the table is otherwise numeric-first) */
.cat-table th.al-left,  .cat-table td.al-left  { text-align: left; }
.cat-table th.al-right, .cat-table td.al-right { text-align: right; }
/* this table's headers aren't sortable — don't imply they are */
#stmt-table thead th, #txn-table thead th { cursor: default; }
#stmt-table thead th:hover, #txn-table thead th:hover { color: var(--text-muted); }

/* ─────────── My Savings page ─────────── */
.kpi-strip.savings-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 700px) { .kpi-strip.savings-kpis { grid-template-columns: minmax(0, 1fr); } }
.savings-input {
  display: flex;
  flex-direction: row;   /* override .panel-body's column so the fields share one line */
  gap: 20px;
  align-items: flex-end;
  flex-wrap: wrap;
}
.savings-input label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.savings-input .rule-input { max-width: 180px; }
.legend .swatch.sav-potential {
  width: 18px; height: 0;
  border: 0; border-top: 1.5px dashed var(--accent);
  background: transparent; border-radius: 0;
  vertical-align: 3px;
}
.legend .swatch.sav-actual {
  width: 18px; height: 2px;
  background: var(--text); border-radius: 0;
  vertical-align: 3px;
}
.cat-table tbody tr.sav-current td { background: var(--bg-panel-hi); font-weight: 600; }
.cat-table .muted-dash { color: var(--text-muted); }
.kpi .value.pos { color: var(--pos); }

/* ─────────── auth (sign in / register / reset / verify) ─────────── */
.auth-wrap {
  position: relative;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 28px;
  overflow: hidden;
  background:
    radial-gradient(820px 520px at 50% -12%, var(--accent-glow), transparent 70%),
    radial-gradient(680px 520px at 112% 118%, var(--accent-haze), transparent 62%);
}
/* faint grid texture behind the card for depth */
.auth-wrap::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(var(--border) 1px, transparent 1px),
    linear-gradient(90deg, var(--border) 1px, transparent 1px);
  background-size: 44px 44px;
  -webkit-mask-image: radial-gradient(620px 620px at 50% 30%, #000, transparent 75%);
          mask-image: radial-gradient(620px 620px at 50% 30%, #000, transparent 75%);
  opacity: 0.7;
  pointer-events: none;
}

.auth-card {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 408px;
  display: flex;
  flex-direction: column;
  gap: 17px;
  padding: 38px 34px 32px;
  background: var(--auth-card-bg);
  -webkit-backdrop-filter: blur(14px) saturate(1.2);
          backdrop-filter: blur(14px) saturate(1.2);
  border: 1px solid var(--border-strong);
  border-radius: 18px;
  box-shadow:
    0 28px 70px rgba(0, 0, 0, 0.45),
    0 1px 0 rgba(255, 255, 255, 0.05) inset;
  animation: auth-rise 420ms cubic-bezier(0.16, 1, 0.3, 1);
}
/* the author display:flex above would otherwise defeat the [hidden] attribute
   used to toggle the forgot-password panel (same gotcha as .bulk-actions) */
.auth-card[hidden] { display: none; }
@keyframes auth-rise {
  from { opacity: 0; transform: translateY(14px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .auth-card { animation: none; }
}

/* brand emblem (login + register) */
.auth-brand {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 54px;
  height: 54px;
  margin-bottom: 2px;
  border-radius: 15px;
  color: #fff;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  box-shadow: 0 12px 26px var(--accent-glow);
}
.auth-brand svg { width: 28px; height: 28px; }

.auth-card h1 {
  margin: 0;
  font-size: 27px;
  font-weight: 800;
  letter-spacing: -0.022em;
  line-height: 1.12;
  color: var(--text);
}
.auth-sub {
  margin: -8px 0 4px;
  font-size: 14px;
  color: var(--text-dim);
}

/* labels stack their input; the small caption sits above */
.auth-card label {
  display: flex;
  flex-direction: column;
  gap: 7px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.auth-card .hint {
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text-muted);
}
.auth-card input[type="text"],
.auth-card input[type="email"],
.auth-card input[type="password"],
.auth-card textarea {
  width: 100%;
  padding: 12px 14px;
  font: inherit;
  font-size: 14px;
  color: var(--text);
  background: var(--bg-app);
  border: 1px solid var(--border-strong);
  border-radius: 11px;
  transition: border-color 130ms, box-shadow 130ms, background 130ms;
}
.auth-card input::placeholder,
.auth-card textarea::placeholder { color: var(--text-muted); }
.auth-card input:focus,
.auth-card textarea:focus {
  outline: none;
  border-color: var(--accent);
  background: var(--bg-panel-hi);
  box-shadow: 0 0 0 4px var(--accent-glow);
}

/* "keep me signed in" — switch from the column layout to an inline row */
.auth-remember {
  flex-direction: row;
  align-items: center;
  gap: 10px;
  margin-top: -2px;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text-dim);
  cursor: pointer;
  user-select: none;
}
.auth-remember input[type="checkbox"] {
  width: 16px;
  height: 16px;
  accent-color: var(--accent);
  cursor: pointer;
}

.auth-card .btn-primary {
  width: 100%;
  margin-top: 4px;
  padding: 13px 16px;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.01em;
  border-radius: 11px;
  box-shadow: 0 10px 24px var(--accent-glow);
  transition: filter 110ms, transform 110ms, box-shadow 110ms;
}
.auth-card .btn-primary:hover {
  filter: brightness(1.07);
  transform: translateY(-1px);
}
.auth-card .btn-primary:active { transform: translateY(0); }

/* status messages */
.auth-error,
.auth-note {
  margin: 0;
  padding: 11px 13px;
  font-size: 13px;
  font-weight: 500;
  border-radius: 10px;
  border: 1px solid var(--border-strong);
}
.auth-error { color: var(--neg); background: var(--neg-bg); }
.auth-note  { color: var(--pos); background: var(--pos-bg); }

.auth-alt {
  margin: 2px 0 0;
  text-align: center;
  font-size: 13px;
  color: var(--text-dim);
}
.auth-alt a {
  color: var(--accent);
  font-weight: 600;
  text-decoration: none;
}
.auth-alt a:hover { text-decoration: underline; }
.auth-alt .dot { margin: 0 9px; color: var(--text-muted); }

@media (max-width: 480px) {
  .auth-card { padding: 30px 22px 26px; border-radius: 16px; }
  .auth-card h1 { font-size: 24px; }
}

/* ── Inline tooltip icon ── */
.rv-tip {
  display: inline-block;
  position: relative;
  width: 14px;
  height: 14px;
  margin-left: 5px;
  border-radius: 50%;
  background: var(--text-dim);
  color: var(--bg-panel);
  font-size: 9px;
  font-weight: 700;
  line-height: 14px;
  text-align: center;
  cursor: default;
  vertical-align: middle;
}
.rv-tip::before { content: '?'; }
.rv-tip::after {
  content: attr(data-tip);
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  background: var(--bg-app);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  padding: 6px 10px;
  font-size: 11px;
  font-weight: 400;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s;
  z-index: 20;
}
.rv-tip:hover::after { opacity: 1; }

/* Group savings + income-allocation grid (budgets page) */
#grp-income-grid .cat-meta { color: var(--text-muted); font-size: 11px; margin-top: 2px; }
#grp-income-grid .grp-sav-bal { width: 90px; font-size: 12px; }
#grp-income-grid tr.grp-income-remaining td { background: var(--bg-panel-hi); }
#grp-income-grid td.grp-over { color: var(--neg); font-weight: 700; }
