/* Finn — design tokens (Cosmic Audit revision, 2026-07-26)
   Source: Claude Design "Cosmic Audit" standalone. Space theme —
   navy control-deck sidebar, Finn the alien mascot, playful copy.
   Templates read these variables; if a value isn't here it doesn't
   exist — flag it rather than inventing one at the template level.
*/

:root {
  /* Color — cosmic palette */
  --bg: #F6F4EF;              /* page background */
  --surface: #FFFFFF;
  --border: #E4E0D8;          /* card / table hairlines */
  --text-primary: #2E3A46;
  --text-secondary: #6B7480;
  --accent: #5F7891;          /* cyan — primary action / active */
  --accent-text: #4A6079;     /* cyan pressed / hover */
  --mint: #93B181;            /* Finn's body, ticker accent */
  --mint-dark: #7A9A68;
  --warm: #F0BD6F;            /* semantic only: pending / needs-review */
  --warm-text: #B98A3A;       /* gold text on light surfaces */
  --danger: #C0564A;          /* voided, destructive */
  --positive: #4A9B6E;        /* reconciled — v2 */

  /* The mothership — navy control deck (sidebar) */
  --space-navy: #3E5064;
  --space-deep: #2F3D4C;
  --nav-muted: #B5C2CF;       /* inactive nav text on navy */
  --cosmic-line: rgba(95, 120, 145, 0.08);

  /* Type */
  --font-display: 'Raleway', sans-serif;   /* weight 700/800 */
  --font-body: 'Krub', sans-serif;
  --font-mono: 'IBM Plex Mono', monospace; /* every numeral in a data context — non-negotiable */

  --text-xs: 12px;
  --text-sm: 14px;
  --text-base: 16px;
  --text-lg: 20px;
  --text-xl: 28px;
  --text-2xl: 40px;

  /* Spacing — 8px base */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 16px;
  --space-4: 24px;
  --space-5: 32px;
  --space-6: 48px;
  --space-7: 56px;

  /* Shape */
  --radius: 8px;
  --radius-lg: 12px;          /* cards / tickers in the cosmic layer */
  --shadow-sm: 0 2px 8px rgba(20, 40, 60, 0.08);
  --shadow-hover: 0 6px 16px rgba(46, 58, 70, 0.10);

  /* Motion */
  --transition-fast: 0.15s ease;
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
  /* !important: the base .bar-reveal rule sits later in this file and would
     otherwise win on source order, leaving every bar collapsed at scaleX(0). */
  .bar-reveal { transform: none !important; }
}

/* Base */
body {
  margin: 0;
  background-color: var(--bg);
  position: relative;
  isolation: isolate;
  /* The page stays light; these fixed layers provide the space-frame around
     readable financial surfaces without adding a particle-heavy canvas. */
  background-image:
    radial-gradient(circle at 76% 12%, rgba(95, 120, 145, .13), transparent 24rem),
    radial-gradient(circle at 12% 88%, rgba(147, 177, 129, .1), transparent 28rem),
    linear-gradient(115deg, rgba(95, 120, 145, .035), transparent 38%, rgba(147, 177, 129, .045));
  background-attachment: fixed;
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: var(--text-sm);
}
body::before,
body::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: -1;
}
body::before {
  opacity: .58;
  background-image:
    radial-gradient(circle at 1px 1px, rgba(20, 40, 60, .16) 1px, transparent 1.5px),
    radial-gradient(circle at 1px 1px, rgba(95, 120, 145, .14) 1px, transparent 1.5px);
  background-position: 0 0, 37px 61px;
  background-size: 83px 83px, 127px 127px;
  mask-image: linear-gradient(135deg, black, transparent 48%, black);
}
body::after {
  inset: 24px 0 0 220px;
  opacity: .34;
  background:
    linear-gradient(115deg, transparent 0 42%, var(--cosmic-line) 42.1%, transparent 42.35%),
    linear-gradient(25deg, transparent 0 72%, rgba(147, 177, 129, .07) 72.1%, transparent 72.3%);
  border-radius: 36px 0 0 0;
}

h1, h2, h3 { font-family: var(--font-display); font-weight: 700; margin: 0; }
h1 { font-size: var(--text-xl); }
h2 { font-size: var(--text-lg); }

.mono { font-family: var(--font-mono); }

input:focus-visible, select:focus-visible, button:focus-visible, a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ── Cosmic animations ── */
@keyframes rowFade   { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
@keyframes pageIn    { from { opacity: 0; transform: translate3d(0, 8px, 0); } to { opacity: 1; transform: none; } }
@keyframes tickerUp  { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes barGrow   { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes twinkle   { 0%, 100% { opacity: 0.9; } 50% { opacity: 0.2; } }
@keyframes finnFloat { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-6px); } }
@keyframes finnBlink { 0%, 92%, 100% { transform: scaleY(1); } 95% { transform: scaleY(0.08); } }
@keyframes antennaGlow { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
@keyframes finnSuccess {
  0% { transform: rotate(0) translateY(0); }
  35% { transform: rotate(-5deg) translateY(-10px); }
  68% { transform: rotate(4deg) translateY(2px); }
  100% { transform: rotate(0) translateY(0); }
}
@keyframes finnWarning {
  0%, 100% { transform: rotate(0); filter: drop-shadow(0 8px 18px rgba(0, 0, 0, .35)); }
  50% { transform: rotate(-4deg) translateX(-2px); filter: drop-shadow(0 0 12px rgba(236, 189, 118, .72)); }
}
@keyframes finnError {
  0%, 100% { transform: translateX(0); }
  20%, 60% { transform: translateX(-5px) rotate(-2deg); }
  40%, 80% { transform: translateX(5px) rotate(2deg); }
}
@keyframes finnThinking {
  0%, 100% { opacity: .82; filter: drop-shadow(0 8px 18px rgba(0, 0, 0, .35)); }
  50% { opacity: 1; filter: drop-shadow(0 0 14px rgba(95, 120, 145, .78)); }
}
@keyframes bubblePop {
  from { opacity: 0; transform: translateY(6px) scale(.97); }
  to { opacity: 1; transform: none; }
}
@keyframes beamIn {
  from { opacity: 0; transform: translate3d(-12px, 0, 0); box-shadow: -28px 0 0 -26px var(--accent); }
  to { opacity: 1; transform: none; box-shadow: none; }
}
@keyframes importReveal {
  from { opacity: 0; transform: translateY(10px); clip-path: inset(0 0 100% 0); }
  to { opacity: 1; transform: none; clip-path: inset(0); }
}
@keyframes scanPulse {
  0%, 100% { border-color: var(--border); box-shadow: none; }
  50% { border-color: rgba(95, 120, 145, .7); box-shadow: 0 0 0 3px rgba(95, 120, 145, .08), 0 0 24px rgba(95, 120, 145, .1); }
}
@keyframes radarPulse {
  0%, 100% { opacity: .22; transform: scale(.96); }
  50% { opacity: .5; transform: scale(1); }
}

.row-fade    { animation: rowFade var(--transition-fast) both; }
.row-beam-in { animation: beamIn .38s cubic-bezier(.22, 1, .36, 1) both; }
.main        { animation: pageIn 0.28s ease both; }
.ticker-up   { animation: tickerUp 0.35s ease both; }
.count-up { font-variant-numeric: tabular-nums; }
.bar-reveal { transform: scaleX(0); transform-origin: left center; animation: barGrow .65s cubic-bezier(.22, 1, .36, 1) both; }

/* ── App shell (moved from base.html so templates stay markup-only) ── */
.shell { display: flex; min-height: 100vh; height: 100vh; overflow: hidden; }

.sidebar {
  width: 220px;
  flex: none;
  background:
    radial-gradient(circle at 18% 8%, rgba(95, 120, 145, .16), transparent 15rem),
    radial-gradient(circle at 90% 72%, rgba(147, 177, 129, .08), transparent 17rem),
    var(--space-navy);
  padding: 24px 20px;
  display: flex;
  flex-direction: column;
  gap: 28px;
  position: sticky;
  top: 0;
  align-self: flex-start;
  height: 100vh;
  overflow: hidden;
  isolation: isolate;
  box-shadow: 10px 0 32px rgba(46, 58, 70, .08);
}
.sidebar::before {
  content: "";
  position: absolute;
  width: 420px;
  height: 420px;
  right: -300px;
  top: 86px;
  border: 1px solid rgba(95, 120, 145, .16);
  border-radius: 50%;
  box-shadow: 0 0 0 22px rgba(95, 120, 145, .025), 0 0 0 76px rgba(147, 177, 129, .02);
  transform: rotate(-18deg);
  pointer-events: none;
  z-index: -1;
}
.sidebar > * { z-index: 1; }
.star {
  position: absolute;
  border-radius: 50%;
  background: #FFFFFF;
  animation: twinkle 4s ease-in-out infinite;
}
.sidebar-brand {
  display: flex; flex-direction: column; gap: 4px; position: relative;
  align-items: flex-start;
}
.sidebar-brand .brand-wordmark {
  display: block;
  width: 100%;
  max-width: 180px;
  height: auto;
}
.sidebar-brand .wordmark {
  font-family: var(--font-display); font-weight: 800; font-size: 20px;
  letter-spacing: 0.5px; color: #FFFFFF;
}
.sidebar-brand .wordmark span { color: var(--accent); }
.sidebar-brand .tagline { font-size: var(--text-xs); color: var(--nav-muted); }

.workspace-control {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px 12px;
  border: 1px solid rgba(95, 120, 145, .28);
  border-radius: 10px;
  background: rgba(95, 120, 145, .08);
}
.workspace-control__label {
  color: var(--nav-muted);
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.workspace-control__name {
  color: #FFFFFF;
  font-size: var(--text-sm);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.workspace-control__identity {
  color: var(--nav-muted);
  font-size: 10px;
}
.workspace-control__select {
  width: 100%;
  color: #FFFFFF;
  background: var(--space-navy);
  border: 1px solid rgba(255, 255, 255, .2);
  border-radius: 6px;
  padding: 5px 7px;
  font: 600 var(--text-sm) var(--font-body);
}

.nav-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  position: relative;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: thin;
}
.nav-group {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.nav-children {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 0 0 4px 12px;
  padding: 2px 0 2px 8px;
  border-left: 1px solid rgba(255, 255, 255, 0.1);
}
.nav-item {
  display: flex; align-items: center; gap: 8px;
  position: relative;
  font-size: var(--text-sm); font-weight: 500;
  color: var(--nav-muted); background: transparent;
  border: 1px solid transparent; border-radius: 10px;
  padding: 8px 12px; text-decoration: none;
  transition: background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
}
.nav-item::before {
  content: ""; position: absolute; left: -1px; top: 7px; bottom: 7px;
  width: 3px; border-radius: 3px; background: var(--accent);
  transform: scaleY(0); transform-origin: center;
  transition: transform 0.22s ease;
}
.nav-item:hover { border-color: var(--accent); color: #FFFFFF; }
.nav-item .nav-num { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--nav-muted); }
.nav-item.active {
  color: #FFFFFF; font-weight: 600;
  background: rgba(95, 120, 145, 0.12);
  border-color: rgba(95, 120, 145, 0.45);
}
.nav-item.active::before { transform: scaleY(1); }
.nav-item.active .nav-num { color: var(--accent); }
.nav-item--child {
  padding: 6px 10px;
  font-size: 13px;
  gap: 6px;
}
.nav-item--child .nav-num {
  font-size: 10px;
  min-width: 2.8em;
  flex-shrink: 0;
}
.nav-item .nav-badge {
  margin-left: auto; font-size: 10px; font-family: var(--font-mono);
  background: var(--warm); color: var(--space-navy);
  border-radius: 8px; padding: 1px 6px; line-height: 16px; font-weight: 600;
}
.nav-logout { margin: 0; }
.nav-button {
  width: 100%;
  font-family: var(--font-body);
  text-align: left;
  cursor: pointer;
}

.finn-dock { margin-top: auto; display: flex; flex-direction: column; gap: 12px; align-items: center; position: relative; }
.finn-bubble {
  background: #FFFFFF; border-radius: 12px; padding: 12px 14px;
  width: 100%; box-sizing: border-box; position: relative;
}
.finn-bubble .says { font-size: 11px; font-weight: 600; color: var(--accent); letter-spacing: 0.08em; }
.finn-bubble p { font-size: var(--text-sm); color: var(--text-primary); line-height: 1.5; margin: 4px 0 0; }
.finn-bubble.is-speaking,
.finn-fab-bubble.is-speaking { animation: bubblePop .24s ease both; }
.finn-bubble::after {
  content: ""; position: absolute; bottom: -6px; left: 50%;
  width: 12px; height: 12px; background: #FFFFFF; transform: translateX(-50%) rotate(45deg);
}
.finn-poke {
  background: transparent; border: none; cursor: pointer; padding: 0;
  animation: finnFloat 4s ease-in-out infinite;
  line-height: 0;
}
.finn-poke:hover { transform: scale(1.04); }
.finn-poke.is-success .finn-mascot,
.finn-fab-poke.is-success .finn-mascot { animation: finnSuccess .65s ease both; }
.finn-poke.is-warning .finn-mascot,
.finn-fab-poke.is-warning .finn-mascot { animation: finnWarning .9s ease-in-out 2 both; }
.finn-poke.is-error .finn-mascot,
.finn-fab-poke.is-error .finn-mascot { animation: finnError .46s ease both; }
.finn-poke.is-thinking .finn-mascot,
.finn-fab-poke.is-thinking .finn-mascot { animation: finnThinking 1s ease-in-out infinite; }
.finn-poke .finn-pose { display: none; }
.finn-poke .finn-pose--idle { display: block; }
.finn-poke:is(.is-success, .is-thinking, .is-warning, .is-error) .finn-pose--idle { display: none; }
.finn-poke.is-success .finn-pose--success,
.finn-poke.is-thinking .finn-pose--thinking,
.finn-poke:is(.is-warning, .is-error) .finn-pose--stern { display: block; }
.finn-mascot {
  display: block;
  width: auto;
  height: 208px;
  object-fit: contain;
  filter: drop-shadow(0 8px 18px rgba(0, 0, 0, 0.35));
}
.finn-mascot--fab {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  filter: none;
}

.nav-item--logout:hover {
  border-color: #e6495e;
  background: rgba(230, 73, 94, 0.12);
  color: #FFFFFF;
}
.nav-item--logout:hover .nav-num { color: #e6495e; }

.main {
  flex: 1; min-width: 0; padding: 32px clamp(24px, 4vw, 64px);
  display: flex; flex-direction: column; gap: 24px; max-width: none;
  overflow-y: auto;
  /* The panel itself still fills the viewport (full-bleed background), but its
     contents are capped. Without this, every space-between row and every
     flex:1 bar stretched to the monitor width, stranding a label at one edge
     and its value at the other. */
  height: 100vh;
  position: relative;
  isolation: isolate;
  border-left: 1px solid rgba(95, 120, 145, .08);
}
/* ── Width tiers ──────────────────────────────────────────────────────────
   Content types want opposite things. Dense tables read better wide; a
   label→value pair reads worse the wider it gets, because the eye has to
   track across dead space to connect a name to its number. So: three tiers,
   not one number. The panel itself stays full-bleed — only content is capped. */
.main {
  --w-wide: 1280px;   /* the ledger, where columns earn the room */
  --w-app: 1120px;    /* default for every page */
  --w-measure: 820px; /* label→value lists, regardless of monitor size */
  --content-max: var(--w-app);
}
.main--wide { --content-max: var(--w-wide); }
/* Applied again at the end of this file at higher specificity — see
   "content column" below. Any component using the `margin` shorthand would
   otherwise reset margin-inline and escape the column. */
/* Pair-based rows stay narrow even inside a full-width card. Capping the row
   rather than the section keeps every card edge and heading aligned down the
   page, while the name and its number stay close enough to read as a pair. */
/* Pair-based content is capped at the ROW, never at the card. Narrowing the
   cards themselves gave the page a zigzag right margin (1651, 1651, 1401,
   1401, 1651 ...) which reads as broken alignment — worse than the loose
   pairing it was meant to fix. Every card keeps the column's edges; the
   content inside packs left and stops at the measure width. */
.section-block--measure .breakdown-row,
.section-block--measure .leaderboard__row,
.section-block--measure .table-header,
.section-block--measure .table-row,
.section-block--measure .budget-row { max-width: var(--w-measure); }
.main::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: -1;
  opacity: .45;
  background-image:
    linear-gradient(var(--cosmic-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--cosmic-line) 1px, transparent 1px);
  background-size: 56px 56px;
  mask-image: linear-gradient(to bottom, black, transparent 72%);
}

/* Skip link — visible on keyboard focus only */
.skip-link {
  position: absolute;
  left: 12px;
  top: 12px;
  z-index: 1000;
  padding: 8px 14px;
  background: var(--accent);
  color: #FFFFFF;
  font-weight: 600;
  font-size: var(--text-sm);
  border-radius: var(--radius);
  text-decoration: none;
  /* -120% of its own height left ~5px poking out below top:12px. */
  transform: translateY(calc(-100% - 16px));
  transition: transform var(--transition-fast);
}
.skip-link:focus { transform: translateY(0); outline: 2px solid #FFFFFF; outline-offset: 2px; }

/* HTMX nav progress bar */
.htmx-progress {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 3px;
  z-index: 999;
  pointer-events: none;
  background: transparent;
  opacity: 0;
  transition: opacity .12s ease;
}
.htmx-progress.is-active { opacity: 1; }
.htmx-progress::after {
  content: "";
  display: block;
  height: 100%;
  width: 40%;
  background: linear-gradient(90deg, transparent, var(--mint) 32%, #FFFFFF 50%, var(--accent) 68%, transparent);
  box-shadow: 0 0 12px rgba(95, 120, 145, .8), 0 0 24px rgba(147, 177, 129, .35);
  animation: htmxSweep 0.9s ease-in-out infinite;
}
@keyframes htmxSweep {
  from { transform: translateX(-100%); }
  to   { transform: translateX(280%); }
}

/* Toast notifications (aria-live host in base.html) */
.toast-host {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-width: min(360px, calc(100vw - 32px));
  pointer-events: none;
}
.toast {
  pointer-events: auto;
  padding: 12px 14px;
  background: var(--space-navy);
  color: #FFFFFF;
  border-radius: var(--radius-lg);
  border: 1px solid rgba(95, 120, 145, 0.35);
  box-shadow: var(--shadow-hover);
  font-size: var(--text-sm);
  line-height: 1.4;
  animation: toastIn 0.22s ease both;
}
.toast--error {
  border-color: rgba(192, 86, 74, 0.55);
  background: #2a1820;
}
.toast--ok {
  border-color: rgba(147, 177, 129, 0.45);
}
@keyframes toastIn {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

/* Page chrome helpers */
.page-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 4px;
}
.page-header__title { display: flex; flex-direction: column; gap: 4px; }
.page-header__title h1 { margin: 0; }
.page-header__sub { font-size: var(--text-xs); color: var(--text-secondary); }
.page-header__actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.page-meta { font-size: var(--text-xs); color: var(--text-secondary); }
.page-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 16px;
  flex-wrap: wrap;
  gap: 8px;
}
.txn-context {
  margin-top: 8px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.empty-state { padding: 48px 24px; text-align: center; }
.empty-state p { margin: 0; }
.empty-state p + p { margin-top: 8px; }
.finn-empty { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.empty-state__finn {
  width: auto;
  height: 120px;
  object-fit: contain;
  filter: drop-shadow(0 8px 14px rgba(46, 58, 70, .18));
  animation: finnFloat 4s ease-in-out infinite;
}
.finn-empty__signal {
  color: var(--accent-text);
  font: 600 10px var(--font-mono);
  letter-spacing: .12em;
  text-transform: uppercase;
}
.milestone-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin: 2px 0 20px;
  padding: 6px 10px;
  color: var(--positive);
  background: rgba(74, 155, 110, .08);
  border: 1px solid rgba(74, 155, 110, .25);
  border-radius: 999px;
  font-size: var(--text-xs);
  animation: tickerUp .35s ease both;
}
.milestone-chip::before { content: "✓"; font-weight: 700; }

/* Collapsible filter panel on Transactions */
.filter-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.filter-toggle .filter-count {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  padding: 1px 6px;
  border-radius: 8px;
  background: rgba(95, 120, 145, 0.15);
  color: var(--accent-text);
}
.filter-panel[hidden] { display: none !important; }
/* Flat on purpose: the controls carry their own outlines, and a card around
   them was one more box on a page that already has plenty. */
.filter-panel { margin-bottom: var(--space-3); }

/* Internal scroll ledger — ~10 rows visible; page body stays put */
.table-scroll {
  max-height: 560px;
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-width: thin;
}
.table-scroll .table-header {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--surface);
  box-shadow: 0 1px 0 var(--border);
}
#txn-table { overflow: hidden; }


/* Mobile Finn FAB — reachable when sidebar dock is hidden */
.finn-fab {
  display: none;
  position: fixed;
  right: 14px;
  bottom: 14px;
  z-index: 40;
  align-items: flex-end;
  gap: 8px;
  flex-direction: column;
  max-width: min(280px, calc(100vw - 28px));
  pointer-events: none;
}
.finn-fab .finn-fab-bubble {
  pointer-events: none;
  background: #FFFFFF;
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 10px 12px;
  box-shadow: var(--shadow-hover);
  font-size: var(--text-sm);
  color: var(--text-primary);
  line-height: 1.4;
}
.finn-fab .finn-fab-bubble[hidden] { display: none !important; }
.finn-fab .finn-fab-poke {
  pointer-events: auto;
  align-self: flex-end;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  border: 2px solid rgba(95, 120, 145, 0.45);
  background: var(--space-navy);
  box-shadow: var(--shadow-hover);
  cursor: pointer;
  display: grid;
  place-items: center;
  padding: 0;
  overflow: hidden;
}
.finn-fab .finn-fab-poke.is-success .finn-mascot--fab,
.finn-fab .finn-fab-poke.is-warning .finn-mascot--fab,
.finn-fab .finn-fab-poke.is-error .finn-mascot--fab,
.finn-fab .finn-fab-poke.is-thinking .finn-mascot--fab { filter: none; }

@media (max-width: 640px) {
  .shell { flex-direction: column; height: auto; min-height: 100vh; overflow: visible; }
  .sidebar {
    /* No global border-box reset in this sheet, so width:100% + padding
       overflowed the viewport and scrolled the whole page sideways. */
    width: 100%; box-sizing: border-box;
    flex-direction: column; align-items: stretch;
    padding: 12px 14px; gap: 10px;
    position: relative; height: auto;
  }
  .sidebar-brand { flex-direction: row; align-items: center; gap: 8px; }
  .sidebar-brand .brand-wordmark {
    width: auto;
    height: 48px;
  }
  .sidebar-brand .tagline { display: none; }
  .workspace-control {
    min-width: 180px;
    padding: 7px 10px;
  }
  .workspace-control__identity { display: none; }
  .nav-list {
    flex-direction: row; flex-wrap: nowrap; gap: 6px;
    overflow-x: auto; overflow-y: hidden; padding-bottom: 4px;
    flex: none; min-height: 0;
    -webkit-overflow-scrolling: touch; scrollbar-width: none;
  }
  .nav-list::-webkit-scrollbar { display: none; }
  .nav-group, .nav-children { display: contents; }
  .nav-item { flex: none; padding: 7px 12px; white-space: nowrap; }
  .nav-item .nav-num { display: none; }
  .nav-item .nav-badge { margin-left: 6px; }
  .nav-item--child {
    padding: 7px 10px;
    font-size: var(--text-xs);
    background: rgba(255, 255, 255, 0.04);
  }
  .finn-dock, .sidebar > .star { display: none; }
  /* The action rail (delete) runs down the right edge of every ledger row, and
     a fixed bottom-right mascot permanently covered the bottom row's button.
     Move it to the left, where nothing is interactive. */
  .finn-fab { right: auto; left: 14px; align-items: flex-start; }
  .sidebar-user { width: 100%; }
  /* Bottom padding clears the fixed mascot so the last row is never under it. */
  .main { padding: 16px 16px 96px; height: auto; overflow: visible; }
  /* The nav is one scrolling row. Account folders used to sit straight after
     Transactions and pushed Summary, Import and the rest off-screen. */
  .nav-item--child { order: 1; }
  .nav-logout { order: 2; }
  .toast-host { right: 12px; bottom: 76px; left: 12px; max-width: none; }
  .finn-fab { display: flex; }
  /* No header to keep sticky on phones, so a nested scroll box only trapped
     the thumb: let the ledger scroll with the page. */
  .table-scroll { max-height: none; overflow-y: visible; }
}

/* Status badge base */
.badge {
  font-size: var(--text-xs);
  border-radius: var(--radius);
  padding: 2px 8px;
  border: 1px solid var(--border);
}
.badge--billed     { color: var(--positive); border-color: var(--positive); background: rgba(74, 155, 110, 0.08); }
.badge--unbilled   { color: var(--warm-text); border-color: var(--warm); background: rgba(236, 189, 118, 0.12); }

/* Buttons */
.btn {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: var(--text-sm);
  border-radius: var(--radius);
  padding: 8px 16px;
  cursor: pointer;
  border: 1px solid transparent;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}
.btn--primary   { color: #FFFFFF; background: var(--accent); border-color: var(--accent); }
.btn--primary:hover { background: var(--accent-text); border-color: var(--accent-text); }
.btn--secondary { color: var(--text-primary); background: var(--surface); border-color: var(--border); }
.btn--secondary:hover { border-color: var(--accent); }
.btn--ghost     { color: var(--accent-text); background: transparent; }
.btn--ghost:hover { background: var(--surface); border-color: var(--border); }
.btn--destructive { color: var(--danger); background: var(--surface); border-color: var(--border); }
.btn--destructive:hover { border-color: var(--danger); }
.btn:disabled   { color: var(--text-secondary); background: var(--bg); border-color: var(--border);
                  cursor: not-allowed; opacity: 0.6; }

/* Transactions stays mounted through HTMX navigation, so its interactive
   styles must be in the shared stylesheet instead of a page-local <head>. */
.cat-display, .merchant-display, .amount-display {
  cursor: pointer;
  border-radius: 4px;
  padding: 1px 3px;
  margin: -1px -3px;
}
.cat-display:hover, .merchant-display:hover, .amount-display:hover,
.date-display:hover, .note-display:hover {
  background: var(--bg);
  outline: 1px dashed var(--border);
}
.cat-select, .merchant-input, .amount-input, .date-input, .note-input {
  width: 100%;
  box-sizing: border-box;
  padding: 2px 6px;
  color: var(--text-primary);
  background: var(--surface);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  font: var(--text-sm) var(--font-body);
}
.amount-input {
  font-family: var(--font-mono);
  text-align: right;
  max-width: 140px;
  margin-left: auto;
}
.amount-cell {
  display: flex;
  justify-content: flex-end;
  align-items: center;
}
.amount-cell.is-busy, .cat-cell.is-busy, .merchant-cell.is-busy,
.date-cell.is-busy, .note-cell.is-busy { opacity: 0.55; pointer-events: none; }
.amount-cell.is-error .amount-display,
.cat-cell.is-error .cat-display,
.merchant-cell.is-error .merchant-display,
.date-cell.is-error .date-display,
.note-cell.is-error .note-display {
  outline: 1px solid var(--danger);
  background: rgba(192, 86, 74, 0.08);
}
.date-display, .note-display { cursor: pointer; border-radius: 4px; }
.note-display {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-secondary);
}
.note-empty { opacity: 0.45; }
.ledger-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin: 8px 0 12px;
}
.ledger-toolbar__start {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.quick-add-panel {
  margin-bottom: 24px;
  padding: 20px 24px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.quick-add-panel .field-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
}
.quick-add-panel .field { display: flex; flex-direction: column; gap: 4px; }
.quick-add-panel label {
  color: var(--text-secondary);
  font-size: var(--text-xs);
  font-weight: 500;
}
.unlearn-btn {
  padding: 0 2px;
  color: var(--text-secondary);
  background: none;
  border: none;
  cursor: pointer;
  font-size: 10px;
  vertical-align: middle;
}
.unlearn-btn:hover { color: #C0564A; }
.cat-auto {
  margin-left: 4px;
  padding: 1px 4px;
  color: #5F7891;
  background: rgba(95, 120, 145, .15);
  border-radius: 4px;
  font-size: 9px;
  font-weight: 600;
  vertical-align: middle;
}
.bills-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 10px;
  margin: 0 0 20px;
  padding: 12px 14px;
  background: rgba(46, 58, 70, 0.03);
  border: 1px dashed var(--border);
  border-radius: var(--radius-lg);
}
.bills-strip .incoming-label { margin-bottom: 2px; }
.bill-card {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
}
.bill-card.bill-urgent {
  background: rgba(192, 86, 74, .12);
  border-color: rgba(192, 86, 74, .3);
}
.incoming-label {
  width: 100%;
  color: var(--text-secondary);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.billing-badge { margin-left: 4px; white-space: nowrap; }
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin-bottom: 8px;
}
.filter-group { display: flex; flex-direction: column; align-items: stretch; gap: var(--space-1); }
.filter-group[hidden] { display: none; }
.filter-bar { align-items: flex-end; }
.filter-bar select.input { min-width: 150px; }
.filter-words { width: 150px; }
/* Category tick list: looks like the other dropdowns, opens a flat list. */
.multi-select { position: relative; }
.multi-select > summary {
  list-style: none;
  cursor: pointer;
  min-width: 150px;
  max-width: 220px;
  box-sizing: border-box;
  padding-right: 28px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  position: relative;
}
.multi-select > summary::-webkit-details-marker { display: none; }
.multi-select > summary::after {
  content: "";
  position: absolute;
  right: 12px;
  top: 50%;
  width: 6px;
  height: 6px;
  border-right: 1.5px solid var(--text-secondary);
  border-bottom: 1.5px solid var(--text-secondary);
  transform: translateY(-70%) rotate(45deg);
}
.multi-select[open] > summary { border-color: var(--accent); }
.multi-select__menu {
  position: absolute;
  z-index: 20;
  top: calc(100% + 4px);
  left: 0;
  min-width: 100%;
  max-height: 280px;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  padding: 4px 0;
}
.multi-select__option {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  font-size: var(--text-sm);
  white-space: nowrap;
  cursor: pointer;
}
.multi-select__option:hover { background: var(--bg); }
.filter-label {
  font-size: var(--text-xs);
  font-weight: 500;
  color: var(--text-secondary);
  margin-right: 2px;
}
.filter-bar.is-filtering {
  opacity: .55;
  pointer-events: none;
  transition: opacity .12s ease;
}

/* Inputs */
.field-label {
  font-size: var(--text-xs);
  font-weight: 500;
  color: var(--text-secondary);
}
.input, select.input {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--text-primary);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 8px 12px;
}
.input--error   { border-color: var(--danger); }
.input-error-msg { font-size: var(--text-xs); color: var(--danger); }

.date-range { display: flex; align-items: center; gap: var(--space-2); }
.date-range .input { width: 130px; }

/* Card / surface */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}

/* Summary category breakdown — responsive rows */
.breakdown-row { display: flex; align-items: center; gap: 12px; }
.breakdown-name { width: 140px; flex: none; font-size: var(--text-sm); color: var(--text-secondary); }
.breakdown-track { flex: 1; height: 20px; background: var(--bg); border-radius: var(--radius); overflow: hidden; }
.breakdown-track > div { height: 100%; border-radius: var(--radius); transition: width 0.4s ease; }
.breakdown-amount { width: 110px; flex: none; text-align: right; font-size: var(--text-sm); }
.breakdown-pct { width: 48px; flex: none; text-align: right; font-size: var(--text-xs); color: var(--text-secondary); }

/* Filter action links (Clear / CSV) stay paired on desktop and mobile */
.filter-actions { display: flex; align-items: center; gap: 8px; }

/* ── Ticker cards (cosmic) ── */
.ticker-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}
.ticker {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  text-decoration: none;
  color: inherit;
}
.ticker--action { cursor: pointer; transition: transform var(--transition-fast), box-shadow var(--transition-fast); }
.ticker--action:hover { transform: translateY(-3px); box-shadow: var(--shadow-hover); }
.ticker-label { font-size: var(--text-xs); color: var(--text-secondary); }
.ticker-value { font-family: var(--font-mono); font-size: 22px; color: var(--text-primary); }
.ticker-sub   { font-size: var(--text-xs); color: var(--text-secondary); }

/* Table */
.table-header, .table-row {
  display: grid;
  /* Weighted by what each column actually holds. Account was 108px, too narrow
     for a name plus its billing badge, so every row wrapped to two lines and
     grew ~20% taller for nothing. Note was a wide column of em-dashes. */
  grid-template-columns: 100px minmax(0, 1fr) minmax(0, 1fr) 150px 124px minmax(0, 1fr) 64px;
  /* Wider column gap than row gap: a right-aligned amount sat 8px from the
     left-aligned note and the two read as one value. */
  gap: var(--space-2) var(--space-3);
  padding: 4px 16px;
  align-items: center;
}
.table-header {
  padding: 8px 16px;
  border-bottom: 1px solid var(--border);
  font-size: var(--text-xs);
  font-weight: 500;
  color: var(--text-secondary);
}
.table-row { min-height: 44px; border-bottom: 1px solid var(--border); font-size: var(--text-sm); }
.table-row:hover { background: var(--bg); }
.col-amount { text-align: right; }
.row-actions { display: flex; justify-content: flex-end; gap: 4px; }
.row-actions form { margin: 0; }
.icon-btn {
  width: 28px;
  height: 28px;
  display: inline-grid;
  place-items: center;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text-secondary);
  cursor: pointer;
  font: 600 var(--text-base) var(--font-body);
}
.icon-btn:hover { border-color: var(--accent); color: var(--text-primary); }
.icon-btn--danger:hover { border-color: var(--danger); color: var(--danger); }

.import-panel { padding: var(--space-4); }
.import-panel.is-scanning { animation: scanPulse 1.1s ease-in-out infinite; }
.import-panel.is-scanning .import-actions .btn { position: relative; color: transparent; }
.import-panel.is-scanning .import-actions .btn::after {
  content: "Scanning…";
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: #FFFFFF;
}
.import-grid {
  display: grid;
  grid-template-columns: minmax(180px, 240px) 1fr;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}
.import-panel .field {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.import-textarea {
  min-height: 220px;
  resize: vertical;
  font-family: var(--font-mono);
}
.import-actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin-top: var(--space-3);
}
.import-actions span,
.import-result p,
.import-result li {
  color: var(--text-secondary);
  font-size: var(--text-sm);
}
.import-result {
  position: relative;
  padding: var(--space-3);
  padding-right: 96px;
  border-left: 4px solid var(--accent);
}
.import-result__finn { position: absolute; right: 12px; bottom: 8px; width: auto; height: 84px; }
.import-result--reveal { animation: importReveal .42s ease both; }
.import-result--ok { border-left-color: var(--positive); }
.import-result--warn { border-left-color: var(--warm); }
.import-result--ok::before { content: "✓  SIGNAL LOCKED"; display: block; margin-bottom: 6px; color: var(--positive); font: 600 10px var(--font-mono); letter-spacing: .1em; }

@media (max-width: 640px) {
  /* Tables: hide headers; generic rows stack vertically. */
  .table-header { display: none; }
  .table-row {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-1);
    padding: var(--space-3) var(--space-2);
  }
  .col-amount { text-align: left; }
  .row-actions { align-self: flex-end; }

  /* Transaction rows get a deliberate card layout. Scoped to #txn-table so
     the summary/subscription tables keep their simple vertical stack. */
  #txn-table .table-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 6px 12px;
    padding: 14px 12px;
    align-items: center;
  }
  /* Merchant and amount share line one — the two facts you actually scan for.
     Everything on the right edge lines up at one x; previously the amount was
     right-aligned inside column 1, giving it an edge nothing else shared. */
  #txn-table .table-row { grid-template-columns: minmax(0, 1fr) auto 28px; }
  #txn-table .table-row > :nth-child(2) { grid-column: 1; grid-row: 1; min-width: 0; } /* merchant */
  #txn-table .merchant-display {
    display: block; overflow: hidden; text-overflow: ellipsis;
    white-space: nowrap; font-weight: 600;
  }
  #txn-table .table-row > :nth-child(5) { /* amount */
    grid-column: 2; grid-row: 1; justify-self: end; text-align: right;
    font-weight: 700; font-size: var(--text-base);
  }
  /* Delete is a full-height action rail in column 3, so every piece of content
     in column 2 (amount, account, status) shares one right edge instead of
     staggering around the button. */
  /* With no explicit rows, 1 / -1 collapses to row 1, so two stacked buttons
     stretched the merchant line. Span the three lines every row has. */
  #txn-table .table-row > :nth-child(7) { grid-column: 3; grid-row: 1 / span 3; align-self: center; } /* repeat + delete */
  #txn-table .table-row > :nth-child(3) { grid-column: 1; grid-row: 2; } /* category */
  #txn-table .table-row > :nth-child(4) { grid-column: 2; grid-row: 2; justify-self: end; text-align: right; } /* account */
  #txn-table .table-row > :nth-child(1) { grid-column: 1; grid-row: 3; } /* date */
  #txn-table .table-row > :nth-child(6) { grid-column: 1 / -1; grid-row: 4; } /* note */
  /* An empty note rendered a full-width em-dash under every single row. */
  #txn-table .table-row > :nth-child(6):has(.note-empty) { display: none; }

  /* Filter bar: stack each group label-over-control, full-width inputs. */
  .filter-bar { flex-direction: column; align-items: stretch; gap: 14px; }
  .filter-bar select.input, .filter-words { width: 100%; min-width: 0; box-sizing: border-box; }
  .multi-select > summary { width: 100%; max-width: none; min-width: 0; }
  .multi-select__menu { right: 0; }
  /* Two row actions stack in the right-hand rail. */
  #txn-table .row-actions { flex-direction: column; }

  /* Recurring rows: two lines like the ledger instead of five stacked cells.
     !important beats the desktop column template set inline on the row. */
  .recurring-row {
    display: grid !important;
    grid-template-columns: minmax(0, 1fr) auto auto !important;
    gap: 4px 10px;
    align-items: center;
  }
  .recurring-row > :nth-child(1) { grid-column: 1; grid-row: 1; }               /* merchant */
  .recurring-row > :nth-child(4) { grid-column: 2; grid-row: 1; font-weight: 600; } /* monthly */
  .recurring-row > :nth-child(2) { grid-column: 1; grid-row: 2; }               /* category */
  .recurring-row > :nth-child(5) { grid-column: 2; grid-row: 2; color: var(--text-secondary); } /* next */
  .recurring-row > :nth-child(3) { display: none; }                             /* pattern */
  .recurring-row > :nth-child(6) { grid-column: 3; grid-row: 1 / span 2; }      /* edit/remove */
  .recurring-row > :nth-child(6):empty { display: none; }
  .filter-label { margin-right: 0; }
  .date-range { width: 100%; }
  .date-range .input { flex: 1; width: auto; min-width: 0; }
  #f-category, #f-search { width: 100% !important; box-sizing: border-box; }

  /* Quick add: two even columns instead of six fields at six widths. */
  .quick-add-panel { padding: var(--space-3); }
  .quick-add-panel .field-row { display: grid; grid-template-columns: 1fr 1fr; }
  .quick-add-panel .field { min-width: 0; }
  .quick-add-panel .field .input { width: 100% !important; box-sizing: border-box; }
  .quick-add-panel .field--wide,
  .quick-add-panel .btn { grid-column: 1 / -1; }

  /* Stacked rows lose their header, so a bare "8" needs its own label. */
  .table-row > [data-label]::before {
    content: attr(data-label) " ";
    color: var(--text-secondary);
    font-family: var(--font-body);
    font-size: var(--text-xs);
  }
  .filter-actions { justify-content: flex-end; }

  /* Summary breakdown: name+pct share a row, bar and amount go full-width. */
  .breakdown-row {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 4px 10px;
  }
  .breakdown-name { width: auto; grid-column: 1; grid-row: 1; }
  .breakdown-pct { width: auto; grid-column: 2; grid-row: 1; }
  .breakdown-track { grid-column: 1 / -1; grid-row: 2; }
  .breakdown-amount { width: auto; grid-column: 1 / -1; grid-row: 3; text-align: left; }

  /* Import: CSV scrolls sideways instead of wrapping mid-word. */
  .import-textarea { white-space: pre; overflow-x: auto; }
  .import-grid { grid-template-columns: 1fr; }
}

/* ── Signal Beam ───────────────────────────────────────────────────────────
   A light beam that travels the border of a card. Reserved for what matters:
   the hero, the active selection, and hover on interactive cards. Everything
   else stays quiet so the beam reads as a spotlight, not decoration.
   Pure CSS: a rotating conic-gradient masked to a 1.5px ring. */
@property --beam-angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}
@keyframes beam-spin { to { --beam-angle: 360deg; } }

.beam, .beam-hover, .beam-active {
  position: relative;
  --beam-tail: rgba(95, 120, 145, .35);
  --beam-c1: var(--accent);
  --beam-c2: var(--mint);
  --beam-head: #ffffff;
}
.beam--warm {
  --beam-tail: rgba(236, 189, 118, .4);
  --beam-c1: var(--warm);
  --beam-c2: var(--danger);
  --beam-head: #ffe9c7;
}
/* hover/active variants keep the ring hidden until triggered */
.beam-hover, .beam-active { --beam-on: 0; }
.beam-hover:hover, .beam-active.is-active { --beam-on: 1; --beam-width: 2.5px; }

.beam::after, .beam-hover::after, .beam-active::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  border-radius: inherit;
  padding: var(--beam-width, 2px);
  background: conic-gradient(from var(--beam-angle),
    transparent 0deg,
    transparent 160deg,
    var(--beam-tail) 250deg,
    var(--beam-c1) 320deg,
    var(--beam-c2) 342deg,
    var(--beam-head) 353deg,
    transparent 360deg);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask-composite: exclude;
  pointer-events: none;
  opacity: var(--beam-on, 1);
  transition: opacity .3s ease;
  animation: beam-spin var(--beam-speed, 4s) linear infinite;
}
.beam--slow { --beam-speed: 7s; --beam-width: 3px; }

/* Glow variant: a wider, fainter halo ring behind the crisp core so the beam
   reads as light, not a hairline. Uses ::before — the hero's faint orbit-ring
   decoration was retired to make room (the beam is the new decoration). */
.beam--glow::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  padding: 18px;
  background: conic-gradient(from var(--beam-angle),
    transparent 0deg,
    transparent 150deg,
    var(--beam-tail) 240deg,
    var(--beam-c1) 305deg,
    var(--beam-c2) 340deg,
    var(--beam-c2) 356deg,
    transparent 360deg);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask-composite: exclude;
  opacity: calc(var(--beam-on, 1) * .6);
  animation: beam-spin var(--beam-speed, 4s) linear infinite;
  pointer-events: none;
}

/* ── Monthly summary — orbit report ── */
.summary-hero {
  padding: 28px;
  margin-bottom: 8px;
}
.summary-hero__kicker {
  display: block;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-text);
  margin-bottom: 8px;
}
.summary-hero__total {
  font: 700 clamp(32px, 5vw, 44px) / 1.1 var(--font-mono);
  color: var(--text-primary);
}
.summary-hero__meta {
  margin-top: 10px;
  font-size: var(--text-xs);
  color: var(--text-secondary);
  display: flex;
  flex-wrap: wrap;
  gap: 8px 14px;
  align-items: center;
}
.summary-hero__delta {
  font-family: var(--font-mono);
  font-weight: 500;
}
.summary-hero__delta--up { color: var(--danger); }
.summary-hero__delta--down { color: var(--positive); }

.summary-cycle-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 12px;
}
.summary-cycle-card {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 16px 18px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
.summary-cycle-card__top {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  color: var(--text-secondary);
  font-size: var(--text-xs);
}
.summary-cycle-card__top strong { color: var(--text-primary); font-size: var(--text-sm); }
.summary-cycle-card__total { font-size: 22px; }
.summary-cycle-card__split {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  color: var(--text-secondary);
  font-size: var(--text-xs);
}
.summary-recurring-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
#card-cycles, #recurring { scroll-margin-top: 16px; }
.badge--manual { background: var(--warm); color: var(--space-navy); font-size: 10px; padding: 1px 6px; border-radius: 8px; font-weight: 600; }
.badge--auto { background: rgba(95, 120, 145, 0.15); color: var(--accent-text, #5F7891); font-size: 10px; padding: 1px 6px; border-radius: 8px; font-weight: 600; }
.manual-form { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 20px 24px; margin-bottom: 16px; }
.manual-form .field-row,
.manual-edit .field-row { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end; }
.manual-form .field,
.manual-edit .field { display: flex; flex-direction: column; gap: 4px; }
.manual-form label,
.manual-edit label { font-size: var(--text-xs); color: var(--text-secondary); font-weight: 500; }
.manual-edit { padding: 16px 24px; background: var(--bg); border-bottom: 1px solid var(--border); }
.summary-finn {
  display: flex; align-items: center; gap: 12px;
  margin: 4px 0 20px;
  padding: 14px 16px;
  background: rgba(147, 177, 129, 0.12);
  border-left: 3px solid var(--mint);
  border-radius: 0 var(--radius) var(--radius) 0;
  font-size: var(--text-sm);
  color: var(--text-primary);
  line-height: 1.45;
}
.summary-finn strong { color: var(--accent-text); font-size: 11px; letter-spacing: 0.06em; }
.summary-finn p { margin: 0; }
.summary-finn__pose { flex: none; width: auto; height: 104px; margin: -8px 0; }

.summary-split {
  display: grid;
  gap: 20px 24px;
  align-items: start;
  margin-bottom: 28px;
}
.summary-split .section-block { margin-bottom: 0; }
.summary-split--pair {
  grid-template-columns: minmax(160px, 220px) minmax(0, 1fr);
}
.heatmap-card {
  width: 100%;
  max-width: 220px;
  padding: 10px;
}
@media (max-width: 720px) {
  .summary-split--pair { grid-template-columns: 1fr; }
  .heatmap-card { max-width: 220px; }
}
.heatmap {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
}
.heatmap__dow {
  text-align: center;
  font-size: 8px;
  color: var(--text-secondary);
  padding-bottom: 2px;
}
.heatmap__cell {
  aspect-ratio: 1;
  border-radius: 2px;
  background: var(--bg);
  border: 1px solid transparent;
  position: relative;
}
.heatmap__cell--empty { opacity: 0.35; }
.heatmap__cell--l1 { background: rgba(95, 120, 145, 0.18); }
.heatmap__cell--l2 { background: rgba(95, 120, 145, 0.38); }
.heatmap__cell--l3 { background: rgba(95, 120, 145, 0.62); }
.heatmap__cell--l4 { background: var(--accent); }
.heatmap__cell[title] { cursor: default; }

.leaderboard { display: flex; flex-direction: column; gap: 10px; }
.leaderboard__row {
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr) 120px;
  gap: 12px;
  align-items: center;
}
.leaderboard__rank {
  font: 600 var(--text-xs) var(--font-mono);
  background: var(--space-navy);
  color: #fff;
  width: 24px; height: 24px;
  border-radius: 8px;
  display: grid; place-items: center;
}
.leaderboard__name {
  font-size: var(--text-sm);
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.leaderboard__bar {
  height: 6px;
  background: var(--bg);
  border-radius: 99px;
  overflow: hidden;
  margin-top: 4px;
}
.leaderboard__bar > i {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--accent), var(--mint));
  border-radius: inherit;
}
.leaderboard__amt {
  text-align: right;
  font: var(--text-xs) var(--font-mono);
}
.breakdown-track > div.breakdown-fill--top {
  background: linear-gradient(90deg, var(--accent), var(--mint));
}
.breakdown-track > div.breakdown-fill {
  background: rgba(147, 177, 129, 0.55);
}
.section-block { margin-bottom: 28px; }
.section-block h2 { margin-bottom: 14px; }

/* ── Admin control room ───────────────────────────────────────────────────── */
.admin { display: flex; flex-direction: column; gap: 28px; }
.admin-section h2 { margin: 0 0 8px; }
.admin-hint {
  margin: 0 0 12px;
  font-size: var(--text-xs);
  color: var(--text-secondary);
  max-width: 60ch;
}
.admin-card { overflow: hidden; }
.admin-btn { padding: 4px 12px; font-size: var(--text-xs); }
.admin-ellipsis {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.admin-empty, .admin-empty-card {
  padding: 16px 20px;
  font-size: var(--text-sm);
  color: var(--text-secondary);
}
.admin-empty-card { text-align: center; }
.admin-empty-card p { margin: 0; }
.muted { color: var(--text-secondary); }

.admin-table__head,
.admin-table__row,
.admin-add {
  display: grid;
  gap: 8px;
  align-items: center;
  padding: 8px 16px;
}
.admin-table__head {
  border-bottom: 1px solid var(--border);
  font-size: var(--text-xs);
  font-weight: 500;
  color: var(--text-secondary);
}
.admin-table__row {
  min-height: 44px;
  border-bottom: 1px solid var(--border);
  font-size: var(--text-sm);
}
.admin-table__row:hover { background: var(--bg); }
.admin-table__row form { margin: 0; }
.admin-actions { display: flex; gap: var(--space-1); justify-content: flex-end; }
.account-edit .field .input { width: 100%; box-sizing: border-box; }
.account-edit .field { width: 132px; }
.account-edit .field--wide { width: 280px; }
/* Cutoff / due only exist for credit cards; drop them for everything else. */
.account-edit .field:has(.input:disabled) { display: none; }

/* ── Table column primitive ───────────────────────────────────────────────
   Columns are declared ONCE per card and inherited by the header, the rows
   and the add-form. Three separate bugs came from hand-maintaining those
   three grids independently until they drifted out of sync with the markup
   (8 tracks for 9 controls; a 4-cell table borrowing a 2-column grid).
   Adding a field is now a one-line change that cannot desynchronise.
   --form-cols exists only for the add-forms that carry an extra control the
   table has no column for; it defaults to matching the table. */
.admin-card {
  --cols: 1fr;
  --form-cols: var(--cols);
}
.admin-table__head,
.admin-table__row { grid-template-columns: var(--cols); }
.admin-add { grid-template-columns: var(--form-cols); }

.admin-card--accounts {
  --cols: 1.1fr 96px 80px 64px 1.2fr 64px 72px 132px;
  /* the add-form also carries due-offset, which the table folds into "Due" */
  --form-cols: 1.1fr 116px 88px 68px 1.2fr 80px 64px 64px 76px;
}
/* Single-label lists (categories). A one-word row stretched to the full column
   put its Delete button ~1000px from the name it belongs to. */
.admin-card--simple { --cols: 1fr 88px; max-width: 560px; }
.admin-card--budget { --cols: 1fr 160px 88px; }
.admin-card--map    { --cols: 1fr 160px 88px; }
.admin-card--channels { --cols: 132px 220px minmax(0, 1fr) 116px; }
/* A lone submit button sizes to its label rather than filling a 1fr track. */
.admin-card--action { --form-cols: max-content; }
.admin-card--action .admin-add { justify-content: start; }

.admin-add {
  background: var(--bg);
  border-top: 1px solid var(--border);
}
.admin-add .input { width: 100%; min-width: 0; padding: 6px 8px; box-sizing: border-box; }
.admin-add .input:disabled { background: transparent; color: var(--text-secondary); opacity: .6; }

.admin-parse {
  display: flex;
  gap: 16px;
  align-items: flex-start;
  padding: 16px;
  border-bottom: 1px solid var(--border);
}
.admin-parse:last-child { border-bottom: none; }
.admin-parse__body { flex: 1; min-width: 0; }
.admin-parse__meta {
  font-size: var(--text-xs);
  color: var(--text-secondary);
  margin-bottom: 4px;
}
.admin-parse__subject {
  font-size: var(--text-sm);
  font-weight: 500;
  margin-bottom: 4px;
}
.admin-parse__raw {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-secondary);
  background: var(--bg);
  padding: 8px;
  border-radius: var(--radius);
  overflow-x: auto;
  margin: 0;
  max-height: 120px;
  white-space: pre-wrap;
  word-break: break-all;
}

@media (max-width: 900px) {
  .admin-card--accounts .admin-table__head,
  .admin-card--accounts .admin-table__row,
  .admin-add {
    grid-template-columns: 1fr 1fr;
  }
  .admin-card--accounts .admin-table__head { display: none; }
  .admin-card--accounts .admin-table__row > span[data-label]::before,
  .admin-add > .input::placeholder {
    /* labels via data-label on rows */
  }
  .admin-card--accounts .admin-table__row > span[data-label]:not([data-label=""])::before {
    content: attr(data-label) ": ";
    color: var(--text-secondary);
    font-size: var(--text-xs);
  }
  .admin-add {
    grid-template-columns: 1fr 1fr;
  }
  .admin-add .btn { grid-column: 1 / -1; }
  /* Statement-cycle fields only apply to credit cards; when stacked they are
     three dead inputs for every other account type. */
  .admin-add .input:disabled { display: none; }
}

@media (max-width: 640px) {
  .admin-table__head { display: none; }
  .admin-table__row,
  .admin-add,
  .admin-add {
    grid-template-columns: 1fr;
    padding: 12px 14px;
  }
  .admin-table__row > span[data-label]:not([data-label=""])::before {
    content: attr(data-label) ": ";
    color: var(--text-secondary);
    font-size: var(--text-xs);
  }
  .admin-table__row .col-amount { text-align: left; }
  .admin-actions { justify-content: flex-start; }
  .manual-edit { padding: 12px 14px; }
  .account-edit .field,
  .account-edit .field--wide,
  .account-edit .btn { width: 100%; }
  .admin-parse { flex-direction: column; }
}

/* ── Content column (must stay last) ──────────────────────────────────────
   Higher specificity than any single-class component rule, and last in source
   order, so a component declaring `margin: 8px 0 12px` cannot silently reset
   margin-inline and break out of the column. That bug left the ledger toolbar
   and three summary blocks hard against the left edge while every card beside
   them was centred, giving the page a ragged left margin. */
.shell .main > * {
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
  /* Without border-box, each block's padding and border are added to width:100%,
     so a card, a chip and a section all compute to different total widths and
     centre at different left edges. That is what made the column look ragged
     even once every block was inside it. */
  box-sizing: border-box;
}
