/* main.css - Structural styles. Color palette lives in css/themes/*.css
   (loaded after this file by index.php based on Settings.Theme). */

/* Global box-sizing reset — every element measures padding/border inside its
   declared width. Previously provided by Bootstrap's global reset (now removed);
   kept here so existing layout math stays correct. */
*, *::before, *::after {
	box-sizing: border-box;
}

/* Universal hide utility — the app toggles `.hidden` (and the `[hidden]`
   attribute) to switch views, collapse action buttons, hide form groups, etc.
   This used to come from Bootstrap's `.hidden` utility / reboot; restored here
   so it survives Bootstrap's removal. `!important` is required because it
   overrides elements that declare their own display (grid / flex / contents). */
.hidden,
[hidden] {
	display: none !important;
}

html, body {
	height: 100%;
	margin: 0;
	overflow: hidden;
}

body {
	background-color: var(--bg-body);
	font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
	color: var(--text-primary);
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

/* ===== Sidebar layout (desktop) =================================== */
/* The page is wrapped in #app — a grid: fixed-width sidebar on the left,
   flexible main column on the right. responsive.css collapses this to a
   single column under 768px; the sidebar becomes a slide-in drawer toggled
   by the hamburger in each canvas header. */
#app {
	display: grid;
	grid-template-columns: 220px 1fr;
	height: 100vh;
	height: 100dvh; /* dvh tracks the actually-visible viewport on mobile */
	max-width: 1200px;
	margin: 0 auto; /* centre the whole shell on wide monitors */
}
#app-main {
	min-width: 0; /* lets the main column shrink so children with overflow scroll */
	height: 100vh;
	height: 100dvh; /* pin to dynamic viewport so absolute children (action bar, date pill) anchor to the visible screen bottom */
	display: flex;
	flex-direction: column;
	overflow: hidden;
	position: relative; /* positioning context for the bottom action bar */
}

#sidebar {
	background: var(--sidebar-bg);
	border-right: 1px solid var(--sidebar-border);
	padding: 18px 12px;
	display: flex;
	flex-direction: column;
	overflow-y: auto;
}

/* Brand block — gradient mark + wordmark */
.brand {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 4px 10px 18px;
	font-weight: 600;
	font-size: 15px;
	color: var(--text-primary);
}
.brand-mark {
	width: 40px;
	height: 40px;
	border-radius: 7px;
	display: block;
	flex-shrink: 0;
	object-fit: contain;
}

/* Group container — uppercase label + stack of nav items */
.nav-group {
	display: flex;
	flex-direction: column;
	gap: 1px;
	margin-bottom: 14px;
}
.nav-label {
	font-size: 10px;
	text-transform: uppercase;
	letter-spacing: 0.12em;
	color: var(--sidebar-label);
	padding: 8px 10px 6px;
}

/* Clickable nav row — icon + text */
.nav-item {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 7px 10px;
	border-radius: 6px;
	color: var(--sidebar-item);
	cursor: pointer;
	border: 0;
	background: transparent;
	font-family: inherit;
	font-size: 13.5px;
	text-align: left;
	width: 100%;
	transition: background 100ms ease, color 100ms ease;
}
.nav-item:hover {
	background: var(--sidebar-item-hover-bg);
	color: var(--sidebar-item-hover-text);
}
.nav-item.active {
	background: var(--sidebar-item-active-bg);
	color: var(--sidebar-item-active-text);
}
.nav-item.active .nav-icon {
	color: var(--sidebar-item-active-icon);
}
.nav-item .nav-icon {
	font-size: 18px;
	color: var(--sidebar-label);
	flex-shrink: 0;
}
.nav-item:hover .nav-icon {
	color: var(--sidebar-item-hover-text);
}

/* "Budget" indicator nav-item — shows the active budget name (opens the
   database manager on click). Name reads in the active-item text colour so it
   stands out as the "you are here" anchor. */
.nav-item-budget .nav-text {
	font-weight: 600;
	color: var(--sidebar-item-active-text);
}

/* Pushes the search + settings block to the bottom of the rail */
.nav-spacer { flex: 1; }

/* ===== Budget date floater ========================================= */
/* Pill that sits inside the Budget canvas BODY but visually floats at the
   bottom of the view. position: absolute anchored to #view-budget (see the
   `position: relative` rule below) — that escapes the canvas-body scroll
   container so the pill stays pinned to the canvas bottom while the body
   scrolls behind it. Hidden when the action bar is visible (multi-select)
   and when any slideout is open (mobile slideouts are 100vw and would
   otherwise sit on top of the floater). */
#view-budget {
	position: relative;
}
/* Budget body — explicit padding on all four sides so this higher-specificity
   rule doesn't silently let any side fall back through the cascade. Matches
   the generic .canvas-body sides (30px) and adds the extra bottom breathing
   room so the last row never sits behind the floating date pill. */
#view-budget .canvas-body {
	/* Only override the bottom — h-padding inherits from .canvas-body's
	   single rule. Extra bottom clears the floating date pill. */
	padding-bottom: 90px;
}
.budget-date-floater {
	position: absolute;
	bottom: 20px;
	left: 50%;
	transform: translateX(-50%);
	/* Only needs to float over the scrolling body content (z-auto). It's
	   display:none'd whenever the action bar or a slideout is visible (the
	   :has rules below), so it never competes with those higher layers. */
	z-index: 1;
	display: inline-flex;
	align-items: center;
	gap: 8px;
	padding: 8px 16px;
	border-radius: 999px;
	background: var(--bg-darker);
	box-shadow: 0 4px 12px var(--shadow);
}
#app-main:has(#action-bar.visible) .budget-date-floater { display: none; }
body:has(.slideout-panel.active) .budget-date-floater { display: none; }


/* Period summary — three-tile row at the top of #view-budget for upcoming
   budget periods. Net Result is the "hero" tile (wider, with Open Period
   button inside); Income + Out are equal-width status tiles. Hidden via
   server-side render (the renderer returns '' for current / past periods),
   so no CSS visibility rules needed here. */
.period-summary {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 10px;
	padding: 14px 0 18px;
}
.period-summary-tile {
	background: var(--bg-darker);
	border: 1px solid var(--border-color);
	border-radius: 10px;
	padding: 14px 16px;
}
.period-summary-tile.hero {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
}
/* Net Result label + value are always right-aligned inside the hero
   tile — keeps the title pinned to the tile's right edge whether the
   Open Period button is present (button left / label right) or absent
   (label right). */
.period-summary-hero-body {
	text-align: right;
}
.period-summary-tile.hero:not(:has(.btn-open-period)) {
	justify-content: flex-end;
}
.period-summary-tile.hero.pos {
	border-color: color-mix(in srgb, var(--accent-green) 35%, var(--border-color));
}
.period-summary-tile.hero.neg {
	border-color: color-mix(in srgb, var(--accent-red) 35%, var(--border-color));
}
.period-summary-lbl {
	font-size: 10.5px;
	text-transform: uppercase;
	letter-spacing: 0.12em;
	color: var(--text-muted);
	margin-bottom: 4px;
}
.period-summary-val {
	font-size: 18px;
	font-weight: 600;
	color: var(--text-primary);
	font-variant-numeric: tabular-nums;
}
.period-summary-tile.hero .period-summary-val {
	font-size: 24px;
}
.period-summary-tile.hero.pos .period-summary-val { color: var(--accent-green); }
.period-summary-tile.hero.neg .period-summary-val { color: var(--accent-red); }

/* Closed/current-period actuals (D_Budget_PeriodActuals.php) — reuses the
   .period-summary tiles for the per-period row, then stacks a cumulative
   "To date" row beneath it, separated by a rule + small heading. The two
   inner .period-summary rows already carry their own v-padding. */
.period-actuals-todate {
	border-top: 1px solid var(--border-color);
}
/* The per-period row sits directly under the header bar (no rule above it). No
   bottom padding — the cumulative row's 10px top padding alone provides the gap,
   matching the 10px gap between the tiles. */
.period-actuals > .period-summary {
	padding-bottom: 0;
}
.period-actuals-todate .period-summary {
	padding-top: 10px;
}

/* Current-period plan-vs-actual (D_Budget_PeriodProgress.php) — reuses the
   .period-summary tiles; each tile carries a muted "Planned $X" reference line
   under the live actual, and the Net Result hero adds a coloured ahead/behind
   variance (the "are we on track?" read). */
.period-progress-sub {
	font-size: 11px;
	color: var(--text-muted);
	margin-top: 5px;
}
.period-progress-var.pos  { color: var(--accent-green); }
.period-progress-var.neg  { color: var(--accent-red); }
.period-progress-var.flat { color: var(--text-muted); }

 .material-symbols-outlined {
      vertical-align: middle;
  }

.progress {
	background-color: var(--bg-input) !important;
}

/* Pills inline with the label (legacy callers — Merge preview, etc.) */
.tag-pills {
	display: inline-flex;
	flex-wrap: wrap;
	gap: 6px;
	vertical-align: middle;
}

/* Wrapper used by the Income/Expense + Split slideouts. Pills and the
   "+ Add Tag" button share one flex/wrap context so they line up with a
   single 6px gap. `.tag-pills` inside dissolves to `display: contents`
   so every pill becomes a direct flex item of `.tags-row`. */
.tags-row {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
	align-items: center;
}

.tags-row .tag-pills {
	display: contents;
}

/* Cursor for any clickable element that needs a pointer */
.pointer {
	cursor: pointer;
}

/* Tag pill — used in tag manager, picker, and expense/income forms.
   inline-flex + overflow:hidden + padding-right transition enable the
   hover-slide-out × built by buildTagPills($tags, $removeFn). */
.tag-pill {
  display: inline-flex;
  align-items: center;
  padding: 2px 7px;
  border-radius: 4px;
  font-size: 0.82em;
  font-weight: 700;
  color: var(--text-on-accent);
  letter-spacing: 0.5px;
  text-transform: uppercase;
  overflow: hidden;
  transition: padding-right 200ms cubic-bezier(.4,0,.2,1);
}

/* Only expand right-padding when the pill actually has an × to reveal
   (display-only pills like Merge preview / import-mode static stay still). */
.tag-pill:has(.tag-pill-remove):hover {
  padding-right: 6px;
}

/* "+ Add Tag" pills — SIZING-only modifier, used as `add-btn add-tag`.
   The dashed border + blue hover come from the .add-btn base; this only shrinks
   the full-width base down to an inline pill that slots into a `.tags-row`. */
.add-tag {
  display: inline-flex;
  align-items: center;
  width: auto;
  margin-top: 0;
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 0.82em;
  font-weight: 700;
  letter-spacing: 0.5px;
  text-transform: uppercase;
}

/* Tags row in the transaction/withdrawal slideouts — the colored .tag-pill
   tags and the "+ Add Tag" .tags-filter-chip share one row and should match
   each other. Sized a touch smaller than the app-wide defaults; scoped to
   .tags-row so budget-row tags and the Tags-canvas filter chips are untouched. */
/* Colored tag pills in a form tags row — sized a touch smaller than app-wide. */
.tags-row .tag-pill {
  padding: 2px 6px;
  font-size: 0.72em;
}

/* "+ Add Tag" in a form tags row should read like the "+ Add row" (.add-btn)
   button, NOT the uppercase filter chip: same 12px / 600 weight, mixed case, no
   letter-spacing, and the same dim text + border colour (the chip's bold 700,
   uppercase, and brighter --text-secondary / --text-tertiary made it look
   bigger & bolder). */
.tags-row .tags-filter-chip {
  padding: 2px 6px;
  font-size: 12px;
  font-weight: 600;
  text-transform: none;
  letter-spacing: normal;
  color: var(--text-muted);
  border-color: var(--border);
}

/* User-tag dots on rows (the `● TagName` chips emitted by buildTagDots()).
   Uppercase only when the dot represents a real Tag — the same .tag-dot-item
   class is used for signifier dots ("Split Transaction", "1 Attachment",
   etc.) which stay in their natural case. data-tagid distinguishes the two. */
.tag-dot-item[data-tagid] {
	text-transform: uppercase;
	letter-spacing: 0.3px;
}

/* ===== Tags filter chips ==========================================
   Live in the Tags canvas SUBHEADER, alongside the settings + transactions-
   search input (same pattern as Jars). The empty-state CTA is a
   static element inside #view-tags, hidden via :has() when any chip
   is present. */
.tags-filter-chips {
	display: inline-flex;
	flex-wrap: wrap;
	gap: 6px;
	align-items: center;
}
/* Collapse the chip container entirely when empty so the topbar's
   12px gap doesn't leave a phantom space before the + button. */
.tags-filter-chips:empty {
	display: none;
}
/* Square-pill shape — small uppercase chip with a 4px border-radius. The
   strip shows EVERY tag in the system; click toggles a pill in/out of
   $_SESSION['TagFilter']. Default state is "ghost" (dashed outline,
   muted text). .is-selected pills carry an inline style with the tag's
   own background + font colours. */
.tags-filter-chip {
	display: inline-flex;
	align-items: center;
	padding: 3px 8px;
	border-radius: 4px;
	/* <button> doesn't inherit font-family — without this it renders in the UA
	   default (MS Shell Dlg on Windows), which looks heavier/wider than the app
	   font used everywhere else. */
	font-family: inherit;
	font-size: 10px;
	font-weight: 700;
	letter-spacing: 0.5px;
	text-transform: uppercase;
	line-height: 1.2;
	white-space: nowrap;
	cursor: pointer;
	background: transparent;
	color: var(--text-secondary);
	border: 1px dashed var(--text-tertiary);
	transition: color 120ms ease, border-color 120ms ease;
}
.tags-filter-chip:hover {
	color: var(--text-primary);
	border-color: var(--accent-blue);
}
/* Selected pill — full tag colour via inline style, solid border to
   match (so the dashed outline doesn't visually compete with the fill). */
.tags-filter-chip.is-selected {
	border-style: solid;
	border-color: transparent;
}
.tags-filter-chip-label {
	line-height: 1;
}
/* Empty-state CTA — sits inside #view-tags as a static element. Hidden
   whenever the topbar's chips container has any selected chip. Sized big
   so the prompt to "choose a tag above" reads as the primary action when
   the canvas is otherwise empty. */
.tags-filter-empty {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 24px;
	padding: 140px 20px;
	color: var(--text-secondary);
	text-align: center;
}
body:has(#refresh-container-tags-header .tags-filter-chip.is-selected) .tags-filter-empty {
	display: none;
}
/* Descendant selector bumps specificity above .material-symbols-outlined,
   which sets font-size: 24px on every icon and would otherwise win on
   source-order tiebreak. */
.tags-filter-empty .tags-filter-empty-icon {
	font-size: 96px;
	color: var(--text-tertiary);
}
.tags-filter-empty-message {
	font-size: 20px;
	font-weight: 500;
	max-width: 360px;
	line-height: 1.4;
}
.tags-filter-empty-cta {
	padding: 8px 16px;
}

/* Categories canvas empty-state — same big icon + message treatment as the
   Tags canvas (.tags-filter-empty), but its OWN class so the tags-filter
   :has() hide rule (keyed on a selected tag chip) can never hide it. */
.categories-empty-state {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 24px;
	padding: 140px 20px;
	color: var(--text-secondary);
	text-align: center;
}
.categories-empty-state .categories-empty-state-icon {
	font-size: 96px;
	color: var(--text-tertiary);
}
.categories-empty-state-message {
	font-size: 20px;
	font-weight: 500;
	max-width: 360px;
	line-height: 1.4;
}

/* Jars canvas empty-state — same big icon + message treatment as the
   Categories (.categories-empty-state) and Tags (.tags-filter-empty)
   canvases. Shown by D_Jars_Grid.php when no jars exist in the system. */
.jars-empty-state {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 24px;
	padding: 140px 20px;
	color: var(--text-secondary);
	text-align: center;
}
.jars-empty-state .jars-empty-state-icon {
	font-size: 96px;
	color: var(--text-tertiary);
}
.jars-empty-state-message {
	font-size: 20px;
	font-weight: 500;
	max-width: 360px;
	line-height: 1.4;
}


/* Actualized summary row — clickable toggle, never hidden by the toggle system */
.actualized-summary-row {
	cursor: pointer;
}

/* Income privacy blur — Settings.BlurIncome renders the class at
   page load. Click-and-hold (1s) triggers a peek by removing the class. */
#IncomeContainer.income-blurred .CostColumn,
#IncomeContainer.income-blurred tfoot td,
#IncomeContainer.income-blurred .expense-amount,
#IncomeContainer.income-blurred .section-footer {
	filter: blur(6px);
	user-select: none;
}
/* Magnifying-glass cursor on the whole income container when blurred. Inner
   .clickable rows have their own cursor: pointer which would otherwise win,
   so override them too — every descendant gets zoom-in until the user releases. */
#IncomeContainer.income-blurred,
#IncomeContainer.income-blurred .clickable,
#IncomeContainer.income-blurred .expense-row {
	cursor: zoom-in;
}
  .category-pickers {
        display: flex;
        gap: 0;
  }

  /* Toggle button - pill style */
  .btn-toggle {
        display: inline-flex;
        align-items: center;
        gap: 4px;
        padding: 4px 12px;
        font-size: 9px;
        font-weight: normal;
        border: 1px solid var(--border-color);
        border-radius: 20px;
        background-color: var(--bg-darker);
        cursor: pointer;
  }

  .btn-toggle:hover {
        background-color: var(--bg-hover);
  }

  .DateColumn {
        white-space: nowrap;
  }

  .budget-grid {
      display: grid !important;
      grid-template-columns: repeat(3, 1fr);
      gap: 8px;
  }

  .budget-item {
      display: flex !important;
      justify-content: space-between;
      padding: 8px;
  }

/* Import rule items in recurring slideouts */
.importrule-item {
	padding: 10px 12px;
	border: 1px solid var(--border);
	border-radius: 4px;
	margin-bottom: 6px;
	font-size: 14px;
	color: var(--text-primary);
	cursor: pointer;
	transition: border-color 0.2s;
}

.importrule-item:hover {
	border-color: var(--accent-blue);
}

/* Match Rules header — label text + small info icon side-by-side */
.match-rules-label {
	display: inline-flex;
	align-items: center;
	gap: 6px;
}
.match-rules-info {
	color: var(--text-secondary);
	cursor: help;
}
.match-rules-info:hover {
	color: var(--accent-blue);
}

/* "+ Add Rule" sits ABOVE the rules list, so it needs bottom spacing. Its
   dashed border + blue hover come from the shared .add-btn base. */
.add-import-rule {
	margin-bottom: 8px;
}

.emoji {
	font-style: normal;
	font-size: 1.1em;
	line-height: 1;
	vertical-align: middle;
	display: inline-block;
	font-display: swap;
}

@font-face {
	font-family: 'Material Symbols Outlined';
	font-style: normal;
	font-weight: 400;
	src: url('/fonts/MaterialSymbolsOutlined.woff2') format('woff2');
	font-display: block;
}

  .verified-row {
      opacity: 0.6;
  }

  
.material-symbols-outlined {
	font-family: 'Material Symbols Outlined';
	font-weight: normal;
	font-style: normal;
	font-size: 24px;
	display: inline-block;
	line-height: 1;
	text-transform: none;
	letter-spacing: normal;
	word-wrap: normal;
	white-space: nowrap;
	direction: ltr;
	font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
}

/* ========== JARS SIDEBAR ========== */
/* Panels wrapper — holds view-budget and view-jars as siblings */
#panels-wrapper {
	display: contents;
}

/* ===== View Canvas — shared header+body frame for every main view =====
   Loaded by D_Main.php via Template::get('View_Canvas') and rendered once
   per view (#view-budget / #view-categories / #view-jars / #view-tags) so
   the structural shape is identical across views. Visual styling
   (typography, colors, borders, padding) deliberately not set here —
   layout-only. */
.canvas {
	flex: 1;
	min-height: 0;
	display: flex;
	flex-direction: column;
}
/* Header is its own row — fixed-height block at the top of the canvas,
   does NOT scroll. Body below takes flex: 1 and owns the scroll. No
   sticky / no z-index / no background gymnastics required. */
.canvas-header {
	display: flex;
	flex-direction: column;
	gap: 10px;
	padding: 20px 20px 12px;
}
.canvas-header-row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
}
.canvas-header-left {
	display: flex;
	align-items: center;
	gap: 14px;
}
.canvas-header-right {
	display: flex;
	align-items: center;
	gap: 8px;
}
/* Icon cluster wrapper inside .canvas-header-right — groups consecutive
   icon buttons with a tight 4px gap. The parent's 8px gap then sits
   between this cluster and the search input (or other widgets), so the
   icons read as a group while still being clearly separated from
   neighbouring widgets. The .header-icon-btn { margin-left: 5px }
   rule from the slideout-header context doesn't fire here — gap owns
   the spacing inside this wrapper. */
.canvas-header-icons {
	display: inline-flex;
	align-items: center; 
	gap: 4px;
}
.canvas-header-icons .header-icon-btn {
	margin-left: 0;
}
/* Optional second row tucked under the title row — used by Tags canvas
   for the selected-tag pill strip. Collapses entirely when empty so
   canvases that don't pass anything don't get a phantom blank row. */
.canvas-header-subrow {
	padding-top: 12px;
}
.canvas-header-subrow:empty {
	display: none;
}
/* Canvas-level footer — sized to content, stays put, sits below the
   scrollable .canvas-body. View_Canvas.template renders the wrapper
   unconditionally; the `:empty` rule below collapses it to nothing when
   the canvas passes `FOOTER => ''`. */
.canvas-footer {
	padding: 14px 20px;
	background: var(--bg-app);
}
/* Collapse the wrapper when no content was passed. `:empty` matches an
   element with NO children and NO text nodes — strtr's empty-string
   substitution leaves `<div class="canvas-footer"></div>` exactly empty,
   so this rule fires. */
.canvas-footer:empty {
	display: none;
	padding: 0;
}
.canvas-title {
	font-size: 22px;
	font-weight: 700;
	color: var(--text-primary);
	letter-spacing: 0.2px;
	line-height: 1.2;
}
/* Hamburger lives in every canvas's left cluster but is hidden on desktop.
   responsive.css un-hides it under 768px. Class (not ID) because there is
   one per canvas — not a singleton. */
.canvas-hamburger {
	display: none;
	background: transparent;
	border: 0;
	color: inherit;
	cursor: pointer;
	padding: 0;
	align-items: center;
	justify-content: center;
}
.canvas-body {
	flex: 1;
	min-height: 0;
	overflow-y: auto;
	/* H-padding matches .canvas-header's h-padding (20px) so body content
	   sits visually flush under the header title — no shift inward.
	   No padding-bottom — short lists (Recurring, Categories Manage) would
	   otherwise show empty space below their last item that reads as a
	   phantom footer. Long-scrolling canvases (Budget) never visually
	   needed it anyway. Inner content adds its own bottom breathing room
	   via section margins. */
	padding: 0 20px 0;
}

/* Jars canvas — 30px top padding so the first row of jar cards isn't flush
   against the canvas header (per-view exception, single property only). */
#view-jars .canvas-body { padding-top: 30px; }

#sumOfSelected {
	padding-right: 10px;
}

/* Open Period button — lives inside the period-summary hero tile.
   Ghost styling (transparent + bordered) so it sits clean on the
   tile's tinted background rather than fighting it with another pill. */
.btn-open-period {
	display: inline-block;
	font-size: 12px;
	font-weight: 500;
	color: var(--text-primary);
	background: transparent;
	padding: 0 12px;
	height: 30px;
	border-radius: 6px;
	border: 1px solid var(--border-color);
	cursor: pointer;
	transition: background 120ms ease;
}

.btn-open-period:hover {
	background: var(--bg-hover);
}

form {
	margin: 0;
}

.col-Date {
	padding-left: 5px;
}

#SaveAndPayButton {
	display: none;
}

.col-Amount {
	text-align: right;
}

.JarsTable,
.IncomeTable,
.CategoryTable,
.BudgetTable {
	display: table;
	overflow: hidden;
	width: 100%;
}

.ChildRow {
	transition: all 500ms;
}

/* Empty jar card — constrained to same size as real jar cards */
.jar-card-empty {
	max-width: 150px;
	color: var(--text-muted);
	opacity: 0.4;
	cursor: default !important;
}

/* No jars found message in jars panel */
.no-jars-message {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 8px;
	padding: 30px 0;
	color: var(--text-muted);
	font-size: 13px;
}

.no-jars-message .material-symbols-outlined {
	font-size: 36px;
	opacity: 0.3;
}

.no-jars-message p {
	margin: 0;
	opacity: 0.5;
}

.CategoryMessage {
	width: 100%;
	margin: auto;
	text-align: center;
	font-weight: bold;
	font-size: 20px;
	padding-top: 50px;
	padding-bottom: 50px;
	color: var(--text-primary);
}

.main-content-scroll {
	flex: 1;
	min-height: 0;
	display: flex;
	flex-direction: column;
	overflow: hidden;
	/* Positioning context so the absolutely-positioned .canvas-loading-overlay
	   anchors to the view it covers, not to the page. */
	position: relative;
}
/* Canvas-level refresh container is structural only — collapse it in
   the layout so .canvas becomes a direct child of the view div
   and the flex chain (view div → canvas → header/body) lines up.
   Inner refresh containers inside the canvas aren't direct children
   of .main-content-scroll, so they're not affected. */
.main-content-scroll > [id^="refresh-container-"] {
	display: contents;
}

/* Canvas loading overlay — refreshCanvas() appends one of these into the view
   (a sibling of the refresh-container) instead of blanking the canvas with the
   spinner. It sits ON TOP of the canvas content via position:absolute and is
   fully transparent — just the centered spinner floats over the existing
   content while the new HTML loads, then the overlay is removed. z-index sits
   above the canvas content but BELOW the slideout overlay (10), so when a
   slideout is open its dim sheet covers this spinner — a canvas refresh fired
   from inside a slideout updates quietly behind it instead of punching a
   spinner through to the front. With no slideout open, it shows normally. */
.canvas-loading-overlay {
	position: absolute;
	inset: 0;
	z-index: 5;
	display: flex;
	align-items: center;
	justify-content: center;
}

/* Slideout loading overlay — slideoutReloadTop() appends one of these over a
   slideout panel's existing content while it reloads. It scrims + blocks
   interaction WITHOUT blanking the panel (no flash); the overlay self-destructs
   when ajaxLoad replaces the panel's HTML with the fresh content. Anchors to the
   position:fixed .slideout-panel; z-index sits above the panel's own content. */
.slideout-loading-overlay {
	position: absolute;
	inset: 0;
	z-index: 5;
	display: flex;
	align-items: center;
	justify-content: center;
	background: color-mix(in srgb, var(--bg-main) 60%, transparent);
}

.DefaultAmountDot {
	color: var(--accent-blue);
}

/* Splat indicator on jar cards — small amber dot in the top-right corner
   marking jars that need settling (fallback or overflow). The card itself
   gets a subtle amber outline so the splat reads at a glance. Both
   directions (fallback/overflow) share the same visual treatment — the
   user finds out which when they open the slideout. */
.jar-card-splat {
	position: relative;
	box-shadow: 0 0 0 1px var(--accent-amber);
}
.jar-card-splat-dot {
	position: absolute;
	top: 6px;
	right: 6px;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: var(--accent-amber);
}

/* Settle banner inside the jar slideout — yellow alert. Whole banner is
   a click target; the inline "Settle Jar →" link is just a visual cue.
   info-box-warning provides the yellow tint. */
.settle-banner {
	display: block;
	margin-bottom: 16px;
	line-height: 1.4;
	cursor: pointer;
}
.settle-banner:hover {
	filter: brightness(1.1);
}
.settle-banner-link {
	color: var(--accent-blue);
	font-weight: 600;
	text-decoration: underline;
	white-space: nowrap;
}

.EntirePageContainerDIV {
      width: 100%;
      height: 100%;
      margin: 0;
      padding: 0;
      display: flex;
      flex-direction: column;
      overflow: hidden;
      box-sizing: border-box;
}

.CostColumn {
	padding-right: 5px;
	text-align: right;
	white-space: nowrap;
	padding-left: 25px;
}

.MainDIV {
      width: 100%;
      background-color: var(--bg-main);
      border-radius: 6px;
      flex: 1;
      display: flex;
      flex-direction: column;
      overflow: hidden;
}

.clickable-container {
	width: 100%;
	margin: auto 0;
	cursor: default;
	border-collapse: collapse;
	box-sizing: border-box;
	background-color: var(--bg-main);
}



tr.selected,
div.expense-row.selected,
div.jarledger-row.selected {
	background-color: var(--selected-bg) !important;
}

tr.selected td {
	border-bottom: 1px solid var(--selected-bg) !important;
}

.clickable-container.AddBorders tbody td {
	border-bottom: 1px solid var(--border);
}

.clickable-container tbody td {
	padding: 3px 8px;
	cursor: default;
	font-size: 13px;
	line-height: 19.5px;
}

.Import .clickable-container {
	margin: auto 0 0 0;
}

div.Ledger .clickable-container thead td {
	font-size: 14px;
}

.clickable-container thead td {
	color: var(--text-primary);
	font-size: 18px;
	font-weight: 500;
	padding: 0 8px 12px;
	border-bottom: 1.5px solid var(--accent-blue);
}

.clickable-container tfoot td {
	text-align: right;
	color: var(--text-primary);
	font-weight: bold;
	font-size: 12px;
	padding-right: 9px;
	padding-top: 5px;
}

#IncomeTable,
#CategoryTable,
#BudgetTable {
	margin-top: 20px;
}

.ImportNewTableFooter td {
	padding-right: 0 !important;
}

.BudgetTotalTable {
	margin-top: 30px;
}

/* Match the rest of the app — body rows + total row use the same 13px font as expense-row */
.BudgetTotalTable tbody td,
.BudgetTotalTable tfoot td {
	font-size: 13px;
}

.BudgetTally {
	border-top: 3px solid var(--border);
}

.BudgetTallyTitles {
	width: 100%;
	text-align: right;
	color: var(--text-primary);
}

.BudgetTallyValues {
	text-align: right;
	color: var(--text-primary);
	font-variant-numeric: tabular-nums;
}

.BudgetTallyDivider {
	padding-left: 15px;
	padding-right: 6px;
	text-align: center;
}

tr.selected td:first-child,
div.expense-row.selected,
div.jarledger-row.selected {
	border-left: 2px solid var(--accent-blue);
}

.clickable-container.HoverableRows tbody tr:hover {
	background-color: var(--bg-hover);
}

@keyframes bounce {
	0%, 20%, 50%, 80%, 100% { transform: translateY(0); }
	40% { transform: translateY(-30px); }
	60% { transform: translateY(-15px); }
}

/* ========== EXPENSE / INCOME ROW LAYOUT ========== */
.section-header {
	font-size: 18px;
	font-weight: 500;
	color: var(--text-primary);
	padding: 0 8px 12px;
	border-bottom: 1.5px solid var(--accent-blue);
	margin-bottom: 4px;
}

.section-footer {
	text-align: right;
	font-weight: bold;
	font-size: 12px;
	padding-right: 9px;
	padding-top: 5px;
	color: var(--text-primary);
}

/* 4-column grid: date | merchant+category | tags | amount */
/* ── Transaction-row typography — SINGLE SOURCE OF TRUTH ───────────────────
   Shared by EVERY transaction-row template so a row looks identical across the
   whole app: the budget-style rows (.expense-row — Budget / Search / Tags /
   Categories / Payment Items) AND the Jar Ledger (.jarledger-row). Each layout
   keeps its own grid/columns, but row text size + colour live HERE ONLY — never
   re-declare them per view. The inner text classes (.expense-merchant-name /
   .expense-category-label / .expense-tags-line / .expense-note) are likewise
   shared by both templates, so the merchant / category / tags / note lines
   already match everywhere. */
.expense-row,
.jarledger-row {
	font-size: 13px;
}
.budget-date-column,
.jarledger-col-date {
	font-size: 12px;
	color: var(--text-primary);
	white-space: nowrap;
}

.expense-row {
	display: grid;
	grid-template-columns: auto 1fr auto;
	align-items: center;
	gap: 8px;
	padding: 9px 8px;
	/* Rows are clickable buttons, not text — block native text-selection so
	   shift-click / drag-select / fast double-click don't paint the row text
	   blue. Selection state is communicated by the .selected class only. */
	user-select: none;
	-webkit-user-select: none;
	border-bottom: 0.5px solid var(--border);
	cursor: default;
	box-sizing: border-box;
}

.expense-row:hover {
	background: var(--bg-hover);
}

.budget-date-column {
	padding-right: 10px;
}

.expense-merchant-name {
	color: var(--text-primary);
	font-weight: 500;
}

.expense-category-label {
	font-size: 11px;
	color: var(--text-muted);
	margin-top: 2px;
}

.expense-tags-line {
	font-size: 11px;
	color: var(--text-muted);
	margin-top: 2px;
}

.expense-category-text {
	padding-right: 8px;
}
.expense-merchant-cell {
	padding-right: 10px;
}

/* Used by summary rows — spans to fill the middle column */
.expense-merchant-cell-wide {
	grid-column: 2 / 3;
}

.expense-note {
	font-size: 11px;
	color: var(--text-muted);
	font-style: italic;
	margin-left: 8px;
}

.tag-dot-item {
	font-size: 11px;
	color: var(--text-muted);
	margin-right: 8px;
	white-space: nowrap;
}

/* Signifier-dot colors — applied as a modifier on .tag-dot.
   Themes can override these without touching inline styles. */
.dot-import    { color: #4a9eff; }
.dot-split     { color: #f0c040; }
.dot-payment   { color: #a78bfa; }
.dot-carryover { color: #a78bfa; }
.dot-receipt   { color: #2dd4bf; }

.expense-amount {
	text-align: right;
	font-variant-numeric: tabular-nums;
	color: var(--text-primary);
}

.no-data-row {
	padding: 12px 8px;
	font-size: 13px;
	color: var(--text-muted);
	text-align: center;
}

/* ========== FORMS & INPUTS ========== */
input,
select,
textarea {
	background-color: var(--bg-input);
	color: var(--text-primary);
	border: 1px solid var(--border);
	border-radius: 4px;
	padding: 6px 10px;
}

/* color-scheme:dark on inputs (date/time pickers need the dark calendar popup)
   and textareas (dark scrollbar). It is deliberately NOT applied to <select>:
   a dark-scheme select makes Chromium paint its option popup with the black
   system canvas and IGNORE author option/select background-color — which is why
   the dropdown was black. Selects stay in the default scheme so our colours win. */
input,
textarea {
	color-scheme: dark;
}

input:focus,
select:focus,
textarea:focus {
	border-color: var(--accent-blue);
	outline: none;
	box-shadow: 0 0 0 3px var(--focus-shadow);
}

/* File inputs — space the native "Browse…" button away from the
   "No file selected" text so they don't sit flush against each other. */
input[type="file"]::file-selector-button {
	margin-right: 12px;
}
input[type="file"]::-webkit-file-upload-button {
	margin-right: 12px;
}

/* ========== BUTTONS ========== */
.btn-default {
	background-color: var(--border);
	color: var(--text-primary);
	border-color: var(--border-hover);
}

.btn-default:hover {
	background-color: var(--bg-hover);
	border-color: var(--border-focus);
	color: var(--text-primary);
}

.btn-primary {
	flex: 1;
	/* Primary button colour is decoupled from --accent-blue so it can be
	   tuned without dragging focus rings / links / hover highlights along.
	   The hex value lives per-theme in css/themes/*.css. */
	background: var(--btn-primary);
	color: white;
	border: none;
	padding: 12px;
	border-radius: 4px;
	cursor: pointer;
	font-size: 14px;
	width: 100%;
	font-weight: 600;
	transition: background 0.2s;
}

.btn-primary:hover {
	background-color: var(--btn-primary-hover);
	border-color: var(--btn-primary-hover);
}

.btn-success {
	background-color: var(--success);
	border-color: var(--success);
	color: var(--success-text);
}

.btn-success:hover {
	background-color: var(--success-hover);
	border-color: var(--success-hover);
}

.btn-danger {
	background-color: var(--danger);
	border-color: var(--danger);
	color: var(--danger-text);
}

.btn-danger:hover {
	background-color: var(--danger-hover);
	border-color: var(--danger-hover);
}

.btn-warning {
	background-color: var(--warning);
	border-color: var(--warning);
	color: var(--warning-text);
}

.btn-warning:hover {
	background-color: var(--warning-hover);
	border-color: var(--warning-hover);
}

/* ========== DROPDOWNS ========== */
.dropdown-menu {
	background-color: var(--bg-input);
	border: 1px solid var(--border);
}

.dropdown-menu > li > a {
	color: var(--text-primary);
}

.dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
	background-color: var(--border);
	color: var(--text-primary);
}

.dropdown-menu > .active > a,
.dropdown-menu > .active > a:hover,
.dropdown-menu > .active > a:focus {
	background-color: var(--accent-blue);
	color: white;
}

/* ========== NAV TABS ========== */
.nav-tabs {
	border-bottom: 2px solid var(--border);
	background: var(--bg-darker);
}

.nav-tabs > li > a {
	background: transparent;
	color: var(--text-muted);
	border: none;
	border-radius: 0;
}

.nav-tabs > li > a:hover {
	background: transparent;
	color: var(--text-primary);
	border: none;
	border-bottom: 2px solid var(--border-hover);
}

.nav-tabs > li.active > a,
.nav-tabs > li.active > a:hover,
.nav-tabs > li.active > a:focus {
	background: transparent;
	color: var(--accent-blue);
	border: none;
	border-bottom: 2px solid var(--accent-blue);
}

.tab-content {
	background: var(--bg-input);
	border: 1px solid var(--border);
	border-top: none;
	padding: 20px;
}

/* ========== BOOTSTRAP TABLES ========== */
.table {
	background-color: var(--bg-main);
	color: var(--text-primary);
}

.table > thead > tr > th,
.table > tbody > tr > th,
.table > tfoot > tr > th,
.table > thead > tr > td,
.table > tbody > tr > td,
.table > tfoot > tr > td {
	border-color: var(--border);
	color: var(--text-primary);
}

.table > thead > tr > th {
	border-bottom: 2px solid var(--accent-blue);
}

.table-striped > tbody > tr:nth-of-type(odd) {
	background-color: var(--bg-input);
}

.table-striped > tbody > tr:nth-of-type(even) {
	background-color: var(--bg-main);
}

.table-hover > tbody > tr:hover {
	background-color: var(--bg-hover);
}

/* ========== TEXT COLORS ========== */
.text-danger {
	color: var(--danger-text);
}

.text-success {
	color: var(--success-text);
}

.text-warning {
	color: var(--warning-text);
}

.text-info {
	color: var(--info-text);
}

.text-muted {
	color: var(--text-dark);
}

/* ========== ALERTS ========== */
.alert-success {
	background-color: var(--success-bg);
	border-color: var(--success);
	color: var(--success-text);
}

.alert-danger {
	background-color: var(--danger-bg);
	border-color: var(--danger);
	color: var(--danger-text);
}

.alert-warning {
	background-color: var(--warning-bg);
	border-color: var(--warning);
	color: var(--warning-text);
}

.alert-info {
	background-color: var(--info-bg);
	border-color: var(--accent-blue);
	color: var(--info-text);
}

/* ========== PANELS ========== */
.panel {
	background-color: var(--bg-main);
	border-color: var(--border);
}

.panel-default > .panel-heading {
	background-color: var(--bg-darker);
	border-color: var(--border);
	color: var(--text-primary);
}

.slideout-body {
	color: var(--text-primary);
}

.ledger-header {
	white-space: nowrap;
	overflow-x: auto;
	padding-bottom: 10px;
	position: sticky;
	top: 0;
	background-color: var(--bg-main);
	z-index: 1;
	padding-top: 10px;
}



/* ========== WELLS ========== */
.well {
	background-color: var(--bg-input);
	border-color: var(--border);
	color: var(--text-primary);
}

/* ========== LABELS & BADGES ========== */
.label-default {
	background-color: var(--border);
	color: var(--text-primary);
}

.badge {
	background-color: var(--accent-blue);
	color: white;
}

.ExpensesToggle {
	font-size:12px;
	font-weight:normal;
	cursor:pointer;
}

  .btn-toggle.active {
        background-color: var(--accent-blue);
        color: white;
  }


  /* ===== Header Bar ===== */

  .header-actions {
      display: flex;
      align-items: center;
      gap: 12px;
  }

  .date-picker {
      display: flex;
      align-items: center;
      gap: 8px;
      background: var(--bg-darker);
      padding: 8px 16px;
      border-radius: 8px;
  }

  .date-arrow {
      background: transparent;
      border: none;
      color: var(--text-muted);
      cursor: pointer;
      padding: 4px;
      transition: color 0.2s;
      display: flex;
      align-items: center;
  }

  .date-arrow:hover {
      color: var(--accent-blue);
  }

  .date-display {
      font-size: 15px;
      font-weight: 600;
      color: var(--text-primary);
      min-width: 180px;
      text-align: center;
      cursor: pointer;
  }


  .action-button {
      padding: 10px 20px;
      background: var(--accent-blue);
      border: none;
      border-radius: 8px;
      color: white;
      font-size: 14px;
      font-weight: 500;
      cursor: pointer;
      display: flex;
      align-items: center;
      gap: 8px;
      transition: background 0.2s;
  }

  .action-button:hover {
      background: var(--accent-blue-hover);
  }

  .text-right {
        text-align: right;
  }

  /* Action Bar */
  /* Anchored to the bottom of #app-main (its `position: relative` ancestor)
     rather than the viewport, so `left/right: 0` resolves to the main-column
     width and the bar never spans over the sidebar on desktop. On mobile the
     sidebar is an overlay drawer (not a layout column), so #app-main is
     full-width and the bar still reaches edge-to-edge as expected. */
  #action-bar {
        position: absolute;
        bottom: 0;
        left: 0;
        right: 0;
        background: var(--bg-darker);
        border-top: 1px solid var(--border-color);
        padding: 12px 24px;
        /* Fixed height so the bar doesn't grow/shrink between the buttons-shown
           and count-only states (action buttons are taller than the text). */
        min-height: 62px;
        display: flex;
        justify-content: space-between;
        align-items: center;
        transform: translateY(100%);
        transition: transform 0.25s ease;
        z-index: 60;
        /* Shadow only applied when .visible — see the .visible rule below
           for why. Same pattern as .slideout-panel.active. */
  }

  /* When closed the action bar sits below the viewport (translateY(100%)),
     so its `0 -4px 20px` shadow extends ~24px UP from its top edge — that
     band is exactly at the viewport's bottom edge, leaking back into the
     visible page as a faded horizontal stripe. Restoring the shadow under
     .visible keeps the open bar's elevation without the leak when closed.
     Same rule fires on every viewport. */
  #action-bar.visible {
        transform: translateY(0);
        box-shadow: 0 -4px 20px var(--shadow);
  }

  /* When the action bar is visible, reserve scroll padding at the bottom
     of the body (the actual scroll container) so the last row isn't
     trapped under the bar. Uses CSS :has() to react to the descendant
     `#action-bar.visible` selector, so JS doesn't need to coordinate a
     separate toggle. Targets every `.canvas-body` since they all live
     inside #app-main. */
  #app-main:has(#action-bar.visible) .canvas-body {
        padding-bottom: 72px;
  }

  .action-bar-info {
        display: flex;
        align-items: center;
        gap: 16px;
  }

  .action-bar-count {
        font-size: 14px;
        color: var(--text-muted);
  }

  .action-bar-sum {
        font-size: 14px;
        color: var(--accent-purple);
        font-weight: 600;
  }

  .action-bar-buttons {
        display: flex;
        gap: 8px;
  }

  .action-btn {
        padding: 8px 14px;
        border-radius: 6px;
        background: transparent;
        border: 1px solid var(--border-hover);
        color: var(--text-secondary);
        cursor: pointer;
        font-size: 13px;
        font-weight: 500;
        display: flex;
        align-items: center;
        transition: background 0.15s, border-color 0.15s, color 0.15s;
        gap: 6px;
        transition: all 0.15s;
  }

  .action-btn .material-symbols-outlined {
        font-size: 18px;
  }

  /* Single neutral hover state for every action-btn variant. The .edit /
     .merge / .delete / .ledger / .transfer modifier classes still exist
     as JS hooks (updateActionBar() toggles them) but no longer paint the
     button — every button matches the slideout header-icon-btn aesthetic
     (transparent bg, neutral grey border, muted icon, blue accent on hover). */
  .action-btn:hover,
  .action-btn:active,
  .action-btn:focus {
        background: var(--bg-row-hover);
        border-color: var(--border-focus);
        color: var(--accent-blue);
  }

  .action-btn.hidden {
        display: none;
  }
  
    /* Jar Cards - Option 1 */
  .jar {
        background: var(--bg-main);
        border: 1px solid var(--border);
        border-radius: 8px;
        padding: 14px 16px;
        display: flex;
        flex-direction: column;
        gap: 8px;
        cursor: pointer;
  }

  .jar:hover {
        background: var(--bg-hover);
  }

  .jar.selected {
        background: var(--selected-bg);
        border-color: var(--accent-blue);
  }

  .jar-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
  }

  .jar-name {
        font-size: 13px;
        color: var(--text-muted);
  }

  .jar-amount {
        font-size: 14px;
        font-weight: 600;
  }

  .jar-amount.positive { color: var(--success-text); }
  .jar-amount.negative { color: var(--danger-text); }
  .jar-amount.zero { color: var(--text-dark); }

  .jar-progress {
        height: 4px;
        background: var(--bg-darker);
        border-radius: 2px;
        overflow: hidden;
  }

  .jar-progress-fill {
        height: 100%;
        background: linear-gradient(90deg, var(--accent-green), #22c55e);
        border-radius: 2px;
  }

  .jar.warning .jar-progress-fill {
        background: linear-gradient(90deg, var(--accent-amber), #f59e0b);
  }

  .jar.danger .jar-progress-fill {
        background: linear-gradient(90deg, var(--accent-red), #ef4444);
  }

  .SideBarTitle {
        display: flex;
        justify-content: space-between;
        align-items: center;
  }

  .jar-search {
        width: 350px;
        padding: 4px 8px;
        font-size: 14px;
        background: var(--bg-input);
        border: 1px solid var(--border);
        border-radius: 4px;
        color: var(--text-primary);
		margin-right: 20px;
  }

  .jar-search:focus {
        outline: none;
        border-color: var(--accent-blue);
  }

.slideout-actions .material-symbols-outlined {
	font-size: 14px;	  
}

/* Danger/Delete button — outlined variant on header buttons (transparent
   background + red border + red icon, hovers to filled red). Standalone
   .btn-delete elsewhere keeps the solid-red default. */
.btn-delete {
	background-color: var(--danger) !important;
	color: white !important;
}

.btn-delete:hover {
	background-color: var(--danger-hover);
}

/* Header-bar delete buttons share the standard outlined header-icon-btn
   look (transparent bg, neutral grey border, muted icon). The danger cue
   only appears on hover — icon turns red while the button stays neutral. */
.header-icon-btn.btn-delete {
	background: transparent !important;
	border: 1px solid var(--border-hover);
	color: var(--text-secondary) !important;
}

.header-icon-btn.btn-delete:hover {
	background: var(--bg-row-hover) !important;
	border-color: var(--border-focus);
	color: var(--danger) !important;
}

  .icon-xs { font-size: 14px; }
  .icon-sm { font-size: 16px; }
  .icon-md { font-size: 20px; }
  .icon-lg { font-size: 28px; }
  .icon-gold {color: #DBC54F;}
  .icon-redish {color: #f985b1;}


/* ========================================================================== */
/* SLIDEOUT STYLES (consolidated from slideout.css)                           */
/* ========================================================================== */

/* Overlay */
.overlay {
	display: none;
	position: fixed;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	background: var(--overlay-bg);
	z-index: 10;
	opacity: 0;
	transition: opacity 0.3s ease;
}

.overlay.active {
	display: block;
	opacity: 1;
}

.info-icon {
	font-size: 13px;
	color: var(--text-dark);
	cursor: help;
	vertical-align: top;
	margin-left: 4px;
	position: relative;
	top: 1px;
}

.info-icon:hover {
	color: var(--text-primary);
}

/* Help "?" — the per-window help affordance that lives beside a title
   (.canvas-title / .slideout-title). Hover (mouse) or tap shows a one-line
   tip; click opens the window's full Help topic (see F_HelpIcon.php + the
   .help-icon handlers in main.js). Distinct from .info-icon: clickable
   (cursor: pointer, not help) and it navigates.

   Base rule = faintly visible always — this is the TOUCH behaviour (no hover
   to reveal it) and the safe fallback for any device that doesn't report
   hover. The @media (hover: hover) block below hides it until the title is
   hovered, so on a mouse it stays out of the way until wanted. */
.help-icon {
	font-size: 16px;
	color: var(--text-dark);
	cursor: pointer;
	vertical-align: middle;
	margin-left: 2px;
	position: relative;
	top: -1px;
	opacity: 0.55;
	transition: opacity 0.15s ease, color 0.15s ease;
}
.help-icon:hover {
	color: var(--accent-blue);
	opacity: 1;
}

/* Hover-capable devices: keep the "?" hidden until the title is hovered, then
   fade it in. It stays in the DOM (opacity only) so the title text never
   shifts. The icon keeps its own :hover reveal so it doesn't vanish as the
   pointer moves from the title text onto it. */
@media (hover: hover) {
	.help-icon {
		opacity: 0;
	}
	.canvas-title:hover .help-icon,
	.slideout-title:hover .help-icon,
	.help-icon:hover,
	.help-icon:focus {
		opacity: 1;
	}
}

/* Custom tooltip — replaces the native title="..." popup with a styled
   floating modal. One shared element on document.body, repositioned per
   trigger. The 1s hover delay is JS-driven; CSS only handles appearance
   and the fade. position:fixed so we don't fight scroll containers. */
.cj-tooltip {
	position: fixed;
	z-index: 90;
	background: var(--bg-darker);
	color: var(--text-primary);
	border: 1px solid var(--border);
	border-radius: 6px;
	padding: 8px 12px;
	font-size: 12px;
	line-height: 1.4;
	max-width: 280px;
	box-shadow: 0 4px 12px var(--shadow);
	pointer-events: none;
	white-space: pre-line;
	opacity: 0;
	visibility: hidden;
	transition: opacity 0.15s ease;
}
.cj-tooltip.visible {
	opacity: 1;
	visibility: visible;
}

/* Merge Chips */
.merge-chip {
	padding: 8px 16px;
	border-radius: 20px;
	background: var(--bg-darker);
	border: 2px solid var(--border);
	cursor: pointer;
	transition: all 0.2s;
	color: var(--text-primary);
}

.merge-chip:hover {
	border-color: var(--border-hover);
	background: var(--bg-hover);
}

.merge-chip-selected {
	background: var(--accent-blue);
	border-color: var(--accent-blue);
	color: var(--text-on-accent);
	font-weight: bold;
	box-shadow: 0 0 0 3px var(--focus-shadow);
}

.merge-chip-empty {
	background: transparent;
	border-style: dashed;
	cursor: default;
	opacity: 0.5;
	color: var(--text-muted);
}

.category-pickers .picker-selector {
	white-space: nowrap;
}

/* Slide-out Panel */
.slideout-panel {
	position: fixed;
	top: 0;
	/* Open position — anchored at the app's right edge on wide screens
	   (max(0px, gutter)) or the viewport's right edge below the app's
	   max-width. The transform below pushes it off-screen when closed. */
	right: max(0px, calc((100vw - 1200px) / 2));
	width: 500px;
	height: 100vh;
	height: 100dvh;
	background: var(--bg-main);
	z-index: 20;
	display: flex;
	flex-direction: column;
	/* Closed — shifted right by (own width + gutter) so the panel's left
	   edge clears the viewport's right edge. translateX is GPU-composited
	   so this animates smoothly. Width-independent across .slideout-sm and
	   the default panel width. */
	transform: translateX(calc(100% + max(0px, (100vw - 1200px) / 2)));
	transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Help slideout sits ABOVE the dialog (z-100) so a "?" link inside a
   Dialog.confirm can open help over it. Help is read-only/informational
   and never fires a confirm itself, so no other slideout needs to win
   over it. showHelp() clears the inline z-index slideoutPush() set so
   this class applies without !important. */
.slideout-panel.slideout-help {
	z-index: 110;
}

/* When help is open, lift the shared slideout overlay above the dialog
   (z-100) too — otherwise the overlay (default z-10) sits BELOW the
   dialog and the dialog stays visible/undimmed behind the help panel.
   109 = just below help's 110, so the dim covers the dialog cleanly. */
body:has(.slideout-panel.slideout-help.active) .overlay {
	z-index: 109;
}

.slideout-panel.active {
	transform: translateX(0);
	box-shadow: -4px 0 20px var(--shadow);
}


/* Panel Header */
.slideout-header {
	padding: 10px 20px;
	border-bottom: 1px solid var(--border);
	background: var(--bg-darker);
	display: flex;
	align-items: center;
}

.slideout-title {
	font-size: 18px;
	color: var(--text-primary);
	font-weight: 600;
	margin: 0;
}

.slideout-actions {
	margin-left: 10px;
	flex-grow: 1;
	display: flex;
}


/* Panel Header Action Button */
.header-icon-btn {
	background: transparent;
	border: 1px solid var(--border-hover);
	font-size: 18px;
	line-height: 1;
	cursor: pointer;
	color: var(--text-secondary);
	width: 32px;
	height: 32px;
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: 8px;
	transition: all 0.15s ease;
	margin-left: 5px;
}

/* Material Symbols icons inside header buttons inherit a global
   vertical-align: middle that fights with flex centering — neutralize so
   the icon centers visually on both axes. */
.header-icon-btn .material-symbols-outlined {
	font-size: 18px;
	line-height: 1;
	vertical-align: baseline;
}

.header-icon-btn:hover {
	background: var(--bg-row-hover);
	border-color: var(--border-focus);
	color: var(--text-primary);
}

/* Intentionally-blocked header icon (e.g. Delete on the ACTIVE database):
   faded + not-allowed, but NOT natively disabled so its tooltip still explains
   why. Hover stays inert so it doesn't look clickable. */
.header-icon-btn.is-disabled {
	opacity: 0.4;
	cursor: not-allowed;
}
.header-icon-btn.is-disabled:hover {
	background: transparent;
	border-color: var(--border-hover);
	color: var(--text-secondary);
}

/* Active / toggled-on variant — accent-blue fill so the button reads as "on"
   while a mode is engaged. Used by the Imports canvas's History button to
   show which mode is active (pending vs history). */
.header-icon-btn.active,
.header-icon-btn.active:hover {
	background: var(--accent-blue);
	border-color: var(--accent-blue);
	color: var(--bg-app);
}

/* Disabled variant — muted look, no hover highlight, native title= tooltip
   still shows on hover so the button can explain why it can't be used. */
.header-icon-btn.btn-disabled,
.header-icon-btn.btn-disabled:hover {
	background: transparent;
	border-color: var(--border-hover);
	color: var(--text-quaternary);
	cursor: not-allowed;
	opacity: 0.55;
}


.slideout-header .close-btn {
	position: relative;
	width: 32px;
	height: 32px;
	border-radius: 8px;
	background: transparent;
	border: 1px solid var(--border-hover);
	display: flex;
	align-items: center;
	justify-content: center;
	color: var(--text-secondary);
	cursor: pointer;
	padding: 0;
	/* Hide the `&times;` text in templates — the X is drawn via the two
	   ::before / ::after pseudo-elements as crossed lines, which centers
	   reliably regardless of font metrics. */
	font-size: 0;
	transition: all 0.15s ease;
}

.slideout-header .close-btn::before,
.slideout-header .close-btn::after {
	content: '';
	position: absolute;
	top: 50%;
	left: 50%;
	width: 14px;
	height: 2px;
	background: currentColor;
	border-radius: 1px;
}

.slideout-header .close-btn::before { transform: translate(-50%, -50%) rotate(45deg); }
.slideout-header .close-btn::after  { transform: translate(-50%, -50%) rotate(-45deg); }

.slideout-header .close-btn:hover {
	background: var(--bg-row-hover);
	border-color: var(--border-focus);
	color: var(--text-primary);
}

/* Panel Body */
.slideout-body {
	flex: 1;
	overflow-y: auto;
	/* Single source of truth for slideout body padding. Mobile halves this
	   in responsive.css. Any per-slideout exceptions should be a single
	   property override, not a full padding redeclaration. */
	padding: 20px;
}

/* Form Groups */
.form-group {
	margin-bottom: 20px;
}

/* LITS row breakdown — clickable "(N)" toggle next to a tallied figure that
   expands to show the individual contributing rows (Date / Notes / Amount).
   Lets the user verify what's being summed without leaving the slideout. */
.lits-breakdown-toggle {
	margin-left: 6px;
	font-size: 11px;
	color: var(--accent-blue);
	cursor: pointer;
	text-decoration: underline;
}
.lits-breakdown {
	margin: 4px 0 12px 12px;
	padding: 8px 12px;
	border-left: 2px solid var(--border);
	background: var(--bg-darker);
	border-radius: 4px;
	font-size: 12px;
}
.lits-breakdown-row {
	display: grid;
	grid-template-columns: auto 1fr auto;
	gap: 12px;
	padding: 3px 0;
	color: var(--text-muted);
}
.lits-breakdown-row .lits-breakdown-date {
	font-family: monospace;
	white-space: nowrap;
}
.lits-breakdown-row .lits-breakdown-notes {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.lits-breakdown-row .lits-breakdown-amount {
	font-family: monospace;
	color: var(--text-primary);
}
.lits-breakdown-empty {
	color: var(--text-muted);
	font-style: italic;
}

/* Instructional copy on the LITS account picker — muted helper text that sits
   between the section label and the tile grid, explaining what the user is
   about to pick and why. */
.lits-instructions {
	margin: 0 0 16px 0;
	color: var(--text-muted);
	font-size: 13px;
	line-height: 1.5;
}

/* Per-account tile styling on the LITS picker grid — the .additem-card frame
   already handles icon + label; this just shapes the name (slightly tighter
   gap above the balance) and styles the balance as a muted monospace figure
   so the dollar amount reads as data rather than UI text. */
.lits-account-card .lits-account-name {
	font-weight: 500;
}
.lits-account-card .lits-account-balance {
	margin-top: -4px;
	font-family: monospace;
	font-size: 13px;
	color: var(--text-muted);
}

/* Empty-state copy — used when a list slideout has nothing to render so the
   user gets a friendly "nothing here" message instead of a blank panel. */
.empty-state {
	padding: 40px 24px;
	text-align: center;
	color: var(--text-muted);
	font-size: 14px;
	line-height: 1.5;
}
/* Optional leading icon for an empty-state (e.g. the category picker's "no
   categories yet" panel). Sits centered on its own line above the message. */
.empty-state-icon {
	display: block;
	font-size: 48px;
	color: var(--text-muted);
	margin-bottom: 12px;
}

/* Segmented control — two-or-more pill segments inside a rounded container.
   Active segment fills with the accent blue; inactive segments stay transparent
   with muted text. Used for the Category form's Top Level / Sub-category
   selector. Add the .disabled modifier to lock the control (edit mode). */
.segmented-control {
	display: flex;
	background: var(--bg-input);
	border: 1px solid var(--border);
	border-radius: 6px;
	padding: 3px;
	width: 100%;
}
.segmented-control .segment {
	flex: 1;
	padding: 6px 14px;
	border: none;
	background: transparent;
	color: var(--text-muted);
	font-weight: 500;
	font-size: 14px;
	border-radius: 4px;
	cursor: pointer;
	transition: background 0.15s, color 0.15s;
}
.segmented-control .segment.active {
	background: var(--accent-blue);
	color: #fff;
	font-weight: 600;
}
.segmented-control .segment:hover:not(.active) {
	color: var(--text-primary);
}
.segmented-control.disabled {
	opacity: 0.6;
	pointer-events: none;
}

/* Full-width label row with checkbox on the right — matches input field style */
.form-row-toggle {
	display: flex;
	align-items: center;
	justify-content: space-between;
	width: 100%;
	padding: 8px 12px;
	margin-bottom: 20px;
	font-size: 14px;
	color: var(--text-primary);
	cursor: pointer;
	border: 1px solid var(--border);
	border-radius: 4px;
	background: var(--bg-input);
}
.form-row-toggle input[type="checkbox"] {
	width: 16px;
	height: 16px;
	cursor: pointer;
	flex-shrink: 0;
}

.form-group label {
	display: block;
	font-size: 13px;
	font-weight: 600;
	color: var(--text-muted);
	margin-bottom: 6px;
}

.form-group input,
.form-group select,
.form-group textarea {
	width: 100%;
	padding: 10px 12px;
	border: 1px solid var(--border);
	border-radius: 4px;
	font-size: 14px;
	font-family: inherit;
	transition: border-color 0.2s;
	/* background-COLOR (not the `background` shorthand) so it doesn't reset the
	   select chevron/divider background-image set on the global `select` rule. */
	background-color: var(--bg-input);
	color: var(--text-primary);
}

/* A <select> inside a .form-group would otherwise inherit the input sizing
   above (4px radius, 12px right padding). Re-assert the .cat-picker-matching
   shape so form-group selects look identical to every other select. */
.form-group select {
	height: 42px;
	padding: 0 52px 0 16px;
	border-radius: 8px;
}

.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
	outline: none;
	border-color: var(--accent-blue);
	box-shadow: 0 0 0 3px var(--focus-shadow);
}

/* Admin-Mode unlocked field — amber border + glow, both resting and focused,
   so the user can SEE they're editing a normally-locked field (currently the
   Jar Deposit date input). Specificity beats the .form-group rule above by
   using the input class directly in the selector. See F_AdminMode.php. */
.admin-unlocked {
	border-color: var(--accent-amber) !important;
	box-shadow: 0 0 0 1px var(--accent-amber);
}
.admin-unlocked:focus {
	outline: none;
	border-color: var(--accent-amber) !important;
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-amber) 40%, transparent);
}

/* The select gets a FLAT background-color only — no background-image. A select
   with a background-image makes Chromium drop the background-color for the open
   option popup and fall back to the black system canvas. Keeping it flat lets
   the popup use this colour, so the dropdown matches the app. The chevron +
   divider therefore CANNOT live on the select's background — they're drawn by
   the .select-wrap overlay below instead. */
select {
	-webkit-appearance: none;
	-moz-appearance: none;
	appearance: none;
	background-color: var(--bg-input);
	color: var(--text-primary);
	/* Match .cat-picker so every native <select> is visually identical to the
	   custom category picker: 42px tall, 8px radius, 16px left inset, 14px font.
	   Right padding leaves 52px room for the .select-wrap chevron + divider. */
	height: 42px;
	padding: 0 52px 0 16px;
	border-radius: 8px;
	font-size: 14px;
}
/* Belt-and-suspenders: colour the option rows too (honoured by browsers that
   style the rows independently of the popup canvas). */
option {
	background-color: var(--bg-input);
	color: var(--text-primary);
}

/* Display-only disabled select (e.g. the fixed Category on the Import Rule
   form). Browsers wash disabled selects out to an unreadable dim grey; keep
   the text legible (the app's readonly-input convention) and signal that it's
   non-interactive via the cursor. */
select.select-readonly:disabled {
	color: var(--text-primary);
	opacity: 1;
	cursor: not-allowed;
}

/* Chevron + divider overlay. Every <select> is wrapped in <div class="select-wrap">
   so the cluster can be drawn on the wrapper (NOT the select's background — see
   above). Pseudo-elements sit over the select's right edge and pass clicks
   through. Geometry matches .cat-picker: chevron glyph centred ~22px from the
   right, divider ~46px from the right. top/bottom:0 + background centring makes
   it height-agnostic, so it stays centred at any select height. */
.select-wrap {
	position: relative;
	display: block;
}
.select-wrap > select {
	width: 100%;
}
.select-wrap::after {            /* chevron */
	content: "";
	position: absolute;
	top: 0;
	bottom: 0;
	right: 15px;
	width: 14px;
	background: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%239ba3b1' stroke-width='2' stroke-linecap='round'><polyline points='6 9 12 15 18 9'/></svg>") center / 14px no-repeat;
	pointer-events: none;
}
.select-wrap::before {           /* divider */
	content: "";
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	right: 46px;
	width: 1px;
	height: 20px;
	background: var(--border);
	pointer-events: none;
}

.form-group textarea {
	resize: vertical;
	min-height: 80px;
}

.form-row {
	display: flex;
	gap: 12px;
}

.form-row .form-group {
	flex: 1;
}

/* Info Boxes (consolidated) */
.info-box,
.info-box-success,
.info-box-error,
.info-box-warning {
	padding: 12px;
	border-radius: 4px;
	margin-bottom: 20px;
	font-size: 13px;
	border-left: 3px solid;
}

/* Yellow banner for recurring-template-linked slideouts (Expense / Income) */
.info-box-warning {
	background: var(--warning-banner-bg);
	border-left-color: var(--warning-banner-edge);
	color: var(--warning-banner-text);
}

.info-box-warning strong {
	color: var(--warning-banner-strong);
}

/* "Break connection" link inside the recurring banner (blue .info-box now;
   the warning variant kept so the link still styles if reused there). */
.info-box-warning .break-template-link,
.info-box .break-template-link {
	text-decoration: underline;
	cursor: pointer;
	font-weight: 600;
}
.info-box-warning .break-template-link { color: var(--warning-banner-strong); }
.info-box .break-template-link        { color: var(--info-strong); }
.info-box-warning .break-template-link:hover,
.info-box .break-template-link:hover {
	color: var(--text-primary);
}

.info-box {
	background: var(--info-bg);
	border-left-color: var(--accent-blue);
	color: var(--info-text);
}

.info-box strong {
	color: var(--info-strong);
}

.info-box-success {
	background: var(--success-bg);
	border-left-color: var(--success);
	color: var(--success-text);
	text-align: center;
}

.info-box-success strong {
	color: var(--success-strong);
}

.info-box-error {
	background: var(--danger-bg);
	border-left-color: var(--danger);
	color: var(--danger-text);
	text-align: center;
}

.info-box-error strong {
	color: var(--danger-strong);
}

/* Panel Footer */
.slideout-footer {
	padding: 20px;
	border-top: 1px solid var(--border);
	display: flex;
	gap: 12px;
	background: var(--bg-darker);
}
/* Collapse the footer wrapper when the slideout passes empty FOOTER.
   Mirrors .canvas-footer:empty — lets Slideout_Frame.template render
   the wrapper unconditionally without showing a blank padded strip. */
.slideout-footer:empty {
	display: none;
	padding: 0;
	border-top: none;
}
/* Subheader sits between .slideout-header and .slideout-body; does NOT
   scroll with the body. Used for sticky search bars / banners. Collapses
   when the slideout passes empty SUBHEADER. */
.slideout-subheader:empty {
	display: none;
}

/* Footer info slot — pairs with .btn-primary (also flex: 1) to split the
   slideout-footer 50/50 between a stat/preview area and the action button. */
.slideout-footer-info {
	flex: 1;
	display: flex;
	align-items: center;
	font-size: 14px;
	color: var(--text-dark);
}

/* Jar Transfer footer preview — two stacked lines, label above amount,
   centered horizontally inside the 50% footer slot. When empty (no jar
   selected yet) the slot keeps its width so the Transfer button stays at
   50%, but the inner contents are invisible. */
.dest-jar-preview {
	flex-direction: column;
	justify-content: center;
	text-align: center;
	gap: 2px;
}
.dest-jar-preview.is-empty .dest-jar-preview-label,
.dest-jar-preview.is-empty .dest-jar-preview-amount {
	visibility: hidden;
}
.dest-jar-preview-label {
	font-size: 11px;
	color: var(--text-muted);
	text-transform: uppercase;
	letter-spacing: 0.5px;
}
.dest-jar-preview-amount {
	font-size: 16px;
	font-weight: 600;
	color: var(--text-light);
}
/* Body-placed variant (Jar Transfer) — left-aligned under the form with a
   divider above; collapses entirely until a destination jar is picked. */
.dest-jar-preview-body {
	text-align: left;
	margin-top: 4px;
	padding-top: 14px;
	border-top: 1px solid var(--border);
}
.dest-jar-preview-body.is-empty {
	display: none;
}

.btn-secondary {
	flex: 1;
	background: var(--border);
	color: var(--text-primary) !important;
	border: 1px solid var(--border-hover);
	padding: 12px;
	border-radius: 4px;
	cursor: pointer;
	font-size: 14px;
	font-weight: 600;
	transition: all 0.2s;
}

.btn-secondary:hover {
	background: var(--bg-hover);
	border-color: var(--border-focus);
}

/* Current Value Badge */
.current-value {
	display: inline-block;
	background: var(--border);
	padding: 4px 8px;
	border-radius: 3px;
	font-size: 12px;
	color: var(--text-muted);
	margin-left: 8px;
}

/* Split Items Section */
.split-items-section {
	margin-top: 24px;
}

.split-items-container {
	background: var(--bg-darker);
	padding: 12px;
	border-radius: 4px;
	margin-top: 8px;
	border: 1px solid var(--border);
}

.split-item {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 8px 0;
	border-bottom: 1px solid var(--border);
}

.split-item:last-child {
	border-bottom: none;
}

.split-item-content {
	flex: 1;
}

.split-item-category {
	font-size: 13px;
	color: var(--text-primary);
	font-weight: 500;
}

.split-item-note {
	font-size: 12px;
	color: var(--text-dark);
	margin-top: 2px;
}

.split-item-amount {
	font-weight: 600;
	color: var(--accent-blue);
}

/* Loading Text */
.loading-text {
	color: var(--text-muted);
	font-size: 14px;
	font-weight: 500;
}

/* Mobile / phone-friendly overrides live in css/responsive.css (loaded last). */

/* Input Group Container */
.input-group {
	display: flex;
	align-items: stretch;
	width: fit-content;
}

/* Default-value placeholders — when the placeholder carries "(default)" the
   text isn't an empty-state hint, it's the actual fallback value the form
   will save if the user leaves the field blank. Render it at normal text
   color so the user can actually read it; the "(default)" suffix already
   makes it clear this isn't a typed entry. Generic empty placeholders
   ("0.00", "Search...", etc.) stay muted via browser default. */
input[placeholder*="(default)"]::placeholder,
textarea[placeholder*="(default)"]::placeholder {
	color: var(--text-primary);
	opacity: 1;
}

/* Vendor Picker Button (right-side addon on Match Name input) */
/* The search button carries BOTH .input-group-addon and .btn-vendor-picker.
   .input-group-addon is defined later with equal specificity, so it would
   otherwise win and round the LEFT (seam) + drop the right border. Qualify
   with both classes to win the cascade: this button sits on the RIGHT, so it
   rounds its right (outer) corners, squares the left (seam), and keeps its
   outer (right) border. */
.input-group-addon.btn-vendor-picker {
	border-left: none;
	border-right: 1px solid var(--border);
	border-radius: 0 4px 4px 0;
	cursor: pointer;
	gap: 6px;
}

/* "VENDORS" label beside the search icon on the vendor-picker button */
.btn-vendor-picker-label {
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.04em;
	color: var(--text-muted);
}

.btn-vendor-picker:hover .btn-vendor-picker-label {
	color: var(--text-primary);
}

.btn-vendor-picker:hover {
	background: var(--border-hover);
	color: var(--text-primary);
}


/* Dollar Sign Addon (Left Side) */
.input-group-addon {
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 6px 12px;
	background: var(--border);
	border: 1px solid var(--border);
	border-right: none;
	border-radius: 4px 0 0 4px;
	color: var(--text-muted);
	font-size: 14px;
	font-weight: normal;
	cursor: default;
	width: auto;
}

/* A bare input that immediately follows a left addon (e.g. the "$" prefix on
   the amount fields) inherits the global all-corners radius, which rounds the
   seam against the addon. Round only the outer (right) corners so the addon +
   input read as one clean pill. (The budget toggle-suffix case squares it fully
   via a higher-specificity :has() rule below; Match Name's input precedes its
   button so it isn't matched here.) */
.input-group-addon + input {
	border-radius: 0 4px 4px 0;
}

.form-group .input-group {
	display: flex;
	align-items: stretch;
	width: 100%;
}

.input-group .form-control {
	flex: 1;
	/* Match Name sits to the LEFT of the search button, so round its
	   left corners (outer edge) and keep the right seam square. */
	border-radius: 4px 0 0 4px;
	border: 1px solid var(--border);
	padding: 10px 12px;
	font-size: 14px;
	background: var(--bg-input);
	color: var(--text-primary);
	font-family: inherit;
}

.input-group .form-control:focus {
	outline: none;
	border-color: var(--accent-blue);
	box-shadow: 0 0 0 3px var(--focus-shadow);
}

.input-group .form-control:disabled,
.input-group .form-control[readonly],
.input-group input[readonly],
.input-group textarea[readonly] {
	background-color: var(--bg-body);
	color: var(--text-primary);
	cursor: not-allowed;
}

/* Match the addon (e.g. the "$" prefix) to the disabled input next to it */
.input-group .form-control:disabled + .input-group-addon,
.input-group .form-control:disabled ~ .input-group-addon,
.input-group:has(.form-control:disabled) .input-group-addon,
.input-group:has(.form-control[readonly]) .input-group-addon,
.input-group:has(input[readonly]) .input-group-addon,
.input-group:has(textarea[readonly]) .input-group-addon {
	color: var(--text-primary);
}

/* Small size variant */
.input-group .input-sm {
	padding: 5px 10px;
	font-size: 12px;
}

/* Toggle Container */
.toggle-container {
	display: flex;
	align-items: center;
	gap: 10px;
}

.toggle-label {
	font-size: 14px;
	color: var(--text-dark);
}

.toggle-switch {
	position: relative;
	display: inline-block;
	width: 50px;
	height: 24px;
	margin: 0;
	cursor: pointer;
}

.toggle-switch input {
	opacity: 0;
	width: 0;
	height: 0;
}

.toggle-slider {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	background-color: var(--toggle-track-off);
	transition: 0.3s;
	border-radius: 24px;
}

.toggle-slider:before {
	position: absolute;
	content: "";
	height: 18px;
	width: 18px;
	left: 3px;
	bottom: 3px;
	background-color: var(--toggle-thumb);
	transition: 0.3s;
	border-radius: 50%;
}

.toggle-switch input:checked + .toggle-slider {
	background-color: var(--success);
}

.toggle-switch input:checked + .toggle-slider:before {
	transform: translateX(26px);
}

.toggle-switch input:disabled + .toggle-slider {
	background-color: var(--toggle-track-disabled);
	cursor: not-allowed;
}

  /* Toggle Switch with Labels Inside */
  .toggle-switch-labeled {
        position: relative;
        display: inline-block;
        width: auto;
        height: 26px;
		margin-left: 10px;
		margin-bottom: 0;
  }

  .toggle-switch-labeled input {
        opacity: 0;
        width: 0;
        height: 0;
  }

  .toggle-slider-labeled {
		position: absolute;
		cursor: pointer;
		top: 3px;
		left: 0;
		right: 0;
		bottom: 0;
		background-color: var(--bg-darker);
		border: 1px solid var(--border);
		border-radius: 13px;
		transition: 0.3s;
		padding: 0 28px;
  }

  .toggle-slider-labeled:before {
        position: absolute;
        content: "";
        height: 20px;
        width: 20px;
        left: 2px;
        top: 50%;
        transform: translateY(-50%);
        background-color: var(--toggle-thumb);
        border-radius: 50%;
        transition: 0.3s;
  }

  .toggle-slider-labeled:after {
        content: attr(data-off);
        position: absolute;
        right: 6px;
        top: 50%;
        transform: translateY(-50%);
        font-size: 8px;
        font-weight: 600;
        color: var(--text-muted);
  }

  .toggle-switch-labeled input:checked + .toggle-slider-labeled {
        background-color: var(--success-bg);
        border-color: var(--success-text);
  }

  .toggle-switch-labeled input:checked + .toggle-slider-labeled:before {
        left: auto;
        right: 2px;
        transform: translateY(-50%);
  }

  .toggle-switch-labeled input:checked + .toggle-slider-labeled:after {
        content: attr(data-on);
        right: auto;
        left: 6px;
        color: var(--success-text);
  }



  /* Budget banner - toggleable */
  .budget-banner {
        border-radius: 6px;
        padding: 8px 12px;
        margin-bottom: 16px;
        font-size: 12px;
        cursor: pointer;
  }

  /* Auto Budget toggle as a suffix attached to the RIGHT end of the Default
     Budget Amount input (mirrors the "$" prefix addon on the left). Colours come
     from budget-banner-on/off; this just shapes/positions it as an addon. */
  .budget-toggle-suffix {
        margin-bottom: 0;
        border-radius: 0 4px 4px 0;
        border-left: none;
        display: flex;
        align-items: center;
        white-space: nowrap;
        padding: 0 12px;
        font-size: 11px;
  }
  /* Square the input between the "$" prefix and the toggle suffix, and let it
     flex to fill the space left over. */
  .input-group:has(.budget-toggle-suffix) input {
        border-radius: 0;
        flex: 1;
        min-width: 0;
  }

  .budget-banner-on {
        background: var(--success-bg);
        border: 1px solid var(--success-bg-strong);
        color: var(--success-text);
  }

  .budget-banner-off {
        background: var(--surface-tint-1);
        border: 1px solid var(--border);
        color: var(--text-muted);
  }

  .budget-banner-archived {
        background: var(--danger-bg);
        border: 1px solid var(--danger-bg-strong);
        color: var(--accent-red);
  }

  /* Informational banner variant — used by the Category form's Jar mode
     to explain that jar-specific fields show up after save. Non-clickable
     (override the parent's cursor: pointer). */
  .budget-banner-info {
        background: var(--surface-tint-1);
        border: 1px solid var(--accent-blue);
        color: var(--text-primary);
        cursor: default;
  }




/* Split Transaction Button */
.btn-split {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	width: 100%;
	background: var(--border);
	color: var(--text-primary);
	border: 1px solid var(--border-hover);
	padding: 12px;
	border-radius: 4px;
	cursor: pointer;
	font-size: 14px;
	font-weight: 600;
	transition: all 0.2s;
}

.btn-split:hover {
	background: var(--bg-hover);
	border-color: var(--border-focus);
}

.btn-split:active {
	background: var(--bg-row-hover);
}

.btn-split .material-symbols-outlined {
	font-size: 20px;
}

/* Split Child Card */
.split-child-card {
	overflow: hidden;
}

/* Card chrome (fill + border + spacing) belongs to the LIST context only — in
   the parent split slideout's #split-children-container the cards read as
   bordered rows. Moved into the child editor host the same node is transparent
   and frame-less by default (no override needed there). The inline
   border-left-color (per-card identity) only shows where this border exists. */
#split-children-container .split-child-card {
	background: var(--bg-darker);
	border: 1px solid var(--border);
	border-left-width: 4px;
	border-radius: 6px;
	margin-bottom: 6px;
}

/* Card Header */
.split-child-header {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 12px 16px;
	background: var(--bg-input);
	border-bottom: 1px solid var(--border);
}

.split-child-title {
	font-size: 14px;
	font-weight: 600;
	color: var(--text-primary);
}

/* Remove Button */
/* Trash button on each split card — same outlined look as the header
   buttons (transparent bg + neutral grey border + muted icon). The
   danger cue only appears on hover (icon turns red). */
.btn-remove-split {
	background: transparent;
	border: 1px solid var(--border-hover);
	cursor: pointer;
	color: var(--text-secondary);
	width: 32px;
	height: 32px;
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: 8px;
	transition: all 0.15s ease;
}

.btn-remove-split:hover {
	background: var(--bg-row-hover);
	border-color: var(--border-focus);
	color: var(--danger);
}

.btn-remove-split .material-symbols-outlined {
	font-size: 18px;
	line-height: 1;
	vertical-align: baseline;
}

/* Card Body */
.split-child-body {
	padding: 16px;
}

/* Override form-group margin for cards */
.split-child-body .form-group:last-child {
	margin-bottom: 0;
}

/* ==========================================================================
   Split slideout — collapsible head, summary pill, proportional bar
   Layered ON TOP of the existing .split-child-card / .btn-remove-split rules.
   The body is hidden by default and revealed when the card has .is-expanded.
   ========================================================================== */

/* Clickable accordion head — replaces the static "Split Item" header.
   Six inline children: chevron, color dot, title, $ amount, %, remove-X. */
.split-child-head {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 10px 14px;
	cursor: pointer;
	user-select: none;
}

/* Body collapsed by default — expanded card reveals the form below */
.split-child-card .split-child-body {
	display: none;
}

.split-child-card.is-expanded .split-child-body {
	display: block;
	border-top: 1px solid var(--border-soft);
}

/* Split-child editor host — openSplitChildEditor() moves the live
   .split-child-card into here. Show its body (the form) and hide the summary
   head. The card carries no chrome outside #split-children-container, so the
   slideout panel frames it cleanly with no background/border override. */
#split-editor-host .split-child-head { display: none; }
#split-editor-host .split-child-body { display: block; padding: 0; border-top: none; }
/* The cloned original-transaction banner (bar + Remaining stripped) sits alone
   here as pure context; a touch more spacing below it before the form. */
#split-editor-summary .split-banner { margin-bottom: 16px; }

/* Subtle accent on the open card — only top/right/bottom borders flip
   to the focus color so the per-card palette color on the left edge
   stays visible (it's the card's identity, not a hover state). */
.split-child-card.is-expanded {
	border-top-color: var(--border-focus);
	border-right-color: var(--border-focus);
	border-bottom-color: var(--border-focus);
}

/* Chevron rotates 90° when expanded */
.split-child-chevron {
	font-size: 18px;
	color: var(--text-secondary);
	transition: transform 0.15s ease;
	flex-shrink: 0;
}

.split-child-card.is-expanded .split-child-chevron {
	transform: rotate(90deg);
	color: var(--accent-blue);
}

/* Title block — category + italic notes preview, ellipsis on overflow */
.split-child-headtitle {
	flex: 1;
	min-width: 0;
	font-size: 13px;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	color: var(--text-primary);
}

.split-child-headtitle strong {
	font-weight: 500;
}

.split-child-headtitle em {
	font-style: italic;
	font-weight: 400;
	color: var(--text-secondary);
	margin-left: 6px;
}

.split-child-headtitle em:empty {
	display: none;
}

/* $ preview — hidden when the card is expanded (form fields take over) */
.split-child-headamount {
	font-size: 13px;
	font-variant-numeric: tabular-nums;
	color: var(--text-primary);
	flex-shrink: 0;
}

.split-child-card.is-expanded .split-child-headamount {
	display: none;
}

/* Remove button matches the attachment-delete X (.receipt-delete) —
   borderless transparent square, muted icon, danger-tinted hover.
   Negative right margin pulls the X tight to the row's right edge
   without changing the head's overall padding. */
.split-child-head .btn-remove-split {
	background: transparent;
	border: none;
	color: var(--text-muted);
	width: 18px;
	height: 18px;
	border-radius: 4px;
	margin-right: -6px;
	transition: all 0.15s;
}

.split-child-head .btn-remove-split:hover {
	background: var(--danger-bg);
	border-color: transparent;
	color: var(--danger-text);
}

.split-child-head .btn-remove-split .material-symbols-outlined {
	font-size: 14px;
}

/* Summary header — replaces the legacy info-box. Two columns:
   left = original amount / merchant / date; right = Remaining pill.
   Bottom corners are squared off because the proportional bar sits
   flush against it (visually one banner, two parts). */
/* Banner wrapper — the ONE tinted, rounded, left-accented block. Holds the
   summary header + the proportional bar so the bar is the banner's bottom edge
   (no separate-element seam / "cut off" look). */
.split-banner {
	background: var(--info-bg);
	border-left: 2px solid var(--accent-blue);
	border-radius: 6px;
	overflow: hidden;
	margin-bottom: 12px;
}

.split-summary {
	display: flex;
	justify-content: space-between;
	align-items: flex-start;
	gap: 12px;
	padding: 10px 14px;
	/* fill + border + rounding live on .split-banner now */
}

.split-summary__main {
	min-width: 0;
}

.split-summary__remaining {
	text-align: right;
	flex-shrink: 0;
}

.split-summary__label {
	display: block;
	font-size: 10px;
	color: var(--text-secondary);
	text-transform: uppercase;
	letter-spacing: 0.5px;
}

.split-summary__amount {
	display: block;
	font-size: 13px;
	color: var(--text-primary);
	margin-top: 2px;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.split-summary__amount strong {
	font-weight: 500;
}

.split-summary__sep {
	color: var(--text-secondary);
	margin: 0 4px;
}

.split-summary__date {
	display: block;
	font-size: 11px;
	color: var(--text-secondary);
	margin-top: 1px;
}

/* Remaining pill — green check when balanced, red when over-allocated,
   neutral when there's still money left to assign. */
.split-remaining {
	display: inline-flex;
	align-items: center;
	gap: 4px;
	font-size: 14px;
	font-weight: 500;
	margin-top: 2px;
}

.split-remaining__icon {
	font-size: 16px;
}

.split-remaining.is-balanced { color: var(--success); }
.split-remaining.is-over     { color: var(--danger); }
.split-remaining.is-under    { color: var(--text-secondary); }

/* Proportional bar — one segment per split, flex weighted by amount,
   color from PALETTE. Empty bar (no segments) collapses out via :empty. */
/* Proportional bar — sits as the bottom strip of the summary banner
   above. Top corners square (flush with summary's bottom edge), bottom
   corners rounded to close off the banner. Half-height (11px) so it
   reads as a meter rather than a primary control. The left-edge accent
   matches the summary so the blue accent runs the full height. */
.split-bar {
	display: flex;
	height: 11px;
	/* Transparent track — it sits inside .split-banner, so the unfilled bar just
	   shows the banner's tint (no separate fill/seam). Coloured segments overlay
	   it as amounts are entered. Fill / rounding / accent live on .split-banner. */
}

.split-bar:empty {
	display: none;
}

.split-bar__seg {
	flex: 0 0 auto;
	transition: width 0.2s ease;
}

/* Split slideout's "+ Add Split" button sits right under the last card —
   match the card-to-card gap (6px) instead of .add-btn's default 10px. */
#split-children-container + .add-btn {
	margin-top: 0px;
}

/* Inside split cards only: shrink the category picker to match the height
   of the Notes / Amount inputs (~38px). Global .cat-picker stays at 48px
   everywhere else in the app. */
.split-child-card .cat-picker {
	height: 38px;
	border-radius: 4px;
}

/* ==========================================================================
   Split Amount widget — compact ($ ⇄ %) + inline breakdown panel.
   Replaces the old two-input row + the AddTax sub-slideout.
   ========================================================================== */

/* Label row — title on the left, "show/hide breakdown" toggle on the right */
.split-amount-label {
	display: flex !important;
	align-items: center;
	justify-content: space-between;
}


/* Compact widget — single row: prefix + input + swap button.
   Both inputs ($ and %) live in the DOM; one is hidden by data-mode. */
.split-amount-compact {
	display: flex;
	align-items: stretch;
	background: var(--bg-input);
	border: 1px solid var(--border);
	border-radius: 4px;
	overflow: hidden;
}

.split-amount-compact .split-amount-prefix {
	display: flex;
	align-items: center;
	justify-content: center;
	min-width: 38px;
	padding: 0 10px;
	background: var(--bg-darker);
	color: var(--text-secondary);
	font-size: 13px;
	border-right: 1px solid var(--border);
}

.split-amount-compact input.form-control {
	flex: 1;
	min-width: 0;
	border: none;
	background: transparent;
	padding: 8px 12px;
	color: var(--text-primary);
	font-size: 14px;
	font-family: inherit;
}

.split-amount-compact input.form-control:focus {
	outline: none;
}

/* Mode toggle — hide the inactive prefix + input via data-mode */
.split-amount-compact[data-mode="dollar"] .split-amount-prefix-percent,
.split-amount-compact[data-mode="dollar"] .split-amount-input-percent {
	display: none;
}

.split-amount-compact[data-mode="percent"] .split-amount-prefix-dollar,
.split-amount-compact[data-mode="percent"] .split-amount-input-dollar {
	display: none;
}

/* Swap button — muted secondary value + ⇄ icon, click to flip mode */
.split-amount-swap {
	display: inline-flex;
	align-items: center;
	gap: 4px;
	background: transparent;
	border: none;
	border-left: 1px solid var(--border);
	color: var(--text-secondary);
	font-family: inherit;
	font-size: 12px;
	font-style: italic;
	padding: 0 12px;
	cursor: pointer;
	flex-shrink: 0;
	transition: color 0.15s ease;
}

.split-amount-swap:hover {
	color: var(--text-primary);
}

.split-amount-swap .material-symbols-outlined {
	font-size: 14px;
}

/* Breakdown panel — transparent container that just stacks the rows
   directly under the Amount field. No bg / border / padding so the
   rows visually read as sub-detail of the same control. */
.split-breakdown {
	margin-top: 6px;
	display: flex;
	flex-direction: column;
	gap: 6px;
}

/* Breakdown panel is hidden when group is collapsed; when open, the
   Amount field below stays fully editable — the breakdown is purely
   additive, giving the user MORE editing surface (rows above) without
   altering the Amount field's normal behaviour. */

/* Breakdown row — matches .split-amount-compact above exactly so the
   row reads as another instance of the same Amount field. Same bg,
   same border, same prefix style, same input padding/font. */
.split-breakdown-row {
	display: flex;
	align-items: stretch;
	background: var(--bg-input);
	border: 1px solid var(--border);
	border-radius: 4px;
	overflow: hidden;
}

.split-breakdown-row .split-amount-prefix {
	display: flex;
	align-items: center;
	justify-content: center;
	min-width: 38px;
	padding: 0 10px;
	background: var(--bg-darker);
	color: var(--text-secondary);
	font-size: 13px;
	border-right: 1px solid var(--border);
}

.split-breakdown-row .split-breakdown-amount {
	flex: 1 1 auto;
	min-width: 0;
	width: auto;
	border: none;
	background: transparent;
	padding: 8px 12px;
	color: var(--text-primary);
	font-size: 14px;
	font-family: inherit;
	box-sizing: border-box;
}

.split-breakdown-row .split-breakdown-amount:focus {
	outline: none;
}

.split-breakdown-row .split-breakdown-tax {
	flex: 0 0 auto;
	width: 80px;
	border: none;
	border-left: 1px solid var(--border);
	background: transparent;
	color: var(--text-secondary);
	padding: 0 8px;
	font-size: 12px;
	font-family: inherit;
	cursor: pointer;
	-webkit-appearance: none;
	-moz-appearance: none;
	appearance: none;
}

.split-breakdown-row .split-breakdown-tax:focus {
	outline: none;
}

.split-breakdown-remove {
	background: transparent;
	border: none;
	border-left: 1px solid var(--border);
	color: var(--text-secondary);
	cursor: pointer;
	padding: 0 8px;
	font-family: inherit;
	flex-shrink: 0;
	transition: color 0.15s ease;
}

.split-breakdown-remove:hover {
	color: var(--danger);
}

.split-breakdown-remove .material-symbols-outlined {
	font-size: 16px;
}

/* "+ Add row" — SIZING-only modifier, used as `add-btn split-breakdown-add`.
   Skin (dashed border + blue hover) comes from .add-btn; this just tightens the
   padding/radius and drops the base's top margin so it sits snug under the
   breakdown rows. Scoped to `.split-breakdown .split-breakdown-add` (0-2-0) so
   it OUTRANKS the base `.add-btn` rule (0-1-0) — which is defined LATER in the
   file and would otherwise win the source-order tie and re-add its 10px
   margin-top / 9px padding, leaving a big gap above this button. */
.split-breakdown .split-breakdown-add {
	margin-top: 0;
	padding: 6px;
	border-radius: 4px;
}


button[disabled],
button:disabled {
	opacity: 0.5;
	cursor: not-allowed;
}

/* Spinner Container */
.spinner-container {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 8px;
	width: 100%;
	height: 100%;
}

/* Make the Material icon spin */
.spinning {
	font-size: 48px;
	animation: spin 1s linear infinite;
	color: var(--text-tertiary);
}

button .spinning {
	font-size: 16px;
	vertical-align: middle;
	animation: spin 0.8s linear infinite;
}

@keyframes spin {
	0% { transform: rotate(0deg); }
	100% { transform: rotate(360deg); }
}

/* Slideout stacking is now handled by js/main.js, which sets each panel's
   z-index inline (20 + level*2) and rides the single #overlay just under the
   top panel. The old fixed #suboverlay / #subslideoutPanel layers are gone. */

/* Add Item Cards */
.additem-cards {
	/* Flex column lets each card grow to fill the slideout height equally */
	display: flex;
	flex-direction: column;
	gap: 15px;
	padding: 10px;
	height: 100%;
}

.additem-card {
	/* flex: 1 — every card shares the remaining vertical space evenly.
	   max-height caps that growth so a picker with only 2 cards (e.g. the
	   Recurring type picker) doesn't stretch each card to half the panel. */
	flex: 1;
	max-height: 200px;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 10px;
	padding: 20px;
	border: 1px solid var(--border);
	border-radius: 8px;
	background: var(--bg-darker);
	color: var(--text-primary);
	cursor: pointer;
	transition: background 0.2s, border-color 0.2s;
}

.additem-card:hover {
	background: var(--bg-hover);
	border-color: var(--border-hover);
}

.additem-card .material-symbols-outlined {
	font-size: 36px;
	color: var(--accent-blue);
}

/* Readonly form fields (e.g. carry over date) */
.form-control-readonly {
	background: var(--bg-darker);
	color: var(--text-muted);
	cursor: not-allowed;
}

/* Date Picker */
.datepicker-current {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 16px 20px;
	background: var(--bg-darker);
	border-bottom: 1px solid var(--border);
	font-size: 16px;
	font-weight: 600;
	color: var(--accent-blue);
	position: sticky;
	top: 0;
	z-index: 1;
	cursor: pointer;
}

.datepicker-list {
	padding: 8px;
}

/* Pinned "Current Budget" row above the sliding window */
.datepicker-pinned {
	padding: 8px;
	border-bottom: 1px solid var(--border);
}

.datepicker-row {
	display: block;
	width: 100%;
	padding: 14px 20px;
	border: none;
	background: transparent;
	color: var(--text-primary);
	font-size: 14px;
	text-align: center;
	cursor: pointer;
	border-radius: 6px;
	transition: background 0.2s;
}

.datepicker-row:hover {
	background: var(--bg-hover);
}

.datepicker-row.datepicker-active {
	color: var(--accent-blue);
	font-weight: 600;
	background: var(--bg-darker);
}

/* Up/down sliding-window arrows at the top + bottom of the date list */
.datepicker-slide {
	display: flex;
	width: 100%;
	padding: 6px 20px;
	border: none;
	background: transparent;
	color: var(--text-muted);
	cursor: pointer;
	align-items: center;
	justify-content: center;
}

.datepicker-slide:hover {
	background: var(--bg-hover);
	color: var(--text-primary);
}

.datepicker-slide.hidden {
	display: none;
}

/* Right-aligned Net Result pill on each future-period row */
.datepicker-row {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
}

.datepicker-net {
	margin-left: auto;
	font-size: 13px;
	font-weight: 500;
	font-variant-numeric: tabular-nums;
}

/* Placeholder shown for past/current periods so layout aligns with future rows */
.datepicker-net-empty {
	color: var(--text-muted);
}

/* "In Progress..." marker on the current period row */
.datepicker-net-current {
	color: var(--accent-blue, #4a9eff);
}

/* "Closed" marker on past period rows — desaturated muted brown, low-contrast */
.datepicker-net-closed {
	color: #7a6a5c;
	font-style: italic;
	font-weight: 400;
}

/* ==========================================================================
   Category Picker — refined-card layout
   ========================================================================== */

/* Search bar — leading magnifier icon, sticky at top of the picker */
.categorypicker-search {
	position: sticky;
	top: 0;
	z-index: 1;
	padding: 12px 14px;
	background: var(--bg-darker);
	border-bottom: 1px solid var(--border);
}
/* Input styling itself lives on .search-field (used app-wide). The
   .categorypicker-search wrapper above just provides the sticky position
   + darker background + bottom border so the search bar reads as part
   of the slideout chrome rather than the scrolling body. */

/* Clear-× inside a slideout search bar. Unlike the canvas .search-field-wrap
   (a flex row with no padding), .categorypicker-search has 14px side padding
   and isn't flex — so the × needs explicit vertical centering plus a right
   offset that clears the padding to sit over the input's right edge. */
.categorypicker-search .search-field-clear {
	top: 50%;
	right: 24px;
	/* The × box is centered on the input's middle, but the &times; glyph renders
	   low within its own line box, so it reads ~2px below centre — nudge it up. */
	transform: translateY(calc(-50% - 2px));
}

/* List container (scrollable body) */
/* Scrollable list inside a picker slideout — fills the slideout-body's height
   minus the slideout's header/footer. Scoped to `.slideout-body` so this rule
   only applies to slideout pickers; canvas-resident lists (Recurring,
   Manage Categories) use the same class for picker visual parity but get
   their height + scroll from the surrounding `.canvas-body` instead. */
/* Inside a standard slideout (.slideout-body owns the scroll, per the CLAUDE.md
   slideout framework rule "Never use max-height or overflow-y on inner divs"),
   the categorypicker-list does NOT get its own overflow — that would create a
   nested scrollbar inside slideout-body. Only the breathing-room padding stays. */
.slideout-body .categorypicker-list {
	/* Top padding lives on the LIST (content) rather than the scroll
	   container — it scrolls away with the content, so it gives breathing
	   room at rest without letting cards peek above the sticky tabs. */
	padding-top: 12px;
	padding-bottom: 8px;
}
/* The slideout-body owns the scroll and carries a 20px (10px mobile) top
   padding. With the sticky section tabs pinned at top:0, cards scrolled up
   through that top-padding band peeked ABOVE the tab. Drop the top padding
   when the body holds a category list — the first section tab / card brings
   its own breathing room and the sticky tabs now pin flush to the scrollport
   top with nothing showing above. */
.slideout-body:has(> .categorypicker-list) {
	padding-top: 0;
}

/* Vendor picker rows — the flat list in the Vendors sub-slideout. Styled here
   (the class had no rules, so rows rendered as bare cramped text). Comfortable
   padding, faint divider, rounded hover highlight, pointer cursor. */
.categorypicker-row {
	padding: 11px 14px;
	border-radius: 6px;
	border-bottom: 1px solid var(--border);
	color: var(--text-primary);
	font-size: 14px;
	cursor: pointer;
	transition: background 0.12s ease, color 0.12s ease;
}

.categorypicker-row:last-child {
	border-bottom: none;
}

.categorypicker-row:hover {
	background: var(--bg-hover);
	/* Soften the divider on the hovered row so the highlight reads as one
	   clean block instead of a boxed cell. */
	border-bottom-color: transparent;
}

/* Section tab — pure visual divider between groups (EXPENSES / INCOME / JARS).
   Sticky to the top of the .categorypicker-list scroller so the current
   section label stays pinned while scrolling through its cards. */
.section-tab {
	position: sticky;
	top: 0;
	/* Just sits above the group cards scrolling under it. The cards are
	   non-positioned, so a minimal value keeps the divider on top. */
	z-index: 1;
	padding: 10px 18px 8px;
	font-size: 11px;
	font-weight: 500;
	letter-spacing: 0.12em;
	color: var(--text-dark);
	text-transform: uppercase;
	/* Use the slideout-panel surface color directly. The `--bg-main` alias
	   resolves to the same value but if a theme misconfigures it to a
	   semi-transparent token the sticky bar bleeds — pin the solid
	   panel-2 colour and a hard fallback so the bar is always opaque. */
	background: var(--bg-panel-2, #1a1e25);
	border-bottom: 1px solid var(--border);
}

/* Group card — wraps one parent + its children */
.group-card {
	margin: 8px 12px;
	background: var(--bg-darker);
	border: 1px solid var(--border);
	border-radius: 10px;
	overflow: hidden;
	transition: border 0.15s;
}
.group-card:hover {
	border-color: var(--border-hover);
}

/* Group head — clickable to toggle collapse; carries data-cat-item for picker selection */
.group-head {
	padding: 14px 14px;
	display: flex;
	align-items: center;
	gap: 0;
	cursor: pointer;
	user-select: none;
}
.group-head .label {
	font-size: 12px;
	font-weight: 400;
	letter-spacing: 0.06em;
	color: var(--text-primary);
	flex: 1;
	text-align: left;
}
.group-head .total {
	font-feature-settings: 'tnum';
	font-size: 13px;
	font-weight: 400;
}
.group-head .total.pos { color: var(--accent-green); }
.group-head .total.neg { color: var(--accent-red); }

/* 10px gap between the chevron and the parent name (the head's own gap is 0). */
.group-head .chevron {
	margin-right: 10px;
}

/* Category Manager — per-parent edit pencil. Sits at the right end of the
   head and fades in on row hover (opacity, not display, so nothing shifts on
   hover). Only rendered on parents WITH children — a plain row click expands
   them, so the pencil is the explicit edit affordance. */
.cat-edit-btn {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 28px;
	height: 28px;
	margin-left: 8px;
	padding: 0;
	border: none;
	background: transparent;
	color: var(--text-muted);
	border-radius: 6px;
	cursor: pointer;
	opacity: 0;
	transition: opacity 0.12s ease, background 0.12s ease, color 0.12s ease;
}
.cat-edit-btn .material-symbols-outlined {
	font-size: 18px;
}
.group-head:hover .cat-edit-btn {
	opacity: 1;
}
.cat-edit-btn:hover {
	background: var(--bg-hover);
	color: var(--text-primary);
}

/* Locked parent (cat-group-locked) — pointer turned off, no hover lift */
.group-head.cat-group-locked {
	cursor: default;
}

/* Active parent shown as context header in archived view — muted, italic */
.group-head.cat-group-context {
	opacity: 0.45;
	font-style: italic;
}

/* Chevron rotates to indicate expanded/collapsed state */
.chevron {
	color: var(--text-dark);
	transition: transform 0.2s ease;
	flex-shrink: 0;
}
.group-card.collapsed .chevron {
	transform: rotate(-90deg);
}

/* Group items — child list inside the card */
.group-items {
	border-top: 1px solid var(--border);
	padding: 4px 0;
}
.group-card.collapsed .group-items {
	display: none;
}

/* Item row — selectable child category */
.group-items .item {
	padding: 8px 14px 8px 30px;
	font-size: 13px;
	font-weight: 300;
	color: var(--text-dark);
	cursor: pointer;
	transition: background 0.12s, color 0.12s, padding 0.12s;
	position: relative;
	display: flex;
	align-items: center;
}
.group-items .item::before {
	content: '';
	position: absolute;
	left: 18px;
	top: 50%;
	width: 4px;
	height: 4px;
	border-radius: 50%;
	background: var(--text-dark);
	transform: translateY(-50%);
	transition: background 0.12s;
}
.group-items .item:hover {
	background: var(--bg-hover);
	color: var(--text-primary);
	padding-left: 32px;
}
.group-items .item:hover::before {
	background: var(--accent-blue);
}

/* Category List - New button container */
.category-newbutton {
	padding: 12px 16px;
	border-bottom: 1px solid var(--border);
}

.category-newbutton .btn-primary {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
}

/* Category Picker — field-style row with value, clear X, divider, chevron */
.cat-picker {
	display: flex;
	align-items: center;
	gap: 6px;
	width: 100%;
	/* Match the .form-group input/select height: 14px × body line-height
	   1.42857 (≈20px) + 10px×2 padding + 1px×2 border = 42px. The 28px inner
	   buttons still centre within it. */
	height: 42px;
	padding: 0 8px 0 16px;
	border: 1px solid var(--border);
	border-radius: 8px;
	background: var(--bg-input);
	color: var(--text-primary);
	font-size: 14px;
	cursor: pointer;
	transition: border-color 0.2s;
}

.cat-picker:hover {
	border-color: var(--border-hover);
}

.cat-picker-display {
	flex: 1;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.cat-picker-display.placeholder {
	color: var(--text-muted);
}

.cat-picker-disabled {
	pointer-events: none;
	opacity: 0.5;
}

/* X clear button + chevron button — square icon buttons with hover lift */
.cat-picker-clear,
.cat-picker-chevron {
	width: 28px;
	height: 28px;
	border-radius: 6px;
	background: transparent;
	border: none;
	display: flex;
	align-items: center;
	justify-content: center;
	color: var(--text-muted);
	cursor: pointer;
	transition: background 0.15s ease, color 0.15s ease;
	flex-shrink: 0;
	padding: 0;
}
.cat-picker-clear:hover,
.cat-picker-chevron:hover {
	background: var(--bg-hover);
	color: var(--text-primary);
}
/* `display:flex` above wins over the user-agent `[hidden]` rule, so make the
   X explicitly disappear when no value is selected */
.cat-picker-clear[hidden] {
	display: none;
}

/* Vertical divider between the X and the chevron */
.cat-picker-divider {
	width: 1px;
	height: 20px;
	background: var(--border);
	margin: 0 4px;
	flex-shrink: 0;
}

.category-pickers .cat-picker {
	white-space: nowrap;
}

/* Picker Selector - Display field (looks like dropdown) */
.picker-disabled {
	pointer-events: none;
	opacity: 0.5;
}

.picker-selector {
	display: flex;
	align-items: center;
	justify-content: space-between;
	width: 100%;
	padding: 8px 12px;
	border: 1px solid var(--border);
	border-radius: 4px;
	background: var(--bg-input);
	color: var(--text-primary);
	font-size: 14px;
	cursor: pointer;
	transition: border-color 0.2s;
}

.picker-selector:hover {
	border-color: var(--border-hover);
}

.picker-selector-text {
	flex: 1;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.picker-selector-text.placeholder {
	color: var(--text-muted);
}

.picker-selector .material-symbols-outlined {
	font-size: 20px;
	color: var(--text-muted);
}

/* Jar Selector - display field */
.jar-selector {
	display: flex;
	align-items: center;
	justify-content: space-between;
	width: 100%;
	padding: 8px 12px;
	border: 1px solid var(--border);
	border-radius: 4px;
	background: var(--bg-input);
	color: var(--text-primary);
	font-size: 14px;
	cursor: pointer;
	transition: border-color 0.2s;
}

.jar-selector:hover {
	border-color: var(--border-hover);
}

.jar-selector-text {
	flex: 1;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.jar-selector-text.placeholder {
	color: var(--text-muted);
}

.jar-selector .material-symbols-outlined {
	font-size: 20px;
	color: var(--text-muted);
}

/* Slideout Size — base .slideout-panel is the default 500px. The only opt-in
   variant is .slideout-sm (used by the compact year / date / period pickers).
   Class-based so it applies to every stacked panel, not a fixed id. The legacy
   .subslideout-sm alias is kept so any caller still passing it keeps working. */
.slideout-panel.slideout-sm,
.slideout-panel.subslideout-sm {
	width: 360px;
}

/* .slideout-wide — wide list panel (Category transactions, Jar Ledger). Sized
   to the FULL usable canvas, i.e. the content area to the right of the 220px
   sidebar within the 1200px app column — it covers the whole canvas while the
   sidebar stays visible. Mobile collapses to 100vw (responsive.css). */
.slideout-panel.slideout-wide {
	width: calc(min(100vw, 1200px) - 220px);
}

/* ========================================================================== */
/* IMPORTS STYLES (consolidated from imports.css)                             */
/* ========================================================================== */

/* Imports Slideout */
.imports-actions {
	padding: 16px 24px;
	display: flex;
	gap: 12px;
	border-bottom: 1px solid var(--border);
	background: var(--bg-input);
}

/* × button inside a tag pill — SVG glyph with a left divider line. Width
   collapses to 0 by default; on parent .tag-pill hover it slides out from
   the right (width + margin-left + padding-left transition) and the SVG
   fades in. Colour follows currentColor so the stroke matches the pill's
   text colour. Wired by buildTagPills($tags, $removeFn) in F_GenerateTag.php. */
.tag-pill-remove {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 0;
	margin-left: 0;
	padding-left: 0;
	opacity: 0;
	overflow: hidden;
	border-left: 1px solid rgba(255, 255, 255, 0.28);
	height: 18px;
	cursor: pointer;
	color: rgba(255, 255, 255, 0.85);
	transition:
		width 200ms cubic-bezier(.4, 0, .2, 1),
		margin-left 200ms cubic-bezier(.4, 0, .2, 1),
		padding-left 200ms cubic-bezier(.4, 0, .2, 1),
		opacity 140ms ease 60ms,
		color 120ms ease;
}

.tag-pill:hover .tag-pill-remove {
	width: 18px;
	margin-left: 8px;
	padding-left: 8px;
	opacity: 1;
}

.tag-pill-remove:hover {
	color: #fff;
}

.tag-pill-remove svg {
	width: 12px;
	height: 12px;
	display: block;
}

/* Edit/delete action icons — base styling. Used by the group-manager rows
   (overlaid inline, see .group-manager-actions). */
.account-action-btn {
	cursor: pointer;
	color: var(--text-muted);
}

.account-action-btn:hover {
	color: var(--text-primary);
}

.account-action-delete:hover {
	color: var(--danger);
}

/* Jar group manager rows — full-width name input with action icons (trash /
   check / close) overlaid INSIDE the input on the right. Row is the positioning
   context; actions are absolutely positioned so the input can take 100% width
   without a separate column eating space. */
/* Flex column with a uniform 6px gap — same spacing model as the attachments
   .receipt-section. The Add Group trigger is the first child; group rows follow.
   margin-top separates the list from the info note above it. */
#group-manager-list {
	display: flex;
	flex-direction: column;
	gap: 6px;
	margin-top: 32px;
}
.group-manager-row {
	position: relative;
}
.group-manager-name {
	width: 100%;
	box-sizing: border-box;
	/* Reserve room on the right for the overlaid action icons */
	padding-right: 56px;
	background: var(--bg-input);
	border: 1px solid var(--border);
	border-radius: 6px;
	color: var(--text-primary);
	padding: 6px 10px;
	font-size: 14px;
}
.group-manager-name:focus {
	outline: none;
	border-color: var(--accent-blue);
}
/* Actions cluster overlaid on the right edge of the input (vertically centered).
   Sits above the input's padding-right reservation so the text never overlaps. */
.group-manager-actions {
	position: absolute;
	right: 8px;
	top: 50%;
	transform: translateY(-50%);
	display: flex;
	align-items: center;
	gap: 6px;
}
.group-manager-actions .account-action-btn {
	opacity: 0;
	transition: opacity 0.15s;
}
.group-manager-row:hover .group-manager-actions .account-action-btn {
	opacity: 1;
}
/* New-group row's check/close icons must always be visible — there's no other
   way to confirm/cancel. Override the hover-only fade. */
#new-group-row .group-manager-actions .account-action-btn {
	opacity: 1;
}

.account-name-input {
	background: var(--bg-input);
	border: 1px solid var(--border);
	border-radius: 4px;
	color: var(--text-primary);
	padding: 2px 6px;
	font-size: 0.9em;
	width: 160px;
}

.imports-section-title {
	padding: 12px 0;
	font-size: 13px;
	color: var(--text-dark);
	text-transform: uppercase;
	letter-spacing: 0.5px;
}

.imports-transactions-list {
	display: flex;
	flex-direction: column;
	gap: 8px;
}

/* Transaction Row */
.imports-transaction-row {
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 10px 16px;
	background: var(--bg-main);
	border-radius: 6px;
	cursor: pointer;
	border: 2px solid transparent;
	transition: all 0.2s ease;
}

.imports-transaction-row.selected {
	border-color: var(--accent-blue);
}

.imports-transaction-row.deselected {
	opacity: 0.5;
	border-color: var(--info-bg);
}

.imports-transaction-row.selected.ignored {
	border-color: var(--danger-text);
}

.imports-transaction-row.deselected.ignored {
	border-color: var(--danger-bg-strong);
}

.imports-transaction-row:hover {
	background: var(--border);
}

/* Row Columns */
.imports-col-date {
	font-size: 13px;
	color: var(--text-dark);
	white-space: nowrap;
}

.imports-col-desc {
	flex: 1;
	font-size: 14px;
	font-weight: 500;
	color: var(--text-primary);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.imports-col-amount {
	font-size: 14px;
	font-weight: 600;
	text-align: right;
	white-space: nowrap;
}

.imports-col-ignore {
	display: flex;
	align-items: center;
	justify-content: center;
}

/* Ignore Toggle Button */
.imports-toggle-btn {
	background: var(--border-hover);
	border: none;
	width: 44px;
	height: 24px;
	border-radius: 12px;
	cursor: pointer;
	position: relative;
	transition: all 0.2s;
}

.imports-toggle-btn::before {
	content: '';
	position: absolute;
	width: 18px;
	height: 18px;
	border-radius: 50%;
	background: var(--text-dark);
	top: 3px;
	left: 3px;
	transition: all 0.2s;
}

.imports-toggle-btn.active {
	background: var(--danger-text);
}

.imports-toggle-btn.active::before {
	left: 23px;
	background: var(--toggle-thumb);
}

.imports-toggle-btn:hover {
	opacity: 0.8;
}

/* Duplicate Badge */
.imports-duplicate-badge {
	display: inline-flex;
	align-items: center;
	flex-shrink: 0;
	white-space: nowrap;
	padding: 2px 6px;
	border-radius: 3px;
	font-size: 10px;
	font-weight: 600;
	text-transform: uppercase;
	margin-left: 8px;
	background: var(--danger-bg-strong);
	color: var(--danger-text);
}

/* Skip Badge (CC payment keyword match — row is force-Skipped and locked) */
.imports-skip-badge {
	display: inline-flex;
	align-items: center;
	flex-shrink: 0;
	white-space: nowrap;
	padding: 2px 6px;
	border-radius: 3px;
	font-size: 10px;
	font-weight: 600;
	text-transform: uppercase;
	margin-left: 8px;
	background: var(--info-bg);
	color: var(--text-secondary);
}

/* Locked-skip row state — visually muted, both row body and toggle button
   are non-interactive (the JS handlers also early-return) */
.imports-transaction-row.locked-skip {
	cursor: not-allowed;
	opacity: 0.7;
}

.imports-transaction-row.locked-skip .imports-toggle-btn {
	cursor: not-allowed;
	opacity: 0.6;
	pointer-events: none;
}

/* Footer */
.imports-footer {
	justify-content: space-between;
	align-items: center;
}

.imports-footer-info {
	font-size: 14px;
	color: var(--text-dark);
}

/* Imports canvas body — fills the entire .canvas-body and arranges its children
   into a flex column. The transactions list owns the scroll (flex:1 +
   overflow-y:auto + min-height:0 = standard "shrinkable scroll child"
   pattern), which leaves the .imports-canvas-footer pinned at the bottom of
   the canvas naturally — no position:sticky needed, same trick the canvas
   frame uses with its header/body split. */
/* Inner layout for the Imports canvas-footer content (counts on the left,
   action button on the right). The .canvas-footer wrapper supplies the chrome
   (border, padding, bg) — this rule just lays out the inner row. */
.imports-canvas-footer {
	display: flex;
	justify-content: space-between;
	align-items: center;
	gap: 12px;
}

/* Account section header inside the imports lists. Sticks to the top of the
   scroll viewport (`.canvas-body`, 20px horizontal padding) so the section
   label stays visible while the user scrolls through that account's rows.
   Negative horizontal margins + matching padding bleed the header to the
   canvas edges so the bg + bottom border span the full width. This sticky
   is for IN-CONTENT section labels — the canvas frame (header/widgets/title)
   is still NOT position:sticky, it sits outside the scroll container. */
.imports-account-header {
	position: sticky;
	top: 0;
	margin: 0 -20px;
	padding: 12px 20px;
	font-size: 14px;
	font-weight: 600;
	color: var(--text-primary);
	text-transform: uppercase;
	letter-spacing: 0.5px;
	border-bottom: 1px solid var(--border);
	background: var(--bg-app);
	z-index: 1;
}

/* Empty State — big icon + message. Mirrors .tags-filter-empty so the Tags,
   Search, and Imports views all read as the same "nothing here yet" pattern. */
.imports-empty-state {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 24px;
	padding: 140px 20px;
	color: var(--text-secondary);
	text-align: center;
}
.imports-empty-state .imports-empty-state-icon {
	font-size: 96px;
	color: var(--text-tertiary);
}
.imports-empty-state-message {
	font-size: 20px;
	font-weight: 500;
	width: 100%;
	line-height: 1.4;
}

/* Recurring canvas empty state — same shape as .imports-empty-state. */
.recurring-empty-state {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 24px;
	padding: 140px 20px;
	color: var(--text-secondary);
	text-align: center;
}
.recurring-empty-state .recurring-empty-state-icon {
	font-size: 96px;
	color: var(--text-tertiary);
}
.recurring-empty-state-message {
	font-size: 20px;
	font-weight: 500;
	width: 100%;
	line-height: 1.4;
}

/* Muted "(Monthly)" / "(Weekly)" frequency label sitting beside the
   uppercase recurring-item name. Inherits the rest of the card layout
   from .group-card / .group-head. */
.recurring-frequency {
	font-weight: 400;
	font-size: 0.85em;
	color: var(--text-muted);
	letter-spacing: 0;
	text-transform: none;
}

/* Main imports container */
.imports-container {
	padding: 35px 0px 20px 0px;
	background: var(--bg-main);
	border-radius: 6px;
}

/* Navigation tabs */
.imports-nav {
	border-bottom: 2px solid var(--border);
	margin-bottom: 0;
}

.imports-nav > li > a {
	background: transparent;
	color: var(--text-muted);
	border: none;
	border-bottom: 2px solid transparent;
	margin-bottom: -2px;
	padding: 10px 20px;
}

.imports-nav > li > a:hover {
	background: transparent;
	color: var(--text-primary);
	border: none;
	border-bottom: 2px solid var(--border-hover);
}

.imports-nav > li.active > a,
.imports-nav > li.active > a:hover,
.imports-nav > li.active > a:focus {
	background: transparent;
	color: var(--accent-blue);
	border: none;
	border-bottom: 2px solid var(--accent-blue);
}

/* Tab content area */
.imports-tab-content {
	padding: 20px;
	background: var(--bg-input);
	border: 1px solid var(--border);
	border-top: none;
}

/* No imports message */
.NoNewImports {
	text-align: center;
	color: var(--danger-text);
	font-weight: bold;
	font-family: Tahoma;
	font-size: 15px;
	padding: 60px 0;
}

/* Import accounts — stacked clickable summary cards. Each .acct-card is a
   single read-only row; tapping it opens the Add/Edit Account form slideout.
   Container is a plain flex-column so cards stack with a small gap. */
#import-accounts-list {
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.acct-card {
	background: var(--bg-input);
	border: 1px solid var(--border);
	border-radius: 8px;
	overflow: hidden;
	transition: background 0.15s;
}

.acct-card:hover {
	background: var(--bg-hover);
}

/* Clickable summary row — main info (flex) + balance + a static "opens"
   chevron. The whole card is the click target. */
.acct-card-row {
	display: flex;
	align-items: center;
	padding: 12px 14px;
	cursor: pointer;
	gap: 10px;
}

.acct-chevron {
	color: var(--text-muted);
	font-size: 20px;
	flex-shrink: 0;
}

/* Main info — name line (name + status badges) over an optional tag pill. */
.acct-card-main {
	flex: 1;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 4px;
}

.acct-name-line {
	display: flex;
	align-items: center;
	gap: 8px;
	min-width: 0;
}

.acct-name {
	color: var(--text-primary);
	font-size: 15px;
	font-weight: 500;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

/* Status badges — small muted pills next to the name (Credit Card / Disabled). */
.acct-badge {
	flex-shrink: 0;
	font-size: 11px;
	font-weight: 500;
	color: var(--text-secondary);
	background: var(--bg-darker);
	border: 1px solid var(--border);
	border-radius: 4px;
	padding: 1px 6px;
}

.acct-badge-off {
	color: var(--accent-red);
}

.acct-card-tagline {
	display: flex;
}

.acct-balance {
	color: var(--text-primary);
	font-size: 15px;
	font-weight: 500;
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
	text-align: right;
	flex-shrink: 0;
}

.acct-balance.is-negative {
	color: var(--accent-red);
}

/* Account form — Credit Card / Enabled toggle rows put the label and the
   switch on one line (label left, switch right). */
.account-toggle-group {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
}

.account-toggle-group label {
	margin-bottom: 0;
}

/* Toggle switch (imports) */
.switch {
	position: relative;
	display: inline-block;
	width: 50px;
	height: 26px;
}

.switch input {
	opacity: 0;
	width: 0;
	height: 0;
}

.slider {
	position: absolute;
	cursor: pointer;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	background-color: var(--border);
	transition: .3s;
}

.slider:before {
	position: absolute;
	content: "";
	height: 20px;
	width: 20px;
	left: 3px;
	bottom: 3px;
	background-color: var(--text-muted);
	transition: .3s;
}

input:checked + .slider {
	background-color: var(--success);
}

input:checked + .slider:before {
	transform: translateX(24px);
	background-color: var(--toggle-thumb);
}

.slider.round {
	border-radius: 26px;
}

.slider.round:before {
	border-radius: 50%;
}

/* Status indicators */
.status-dot {
	display: inline-block;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	margin-left: 5px;
}

.status-active {
	background-color: var(--success);
}

.status-inactive {
	background-color: var(--danger);
}

/* Account header rows */
.account-header {
	background: var(--bg-darker);
}

.account-header td {
	padding: 10px 8px;
	border-top: 2px solid var(--border);
	color: var(--text-primary);
	font-weight: 600;
}

/* Pending transactions table */
.pending-table {
	width: 100%;
	margin-top: 15px;
	background: var(--bg-main);
}

.pending-table thead {
	background: var(--bg-darker);
}

.pending-table th {
	color: var(--text-primary);
	padding: 10px 8px;
	border-bottom: 2px solid var(--accent-blue);
}

.pending-table td {
	padding: 8px;
	border-bottom: 1px solid var(--border);
}

.pending-table tbody tr:hover {
	background: var(--bg-hover);
}

.pending-table .col-checkbox {
	width: 50px;
	text-align: center;
}

.pending-table .col-date {
	white-space: nowrap;
}

.pending-table .col-merchant {
	width: 100%;
	max-width: 200px;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.pending-table .col-amount {
	width: 120px;
	text-align: right;
	white-space: nowrap;
}

/* Transaction footer buttons */
.pending-transactions-footer {
	margin-top: 15px;
	padding: 15px;
	background: var(--bg-darker);
	border-top: 1px solid var(--border);
	display: flex;
	gap: 12px;
}

.pending-transactions-footer .btn {
	padding: 10px 20px;
	border-radius: 4px;
	font-size: 14px;
	font-weight: 600;
	cursor: pointer;
	transition: all 0.2s;
}

.pending-transactions-footer .btn-success {
	background: var(--success);
	color: var(--success-text);
	border: none;
}

.pending-transactions-footer .btn-success:hover {
	background: var(--success-hover);
}

.pending-transactions-footer .btn-warning {
	background: var(--border);
	color: var(--text-primary);
	border: 1px solid var(--border-hover);
}

.pending-transactions-footer .btn-warning:hover {
	background: var(--bg-hover);
	border-color: var(--border-focus);
}

/* Import Container */
.import-container {
	display: flex;
	flex-direction: column;
	height: 500px;
}

.import-header {
	flex-shrink: 0;
	font-weight: bold;
}

.import-body {
	flex: 1;
	overflow-y: auto;
}

.import-footer {
	flex-shrink: 0;
	padding: 10px 0;
	text-align: right;
}

.import-row {
	display: flex;
}

.col-check {
	width: 40px;
}

.col-date {
	width: 120px;
}

.col-desc {
	flex: 1;
}

.col-amount {
	width: 100px;
	text-align: right;
}

/* Pending transactions - div-based layout */
.pending-container {
	display: flex;
	flex-direction: column;
	height: 576px;
	background: var(--bg-main);
}

.pending-header {
	flex-shrink: 0;
	background: var(--bg-darker);
}

.pending-header .pending-row {
	font-weight: 600;
	color: var(--text-primary);
	border-bottom: 2px solid var(--accent-blue);
}

.pending-body {
	flex: 1;
	overflow-y: auto;
}

.pending-body .pending-row:hover {
	background: var(--bg-hover);
}

.pending-footer {
	flex-shrink: 0;
	padding: 15px;
	background: var(--bg-darker);
	border-top: 1px solid var(--border);
	display: flex;
	justify-content: flex-end;
	gap: 12px;
}

.pending-row {
	display: flex;
	align-items: center;
	border-bottom: 1px solid var(--border);
	padding: 0 10px;
}

.pending-row .col-checkbox {
	width: 50px;
	text-align: center;
	padding: 10px 8px;
}

.pending-row .col-date {
	width: 120px;
	white-space: nowrap;
	padding: 10px 8px;
}

.pending-row .col-description {
	flex: 1;
	padding: 10px 8px;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.pending-row .col-amount {
	width: 120px;
	text-align: right;
	white-space: nowrap;
	padding: 10px 8px;
}

.potential-duplicate {
	background-color: var(--danger-bg);
	border-left: 4px solid var(--danger-text);
}

.potential-duplicate:hover {
	background-color: var(--danger-bg-strong);
}

 /* LITS — Line in the Sand
    Layout follows the supplied spec: sectioned panel, label/amount rows,
    indented per-group jar rows with a clickable check, plain blue underlined
    "+ Pending Credit Card" action, and a borderless Surplus/Shortfall row at
    the bottom (green for surplus, red for shortfall). */

  .lits-section {
        margin-bottom: 20px;
  }
  .lits-section-title {
        font-size: 16px;
        font-weight: 600;
        margin-bottom: 8px;
        color: var(--text-primary);
  }

  .lits-row {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 8px 0;
        font-size: 14px;
  }
  .lits-row-label { color: var(--text-secondary); }
  .lits-row-amt   { color: var(--text-primary); font-variant-numeric: tabular-nums; }

  /* Pending CC label sits flush against the pill row below it (no
     intervening padding). Replaces an inline `style="padding-bottom: 0;"`. */
  .lits-row.lits-row-pcc-label { padding-bottom: 0; }

  /* Indented per-group jar row — a custom check + label + amount. `.off` flips
     the check to hollow and mutes the row; the calculateLITS sum excludes
     anything carrying .off. */
  .lits-row.indent {
        padding-left: 26px;
        position: relative;
        cursor: pointer;
  }
  .lits-row.indent .check {
        position: absolute;
        left: 0;
        top: 50%;
        transform: translateY(-50%);
        width: 16px;
        height: 16px;
        border-radius: 3px;
        border: 1px solid var(--accent-blue);
        background: var(--accent-blue);
        display: flex;
        align-items: center;
        justify-content: center;
  }
  .lits-row.indent .check::after {
        content: "";
        width: 4px;
        height: 7px;
        border: solid #fff;
        border-width: 0 1.5px 1.5px 0;
        transform: rotate(45deg);
        margin-bottom: 1px;
  }
  .lits-row.indent.off .check {
        background: transparent;
        border-color: var(--border);
  }
  .lits-row.indent.off .check::after { display: none; }
  .lits-row.indent.off .lits-row-label,
  .lits-row.indent.off .lits-row-amt { color: var(--text-muted); }

  /* Inline (N) link beside "Income Not Arrived" — toggles the breakdown panel. */
  .lits-ilink {
        color: var(--accent-blue);
        text-decoration: underline;
        text-underline-offset: 2px;
        font-size: 13px;
        margin-left: 4px;
        cursor: pointer;
  }

  /* Subtotal row at the bottom of each section. */
  .lits-total-row {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 10px 0 4px;
        border-top: 1px solid var(--border);
        margin-top: 4px;
        font-size: 14px;
        font-weight: 600;
        color: var(--text-primary);
        font-variant-numeric: tabular-nums;
  }

  /* "+ Pending Credit Card" — plain underlined link, not a button. */
  .lits-action {
        color: var(--accent-blue);
        font-size: 13px;
        padding: 10px 0 4px;
        cursor: pointer;
        text-decoration: underline;
        text-underline-offset: 2px;
        display: inline-block;
  }

  /* Pending Credit Card chips — pill-style amounts that wrap onto multiple
     lines. The trailing pill is an empty input (no value yet); typing a
     value and pressing Enter / blurring converts it to a static pill with
     a × delete button and appends a fresh empty input pill at the end. */
  .pcc-pills {
        display: flex;
        flex-wrap: wrap;
        gap: 6px;
        padding: 6px 0 4px;
  }
  .pcc-pill {
        display: inline-flex;
        align-items: center;
        gap: 4px;
        background: var(--bg-darker);
        border-radius: 4px;
        padding: 3px 4px 3px 8px;
        font-size: 13px;
        color: var(--text-primary);
        font-variant-numeric: tabular-nums;
  }
  .pcc-pill .pcc-x {
        color: var(--text-muted);
        font-size: 14px;
        cursor: pointer;
        width: 16px;
        height: 16px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        border-radius: 2px;
  }
  .pcc-pill .pcc-x:hover {
        color: var(--text-primary);
        background: var(--bg-hover);
  }
  .pcc-pill input {
        width: 56px;
        background: transparent;
        border: none;
        color: var(--text-primary);
        font-size: 13px;
        text-align: right;
        padding: 0;
        outline: none;
        font-family: inherit;
  }
  .pcc-pill input::placeholder { color: var(--text-muted); }

  /* Result row — borderless flex line at the bottom; color flips based on
     whether the result is surplus (green) or shortfall (red). */
  .lits-result-row {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 14px 0 4px;
        border-top: 1px solid var(--border);
        margin-top: 24px;
  }
  .lits-result-label,
  .lits-result-amt {
        font-size: 15px;
        font-weight: 600;
        font-variant-numeric: tabular-nums;
  }
  .lits-result-positive .lits-result-label,
  .lits-result-positive .lits-result-amt { color: var(--success-text, #22c55e); }
  .lits-result-negative .lits-result-label,
  .lits-result-negative .lits-result-amt { color: var(--danger-text, #ef4444); }

  
   /* ========================================
     Jars Grid - New Card Layout
     ======================================== */

  /* .jars-container takes no padding — .canvas-body provides the standard
     gutter, and .jars-grid's `gap` handles between-card spacing only (CSS
     Grid gap doesn't add outer-edge insets). */

  .jars-header {
        display: flex;
        justify-content: space-between;
        align-items: baseline;
        margin-bottom: 16px;
  }
  /* Ungrouped sections render with an empty .jars-title — collapse the
     whole header (and its margin) so the first grid sits flush at the top. */
  .jars-header:has(.jars-title:empty) {
        display: none;
  }

  /* Per-section running total — sits beneath the grid, right-aligned */
  .jars-footer {
        display: flex;
        justify-content: flex-end;
        align-items: baseline;
        margin-top: 12px;
        padding-top: 10px;
  }

  .jars-title {
        font-size: 20px;
        font-weight: 800;
        color: var(--text-primary);
        letter-spacing: -0.03em;
  }

  .jars-total {
        font-size: 18px;
        font-weight: 800;
        font-family: 'JetBrains Mono', monospace;
        color: var(--text-primary);
        letter-spacing: -0.03em;
  }

  /* Wrapper for search + clear X button. Fixed desktop width so every canvas
     (Jars / Tags / Imports history) renders the same-sized search input
     regardless of how many sibling widget buttons share the WIDGETS cluster.
     responsive.css overrides on mobile to flex:1. */
  .search-field-wrap {
        position: relative;
        display: flex;
        align-items: center;
        width: 200px;
        flex-shrink: 0;
  }

  .search-field-clear {
        position: absolute;
        right: 10px;
        cursor: pointer;
        color: var(--text-muted);
        font-size: 18px;
        line-height: 1;
        user-select: none;
        /* The &times; glyph renders low within its line box, so it reads ~2px
           below centre — nudge it up so it sits centered on the input. */
        transform: translateY(-2px);
  }

  .search-field-clear:hover {
        color: var(--text-primary);
  }

  .search-field {
        width: 100%;
        height: 32px; /* match .header-icon-btn icon height */
        padding: 0 30px 0 12px; /* right padding leaves room for X */
        border-radius: 8px; /* match .header-icon-btn radius */
        border: 1px solid var(--surface-edge);
        background: var(--surface-tint-1);
        color: var(--text-primary);
        font-size: 13px;
        box-sizing: border-box;
  }

  .search-field::placeholder {
        color: var(--text-faint);
  }

  .search-field:focus {
        outline: none;
        border-color: var(--accent-blue);
  }

  /* Global search no-results placeholder — rendered in the Budget canvas
     BODY when search is active but every result block is empty.
     D_Budget.php emits .search-placeholder only in that case,
     so visibility is decided server-side (no :has() chain needed).
     Sizing matches `.tags-filter-empty` so the two empty states read the same. */
  .search-placeholder {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 24px;
        padding: 140px 20px;
        color: var(--text-secondary);
        text-align: center;
  }

  /* Descendant selector bumps specificity above .material-symbols-outlined's
     own 24px so the search icon paints at 96px like the Tags empty-state. */
  .search-placeholder .material-symbols-outlined {
        font-size: 96px;
        color: var(--text-tertiary);
  }

  .search-placeholder-message {
        font-size: 20px;
        font-weight: 500;
        max-width: 360px;
        line-height: 1.4;
  }

  .jars-grid {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
        gap: 6px;
  }

  .jar-card {
        padding: 10px 12px;
        border-radius: 12px;
        background: var(--surface-tint-1);
        border: 1px solid var(--surface-edge-soft);
        cursor: pointer;
        text-align: center;
        /* Flex column so the amount can be pushed to the bottom regardless
           of how many lines the jar name wraps to. CSS Grid makes all cards
           in a row the same height; combined with margin-top:auto on the
           amount, the amount lines up across every card. */
        display: flex;
        flex-direction: column;
  }

  .jar-card:hover {
        background: var(--surface-tint-2);
  }

  .jar-card.selected {
        background: var(--selected-bg);
        border-color: var(--accent-blue);
  }

  /* Scoped to .jar-card so the same .jar-card-negative class can be reused on
     other elements (e.g. .jar-list-row in list-view mode) without forcing the
     red row background. */
  .jar-card.jar-card-negative {
        background: var(--danger-bg);
        border-color: var(--danger-bg);
  }

  .jar-card.jar-card-negative:hover {
        background: var(--danger-bg-strong);
  }

  .jar-card-name {
        font-size: 12px;
        font-weight: 600;
        color: var(--text-secondary);
        margin-bottom: 4px;
        line-height: 1.25;
        overflow: hidden;
        display: -webkit-box;
        line-clamp: 2;
		-webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
  }

  .jar-card-amount {
        font-size: 15px;
        font-weight: 700;
        font-family: 'JetBrains Mono', monospace;
        color: var(--text-primary);
        /* Push the amount to the bottom of the (flex column) card so it
           lines up across every card in the row regardless of how many
           lines the name above wrapped to. */
        margin-top: auto;
  }

  .jar-card-negative .jar-card-amount {
        color: var(--accent-red);
  }

  /* ── Jars LIST view ─────────────────────────────────────────────────────────
     Each section reuses Budget_TransactionContainer.template, so list rows
     inherit .expense-row's grid layout / hover / selection / click handling
     directly. The list-specific class .jar-list-row only carries jar-mode
     overrides:
       - red amount when the row carries .jar-card-negative (no row tint —
         the .jar-card-negative red background is scoped to .jar-card above)
       - the .jar-card-splat amber outline already applies from the grid rule
         (it's unscoped). That gives the overflow signal on list rows for free.
     The list section header / total bar come from .section-header /
     .section-footer in Budget_TransactionContainer's existing CSS. */
  .jar-list-row.jar-card-negative .expense-amount {
        color: var(--accent-red);
  }

  /* ── Jars COMPACT view ──────────────────────────────────────────────────────
     Dense 2-column flow per group. A small status dot on the left carries the
     sign so the numbers stay clean (green positive / red negative / grey zero).
     No per-section total — the view is for "everything on one screen, no
     scrolling" / sidebar reference mode. */
  .jars-compact-section {
        margin-bottom: 20px;
  }
  .jars-compact-section-title {
        font-size: 13px;
        font-weight: 600;
        color: var(--text-secondary);
        text-transform: uppercase;
        letter-spacing: 0.5px;
        padding-bottom: 6px;
        border-bottom: 1px solid var(--border-color);
        margin-bottom: 6px;
  }
  /* CSS columns over flex/grid so the rows flow newspaper-style and balance
     across columns automatically — column-count handles odd jar counts cleanly. */
  .jars-compact-rows {
        column-count: 2;
        column-gap: 32px;
  }
  .jar-compact-row {
        display: flex;
        align-items: center;
        gap: 8px;
        padding: 3px 4px;
        cursor: pointer;
        break-inside: avoid;
        font-size: 13px;
        border-radius: 4px;
  }
  .jar-compact-row:hover {
        background: var(--surface-tint-1);
  }
  .jar-compact-row.selected {
        background: var(--selected-bg);
  }
  .jar-compact-dot {
        width: 8px;
        height: 8px;
        border-radius: 50%;
        flex-shrink: 0;
        background: var(--text-tertiary);
  }
  .jar-compact-row.is-positive .jar-compact-dot { background: var(--accent-green); }
  .jar-compact-row.is-negative .jar-compact-dot { background: var(--accent-red); }
  .jar-compact-name {
        flex: 1;
        color: var(--text-primary);
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
  }
  .jar-compact-amount {
        color: var(--text-tertiary);
        font-variant-numeric: tabular-nums;
        font-weight: 600;
  }
  .jar-compact-row.is-positive .jar-compact-amount { color: var(--accent-green); }
  .jar-compact-row.is-negative .jar-compact-amount { color: var(--accent-red); }
  
  
    /* ========================================================================== */
  /* TOAST NOTIFICATIONS                                                        */
  /* ========================================================================== */

  /* Toast container - fixed position holds all toasts */
  .toast-container {
        position: fixed;
        z-index: 80;
        display: flex;
        flex-direction: column;
        gap: 10px;
        pointer-events: none;
        bottom: 20px;
        left: 20px;
        align-items: flex-start;
  }

  /* Individual toast */
  .toast {
        min-width: 300px;
        max-width: 420px;
        padding: 0;
        border-radius: 10px;
        color: var(--toast-text);
        font-family: inherit;
        box-shadow: 0 6px 20px var(--shadow);
        pointer-events: auto;
        cursor: pointer;
        overflow: hidden;
        position: relative;
        animation: toast-slide-in 0.35s cubic-bezier(0.21, 1.02, 0.73, 1) forwards;
  }

  /* Toast body layout */
  .toast-body {
        display: flex;
        align-items: center;
        gap: 12px;
        padding: 14px 18px;
  }

  /* Toast type colors */
  .toast-success { background: var(--toast-bg-success); border-left: 4px solid var(--toast-success); }
  .toast-error   { background: var(--toast-bg-error);   border-left: 4px solid var(--toast-error); }
  .toast-warning { background: var(--toast-bg-warning); border-left: 4px solid var(--toast-warning); }
  .toast-info    { background: var(--toast-bg-info);    border-left: 4px solid var(--toast-info); }

  /* Toast icon */
  .toast-icon-wrap {
        width: 32px;
        height: 32px;
        border-radius: 8px;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 16px;
        flex-shrink: 0;
  }

  .toast-success .toast-icon-wrap { background: var(--toast-icon-bg-success); color: var(--toast-success); }
  .toast-error .toast-icon-wrap   { background: var(--toast-icon-bg-error);   color: var(--toast-error); }
  .toast-warning .toast-icon-wrap { background: var(--toast-icon-bg-warning); color: var(--toast-warning); }
  .toast-info .toast-icon-wrap    { background: var(--toast-icon-bg-info);    color: var(--toast-info); }

  /* Toast text content */
  .toast-content { flex: 1; min-width: 0; }

  .toast-title {
        font-size: 13px;
        font-weight: 600;
        margin-bottom: 2px;
  }

  .toast-message {
        font-size: 12px;
        opacity: 0.7;
        line-height: 1.4;
  }

  /* Toast close button */
  .toast-close {
        position: absolute;
        top: 8px;
        right: 10px;
        background: none;
        border: none;
        color: var(--toast-close);
        font-size: 16px;
        cursor: pointer;
        padding: 2px 4px;
        line-height: 1;
        pointer-events: auto;
        transition: color 0.15s;
  }

  .toast-close:hover { color: var(--toast-close-hover); }

  /* Toast progress bar */
  .toast-progress {
        height: 3px;
        width: 100%;
        position: relative;
        overflow: hidden;
  }

  .toast-progress-bar {
        height: 100%;
        width: 100%;
        transform-origin: left;
  }

  .toast-success .toast-progress-bar { background: var(--toast-success); }
  .toast-error .toast-progress-bar   { background: var(--toast-error); }
  .toast-warning .toast-progress-bar { background: var(--toast-warning); }
  .toast-info .toast-progress-bar    { background: var(--toast-info); }

  /* Toast slide animations */
  @keyframes toast-slide-in {
        from { opacity: 0; transform: translateY(20px) scale(0.95); }
        to   { opacity: 1; transform: translateY(0) scale(1); }
  }

  @keyframes toast-slide-out {
        from { opacity: 1; transform: translateY(0) scale(1); }
        to   { opacity: 0; transform: translateY(20px) scale(0.95); }
  }

  @keyframes toast-progress-shrink {
        from { transform: scaleX(1); }
        to   { transform: scaleX(0); }
  }

  /* Removing state */
  .toast.removing {
        animation: toast-slide-out 0.3s ease forwards;
  }


  /* ========================================================================== */
  /* DIALOG (Yes/No confirm modal)                                              */
  /* ========================================================================== */

  /* Backdrop overlay — covers whole viewport, click-outside cancels */
  .dialog-overlay {
        position: fixed;
        inset: 0;
        background: var(--dialog-overlay);
        z-index: 100;
        display: flex;
        align-items: center;
        justify-content: center;
        animation: dialog-fade-in 0.2s ease forwards;
  }

  /* Centered card */
  .dialog {
        position: relative;
        min-width: 320px;
        max-width: 480px;
        background: var(--dialog-bg);
        border-radius: 10px;
        color: var(--dialog-text);
        font-family: inherit;
        box-shadow: 0 10px 40px var(--shadow);
        overflow: hidden;
        animation: dialog-slide-in 0.25s cubic-bezier(0.21, 1.02, 0.73, 1) forwards;
  }

  /* Header — title + close X */
  .dialog-header {
        display: flex;
        align-items: center;
        padding: 14px 18px;
        border-bottom: 1px solid var(--dialog-border);
  }

  .dialog-title {
        flex: 1;
        font-size: 14px;
        font-weight: 600;
        margin: 0;
        padding-right: 12px;
  }

  /* X close button — top right */
  .dialog-close {
        background: none;
        border: none;
        color: var(--dialog-close);
        font-size: 22px;
        line-height: 1;
        cursor: pointer;
        padding: 0 4px;
        transition: color 0.15s;
  }

  .dialog-close:hover {
        color: var(--dialog-close-hover);
  }

  /* Body — message text. white-space:pre-line preserves \n breaks */
  .dialog-body {
        padding: 18px;
        font-size: 13px;
        line-height: 1.5;
        color: var(--dialog-body-text);
        white-space: pre-line;
  }

  /* Footer — Yes/No buttons */
  .dialog-footer {
        display: flex;
        justify-content: flex-end;
        gap: 8px;
        padding: 12px 18px;
        background: var(--dialog-footer-bg);
  }

  /* Optional help link in the dialog footer, sits to the LEFT of the
     No/Yes buttons. margin-right:auto pushes the buttons to the right
     while the link stays anchored on the left. */
  .dialog-help-link {
        margin-right: auto;
        align-self: center;
        font-size: 13px;
        color: var(--accent-blue);
        text-decoration: none;
  }

  .dialog-help-link:hover {
        text-decoration: underline;
  }

  .dialog-btn {
        padding: 8px 18px;
        font-size: 13px;
        font-weight: 500;
        border: none;
        border-radius: 6px;
        cursor: pointer;
        font-family: inherit;
        transition: background 0.15s;
  }

  .dialog-btn-no {
        background: var(--dialog-btn-no-bg);
        color: var(--dialog-btn-no-text);
  }

  .dialog-btn-no:hover {
        background: var(--dialog-btn-no-bg-hover);
  }

  .dialog-btn-yes {
        background: var(--accent-blue);
        color: var(--text-on-accent);
  }

  .dialog-btn-yes:hover {
        background: var(--accent-blue-hover);
  }

  /* Animations */
  @keyframes dialog-fade-in {
        from { opacity: 0; }
        to   { opacity: 1; }
  }

  @keyframes dialog-slide-in {
        from { opacity: 0; transform: translateY(-12px) scale(0.97); }
        to   { opacity: 1; transform: translateY(0) scale(1); }
  }

  @keyframes dialog-fade-out {
        from { opacity: 1; }
        to   { opacity: 0; }
  }

  .dialog-overlay.removing {
        animation: dialog-fade-out 0.18s ease forwards;
  }


    .add-btn {
        width: 100%;
        margin-top: 10px;
        padding: 9px;
        background: var(--bg-main);
        border: 1px dashed var(--border);
        border-radius: 6px;
        color: var(--text-muted);
        font-size: 12px;
        font-weight: 600;
        cursor: pointer;
        font-family: inherit;
        transition: all 0.15s;
  }

  .add-btn:hover {
        border-color: var(--accent-blue);
        color: var(--text-primary);
  }

/* ========== CATEGORIES CANVAS — PILLS + BAR LIST + BREADCRUMB ========== */

/* Year pill strip — lives in the canvas SUBHEADER slot. Horizontally
   scrollable on overflow; native scrollbar hidden so the strip reads as
   a single row. One pill per year of activity since the most recent
   Epoch row; newest first. */
.period-chips {
	display: flex;
	gap: 6px;
	overflow-x: auto;
	scrollbar-width: none;
	-ms-overflow-style: none;
	padding: 2px 0 4px 0;
	width: 100%;
}
.period-chips::-webkit-scrollbar { display: none; }

.period-chip {
	flex: 0 0 auto;
	border: 1px dashed var(--border);
	background: transparent;
	color: var(--text-secondary);
	border-radius: 14px;
	padding: 4px 12px;
	font-size: 12px;
	white-space: nowrap;
	cursor: pointer;
	transition: background-color 0.1s, color 0.1s, border-color 0.1s;
}
.period-chip:hover {
	color: var(--text-primary);
	border-color: var(--text-muted);
}
.period-chip.is-selected {
	background: var(--accent-blue);
	color: #fff;
	border: 1px solid var(--accent-blue);
}

/* Breadcrumb sits above the bar list / transaction list when the user
   has drilled into a parent or child. Top-level view has no breadcrumb. */
.cat-breadcrumb {
	padding: 8px 4px 6px 4px;
	margin-bottom: 20px;
	font-size: 13px;
	min-height: 30px;
	display: flex;
	align-items: center;
	gap: 2px;
	flex-wrap: wrap;
}

.cat-crumb-link {
	color: var(--accent-blue);
	cursor: pointer;
}

.cat-crumb-link:hover {
	text-decoration: underline;
}

.cat-crumb-active {
	color: var(--text-primary);
}

.cat-crumb-sep {
	margin: 0 5px;
	color: var(--text-muted);
}

/* Categories bar list — section labels + full-height proportional gradient
   bars sitting behind each row's content (top-level + parent-drill views). */
.cat-section-label {
	font-size: 14px;
	font-weight: 700;
	color: var(--text-muted);
	letter-spacing: 0.08em;
	text-transform: uppercase;
	margin-top: 24px;
	margin-bottom: 14px;
}
.cat-section-label + .cat-section-label,
.cat-row + .cat-section-label,
.cat-group + .cat-section-label {
	margin-top: 44px;
}

.cat-row {
	position: relative;
	padding: 12px 14px;
	border-radius: 8px;
	overflow: hidden;
	margin-bottom: 4px;
	cursor: pointer;
	transition: background 0.12s ease;
}
.cat-row:hover {
	background: var(--bg-hover);
}

/* Childless top-level — shown for awareness (with a "No sub-categories" note)
   but not interactive: nothing to expand, and a top-level can't hold
   transactions directly. Default cursor + no hover highlight. */
.cat-row--childless {
	cursor: default;
}
.cat-row--childless:hover {
	background: transparent;
}

.cat-row__bar {
	position: absolute;
	top: 0;
	bottom: 0;
	left: 0;
	pointer-events: none;
}
.cat-row__bar--income {
	background: linear-gradient(90deg, rgba(29,158,117,0.55) 0%, rgba(29,158,117,0.35) 100%);
}
.cat-row__bar--expense {
	background: linear-gradient(90deg, rgba(226,75,74,0.55) 0%, rgba(226,75,74,0.35) 100%);
}
.cat-row__bar--other {
	background: linear-gradient(90deg, rgba(148,163,184,0.45) 0%, rgba(148,163,184,0.25) 100%);
}

.cat-row__content {
	position: relative;
	display: flex;
	justify-content: space-between;
	align-items: center;
}

.cat-row__name {
	color: var(--text-primary);
	font-size: 15px;
	font-weight: 500;
}
.cat-row__count {
	color: var(--text-secondary);
	font-size: 12px;
	margin-top: 2px;
}
.cat-row__amount {
	color: var(--text-primary);
	font-size: 15px;
	font-weight: 500;
	font-variant-numeric: tabular-nums;
}

/* Accordion — chevron + left cluster + nested sub-category indent.
   The left cluster keeps the chevron and the name/count block together so the
   amount stays pinned right. A leaf / child renders an EMPTY chevron span that
   still occupies its width, so top-level names line up whether or not the row
   expands. */
.cat-row__left {
	display: flex;
	align-items: center;
	gap: 8px;
	min-width: 0;
}
.cat-row__chevron {
	flex-shrink: 0;
	width: 20px;
	font-size: 20px;
	color: var(--text-secondary);
	transition: transform 0.15s ease;
}
/* Parent chevron points right when collapsed, rotates down when expanded. */
.cat-row--parent.is-expanded .cat-row__chevron {
	transform: rotate(90deg);
}
/* Sub-category rows are indented by their container (below), so they drop the
   chevron slot entirely and align under the parent's name. */
.cat-row--child .cat-row__chevron {
	display: none;
}

/* Parent + its sub-category container. The container indents with a left rule
   so the nesting reads clearly; collapsed via the global .hidden when closed. */
.cat-group {
	margin-bottom: 4px;
}
.cat-children {
	margin-left: 18px;
	padding-left: 10px;
	border-left: 2px solid var(--border);
}

/* Category transactions slideout — unactualized (forecast) rows are loaded but
   hidden until the forecast toggle (#cattxn-forecast-btn) reveals them,
   mirroring the Jar Ledger. The class sits on each row now (not the section);
   revealed rows show muted + italic so they read as projected, not settled.
   The class is toggled on the panel that contains the button, so it works at
   any stack depth. */
.slideout-panel .category-forecast { display: none; }
.slideout-panel.show-forecast .category-forecast {
	display: grid;
	opacity: 0.55;
	font-style: italic;
}

/* Net line under the Expense + Income sections — bold, right-aligned with the
   "Net" label sitting 20px left of the signed amount (no divider). */
.category-net-row {
	display: flex;
	align-items: center;
	justify-content: flex-end;
	gap: 20px;
	padding: 12px 0 4px;
	margin-top: 20px;
	font-weight: 600;
	font-size: 15px;
}
.category-net-label  { color: var(--text-secondary); }
.category-net-amount { color: var(--text-primary); }

/* Category path heading the Transactions body — sits at the top of the
   scrollable body (inherits the body's h-padding), decent size + weight. */
.cattxn-subtitle {
	font-size: 18px;
	font-weight: 600;
	color: var(--text-primary);
	margin-bottom: 16px;
}

/* ========== RECEIPT / ATTACHMENTS ========== */

/* Receipt section block — sits in the form flow on the Transaction
   slideout (after Notes) and above the split cards on the Split slideout.
   The whole block is a labeled group; spacing matches form-group rhythm. */
.receipt-section {
	margin-top: 16px;
	margin-bottom: 16px;
	/* Flex column with a uniform 6px gap — matches the inter-item gap inside
	   .receipt-list, so the dropzone sits the same distance from the first
	   attachment as the attachments sit from each other. */
	display: flex;
	flex-direction: column;
	gap: 6px;
}
/* The gap owns the spacing now — zero out the child margins that would
   otherwise stack on top of it. Scoped to direct children so the read-only
   Receipt List slideout (a bare .receipt-list, no .receipt-section) is
   unaffected. */
.receipt-section > .receipt-label { margin-bottom: 0; }
.receipt-section > .receipt-list { margin-top: 0; }
/* An empty saved/pending list must not consume a flex gap before any file
   exists — collapse it entirely until it has rows. */
.receipt-section > .receipt-list:empty { display: none; }

.receipt-label {
	display: block;
	margin-bottom: 6px;
	color: var(--text-secondary);
	font-size: 13px;
}

/* "+ Add Attachment" affordance — dashed box matching .add-btn so the upload
   target reads as the same kind of "add an item" affordance the rest of
   the app uses. (Click opens the file picker — there is no drag-and-drop.) */
.receipt-dropzone {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	padding: 7px 8px;
	background: var(--bg-main);
	border: 1px dashed var(--border);
	border-radius: 4px;
	color: var(--text-muted);
	font-size: 13px;
	cursor: pointer;
	transition: all 0.15s;
}
.receipt-dropzone:hover {
	border-color: var(--accent-blue);
	color: var(--text-primary);
}

/* Add-mode placeholder — small italic hint when there's no Ledger.ID yet. */
.receipt-hint {
	padding: 10px 12px;
	background: var(--bg-main);
	border: 1px dashed var(--border);
	border-radius: 6px;
	color: var(--text-tertiary);
	font-size: 12px;
	font-style: italic;
}

/* List of uploaded receipts under the drop zone — each row is a thumb,
   filename + size, and a delete X. */
.receipt-list {
	margin-top: 10px;
	display: flex;
	flex-direction: column;
	gap: 6px;
}

.receipt-item {
	display: grid;
	grid-template-columns: 22px 1fr auto;
	align-items: center;
	gap: 8px;
	padding: 7px 8px;
	background: var(--bg-input);
	border: 1px solid var(--border-soft);
	border-radius: 4px;
	cursor: pointer;
	transition: background 0.15s;
}
.receipt-item:hover {
	background: var(--bg-row-hover);
}

.receipt-thumb-link {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 22px;
	height: 22px;
}

.receipt-icon {
	font-size: 16px;
	color: var(--text-muted);
}

/* Filename + size sit on the same line — size in italic to the right. */
.receipt-meta {
	display: flex;
	flex-direction: row;
	align-items: baseline;
	gap: 6px;
	min-width: 0;
}

.receipt-name {
	color: var(--text-primary);
	font-size: 12px;
	text-decoration: none;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.receipt-size {
	color: var(--text-tertiary);
	font-size: 11px;
	font-style: italic;
}

.receipt-delete {
	background: transparent;
	border: none;
	color: var(--text-muted);
	font-size: 18px;
	line-height: 1;
	width: 22px;
	height: 22px;
	border-radius: 4px;
	cursor: pointer;
	transition: all 0.15s;
}
.receipt-delete:hover {
	background: var(--danger-bg);
	color: var(--danger-text);
}

/* ===== Hamburger button + mobile drawer ============================ */

/* ============================================================
   Jar Ledger drill view — inline replacement of the jar grid
   inside #refresh-container-jars. Toolbar + table styles
   previously lived in Slideout_Jar_Ledger.template's <style>
   block; lifted here since the slideout is gone.
   ============================================================ */


/* Drill view's back arrow now lives in the canvas's OTHER slot. Style it
   like a square neutral button (matches .header-icon-btn / .action-btn
   aesthetic). Kept compact so the title gets the room. */
.jarledger-back-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 32px;
	height: 32px;
	border: 1px solid var(--border);
	border-radius: 6px;
	background: transparent;
	color: var(--text-secondary);
	cursor: pointer;
	transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
	padding: 0;
}
.jarledger-back-btn:hover {
	background: var(--bg-hover);
	color: var(--accent-blue);
	border-color: var(--accent-blue);
}
.jarledger-back-btn .material-symbols-outlined {
	font-size: 20px;
}

/* Search input in the drill view's WIDGETS slot — sized to fit the
   placeholder without stretching out the cluster on desktop. Mobile
   override in responsive.css lets it grow to fill the remaining row. */
.jarledger-search-input {
	width: 200px;
}

/* Jar name header — sits between the year strip and the table so the user
   always knows which jar's ledger they're looking at. Inherits canvas-body
   h-padding; only v-padding here. */
.jarledger-jarname {
	font-size: 18px;
	font-weight: 700;
	color: var(--text-primary);
	padding: 16px 0 0;
}

/* Epoch year navigation — horizontal scroll. Inherits canvas-body h-padding;
   only v-padding here so the pill row doesn't sit right under the toolbar
   border. */
.jarledger-years {
	display: flex;
	gap: 8px;
	padding: 12px 0 8px;
	overflow-x: auto;
	white-space: nowrap;
}
/* Collapse the years row entirely when empty (no Epoch rows). */
.jarledger-years:empty {
	display: none;
}
/* Epoch-period pill. Self-contained (the old `btn btn-default` shape came from
   Bootstrap's base `.btn`, which is gone) — filled rounded pill, 14px radius. */
.jarledger-year-btn {
	flex-shrink: 0;
	background: var(--border);
	color: var(--text-primary);
	border: 1px solid var(--border-hover);
	border-radius: 14px;
	padding: 4px 12px;
	font-size: 12px;
	cursor: pointer;
	white-space: nowrap;
	transition: background 0.1s, border-color 0.1s;
}
.jarledger-year-btn:hover {
	background: var(--bg-hover);
	border-color: var(--border-focus);
}

/* Pull the slideout-body's 20px top padding INSIDE the scrollable content
   so it scrolls away with the rows. Otherwise the sticky tablehead pins at
   `top: 0` of the scroll port's content edge (below the padding), leaving
   a 20px strip above the sticky where scrolling rows are visible — the
   "header is bleeding" look. With padding-top moved to .jar-drill-active,
   the sticky pins flush at the slideout-body's true top edge. */
.slideout-body:has(.jar-drill-active) {
	padding-top: 0;
}
.jar-drill-active {
	padding-top: 20px;
}

/* Master grid — six tracks: Date | Description | Type | Deposit |
   Withdrawal | Balance. Description gets `1fr` to absorb leftover
   space; everything else sizes to content. H-padding comes from
   .canvas-body — same single source of truth as every other canvas. */
.jarledger-table {
	display: grid;
	grid-template-columns: auto 1fr auto auto auto auto;
	column-gap: 16px;
}

/* Each row is a grid item that spans all 6 columns AND uses subgrid
   so its children land in the same column tracks as every other row.
   This is what makes columns line up like a real table. */
.jarledger-tablehead,
.jarledger-row {
	display: grid;
	grid-column: 1 / -1;
	grid-template-columns: subgrid;
	align-items: center;
}

/* Sticky header row — pins to the top of .canvas-body's scroll area so the
   column labels stay visible while scrolling. No toolbar above it anymore
   (canvas .canvas-header sits OUTSIDE .canvas-body), so top: 0 is correct. */
.jarledger-tablehead {
	position: sticky;
	top: 0;
	z-index: 2;
	background-color: var(--bg-main);
	font-size: 11px;
	font-weight: 400;
	color: var(--text-secondary);
	text-transform: uppercase;
	letter-spacing: 0.04em;
	border-bottom: 1px solid var(--border);
}
.jarledger-tablehead > div {
	padding: 22px 0 14px;
}

/* Data row — vertical padding lives on the cells (row-level padding
   would disturb subgrid track alignment). Bottom separator is on the
   row element so it spans column gaps as a single line. */
.jarledger-row {
	border-bottom: 0.5px solid var(--border);
}
.jarledger-row > div {
	padding: 9px 0;
}
.jarledger-row.clickable {
	cursor: pointer;
}
.jarledger-row:hover {
	background: var(--bg-hover);
}

/* Per-column styling — every column inherits the row's font/size/weight/
   color so the table reads uniformly. Only differences: description
   allows wrap + overflow handling, numeric columns right-align. */
.jarledger-col-date,
.jarledger-col-type,
.jarledger-col-deposit,
.jarledger-col-withdrawal,
.jarledger-col-balance {
	white-space: nowrap;
}
.jarledger-col-note {
	min-width: 0;
	overflow: hidden;
}
.jarledger-col-deposit,
.jarledger-col-withdrawal,
.jarledger-col-balance {
	text-align: right;
}

/* Tiny right-pad on the category text so tag dots / split markers
   don't butt up against the category label. */
.jarledger-cat-text {
	padding-right: 10px;
}

/* Green / red on the change-amount column spans (Deposit / Withdrawal) —
   themed via accent vars so each theme can dial the saturation. */
.ledger-positive { color: var(--accent-green); }
.ledger-negative { color: var(--accent-red); }

/* Running balance is informational, not signal — keep it muted regardless
   of sign so the eye stays on the change amount above it. Overrides the
   .ledger-positive / .ledger-negative tint when the span is inside the
   balance column. */
.jarledger-col-balance .ledger-positive,
.jarledger-col-balance .ledger-negative {
	color: var(--text-tertiary);
}

/* Search filter — rows that don't match the typed query get this class
   from filterJarLedger() / filterTagResults(). Class-based hide instead
   of inline style so the row's `display: grid` rule (and the forecast-row
   hide rule below) stay authoritative when the search clears. */
.jarledger-row.search-hidden,
.expense-row.search-hidden {
	display: none;
}

/* Forecast rows — future-dated Ledger or synthetic Budget projections.
   Hidden by default; .show-forecast on the table reveals them muted +
   italic so they're visually distinct from settled actuals. */
.jarledger-table .forecast-row {
	display: none;
}
.jarledger-table.show-forecast .forecast-row {
	display: grid;
	opacity: 0.55;
	font-style: italic;
}
/* Active toggle button — pressed/lit look so the user can see at a
   glance whether forecast is currently on. */
#jarledger-forecast-btn.active {
	background: var(--bg-hover);
	border-color: var(--border-focus);
	color: #e8ebf0;
}

/* Empty state. */
.jarledger-empty {
	padding: 40px;
	text-align: center;
	color: var(--text-secondary);
}

/* ============================================================ */
/* Jar Performance slideout — per-period movement table          */
/* (Period | In | Out | Closing | Change). Mirrors the jar        */
/* ledger's subgrid table so columns size to content and line up. */
/* ============================================================ */

/* Jar name header — matches the ledger's body header. */
.jarperf-jarname {
	font-size: 18px;
	font-weight: 700;
	color: var(--text-primary);
	padding: 16px 0 2px;
}
.jarperf-sub {
	font-size: 12px;
	color: var(--text-secondary);
	padding: 0 0 8px;
}

/* One grid wraps the header + every row; rows use subgrid so all five
   column tracks line up like a real table with no fixed widths. */
.jarperf-table {
	display: grid;
	grid-template-columns: 1fr auto auto auto auto;
	column-gap: 16px;
}
.jarperf-tablehead,
.jarperf-row {
	display: grid;
	grid-column: 1 / -1;
	grid-template-columns: subgrid;
	align-items: center;
}

/* Sticky header — pins to the top of the slideout-body scroll area. */
.jarperf-tablehead {
	position: sticky;
	top: 0;
	z-index: 1;
	background: var(--bg-main);
	font-size: 11px;
	font-weight: 400;
	color: var(--text-secondary);
	text-transform: uppercase;
	letter-spacing: 0.04em;
	border-bottom: 1px solid var(--border);
}
.jarperf-tablehead > div {
	padding: 22px 0 14px;
}

/* Data row — bottom separator on the row element so it spans the column
   gaps as one continuous line; v-padding lives on the cells. */
.jarperf-row {
	border-bottom: 0.5px solid var(--border);
	font-size: 13px;
}
.jarperf-row > div {
	padding: 10px 0;
}
.jarperf-row:hover {
	background: var(--bg-hover);
}

/* Period left-aligned; the four numeric columns right-aligned. */
.jarperf-col-period {
	white-space: nowrap;
	color: var(--text-primary);
}
.jarperf-col-in,
.jarperf-col-out,
.jarperf-col-closing,
.jarperf-col-delta {
	text-align: right;
	white-space: nowrap;
}

/* Totals footer — bolder, a heavier top rule to separate it from the period
   rows, and no hover (it's a summary, not a selectable row). */
.jarperf-foot {
	font-weight: 600;
	border-top: 1px solid var(--border);
	border-bottom: 0;
}
.jarperf-foot:hover {
	background: transparent;
}
.jarperf-foot .jarperf-col-period {
	text-transform: uppercase;
	font-size: 11px;
	letter-spacing: 0.04em;
	color: var(--text-secondary);
}

/* A flat $0.00 (no flow / no net change) reads as muted, not signal. */
.jarperf-zero { color: var(--text-tertiary); }

/* Empty state — spans the whole grid so the table chrome stays clean. */
.jarperf-empty {
	grid-column: 1 / -1;
	padding: 40px;
	text-align: center;
	color: var(--text-secondary);
}


/* ===================================================================
   Slideout-scoped styles — moved out of per-template <style> blocks.
   Browser-cached + greppable here; templates ship clean HTML only.
   =================================================================== */


/* --- Slideout_Databases (budget database manager) ---
   The LIST is a stack of clickable summary rows (.db-card.db-card-row) — tap one
   to open the Add/Edit Database form slideout (showDatabaseForm). Mirrors the
   Account Setup list. The stat tiles / meta rows / action buttons below are used
   by the FORM (D_Slideout_Database.php), not the list. Own db-* classes
   (deliberately NOT the account-* ones). */
.db-list {
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.db-card {
	background: var(--bg-input);
	border: 1px solid var(--border);
	border-radius: 8px;
	overflow: hidden;
	transition: background 0.15s;
}
.db-card:hover { background: var(--bg-hover); }

/* "Active" pill on the active database's row in the list (D_Slideout_Databases).
   Sits next to the name, marks which budget is currently selected. Matches the
   primary action button's colour for visual consistency. */
.db-active-pill {
	display: inline-block;
	padding: 1px 8px;
	border-radius: 10px;
	background: var(--btn-primary);
	color: #ffffff;
	font-size: 10px;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	flex-shrink: 0;
}

/* "Make Active" button on the edit form for a non-active budget. Full-width
   primary action that switches the active budget (full reload after). Sits at
   the bottom of the body, under the stats + meta. Centered icon + label. */
.db-make-active {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 6px;
	width: 100%;
	margin-top: 50px;
}

/* Clickable summary row — main info (flex) + a static "opens" chevron. The
   whole card is the click target → showDatabaseForm(id). */
.db-card-row {
	display: flex;
	align-items: center;
	padding: 12px 14px;
	cursor: pointer;
	gap: 10px;
}
.db-chevron {
	color: var(--text-muted);
	font-size: 20px;
	flex-shrink: 0;
}
.db-card-main {
	flex: 1;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 4px;
}
.db-name-line {
	display: flex;
	align-items: center;
	gap: 8px;
	min-width: 0;
}
.db-name {
	color: var(--text-primary);
	font-size: 15px;
	font-weight: 500;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
/* Muted file subtitle under the name on each list row. */
.db-card-sub {
	color: var(--text-muted);
	font-size: 12px;
	font-variant-numeric: tabular-nums;
}

/* Wraps the read-only edit-mode details block (stats + file + created +
   optional Make Active button). Gap below it pushes the editable form fields
   that follow down by 40px so the two sections read as distinct. */
.db-edit-details {
	margin-bottom: 30px;
}

/* Stat tiles + meta rows + action row below are used by the Database FORM
   (D_Slideout_Database.php), rendered directly in its slideout body. */
.db-row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	padding: 10px 0;
	border-bottom: 1px solid var(--border);
}
.db-row:last-child { border-bottom: none; }
.db-row-label { color: var(--text-secondary); font-size: 13px; }
.db-meta { color: var(--text-muted); font-size: 13px; font-variant-numeric: tabular-nums; }

/* Stat tiles — Ledger / Categories / Recurring / Tags counts, four across. */
.db-stats {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: 8px;
	padding: 12px 0;
	border-bottom: 1px solid var(--border);
}
.db-stat {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 2px;
	min-width: 0;
}
.db-stat-value {
	font-size: 16px;
	font-weight: 700;
	color: var(--text-primary);
	font-variant-numeric: tabular-nums;
}
.db-stat-label {
	font-size: 10px;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	color: var(--text-muted);
	text-align: center;
}
/* Shown instead of stats for a blank (schema-less) budget. */
.db-blank-note {
	padding: 10px 0;
	border-bottom: 1px solid var(--border);
	font-size: 13px;
	font-style: italic;
	color: var(--text-muted);
}


/* --- Slideout_Help (index + topic) --- */
/* Index — clickable topic rows. Same neutral card aesthetic as the other
   slideout lists: accent icon left, title fills, chevron right. */
.help-index {
	display: flex;
	flex-direction: column;
	gap: 6px;
}
.help-index-item {
	display: flex;
	align-items: center;
	gap: 12px;
	width: 100%;
	padding: 12px 14px;
	background: var(--bg-input);
	border: 1px solid var(--border);
	border-radius: 6px;
	color: var(--text-primary);
	font-size: 14px;
	text-align: left;
	cursor: pointer;
	transition: background 0.15s, border-color 0.15s;
}
.help-index-item:hover {
	background: var(--bg-hover);
	border-color: var(--accent-blue);
}
.help-index-item-icon {
	color: var(--accent-blue);
	font-size: 20px;
}
.help-index-item-title {
	flex: 1;
}
.help-index-item-chevron {
	color: var(--text-tertiary);
	font-size: 20px;
}

/* Topic — long-form help copy authored as plain .html fragments. Tighten the
   heading / paragraph / list rhythm so pages read like documentation. */
.help-content {
	font-size: 14px;
	line-height: 1.6;
	color: var(--text-primary);
}
.help-content h2 {
	font-size: 18px;
	margin: 4px 0 10px;
	color: var(--text-primary);
}
.help-content h3 {
	font-size: 15px;
	margin: 20px 0 8px;
	color: var(--text-primary);
}
.help-content p {
	margin: 0 0 12px;
	color: var(--text-secondary);
}
.help-content ul,
.help-content ol {
	margin: 0 0 12px;
	padding-left: 20px;
	color: var(--text-secondary);
}
.help-content li {
	margin-bottom: 6px;
}
.help-content strong {
	color: var(--text-primary);
}
.help-content code {
	font-family: monospace;
	font-size: 12px;
	background: var(--bg-darker);
	padding: 2px 5px;
	border-radius: 4px;
}


/* --- Slideout_Recurring_Item --- */
.end-options {
	margin-top: 10px;
}

/* Read-only Type value shown in edit mode (the toggle is hidden — Type isn't
   editable once a recurring item / category is created; see the WHY in the
   templates). Shared by the Recurring-Item and Category forms. */
.recurring-type-static,
.category-type-static {
	font-size: 14px;
	font-weight: 600;
	color: var(--text-primary);
}

/* Locked schedule fields in edit mode — the not-allowed cursor on hover makes
   it obvious they're disabled (paired with the info icon explaining why). */
#slideout-recurring-startdate:disabled,
#slideout-recurring-frequency:disabled {
	cursor: not-allowed;
}


/* --- Slideout_Tag_Manager (View by Tag — multi-select picker) --- */
/* Negative h-margin so each row's border-bottom spans the full width of
   .slideout-body (which provides 20px h-padding). Same rules used by
   Slideout_Picker_Tag — single source of truth. */
.tag-picker-row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 10px 20px;
	margin: 0 -20px;
	border-bottom: 1px solid var(--border);
	cursor: pointer;
}
.tag-picker-row:hover {
	background: var(--bg-hover);
}
.tag-picker-check {
	color: var(--accent-blue);
	opacity: 0;
	transition: opacity 0.15s;
}
.tag-picker-row.tag-picker-selected .tag-picker-check {
	opacity: 1;
}
.tag-picker-empty {
	padding: 24px;
	text-align: center;
	color: var(--text-muted);
}


/* --- Slideout_Tag_Manager_Edit (Edit Tags — pill list with chevrons) --- */
.tag-manager-row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 10px 20px;
	margin: 0 -20px;
	border-bottom: 1px solid var(--border);
	cursor: pointer;
}
.tag-manager-row:hover {
	background: var(--bg-hover);
}
.tag-manager-edit-icon {
	color: var(--text-muted);
	font-size: 1.2em;
}
.tag-manager-empty {
	padding: 24px;
	text-align: center;
	color: var(--text-muted);
}


/* --- Slideout_Tag (single-tag editor — color pickers + preview) --- */
/* Hide all native color pickers — triggered via eyedropper icon */
#tag-color-picker,
#tag-fontcolor-picker,
#tag-rowcolor-picker {
	position: absolute;
	width: 0;
	height: 0;
	opacity: 0;
	pointer-events: none;
}
/* Wrapper positions eyedropper icon inside the text field */
.color-input-wrap {
	position: relative;
	display: flex;
	align-items: center;
}
/* Hex text input — monospace, room for the random + eyedropper icons on the right */
.color-hex-input {
	width: 100%;
	font-family: monospace;
	padding-right: 52px;
}
/* Eyedropper (right) + random-colour dice (left of it) — both inside the input's
   right edge. */
.color-eyedropper-btn,
.color-random-btn {
	position: absolute;
	font-size: 1.1em;
	color: var(--text-muted);
	cursor: pointer;
	user-select: none;
}
.color-eyedropper-btn { right: 6px; }
.color-random-btn     { right: 30px; }
.color-eyedropper-btn:hover,
.color-random-btn:hover {
	color: var(--text-primary);
}
/* Tag preview — a REAL budget .expense-row (see Slideout_Tag.template) inside a
   bordered field, so it looks exactly like a tagged row in the budget panel. */
.tag-preview-wrap {
	border: 1px solid var(--border);
	border-radius: 4px;
	overflow: hidden;
}
/* The preview row isn't interactive — drop the budget-row hover/cursor. (The
   row tint is set inline by updateRowColor, which beats this hover rule anyway.)
   It also always uses the STACKED mobile layout (date on top) regardless of
   viewport, because the slideout is narrow — mirrors responsive.css's mobile
   .expense-row rules, scoped here so they apply on desktop too. */
.tag-preview-wrap .expense-row {
	cursor: default;
	grid-template-columns: 1fr auto;
	grid-template-areas:
		"date   date"
		"name   amount"
		"label  label"
		"tags   tags";
	row-gap: 2px;
}
.tag-preview-wrap .expense-row:hover {
	background: transparent;
}
.tag-preview-wrap .expense-merchant-cell  { display: contents; }
.tag-preview-wrap .budget-date-column     { grid-area: date; font-size: 11px; color: var(--text-muted); }
.tag-preview-wrap .expense-merchant-name  { grid-area: name; }
.tag-preview-wrap .expense-category-label { grid-area: label; }
/* Tags line holds both forms: the dot (left) and the full pill (right). */
.tag-preview-wrap .expense-tags-line {
	grid-area: tags;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
}
.tag-preview-wrap .expense-amount         { grid-area: amount; align-self: start; }


/* --- Slideout_Merge (merge resolution UI) --- */
/* Result preview card */
.merge-body .preview {
	background: var(--bg-darker, #1c2030);
	border: 0.5px solid var(--border, #2a2e3a);
	border-radius: 8px;
	padding: 12px 14px;
	margin-bottom: 14px;
}
.merge-body .preview__label {
	font-size: 10px;
	text-transform: uppercase;
	letter-spacing: 0.8px;
	color: var(--text-muted, #6b7180);
	margin-bottom: 8px;
	font-weight: 500;
}
.merge-body .preview__row {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	margin-bottom: 4px;
}
.merge-body .preview__date   { font-size: 13px; color: var(--text-secondary, #a4abbb); }
.merge-body .preview__amount { font-size: 16px; font-weight: 500; }
.merge-body .preview__notes  { font-size: 14px; margin-bottom: 8px; }
.merge-body .preview__tags   { display: flex; gap: 6px; flex-wrap: wrap; }
.merge-body .preview .tag {
	font-size: 11px;
	padding: 2px 8px;
	border-radius: 4px;
	background: #252a38;
	color: var(--text-secondary, #a4abbb);
}
.merge-body .preview .tag:empty { display: none; }

/* Summary strip */
.merge-body .summary {
	display: flex;
	gap: 10px;
	align-items: center;
	margin-bottom: 4px;
	padding: 6px 10px;
	background: #1a1d28;
	border-radius: 6px;
	font-size: 12px;
	color: var(--text-secondary, #a4abbb);
}
.merge-body .summary__num { color: var(--accent-blue, #4a9eff); font-weight: 500; }
.merge-body .summary__sep { color: #3a3f4d; }

/* Field row */
.merge-body .field {
	display: flex;
	align-items: flex-start;
	gap: 10px;
	padding: 11px 0;
	border-top: 0.5px solid #232734;
}
.merge-body .field:first-of-type { border-top: 0; }
.merge-body .field__label {
	flex: 0 0 84px;
	font-size: 13px;
	padding-top: 7px;
	display: flex;
	align-items: center;
	gap: 6px;
}
.merge-body .field__label--resolved { color: var(--text-muted, #6b7180); }
.merge-body .field__label--conflict { color: var(--text-primary, #e6e8eb); font-weight: 500; }
.merge-body .field__dot {
	width: 6px; height: 6px;
	border-radius: 50%;
	background: var(--accent-blue, #4a9eff);
	flex-shrink: 0;
}
.merge-body .field__value {
	flex: 1;
	font-size: 14px;
	padding-top: 7px;
	display: flex;
	align-items: baseline;
	gap: 8px;
	flex-wrap: wrap;
	min-width: 0;
	word-break: break-word;
}
.merge-body .field__value--empty { color: #565b6b; font-style: italic; }
.merge-body .field__source {
	font-size: 10px;
	color: #565b6b;
	text-transform: uppercase;
	letter-spacing: 0.5px;
}
.merge-body .field__options { flex: 1; min-width: 0; }

/* Segmented control */
.merge-body .segmented {
	display: inline-flex;
	background: #1a1d28;
	border: 0.5px solid var(--border, #2a2e3a);
	border-radius: 8px;
	padding: 3px;
	gap: 2px;
	max-width: 100%;
}
.merge-body .segmented--stack {
	display: flex;
	flex-direction: column;
	width: 100%;
}
.merge-body .segmented__opt {
	font-size: 13px;
	padding: 6px 11px;
	border-radius: 6px;
	cursor: pointer;
	color: var(--text-secondary, #a4abbb);
	background: transparent;
	border: 0;
	font-family: inherit;
	text-align: left;
	transition: background 0.12s, color 0.12s;
}
.merge-body .segmented__opt:hover { color: var(--text-primary, #e6e8eb); }
.merge-body .segmented__opt--selected {
	background: var(--accent-blue, #2563d6);
	color: #fff;
	font-weight: 500;
}
.merge-body .segmented__opt-source {
	display: block;
	font-size: 10px;
	opacity: 0.7;
	margin-top: 2px;
	font-weight: 400;
	text-transform: uppercase;
	letter-spacing: 0.4px;
}


/* --- Slideout_Payment_Items (covered-items list) --- */
/* Override actualized row styling — covered list shows all rows full-strength */
.tag-results-body .verified-row,
.tag-results-body .unverified-row {
	border-left: none !important;
	opacity: 1 !important;
}
/* Space between each section (Payment / Refunds / Expenses). Applied to the
   table so the next section's header sits at a comfortable distance.
   :last-of-type strips the trailing gap. */
.tag-results-body .section-header + .expense-table {
	margin-bottom: 40px;
}
.tag-results-body .expense-table:last-of-type {
	margin-bottom: 0;
}


/* --- Slideout_Groups (group manager — add new group row) --- */
.group-manager-add-row {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 6px;
	/* 6px vertical padding matches .group-manager-name's 6px so the Add row is
	   the same height as the group rows below it. */
	padding: 6px 0;
	border: 1px dashed var(--border-hover);
	border-radius: 6px;
	color: var(--text-muted);
	cursor: pointer;
	transition: all 0.15s ease;
}
.group-manager-add-row:hover {
	border-color: var(--border-focus);
	color: #e8ebf0;
	background: var(--bg-hover);
}


/* --- Slideout_Settings (key/value settings list) --- */
#settings-manager-list {
	padding: 8px 0;
}
/* Each row stacks: key (label) → description (muted) → value input. */
.settings-manager-row {
	display: flex;
	flex-direction: column;
	gap: 4px;
	padding: 12px 0;
	border-bottom: 1px solid var(--border);
}
.settings-manager-name {
	font-size: 14px;
	font-weight: 600;
	color: var(--text-primary);
}
/* Read-only rows: muted text + visible lock icon, disabled input keeps its native browser styling */
.settings-manager-readonly .settings-manager-name {
	color: var(--text-muted);
}
.settings-manager-lock {
	color: var(--text-muted);
	vertical-align: middle;
}
.settings-manager-desc {
	font-size: 11px;
	color: var(--text-muted);
	line-height: 1.4;
}
.settings-manager-value {
	margin-top: 4px;
}
