/* ============================================================================
   ledger.css — single stylesheet (no build step; baked into the image).

   LAYER ORDER (cascade matters — keep new rules in the right band):
     1. Tokens            — :root design tokens (color, type, space, elevation)
     2. Reset / base      — *,html,body,a,button
     3. Layout / shell    — .layout/.sidebar/.main/.appbar/.scrim
     4. Primitives        — .card surface, .grid, .btn, .ledger-table,
                             forms, .page-header, .card-header/section
     5. Feature blocks    — per-sprint components (kept in place; the
                             section banners below read E05/Sxx, E06/Sxx…)
     6. Responsive        — ONE consolidated band at the end

   BREAKPOINTS (canonical — do not introduce new ad-hoc values):
     - max-width: 768px   → shell switches to the mobile drawer; tables
                             reflow to cards; multi-col grids stack.
     - max-width: 1024px  → wide multi-col grids relax (optional tier).
   Legacy 680/720/900 blocks are being migrated onto these two; the
   responsive grid primitive (.grid) collapses without a media query.
   ============================================================================ */

/* ── Tokens ───────────────────────────────────────────────────────────────────
   Palette mirrors the landing-page design (green-deep / amber / cream).
   The auth app keeps its tight 7-step type scale and dense layout — only
   surface colors, sidebar chrome, accents, fonts, and radii follow the
   landing identity. Semantic income/expense/warn colors are unchanged
   because they're data legibility, not branding. */
:root {
  --bg:           #faf7f2;   /* cream */
  --bg-card:      #ffffff;
  --sidebar-bg:           #1b3a2d;   /* green-deep */
  --sidebar-border:       #2b5940;   /* green-mid */
  --sidebar-text:         #b8c4bb;   /* muted on green-deep */
  --sidebar-text-hover:   #ffffff;
  --sidebar-active-bg:    #2b5940;   /* green-mid */
  --sidebar-active-accent:#c8923a;   /* amber */
  --text-primary: #18180f;
  --text-secondary:#3a3a30;
  --text-muted:   #6b6b5e;
  --border:       #e2ddd6;
  --border-light: #f0ece5;   /* warmer than the old cool gray */
  --income:       #0d7a5f;
  --income-bg:    #e6f7f3;
  --expense:      #c0392b;
  --expense-bg:   #fdf2f2;
  --warn:         #b45309;
  --warn-bg:      #fffbeb;
  --accent:       #1b3a2d;   /* green-deep */
  --accent-soft:  #3d7a57;   /* green-soft — hover/secondary use */
  --amber:        #c8923a;
  --amber-pale:   #fff8ed;
  --radius:       8px;
  --radius-lg:    16px;
  --radius-xl:    24px;
  --shadow:       0 1px 3px rgba(0,0,0,.06),0 1px 2px rgba(0,0,0,.04);
  --font-sans:    'Plus Jakarta Sans',system-ui,-apple-system,sans-serif;
  --font-serif:   'Lora',Georgia,serif;
  --font-mono:    'JetBrains Mono','Fira Code',ui-monospace,monospace;

  /* Type scale — 7 steps consolidating the ~17 ad-hoc px sizes that
     accreted per sprint. Mapping used for the sweep:
       9.5/10/10.5/11        → --fs-xs   (11px)  micro labels, badges
       11.5/12/12.5          → --fs-sm   (12.5px) hints, captions
       13/13.5/14/14.5       → --fs-base (13.5px) body, table, nav
       15                    → --fs-md   (15px)  emphasised body
       18                    → --fs-lg   (18px)  card/section headings
       20/22                 → --fs-xl   (22px)  page titles
       24/26                 → --fs-2xl  (26px)  hero figures */
  --fs-xs:        11px;
  --fs-sm:        12.5px;
  --fs-base:      13.5px;
  --fs-md:        15px;
  --fs-lg:        18px;
  --fs-xl:        22px;
  --fs-2xl:       26px;

  /* Spacing scale — replaces ad-hoc rem/px margins & padding. */
  --sp-1:         .25rem;
  --sp-2:         .5rem;
  --sp-3:         .75rem;
  --sp-4:         1rem;
  --sp-5:         1.5rem;
  --sp-6:         2rem;
  --sp-7:         2.5rem;

  /* Elevation scale. --elev-1 is the existing card --shadow (aliased so
     legacy `var(--shadow)` refs keep working); --elev-2/-3 replace the
     hardcoded one-off popover / modal shadows. */
  --elev-1:       0 1px 3px rgba(0,0,0,.06),0 1px 2px rgba(0,0,0,.04);
  --elev-2:       0 8px 24px rgba(0,0,0,.10);
  --elev-3:       0 24px 60px rgba(15,23,42,.32);
  /* Grid surface tints — these were previously hardcoded inside the rule
     definitions, which broke on dark. Promoted to variables so the dark
     palette below can override them without touching the rules. Warm-
     cream-tinted to compose with the new --bg. */
  --table-header-bg:    #f5f1ea;
  --table-row-hover-bg: #f7f3ec;
  --row-pending-bg:     #fff7e6;   /* faint amber wash on pending rows */
  --ring-cell-hover-bg: #f7f3ec;
}

/* ── Dark palette ────────────────────────────────────────────────────
   Activated by <html data-theme="dark">. Server-rendered from the
   user's saved preference (app_user.preferences.theme) so there's no
   flash of wrong palette on first paint. The light theme's sidebar is
   already deep-green, so dark mode pushes the sidebar a step darker
   than the canvas, and recolours surfaces / borders / text. Amber is
   lifted slightly for contrast against the dark surface. Income /
   expense / warn tints stay as translucent overlays so they read on
   the warmer dark surface without losing their semantic colour cue. */
:root[data-theme="dark"] {
  --bg:            #0f1a14;   /* very dark green-tinted */
  --bg-card:       #1a2820;   /* slightly lifted */

  --sidebar-bg:           #0a130e;   /* darker than canvas */
  --sidebar-border:       #1a2820;
  --sidebar-text:         #9eb0a3;
  --sidebar-text-hover:   #ffffff;
  --sidebar-active-bg:    #1b3a2d;   /* re-uses the light-theme sidebar bg */
  --sidebar-active-accent:#d4a04a;   /* amber lifted for dark contrast */

  --text-primary:  #f0ede5;          /* warm off-white */
  --text-secondary:#b8b5a8;
  --text-muted:    #7a786e;

  --border:        #2c3a30;
  --border-light:  #1f2a22;

  --accent:        #3d7a57;          /* green-soft — brighter against dark */
  --accent-soft:   #5a9876;
  --amber:         #d4a04a;

  --income-bg:     rgba(13,122,95,0.18);
  --expense-bg:    rgba(192,57,43,0.18);
  --warn-bg:       rgba(180,83,9,0.18);
  --shadow:        0 1px 3px rgba(0,0,0,.45),0 1px 2px rgba(0,0,0,.35);

  /* Grid surface tints — lifted from --bg-card so headers and pending
     rows separate from the surrounding table without going white.
     Pending uses an amber wash matching the new identity. */
  --table-header-bg:    #1f2a22;
  --table-row-hover-bg: rgba(255,255,255,0.045);
  --row-pending-bg:     rgba(212,160,74,0.12);
  --ring-cell-hover-bg: rgba(255,255,255,0.045);
}
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{font-size:var(--fs-md)}
body{font-family:var(--font-sans);background:var(--bg);color:var(--text-primary);line-height:1.6;-webkit-font-smoothing:antialiased}
a{color:inherit;text-decoration:none}
button{cursor:pointer;font-family:inherit}

/* ── Layout ─────────────────────────────────────────────────────────────────── */
.layout{display:flex;min-height:100vh}
.sidebar{width:220px;min-height:100vh;background:var(--sidebar-bg);border-right:1px solid var(--sidebar-border);display:flex;flex-direction:column;position:fixed;top:0;left:0;bottom:0;z-index:10}
.main{margin-left:220px;flex:1;min-height:100vh}
.main-inner{max-width:1280px;margin:0 auto;padding:2rem 2.5rem}

/* Mobile app-bar + drawer scrim. Hidden on desktop (the fixed sidebar
   is always visible there); the @media(max-width:768px) band at the end
   of the file flips these on and turns .sidebar into an off-canvas
   drawer. Kept in the Layout layer so the shell lives in one place. */
.appbar{display:none}
.scrim{display:none}

/* ── Sidebar ─────────────────────────────────────────────────────────────────── */
.sidebar-brand{display:flex;align-items:center;gap:10px;padding:1.5rem 1.25rem 1.25rem;border-bottom:1px solid var(--sidebar-border)}
.brand-mark{color:var(--sidebar-active-accent);font-size:var(--fs-base)}
.brand-name{font-size:var(--fs-sm);font-weight:600;letter-spacing:.12em;color:var(--sidebar-text-hover)}
/* MoMoFi wordmark spans — "MoMo" carries the brand, "Fi" is the
 * URL/domain anchor (smaller + lower opacity) so visually the brand
 * reads as "MoMo" first. On dark surfaces (sidebar + mobile appbar)
 * the colours flip so the wordmark stays legible. */
.brand-mo{color:var(--green-deep,#1b3a2d);font-weight:700}
.brand-fi{color:var(--amber,#c8923a);font-weight:700;font-size:.85em;opacity:.78}
.sidebar .brand-mo,.appbar .brand-mo{color:#fff}
.sidebar .brand-fi,.appbar .brand-fi{color:var(--sidebar-active-accent);opacity:.92}
.sidebar-nav{flex:1;padding:1rem 0}
.nav-section-label{padding:.9rem 1.25rem .25rem;font-size:.65rem;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--sidebar-text);opacity:.55}
.nav-section-label:first-child{padding-top:.25rem}
.nav-item{display:flex;align-items:center;gap:10px;padding:.6rem 1.25rem;font-size:var(--fs-base);color:var(--sidebar-text);transition:all .12s;border-left:2px solid transparent}
.nav-item:hover{color:var(--sidebar-text-hover);background:rgba(255,255,255,.04)}
.nav-item.active{color:var(--sidebar-text-hover);background:var(--sidebar-active-bg);border-left-color:var(--sidebar-active-accent)}
.nav-icon{width:16px;height:16px;flex-shrink:0;opacity:.75}
.nav-item.active .nav-icon,.nav-item:hover .nav-icon{opacity:1}
.sidebar-foot{padding:1rem 1.25rem;border-top:1px solid var(--sidebar-border);display:flex;flex-direction:column;gap:.35rem}
.sidebar-user-name{font-size:var(--fs-sm);color:var(--sidebar-text-hover);font-weight:500;letter-spacing:.02em;text-decoration:none;display:flex;flex-direction:column;line-height:1.2}
.sidebar-user-name:hover{color:var(--sidebar-text);text-decoration:underline}
.sidebar-user-sub{font-size:.7rem;font-weight:400;opacity:.55;letter-spacing:.04em}
.sidebar-foot-row{display:flex;align-items:center;gap:.5rem}
.sidebar-logout{background:transparent;border:0;color:var(--sidebar-text);font-size:var(--fs-base);cursor:pointer;padding:.4rem 0;text-align:left;font-family:inherit;flex:1}
.sidebar-logout:hover{color:var(--sidebar-text-hover)}
.sidebar-toggle{background:transparent;border:1px solid var(--sidebar-border);color:var(--sidebar-text);cursor:pointer;font-family:inherit;width:30px;height:30px;border-radius:6px;display:inline-flex;align-items:center;justify-content:center;font-size:var(--fs-base);line-height:1;padding:0}
.sidebar-toggle:hover{color:var(--sidebar-text-hover);border-color:var(--sidebar-text-hover)}

/* ── Page header ─────────────────────────────────────────────────────────────── */
.page-header{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:1.75rem}
.page-header__back{display:inline-block;font-size:var(--fs-sm);color:var(--text-muted);text-decoration:none;margin-bottom:.35rem}
.page-header__back:hover{color:var(--text-primary);text-decoration:underline}
.page-title{font-family:var(--font-serif);font-size:var(--fs-xl);font-weight:600;letter-spacing:-.01em;line-height:1.2}
.page-sub{font-size:var(--fs-base);color:var(--text-muted);margin-top:2px}

/* Headings — Lora serif for the editorial feel from the landing page.
   Body, table, form, and nav text stay in --font-sans (Plus Jakarta).
   Numeric tables use --font-mono (JetBrains Mono) via .mono / .money. */
h1,h2,h3{font-family:var(--font-serif);font-weight:600;letter-spacing:-.005em}

/* ── Prompt card ─────────────────────────────────────────────────────────────── */
.prompt-card{display:flex;align-items:center;gap:16px;background:var(--sidebar-bg);color:var(--sidebar-text-hover);border-radius:var(--radius-lg);padding:1rem 1.25rem;margin-bottom:1.75rem}
.prompt-icon{font-size:var(--fs-xl);flex-shrink:0;width:32px;text-align:center}
.prompt-body{flex:1;font-size:var(--fs-base);line-height:1.5}
.prompt-body strong{display:block;color:#fff;font-weight:500;margin-bottom:2px}
.prompt-body span{color:var(--sidebar-text)}
.prompt-action{font-size:var(--fs-base);color:var(--sidebar-active-accent);white-space:nowrap;font-weight:500;flex-shrink:0}
.prompt-action:hover{text-decoration:underline}

/* ── Stat grid ─────────────────────────────────────────────────────────────── */
.stat-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:14px;margin-bottom:1.75rem}
.stat-grid--3{grid-template-columns:repeat(3,1fr)}
.stat-grid--2{grid-template-columns:repeat(2,1fr)}
.stat-card{background:var(--bg-card);border:1px solid var(--border-light);border-radius:var(--radius);padding:1rem 1.25rem}
.stat-label{font-size:var(--fs-xs);font-weight:500;letter-spacing:.06em;text-transform:uppercase;color:var(--text-muted);margin-bottom:6px}
.stat-value{font-size:var(--fs-xl);font-weight:600;letter-spacing:-.02em;font-family:var(--font-mono);line-height:1.2}
.stat-compare{font-size:var(--fs-sm);color:var(--text-muted);margin-top:4px}
.stat-card--positive{border-top:3px solid var(--income)}
.stat-card--negative{border-top:3px solid var(--expense)}

/* ── Cards ─────────────────────────────────────────────────────────────────── */
.card{background:var(--bg-card);border:1px solid var(--border-light);border-radius:var(--radius-lg);overflow:hidden;box-shadow:var(--shadow);margin-bottom:1.5rem}
.card--table{padding:0}
.card--empty{padding:2.5rem;text-align:center;color:var(--text-secondary)}
.card-header{display:flex;justify-content:space-between;align-items:center;padding:.875rem 1.25rem;border-bottom:1px solid var(--border-light)}
.card-title{font-size:var(--fs-base);font-weight:600;letter-spacing:-.01em}
.card-link{font-size:var(--fs-sm);color:var(--accent);font-weight:500}
.card-link:hover{text-decoration:underline}
.two-col{display:grid;grid-template-columns:1fr 1fr;gap:1.5rem;align-items:start}

/* ── Ledger table ─────────────────────────────────────────────────────────── */
.ledger-table{width:100%;border-collapse:collapse;font-size:var(--fs-base)}
.ledger-table th{font-size:var(--fs-xs);font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--text-muted);padding:.6rem 1.25rem;text-align:left;border-bottom:1px solid var(--border-light);background:var(--table-header-bg)}
.ledger-table td{padding:.7rem 1.25rem;border-bottom:1px solid var(--border-light);vertical-align:middle}
.ledger-table tbody tr:last-child td{border-bottom:none}
.ledger-table tbody tr:hover{background:var(--table-row-hover-bg)}
.ledger-table--full .ledger-table th,.ledger-table--full .ledger-table td{padding:.7rem 1rem}
.row-pending{background:var(--row-pending-bg) !important}
.row-reconciled{opacity:.65}
tfoot .total-row td{border-top:2px solid var(--border);border-bottom:none;padding-top:.875rem;background:var(--table-header-bg)}

/* ── Typography helpers ───────────────────────────────────────────────────── */
.mono{font-family:var(--font-mono);font-size:.92em}
.text-right{text-align:right}
.text-center{text-align:center}
.text-muted{color:var(--text-muted)}
.text-income{color:var(--income)}
.text-expense{color:var(--expense)}
.date-cell{color:var(--text-secondary);font-size:var(--fs-sm);white-space:nowrap}

/* ── Money presentation (see docs/MONEY_PRESENTATION.md) ───────────────────
   Flows: magnitude-only, direction by colour + ▲/▼ arrow + sr-only word.
   Nets: signed (the one place a sign appears). Reuses the --income/--expense
   tokens so dark mode is inherited. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.money{font-variant-numeric:tabular-nums;white-space:nowrap}
.money--in{color:var(--income)}
.money--out{color:var(--expense)}
.money__arrow{font-size:.78em;margin-right:.14em;vertical-align:baseline}

/* ── Tooltip engine (CSP-safe: pure CSS, no JS). Wrap the trigger in
   <span class="tip" tabindex="0" aria-label="…"> and add a sibling
   <span class="tip__bubble" aria-hidden="true">…</span>. Reveals on
   hover AND keyboard focus. .tip--help adds a learn-more affordance. */
.tip{position:relative;display:inline-flex;align-items:center;gap:.2em}
.tip--help{cursor:help;border-bottom:1px dotted currentColor}
.tip__bubble{position:absolute;bottom:calc(100% + 6px);left:50%;transform:translateX(-50%);
  background:var(--text-primary);color:var(--bg);padding:.42rem .6rem;border-radius:6px;
  font-size:var(--fs-xs);font-weight:500;line-height:1.35;white-space:normal;
  width:max-content;max-width:240px;text-align:left;
  opacity:0;visibility:hidden;transition:opacity .12s ease;z-index:60;pointer-events:none}
.tip:hover .tip__bubble,.tip:focus-within .tip__bubble{opacity:1;visibility:visible}
.tx-link{color:var(--text-primary)}
.tx-link:hover{color:var(--accent);text-decoration:underline}
.tx-desc{display:block}
.tx-notes{display:block;font-size:var(--fs-sm);color:var(--text-muted)}
.action-cell{white-space:nowrap;text-align:right}
.action-link{font-size:var(--fs-sm);color:var(--text-muted);padding:2px 6px;background:none;border:none;font-family:inherit}
.action-link:hover{color:var(--accent)}
.action-link--danger:hover{color:var(--expense)}
.action-link--muted{color:var(--text-muted)}
.action-link--ghost{font-size:.7rem;opacity:.6;font-style:italic}
.action-link--ghost:hover{opacity:1}
.notif-header-actions{display:flex;gap:.5rem;align-items:center}

/* ── Badges ─────────────────────────────────────────────────────────────── */
.badge,.badge-pending{display:inline-block;font-size:var(--fs-xs);font-weight:500;padding:1px 6px;border-radius:4px;background:var(--warn-bg);color:var(--warn);margin-left:6px;vertical-align:middle}
.badge-count{display:inline-block;font-size:var(--fs-xs);font-weight:600;padding:1px 7px;border-radius:10px;background:var(--border-light);color:var(--text-secondary);margin-left:6px}
.badge-custom{display:inline-block;font-size:var(--fs-xs);font-weight:500;padding:1px 5px;border-radius:4px;background:#eff6ff;color:#1d4ed8;margin-left:5px}
.cat-badge{display:inline-block;font-size:var(--fs-sm);padding:2px 8px;border-radius:4px;font-weight:500}
.cat-badge--income{background:var(--income-bg);color:var(--income)}
.cat-badge--expense{background:var(--expense-bg);color:var(--expense)}
.cat-badge--transfer{background:#f3e8ff;color:#7e22ce}
.cat-badge--payment{background:#fef3c7;color:#b45309}
/* Category reorder (drag-and-drop on /categories) — handle column,
   dragged-row state, drop-target highlight, and budget-group
   separator rows inside the Expense card. The handle is a static
   text glyph; the row is draggable=true so the entire row is the
   drag source, with the handle providing the visual affordance. */
.cat-reorder-row{cursor:grab}
.cat-reorder-row:active{cursor:grabbing}
.cat-reorder-row.is-dragging{opacity:.45}
.cat-reorder-row.is-drop-target{box-shadow:inset 0 2px 0 0 var(--accent);background:var(--table-row-hover-bg)}
.cat-reorder-handle{width:24px;color:var(--text-muted);font-weight:700;letter-spacing:-2px;text-align:center;cursor:grab;user-select:none}
.cat-reorder-sep td{padding-top:.85rem;padding-bottom:.25rem;font-size:var(--fs-xs);font-weight:600;text-transform:uppercase;letter-spacing:.05em;border-bottom:1px solid var(--border-light)}
.cat-reorder-sep{cursor:default}
.lines-chip{display:inline-block;font-size:var(--fs-xs);margin-left:6px;padding:1px 6px;border-radius:3px;background:#eef2ff;color:#4338ca;font-weight:500}
.verify-banner{display:flex;align-items:center;gap:.6rem;padding:.7rem 1rem;margin:-.5rem 0 1rem;border-radius:8px;background:#fff7ed;color:#9a3412;border:1px solid #fed7aa;font-size:var(--fs-base)}
/* alert-banner — unified top-of-page banner. One component, three
   severity variants (critical/warn/info). Replaces both the old
   .critical-banner (notification-record-driven) and .outcome-alert
   (score-derived) blocks that had drifted into separate visual
   languages. Driven by .NotificationMeta.Critical, which now
   surfaces the newest unread notification at severity ≥ warn.
   Layout: icon · title+body stack · CTA pill · × dismiss. Mobile
   reflow at 640px stacks the cluster vertically. */
.alert-banner{display:flex;align-items:flex-start;gap:.9rem;padding:1rem 1.2rem;margin:0 0 1.2rem;border-radius:var(--radius-lg);border:1px solid;font-size:var(--fs-base);line-height:1.45}
.alert-banner__icon{font-size:1.4rem;line-height:1;flex:0 0 auto;padding-top:.1rem}
.alert-banner__body{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:.2rem}
.alert-banner__title{display:block;font-weight:600;font-size:var(--fs-md)}
.alert-banner__text{margin:0;font-size:var(--fs-sm);opacity:.9}
.alert-banner__action{flex:0 0 auto;align-self:center;font-weight:600;font-size:var(--fs-sm);text-decoration:none;padding:.45rem .9rem;border-radius:999px;border:1px solid currentColor;white-space:nowrap;color:inherit}
.alert-banner__action:hover{background:rgba(0,0,0,.06)}
.alert-banner__dismiss-form{margin:0;flex:0 0 auto;align-self:flex-start}
.alert-banner__dismiss{background:none;border:none;cursor:pointer;font-size:var(--fs-lg);line-height:1;padding:.2rem .4rem;color:inherit;opacity:.55}
.alert-banner__dismiss:hover{opacity:1}
.alert-banner__dismiss:focus-visible{outline:2px solid currentColor;outline-offset:2px;border-radius:.25rem}
.alert-banner--critical{background:#fdf2f2;color:#7f1d1d;border-color:#fca5a5}
.alert-banner--warn{background:#fffbeb;color:#92400e;border-color:#fcd34d}
.alert-banner--info{background:#eff6ff;color:#1e3a8a;border-color:#93c5fd}
@media(max-width:640px){.alert-banner{flex-direction:column;align-items:stretch}.alert-banner__action{align-self:flex-start}.alert-banner__dismiss-form{position:absolute;top:.5rem;right:.5rem}.alert-banner{position:relative}}
.verify-banner__icon{font-size:var(--fs-lg);flex:0 0 auto}
.verify-banner__msg{flex:1 1 auto;line-height:1.4}
.settings-section{margin-bottom:1.5rem;padding:1.25rem 1.5rem}
.settings-h{font-size:var(--fs-md);font-weight:600;margin:0 0 1rem;padding-bottom:.6rem;border-bottom:1px solid var(--border-light)}
/* .settings-back was the per-settings-sub-page back-link style; the four
 * sub-pages that used it (Account/Appearance/Security/Profile) now render
 * via page_header_lead which uses .page-header__back — same visual, one
 * source of truth. Class removed. */

/* Hub tiles — 5 stacked tap targets on the /settings page. Each tile
 * is an <a> sized for touch (≥56px tall). Width capped at 680px so
 * the column reads well on a wide monitor without stretching across
 * the full main-inner area. Phone view inherits the cap and naturally
 * collapses since 680 > 360. */
.settings-tiles{display:flex;flex-direction:column;gap:.5rem;max-width:680px}
.settings-tile{
  display:flex;align-items:center;gap:1rem;
  /* min-height keeps every tile the same size regardless of how
   * many lines the description wraps to. Combined with the icon's
   * fixed square container + the chevron's fixed font-size, the
   * row reads as a uniform grid: icons line up horizontally down
   * the column, chevrons line up on the right, titles line up on
   * the same baseline. */
  min-height:64px;
  padding:1rem 1.25rem;
  background:var(--bg-card);border:1px solid var(--border-light);
  border-radius:var(--radius-lg);
  text-decoration:none;color:inherit;
  transition:border-color .12s,background .12s;
}
.settings-tile:hover{border-color:var(--accent);background:rgba(0,0,0,.02)}
/* Icon container — a 2rem square box centered on the row. Emojis
 * render at different glyph sizes; the fixed square + inline-flex
 * centering keeps the visual anchor point consistent across rows
 * (so 👤 vs 💳 vs 📦 all sit on the same x-coordinate). */
.settings-tile__icon{
  flex:0 0 2rem;width:2rem;height:2rem;
  display:inline-flex;align-items:center;justify-content:center;
  font-size:1.5rem;line-height:1;
}
.settings-tile__body{flex:1;display:flex;flex-direction:column;gap:.15rem;min-width:0}
.settings-tile__title{font-size:var(--fs-base);font-weight:600;color:var(--text-primary);line-height:1.3}
.settings-tile__desc{font-size:var(--fs-sm);color:var(--text-muted);line-height:1.4}
/* Chevron — same fixed box treatment so it lines up on the right
 * edge regardless of icon or body content. */
.settings-tile__chevron{
  flex:0 0 1.25rem;width:1.25rem;height:1.25rem;
  display:inline-flex;align-items:center;justify-content:center;
  font-size:1.4rem;color:var(--text-muted);line-height:1;
}
.settings-form{display:flex;flex-direction:column;gap:.35rem;max-width:480px}
.settings-form .btn{margin-top:.75rem;align-self:flex-start}
.settings-inline-form{display:inline-block;margin-top:.5rem}
.settings-row{display:flex;align-items:center;gap:.6rem;margin:0 0 .75rem}
.settings-label{color:var(--text-secondary);font-size:var(--fs-base)}
.settings-pending{background:#fff7ed;border:1px solid #fed7aa;border-radius:8px;padding:.75rem 1rem;margin-top:.75rem;color:#9a3412;font-size:var(--fs-base)}
.settings-pending p{margin:0 0 .5rem}
.settings-link-strip{margin-top:1rem;padding:.6rem .85rem;border-radius:6px;background:rgba(0,0,0,.02);font-size:var(--fs-sm);color:var(--text-muted);display:flex;flex-wrap:wrap;align-items:center;gap:.4rem;line-height:1.6}
.settings-link-strip__label{font-weight:600;color:var(--text-secondary);margin-right:.25rem}
.settings-link-strip__sep{opacity:.5}
.settings-link-strip__locked{opacity:.65;display:inline-flex;align-items:center;gap:.3rem}
.badge--ok{background:#d1fae5;color:#065f46;padding:1px 7px;border-radius:4px;font-size:var(--fs-xs);font-weight:600}
.badge--warn{background:#fef3c7;color:#92400e;padding:1px 7px;border-radius:4px;font-size:var(--fs-xs);font-weight:600}
.badge--pro{background:#1e40af;color:#fff;padding:1px 7px;border-radius:4px;font-size:var(--fs-xs);font-weight:600;letter-spacing:.04em;margin-left:.4rem}
.badge--pro-locked{background:#e5e7eb;color:#6b7280;padding:1px 7px;border-radius:4px;font-size:var(--fs-xs);font-weight:600;letter-spacing:.04em;margin-left:.4rem}
.mfa-enroll{display:flex;gap:1.25rem;align-items:flex-start}
.mfa-qr{flex:0 0 auto;border-radius:6px;background:#fff;padding:6px}
.mfa-enroll-side{flex:1 1 auto}
.mfa-secret{background:var(--surface-2);padding:.6rem .8rem;border-radius:6px;font-size:var(--fs-base);font-family:ui-monospace,monospace;display:inline-block}
.mfa-codes{background:var(--surface-2);padding:.8rem 1rem;border-radius:6px;font-family:ui-monospace,monospace;font-size:var(--fs-base);line-height:1.7;letter-spacing:.05em;white-space:pre;user-select:all}
.mfa-codes-warning{background:#fff7ed;border:1px solid #fed7aa;border-radius:6px;padding:.6rem .8rem;color:#7c2d12}
.mfa-codes-actions{display:flex;align-items:center;gap:.6rem;margin-top:.6rem}
.mfa-confirm-saved{display:flex;align-items:center;gap:.5rem;margin-bottom:.75rem;font-size:var(--fs-base);color:var(--text-secondary)}
.mfa-confirm-saved input{margin:0}
#mfa-confirm-btn:disabled{opacity:.55;cursor:not-allowed}
.recipient-list{list-style:none;padding:0;margin:0 0 1rem}
.recipient-row{display:flex;justify-content:space-between;align-items:center;padding:.5rem .25rem;border-bottom:1px solid var(--border-light)}
.recipient-row:last-child{border-bottom:0}
.balance-label{font-size:var(--fs-xs);font-weight:500;opacity:.7;text-transform:uppercase;letter-spacing:.04em;margin-left:.25rem}

/* ── Reconcile button ─────────────────────────────────────────────────────── */
.reconcile-btn{width:22px;height:22px;border-radius:50%;border:1.5px solid var(--border);background:transparent;font-size:var(--fs-xs);color:var(--text-muted);display:inline-flex;align-items:center;justify-content:center;transition:all .12s;padding:0}
.reconcile-btn:hover{border-color:var(--income);color:var(--income);background:var(--income-bg)}
.reconcile-btn--done{border-color:var(--income);background:var(--income-bg);color:var(--income)}
.reconcile-btn--lg{width:28px;height:28px;font-size:var(--fs-base)}

/* ── Month nav ─────────────────────────────────────────────────────────────── */
.month-nav{display:flex;align-items:center;gap:16px;margin-bottom:1.25rem}
.month-nav-label{font-size:var(--fs-base);font-weight:600;min-width:120px;text-align:center}
.month-nav-btn{font-size:var(--fs-sm);color:var(--text-secondary);padding:4px 10px;border:1px solid var(--border);border-radius:6px;background:var(--bg-card);transition:all .12s}
.month-nav-btn:hover{border-color:var(--accent);color:var(--accent)}

/* ── Filter bar (legacy) ─────────────────────────────────────────────────── */
.filter-bar{display:flex;align-items:center;gap:8px;margin-bottom:1rem;flex-wrap:wrap}

/* ── Filter panel (new compact style) ───────────────────────────────────── */
.filter-panel{display:flex;align-items:center;gap:10px;padding:10px 14px;background:var(--bg-card);border:1px solid var(--border-light);border-radius:var(--radius);margin-bottom:1rem;flex-wrap:wrap}
.filter-group{display:flex;align-items:center;gap:5px}
.filter-label{font-size:var(--fs-sm);font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.04em;white-space:nowrap}
.filter-select{width:auto;min-width:90px;max-width:180px}
/* Transactions day-filter: wide enough that the year + the native
   date-picker / clear icons aren't clipped (the old .filter-select
   180px cap overlaid the last year digit). Uses .form-control (no
   select chevron) so nothing sits over the native calendar control. */
.txn-date-filter{width:auto;min-width:13rem;max-width:none}
/* Custom placeholder for the always-type=date day filter. The overlay
   span sits on top of the (text-hidden) empty input; pointer-events:
   none so a single click reaches the input and opens the native
   picker. ledger.js toggles .showing-native (focused or has a value).*/
.txn-date-wrap{position:relative;display:inline-block;vertical-align:middle}
.txn-date-wrap:not(.showing-native) .txn-date-filter{color:transparent}
.txn-date-ph{
  position:absolute;left:.65rem;top:50%;transform:translateY(-50%);
  pointer-events:none;color:var(--text-muted);font-size:var(--fs-sm);
  white-space:nowrap;
}
.txn-date-wrap.showing-native .txn-date-ph{display:none}
.filter-clear{margin-left:auto}

/* ── Direction toggle ────────────────────────────────────────────────────── */
.dir-toggle{display:flex;gap:0;border:1px solid var(--border);border-radius:6px;overflow:hidden;width:fit-content}
.dir-btn{display:flex;align-items:center;gap:6px;padding:.4rem .9rem;cursor:pointer;font-size:var(--fs-base);color:var(--text-secondary);transition:background .1s,color .1s}
.dir-btn:first-child{border-right:1px solid var(--border)}
.dir-btn input[type=radio]{display:none}
.dir-btn:has(input:checked){background:var(--accent);color:#fff}

/* ── Flow badge ──────────────────────────────────────────────────────────── */
.flow-badge{display:inline-block;font-size:var(--fs-xs);font-weight:600;letter-spacing:.05em;text-transform:uppercase;padding:.1em .45em;border-radius:4px;margin-left:5px;vertical-align:middle}
.flow-badge--asset{background:#d1fae5;color:#065f46}
.flow-badge--liability{background:#fee2e2;color:#991b1b}
.flow-badge--general{background:#e0e7ff;color:#3730a3}

/* ── Totals strip ─────────────────────────────────────────────────────────── */
.totals-strip{display:flex;align-items:center;gap:12px;padding:.625rem 1rem;background:var(--bg-card);border:1px solid var(--border-light);border-radius:var(--radius);margin-bottom:1rem;font-size:var(--fs-base)}
.totals-item{display:flex;gap:6px;align-items:center}
.totals-sep{color:var(--border)}

/* ── Budget ─────────────────────────────────────────────────────────────── */
.budget-list{padding:.5rem 1.25rem 1rem}
.budget-row{margin-bottom:1rem}
.budget-row:last-child{margin-bottom:0}
.budget-meta{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:5px}
.budget-cat{font-size:var(--fs-base);font-weight:500}
.budget-amounts{font-size:var(--fs-sm);color:var(--text-muted)}
.progress-track{height:5px;background:var(--border-light);border-radius:3px;overflow:hidden;margin-bottom:3px}
.progress-track--inline{margin-top:4px;margin-bottom:0}
.progress-fill{height:100%;background:var(--income);border-radius:3px;transition:width .3s}
.progress-fill--warn{background:#f59e0b}
.progress-fill--danger{background:var(--expense)}
.budget-pct{font-size:var(--fs-sm);color:var(--text-muted)}
.budget-table-cat{display:flex;flex-direction:column;gap:2px}

/* ── Account cards ─────────────────────────────────────────────────────────── */
.account-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:14px;margin-bottom:1.5rem}
.account-card{background:var(--bg-card);border:1px solid var(--border-light);border-radius:var(--radius-lg);padding:1.25rem;box-shadow:var(--shadow);position:relative}
/* Liability cards visually differentiated from assets: rose-tinted background,
   matching left border, and a small "Liability" tag in the header. Asset cards
   are unchanged so the eye picks out debts at a glance. */
.account-card--liability{background:#fff1f2;border-left:3px solid #f43f5e}
.account-class-tag{font-size:var(--fs-xs);letter-spacing:.06em;text-transform:uppercase;font-weight:600;padding:2px 6px;border-radius:4px;background:#fee2e2;color:#9f1239;margin-left:.4rem}
.account-card-top{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem;gap:.4rem}
.account-card-top .account-type-badge{margin-right:auto}
.account-card-top .action-link{margin-left:auto}
.account-type-badge{font-size:var(--fs-xs);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--text-muted)}
.account-name{font-size:var(--fs-md);font-weight:600;margin-bottom:.5rem}
/* E07 — marks bank-linked accounts vs manually-added ones. Sits inline
   before the name, baseline-aligned, in the accent colour. */
.account-linked-icon{
  width:15px;height:15px;flex:0 0 auto;
  color:var(--accent);vertical-align:-2px;margin-right:.35rem;
}
.account-balance{font-size:var(--fs-2xl);font-weight:600;letter-spacing:-.02em;font-family:var(--font-mono);margin-bottom:.5rem}
.account-meta{font-size:var(--fs-sm);color:var(--text-muted);margin-bottom:.75rem}
/* Tech-12 — provider liability detail line (APR/min/due) on debt cards. */
.liability-detail{display:flex;flex-wrap:wrap;align-items:center;gap:.15rem}
.account-txn-link a{font-size:var(--fs-sm);color:var(--accent);font-weight:500}
.account-txn-link a:hover{text-decoration:underline}

/* ── Info / success / empty ─────────────────────────────────────────────── */
.info-card{background:var(--bg-card);border:1px solid var(--border-light);border-radius:var(--radius);padding:1rem 1.25rem;margin-bottom:1.5rem}
.info-card-steps{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.info-step{display:flex;align-items:center;gap:7px;font-size:var(--fs-sm);color:var(--text-secondary)}
.info-step-num{width:20px;height:20px;border-radius:50%;background:var(--sidebar-bg);color:#fff;font-size:var(--fs-xs);font-weight:600;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0}
.info-step-sep{color:var(--border);font-size:var(--fs-sm)}
.success-card{display:flex;align-items:center;gap:16px;background:var(--income-bg);border:1px solid #b7e8d8;border-radius:var(--radius-lg);padding:1.25rem 1.5rem;margin-bottom:1.5rem;color:var(--income)}
.success-icon{font-size:var(--fs-2xl);font-weight:700}
.success-card strong{display:block;font-weight:600;margin-bottom:2px}
.success-card p{font-size:var(--fs-base);margin:0;opacity:.8}
.empty-state{padding:1.5rem 1.25rem;font-size:var(--fs-base);color:var(--text-muted);text-align:center}
.empty-state a{color:var(--accent)}
.empty-card{text-align:center;padding:3rem 2rem;background:var(--bg-card);border:1px solid var(--border-light);border-radius:var(--radius-lg);color:var(--text-secondary)}
.empty-card p{margin-bottom:1rem}

/* ── Forms ─────────────────────────────────────────────────────────────── */
/* Single-column forms cap at 560px — comfortable scan length for an
 * email/password-style stack. Forms that contain a .form-row--2
 * (multi-column row) widen to 880px so each 2-col cell gets ~420px
 * of usable width instead of cramming dropdowns + selects into
 * ~270px each. `:has()` is supported by all evergreen browsers as of
 * Safari 15.4 / Chrome 105 / Firefox 121; older browsers fall through
 * to the 560px baseline (degraded but functional). Mobile is
 * unaffected — viewport ≪ 880px clamps via the natural sizing. */
.form-wrap{max-width:560px}
.form-wrap:has(.form-row--2){max-width:880px}
.form-group{margin-bottom:1.25rem}
.form-row{display:grid;gap:14px}
.form-row--2{grid-template-columns:1fr 1fr}
.form-label{display:block;font-size:var(--fs-base);font-weight:500;color:var(--text-primary);margin-bottom:6px}
.form-optional{font-size:var(--fs-xs);font-weight:400;color:var(--text-muted);margin-left:4px}
.form-required{font-size:var(--fs-xs);font-weight:500;color:#b91c1c;margin-left:4px;text-transform:uppercase;letter-spacing:.04em}
.form-hint{font-size:var(--fs-sm);color:var(--text-muted);margin-top:5px}
.form-error{font-size:var(--fs-sm);color:var(--expense);margin-top:4px}
.form-control,.form-select{display:block;width:100%;padding:.5rem .75rem;font-size:var(--fs-base);font-family:var(--font-sans);color:var(--text-primary);background:var(--bg-card);border:1px solid var(--border);border-radius:6px;transition:border-color .12s,box-shadow .12s;appearance:none;-webkit-appearance:none}
.form-select{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%238b929e' d='M4.5 6l3.5 4 3.5-4z'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right .5rem center;background-size:16px;padding-right:2rem}
.form-control:focus,.form-select:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px rgba(26,127,100,.12)}
.form-control::placeholder{color:var(--text-muted)}
.form-control.form-control-sm,.form-select.form-select-sm{padding:.35rem .65rem;font-size:var(--fs-sm)}

/* ── seg-control — segmented-radio "pill group" for small fixed enums (≤4
   options). Native <input type="radio"> under the hood, so a11y is
   automatic (radiogroup + arrow-key nav). The visible chip is a sibling
   span; the input is screen-reader-only via :sr-only-equivalent positioning.
   Use when all options + their meaning matter at a glance (vs a quiet
   <select> for data pickers or long lists). */
.seg-control{display:inline-flex;border:1px solid var(--border);border-radius:8px;background:var(--bg-card);padding:2px;gap:2px;vertical-align:middle}
/* On narrow viewports the long-label seg-controls (e.g. the account
 * classification "Asset (income-side) / Liability (expense-side) /
 * General (both)") can't fit all three nowrap chips in one row.
 * Opt-in modifier lets the group wrap to multiple rows instead of
 * clipping. Used by the /accounts edit form's classification row. */
.seg-control--wrap{display:flex;flex-wrap:wrap}
.seg-control__item{cursor:pointer;display:inline-flex;margin:0}
.seg-control__item input{position:absolute;opacity:0;width:1px;height:1px;pointer-events:none}
.seg-control__chip{padding:.38rem .75rem;font-size:var(--fs-sm);font-weight:500;color:var(--text-secondary);border-radius:6px;line-height:1.2;display:inline-flex;align-items:center;transition:background .12s,color .12s;white-space:nowrap}
.seg-control__item:hover .seg-control__chip{color:var(--text-primary)}
.seg-control__item input:focus-visible + .seg-control__chip{outline:2px solid var(--accent);outline-offset:2px}
.seg-control__item input:checked + .seg-control__chip{background:var(--accent);color:#fff}
.seg-control__item input:checked:focus-visible + .seg-control__chip{outline-color:transparent}
.input-prefix{position:relative}
.input-prefix-symbol{position:absolute;left:.75rem;top:50%;transform:translateY(-50%);color:var(--text-muted);font-size:var(--fs-base);pointer-events:none}
.input-prefix .form-control{padding-left:1.75rem}
.form-actions{display:flex;align-items:center;gap:10px;padding-top:.5rem;border-top:1px solid var(--border-light);margin-top:1.5rem}
.delete-form{margin-left:auto}
.divider{border:none;border-top:1px solid var(--border-light);margin:1.25rem 0}

/* ── Buttons ─────────────────────────────────────────────────────────────── */
.btn{display:inline-flex;align-items:center;gap:6px;padding:.5rem 1rem;font-size:var(--fs-base);font-weight:500;border-radius:100px;border:1px solid transparent;transition:all .12s;white-space:nowrap;font-family:var(--font-sans)}
.btn-primary{background:var(--accent);color:#fff;border-color:var(--accent);box-shadow:0 2px 8px rgba(27,58,45,.18)}
.btn-primary:hover{background:var(--accent-soft);border-color:var(--accent-soft);transform:translateY(-1px);box-shadow:0 4px 12px rgba(27,58,45,.22)}
.btn-outline{background:var(--bg-card);color:var(--text-secondary);border-color:var(--border)}
.btn-outline:hover{border-color:var(--accent);color:var(--accent)}
.btn-ghost{background:transparent;color:var(--text-muted);border-color:transparent}
.btn-ghost:hover{background:var(--border-light);color:var(--text-primary)}
.btn-danger{background:var(--expense-bg);color:var(--expense);border-color:#fca5a5}
.btn-danger:hover{background:#fce8e8}
.btn-sm{padding:.3rem .75rem;font-size:var(--fs-sm)}
.btn-full{width:100%;justify-content:center}

/* ── Toast notifications ────────────────────────────────────────────────
   Fixed-position floating message at the bottom-center of the viewport.
   Lives outside the document flow so showing/hiding never reflows page
   content. Auto-dismiss + fade-out run from ledger.js after ~4 seconds;
   the close button (and clicking the toast body) also dismiss early.
   Translucent border on the success/error/warning variants matches the
   existing palette (income / expense / warn). */
.toast{
  position:fixed; left:50%; top:1.25rem; transform:translateX(-50%);
  display:flex; align-items:center; gap:.85rem;
  min-width:220px; max-width:calc(100vw - 2rem);
  padding:.75rem 1rem .75rem 1.1rem; border-radius:10px;
  font-size:var(--fs-base); line-height:1.4;
  background:var(--income-bg); color:var(--income); border:1px solid #b7e8d8;
  box-shadow:0 12px 28px rgba(0,0,0,.18), 0 2px 6px rgba(0,0,0,.10);
  z-index:1000;
  animation:toast-in .25s ease-out;
}
.toast-error,.toast-danger{background:var(--expense-bg); color:var(--expense); border-color:#fca5a5}
.toast-warning{background:var(--warn-bg); color:var(--warn); border-color:#fcd34d}
.toast-msg{flex:1}
.toast-close{
  background:transparent; border:0; color:inherit; opacity:.6; cursor:pointer;
  font-size:var(--fs-lg); line-height:1; padding:0 .25rem; font-family:inherit;
}
.toast-close:hover{opacity:1}
@keyframes toast-in{
  from{opacity:0; transform:translate(-50%, -12px)}
  to  {opacity:1; transform:translate(-50%, 0)}
}
@media (prefers-reduced-motion: reduce){
  .toast{animation:none}
}

/* ── Responsive ─────────────────────────────────────────────────────────── */
@media(max-width:900px){
  .two-col{grid-template-columns:1fr}
  .stat-grid--3{grid-template-columns:1fr 1fr}
}
/* ── Mobile shell (≤768px) — canonical breakpoint ───────────────────────
   Replaces the old 56px icon-rail. The fixed sidebar becomes an
   off-canvas drawer opened by the app-bar hamburger. Two open
   mechanisms, both supported:
     • JS (ledger.js)  → toggles `.is-open` + manages aria/scroll-lock/Esc
     • No-JS fallback  → the burger is <a href="#sidebar">, so
                          `.sidebar:target` opens it; the scrim is
                          <a href="#"> which clears the hash to close.
   Multi-column grids collapse here too (desktop grid behaviour is left
   untouched above — protects the "desktop identical" constraint). */
@media(max-width:768px){
  /* Day filter: full-width on phones so the date box + native picker
     aren't squished inside the wrapping filter panel. */
  .filter-group--wide{flex:1 1 100%}
  .txn-date-wrap{display:block;width:100%}
  .txn-date-filter{width:100%;min-width:0}

  .appbar{
    display:flex;align-items:center;gap:var(--sp-3);
    /* z-index 50 puts the appbar (and its ☰ burger) above the open
     * drawer (sidebar gets z-index:40 below). Without this lift the
     * drawer covers the burger when open, leaving scrim-tap or Esc
     * as the only ways to close it — the burger's own click handler
     * in ledger.js can close it, but only if the user can see it.
     * The same fix is mirrored under :root[data-effective-layout=
     * "mobile"] in ledger.mobile.css for the explicit mobile toggle. */
    position:sticky;top:0;z-index:50;
    padding:var(--sp-3) var(--sp-4);
    background:var(--sidebar-bg);border-bottom:1px solid var(--sidebar-border);
  }
  .appbar-burger{
    display:inline-flex;align-items:center;justify-content:center;
    width:40px;height:40px;border-radius:var(--radius);
    color:var(--sidebar-text-hover);background:transparent;border:0;
    font-size:var(--fs-lg);line-height:1;
  }
  .appbar-burger:hover{background:rgba(255,255,255,.06)}
  .appbar-title{font-size:var(--fs-sm);font-weight:600;letter-spacing:.12em;color:var(--sidebar-text-hover)}

  .layout{display:block}
  .sidebar{
    width:min(82vw,300px);
    transform:translateX(-100%);
    transition:transform .22s ease;
    box-shadow:var(--elev-3);z-index:40;
  }
  .sidebar:target,.sidebar.is-open{transform:none}

  .scrim{
    display:block;position:fixed;inset:0;z-index:35;
    background:rgba(2,6,23,.55);
    opacity:0;pointer-events:none;transition:opacity .22s ease;
  }
  .sidebar:target ~ .scrim,
  .sidebar.is-open ~ .scrim,
  body.drawer-open .scrim{opacity:1;pointer-events:auto}

  .main{margin-left:0}
  .main-inner{padding:var(--sp-4)}

  /* Stack the page-header title row + its action buttons. */
  .page-header{flex-direction:column;gap:var(--sp-3);align-items:stretch}
  .page-header-actions{flex-wrap:wrap}

  /* Grid collapse catch-all (desktop column rules untouched above). */
  .two-col,.stat-grid,.stat-grid--2,.stat-grid--3,
  .account-grid,.account-mini-grid,.goal-grid,.badge-grid,
  .template-grid,.quick-log-grid,.income-card-grid,
  .persona-grid,.form-row,.custom-weights{
    grid-template-columns:1fr;
  }

  /* Comfortable tap targets + no iOS zoom-on-focus (inputs ≥16px). */
  .btn,.nav-item,.appbar-burger{min-height:44px}
  input,select,textarea{font-size:16px}

  /* Tables → stacked label/value cards. thead is visually hidden (kept
     for a11y); each row becomes a card; each cell shows its column name
     from data-label. Cells without a data-label (action buttons) just
     render right-aligned with no label. */
  .card--table{padding:var(--sp-3)}
  .ledger-table thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
  .ledger-table,.ledger-table tbody,.ledger-table tr,.ledger-table td{display:block;width:auto}
  .ledger-table tr{
    background:var(--bg-card);border:1px solid var(--border-light);
    border-radius:var(--radius-lg);box-shadow:var(--elev-1);
    margin-bottom:var(--sp-3);padding:var(--sp-2) var(--sp-4);
  }
  .ledger-table tbody tr:last-child{margin-bottom:0}
  .ledger-table tbody tr:hover{background:var(--bg-card)}
  .ledger-table td{
    display:flex;justify-content:space-between;align-items:baseline;
    gap:var(--sp-4);text-align:right;
    padding:var(--sp-2) 0;border:0;
    border-bottom:1px solid var(--border-light);
  }
  .ledger-table td:last-child{border-bottom:0}
  .ledger-table td::before{
    content:attr(data-label);
    flex:0 0 auto;text-align:left;
    font-size:var(--fs-xs);font-weight:600;letter-spacing:.04em;
    text-transform:uppercase;color:var(--text-muted);
  }

  /* Overflow safety net — nothing should push the page sideways on a
     phone. Media (incl. SVG charts) caps to its container; the score
     ring + the 2-col scorecard stack. */
  img,svg,canvas,video{max-width:100%;height:auto}
  .scorecard{grid-template-columns:1fr;gap:var(--sp-4);text-align:center}
  .scorecard-overall{flex-direction:column}

  /* Calendar stays a 7-col month grid (columns keep aligned via 1fr)
     but tightens so it fits a 375px viewport without overflow. */
  .cal-grid-head,.cal-week{gap:3px}
  .cal-cell{min-height:60px;padding:3px}
  .cal-chip{font-size:var(--fs-xs)}
  .cal-chip__label{max-width:5ch}
}

@media(max-width:768px) and (prefers-reduced-motion:reduce){
  .sidebar,.scrim{transition:none}
}

/* ── Scorecard ──────────────────────────────────────────────────────────── */
.scorecard{display:grid;grid-template-columns:auto 1fr;gap:24px;align-items:center;background:var(--bg-card);border:1px solid var(--border-light);border-radius:var(--radius);padding:1.25rem 1.5rem;margin-bottom:1.25rem}
.scorecard--compact{padding:1rem 1.25rem;margin-bottom:1rem}
.scorecard-overall{display:flex;align-items:center;gap:14px;text-decoration:none;color:inherit}
.score-context{display:flex;flex-direction:column;gap:2px;font-size:var(--fs-base)}
/* flex-shrink:0 keeps the circle round when its flex parent (e.g.
   .scorecard-overall) tries to compress it sideways to make room for an
   adjacent blurb. Without this the circle ends up egg-shaped at narrow
   widths because width shrinks while height stays fixed. */
.score-circle{width:84px;height:84px;flex-shrink:0;border-radius:50%;display:flex;flex-direction:column;justify-content:center;align-items:center;color:#fff;font-family:var(--font-mono)}
.score-circle.score-good{background:#1a7f64}
.score-circle.score-warn{background:#d97706}
.score-circle.score-bad{background:#b91c1c}
.score-number{font-size:var(--fs-2xl);font-weight:600;line-height:1}
.score-label{font-size:var(--fs-xs);opacity:.75;margin-top:2px}
/* --sm matches the 64x64 fitness rings on /health (see .ring-svg) so the
   per-pillar icon on /health/breakdown has the same visual footprint as
   its counterpart on the scorecard. Inner text scales proportionally:
   20px score number = round(26 * 64/84); 10px label keeps the prior floor. */
.score-circle--sm{width:64px;height:64px;flex-shrink:0}
.score-circle--sm .score-number{font-size:var(--fs-xl)}
.score-circle--sm .score-label{font-size:var(--fs-xs)}
.score-circle-link{display:inline-block;text-decoration:none;color:inherit;border-radius:50%;transition:transform .12s,box-shadow .12s}
.score-circle-link:hover{transform:scale(1.04);box-shadow:0 0 0 4px rgba(110,168,255,.12)}

/* ── Rubric (score breakdown) ─────────────────────────────────────────── */
.rubric-list{display:flex;flex-direction:column;gap:.5rem;margin-top:.5rem}
.rubric-row{padding:.75rem .9rem;border-radius:8px;border:1px solid var(--border-light);background:rgba(255,255,255,.02)}
.rubric-row--full{border-color:rgba(26,127,100,.4);background:rgba(26,127,100,.06)}
.rubric-row--partial{border-color:rgba(217,119,6,.35);background:rgba(217,119,6,.04)}
.rubric-row--empty{border-color:rgba(185,28,28,.3);background:rgba(185,28,28,.04)}
.rubric-row-head{display:flex;align-items:baseline;justify-content:space-between;gap:1rem}
.rubric-points{font-size:var(--fs-base);white-space:nowrap}
.rubric-earned{font-size:var(--fs-lg);font-weight:600}
.rubric-detail{margin:.25rem 0;font-size:var(--fs-base);line-height:1.45}
.rubric-actual{margin:.4rem 0 0;font-size:var(--fs-base)}

/* ── Breakdown page (one card per pillar) ─────────────────────────────── */
.breakdown-pillar{padding:1.25rem;margin-bottom:1rem}
.breakdown-pillar-head{display:flex;align-items:center;justify-content:space-between;gap:1rem;padding-bottom:.85rem;border-bottom:1px solid var(--border-light);margin-bottom:.85rem}
.breakdown-pillar-title{text-decoration:none;color:inherit;display:flex;flex-direction:column;gap:2px;flex:1}
.breakdown-pillar-title h2{margin:0;font-size:var(--fs-md);font-weight:600}
.breakdown-pillar-title:hover h2{color:#7dc6ff}
.breakdown-recs{margin-top:1rem;padding-top:1rem;border-top:1px solid var(--border-light)}
.breakdown-recs-title{margin:0 0 .5rem;letter-spacing:.04em;text-transform:uppercase}
.score-blurb{margin:0;color:var(--text-secondary);font-size:var(--fs-base)}
/* Pillar rings — Apple-Watch-style. Each ring is an SVG <circle> whose
   stroke-dasharray=circumference; stroke-dashoffset is computed from the
   per-pillar --score custom property (0..100). The track is the full ring
   in border-light, the fill uses a per-pillar SVG <linearGradient> so the
   colour grades around the arc. Circumference for r=26 is 2π·26 ≈ 163.36. */
/* Ring strip — 9 cells per row on desktop, 3×3 on mobile. Was 8 cols
   (8 pillars pre-#76) and the 9th pillar (Outcome) was wrapping to a
   lonely second row. The 9-col layout fills the row evenly; circles
   are sized larger (80px, was 64) to use the extra height the bigger
   gap creates. CSS-var `--ring-size` lets the ring SVG + score
   position scale together — change in one place. */
.ring-strip{display:grid;grid-template-columns:repeat(9,1fr);gap:8px;--ring-size:80px}
.ring-cell{display:flex;flex-direction:column;align-items:center;gap:2px;padding:.5rem .25rem;text-decoration:none;color:inherit;border-radius:8px;transition:transform .12s,background .12s;position:relative}
.ring-cell:hover{transform:translateY(-1px);background:var(--ring-cell-hover-bg)}
.ring-svg{width:var(--ring-size);height:var(--ring-size);display:block}
.ring-track{fill:none;stroke:var(--border-light);stroke-width:6}
.ring-fill{
  fill:none;
  stroke-width:6;
  stroke-linecap:round;
  stroke-dasharray:163.36;
  /* (1 - score/100) × circumference: a 0-score ring is fully offset (empty);
     a 100-score ring has zero offset (fully filled). */
  stroke-dashoffset:calc(163.36 * (100 - var(--score, 0)) / 100);
  transform:rotate(-90deg);
  transform-origin:50% 50%;
  transition:stroke-dashoffset .6s ease-out;
}
/* Score text centered over the ring. top = ring-size/2 minus half the
   line-height so the digits land on the SVG's centerline regardless
   of --ring-size. font-size bumps with the ring so the number stays
   readable at 80+px. */
.ring-score{position:absolute;top:calc(var(--ring-size)/2 - 0.65em + .5rem);left:0;right:0;text-align:center;font-size:var(--fs-md);font-weight:700;color:var(--text-primary);pointer-events:none}
.ring-label{font-size:var(--fs-xs);text-align:center;color:var(--text-secondary);line-height:1.25;margin-top:4px;font-weight:500}
.ring-weight{font-size:var(--fs-xs);color:var(--text-muted);font-family:var(--font-mono)}
.pillar-detail{display:flex;align-items:center;gap:24px}
.pillar-detail-body{flex:1}
.pillar-status{font-size:var(--fs-base);color:var(--text-secondary);margin:0}
.rec-list{display:flex;flex-direction:column;gap:14px}
.rec-row{display:flex;align-items:center;gap:14px;padding:.75rem 0;border-bottom:1px solid var(--border-light)}
.rec-row:last-child{border-bottom:none}
.rec-body{flex:1}
.rec-body strong{display:block;font-size:var(--fs-base);color:var(--text-primary);margin-bottom:2px}
.rec-body p{margin:0;font-size:var(--fs-base);color:var(--text-secondary)}
.prompt-card--rec{border-color:#a7d4c4;background:linear-gradient(0deg,var(--income-bg),var(--bg-card))}
.strategy-presets{display:flex;flex-direction:column;gap:10px;border:none;padding:0;margin:0}
.strategy-option{display:flex;align-items:flex-start;gap:12px;padding:.85rem 1rem;border:1px solid var(--border-light);border-radius:var(--radius);cursor:pointer}
.strategy-option:has(input:checked){border-color:var(--accent);background:rgba(26,127,100,.04)}
.strategy-option-body{display:flex;flex-direction:column;gap:4px;flex:1}
.weight-mini{display:flex;flex-wrap:wrap;gap:6px;margin-top:4px;font-size:var(--fs-xs);color:var(--text-muted);font-family:var(--font-mono)}
.weight-mini span{padding:1px 5px;border:1px solid var(--border-light);border-radius:3px}
.custom-weights{display:grid;grid-template-columns:repeat(2,1fr);gap:8px 14px;margin-top:8px}
.custom-weights label{display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:var(--fs-sm);color:var(--text-secondary)}
.custom-weights input{width:90px;padding:.3rem .5rem;border:1px solid var(--border);border-radius:5px;font-family:var(--font-mono);font-size:var(--fs-sm)}

@media(max-width:900px){
  .scorecard{grid-template-columns:1fr;gap:14px}
  /* 9 pillars wrap to 3×3 — fully balanced (no orphan row). Bump
     ring-size up a hair since narrower viewports give each cell
     more relative width than the 9-across desktop layout. */
  .ring-strip{grid-template-columns:repeat(3,1fr);--ring-size:88px}
}

/* ── Onboarding ─────────────────────────────────────────────────────────── */
.onboarding-shell{max-width:720px;margin:1rem auto}
.onboarding-progress{display:flex;justify-content:center;gap:8px;margin:0 0 1.5rem}
.step-pill{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:50%;background:var(--border-light);color:var(--text-muted);font-size:var(--fs-base);font-weight:600;font-family:var(--font-mono)}
.step-pill--active{background:var(--sidebar-bg);color:#fff}
.step-pill--done{background:#1a7f64;color:#fff}
.form-section-title{font-size:var(--fs-base);font-weight:600;color:var(--text-primary);margin:.5rem 0 .75rem}
.form-help{font-size:var(--fs-sm);color:var(--text-muted);margin:.25rem 0 .75rem}
.form-row{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.form-label{display:block;font-size:var(--fs-sm);font-weight:500;color:var(--text-secondary);margin:.85rem 0 .35rem}
.checkbox-inline{display:flex;align-items:center;gap:6px;font-size:var(--fs-sm);color:var(--text-secondary);cursor:pointer}
.withholding-grid{display:flex;flex-direction:column;gap:6px}
.withholding-grid-header,.withholding-row{display:grid;grid-template-columns:1.4fr 1.2fr 1fr 50px;gap:10px;align-items:center}
.withholding-grid-header{font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.5px;color:var(--text-muted);padding-bottom:4px;border-bottom:1px solid var(--border-light)}
@media(max-width:680px){
  .form-row,.withholding-row,.withholding-grid-header,.custom-weights{grid-template-columns:1fr}
}

/* ── Income-rule live math strip ──────────────────────────────────────
   Pinned under the Gross/Net inputs on /income/add and /income/{id}/edit.
   Three states keyed by .is-ok | .is-off | .is-empty on the wrapper —
   driven by income_form.js. Tokens follow the rest of the app so light
   and dark variants flow through without per-state hex literals. */
.income-math{
  background:var(--table-header-bg);
  border:1px solid var(--border-light);
  border-radius:var(--radius);
  padding:.75rem 1rem;
  margin-top:.75rem;
  font-size:var(--fs-sm);
  font-family:var(--font-mono);
}
.income-math__row{
  display:flex;justify-content:space-between;align-items:baseline;
  padding:.15rem 0;
}
.income-math__label{color:var(--text-secondary)}
.income-math__val{font-variant-numeric:tabular-nums;color:var(--text-primary)}
.income-math__row--expected{
  border-top:1px dashed var(--border);
  padding-top:.45rem;margin-top:.3rem;
  font-weight:600;
}
.income-math__row--delta .income-math__val{font-weight:600}
.income-math.is-ok  .income-math__row--delta .income-math__val{color:var(--income)}
.income-math.is-off .income-math__row--delta .income-math__val{color:var(--expense)}
.income-math.is-empty .income-math__row--delta .income-math__val{color:var(--text-muted)}
.income-math__hint{
  margin:.6rem 0 0;
  font-family:var(--font-sans);
  font-size:var(--fs-xs);
  color:var(--text-muted);
  line-height:1.4;
}

/* ── Sparkline + goals ──────────────────────────────────────────────────── */
.sparkline{display:block;width:200px;height:40px;color:var(--text-muted);margin-top:6px}
.goal-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:14px}
.goal-card{padding:1rem 1.25rem;display:flex;flex-direction:column;gap:8px}
.goal-header{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}
.goal-name{margin:.25rem 0 0;font-size:var(--fs-md);font-weight:600}
.goal-name a{color:var(--text-primary)}
.goal-numbers{font-size:var(--fs-lg)}
.goal-footer{display:flex;align-items:center;gap:12px;font-size:var(--fs-sm);color:var(--text-muted)}
.progress-fill--success{background:#1a7f64}
.small{font-size:var(--fs-sm)}

/* ── Card body padding ─────────────────────────────────────────────────────
   `.card` is just a chrome container (background + border + radius). When it
   holds a `.card-header`, `.ledger-table`, or `.budget-list`, those inner
   elements supply their own padding and stay edge-flush — that's the
   dashboard pattern. When it holds a form, prose, or one of the wellness
   widgets directly, those need their own body padding or text sits against
   the boundary. Match the 1.25rem horizontal used by .card-header /
   .ledger-table cells so the spacing is visually consistent. */
form.card,
.card > form,
.card > .pillar-detail,
.card > .rec-list,
.card > .strategy-presets {
  padding: 1.25rem;
}

/* ── Income source extras ───────────────────────────────────────────────── */
.auto-pill{display:inline-block;font-size:var(--fs-xs);font-weight:600;letter-spacing:.04em;text-transform:uppercase;padding:1px 7px;border-radius:10px}
.auto-pill--on{background:var(--income-bg);color:var(--income);border:1px solid #b7e8d8}
.auto-pill--off{background:var(--border-light);color:var(--text-muted);border:1px solid var(--border)}
.checkbox-row{display:flex;align-items:flex-start;gap:10px;padding:.5rem 0;font-size:var(--fs-base);line-height:1.5}
.checkbox-row input[type=checkbox]{margin-top:3px;flex-shrink:0}
.checkbox-row strong{display:block;color:var(--text-primary)}

/* ── Dashboard sections ─────────────────────────────────────────────────── */
.dash-section{margin-bottom:1.75rem}
.dash-section-head{display:flex;justify-content:space-between;align-items:baseline;margin:0 0 .65rem;padding:0 .25rem}
.dash-section-title{font-size:var(--fs-base);font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--text-muted);margin:0}
.dash-section-sub{font-size:var(--fs-sm);color:var(--text-muted)}

/* Debt card — canonical view of every household debt on /accounts.
 * Replaces the prior plan-card-plus-table pair that duplicated queue
 * ordering. Each row carries the full term sheet (balance/APR/min/
 * target/due) plus the Edit/Add terms action. Strategy-specific
 * bits (rank badge, recommended monthly payment, cascade arrow) only
 * render for ranked rows. Excluded + paid-off debts still appear so
 * the user can edit terms or re-enroll, with muted treatment. */
.debt-plan-card{margin:0 0 1rem;padding:1.1rem 1.25rem}
.debt-plan-card__head{margin-bottom:.85rem}
.debt-plan-card__title{font-size:var(--fs-md);font-weight:600;margin:0 0 .25rem;font-family:var(--font-serif);letter-spacing:-.005em}
.debt-plan-card__sub{font-size:var(--fs-sm);color:var(--text-muted);margin:0;line-height:1.5}
.debt-plan-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.65rem}
.debt-plan-row{border:1px solid var(--border-light);border-radius:6px;padding:.75rem .9rem;background:var(--bg-card)}
.debt-plan-row--target{border-color:#fcd34d;background:rgba(254,243,199,.25)}
.debt-plan-row--excluded,.debt-plan-row--paid{opacity:.72}
.debt-plan-row--paid .debt-plan-row__name{text-decoration:line-through;text-decoration-color:rgba(0,0,0,.25)}

.debt-plan-row__head{display:flex;align-items:baseline;gap:.65rem;flex-wrap:wrap}
.debt-plan-row__rank{font-size:var(--fs-xs);font-weight:600;letter-spacing:.02em;padding:2px 8px;border-radius:4px;background:#e5e7eb;color:#6b7280;white-space:nowrap;flex:0 0 auto;text-transform:uppercase}
.debt-plan-row__rank--target{background:#fef3c7;color:#92400e}
.debt-plan-row__rank--muted{background:transparent;color:var(--text-muted);border:1px solid var(--border-light)}
.debt-plan-row__name{font-weight:500;flex:1 1 auto;min-width:0}
.debt-plan-row__amount{font-weight:600;flex:0 0 auto;white-space:nowrap}

.debt-plan-row__promo{margin-top:.45rem;font-size:var(--fs-sm);display:flex;align-items:center;gap:.45rem;flex-wrap:wrap}

/* Terms grid — five label/value pairs (Balance / APR / Min / Target /
 * Due) laid out as a wrapping flex row. Each pair is a tiny stack:
 * muted uppercase label over a mono value. Wraps to multiple lines
 * on narrow viewports without breaking pairs. */
.debt-plan-row__terms{display:flex;flex-wrap:wrap;gap:.85rem 1.4rem;margin:.55rem 0 0;padding:0}
.debt-plan-row__terms > div{display:flex;flex-direction:column;gap:1px;min-width:5rem}
.debt-plan-row__terms dt{font-size:.65rem;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--text-muted);margin:0}
.debt-plan-row__terms dd{margin:0;font-size:var(--fs-sm);color:var(--text-primary)}

.debt-plan-row__split{font-size:var(--fs-sm);margin-top:.45rem;line-height:1.4}
.debt-plan-row__cascade{font-size:var(--fs-sm);color:var(--text-secondary);margin-top:.5rem;padding-top:.5rem;border-top:1px dashed var(--border-light);line-height:1.4}
.debt-plan-row__foot{margin-top:.5rem;padding-top:.45rem;border-top:1px dashed var(--border-light);text-align:right}
.debt-plan-row__foot .action-link{font-size:var(--fs-sm)}

/* Cash-flow card — income vs expense bars on a shared 100% baseline,
   net position summarised below. Bar width comes from the handler so a
   $0/0 month doesn't divide-by-zero. */
.cashflow-card{padding:1.25rem 1.5rem}
.cashflow-row{display:grid;grid-template-columns:80px 1fr 130px 130px;gap:14px;align-items:center;padding:.4rem 0}
.cashflow-row-label{font-size:var(--fs-base);color:var(--text-secondary);font-weight:500}
.cashflow-bar-track{height:14px;background:var(--border-light);border-radius:7px;overflow:hidden}
.cashflow-bar{display:block;height:100%;border-radius:7px;transition:width .4s ease-out}
.cashflow-bar--income{background:linear-gradient(90deg,#34d399,#047857)}
.cashflow-bar--expense{background:linear-gradient(90deg,#fb923c,#c2410c)}
.cashflow-row-amount{font-size:var(--fs-md);font-weight:600;text-align:right}
.cashflow-row-compare{font-size:var(--fs-sm);text-align:right}
.cashflow-net{display:flex;align-items:baseline;gap:14px;margin-top:.85rem;padding-top:.85rem;border-top:1px solid var(--border-light)}
.cashflow-net-label{font-size:var(--fs-sm);text-transform:uppercase;letter-spacing:.06em;color:var(--text-muted);font-weight:600}
.cashflow-net-value{font-size:var(--fs-xl);font-weight:600;letter-spacing:-.02em}
.cashflow-net-tag{font-size:var(--fs-sm);color:var(--text-muted);margin-left:auto}
.cashflow-net--surplus .cashflow-net-value{color:var(--income)}
.cashflow-net--deficit .cashflow-net-value{color:var(--expense)}
/* Net worth row inside the cashflow card — visually a "by the way,
   here's the lifetime number" anchor under the month-level cash flow.
   Lighter weight than .cashflow-net so the month figure still leads. */
.cashflow-networth{display:flex;align-items:baseline;gap:14px;margin-top:.6rem;padding-top:.6rem;border-top:1px dashed var(--border-light);font-size:var(--fs-sm)}
.cashflow-networth-label{text-transform:uppercase;letter-spacing:.06em;color:var(--text-muted);font-weight:600}
.cashflow-networth-value{font-weight:600;letter-spacing:-.01em}
.cashflow-networth-link{margin-left:auto;text-decoration:none;font-size:var(--fs-sm)}
.cashflow-networth-link:hover{text-decoration:underline}

/* Account mini cards — compact tiles for the dashboard's accounts section.
   Distinct from .account-card on /accounts which is roomier. */
.account-mini-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:12px}
.account-mini-card{display:flex;flex-direction:column;gap:4px;padding:.85rem 1rem;background:var(--bg-card);border:1px solid var(--border-light);border-radius:var(--radius);text-decoration:none;color:inherit;transition:border-color .12s,transform .12s}
.account-mini-card:hover{border-color:var(--text-muted);transform:translateY(-1px)}
.account-mini-type{font-size:var(--fs-xs);font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--text-muted)}
.account-mini-name{font-size:var(--fs-base);font-weight:500;color:var(--text-primary)}
.account-mini-balance{font-size:var(--fs-lg);font-weight:600;letter-spacing:-.01em;margin-top:2px}
.account-mini-card--credit .account-mini-balance,
.account-mini-card--mortgage .account-mini-balance,
.account-mini-card--auto_loan .account-mini-balance,
.account-mini-card--personal_loan .account-mini-balance,
.account-mini-card--heloc .account-mini-balance,
.account-mini-card--student_loan .account-mini-balance,
.account-mini-card--line_of_credit .account-mini-balance{color:var(--expense)}
.account-mini-card--investment .account-mini-balance,
.account-mini-card--property .account-mini-balance{color:var(--accent)}

@media(max-width:680px){
  .cashflow-row{grid-template-columns:80px 1fr 110px;gap:10px}
  .cashflow-row-compare{display:none}
  .cashflow-net{flex-wrap:wrap}
  .cashflow-net-tag{margin-left:0;width:100%}
}

/* Page-header action group — multiple buttons aligned to the right of a title. */
.page-header-actions{display:flex;align-items:center;gap:8px}

/* Live weight tally on /health/settings custom strategy editor. */
.weight-tally{font-size:var(--fs-sm);margin:.65rem 0 0;line-height:1.4}
.weight-tally[data-state="ok"]{color:var(--income)}
.weight-tally[data-state="over"]{color:var(--warn)}

/* Strategy list on /health/settings — radio + per-row edit/delete actions. */
.strategy-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:10px}
.strategy-row{display:flex;align-items:flex-start;gap:12px;padding:.85rem 1rem;border:1px solid var(--border-light);border-radius:var(--radius);background:var(--bg-card);transition:border-color .12s,background .12s}
.strategy-row:hover{border-color:var(--text-muted)}
.strategy-row--active{border-color:var(--accent);background:rgba(26,127,100,.04)}
.strategy-row-main{display:flex;align-items:flex-start;gap:12px;flex:1;cursor:pointer}
.strategy-row-main input[type=radio]{margin-top:5px;flex-shrink:0}
.strategy-row-body{display:flex;flex-direction:column;gap:6px;flex:1;min-width:0}
.strategy-row-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:var(--fs-base)}
.strategy-row-head strong{color:var(--text-primary);font-weight:600}
.strategy-row-actions{display:flex;align-items:center;gap:6px;flex-shrink:0}
.badge-active{background:var(--income-bg);color:var(--income);border:1px solid #b7e8d8;font-weight:600;text-transform:uppercase;letter-spacing:.04em}

/* ── E05/S10 — literacy layer ───────────────────────────────────── */

/* Glossary terms — dotted underline + popover on hover/focus.
   Keyboard-accessible via tabindex="0" on the term + :focus-within. */
.glossary-term{position:relative;border-bottom:1px dotted var(--text-muted);cursor:help;outline:none}
.glossary-term:focus,.glossary-term:hover{border-bottom-color:var(--accent)}
.glossary-pop{position:absolute;left:0;top:calc(100% + 6px);z-index:30;display:none;width:max-content;max-width:280px;padding:.55rem .7rem;border-radius:var(--radius);background:var(--bg-card);border:1px solid var(--border-light);box-shadow:var(--elev-2);color:var(--text-primary);font-size:var(--fs-base);line-height:1.45;font-weight:400;cursor:default}
.glossary-term:hover .glossary-pop,.glossary-term:focus .glossary-pop,.glossary-term:focus-within .glossary-pop{display:block}

/* Persona picker — used on /onboarding/welcome (4 cards) and
   /settings/profile (5 cards including Retired). Same shape as the
   scoring-strategy radio cards already in use. */
.persona-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px;margin:.5rem 0 1rem}
.persona-card{position:relative;display:block;padding:.85rem .95rem;border:1px solid var(--border-light);border-radius:var(--radius);background:var(--bg-card);cursor:pointer;transition:border-color .12s,background .12s}
.persona-card:hover{border-color:var(--text-muted)}
.persona-card input[type=radio]{position:absolute;opacity:0;pointer-events:none}
.persona-card input[type=radio]:checked + .persona-card-body{}
.persona-card:has(input[type=radio]:checked){border-color:var(--accent);background:rgba(26,127,100,.04)}
.persona-card-body{display:block}
.persona-card-label{display:block;font-weight:600;color:var(--text-primary);font-size:var(--fs-base);margin-bottom:.2rem}
.persona-card-tag{display:block;color:var(--text-muted);font-size:var(--fs-sm);line-height:1.4}

/* Pillar-detail "Learn about this pillar" collapsible. Built on the
   <details>/<summary> primitive so it works with no JS and is keyboard-
   accessible by default. */
.pillar-lesson{margin:1rem 0 1.5rem;padding:1rem 1.1rem;border:1px solid var(--border-light);border-radius:var(--radius);background:var(--bg-card)}
.pillar-lesson summary{cursor:pointer;font-weight:600;color:var(--text-primary);list-style:none;padding-right:1rem;position:relative}
.pillar-lesson summary::-webkit-details-marker{display:none}
.pillar-lesson summary::after{content:"▸";position:absolute;right:0;top:0;color:var(--text-muted);transition:transform .15s}
.pillar-lesson[open] summary::after{transform:rotate(90deg)}
.pillar-lesson-body{margin-top:.85rem;color:var(--text-primary);line-height:1.55;font-size:var(--fs-base)}
.pillar-lesson-body p{margin:0 0 .65rem}
.pillar-lesson-good{color:var(--text-muted);font-size:var(--fs-base);line-height:1.5;margin:.5rem 0 0;padding:.55rem .7rem;border-left:3px solid var(--accent);background:rgba(26,127,100,.04)}

/* ── E05/S11 — flexible income wizard ─────────────────────────── */

/* Picker grid — same shape as the persona-picker from S10 but tighter
   so all 6 cards fit on a row at desktop widths. */
.income-card-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:10px;margin:.5rem 0 1rem}
.income-card{position:relative;display:flex;align-items:flex-start;gap:.7rem;padding:.85rem .95rem;border:1px solid var(--border-light);border-radius:var(--radius);background:var(--bg-card);cursor:pointer;transition:border-color .12s,background .12s}
.income-card:hover{border-color:var(--text-muted)}
.income-card input[type=checkbox]{position:absolute;opacity:0;pointer-events:none}
.income-card:has(input[type=checkbox]:checked){border-color:var(--accent);background:rgba(26,127,100,.04)}
.income-card-icon{font-size:var(--fs-xl);line-height:1;flex-shrink:0;margin-top:1px}
.income-card-body{display:flex;flex-direction:column;gap:.15rem;min-width:0}
.income-card-label{font-weight:600;color:var(--text-primary);font-size:var(--fs-base)}
.income-card-tag{color:var(--text-muted);font-size:var(--fs-sm);line-height:1.4}

/* Fragments — hidden by default; revealed when their matching picker
   checkbox is :checked. Uses :has() (well-supported in modern
   browsers; older agents see all fragments hidden but the form still
   submits cleanly because picked_X gates parsing). */
.income-fragment{display:none;margin-top:1.25rem;padding-top:1rem;border-top:1px solid var(--border-light)}
.income-wizard-form:has(input[name="picked_paystub"]:checked) .income-fragment[data-for="paystub"]{display:block}
.income-wizard-form:has(input[name="picked_allowance"]:checked) .income-fragment[data-for="allowance"]{display:block}
.income-wizard-form:has(input[name="picked_gig"]:checked) .income-fragment[data-for="gig"]{display:block}
.income-wizard-form:has(input[name="picked_freelance"]:checked) .income-fragment[data-for="freelance"]{display:block}
.income-wizard-form:has(input[name="picked_rental"]:checked) .income-fragment[data-for="rental"]{display:block}
.income-wizard-form:has(input[name="picked_gift"]:checked) .income-fragment[data-for="gift"]{display:block}
.income-fragment-title{font-size:var(--fs-md);font-weight:600;margin:0 0 .65rem;color:var(--text-primary)}

/* Quick log income tiles — dashboard surface for irregular rules. Same
   .account-mini-card-shaped grid for visual consistency, but tinted to
   read as "tap me to log income" (income green hint, plus a + sign). */
.quick-log-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px}
.quick-log-tile{display:flex;flex-direction:column;gap:.25rem;padding:.85rem 1rem;border:1px solid var(--border-light);border-radius:var(--radius);background:var(--bg-card);text-decoration:none;color:inherit;transition:transform .08s,border-color .12s,box-shadow .12s}
.quick-log-tile:hover{border-color:var(--income);box-shadow:0 0 0 1px var(--income-bg);transform:translateY(-1px)}
.quick-log-tile-icon{font-size:var(--fs-xl);line-height:1}
.quick-log-tile-name{font-weight:600;font-size:var(--fs-base);color:var(--text-primary)}
.quick-log-tile-amount{font-size:var(--fs-base);font-weight:600}
.quick-log-tile-acct{font-size:var(--fs-sm)}
/* Past-due variant — amber/warning treatment for recurring charges
 * that slipped past their due date without a logged payment. The
 * extra .quick-log-tile-prompt row sits at the bottom and reads as
 * a soft prompt ("Already paid? Tap to log →"). Border + left-stripe
 * use the existing amber-warn palette so users recognise it as the
 * same severity as overdue cards in /accounts. */
.quick-log-tile--past-due{border-color:#fcd34d;background:rgba(254,243,199,.28);box-shadow:inset 3px 0 0 var(--amber)}
.quick-log-tile--past-due:hover{border-color:var(--amber);box-shadow:inset 3px 0 0 var(--amber-dark),0 0 0 1px var(--amber-light)}
.quick-log-tile--past-due .quick-log-tile-acct{color:#92400e;font-weight:500}
.quick-log-tile-prompt{font-size:var(--fs-sm);color:var(--amber-dark);font-weight:500;margin-top:.15rem}

/* ─── Budget templates (E05/S12) ──────────────────────────────────────────
   Three group buckets — Needs / Wants / Savings — each get a tinted card
   on /budget and a coloured pill on the preview table. Palette borrows
   from the pillar gradients: blue for needs (structural / required),
   purple for wants (discretionary), green for savings (forward-looking).
*/
.group-summary{margin-top:0}
.group-card{border-top:3px solid var(--border-light);position:relative}
.group-card--need{border-top-color:#3b82f6}
.group-card--want{border-top-color:#8b5cf6}
.group-card--savings{border-top-color:#10b981}
.group-card .stat-label{display:flex;align-items:center;justify-content:space-between}
.group-target-pct{font-size:var(--fs-xs);color:var(--text-muted);font-weight:500;letter-spacing:.03em}
.group-target{color:var(--text-muted);font-size:var(--fs-sm);font-weight:500}
.progress-fill--need{background:#3b82f6}
.progress-fill--want{background:#8b5cf6}
.progress-fill--savings{background:#10b981}

/* Template picker — three cards in a grid on /budget/templates */
.template-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:1rem;margin-top:1rem}
.template-card{background:var(--bg-card);border:1px solid var(--border-light);border-radius:var(--radius);padding:1.25rem;display:flex;flex-direction:column;gap:.75rem;transition:border-color .12s,box-shadow .12s}
.template-card:hover{border-color:var(--text-muted)}
.template-card__head{display:flex;flex-direction:column;gap:.25rem}
.template-card__title{margin:0;font-size:var(--fs-lg);font-weight:600}
.template-card__tag{font-size:var(--fs-sm);color:var(--text-muted);text-transform:uppercase;letter-spacing:.04em}
.template-card__desc{margin:0;font-size:var(--fs-base);color:var(--text-secondary);flex:1;line-height:1.45}

/* Preview rows + group pills */
.preview-row td{vertical-align:middle}
.group-pill{display:inline-block;padding:.15rem .55rem;border-radius:999px;font-size:var(--fs-xs);font-weight:600;letter-spacing:.02em;text-transform:uppercase}
.group-pill--need{background:rgba(59,130,246,.12);color:#1d4ed8}
.group-pill--want{background:rgba(139,92,246,.12);color:#6d28d9}
.group-pill--savings{background:rgba(16,185,129,.12);color:#047857}
.group-pill--none{background:var(--border-light);color:var(--text-muted)}
.input-prefix--compact{max-width:8rem;margin-left:auto}
.checkbox-label{display:flex;align-items:center;gap:.5rem;cursor:pointer}

/* ─── Budget vs actual (E05/S13a) ─────────────────────────────────────────
   Inline SVG bar chart + click-to-edit row list on /budget; Budget Health
   tile on the dashboard. Status colors duplicate the inline fills in
   internal/svg/budgetviz.go so theme overrides work without recompiling.
*/
.page-header-actions{display:flex;gap:.5rem;align-items:center}
.budget-chart-card{padding:0;overflow:hidden}
.budget-chart-card .card-header{padding:1rem 1.25rem;border-bottom:1px solid var(--border-light);display:flex;align-items:center;justify-content:space-between}
.card-hint{color:var(--text-muted);font-size:var(--fs-sm)}
.budget-chart-scroll{padding:1rem 1.25rem;overflow-x:auto}
.budget-chart-scroll svg{display:block;max-width:100%;height:auto}
.budget-chart-empty{padding:2rem 1.25rem;text-align:center}

/* Insights summary "stat strip" — small data-anchored text strip
   sitting between the card-header and the chart on each /insights
   card. Gives the user concrete totals, averages, and peaks so the
   chart's shapes have numbers to map against. Wraps gracefully on
   mobile; tabular-nums keeps the dollar figures aligned. */
.insights-stat-strip{
  display:flex;flex-wrap:wrap;gap:.25rem 1.5rem;
  padding:.6rem 1.25rem;
  background:var(--table-header-bg);
  border-bottom:1px solid var(--border-light);
  font-size:var(--fs-sm);
  font-variant-numeric:tabular-nums;
  color:var(--text-secondary);
}
.insights-stat-strip__item{display:inline-flex;align-items:baseline;gap:.35rem;white-space:nowrap}
.insights-stat-strip__label{color:var(--text-muted);font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.04em}
.insights-stat-strip__item strong{color:var(--text-primary);font-weight:600}
.insights-stat-strip__pos{color:var(--income)}
.insights-stat-strip__neg{color:var(--expense)}

.budget-row-list{list-style:none;margin:0;padding:0;border-top:1px solid var(--border-light)}

/* E10 polish — each row now contains its own inline bar (no separate
 * SVG chart above the list). Two grid columns: body (the tappable
 * anchor that opens /budget/category/<id> burndown detail) +
 * actions (✎ edit, × delete). The bar lives inside the body so the
 * whole visual is one cohesive surface.
 *
 * Three CSS custom properties on each <li> drive the bar geometry
 * (server-rendered in BudgetList; --pace-pct is pct-of-month-elapsed
 * which the SP already computes per row):
 *   --actual-pct    width of the actual-spend fill, 0-100
 *   --budgeted-pct  where the budget cap (and overshoot split) sits
 *   --pace-pct      "ghost zone" extent within the budget track —
 *                   a darker shade showing where you SHOULD be by
 *                   now. The fill draws on top; under-pace rows
 *                   show the gap between fill and ghost-zone-end. */
.budget-row{
  display:grid;grid-template-columns:1fr auto;gap:.5rem 1rem;
  align-items:center;padding:.75rem 1.25rem;
  border-bottom:1px solid var(--border-light);transition:background .12s;
}
.budget-row:last-child{border-bottom:0}
.budget-row:hover{background:rgba(0,0,0,.02)}

.budget-row__body{
  display:flex;flex-direction:column;gap:.45rem;
  text-decoration:none;color:inherit;
}
.budget-row__body:hover .budget-row__name{text-decoration:underline}
.budget-row__head{
  display:flex;align-items:baseline;gap:.65rem;flex-wrap:wrap;
}
.budget-row__name{font-weight:500}
.budget-row__values{
  font-size:var(--fs-base);color:var(--text-secondary);
  font-variant-numeric:tabular-nums;
  display:flex;gap:.3rem;align-items:baseline;
  margin-left:auto;                /* push to right side of head row */
}
.budget-row__sep{color:var(--text-muted)}
.budget-row__pct{color:var(--text-muted);font-size:var(--fs-sm)}

/* Actual-spend amount carries the warning colour:
 *   on_track / untracked → readable default
 *   over_pace            → amber (approaching the cap)
 *   over_budget          → red (at or past the cap)
 * The same status colours light up the percentage in parens so the
 * two read together. */
.budget-row__actual{color:var(--text-primary);font-weight:600}
.budget-row--untracked  .budget-row__actual{color:var(--text-secondary);font-weight:500}
.budget-row--over_pace  .budget-row__actual,
.budget-row--over_pace  .budget-row__pct   {color:#b45309;font-weight:600}
.budget-row--over_budget .budget-row__actual,
.budget-row--over_budget .budget-row__pct  {color:var(--expense);font-weight:700}

/* The bar lives directly beneath the head row. Track + fill + tick
 * + overshoot are sibling spans positioned absolutely inside the
 * bar container. Heights match the SVG's old 16px. */
.budget-row__bar{
  position:relative;height:14px;border-radius:3px;
  background:transparent;
}
/* Track = the grey "budget cap" rectangle. Width is --budgeted-pct
 * so it visually represents how much room the cap occupies in the
 * shared maxVal-relative scale. */
.budget-row__bar-track{
  position:absolute;left:0;top:0;bottom:0;
  width:var(--budgeted-pct);
  background:var(--border-light);border-radius:3px;
}
/* Pace zone = a slightly darker shade INSIDE the track, sized by
 * --pace-pct (pct-of-month-elapsed). Because it's a child of
 * .budget-row__bar-track (which is itself absolutely positioned),
 * `width: var(--pace-pct)` resolves against the track's width —
 * e.g. mid-month with budgeted-pct=60 and pace-pct=50, the pace
 * zone extends to 30% of the bar (= 50% of the way through the
 * 60%-wide track). No calc()-multiplication needed.
 *
 * The .budget-row__bar-fill draws on top in DOM order, so:
 *   - Under-pace rows show the pace zone peeking out past the
 *     fill's right edge (the visible "buffer you have left").
 *   - Over-pace rows have the pace zone fully hidden by the fill;
 *     the fill colour already switched to amber via the
 *     .budget-row--over_pace status class. */
.budget-row__bar-pace{
  position:absolute;left:0;top:0;bottom:0;
  width:var(--pace-pct);
  background:rgba(0,0,0,.07);
  border-radius:3px 0 0 3px;
}
/* Fill = the actual-spend in the row's status colour. Capped at
 * the budget cap for tracked rows (so over-budget rows show solid
 * fill + striped overshoot); untracked rows have no track, so the
 * fill is just a grey actual-spend bar. */
.budget-row__bar-fill{
  position:absolute;left:0;top:0;bottom:0;
  width:min(var(--actual-pct), var(--budgeted-pct));
  border-radius:3px;
  background:#9ca3af; /* default = untracked grey; overridden below */
}
.budget-row--on_track   .budget-row__bar-fill{background:#10b981}
.budget-row--over_pace  .budget-row__bar-fill{background:#f59e0b}
.budget-row--over_budget .budget-row__bar-fill{background:#dc2626}
/* Untracked has no track so the fill should run the full actual
 * width, not be capped at budgeted-pct (which is 0 for untracked). */
.budget-row--untracked .budget-row__bar-fill{
  width:var(--actual-pct);background:#9ca3af;
}
/* Over-budget overshoot — striped continuation from --budgeted-pct
 * to --actual-pct, signalling the cap was blown past. Diagonal
 * red stripes match the old SVG pattern (the visual is well-known
 * to anyone migrating from the chart). */
.budget-row__bar-overshoot{
  position:absolute;top:0;bottom:0;
  left:var(--budgeted-pct);
  width:calc(var(--actual-pct) - var(--budgeted-pct));
  border-radius:3px;
  background:
    repeating-linear-gradient(45deg,
      rgba(220,38,38,.85) 0,
      rgba(220,38,38,.85) 4px,
      rgba(127,29,29,.65) 4px,
      rgba(127,29,29,.65) 8px);
}
.budget-row__delete{margin:0}

/* Dashboard Budget Health tile */
.health-card{padding:1.25rem}
.health-card__empty{display:flex;flex-direction:column;gap:.6rem;align-items:flex-start}
.health-card__empty .empty-state{margin-bottom:.4rem}
.health-card__top{display:flex;align-items:flex-start;justify-content:space-between;gap:1rem;margin-bottom:.85rem}
.health-card__headline{display:flex;flex-direction:column}
.health-card__count{font-size:var(--fs-2xl);font-weight:600;color:var(--text-primary);font-variant-numeric:tabular-nums}
.health-card__count-sep{font-size:var(--fs-sm);color:var(--text-muted);font-weight:400;margin:0 .25rem}
.health-card__count-label{font-size:var(--fs-sm);color:var(--text-muted)}
.health-card__spark{display:flex;flex-direction:column;align-items:flex-end;gap:.15rem}
.health-card__spark svg{display:block}
.health-card__spark-label{font-size:var(--fs-xs);color:var(--text-muted);letter-spacing:.04em;text-transform:uppercase}

.health-card__variance{display:flex;align-items:center;gap:.5rem;padding:.55rem 0;border-top:1px solid var(--border-light);font-size:var(--fs-base)}
.health-card__dot{width:.6rem;height:.6rem;border-radius:50%;display:inline-block;flex-shrink:0}
.health-card__dot--ok{background:#10b981}
.health-card__dot--over{background:#dc2626}
.health-card__sub{color:var(--text-muted);font-size:var(--fs-sm);margin-left:.25rem}

.health-card__top-over{display:flex;align-items:center;gap:.4rem;padding-top:.45rem;border-top:1px dashed var(--border-light);font-size:var(--fs-base)}
.health-card__top-over-label{color:var(--text-muted);font-size:var(--fs-sm)}
.health-card__top-over-cat{font-weight:500}
.health-card__top-over-amt{margin-left:auto;font-weight:600}

.health-card__pace{margin:.4rem 0 0;font-size:var(--fs-sm)}

/* ─── Budget burndown + history (E05/S13b) ────────────────────────────────
   Drill-down page /budget/category/{pk} + multi-period trend /budget/history.
   Reuses .budget-chart-card, .budget-chart-scroll, .stat-card from S13a.
*/
.budget-row__actions{display:flex;align-items:center;gap:.35rem}
.budget-row__actions .action-link{display:inline-flex;align-items:center;justify-content:center;width:1.7rem;height:1.7rem;border-radius:4px;text-decoration:none;font-size:var(--fs-base);color:var(--text-muted)}
.budget-row__actions .action-link:hover{background:rgba(0,0,0,.05);color:var(--text-primary)}
.budget-row__actions .action-link--danger:hover{background:rgba(220,38,38,.10);color:var(--expense)}

/* Status pills — used by both the burndown stat-card and the history table */
.status-pill{display:inline-block;padding:.18rem .55rem;border-radius:999px;font-size:var(--fs-xs);font-weight:600;letter-spacing:.02em}
.status-pill--on_track{background:rgba(16,185,129,.12);color:#047857}
.status-pill--over_pace{background:rgba(245,158,11,.14);color:#b45309}
.status-pill--over_budget{background:rgba(220,38,38,.12);color:#b91c1c}
.status-pill--untracked{background:var(--border-light);color:var(--text-muted)}
/* Bank connection status (E07/S3) — reuses the budget pill palette. */
.status-pill--good{background:rgba(16,185,129,.12);color:#047857}
.status-pill--reauth{background:rgba(245,158,11,.14);color:#b45309}
.status-pill--error{background:rgba(220,38,38,.12);color:#b91c1c}
.status-pill--off{background:var(--border-light);color:var(--text-muted)}

/* Periods switcher on /budget/history */
.card-actions{display:flex;gap:.35rem;align-items:center}
.periods-pill{padding:.2rem .6rem;border-radius:999px;border:1px solid var(--border-light);font-size:var(--fs-sm);text-decoration:none;color:var(--text-muted);transition:border-color .12s,background .12s}
.periods-pill:hover{border-color:var(--text-muted);color:var(--text-primary)}
.periods-pill--active{background:var(--text-primary);color:#fff;border-color:var(--text-primary);cursor:default}
.periods-pill--locked{opacity:.4;cursor:not-allowed;background:repeating-linear-gradient(45deg,transparent 0 4px,rgba(0,0,0,.04) 4px 8px)}

/* Key-value list on the drill-down stat panel */
.kv-list{display:grid;grid-template-columns:auto 1fr;gap:.45rem 1rem;margin:0}
.kv-list dt{color:var(--text-muted);font-size:var(--fs-base)}
.kv-list dd{margin:0;font-size:var(--fs-base)}
.text-muted{color:var(--text-muted)}

/* ─── Celebrations (E06/S14b) ─────────────────────────────────────────────
   Score-delta chip on /dashboard, tier label on the scorecard, full-screen
   celebration modal with confetti, and the /health Badges card grid.
   Every animation has a prefers-reduced-motion: reduce escape hatch.
*/

/* Tier label between "Financial health" and the strategy line on dashboard.
   Tone variants reuse the bronze/silver/gold palette from the badge tiles. */
.score-tier{display:inline-block;padding:.1rem .45rem;border-radius:999px;font-size:var(--fs-xs);font-weight:600;letter-spacing:.04em;text-transform:uppercase;margin-right:.4rem}
.score-tier--bronze{background:rgba(180,83,9,.12);color:#92400e}
.score-tier--silver{background:rgba(156,163,175,.18);color:#374151}
.score-tier--gold{background:rgba(251,191,36,.16);color:#92400e}

/* Score-delta chip — sits next to the score circle on /dashboard. Floats
   up + fades over 1.6s; JS removes the element after animationend so it
   doesn't outstay its welcome as a focus target. */
.score-delta{position:absolute;top:-.25rem;right:-.5rem;padding:.1rem .45rem;border-radius:999px;font-size:var(--fs-xs);font-weight:600;font-variant-numeric:tabular-nums;animation:score-delta-float 1.6s ease-out forwards}
.score-delta--positive{background:rgba(16,185,129,.16);color:#047857}
.score-delta--negative{background:rgba(220,38,38,.12);color:#b91c1c}

@keyframes score-delta-float{
  0%   {opacity:0; transform:translateY(0)}
  18%  {opacity:1; transform:translateY(-4px)}
  100% {opacity:0; transform:translateY(-14px)}
}

/* scorecard-overall is the existing wrapping <a>; mark it relative so
   the delta chip can absolute-position above it. */
.scorecard-overall{position:relative}

/* ── Modal ────────────────────────────────────────────────────────────── */

.celebration-modal{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(15,23,42,.55);z-index:1100;animation:celebration-fade-in .25s ease-out}
@keyframes celebration-fade-in{from{opacity:0} to{opacity:1}}

.celebration-card{position:relative;background:var(--bg-card);border:1px solid var(--border-light);border-radius:16px;padding:2.25rem 2rem 1.75rem;width:min(420px, 92vw);text-align:center;box-shadow:var(--elev-3);z-index:1102}
.celebration-card--bronze{border-color:#b45309}
.celebration-card--silver{border-color:#9ca3af}
.celebration-card--gold{border-color:#fbbf24;box-shadow:0 24px 60px rgba(251,191,36,.32)}

/* Intentional one-off display size (the celebration glyph) — larger
   than the type scale tops out (--fs-2xl); not a missed token sweep. */
.celebration-icon{font-size:3rem;line-height:1;margin-bottom:.85rem}
.celebration-title{font-size:var(--fs-xl);font-weight:600;margin:0 0 .5rem;color:var(--text-primary)}
.celebration-subtitle{margin:0 0 1.5rem;color:var(--text-secondary);font-size:var(--fs-base);line-height:1.45}
.celebration-form{margin:0}
.celebration-cta{min-width:160px}

/* ── Confetti ─────────────────────────────────────────────────────────── */

.celebration-confetti{position:absolute;inset:0;pointer-events:none;overflow:hidden;z-index:1101}
.confetti-piece{position:absolute;top:-12px;width:8px;height:14px;border-radius:2px;will-change:transform,top,opacity;animation-name:confetti-fall;animation-timing-function:linear;animation-fill-mode:forwards}

@keyframes confetti-fall{
  0%   {transform:translateY(0) rotate(0deg); opacity:1}
  85%  {opacity:1}
  100% {transform:translateY(110vh) rotate(720deg); opacity:0}
}

/* ── Badges card on /health ──────────────────────────────────────────── */

.badge-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:.85rem;padding:1rem 1.25rem 1.25rem}
.badge-tile{display:grid;grid-template-columns:auto 1fr;gap:.85rem;align-items:center;padding:.85rem 1rem;border:1px solid var(--border-light);border-radius:10px;background:var(--bg-card);transition:border-color .12s,box-shadow .12s}
.badge-tile--bronze{border-left:4px solid #b45309}
.badge-tile--silver{border-left:4px solid #9ca3af}
.badge-tile--gold{border-left:4px solid #fbbf24}
.badge-tile--locked{opacity:.55;filter:grayscale(.7)}
.badge-tile__icon{font-size:var(--fs-2xl);line-height:1}
.badge-tile__body{display:flex;flex-direction:column;gap:.15rem}
.badge-tile__name{font-weight:600;font-size:var(--fs-base)}
.badge-tile__desc{font-size:var(--fs-sm);color:var(--text-secondary);line-height:1.35}
.badge-tile__earned{font-size:var(--fs-xs);color:var(--text-muted);font-variant-numeric:tabular-nums;margin-top:.2rem}
.badge-tile__locked-tag{font-size:var(--fs-xs);color:var(--text-muted);text-transform:uppercase;letter-spacing:.06em;margin-top:.2rem}

/* ── prefers-reduced-motion: turn off every animation in this section ── */

@media (prefers-reduced-motion: reduce){
  .score-delta{animation:none; opacity:1; transform:none}
  .celebration-modal{animation:none}
  .confetti-piece{display:none}
}

/* ─── Streaks (E06/S15) ──────────────────────────────────────────────────
   Three-state pill (active / grace / broken) + optional comeback card on
   the dashboard. No animations — pills are persistent shell furniture and
   shouldn't draw the eye more than the score circle.
   ───────────────────────────────────────────────────────────────────── */

.streak-row{
  display:flex; flex-wrap:wrap; gap:.6rem;
  margin:.85rem 0 1.1rem;
}

.streak-pill{
  display:inline-flex; align-items:center; gap:.45rem;
  padding:.35rem .75rem;
  border-radius:999px;
  border:1px solid transparent;
  font-size:var(--fs-base);
  line-height:1;
  font-variant-numeric:tabular-nums;
  background:var(--bg-card, #fff);
}
.streak-pill__flame{font-size:var(--fs-md); line-height:1}
.streak-pill__count{font-weight:700; min-width:1ch; text-align:right}
.streak-pill__label{color:var(--text-secondary); font-size:var(--fs-sm)}

.streak-pill--active{
  background:rgba(249,115,22,.08);
  border-color:rgba(249,115,22,.35);
  color:#9a3412;
}
.streak-pill--active .streak-pill__flame{filter:none}

.streak-pill--grace{
  background:rgba(245,158,11,.08);
  border-color:rgba(245,158,11,.30);
  color:#92400e;
}
.streak-pill--grace .streak-pill__flame{filter:saturate(.6) brightness(.95)}

.streak-pill--broken{
  background:rgba(100,116,139,.08);
  border-color:rgba(100,116,139,.30);
  color:var(--text-muted);
}
.streak-pill--broken .streak-pill__flame{filter:grayscale(1) opacity(.6)}

.scorecard-streak{
  display:flex; align-items:center; gap:.7rem;
  margin:.5rem 0 .35rem;
  flex-wrap:wrap;
}

.comeback-card{
  display:flex; align-items:center; gap:1rem;
  padding:.9rem 1rem;
  margin:.5rem 0 1.1rem;
  border-radius:.65rem;
  border:1px solid rgba(249,115,22,.35);
  background:rgba(249,115,22,.05);
}
.comeback-card__icon{font-size:var(--fs-xl); line-height:1; flex:0 0 auto}
.comeback-card__body{flex:1; display:flex; flex-direction:column; gap:.15rem}
.comeback-card__body strong{font-size:var(--fs-md)}
.comeback-card__body span{font-size:var(--fs-sm); color:var(--text-secondary)}
.comeback-card__action{
  flex:0 0 auto;
  padding:.4rem .75rem;
  border-radius:.4rem;
  background:#f97316; color:#fff;
  text-decoration:none; font-size:var(--fs-base); font-weight:600;
  white-space:nowrap;
}
.comeback-card__action:focus-visible{outline:2px solid #c2410c; outline-offset:2px}
.comeback-card__dismiss-form{margin:0}
.comeback-card__dismiss{
  background:none; border:none; cursor:pointer;
  font-size:var(--fs-lg); line-height:1; padding:.2rem .4rem;
  color:var(--text-muted);
}
.comeback-card__dismiss:hover{color:var(--text-primary)}
.comeback-card__dismiss:focus-visible{outline:2px solid #c2410c; outline-offset:2px; border-radius:.25rem}

/* ─── Chores & earned allowance (E06/S19) ────────────────────────────────
   Dashboard tile + the 0-chores setup card. Reuses the comeback-card
   layout; green accent (earned money) vs the setup card's neutral tone.
   No animations. */
.chores-card{
  display:flex; align-items:center; gap:1rem;
  padding:.9rem 1rem; margin:.5rem 0 1.1rem;
  border-radius:.65rem;
  border:1px solid rgba(16,185,129,.35);
  background:rgba(16,185,129,.05);
}
.chores-card--setup{
  border-color:var(--border); background:var(--border-light);
}
.chores-card__icon{font-size:var(--fs-xl); line-height:1; flex:0 0 auto}
.chores-card__body{flex:1; display:flex; flex-direction:column; gap:.15rem}
.chores-card__body strong{font-size:var(--fs-md)}
.chores-card__body span{font-size:var(--fs-sm); color:var(--text-secondary)}
.chores-card__action{
  flex:0 0 auto; padding:.4rem .75rem; border-radius:.4rem;
  background:#10b981; color:#fff;
  text-decoration:none; font-size:var(--fs-base); font-weight:600;
  white-space:nowrap;
}
.chores-card--setup .chores-card__action{background:var(--accent)}
.chores-card__action:focus-visible{outline:2px solid #047857; outline-offset:2px}
/* Chore/pending action cluster: keep buttons on one line but
   left-align so the column header sits above the buttons (the rest of
   the chores table is left-aligned). Scoped — does not touch the
   app-wide right-aligned .action-cell. */
.chore-actions{white-space:nowrap;text-align:left}

/* ─── Notifications (E06/S16) ────────────────────────────────────────────
   Sidebar bell badge, inbox rows with a severity colour stripe, and the
   top-of-dashboard critical banner. No animations — notifications are
   informational furniture, not attention-grabbers.
   ───────────────────────────────────────────────────────────────────── */

/* Notification bell — icon-only, right-aligned on the user-name row in
   the sidebar footer (moved out of the nav list). */
.sidebar-user-row{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:.5rem;
  /* Lives in the footer account cluster now (name+bell above Sign out).
     No own padding/border — .sidebar-foot supplies the inset and the
     border-top that separates the cluster from the nav; the divider is
     back on .sidebar-brand so nav reads cleanly under the brand. */
  padding-bottom:.35rem;
}
.sidebar-bell{
  position:relative;
  flex:0 0 auto;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:28px;
  height:28px;
  border-radius:6px;
  color:var(--sidebar-text);
  text-decoration:none;
}
.sidebar-bell svg{width:18px;height:18px}
.sidebar-bell:hover{color:var(--sidebar-text-hover);background:var(--sidebar-active-bg)}
.sidebar-bell.active{color:var(--sidebar-text-hover);background:var(--sidebar-active-bg)}
.sidebar-bell:focus-visible{outline:2px solid var(--sidebar-active-accent);outline-offset:1px}
.sidebar-bell__badge{
  position:absolute;
  top:-2px;
  right:-2px;
  min-width:1rem;
  height:1rem;
  padding:0 .25rem;
  border-radius:999px;
  background:#ef4444;
  color:#fff;
  font-size:var(--fs-xs);
  font-weight:700;
  line-height:1rem;
  text-align:center;
  font-variant-numeric:tabular-nums;
}

.notif-group{margin-bottom:1.4rem}
.notif-group__date{
  font-size:var(--fs-xs);
  text-transform:uppercase;
  letter-spacing:.06em;
  color:var(--text-muted);
  margin:0 0 .5rem;
}

.notif{
  display:flex;
  align-items:flex-start;
  gap:.8rem;
  padding:.85rem 1rem .85rem 0;
  background:var(--bg-card);
  border:1px solid var(--border-light);
  border-radius:.5rem;
  margin-bottom:.5rem;
  overflow:hidden;
}
.notif__stripe{
  flex:0 0 4px;
  align-self:stretch;
  border-radius:4px 0 0 4px;
  background:var(--text-muted);
}
.notif--info    .notif__stripe{background:#3b82f6}
.notif--success .notif__stripe{background:#10b981}
.notif--warn    .notif__stripe{background:#f59e0b}
.notif--critical .notif__stripe{background:#ef4444}
.notif--read{opacity:.6}
/* Dismissed = the user explicitly closed the banner. Page now shows
   dismissed rows (history view); they get a heavier fade + a small
   inline "dismissed" badge in the timestamp line. Layers with
   .notif--read so a read+dismissed row is the most-faded. */
.notif--dismissed{opacity:.45;background:repeating-linear-gradient(45deg,transparent,transparent 12px,rgba(0,0,0,.018) 12px,rgba(0,0,0,.018) 13px)}
.notif--dismissed .notif__stripe{filter:saturate(.3)}
.notif__badge{display:inline-block;font-size:var(--fs-xs);padding:1px 5px;border-radius:3px;background:var(--border-light);color:var(--text-muted);font-weight:500;text-transform:uppercase;letter-spacing:.04em}

/* Archive section on /notifications — native <details> for the
   collapse, styled to match the rest of the page. Closed by default;
   summary acts as a clickable header with count + a "change cutoff"
   link to /settings/profile. */
.notif-archive{margin-top:1.5rem;border-top:1px solid var(--border-light);padding-top:1rem}
.notif-archive__summary{display:flex;align-items:center;gap:.5rem;font-family:var(--font-sans);font-size:var(--fs-md);font-weight:600;color:var(--text-secondary);cursor:pointer;list-style:none;padding:.3rem .15rem;border-radius:6px}
.notif-archive__summary:hover{background:var(--table-row-hover-bg)}
.notif-archive__summary::-webkit-details-marker{display:none}
.notif-archive__chevron{display:inline-block;font-size:var(--fs-base);transition:transform .15s ease-out;color:var(--text-muted);width:1em}
.notif-archive[open] .notif-archive__chevron{transform:rotate(90deg)}
.notif-archive__count{font-weight:400;font-size:var(--fs-sm);color:var(--text-muted)}
.notif-archive__settings{margin-left:auto;font-weight:500;font-size:var(--fs-sm);color:var(--accent);text-decoration:none}
.notif-archive__settings:hover{text-decoration:underline}
.notif-archive__body{margin-top:.75rem}

/* Notification settings rows on /settings/profile — unified
   typography across checkboxes and numeric-input labels. Previously
   `.checkbox-inline` and bare `<label class="form-inline-label">`
   inherited different fonts (the bare label fell back to the browser
   default, which is serif on most browsers, while .checkbox-inline
   used the system sans). This block re-uses the body sans font + fs-sm
   so the whole settings section reads consistently. */
.notif-pref-list{display:flex;flex-direction:column;gap:.55rem;margin:.85rem 0 1.1rem}
.notif-pref-row{display:flex;align-items:center;gap:.55rem;font-family:var(--font-sans);font-size:var(--fs-sm);color:var(--text-secondary);cursor:pointer;line-height:1.4}
.notif-pref-row input[type="checkbox"]{flex:0 0 auto;margin:0}
.notif-pref-row > span{flex:1 1 auto}
.notif-pref-num{display:flex;align-items:center;justify-content:space-between;gap:.75rem;padding:.25rem 0 .25rem 1.8rem;font-family:var(--font-sans);font-size:var(--fs-sm);color:var(--text-secondary);line-height:1.4}
.notif-pref-num > span{flex:1 1 auto}
.notif-pref-num input[type="number"]{flex:0 0 auto;width:6rem;padding:.3rem .5rem;border:1px solid var(--border);border-radius:5px;font-family:var(--font-mono);font-size:var(--fs-sm);color:var(--text-primary);background:var(--bg-card)}
/* Standalone variant — drops the left-indent that aligns sub-option
   labels under their parent checkbox. Used for top-level numeric
   settings (e.g. Inbox-display "Archive after N days") that aren't
   bound to a sibling checkbox above. Without this the row reads as
   a sub-option of whatever checkbox precedes it. */
.notif-pref-num--standalone{padding-left:0}
@media(max-width:540px){
  .notif-pref-num{flex-direction:column;align-items:flex-start;gap:.25rem;padding-left:1.8rem}
  .notif-pref-num--standalone{padding-left:0}
  .notif-pref-num input[type="number"]{width:100%}
}

/* Settings-section subdividers — break one settings card into clearly-
   distinct subsections (e.g. "Notifications" subscriptions vs "Inbox
   display" layout). The h3 uses uppercase tracking so it reads as a
   sub-label, not a competing heading with the card's h2. */
.settings-divider{border:none;border-top:1px solid var(--border-light);margin:1.25rem 0 .85rem}
.settings-subh{font-size:var(--fs-xs);font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--text-muted);margin:0 0 .6rem}
.notif__body{flex:1;display:flex;flex-direction:column;gap:.15rem;padding:.1rem 0}
.notif__title{font-size:var(--fs-base)}
.notif__text{font-size:var(--fs-sm);color:var(--text-secondary);line-height:1.4}
.notif__time{font-size:var(--fs-xs);color:var(--text-muted);margin-top:.1rem}
.notif__actions{
  display:flex;align-items:center;gap:.4rem;
  padding-right:1rem;flex-wrap:wrap;
}

/* .critical-banner replaced by the unified .alert-banner above (line
   ~303). The bank_reauth_banner.html partial still uses the
   .critical-banner classes — it's a derived (not notification-record-
   driven) banner; updated below to use .alert-banner classes too. */

/* ─── Starter journey (E06/S17) ──────────────────────────────────────────
   Dashboard hero card + step strip + the /journey detail list. Shares the
   dark prompt-card surface so it reads as the primary CTA. No animations.
   ───────────────────────────────────────────────────────────────────── */

.journey-card{
  background:var(--sidebar-bg);color:#e6edf3;
  border-radius:var(--radius-lg);
  padding:1.1rem 1.25rem;margin-bottom:1.75rem;
}
.journey-card__head{display:flex;align-items:baseline;justify-content:space-between;gap:1rem}
.journey-card__head strong{color:#fff;font-weight:600;font-size:var(--fs-md)}
.journey-card__step{font-size:var(--fs-sm);color:#8b929e;font-variant-numeric:tabular-nums;white-space:nowrap}

.journey-steps{
  list-style:none;display:flex;gap:6px;margin:.85rem 0;padding:0;
}
.journey-step{flex:1}
.journey-step__dot{
  display:flex;align-items:center;justify-content:center;
  height:24px;border-radius:12px;
  background:rgba(255,255,255,.08);color:#8b929e;
  font-size:var(--fs-xs);font-weight:600;font-family:var(--font-mono);
}
.journey-step--done .journey-step__dot{background:#1a7f64;color:#fff}
.journey-step--current .journey-step__dot{background:var(--sidebar-active-accent);color:#06241b}

.journey-card__current{
  border-top:1px solid rgba(255,255,255,.08);
  padding-top:.85rem;font-size:var(--fs-base);line-height:1.5;
}
.journey-card__current strong{display:block;color:#fff;font-weight:600;margin-bottom:2px}
.journey-card__current span{color:#8b929e;display:block;margin-bottom:.7rem}
.journey-card__actions{display:flex;align-items:center;gap:1rem;flex-wrap:wrap}
.journey-card__all{font-size:var(--fs-base);color:var(--sidebar-active-accent);font-weight:500;white-space:nowrap}

.journey-card--done{display:flex;align-items:center;gap:16px}
.journey-card--done .journey-card__badge{font-size:var(--fs-2xl);flex-shrink:0}
.journey-card--done .journey-card__body{flex:1;font-size:var(--fs-base);line-height:1.5}
.journey-card--done .journey-card__body strong{display:block;color:#fff;font-weight:600;margin-bottom:2px}
.journey-card--done .journey-card__body span{color:#8b929e}

/* /journey/{code} detail list — the wrapping .card has no inner
   padding by default (the global .card rule only sets background +
   radius + shadow); without horizontal padding here the marker
   chip and body text hug the card border, which reads as cramped
   especially on the family_foundations journey where body copy
   wraps to two lines. The border-bottom still spans card edge to
   edge per typical list-inside-card pattern. */
.journey-list{list-style:none;margin:0;padding:0}
.journey-list__item{
  display:flex;align-items:flex-start;gap:1rem;
  padding:1rem 1.5rem;border-bottom:1px solid var(--border-light);
}
.journey-list__item:last-child{border-bottom:none}
.journey-list__marker{
  flex:0 0 28px;height:28px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:var(--border-light);color:var(--text-muted);
  font-size:var(--fs-base);font-weight:600;font-family:var(--font-mono);
}
.journey-list__item.is-done .journey-list__marker{background:#1a7f64;color:#fff}
.journey-list__item.is-current .journey-list__marker{background:var(--sidebar-bg);color:#fff}
.journey-list__body{flex:1;display:flex;flex-direction:column;gap:.2rem}
.journey-list__body strong{font-size:var(--fs-base)}
.journey-list__body span{font-size:var(--fs-base);color:var(--text-secondary);line-height:1.45}
.journey-list__cta{font-size:var(--fs-base);color:var(--accent);font-weight:500;margin-top:.3rem}
.journey-list__status{
  flex:0 0 auto;font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.05em;
  color:var(--text-muted);padding-top:.3rem;
}
.journey-list__item.is-current .journey-list__status{color:var(--accent)}

/* ─── Calendar (upcoming outlook) ────────────────────────────────────────
   Read-only month grid of projected recurring income/expense. Reuses the
   repeat(7,1fr) grid idiom + existing card/border/color tokens. No
   animations.
   ───────────────────────────────────────────────────────────────────── */

.cal-nav{display:flex;align-items:center;gap:.75rem}
.cal-nav__label{font-weight:600;font-size:var(--fs-base);min-width:9.5rem;text-align:center;font-variant-numeric:tabular-nums}

.cal-summary{
  display:grid;grid-template-columns:repeat(3,1fr);gap:1rem;margin-bottom:1rem;
}
.cal-summary__card{
  display:flex;flex-direction:column;gap:.2rem;
  padding:.7rem .9rem;border:1px solid var(--border-light);
  border-radius:.5rem;background:var(--bg-card);
}
.cal-summary__label{font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted)}
.cal-summary__val{font-size:var(--fs-md);font-weight:700;font-variant-numeric:tabular-nums}

.cal-card{padding:.75rem}
.cal-grid-head,.cal-week{display:grid;grid-template-columns:repeat(7,1fr);gap:6px}
.cal-grid-head{margin-bottom:6px}
.cal-grid-head span{
  font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.05em;
  color:var(--text-muted);text-align:center;padding-bottom:2px;
}
.cal-week{margin-bottom:6px}
.cal-week:last-child{margin-bottom:0}
.cal-cell{
  /* Fixed height so every day box in the month grid is identical
     regardless of how many items land on it. Overflow is clipped; the
     per-chip label truncates with an ellipsis (.cal-chip__label). The
     mobile agenda overrides this back to height:auto. */
  height:7.5rem;padding:5px 5px 6px;overflow:hidden;
  border:1px solid var(--border-light);border-radius:.4rem;
  background:var(--bg-card);display:flex;flex-direction:column;gap:3px;
}
.cal-cell--blank{background:transparent;border-color:transparent}
/* Today highlight — gives instant past/future context. Accent ring +
   tint, bolded day number. */
.cal-cell--today{
  border-color:var(--accent);
  box-shadow:0 0 0 1px var(--accent) inset;
  background:rgba(26,127,100,.06);
}
.cal-cell--today .cal-daynum{color:var(--accent);font-weight:700}
/* Full date label — agenda-only (mobile drops the grid; see the 768
   block). Hidden on desktop. */
.cal-cell__date{display:none}
.cal-daynum{font-size:var(--fs-xs);color:var(--text-muted);font-variant-numeric:tabular-nums}
/* The date is a link to that day's filtered transactions — a hover cue
   makes it discoverable without changing the resting look (global
   a{} already gives inherit colour + no underline). */
.cal-daynum,.cal-cell__date{cursor:pointer;align-self:flex-start}
.cal-daynum:hover,.cal-cell__date:hover{color:var(--accent);text-decoration:underline}
.cal-chip{
  display:flex;justify-content:space-between;gap:4px;
  font-size:var(--fs-xs);line-height:1.25;padding:2px 5px;border-radius:4px;
  text-decoration:none;border:1px solid transparent;
}
.cal-chip__label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cal-chip__amt{font-variant-numeric:tabular-nums;flex:0 0 auto}
.cal-chip--income{
  color:var(--income);background:rgba(13,122,95,.10);border-color:rgba(13,122,95,.30);
}
.cal-chip--expense{
  color:var(--expense);background:rgba(192,57,43,.09);border-color:rgba(192,57,43,.28);
}
/* Transfers/payments — neutral; listed but out of the income/expense
   totals (they don't change net worth). */
.cal-chip--transfer{
  color:var(--text-secondary);background:rgba(120,130,145,.10);
  border-color:var(--border-light);
}
/* Projected = upcoming recurring (not yet booked). Dashed border +
   slightly muted distinguishes a forecast from a logged transaction. */
.cal-chip--projected{border-style:dashed;opacity:.92}
.cal-chip:hover{filter:brightness(.97)}
.cal-chip:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.cal-foot{font-size:var(--fs-sm);margin-top:.9rem}
.cal-foot a{color:var(--accent)}

/* Mobile = agenda, not a squeezed 7-col grid. The grid crushed chip
   text into ~45px columns and overlapped the cells; here each day with
   activity becomes a full-width block led by its date. Empty/blank days
   are dropped (a true agenda). Canonical 768px breakpoint. */
@media (max-width:768px){
  .cal-summary{grid-template-columns:1fr}
  .cal-card{padding:.5rem}
  .cal-grid-head{display:none}
  .cal-week{display:block;margin:0}
  .cal-cell{
    height:auto;min-height:0;margin-bottom:8px;overflow:visible;
    flex-direction:column;gap:5px;padding:.6rem .7rem;
  }
  /* Agenda lists only days with activity — EXCEPT today, which always
     shows (even empty) so the current-day highlight is present on
     mobile for the same past/future context the desktop grid gives. */
  .cal-cell--blank,.cal-cell--empty:not(.cal-cell--today){display:none}
  .cal-cell__date{
    display:block;font-size:var(--fs-sm);font-weight:600;
    color:var(--text-secondary);
  }
  /* Today in the agenda: the base .cal-cell--today accent ring/tint
     still applies; make the date line accent + a touch larger so it
     clearly reads as the highlight, and give an empty today a caption
     so it isn't a bare highlighted box. */
  .cal-cell--today .cal-cell__date{color:var(--accent);font-size:var(--fs-base)}
  .cal-cell--today.cal-cell--empty::after{
    content:"Nothing logged or due today.";
    font-size:var(--fs-sm);color:var(--text-muted);
  }
  .cal-daynum{display:none}
  .cal-chip{font-size:var(--fs-sm);padding:.4rem .6rem}
  .cal-chip__label{overflow:visible;white-space:normal;text-overflow:clip}
}

/* ─── Auth pages (standalone dark) ───────────────────────────────────────
   Consolidated from the per-page inline <style> blocks that were copy-
   pasted verbatim across login / forgot / reset / login_mfa / signup.
   Scoped under body.auth-page so the dark treatment never leaks into the
   app (the bare body{} rule is exactly why it had to be inline before —
   adding the class lets it live here). landing.html stays inline by
   design (standalone marketing page, its own theme, redefines base).
   ───────────────────────────────────────────────────────────────────── */
body.auth-page{background:var(--bg);color:var(--text-primary)}
.auth-page .auth-shell{max-width:460px;margin:0 auto;padding:4rem 1.5rem}
/* MoMoFi wordmark (≥ PR #126 follow-up: the auth-pages brand-rebrand
   sweep). letter-spacing was tuned for the all-caps LEDGER wordmark
   that used to live here; the mixed-case MoMoFi wordmark wants
   negative tracking to match the landing-page nav-logo treatment.
   Inner .brand-mo / .brand-fi spans (defined elsewhere in this file)
   set the green-deep / amber two-tone colors. */
.auth-page .auth-brand{text-align:center;font-family:var(--font-serif);font-weight:700;letter-spacing:-.02em;font-size:1.6rem;margin-bottom:2rem;color:var(--accent)}
.auth-page .auth-brand .mark{color:var(--amber);margin-right:.4rem}
.auth-page .auth-card{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius-lg);padding:2rem 1.75rem;box-shadow:0 8px 32px rgba(27,58,45,.08)}
.auth-page .auth-title{font-family:var(--font-serif);font-size:var(--fs-xl);font-weight:600;margin:0 0 .5rem;color:var(--text-primary)}
.auth-page .auth-sub{color:var(--text-secondary);margin:0 0 1.5rem;font-size:var(--fs-base)}
.auth-page .auth-flash{padding:.7rem .9rem;border-radius:8px;margin-bottom:1rem;font-size:var(--fs-base)}
.auth-page .auth-flash.success{background:var(--income-bg);color:var(--income)}
.auth-page .auth-flash.error{background:var(--expense-bg);color:var(--expense)}
.auth-page .auth-label{display:block;font-size:var(--fs-sm);font-weight:500;color:var(--text-primary);margin:.85rem 0 .35rem}
.auth-page .auth-input{width:100%;padding:.7rem .85rem;border-radius:8px;border:1px solid var(--border);background:var(--bg-card);color:var(--text-primary);font-size:var(--fs-base);font-family:inherit;box-sizing:border-box;transition:border-color .12s,box-shadow .12s}
.auth-page .auth-input:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px rgba(27,58,45,.12)}
/* login_mfa OTP field — large, spaced, centred. */
.auth-page .auth-input--otp{font-size:var(--fs-lg);letter-spacing:.1em;text-align:center}
.auth-page .auth-hint{font-size:var(--fs-sm);color:var(--text-muted);margin-top:.3rem}
.auth-page .auth-btn{display:block;width:100%;padding:.8rem;margin-top:1.5rem;background:var(--accent);color:#fff;border:0;border-radius:100px;font-weight:600;font-size:var(--fs-base);cursor:pointer;font-family:inherit;box-shadow:0 4px 12px rgba(27,58,45,.18);transition:background .15s,transform .12s,box-shadow .15s}
.auth-page .auth-btn:hover{background:var(--accent-soft);transform:translateY(-1px);box-shadow:0 6px 16px rgba(27,58,45,.22)}
.auth-page .auth-foot{text-align:center;color:var(--text-secondary);margin-top:1.25rem;font-size:var(--fs-base)}
.auth-page .auth-foot a{color:var(--accent);font-weight:500}
.auth-page .auth-back{display:inline-block;margin-top:1.5rem;color:var(--text-muted);font-size:var(--fs-sm);text-align:center;width:100%;text-decoration:none}
.auth-page .trial-banner{background:var(--amber-pale);border:1px solid #e8c87a;color:var(--amber);padding:.7rem .9rem;border-radius:8px;font-size:var(--fs-base);margin-bottom:1.25rem}
.auth-page .trial-banner strong{color:var(--text-primary)}

/* Split-transaction editor (was inline in transaction_form.html). */
.split-lines{display:flex;flex-direction:column;gap:.5rem;margin-bottom:.5rem}
.split-line{display:grid;grid-template-columns:7rem 1fr 1fr 2rem;gap:.5rem;align-items:center}
.split-line__amount{text-align:right}
.split-line__remove{padding:.25rem .5rem;font-size:var(--fs-lg);line-height:1}
.split-controls{display:flex;gap:.5rem;margin-top:.25rem}
.split-sum{margin-top:.5rem;font-variant-numeric:tabular-nums}

/* Wide withholding row + matching header variant (income_form.html
   uses the 6-column layout: label / type / amount / % / target /
   remove). The base .withholding-grid-header,.withholding-row CSS
   still declares a 4-col grid for legacy compatibility, but the
   income form opts into 6 via the --wide modifier on BOTH the header
   and the row so they line up. The remove column is a fixed 28px box
   for the × button so it doesn't steal horizontal space from the
   data columns. ≤768px collapse to 1fr is already handled by the
   mobile band's .withholding-row catch-all. */
.withholding-row--wide,
.withholding-grid-header--wide{grid-template-columns:1.4fr 1.2fr 1fr 50px 1.4fr 28px}

/* Per-row × Remove button. Muted by default; tints expense-red on
   hover so the destructive intent is visible. Focus-visible outline
   keeps it keyboard-reachable. */
.withholding-row__remove{
  background:transparent;border:0;cursor:pointer;
  font-size:18px;line-height:1;padding:2px 6px;
  color:var(--text-muted);border-radius:4px;
  align-self:center;justify-self:end;
}
.withholding-row__remove:hover{background:var(--expense-bg);color:var(--expense)}
.withholding-row__remove:focus-visible{outline:2px solid var(--accent);outline-offset:1px}

.withholding-add-row{display:flex;align-items:center;gap:.75rem;margin-top:.75rem}
.withholding-add-row__hint{font-size:var(--fs-sm);color:var(--text-muted)}

/* ── Billing pricing cards + interval toggle ─────────────────────────────
 * Used on /settings/billing for free-tier users picking a paid plan.
 * Mirrors the landing-page pricing section's structure but in the authed
 * light theme. The monthly/annual toggle JS (in ledger.js) flips
 * .is-annual on .billing-tiers and updates the hidden interval inputs
 * inside each tier's checkout form. CSS does the rest (price labels
 * hide/show; .is-active styles the chosen toggle button).
 */
.billing-interval{
  display:inline-flex;gap:.25rem;
  background:var(--bg);border:1px solid var(--border-light);
  border-radius:999px;padding:.25rem;margin:.25rem 0 1rem;
}
.billing-interval button{
  appearance:none;background:transparent;border:0;cursor:pointer;
  padding:.4rem 1rem;border-radius:999px;
  font:inherit;font-size:var(--fs-sm);font-weight:500;
  color:var(--text-muted);transition:background .12s,color .12s;
}
.billing-interval button:hover{color:var(--text-secondary)}
.billing-interval button.is-active{
  background:var(--bg-card);color:var(--text-primary);
  box-shadow:0 1px 2px rgba(0,0,0,.06);
}
.billing-interval__save{
  display:inline-block;margin-left:.4rem;
  font-size:var(--fs-xs);color:var(--accent);font-weight:600;
}
.billing-tiers{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
  gap:1rem;margin-top:.5rem;
}
.billing-tier{
  position:relative;display:flex;flex-direction:column;
  background:var(--bg-card);border:1px solid var(--border-light);
  border-radius:var(--radius-lg);padding:1.5rem 1.25rem 1.25rem;
}
.billing-tier--current{background:var(--bg)}
.billing-tier--featured{
  border-color:var(--accent);
  box-shadow:0 0 0 1px var(--accent),0 8px 20px rgba(26,127,100,.08);
}
.billing-tier__ribbon{
  position:absolute;top:-10px;left:50%;transform:translateX(-50%);
  background:var(--accent);color:#fff;
  font-size:var(--fs-xs);letter-spacing:.06em;font-weight:600;
  padding:.2rem .65rem;border-radius:999px;text-transform:uppercase;
}
.billing-tier__head h3{margin:0;font-size:var(--fs-md);font-weight:600;color:var(--text-primary)}
.billing-tier__tag{color:var(--text-muted);font-size:var(--fs-sm);margin:.15rem 0 0}
.billing-tier__price{margin:1rem 0 .85rem;line-height:1.2}
.billing-tier__price-num{font-size:1.9rem;font-weight:700;color:var(--text-primary)}
.billing-tier__price-unit{color:var(--text-muted);margin-left:.3rem;font-size:var(--fs-sm)}
.billing-tier__feats{list-style:none;padding:0;margin:0 0 1.25rem;flex-grow:1}
.billing-tier__feats li{
  color:var(--text-secondary);font-size:var(--fs-sm);
  padding:.3rem 0 .3rem 1.3rem;position:relative;line-height:1.45;
}
.billing-tier__feats li::before{
  content:"✓";position:absolute;left:0;color:var(--accent);font-weight:700;
}
.billing-tier__form{margin:0}
.billing-tier__cta{display:block;width:100%;text-align:center}
.billing-tier__current-pill{
  display:inline-block;align-self:flex-start;
  background:var(--bg-card);border:1px solid var(--border-light);
  color:var(--text-muted);
  font-size:var(--fs-xs);font-weight:600;letter-spacing:.04em;
  padding:.35rem .75rem;border-radius:999px;text-transform:uppercase;
}
.billing-tier__price-annual{display:none}
.billing-tiers.is-annual .billing-tier__price-monthly{display:none}
.billing-tiers.is-annual .billing-tier__price-annual{display:inline}

/* ── Receipt attachments on the transaction form ────────────────────── */
.receipt-group .form-control[type="file"]{padding:.4rem}
.receipt-existing{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));
  gap:.6rem;margin-bottom:.6rem;
}
.receipt-thumb{
  margin:0;display:flex;flex-direction:column;
  border:1px solid var(--border-light);border-radius:8px;
  overflow:hidden;background:var(--bg);
}
.receipt-thumb a{display:block;line-height:0}
.receipt-thumb img{
  width:100%;aspect-ratio:1/1;object-fit:cover;
  display:block;background:#f3f3f1;
}
.receipt-thumb figcaption{
  display:flex;align-items:center;gap:.3rem;
  padding:.35rem .5rem;background:var(--bg-card);
  font-size:var(--fs-xs);color:var(--text-secondary);
  border-top:1px solid var(--border-light);
}
.receipt-thumb__name{
  flex:1;min-width:0;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.receipt-thumb__delete{margin:0;display:inline-flex}
.btn-icon{
  appearance:none;background:transparent;border:0;cursor:pointer;
  width:1.4rem;height:1.4rem;border-radius:4px;padding:0;
  font:inherit;font-size:1rem;line-height:1;
  color:var(--text-muted);
  display:inline-flex;align-items:center;justify-content:center;
}
.btn-icon:hover{background:var(--bg);color:var(--text-primary)}
.btn-icon--danger:hover{background:var(--expense-bg);color:var(--expense)}
.receipt-cap-hint{color:var(--text-muted)}
.receipt-cap-hint--full{color:var(--warn);font-weight:500}

