/* styles.css — the look of the page. Plain CSS, no frameworks.
   Visual direction: a dark, calm sidebar for navigation and a light,
   spacious workspace for content - the same shape most modern budgeting
   apps use - built around one confident accent color (a YNAB-esque green)
   that's reserved for the things that matter: primary actions, money coming
   in, and "on track" states. */

:root {
  --bg: #F4F6F5;
  --card: #FFFFFF;
  --ink: #1C2B33;
  --muted: #6B7C82;
  --line: #E3E9E7;

  --accent: #1BA97F;
  --accent-dark: #148F6B;
  --accent-soft: #E4F5EE;

  --danger: #E2574C;
  --danger-soft: #FBEAE8;
  --pos: #1BA97F;

  --orange: #D9822B;
  --orange-soft: #FCEEDD;

  --warn-bg: #FDF1D6;
  --warn-ink: #92620C;

  --sidebar-bg: #17262B;
  --sidebar-ink: #AFC3C2;
  --sidebar-ink-dim: #7C9291;
  --sidebar-active-bg: #22383E;
  --sidebar-active-ink: #FFFFFF;

  --radius: 14px;
  --radius-sm: 9px;
  --shadow-card: 0 1px 2px rgba(23, 38, 43, 0.05), 0 8px 24px rgba(23, 38, 43, 0.06);

  /* User-adjustable (Admin -> Other -> Grid font size); this is just the
     default before that preference loads from localStorage. */
  --grid-font-size: 14px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
}

/* ---- App shell: dark sidebar + light content area ----------------------- */

.app-shell {
  display: flex;
  min-height: 100vh;
}

.sidebar {
  flex-shrink: 0;
  width: 232px;
  background: var(--sidebar-bg);
  padding: 20px 14px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  transition: width 0.15s ease;
}

/* Collapsed: an icon-only rail. Reclaims ~170px of width for the content
   area - the main space-saving lever on this page, since every other panel
   (grids included) sits to the right of this. Labels are hidden, not
   removed, so expanding is instant with no re-render. */
.sidebar.collapsed { width: 64px; }
.sidebar.collapsed .tab { text-align: center; padding: 11px 0; }
.sidebar.collapsed .tab-label,
.sidebar.collapsed .sidebar-brand-name { display: none; }
.sidebar.collapsed .sidebar-brand { justify-content: center; padding: 6px 0 22px; }
.sidebar.collapsed .sidebar-toggle { transform: rotate(180deg); }

.sidebar-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 10px 22px;
  color: #fff;
}
.sidebar-brand-mark { font-size: 22px; line-height: 1; }
.sidebar-brand-name { font-size: 16px; font-weight: 700; letter-spacing: 0.01em; flex: 1; }

.sidebar-toggle {
  background: none;
  border: none;
  color: var(--sidebar-ink-dim);
  cursor: pointer;
  font-size: 14px;
  padding: 4px 6px;
  border-radius: var(--radius-sm);
  line-height: 1;
}
.sidebar-toggle:hover { background: var(--sidebar-active-bg); color: #fff; }

.sidebar .tab {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  color: var(--sidebar-ink);
  padding: 11px 14px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
}
.tab-icon { font-size: 16px; line-height: 1; flex-shrink: 0; }
.tab-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sidebar .tab:hover { background: var(--sidebar-active-bg); color: #fff; }
.sidebar .tab.active {
  background: var(--accent);
  color: #fff;
  font-weight: 700;
}

main { flex: 1; min-width: 0; padding: 20px 26px; }

.panel { display: none; }
.panel.active { display: block; }

/* ---- Admin's second-level tabs (Bank Accounts / Category Rules) --------- */

.subnav {
  display: flex;
  gap: 4px;
  margin-bottom: 20px;
  border-bottom: 1px solid var(--line);
}
.subtab {
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  color: var(--muted);
  padding: 10px 6px;
  margin-bottom: -1px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  margin-right: 20px;
}
.subtab:hover { color: var(--ink); }
.subtab.active { color: var(--accent-dark); border-bottom-color: var(--accent); }

.subpanel { display: none; }
.subpanel.active { display: block; }

/* ---- Layout basics -------------------------------------------------------- */

.toolbar {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 16px;
}

.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  padding: 22px 24px;
  margin-bottom: 24px;
}
.card h2 { margin: 0 0 16px; font-size: 16px; font-weight: 700; }

/* A small centered choice dialog (currently just the export prompt) - not
   the Excel-style column menu, which is positioned under its header button
   instead of centered over the whole page. */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(23, 38, 43, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2000;
}
.modal-card {
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: 0 20px 48px rgba(23, 38, 43, 0.3);
  padding: 24px 28px;
  width: 340px;
}
.modal-card h2 { margin: 0 0 8px; font-size: 17px; font-weight: 700; }
.modal-card .hint { margin-bottom: 18px; }
.modal-card .form-actions button { width: 100%; }

/* The auth overlay (AUTH-1/AUTH-9 - setup/login/recovery/idle-timeout) is
   the one place a see-through backdrop is actually wrong: every other use
   of .modal-overlay is a confirmation/choice dialog where keeping the
   dimmed page visible behind it is the point (context for what you're
   acting on) - here, the whole reason this shows at all can be that
   someone might be looking at the screen who shouldn't see what's behind
   it (idle timeout), so it needs to fully block the page, not a
   45%-opacity tint that still lets balances/transactions read through
   around the card's edges. Solid instead of transparent, otherwise
   identical positioning. */
#authOverlay { background: var(--bg); }

/* Brief "Saved" confirmation after an inline edit or a Budget change (TXN-15,
   the Budget drill-down's own inline edit, BUD-11) - these all save
   on-the-spot with just a silent reload, so this is the only positive
   feedback that a click actually took. Fades in/out rather than needing a
   dismiss click; one at a time (re-triggering just restarts the timer). */
.toast {
  position: fixed;
  bottom: 24px;
  right: 24px;
  background: var(--ink);
  color: #fff;
  padding: 10px 18px;
  border-radius: var(--radius-sm);
  font-size: 14px;
  font-weight: 600;
  box-shadow: 0 8px 24px rgba(23, 38, 43, 0.35);
  border-left: 4px solid var(--accent);
  opacity: 0;
  transform: translateY(8px);
  pointer-events: none;
  transition: opacity 160ms ease, transform 160ms ease;
  z-index: 3000;
}
.toast.toast-show { opacity: 1; transform: translateY(0); }

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 14px;
  margin-bottom: 14px;
}
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }

label { display: block; font-size: 13px; font-weight: 600; color: var(--muted); }
input, select {
  display: block;
  width: 100%;
  margin-top: 5px;
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 14px;
  font-family: inherit;
  color: var(--ink);
  background: #fff;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
input:focus, select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.toolbar input { width: auto; display: inline-block; margin-top: 0; }
.tx-search-wrap { position: relative; display: inline-block; }
.tx-search-box { width: 260px; padding-right: 28px; }
.tx-search-clear {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  width: 22px;
  height: 22px;
  padding: 0;
  border: none;
  background: none;
  color: var(--muted);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  border-radius: var(--radius-sm);
}
.tx-search-clear:hover { color: var(--ink); background: var(--bg); }

.form-actions { margin-top: 18px; display: flex; gap: 10px; }

button {
  background: var(--accent);
  color: #fff;
  border: none;
  padding: 10px 20px;
  border-radius: 999px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 600;
  transition: background 120ms ease, transform 120ms ease;
}
button:hover { background: var(--accent-dark); }
button:active { transform: translateY(1px); }
button.secondary { background: var(--bg); color: var(--ink); border: 1px solid var(--line); }
button.secondary:hover { background: var(--line); }
.link-btn { background: none; color: var(--accent-dark); padding: 4px; border-radius: 6px; font-weight: 600; }
.link-btn:hover { background: none; text-decoration: underline; }

table {
  width: 100%;
  border-collapse: collapse;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}
th, td { padding: 12px 14px; text-align: left; border-bottom: 1px solid var(--line); font-size: var(--grid-font-size); }
/* Header stays relatively a little smaller than the body text, same as
   before the grid font size setting existed, but now scales along with it
   (calc() off the same variable) instead of being stuck at a fixed size. */
th { background: #FBFCFC; color: var(--muted); font-weight: 700; font-size: calc(var(--grid-font-size) - 1.5px); text-transform: uppercase; letter-spacing: 0.03em; }
tbody tr:last-child td { border-bottom: none; }
tbody tr:hover td { background: #F1F5F3; }
/* Zebra striping to make a wide row easier to track across - skipped on the
   Budget grid specifically, which already shades Master/Category rows a
   different way (BUD-12) that this would otherwise clash with. The hover
   rule is repeated at matching specificity so it still wins over a striped
   row on every other grid (:not(#budgetTable) carries ID-level
   specificity, same as an #id selector, which the plain hover rule above
   can't outweigh on its own). */
table:not(#budgetTable) tbody tr:nth-child(even) td { background: #FAFCFB; }
table:not(#budgetTable) tbody tr:hover td { background: #F1F5F3; }
.right { text-align: right; }

tfoot th { background: var(--accent-soft); font-size: calc(var(--grid-font-size) + 1px); color: var(--ink); text-transform: none; }

.amount-pos { color: var(--pos); font-weight: 600; }
.amount-neg { color: var(--ink); }

.row-btn {
  background: none;
  color: var(--accent-dark);
  padding: 2px 6px;
  font-size: 13px;
  font-weight: 600;
  border-radius: 6px;
}
.row-btn:hover { background: none; text-decoration: underline; }
.row-btn.delete { color: var(--danger); }
.row-btn:disabled { color: var(--muted); cursor: default; }
.row-btn:disabled:hover { text-decoration: none; }

.pill {
  display: inline-block;
  background: var(--accent-soft);
  color: var(--accent-dark);
  padding: 3px 11px;
  border-radius: 999px;
  font-size: calc(var(--grid-font-size) - 2px);
  font-weight: 600;
}
.pill-warn { background: var(--warn-bg); color: var(--warn-ink); }

.hint { color: var(--muted); font-size: 13px; line-height: 1.55; margin-bottom: 16px; }
.hint code { background: var(--bg); padding: 1px 6px; border-radius: 4px; }
.hint.error-text { color: var(--danger); }
.empty { color: var(--muted); text-align: center; padding: 28px; }
.filter-input { margin-bottom: 12px; }

.color-swatch {
  display: inline-block;
  width: 12px;
  height: 12px;
  border-radius: 4px;
  margin-right: 8px;
  vertical-align: middle;
  border: 1px solid rgba(0, 0, 0, 0.08);
}
.hidden { display: none; }

/* ---- Data grids: resizable columns + Excel-style filter/sort dropdown --- */

.table-wrap { overflow-x: auto; border-radius: var(--radius); }
table.data-table { table-layout: fixed; }

/* Transactions specifically: a bounded height with its own vertical scroll,
   so the horizontal scrollbar (which lives at this container's own bottom
   edge) is always at a fixed, reachable position - scrolling through many
   rows no longer means scrolling the whole page down to find it. */
.tx-table-wrap { max-height: 65vh; overflow-y: auto; }
/* The generic `table { overflow: hidden }` rule (clips header-cell corners
   to the table's rounded corners) also clips position:sticky - same fix as
   the Budget table's sticky header. */
#txTable { overflow: visible; }
#txTable thead tr:first-child th:first-child { border-top-left-radius: var(--radius); }
#txTable thead tr:first-child th:last-child { border-top-right-radius: var(--radius); }
#txTable thead th { position: sticky; top: 0; z-index: 2; background: #FBFCFC; }

.header-row th { position: relative; user-select: none; }
/* The Monthly Summary table keeps the simpler "click header to sort"
   behavior (it has no filter dropdown, see the JS comment for why). */
.summary-table .header-row th { cursor: pointer; }
.summary-table .header-row th:hover { background: #EFF3F2; }

.data-table .header-row th { padding-right: 34px; }
.th-label { display: inline-block; }
.sort-arrow { display: inline-block; margin-left: 4px; font-size: 11px; color: var(--accent-dark); }

.col-filter-btn {
  position: absolute;
  top: 50%;
  right: 12px;
  transform: translateY(-50%);
  background: none;
  border: none;
  padding: 2px 5px;
  font-size: 11px;
  color: var(--muted);
  cursor: pointer;
  line-height: 1;
  border-radius: 4px;
}
.col-filter-btn:hover { background: var(--line); }
.col-filter-btn.active { color: var(--accent-dark); font-weight: bold; }

.col-resize-handle {
  position: absolute;
  top: 0;
  right: -1px;
  width: 10px;
  height: 100%;
  cursor: col-resize;
}
.col-resize-handle:hover { background: rgba(27, 169, 127, 0.35); }

/* Applied to <body> for the duration of a column-resize drag - keeps the
   col-resize cursor showing and text from being selected even when the
   mouse drifts slightly off the thin resize handle itself, which is what
   made dragging feel broken (see makeColumnsResizable's comment). */
body.resizing-column, body.resizing-column * {
  cursor: col-resize !important;
  user-select: none !important;
}

.data-table td { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Action buttons (Edit/Delete/Unmatch/etc., .row-btn) must never be
   clipped or ellipsized the way overflowing text is above - a cell that
   holds one is let back to its natural size/wrapping instead, relying on
   the grid's own horizontal scroll (.table-wrap, GEN-17) if that makes the
   row wider than the viewport, rather than silently hiding a button. */
.data-table td:has(.row-btn) { overflow: visible; text-overflow: clip; white-space: normal; }

/* Excel-style column menu: sort buttons, a search box, and a checkbox list
   of unique values. Appended to <body> and positioned under whichever
   header's filter button opened it. */
.col-filter-menu {
  position: absolute;
  z-index: 1000;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  box-shadow: 0 12px 28px rgba(23, 38, 43, 0.18);
  padding: 8px;
  width: 230px;
  font-size: 13px;
}
.cfm-option {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  color: var(--ink);
  padding: 6px 8px;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
}
.cfm-option:hover { background: var(--accent-soft); }
.cfm-sep { border-top: 1px solid var(--line); margin: 6px 0; }
.cfm-search {
  width: 100%;
  margin: 4px 0 6px;
  padding: 6px 8px;
  border: 1px solid var(--line);
  border-radius: 6px;
  font-size: 12px;
}
.cfm-select-all {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px;
  font-weight: 600;
  border-bottom: 1px solid var(--line);
  margin-bottom: 4px;
  cursor: pointer;
}
.cfm-values { max-height: 220px; overflow-y: auto; margin-bottom: 8px; }
.cfm-value-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px;
  border-radius: 4px;
  cursor: pointer;
  font-size: 12px;
}
.cfm-value-row:hover { background: var(--bg); }
.cfm-empty { color: var(--muted); padding: 8px; font-size: 12px; }
.cfm-actions { display: flex; gap: 6px; justify-content: flex-end; }
.cfm-actions button { padding: 6px 14px; font-size: 12px; }
.cfm-cancel { background: var(--bg); color: var(--ink); border: 1px solid var(--line); }
.cfm-cancel:hover { background: var(--line); }

/* Checkboxes shouldn't inherit the block/bordered look meant for text inputs. */
input[type="checkbox"] {
  display: inline-block;
  width: auto;
  height: auto;
  margin: 0;
  padding: 0;
  border: none;
  background: none;
}

/* Monthly summary: indentation and weight differentiate Master / Category /
   Subcategory rows without needing a tree widget. */
.summary-table .row-master td { font-weight: 700; background: #F1F6F4; }
.summary-table .row-category td { font-weight: 600; padding-left: 28px; color: #33474C; }
.summary-table .row-subcategory td:first-child { padding-left: 44px; color: var(--muted); }
.summary-table .row-subcategory td { font-size: calc(var(--grid-font-size) - 1px); }

.budget-input {
  width: 100px;
  margin: 0 0 0 auto;
  padding: 4px 8px;
  text-align: right;
  font-size: calc(var(--grid-font-size) - 1px);
}
/* No spin buttons on grid number inputs - typing a value directly is the
   whole interaction here, the up/down steppers just eat width and clutter
   the cell for no real benefit. */
.budget-input::-webkit-outer-spin-button,
.budget-input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.budget-input[type="number"] { appearance: textfield; -moz-appearance: textfield; }

/* Inline editing (Transactions grid, TXN-15) - text boxes/dropdowns that
   replace a row's plain cells while it's being edited. Overrides the
   global input/select rule's much larger padding/margin/font-size, which
   is sized for a standalone form, not a table cell. */
.grid-edit-input {
  width: 100%;
  box-sizing: border-box;
  margin: 0;
  padding: 3px 6px;
  font-size: calc(var(--grid-font-size) - 1px);
}
.grid-edit-input[type="number"] { text-align: right; }
.grid-edit-input::-webkit-outer-spin-button,
.grid-edit-input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.grid-edit-input[type="number"] { appearance: textfield; -moz-appearance: textfield; }
/* Stacks multiple fields in one cell (the category cascade, the Recurring
   checkbox + its frequency select) - those cells are too narrow to fit
   them side by side. */
.inline-edit-stack { display: flex; flex-direction: column; gap: 3px; }
.inline-edit-stack .checkbox-label {
  font-size: calc(var(--grid-font-size) - 1px);
  gap: 4px;
  white-space: nowrap;
}

/* The Budget drill-down's own inline edit (BUD-13) - unlike the
   Transactions grid, this table's columns (Budgeted/Activity/Remaining/
   Last month/Progress) have no natural place to put a Description or
   Account field, so an editing row spans every column (colspan) and lays
   every field out as one wrapping line instead of one field per column. */
.budget-inline-edit {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  padding: 4px 0;
}
.budget-inline-edit .grid-edit-input { width: auto; flex: 0 0 auto; }
.budget-inline-edit-description { flex: 1 1 160px; min-width: 120px; }
.budget-inline-edit-amount { width: 90px; }
.budget-inline-edit .checkbox-label {
  font-size: calc(var(--grid-font-size) - 1px);
  gap: 4px;
  white-space: nowrap;
}

.variance-over { color: var(--danger); font-weight: 600; }
.variance-under { color: var(--pos); font-weight: 600; }

/* A checkbox with its label on one line, used for the "Include in budget"
   toggle on the Master/Category/Subcategory admin forms. */
.checkbox-label { display: flex; align-items: center; gap: 8px; font-weight: 500; }
.checkbox-label input { width: auto; }

/* One checkbox per suggested recurring group (Import's automatic panel and
   Admin -> Recurring's on-demand scan share this same list styling). */
.recurring-suggestion-row { margin-bottom: 8px; font-weight: 400; }

#txAddToggleBtn { margin-bottom: 20px; }

/* ---- Budget tab -------------------------------------------------------- */

.budget-month-nav {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 20px;
}
.budget-month-nav .row-btn {
  font-size: 16px;
  padding: 4px 12px;
}
.budget-month-label { font-size: 20px; font-weight: 700; color: var(--ink); min-width: 160px; text-align: center; }
.budget-month-nav input[type="month"] { max-width: 160px; }
.budget-currency-picker {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-left: auto;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
}
.budget-currency-picker select { width: auto; padding: 6px 10px; }

.budget-toolbar {
  display: flex;
  align-items: center;
  gap: 20px;
  margin-bottom: 10px;
  flex-wrap: wrap;
}
.budget-collapse-picker {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
}
.budget-collapse-picker select { width: auto; padding: 6px 10px; }

/* Lays out several banners side by side (Income vs Expense's Income/
   Expense/Net trio) instead of one full-width banner stacked per row -
   each banner keeps its own margin-bottom, so wrapping to a second line
   on narrow viewports still looks intentional. */
.budget-summary-row { display: flex; gap: 16px; flex-wrap: wrap; margin-bottom: 20px; }
.budget-summary-row .budget-banner { flex: 1 1 220px; margin-bottom: 0; }

.budget-banner {
  border-radius: var(--radius);
  padding: 24px 28px;
  margin-bottom: 20px;
  box-shadow: var(--shadow-card);
  color: #FFFFFF;
  transition: background 0.2s ease;
}
.budget-banner-green { background: linear-gradient(135deg, var(--accent), var(--accent-dark)); }
.budget-banner-orange { background: linear-gradient(135deg, #E6A44E, var(--orange)); }
.budget-banner-red { background: linear-gradient(135deg, #EB7169, var(--danger)); }

.budget-banner-amount { font-size: 36px; font-weight: 800; letter-spacing: -0.5px; }
.budget-banner-label { font-size: 14px; text-transform: uppercase; letter-spacing: 0.5px; opacity: 0.9; margin-top: 2px; }
.budget-banner-breakdown {
  display: flex;
  gap: 24px;
  margin-top: 14px;
  font-size: 13px;
  opacity: 0.95;
  flex-wrap: wrap;
}
.budget-banner-breakdown strong { font-weight: 700; }

/* ---- Reports: Net Worth --------------------------------------------- */

#netWorthChartContainer { width: 100%; overflow-x: auto; }
#netWorthChartContainer svg { display: block; width: 100%; height: auto; }
.networth-chart-line { fill: none; stroke: var(--accent); stroke-width: 2.5; }
.networth-chart-area { fill: url(#networthAreaGradient); }
.networth-chart-dot { fill: var(--accent-dark); }
.networth-chart-axis { stroke: var(--line); stroke-width: 1; }
.networth-chart-label { fill: var(--muted); font-size: 11px; }

/* ---- Reports: Spending Trends ---------------------------------------- */
/* Same chart shape as Net Worth just above (renderSpendingChart mirrors
   renderNetWorthChart), colored red-toned rather than green - an
   increase in spending is the unwelcome direction, the opposite sense
   from net worth going up. */

#spendingChartContainer { width: 100%; overflow-x: auto; }
#spendingChartContainer svg { display: block; width: 100%; height: auto; }
.spending-chart-line { fill: none; stroke: var(--danger); stroke-width: 2.5; }
.spending-chart-area { fill: url(#spendingAreaGradient); }
.spending-chart-dot { fill: var(--danger); }

/* Reports - Income vs Expense: a grouped bar per month (green = income,
   red = expense), same axis/label styling as the line charts above. */
#incomeExpenseChartContainer { width: 100%; overflow-x: auto; }
#incomeExpenseChartContainer svg { display: block; width: 100%; height: auto; }
.ie-chart-bar-income { fill: var(--accent); }
.ie-chart-bar-expense { fill: var(--danger); }

/* Reports - shared period/account filter bar (Net Worth, Spending Trends,
   Income vs Expense) and Spending Trends' category drill-down breadcrumb. */
.report-breadcrumb { font-size: 13px; margin-bottom: 10px; }
.report-breadcrumb button { background: none; border: none; color: var(--accent-dark); font-weight: 600; padding: 0; cursor: pointer; }
.report-breadcrumb button:hover { text-decoration: underline; }

/* Spending Trends "Totals" view - a hand-rolled SVG pie/donut (GEN-2, same
   no-charting-library rule as the line charts) plus a clickable legend;
   clicking a Master slice drills into its subcategories, clicking a
   subcategory jumps to the Transactions grid filtered to it. */
.spending-pie-wrap { display: flex; gap: 28px; align-items: center; flex-wrap: wrap; }
.spending-pie-wrap svg { width: 280px; height: 280px; flex-shrink: 0; }
.spending-pie-slice { cursor: pointer; stroke: #fff; stroke-width: 1.5; transition: opacity 0.15s; }
.spending-pie-slice:hover { opacity: 0.82; }
.spending-pie-legend { display: flex; flex-direction: column; gap: 6px; flex: 1; min-width: 220px; }
.spending-pie-legend-row {
  display: flex; align-items: center; gap: 8px; cursor: pointer;
  padding: 4px 6px; border-radius: 6px; font-size: 13px;
}
.spending-pie-legend-row:hover { background: var(--bg); }
.spending-pie-swatch { width: 12px; height: 12px; border-radius: 3px; flex-shrink: 0; }
.spending-pie-legend-label { flex: 1; }
.spending-pie-legend-value { color: var(--muted); font-variant-numeric: tabular-nums; }

/* Three visibly distinct shades, darkest at the top - so it's obvious at a
   glance which level a row belongs to even before reading its indent. */
#budgetTable .row-master td { background: #E3ECE8; }
.budget-table .row-category td { font-weight: 600; padding-left: 16px; color: #33474C; background: #F1F6F4; }
.budget-table .row-subcategory td { background: #FFFFFF; font-size: calc(var(--grid-font-size) - 1px); }
.budget-table .row-subcategory td:first-child { padding-left: 32px; color: var(--muted); }
.budget-table .budget-input { width: 100px; text-align: right; padding: 4px 6px; }

.disclosure-spacer { display: inline-block; width: 18px; }
.budget-txn-count { color: var(--muted); font-size: calc(var(--grid-font-size) - 2px); }

/* A subcategory's transaction drill-down - indented one level past the
   subcategory row itself, in a muted tone so it reads as supporting detail
   rather than another row of the same kind. */
.budget-table .row-transaction-detail td {
  background: #FBFCFC;
  padding-left: 52px;
  font-size: calc(var(--grid-font-size) - 1.5px);
  color: var(--muted);
  font-style: italic;
}

/* Budget uses the dropdown-only sort/filter model (like Transactions), not
   Monthly Summary's click-header-text-to-sort model, so it shouldn't inherit
   summary-table's pointer cursor + hover highlight on the header text. */
.budget-table.data-table .header-row th { cursor: default; }
.budget-table.data-table .header-row th:hover { background: #FBFCFC; }

/* The little ▸/▾ triangle that collapses a Master or Category's children.
   Sits inline right before the name, in whichever cell already has the
   right indentation for that row's level. */
.disclosure {
  display: inline-block;
  width: 14px;
  margin-right: 4px;
  cursor: pointer;
  user-select: none;
  color: var(--muted);
}

/* ---- Sticky header: the month nav, banner, and grid column headers stay
   in place while the category/subcategory rows scroll underneath them. ---- */
.budget-sticky-header {
  position: sticky;
  top: 0;
  z-index: 6;
  background: var(--bg);
  padding-top: 4px;
  padding-bottom: 4px;
}
/* The generic `table { overflow: hidden }` rule above (there to clip
   square header-cell corners to the table's rounded corners) also clips
   position:sticky - an ancestor with overflow other than visible breaks a
   sticky descendant's ability to stick to the page. Turn it back off here,
   and round the header row's own outer corners directly instead so the
   table still looks the same. */
#budgetTable { overflow: visible; }
#budgetTable thead tr:first-child th:first-child { border-top-left-radius: var(--radius); }
#budgetTable thead tr:first-child th:last-child { border-top-right-radius: var(--radius); }
#budgetTable thead th {
  position: sticky;
  z-index: 5;
  background: #FBFCFC;
}

.budget-bar-track {
  width: 100px;
  height: 8px;
  border-radius: 999px;
  background: var(--line);
  overflow: hidden;
}
.budget-bar-fill { height: 100%; border-radius: 999px; transition: width 0.2s ease; }
.budget-bar-green { background: var(--accent); }
.budget-bar-orange { background: var(--orange); }
.budget-bar-red { background: var(--danger); }

/* Smaller screens: the sidebar becomes a horizontal top bar, and the
   cascading selects/toolbars drop back to a single column. */
@media (max-width: 700px) {
  .app-shell { flex-direction: column; }
  .sidebar, .sidebar.collapsed { width: 100%; flex-direction: row; align-items: center; overflow-x: auto; padding: 10px 12px; }
  .sidebar-brand { padding: 6px 10px; }
  .sidebar .tab { width: auto; white-space: nowrap; }
  .sidebar-toggle { display: none; } /* collapsing isn't useful once the sidebar is already a horizontal bar */
  .sidebar.collapsed .tab-label, .sidebar.collapsed .sidebar-brand-name { display: inline; }
  main { padding: 16px; }
  .grid-2, .grid-3 { grid-template-columns: 1fr; }
  .toolbar { flex-wrap: wrap; }
}
