:root {
      --bg: #F2F2F2;
      --surface: #FFFFFF;
      --surface-solid: #FFFFFF;
      --glass-border: rgba(0,0,0,0.06);
      --glass-border-dark: rgba(0,0,0,0.06);
      --border: #E2E2E2;
      --text: #1A1A1A;
      --text-secondary: #5E5E5E;
      /* #9A9A9A measured 2.81:1 on white — well under the 4.5 floor for text
         this size. #6A6A6A is 5.4:1 on white and 4.8:1 on the --bg tint,
         which is what most of this text actually sits on. (Pre-existing, not
         introduced by the true-black work; surfaced by measuring rather than
         eyeballing.) */
      /* Tertiary is no longer a separate text grey (Quiet Ledger): one secondary grey explains, ink states. */
      --text-tertiary: #5E5E5E;
      /* --ink = structural near-black (text, borders, structural chrome).
         --accent = the single chromatic action color (active/primary states only).
         Palette: indigo #23004C, red-orange #DA3A16, violet #7A00E6,
         teal-blue #007FAD, magenta #D515B9, green #268500. */
      --ink: #1A1A1A;
      --accent: #23004C;
      --accent-inverse: #FFFFFF;
      --accent-soft: rgba(35,0,76,0.08);
      --danger: #DA3A16;
      --danger-soft: rgba(218,58,22,0.08);
      --success: #268500;
      --success-soft: rgba(38,133,0,0.08);
      --warning: #C9943A;
      --warning-soft: rgba(201,148,58,0.10);
      /* Status-icon-only accents (Color Schema 1) — teal-blue for exchange
         initiated, violet for exchange completed. Not used as general UI
         chrome color, only for refund/exchange status icons. */
      --teal-blue: #007FAD;
      --teal-blue-soft: rgba(0,127,173,0.08);
      --violet: #7A00E6;
      --violet-soft: rgba(122,0,230,0.08);
      /* The sixth palette entry. It was named in the comment above but never
         had a token, so the one place that wanted it would have had to
         hard-code a hex. */
      --magenta: #D515B9;
      --magenta-soft: rgba(213,21,185,0.08);
      /* Corner radius — a first-class One UI signature, not an afterthought.
         The old 8/10/12/16 scale is the generic-web default range, and it is
         the single most common reason a One UI attempt reads as stock
         Material instead. Measured before the change: 28 elements at 8px on
         History alone, nothing anywhere above 16px.

         Nesting is exact, not approximate — an inner radius must equal the
         outer radius minus the padding between them or the curves visibly
         disagree: .segmented (md 18, pad 3) -> .segmented-btn ~15 ≈ sm 14,
         .type-toggle (md 18, pad 4) -> .type-btn 14 = sm, .header-menu
         (md 18, pad 4) -> item 14 = sm. Changing one means rechecking its pair. */
      --radius-sm: 14px;   /* chips, small buttons, menu items */
      --radius-md: 18px;   /* inputs, popovers, segmented tracks */
      --radius-lg: 22px;   /* cards and list items */
      --radius-xl: 28px;   /* sheets and large surfaces */
      --radius-2xl: 32px;  /* bottom-sheet top corners */
      --radius-pill: 50px;
      /* Spacing scale (4px base) */
      /* Six-step type scale (round seven, board 34): 18 distinct font sizes had
         drifted in, none through a token. Form fields take --fs-input, 16px,
         because iOS zooms the page into any field smaller than that. */
      /* Quiet Ledger scale (2026-09-16): caption 12, secondary 14, body 16,
         title 20, page title 28, and the typed amount at 40. Nothing a person
         reads as a sentence or a value is under 14. Was 11/12/13/15/22/32. */
      --fs-12: 0.75rem;
      --fs-14: 0.875rem;
      --fs-16: 1rem;
      --fs-20: 1.25rem;
      --fs-28: 1.75rem;
      --fs-figure: 2.5rem;
      --fs-input: 1rem;
      --sp-1: 4px;
      --sp-2: 8px;
      --sp-3: 12px;
      --sp-4: 16px;
      --sp-6: 24px;
      /* Unified soft-elevation scale (replaces the glass + neumorphic systems) */
      --elev-1: 0 1px 2px rgba(0,0,0,0.04), 0 1px 1px rgba(0,0,0,0.03);
      --elev-2: 0 4px 14px rgba(0,0,0,0.06);
      --elev-3: 0 12px 30px rgba(0,0,0,0.10);
      --inset: inset 0 1px 2px rgba(0,0,0,0.05);
      /* Legacy aliases — point every old shadow name at the new scale so any
         missed reference still renders coherently. */
      --shadow-glass: var(--elev-2);
      --shadow-neu: var(--elev-1);
      --shadow-neu-inset: var(--inset);
      --shadow-soft: var(--elev-1);
      --shadow-hover: var(--elev-3);
      --transition: 180ms cubic-bezier(0.22,0.25,0,1);
      /* The One UI macro curve. Every control point stays inside [0,1], so it
         decelerates hard into its resting position and STOPS there — no
         overshoot, no bounce-back. That is the whole difference from what was
         here before (0.34/1.56/0.64/1), whose 1.56 sent every menu, chip, dock
         icon and toast past its target and back. One UI content settles; it
         does not spring.

         NOTE: these are duration+easing PAIRS. Dropping one into an
         `animation:` shorthand that already carries a duration yields two time
         values, so the pair's duration silently becomes a DELAY — and adding a
         third makes the whole declaration invalid, i.e. animation:none. Always
         spell the curve out when a delay is also wanted. */
      --ease-settle: 340ms cubic-bezier(0.22,0.25,0,1);
      /* Legacy alias — the name is a lie now, kept because it is referenced
         throughout and repointing beats a risky sweep. Same pattern as the
         --shadow-* aliases above. */
      --ease-spring: var(--ease-settle);
      --ease-out: 260ms cubic-bezier(0.16,1,0.3,1);
      /* Text that carries a state (round seven, board 31). On the light
         ground --danger measures 4.08:1, --success 3.8-4.7:1 and --warning
         2.4:1 as text, so state words read in --text there and the colour
         moves to a border, bar, dot or sign beside them. On true black every
         state colour clears 4.5:1, so dark keeps coloured words. No new
         colours: each ink is one of the existing tokens. */
      --danger-ink: var(--text);
      --success-ink: var(--text);
      --warning-ink: var(--text);
    }
    /* One UI's dark theme is a true-black AMOLED theme, not a dark-grey one —
       on the OLED panels these phones ship with, #000 pixels are simply off,
       which is where the depth comes from. #0D0D0D looked black on an LCD
       preview and merely dark on the actual hardware.
       Surface lifted 1A -> 1C at the same time so cards keep separating from
       the page now that the page is fully black. */
    [data-theme="dark"] {
      --bg: #000000;
      --surface: #1C1C1C;
      --surface-solid: #1C1C1C;
      --glass-border: rgba(255,255,255,0.08);
      --glass-border-dark: rgba(255,255,255,0.07);
      --border: #2A2A2A;
      --text: #F0F0F0;
      --text-secondary: #A0A0A0;
      /* 3.34:1 on the card surface at #6E6E6E; #8A8A8A is 4.9:1. */
      --text-tertiary: #A0A0A0;
      --ink: #F0F0F0;
      --accent: #A07CFF;
      --accent-inverse: #1A0938;
      --accent-soft: rgba(160,124,255,0.14);
      --danger: #F0714C;
      --danger-soft: rgba(240,113,76,0.14);
      --success: #5DBF3A;
      --success-soft: rgba(93,191,58,0.14);
      --warning: #D9A94E;
      --warning-soft: rgba(217,169,78,0.14);
      --teal-blue: #4DC8E8;
      --teal-blue-soft: rgba(77,200,232,0.14);
      --violet: #C48FFF;
      --violet-soft: rgba(196,143,255,0.14);
      --magenta: #F06FDC;
      --magenta-soft: rgba(240,111,220,0.14);
      --danger-ink: var(--danger);
      --success-ink: var(--success);
      --warning-ink: var(--warning);
      /* White on --danger is 2.93:1 in dark; the accent's dark ink clears it. */
      --badge-ink: var(--accent-inverse);
      --elev-1: 0 1px 2px rgba(0,0,0,0.4);
      --elev-2: 0 4px 14px rgba(0,0,0,0.45);
      --elev-3: 0 12px 30px rgba(0,0,0,0.55);
      --inset: inset 0 1px 2px rgba(0,0,0,0.5);
      --shadow-glass: var(--elev-2);
      --shadow-neu: var(--elev-1);
      --shadow-neu-inset: var(--inset);
      --shadow-soft: var(--elev-1);
      --shadow-hover: var(--elev-3);
    }

    /* Noto Sans, self-hosted (Quiet Ledger, 2026-09-16). Two subset files from Google Fonts v42,
       SIL Open Font License: Latin, and Devanagari, which carries the rupee sign. Both are precached
       by the service worker, so the face works offline; the system stack stands in until they load. */
    @font-face {
      font-family:'Noto Sans'; font-style:normal; font-weight:400 600; font-stretch:100%; font-display:swap;
      src:url('noto-sans-latin.woff2') format('woff2');
      unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
    }
    @font-face {
      font-family:'Noto Sans'; font-style:normal; font-weight:400 600; font-stretch:100%; font-display:swap;
      src:url('noto-sans-devanagari.woff2') format('woff2');
      unicode-range:U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, U+11B00-11B09;
    }
    * { margin:0; padding:0; box-sizing:border-box; -webkit-tap-highlight-color:transparent; }
    html { height:100%; overflow:hidden; }
    body {
      /* System font stack (§3): iOS/macOS render SF, Android renders Roboto,
         Windows Segoe. 'Inter' used to lead this list but the repo ships no
         @font-face and no inter-var.woff2, so it only ever resolved for the
         rare user with Inter installed locally — meaning the app rendered in
         a different typeface for them than for everyone else. Dropping it
         makes the platform font the deliberate choice rather than an
         accident of what happens to be installed. */
      /* Roboto is pulled ahead of Segoe UI because it is what One UI devices
         actually render and it shares One UI's geometric, slightly-rounded
         letterforms. In practice system-ui still wins on every platform that
         supports it (Roboto on Android, SF on iOS, Segoe on Windows), so this
         is about stating the intent for the fallback path — Samsung's own
         SamsungOne/SharpSans are not licensed for the web and are not an
         option here. */
      /* Quiet Ledger: Noto Sans on every device, so a row wraps at the same width on a phone
         and a laptop; the platform face is the fallback until the files load. */
      font-family:'Noto Sans',system-ui,Roboto,-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
      background:var(--bg); color:var(--text); height:100%; line-height:1.45;
      -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
      overscroll-behavior-y:none; font-size:var(--fs-16); font-weight:400;
      font-feature-settings:'cv05' 1, 'ss01' 1, 'cv11' 1; text-rendering:optimizeLegibility;
    }
    /* Money & metric values get tabular, slashed-zero numerals for clean column alignment. */
    .progress-value, .tx-amount, .report-value, .add-hero-input {
      font-feature-settings:'tnum' 1, 'zero' 1; font-variant-numeric:tabular-nums slashed-zero;
    }
    ::-webkit-scrollbar { width:3px; height:3px; }
    ::-webkit-scrollbar-track { background:transparent; }
    ::-webkit-scrollbar-thumb { background:var(--border); border-radius:3px; }

    .app { height:100%; display:flex; flex-direction:column; max-width:720px; margin:0 auto; position:relative; }

    /* ── Desktop layout ───────────────────────────────────────────────────
       At 1440px the 720px shell used 48% of the window with ~374px of dead
       gutter each side — the "stretched mobile layout" anti-pattern, where
       extra width buys bigger margins instead of more content.

       The shell now grows in steps, and the width is spent on CONTENT:
       Home and Lifecycle flow their independent cards into two columns, so
       more is visible at once. Surfaces that would read worse wide are
       constrained individually instead — a form and a list have a natural
       comfortable measure, and stretching them to 1280px would be its own
       anti-pattern. The Plan tab keeps the full shell because its annual
       table genuinely wants the room. */
    @media (min-width:1100px) {
      .app { max-width:1100px; }
      /* Multicol rather than grid: cards differ in height, so column flow
         packs them without the ragged gaps a 2-row grid would leave. */
      #homeSection, #trackSection > #trackList { column-count:2; column-gap:var(--sp-4); }
      #homeSection > *, #trackSection > #trackList > * { break-inside:avoid; -webkit-column-break-inside:avoid; }
      /* Entry form keeps a comfortable measure — a 1100px-wide form is worse
         than a 640px one, not better. */
      #addSection { max-width:640px; margin-inline:auto; }
      /* Long rows with the amount far from the label are hard to scan. */
      #historySection { max-width:900px; margin-inline:auto; }
    }
    @media (min-width:1600px) {
      .app { max-width:1280px; }
      #homeSection { column-count:3; }
    }

    /* NOTE: the desktop navigation rail (D5) lives further down the file,
       immediately after the base .dock / .main-scroll rules it overrides —
       media queries add no specificity, so it has to come later in source
       order to win. Putting it here would silently lose. */

    /* Header */
    .app-header {
      position:sticky; top:0; z-index:50; background:var(--surface);

      border-bottom:1px solid var(--glass-border-dark); padding:calc(12px + env(safe-area-inset-top)) 16px 12px; flex-shrink:0;
    }
    .header-bar { display:flex; align-items:center; justify-content:space-between; gap:6px; }
    .header-controls { display:flex; align-items:center; gap:var(--sp-1); flex-shrink:0; max-width:100%; overflow-x:auto; scrollbar-width:none; -ms-overflow-style:none; -webkit-overflow-scrolling:touch; padding-right:2px; }
    .header-controls::-webkit-scrollbar { display:none; }
    .header-menu {
      position:absolute; z-index:900;
      background:var(--surface-solid); border:1px solid var(--glass-border-dark); border-radius:var(--radius-md);
      box-shadow:var(--shadow-glass); min-width:160px; max-width:min(260px, calc(100% - 20px)); display:none; flex-direction:column; padding:var(--sp-1);
      transform-origin:top right;
      animation:menuPop 0.28s cubic-bezier(0.22,0.25,0,1);
    }
    .header-menu.active { display:flex; }
    /* Popovers spring open from their anchor corner. */
    @keyframes menuPop { from { opacity:0; transform:scale(0.88) translateY(-6px); } to { opacity:1; transform:scale(1) translateY(0); } }
    .header-menu-item {
      display:flex; align-items:center; gap:var(--sp-2); padding:var(--sp-2) 10px; border-radius:var(--radius-sm);
      background:transparent; border:none; color:var(--text-secondary); font-size:var(--fs-14); font-weight:500;
      cursor:pointer; font-family:inherit; transition:var(--transition); text-align:left; white-space:nowrap;
    }
    .header-menu-item:hover, .header-menu-item:active { background:var(--bg); color:var(--text); }
    .header-menu-item:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
    .brand { display:flex; align-items:center; gap:var(--sp-2); min-width:0; flex-shrink:1; }
    .brand-icon {
      width:28px; height:28px; border-radius:11px; background:linear-gradient(135deg, var(--accent), color-mix(in srgb, var(--accent) 75%, #000)); color:var(--accent-inverse);
      display:flex; align-items:center; justify-content:center; flex-shrink:0; box-shadow:var(--shadow-soft);
    }
    .brand-text h1 { font-size:var(--fs-16); font-weight:600; letter-spacing:-0.02em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
    .brand-text { min-width:0; overflow:hidden; }

    .icon-btn {
      width:32px; height:32px; border-radius:50%; border:1px solid var(--glass-border-dark);
      background:var(--surface); color:var(--text-secondary); display:flex; align-items:center; justify-content:center;
 cursor:pointer; transition:var(--transition); flex-shrink:0;
    }
    @media (hover:hover) { .icon-btn:hover { background:var(--bg); color:var(--text); } }
    .icon-btn:active { background:var(--accent-soft); transform:scale(0.95); }
    .icon-btn:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
    @media (max-width:480px) {
      .app-header { padding:var(--sp-2) 10px; }
      .header-bar { gap:var(--sp-1); }
      .brand-icon { width:26px; height:26px; }
      .brand-text h1 { font-size:var(--fs-14); }
      .header-controls { gap:2px; }
      .icon-btn { width:28px; height:28px; }
      .icon-btn svg { width:14px; height:14px; }
      .header-controls .chip { padding:3px 6px !important; font-size:var(--fs-14) !important; }
    }
    @media (max-width:360px) {
      .brand-text { display:none; }
    }

    /* Main scroll */
    /* Top padding lives on the sections, not the scroller: a position:sticky
       child pins at the scroller's CONTENT edge, so scroller padding would
       leave a strip above every pinned day header for rows to scroll through. */
    .main-scroll { flex:1; overflow-y:auto; overflow-x:hidden; -webkit-overflow-scrolling:touch; padding:0 var(--sp-4); padding-bottom:calc(140px + env(safe-area-inset-bottom)); }
    .main-scroll > section { padding-top:var(--sp-4); }

    /* Dock */
    .dock {
      position:fixed; bottom:calc(10px + env(safe-area-inset-bottom)); left:50%; transform:translateX(-50%); z-index:100;
 display:flex; gap:2px; background:var(--surface);
      border:1px solid var(--glass-border); border-radius:var(--radius-pill); padding:var(--sp-1) 6px; box-shadow:var(--shadow-glass);
    }
    .dock-btn {
      position:relative;
      width:58px; height:40px; border-radius:var(--radius-pill); border:none; background:transparent; color:var(--text-secondary);
      display:flex; flex-direction:column; align-items:center; justify-content:center; gap:1px; cursor:pointer;
      font-family:inherit; font-size:var(--fs-12); font-weight:600; letter-spacing:0.03em; transition:color var(--transition), background var(--ease-spring);
    }
    /* Restock-alert count bubble on the Lifecycle dock icon. */
    .dock-badge {
      position:absolute; top:2px; right:8px; min-width:14px; height:14px; padding:0 var(--sp-1);
      border-radius:999px; background:var(--danger); color:var(--badge-ink, #fff); font-size:var(--fs-12); font-weight:600;
      display:flex; align-items:center; justify-content:center; line-height:1; pointer-events:none;
      box-shadow:0 0 0 2px var(--surface-solid);
      animation:badgePop 0.35s cubic-bezier(0.22,0.25,0,1);
    }
    @keyframes badgePop { from { transform:scale(0); } to { transform:scale(1); } }
    /* Per-item restock blob in the Lifecycle list (color set inline: red for
       <=1 day / past due, orange for the rest of the 5-day window). */
    .lc-blob {
      display:inline-block; width:8px; height:8px; border-radius:50%; margin-right:6px; flex-shrink:0;
      vertical-align:middle; animation:blobPulse 2s ease-in-out infinite;
    }
    @keyframes blobPulse { 0%,100% { opacity:1; } 50% { opacity:0.45; } }
    .dock-btn .dock-icon { display:flex; align-items:center; justify-content:center; transition:transform var(--ease-spring); }
    .dock-btn.on { background:var(--accent); color:var(--accent-inverse); box-shadow:var(--shadow-soft); }
    .dock-btn.on .dock-icon { transform:translateY(-1px) scale(1.05); animation:dockPop 0.4s cubic-bezier(0.22,0.25,0,1); }
    /* Monotonic grow. The old middle keyframe punched to scale(1.22) and fell
       back to 1.05 — a bounce on top of an already-bouncy curve, which read as
       a Material ripple-pop rather than a One UI selection settle. */
    @keyframes dockPop { 0% { transform:translateY(-1px) scale(0.88); } 100% { transform:translateY(-1px) scale(1.05); } }

    /* ── Desktop navigation rail (D5) ──────────────────────────────────────
       A fixed bottom dock is a phone idiom; a desktop app of this shape puts
       navigation down the side. Deliberately a PURE CSS restyle of the SAME
       element — markup, dock-button order, the swipe-gesture tab map and the
       Lifecycle alert badge are all untouched, so none of that logic needed
       re-verifying.

       Gated at 1340px for a measured geometric reason: the shell is centred at
       max-width 1100, so the side gutter is (viewport-1100)/2. The rail
       occupies x=16..88. At 1280 the gutter is 90px, leaving just 2px of
       clearance — non-overlapping but close enough that a font or zoom change
       could tip it. At 1340 the gutter is 120px, giving ~32px of real
       breathing room. Below this width the bottom dock stays exactly as it is.

       Placement matters, and it was got WRONG here once already: a media query
       carries no extra specificity, so this block has to sit after EVERY base
       rule it overrides — including the .dock-fab rules below, not only .dock
       and .main-scroll. It originally sat above them, so the rail's
       `margin:2px 0` lost to the base `margin-top:-22px` and the FAB rode 18px
       up into the "Plan" label on desktop. The block now lives immediately
       after .dock-fab:focus-visible, which is the last of them. */
    .dock-btn:focus-visible { outline:2px solid var(--accent); outline-offset:2px; border-radius:var(--radius-pill); }
    .dock-fab {
      width:52px; height:52px; margin:0 var(--sp-1); margin-top:-22px; border-radius:50%; border:none; cursor:pointer;
      background:var(--accent); color:var(--accent-inverse);
      display:flex; align-items:center; justify-content:center; flex-shrink:0;
      box-shadow:0 6px 16px rgba(0,0,0,0.28); transition:transform var(--ease-spring), box-shadow var(--transition);
    }
    @media (hover:hover) { .dock-fab:hover { box-shadow:0 8px 22px rgba(0,0,0,0.34); transform:translateY(-1px); } }
    /* Softened from scale(0.90) rotate(90deg). A quarter-turn spin on press is
       a playful Material flourish, not the calm, unhurried feedback One UI
       gives; halving the rotation keeps the character without the drama. */
    .dock-fab:active { transform:scale(0.94) rotate(45deg); filter:brightness(0.94); }
    .dock-fab svg { transition:transform var(--ease-spring); }
    .dock-fab:focus-visible { outline:3px solid var(--accent); outline-offset:3px; }

    /* ── Desktop navigation rail (see the note above .dock-btn:focus-visible) ──
       Must stay BELOW every base .dock / .dock-btn / .dock-fab / .main-scroll
       rule. Anything added to those after this point will silently win. */
    @media (min-width:1340px) {
      .dock {
        left:16px; top:50%; bottom:auto;
        transform:translateY(-50%);
        flex-direction:column; gap:var(--sp-1);
        border-radius:var(--radius-lg); padding:6px 5px;
      }
      .dock-btn { width:58px; height:50px; }
      /* FAB sits inline in the column rather than breaking the rhythm. The
         margin reset is the whole point: the base rule lifts the FAB with a
         negative top margin so it floats above a HORIZONTAL bar, and in a
         vertical rail that same lift just drags it onto its upstairs
         neighbour. Longhand `margin-top` too, because the base rule sets it
         longhand after its own shorthand. */
      .dock-fab { width:50px; height:50px; margin:2px 0; margin-top:2px; }
      .dock-fab svg { width:22px; height:22px; }
      /* The 140px reserved for a bottom dock is dead space once nav moves aside. */
      .main-scroll { padding-bottom:32px; }
      /* The mobile pass expanded these hit areas vertically only, to avoid
         colliding with horizontal neighbours. In a vertical rail the
         neighbours are above/below instead, so grow horizontally here. */
      .dock-btn::after { left:-4px; right:-4px; height:50px; }
    }


    /* Cards */
    .card {
 background:var(--surface); border:1px solid var(--glass-border);
      border-radius:var(--radius-lg); padding:var(--sp-4); transition:transform var(--transition), box-shadow var(--transition);
      animation:enter 0.25s var(--ease-out) backwards; overflow:hidden;
    }
    @media (hover:hover) {
      .card:hover { border-color:var(--glass-border-dark); }
    }
    /* Staggered reveal: each block in a section eases in slightly after the
       last. 0.25s with the stagger capped at 0.12s — the audited 0.5s + 0.30s
       stagger with a `backwards` fill left the last section invisible for
       0.8s on EVERY visit (design-audit-2026-09.md D1). The data is already
       in memory; the wait was pure choreography. */
    #homeSection > .card, #homeSection > .section { animation:enter 0.25s var(--ease-out) backwards; }
    #homeSection > *:nth-child(1) { animation-delay:0.02s; }
    #homeSection > *:nth-child(2) { animation-delay:0.04s; }
    #homeSection > *:nth-child(3) { animation-delay:0.06s; }
    #homeSection > *:nth-child(4) { animation-delay:0.08s; }
    #homeSection > *:nth-child(5) { animation-delay:0.10s; }
    #homeSection > *:nth-child(n+6) { animation-delay:0.12s; }
    @keyframes enter { from { opacity:0; transform:translateY(12px); } to { opacity:1; transform:translateY(0); } }
    /* The entrance plays ONCE per tab per launch. setTab marks a section
       .entered on every RE-visit; from then on its blocks render instantly
       (this also stops in-tab re-renders — every save used to replay the
       card entrance) and the whole pane gets one quiet 120ms fade instead.
       The #homeSection variants exist because the base stagger rule carries
       ID specificity, which a class-only override can never beat regardless
       of source order. */
    section.entered .card, section.entered > * { animation:none; }
    #homeSection.entered > .card, #homeSection.entered > .section, #homeSection.entered > * { animation:none; }
    section.entered.revisit { animation:fadeIn 0.12s var(--ease-out); }
    /* The section ids carry the entrance animation, and an id outranks
       .entered.revisit, so a re-visit replayed the 240ms slide (board 21). */
    #addSection.entered.revisit, #planSection.entered.revisit, #historySection.entered.revisit, #trackSection.entered.revisit, #reportsSection.entered.revisit { animation:fadeIn 0.12s cubic-bezier(0.16,1,0.3,1); }

    /* Delivery view. Two stat cells rather than the Lifecycle view's four,
       so the grid is declared here instead of inline; everything else reuses
       .track-stat-cell so the two views read as one screen. */
    .delivery-stat-grid { display:grid; grid-template-columns:repeat(2,1fr); gap:6px; text-align:center; }
    .delivery-stat-label { font-size:var(--fs-12); color:var(--text-secondary); font-weight:600; text-transform:none; letter-spacing:0; }
    .delivery-stat-value { font-size:var(--fs-16); font-weight:600; }
    .delivery-card { margin-bottom:var(--sp-2); cursor:pointer; }
    .delivery-meta {
      display:flex; justify-content:space-between; align-items:center; gap:var(--sp-2);
      font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; margin-top:2px;
    }
    .delivery-badge--pending { background:var(--warning-soft, var(--bg)); color:var(--warning-ink); border-color:var(--warning); }
    .delivery-badge--delivered { background:var(--success-soft); color:var(--success-ink); border-color:var(--success); }

    /* Lifecycle Overdue exits + completion labels. The strip lives inside a
       tap-to-edit card, so buttons swallow their own clicks; .btn already
       carries the 44px floor. */
    .lc-actions { display:flex; gap:var(--sp-2); margin-top:10px; }
    .lc-action-btn { flex:1; justify-content:center; font-size:var(--fs-14); padding:var(--sp-2) 10px; }
    .lc-action-undo { color:var(--text-secondary); }
    .lc-comp-badge { background:var(--bg); color:var(--text-secondary); border-color:var(--glass-border-dark); }
    /* Settings sheet (design prototypes, board 7): grouped rows, one place. */
    .settings-body { padding:var(--sp-1) var(--sp-3) var(--sp-4); }
    .settings-group { margin:10px 0 14px; }
    .settings-group-title { font-size:var(--fs-12); font-weight:600; color:var(--text-tertiary); text-transform:none; letter-spacing:0; margin:0 2px 6px; }
    .settings-card { background:var(--surface); border:1px solid var(--glass-border); border-radius:var(--radius-lg); padding:0 14px; }
    .settings-row {
      display:flex; align-items:center; gap:var(--sp-3); width:100%; min-height:52px; padding:6px 0;
      border:none; border-top:1px solid var(--glass-border); background:transparent; color:var(--text);
      font-family:inherit; text-align:left; cursor:pointer;
    }
    .settings-row:first-child { border-top:none; }
    .settings-icon {
      width:32px; height:32px; border-radius:11px; background:var(--bg); border:1px solid var(--glass-border-dark);
      color:var(--text-secondary); display:flex; align-items:center; justify-content:center; flex-shrink:0;
    }
    .settings-icon svg { width:16px; height:16px; }
    .settings-text { flex:1; min-width:0; display:flex; flex-direction:column; gap:2px; }
    .settings-name { font-size:var(--fs-16); font-weight:600; }
    .settings-sub { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }
    .settings-right { color:var(--text-secondary); font-size:var(--fs-14); font-weight:600; display:flex; align-items:center; gap:6px; flex-shrink:0; }
    .settings-right svg { width:14px; height:14px; }
    /* Lifecycle card, ring layout (design prototypes, board 5). */
    .lc-row { display:flex; align-items:center; gap:var(--sp-3); }
    .lc-ring { width:34px; height:34px; flex-shrink:0; }
    .lc-main { flex:1; min-width:0; }
    .lc-meta { font-size:var(--fs-14); color:var(--text-secondary); font-weight:500; margin-top:2px; }
    .lc-meta--faint { color:var(--text-tertiary); }
    .lc-days { font-weight:600; }
    .lc-badges { display:inline-flex; gap:var(--sp-1); align-items:center; flex-shrink:0; }
    .lc-focus { outline:2px solid var(--accent); outline-offset:2px; }
    /* Due-soon strip: the tab's headline, one tap from its card. */
    .lc-due-strip {
      display:flex; align-items:center; gap:10px; width:100%; min-height:44px; padding:var(--sp-2) var(--sp-3); margin-bottom:var(--sp-3);
      border-radius:var(--radius-sm); border:1px solid var(--warning); background:var(--warning-soft);
      color:var(--text); font-family:inherit; font-size:var(--fs-14); font-weight:500; text-align:left; cursor:pointer;
    }
    .lc-due-strip b { font-weight:600; }
    .lc-due-strip svg { width:16px; height:16px; margin-left:auto; color:var(--text-secondary); flex-shrink:0; }
    .lc-due-dot { width:8px; height:8px; border-radius:50%; flex-shrink:0; }
    /* Overdue strip (round-two board 7): the item, and Restock beside it. */
    .lc-overdue-strip {
      display:flex; align-items:center; gap:6px; min-height:44px; padding:var(--sp-1) var(--sp-1) var(--sp-1) var(--sp-3); margin-bottom:var(--sp-2);
      border-radius:var(--radius-sm); border:1px solid var(--danger); background:var(--danger-soft); font-size:var(--fs-14);
    }
    .lc-overdue-text { flex:1; min-width:0; display:flex; align-items:center; gap:10px; min-height:36px; background:none; border:0; padding:0; color:var(--text); font:inherit; font-size:var(--fs-14); font-weight:500; text-align:left; cursor:pointer; }
    .lc-overdue-text b { font-weight:600; }
    .lc-overdue-restock { min-height:36px; padding:0 10px; border-radius:var(--radius-pill); border:0; background:var(--danger); color:#fff; font:inherit; font-size:var(--fs-14); font-weight:600; white-space:nowrap; cursor:pointer; flex-shrink:0; }
    .lc-overdue-strip + .lc-due-strip { margin-top:0; }
    /* Stat cell words never wrap. */
    .track-stat-label { font-size:var(--fs-12); color:var(--text-secondary); font-weight:600; text-transform:none; letter-spacing:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
    /* Category group headers cost less: 8px above, 4px below (was 14/6). */
    @media (max-width:1099px) {
      #trackList .lc-cat-header { margin:var(--sp-2) 0 var(--sp-1); }
      #trackList .lc-cat-header:first-child { margin-top:2px; }
    }
    /* Reorder mode on the stats card: arrows and a Done button appear only
       after a long-press / right-click, so the default surface carries no
       14px targets. */
    .track-reorder-done { width:100%; margin-top:10px; }
    .track-stats.reordering .track-stat-cell { border-style:dashed; border-color:var(--glass-border-dark); }
    /* Single-line body for a ratios card with nothing to compare (D4). */

    /* Every tab section eases in on entry (display:none -> block restarts the
       animation, so this replays on each tab switch). Home's children already
       stagger via `enter`, so it is excluded to avoid double motion. */
    /* NOTE: --ease-out is "260ms cubic-bezier(...)" — a duration+easing pair,
       not a bare easing — so it cannot be combined with an explicit delay in
       an animation shorthand (three time values = invalid = animation:none).
       These rules spell the easing function out instead. */
    #addSection, #planSection, #historySection, #trackSection, #reportsSection {
      animation:sectionEnter 0.24s cubic-bezier(0.16,1,0.3,1);
    }
    /* Add fades rather than slides: a transformed ancestor turns its fixed
       Save bar into a positioned child for the length of the animation,
       parking it mid-screen until the slide ends. */
    #addSection {
      animation-name:fadeIn;
    }
    @keyframes sectionEnter { from { opacity:0; transform:translateY(8px); } to { opacity:1; transform:translateY(0); } }

    /* Line charts draw themselves in; the area fill fades up after the line
       has mostly landed. pathLength="1" on the path normalizes the dash math. */
    .chart-line { stroke-dasharray:1; animation:drawLine 0.8s cubic-bezier(0.16,1,0.3,1) 0.1s backwards; }
    @keyframes drawLine { from { stroke-dashoffset:1; } to { stroke-dashoffset:0; } }
    @keyframes fadeIn { from { opacity:0; } to { opacity:1; } }

    /* ---- Bolder motion accents ---- */
    /* Data dots pop in one after another, timed so each appears roughly as
       the drawing line reaches it; value labels land after the draw. */
    .chart-area svg circle { transform-box:fill-box; transform-origin:center; animation:dotPop 0.35s cubic-bezier(0.22,0.25,0,1) backwards; }
    .chart-area svg circle:nth-of-type(1) { animation-delay:0.15s; }
    .chart-area svg circle:nth-of-type(2) { animation-delay:0.26s; }
    .chart-area svg circle:nth-of-type(3) { animation-delay:0.37s; }
    .chart-area svg circle:nth-of-type(4) { animation-delay:0.48s; }
    .chart-area svg circle:nth-of-type(5) { animation-delay:0.59s; }
    .chart-area svg circle:nth-of-type(6) { animation-delay:0.70s; }
    @keyframes dotPop { from { opacity:0; transform:scale(0); } to { opacity:1; transform:scale(1); } }
    .chart-value-label { animation:fadeIn 0.4s ease 0.75s backwards; }
    /* Hero headline numbers focus in from a slight blur on Home entry. */
    #homeSection .progress-value { animation:valueIn 0.6s cubic-bezier(0.16,1,0.3,1) 0.1s backwards; }
    @keyframes valueIn { from { opacity:0; filter:blur(3px); transform:translateY(4px); } to { opacity:1; filter:blur(0); transform:translateY(0); } }
    /* Desktop: charts lift toward the cursor. */
    @media (hover:hover) { .chart-card:hover { transform:translateY(-2px); box-shadow:var(--elev-2); } }

    /* Event/Goal/Lifecycle list cards ease in with a tiny stagger on render
       (covers create/delete/reorder — the list re-renders each time), and
       press down on tap for touch feedback. */
    #eventsList .card, #goalsList .card, #trackList .card { animation:enter 0.3s cubic-bezier(0.16,1,0.3,1) backwards; }
    #eventsList .card:nth-child(2), #goalsList .card:nth-child(2), #trackList .card:nth-child(2) { animation-delay:0.04s; }
    #eventsList .card:nth-child(3), #goalsList .card:nth-child(3), #trackList .card:nth-child(3) { animation-delay:0.08s; }
    #eventsList .card:nth-child(n+4), #goalsList .card:nth-child(n+4), #trackList .card:nth-child(n+4) { animation-delay:0.12s; }
    #eventsList .card:active, #goalsList .card:active, #trackList .card:active { transform:scale(0.985); }

    /* Progress fills inside re-rendered lists grow to their value with a
       clean ease-out — deliberately no overshoot, so a bar never visually
       overstates its value mid-animation. (The Home hero bars persist in the
       DOM and interpolate via their width transition instead.) */
    #eventsList .progress-fill, #goalsList .progress-fill, #trackList .progress-fill {
      transform-origin:left; animation:barGrow 0.5s cubic-bezier(0.16,1,0.3,1);
    }
    @keyframes barGrow { from { transform:scaleX(0); } }

    /* History rows: render-scoped entrance. Only elements tagged .tx-enter
       animate — the first screenful of a flagged render (tab entry or
       filter/search change), staggered via inline delays. Everything below
       the fold renders with no animation at all, so scrolling reveals rows
       already in place instead of a bulk flash. A tighter 8px rise than the
       generic `enter` keeps the cascade feeling calm at list density. */
    /* One-by-one read: the 90ms inline stagger is a large fraction of this
       duration, so each row is mostly landed before the next begins, instead
       of the whole list moving as one wave. */
    #historyList .tx-enter { animation:rowEnter 0.26s cubic-bezier(0.16,1,0.3,1) backwards; }
    @keyframes rowEnter { from { opacity:0; transform:translateY(16px); } to { opacity:1; transform:translateY(0); } }
    /* A just-added expense announces itself: stronger slide + a highlight
       flash that fades out, distinct from the ambient stagger. */
    #historyList .tx-history-row.tx-new { animation:txNew 0.7s cubic-bezier(0.16,1,0.3,1); }
    @keyframes txNew {
      0% { opacity:0; transform:translateX(-12px); background:var(--accent-soft); }
      55% { opacity:1; transform:translateX(0); background:var(--accent-soft); }
      100% { background:transparent; }
    }

    /* Edge-of-range nudge when a swipe can't go further. */
    .edge-bounce-left { animation:edgeNudgeLeft 0.3s ease; }
    .edge-bounce-right { animation:edgeNudgeRight 0.3s ease; }
    @keyframes edgeNudgeLeft { 30% { transform:translateX(-8px); } }
    @keyframes edgeNudgeRight { 30% { transform:translateX(8px); } }

    @media (prefers-reduced-motion: reduce) {
      .card, #homeSection > *,
      #addSection, #planSection, #historySection, #trackSection, #reportsSection,
      .chart-line, .card-info, .history-selection-bar,
      .chart-area svg circle, .chart-value-label, #homeSection .progress-value,
      .dock-btn.on .dock-icon, .chip.on, .add-chip.on,
      .header-menu, .modal-overflow, .autocomplete-list.active,
      .dock-badge, .lc-blob,
      #eventsList .card, #goalsList .card, #trackList .card,
      #eventsList .progress-fill, #goalsList .progress-fill, #trackList .progress-fill,
      .edge-bounce-left, .edge-bounce-right,
      #historyList .tx-enter,
      #historyList .tx-history-row.tx-new { animation:none !important; }
      .modal-panel, .tip { transition:none !important; }

      /* Safety net behind the enumerated list above. The list stays because it
         documents intent, but it can only cover motion someone remembered to
         add to it, and a missed entry is an accessibility bug that no test
         above would notice. Verified safe to apply globally: the app has zero
         transitionend/animationend listeners, so nothing is waiting on a
         transition to finish before it advances state. Not 0s — a hair of
         duration still fires the events, so any future listener keeps working. */
      *, *::before, *::after {
        animation-duration:0.01ms !important;
        animation-iteration-count:1 !important;
        transition-duration:0.01ms !important;
        scroll-behavior:auto !important;
      }
    }

    .progress-header { display:flex; justify-content:space-between; align-items:flex-end; margin-bottom:var(--sp-3); }
    .progress-label { font-size:var(--fs-12); font-weight:600; color:var(--text-secondary); letter-spacing:0; }
    .progress-value { font-size:var(--fs-28); font-weight:600; color:var(--text); letter-spacing:-0.03em; line-height:1; }
    .progress-track { height:6px; background:var(--border); border-radius:var(--radius-pill); overflow:hidden; box-shadow:var(--inset); }
    .progress-fill { height:100%; background:var(--accent); border-radius:var(--radius-pill); transition:width 600ms var(--ease-out); position:relative; }
    /* Subtle sheen sweep on the fill for a premium, alive feel */
    .progress-fill::after {
      content:''; position:absolute; inset:0; border-radius:inherit;
      background:linear-gradient(90deg, transparent, rgba(255,255,255,0.25), transparent);
      transform:translateX(-100%); animation:sheen 2.6s cubic-bezier(0.16,1,0.3,1) 0.6s 1 both;
    }
    @media (prefers-reduced-motion: reduce) { .progress-fill::after { animation:none; } }
    @keyframes sheen { 0% { transform:translateX(-100%); } 55%,100% { transform:translateX(100%); } }
    .progress-fill.danger { background:var(--danger); }
    .progress-fill.warning { background:var(--warning); }

    /* Unified Home hero: progress + the three key stats in one surface. */
    .hero-card { padding:20px 18px 18px; margin-bottom:14px; box-shadow:var(--elev-1); }
    /* One line under the budget label: today's spend, count, daily average.
       Replaces the Expense Log hero (design prototypes, Home). */
    .hero-today { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; margin:-6px 0 10px; }
    /* Plan · This month (round-two board 4) */
    .plan-strip { padding:14px var(--sp-4); margin-bottom:var(--sp-3); }
    .plan-strip-grid { display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:10px; }
    .plan-strip-cell { border-left:2px solid var(--border); padding-left:10px; min-width:0; }
    .plan-strip-cell--income { border-color:var(--success); } .plan-strip-cell--free { border-color:var(--accent); }
    /* Sentence case (round seven, board 34): uppercase letter-spaced labels
       came back after One UI A2 retired them, and truncated at 360-390px. */
    .plan-strip-label { font-size:var(--fs-12); font-weight:600; color:var(--text-secondary); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
    .plan-strip-value { font-size:var(--fs-16); font-weight:600; letter-spacing:-0.03em; margin-top:var(--sp-1); font-variant-numeric:tabular-nums; white-space:nowrap; }
    .plan-strip-cell--income .plan-strip-value { color:var(--success); }
    .plan-strip-cell--free .plan-strip-value { color:var(--accent); }
    .plan-strip-cell--free.over .plan-strip-value { color:var(--danger-ink); }
    /* Income received against income expected (round six, board 2). */
    .plan-income-in { height:3px; margin-top:5px; border-radius:var(--radius-pill); overflow:hidden; background:var(--border); }
    .plan-income-in[hidden] { display:none; }
    .plan-income-in-fill { height:100%; width:0; background:var(--success); transition:width 600ms var(--ease-out); }
    /* ── Goals on the Saving row (round six, board 4) ── */
    .goal-need-line1 { display:flex; align-items:center; flex-wrap:wrap; gap:6px var(--sp-2); }
    .goal-need-line1 .goal-need-sum { margin:0; flex:1 1 180px; }
    .goal-need-detail { margin-top:6px; }
    .goal-need-detail[hidden] { display:none; }
    .goal-need { margin:var(--sp-2) 0 var(--sp-1); padding:10px var(--sp-3); border:1px solid var(--glass-border-dark); border-radius:var(--radius-md); }
    .goal-need-head {
      font-size:var(--fs-12); font-weight:600; letter-spacing:0; text-transform:none;
      color:var(--text-tertiary); margin-bottom:var(--sp-1);
    }
    .goal-need-row { display:flex; align-items:baseline; gap:var(--sp-2); padding:3px 0; font-size:var(--fs-14); }
    .goal-need-name { flex:1; min-width:0; font-weight:600; }
    .goal-need-left { font-weight:500; color:var(--text-tertiary); }
    .goal-need-amt { font-weight:600; font-variant-numeric:tabular-nums; }
    .goal-need-sum { margin:6px 0 0; font-size:var(--fs-14); color:var(--text-secondary); }
    .goal-need-sum b { color:var(--text); font-variant-numeric:tabular-nums; }
    .goal-need-pace { margin:var(--sp-1) 0 0; font-size:var(--fs-14); color:var(--text); font-weight:600; line-height:1.5; }
    .goal-need-line1 .plan-set { margin:0; }
    .goal-need-hint { margin:var(--sp-1) 0 0; font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }
    .goal-need-line { margin-top:var(--sp-1); font-size:var(--fs-14); font-weight:600; color:var(--text-secondary); }
    .plan-income-sub { margin:var(--sp-2) 0 0; font-size:var(--fs-14); font-weight:500; color:var(--text-secondary); }
    .plan-income-sub[hidden] { display:none; }
    .plan-stack { display:flex; height:6px; border-radius:var(--radius-pill); overflow:hidden; background:var(--border); margin-top:var(--sp-3); box-shadow:var(--inset); }
    .plan-stack-committed { width:0; background:var(--violet); transition:width 600ms var(--ease-out); }
    .plan-stack-spend { width:0; background:var(--accent); transition:width 600ms var(--ease-out); }
    .plan-stack-save { width:0; background:var(--success); transition:width 600ms var(--ease-out); }
    /* The jobs, from income down (round six, board 3). */
    .plan-jobs { margin:var(--sp-2) 0 0; }
    .plan-job { display:flex; align-items:baseline; gap:var(--sp-2); padding:3px 0; font-size:var(--fs-14); }
    .plan-job-dot { flex-shrink:0; width:8px; height:8px; border-radius:50%; background:var(--border); align-self:center; }
    .plan-job-dot--committed { background:var(--violet); }
    .plan-job-dot--saving { background:var(--success); }
    .plan-job-dot--allowance { background:var(--accent); }
    .plan-job-dot--promised { background:var(--magenta); }
    .plan-job-dot--free { background:none; border:1.5px dashed var(--text-tertiary); }
    .plan-job-name { flex:1; min-width:0; font-weight:600; }
    .plan-job-what { font-weight:500; color:var(--text-tertiary); }
    .plan-job-amt { font-weight:600; font-variant-numeric:tabular-nums; }
    .plan-job-empty { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }
    .plan-job-note { margin:0; font-size:var(--fs-14); color:var(--text-secondary); line-height:1.5; flex:1; min-width:0; }
    .plan-job-line { display:flex; align-items:center; gap:var(--sp-2); margin-top:var(--sp-2); flex-wrap:wrap; }
    .plan-legend-toggle { margin-left:auto; min-height:32px; padding:0 10px; border:1px solid var(--border); border-radius:var(--radius-pill); background:var(--surface); color:var(--text); font:inherit; font-size:var(--fs-14); font-weight:600; cursor:pointer; position:relative; }
    .plan-legend-toggle::after { content:''; position:absolute; inset:-6px 0; }
    .plan-legend-toggle[aria-expanded="true"] { background:var(--bg); }
    .plan-legend-toggle[hidden], .plan-legend[hidden] { display:none; }
    .plan-job-note[hidden] { display:none; }
    .plan-job-note b { color:var(--text); font-variant-numeric:tabular-nums; }
    .plan-legend { display:flex; flex-wrap:wrap; gap:var(--sp-1) var(--sp-3); margin:6px 0 0; font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }
    .plan-legend i { display:inline-block; width:7px; height:7px; border-radius:50%; margin-right:var(--sp-1); vertical-align:0; }
    /* Event and goal cards: the figure once, human dates, state as a badge. */
    .plan-card { padding:14px var(--sp-4); margin-bottom:var(--sp-2); cursor:pointer; }
    .plan-card-head { display:flex; align-items:center; gap:var(--sp-2); }
    .plan-card-name { flex:1; min-width:0; font-size:var(--fs-16); font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
    .plan-card-meta { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; margin-top:3px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
    .plan-card-bar { margin:var(--sp-3) 0 6px; }
    .plan-card-foot { display:flex; justify-content:space-between; align-items:center; gap:var(--sp-2); font-size:var(--fs-14); color:var(--text-secondary); font-weight:500; }
    .plan-card-right { white-space:nowrap; }
    .plan-card-foot b { font-weight:600; }
    /* Month in review (round-three board 6) */
    .review-card { padding:var(--sp-4); margin-bottom:10px; box-shadow:var(--elev-1); }
    .review-title { display:flex; align-items:center; gap:var(--sp-2); font-size:var(--fs-14); font-weight:600; }
    .review-title > svg { width:16px; height:16px; flex-shrink:0; color:var(--accent); }
    .review-title > span:first-of-type { flex:1; min-width:0; }
    .review-headline { font-size:var(--fs-20); font-weight:600; letter-spacing:-0.03em; margin:var(--sp-3) 0 var(--sp-1); color:var(--success); }
    .review-headline.over { color:var(--danger-ink); }
    .review-sub { font-size:var(--fs-14); color:var(--text-secondary); font-weight:500; line-height:1.45; }
    .review-bar { margin-top:var(--sp-3); }
    .review-block { margin-top:14px; padding-top:var(--sp-3); border-top:1px solid var(--glass-border); }
    .review-head { display:flex; align-items:baseline; gap:6px; font-size:var(--fs-14); font-weight:600; margin-bottom:var(--sp-1); }
    .review-head span { font-size:var(--fs-12); color:var(--text-tertiary); font-weight:500; }
    .review-mover { display:flex; align-items:center; gap:10px; padding:6px 0; font-size:var(--fs-14); border-top:1px solid var(--glass-border); }
    .review-mover:first-of-type { border-top:0; }
    .review-arrow { display:inline-flex; flex-shrink:0; }
    .review-arrow svg { width:14px; height:14px; }
    .review-arrow.up { color:var(--danger); } .review-arrow.down { color:var(--success); }
    .review-cat { flex:1; min-width:0; font-weight:500; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
    .review-delta { font-weight:600; font-variant-numeric:tabular-nums; white-space:nowrap; }
    .review-delta.up { color:var(--danger-ink); } .review-delta.down { color:var(--success-ink); }
    .review-now { width:60px; text-align:right; color:var(--text-tertiary); font-variant-numeric:tabular-nums; white-space:nowrap; }
    .review-note { display:flex; align-items:flex-start; gap:9px; padding:7px 0; font-size:var(--fs-14); line-height:1.45; border-top:1px solid var(--glass-border); }
    .review-note:first-of-type { border-top:0; }
    .review-note b { font-weight:600; }
    .review-note-icon { display:inline-flex; flex-shrink:0; margin-top:1px; }
    .review-note-icon svg { width:15px; height:15px; }
    .review-note-icon.alert { color:var(--warning); } .review-note-icon.cycle { color:var(--accent); }
    .plan-group { font-size:var(--fs-12); font-weight:600; color:var(--text-tertiary); text-transform:none; letter-spacing:0; margin:14px 0 2px; }
    .plan-group:first-child { margin-top:2px; }
    .plan-row { border-top:1px solid var(--glass-border); }
    .plan-head { display:flex; align-items:center; gap:var(--sp-2); width:100%; min-height:44px; padding:var(--sp-2) 0; background:none; border:0; color:inherit; font:inherit; text-align:left; cursor:pointer; }
    .plan-name { flex:1; font-size:var(--fs-14); font-weight:600; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
    .plan-amt { font-size:var(--fs-14); font-weight:600; font-variant-numeric:tabular-nums; white-space:nowrap; }
    .plan-amt .of { color:var(--text-tertiary); font-weight:500; }
    .plan-chev { width:14px; height:14px; color:var(--text-tertiary); flex-shrink:0; transition:transform 200ms var(--ease-out); }
    .plan-row.open .plan-chev { transform:rotate(180deg); }
    .plan-bar { margin:0 0 6px 30px; }
    .plan-note { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; margin:0 0 var(--sp-2) 30px; }
    .plan-note--over { color:var(--danger-ink); font-weight:600; }
    /* Offers under a row are buttons you can see and hit (round seven, board 22):
       inline text links were ~16px tall. */
    .plan-set, .plan-edit-toggle { display:inline-flex; align-items:center; min-height:32px; margin:var(--sp-1) 0 0; padding:0 10px; border:1px solid var(--border); border-radius:var(--radius-pill); background:var(--surface); font:inherit; font-size:var(--fs-14); font-weight:600; color:var(--text); cursor:pointer; position:relative; vertical-align:middle; }
    .plan-set::after, .plan-edit-toggle::after { content:''; position:absolute; inset:-6px -2px; }
    .plan-cats { display:flex; flex-direction:column; gap:2px; padding:0 0 6px 30px; }
    .plan-cat { display:flex; align-items:center; gap:var(--sp-2); min-height:26px; font-size:var(--fs-14); }
    .plan-cat-name { color:var(--text-secondary); font-weight:500; width:84px; flex-shrink:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
    .plan-cat-bar { flex:1; } .plan-cat-bar .progress-track { height:3px; }
    .plan-cat-amt { margin-left:auto; font-weight:600; font-variant-numeric:tabular-nums; white-space:nowrap; }
    .plan-cat-amt .of { color:var(--text-tertiary); font-weight:500; }
    .plan-cat-set { font-size:var(--fs-14); font-weight:600; color:var(--accent); padding:2px 6px; border-radius:var(--radius-pill); border:1px dashed var(--accent); background:none; font-family:inherit; cursor:pointer; white-space:nowrap; position:relative; }
    .plan-cat-set::after { content:''; position:absolute; inset:-10px -6px; }
    .plan-editor { margin:0 0 10px 30px; padding-top:var(--sp-2); border-top:1px dashed var(--glass-border-dark); }
    .plan-editor-actions { display:flex; gap:var(--sp-2); margin-top:var(--sp-2); }
    .plan-editor-actions .btn { justify-content:center; font-size:var(--fs-14); padding:9px; }
    .plan-editor-actions .btn-add { flex:1; border-style:dashed; }
    .plan-editor-actions .btn-total { font-size:var(--fs-14); padding:9px var(--sp-3); color:var(--text-secondary); }
    @media (max-width:480px) { .plan-cat-name { width:76px; } .plan-editor, .plan-cats, .plan-bar, .plan-note { margin-left:0; } }
    /* Hero trend: the Daily Averages card folded into one row. */
    .hero-trend { display:flex; align-items:center; justify-content:space-between; gap:var(--sp-3); margin-top:14px; padding-top:var(--sp-3); border-top:1px solid var(--glass-border); }
    .hero-trend:empty { display:none; }
    .hero-trend-label { font-size:var(--fs-14); font-weight:600; color:var(--text-tertiary); text-transform:none; letter-spacing:0; }
    .hero-trend-value { font-size:var(--fs-14); font-weight:600; margin-top:var(--sp-1); font-variant-numeric:tabular-nums; }
    .hero-trend-value .up { color:var(--danger-ink); } .hero-trend-value .down { color:var(--success-ink); } .hero-trend-value .vs { color:var(--text-tertiary); font-weight:500; }
    .hero-trend-sub { font-size:var(--fs-14); color:var(--text-tertiary); margin-top:2px; font-weight:500; }
    .hero-trend-link { background:var(--surface); border:1px solid var(--glass-border-dark); border-radius:var(--radius-pill); padding:6px 10px; min-height:32px; font:inherit; font-size:var(--fs-14); font-weight:600; color:var(--accent); cursor:pointer; position:relative; }
    .hero-trend-link::after { content:''; position:absolute; inset:-6px -4px; }
    .spark { display:flex; align-items:flex-end; gap:5px; height:48px; width:150px; flex-shrink:0; }
    .spark-col { flex:1; display:flex; flex-direction:column; justify-content:flex-end; align-items:center; gap:3px; min-width:0; }
    .spark-bar { width:100%; border-radius:3px 3px 1px 1px; background:var(--border); }
    .spark-col.now .spark-bar { background:var(--danger); }
    .spark-gap { width:100%; height:0; border-top:1px dashed var(--glass-border-dark); }
    .spark-lbl { font-size:var(--fs-12); color:var(--text-tertiary); font-weight:500; line-height:1; }
    .spark-col.now .spark-lbl { color:var(--text); font-weight:600; }
    /* This-month chip line (the Spending Ratios card, as one row). */
    .month-chips { display:flex; gap:6px; align-items:center; overflow-x:auto; scrollbar-width:none; margin:-2px 0 var(--sp-3); padding-bottom:2px; }
    .month-chips::-webkit-scrollbar { display:none; }
    .month-chips[hidden] { display:none; }
    /* A chip that states a fact has no border; only chips that open something (attention) do (round 8, H6). */
    .month-chip { flex-shrink:0; font-size:var(--fs-14); font-weight:600; padding:3px var(--sp-2); border-radius:11px; border:1px solid transparent; color:var(--text-tertiary); background:var(--bg); white-space:nowrap; }
    .month-chip--good { color:var(--success-ink); border-color:var(--success); background:var(--success-soft); }
    .month-chip--bad { color:var(--danger-ink); border-color:var(--danger); background:var(--danger-soft); }
    /* Tracked Transactions as collapsible type rows. */
    .tracked-row { border-top:1px solid var(--glass-border); }
    .tracked-head { display:flex; align-items:center; gap:var(--sp-2); width:100%; min-height:44px; padding:6px 0; background:none; border:0; color:inherit; font:inherit; text-align:left; cursor:pointer; }
    .tracked-name { flex:1; display:flex; align-items:center; flex-wrap:wrap; gap:var(--sp-1); font-size:var(--fs-14); font-weight:600; min-width:0; }
    .tracked-sub { font-weight:500; color:var(--text-tertiary); }
    .tracked-amt { font-size:var(--fs-14); color:var(--text-secondary); font-weight:500; font-variant-numeric:tabular-nums; white-space:nowrap; }
    .tracked-chev { width:14px; height:14px; color:var(--text-tertiary); flex-shrink:0; transition:transform 200ms var(--ease-out); }
    .tracked-row.open .tracked-chev { transform:rotate(180deg); }
    .tracked-bar { margin:0 0 var(--sp-2) var(--sp-6); }
    .tracked-cats { display:none; flex-direction:column; gap:2px; padding:0 0 var(--sp-2) var(--sp-6); }
    .tracked-row.open .tracked-cats { display:flex; }
    .tracked-cat { display:flex; align-items:center; gap:var(--sp-2); min-height:24px; font-size:var(--fs-14); }
    .tracked-cat-name { color:var(--text-secondary); font-weight:500; width:88px; flex-shrink:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
    .tracked-cat-bar { flex:1; }
    .tracked-cat-bar .progress-track { height:3px; }
    .tracked-cat-amt { margin-left:auto; font-weight:600; font-variant-numeric:tabular-nums; white-space:nowrap; }
    .tracked-cat-amt .of { color:var(--text-tertiary); font-weight:500; }
    .hero-today b { color:var(--text); font-weight:600; font-variant-numeric:tabular-nums; }
    /* Until payday (round six, board 5). */
    .hero-payday { margin:10px 0 0; font-size:var(--fs-14); font-weight:500; color:var(--text-secondary); line-height:1.5; }
    .hero-payday[hidden] { display:none; }
    .hero-payday b { color:var(--text); font-weight:600; font-variant-numeric:tabular-nums; }
    .hero-payday-vs { color:var(--text-tertiary); }
    /* Needs-attention chips: what is waiting on the user, tap to jump. */
    /* Active History filters, said back to you and removable. */
    /* 12px of clearance under the axis bar: the chips' hit-expanders reach
       6px up, and at 6px of margin they were swallowing taps meant for the
       bar's own buttons. */
    #historyFilterClear { display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin:10px 0 2px; }
    #historyFilterClear[hidden] { display:none; }
    .hfilter-chip {
      display:inline-flex; align-items:center; gap:5px; min-height:32px; padding:0 7px 0 10px;
      border-radius:var(--radius-pill); border:1px solid var(--accent); background:var(--accent-soft);
      color:var(--accent); font:inherit; font-size:var(--fs-14); font-weight:600; white-space:nowrap; cursor:pointer;
      position:relative; max-width:100%; overflow:hidden; text-overflow:ellipsis;
    }
    .hfilter-chip::after { content:''; position:absolute; inset:-6px -2px; }
    .hfilter-chip svg { width:11px; height:11px; flex-shrink:0; opacity:0.8; }
    .hfilter-clear-all {
      min-height:32px; padding:0 var(--sp-1); background:none; border:0; font:inherit; font-size:var(--fs-14);
      font-weight:600; color:var(--text-tertiary); cursor:pointer; position:relative;
    }
    .hfilter-clear-all::after { content:''; position:absolute; inset:-6px -4px; }
    .attention-row { display:flex; flex-wrap:wrap; gap:6px; margin-bottom:var(--sp-3); }
    /* A money alert states a fact and offers the entries behind it, so it
       takes the full width; the count chips share the line below. Scoped to
       the row so it outranks .attention-chip's own `flex`, which is declared
       further down the sheet — without that it shared the line and wrapped
       its text to four lines. */
    .attention-row .attention-chip--wide { flex:0 0 100%; }
    .attention-text { flex:1; min-width:0; text-align:left; }
    .attention-act { font-size:var(--fs-14); font-weight:600; white-space:nowrap; opacity:0.9; }
    .attention-act::after { content:' \203A'; }
    /* Coming up */
    .coming-row {
      display:flex; align-items:center; gap:9px; width:100%; min-height:44px; padding:7px 0;
      background:none; border:0; border-top:1px solid var(--glass-border); color:inherit; font:inherit;
      text-align:left; cursor:pointer;
    }
    .coming-row:first-child { border-top:0; }
    .coming-row > svg:first-child { width:15px; height:15px; flex-shrink:0; color:var(--accent); }
    .coming-main { flex:1; min-width:0; display:flex; flex-direction:column; gap:2px; }
    .coming-name { font-size:var(--fs-14); font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
    .coming-when { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }
    .coming-bar { width:56px; flex-shrink:0; }
    .coming-bar .progress-track { display:block; height:4px; }
    .coming-bar .progress-fill { display:block; }
    .coming-chev { width:14px; height:14px; flex-shrink:0; color:var(--text-tertiary); }
    .attention-chip {
      flex:1; display:inline-flex; align-items:center; gap:var(--sp-2); min-height:44px; padding:var(--sp-2) 10px;
      border-radius:var(--radius-sm); border:1px solid; background:var(--bg); color:var(--text);
      font-family:inherit; font-size:var(--fs-14); font-weight:600; text-align:left; cursor:pointer; transition:var(--transition);
    }
    .attention-chip svg { width:16px; height:16px; flex-shrink:0; }
    .attention-chip--warning { border-color:var(--warning); background:var(--warning-soft); }
    .attention-chip--warning svg { color:var(--warning); }
    .attention-chip--danger { border-color:var(--danger); background:var(--danger-soft); }
    .attention-chip--danger svg { color:var(--danger); }
    .attention-chip:active { transform:scale(0.98); }
    .hero-stats { display:grid; grid-template-columns:repeat(3,1fr); gap:var(--sp-2); margin-top:14px; }
    .hero-stat { display:flex; flex-direction:column; gap:3px; position:relative; padding-left:11px; }
    .hero-stat::before {
      content:''; position:absolute; left:0; top:2px; bottom:2px; width:2px;
      border-radius:1px; background:var(--border);
    }
    .hero-stat.danger::before { background:var(--danger); }
    .hero-stat.warning::before { background:var(--warning); }
    .hero-stat-label { font-size:var(--fs-12); font-weight:600; color:var(--text-tertiary); text-transform:none; letter-spacing:0; }
    .hero-stat-value { font-size:var(--fs-16); font-weight:600; letter-spacing:-0.03em; color:var(--text); line-height:1.1; }
    .hero-stat.danger .hero-stat-value { color:var(--danger-ink); }
    .hero-stat.warning .hero-stat-value { color:var(--warning-ink); }

    /* Shared chart-card chrome for Cash Flow Trend and Average Spend Per Day —
       same soft-card background, radius, shadow, padding, and header/graph
       spacing rhythm, so the two read as one consistent system rather than
       one being a flat section and the other a card. */
    .chart-card { padding:18px; margin-bottom:var(--sp-2); box-shadow:0px 1px 3px rgba(0,0,0,0.06); }
    /* No scroll container by design — the SVG viewBox compresses to fit any
       width instead, so all 6 months are always visible without scrolling. */
    .chart-area { width:100%; aspect-ratio:2/1; position:relative; }
    .chart-area svg .chart-label { font-size:var(--fs-12); fill:var(--text-tertiary); font-weight:500; }
    .chart-area svg .chart-value-label { font-size:var(--fs-12); fill:var(--text-secondary); font-weight:600; }
    .chart-legend { display:flex; gap:6px; margin-top:var(--sp-2); flex-wrap:wrap; }
    .chart-legend-item { display:flex; align-items:center; gap:var(--sp-1); font-size:var(--fs-12); position:relative; }
    /* Legend toggles are 23px tall, 6px apart: full-height expander, and
       half the shared gap each way so neighbours touch without overlap. */
    .legend-toggle::after { content:''; position:absolute; left:-3px; right:-3px; top:50%; transform:translateY(-50%); height:44px; }
    .chart-legend-dot { width:7px; height:7px; border-radius:50%; flex-shrink:0; }
    .chart-legend-label { font-size:var(--fs-12); color:var(--text-secondary); font-weight:600; }
    /* Legend entries double as show/hide toggles for their line. */
    .legend-toggle { border:none; background:transparent; padding:var(--sp-1) var(--sp-2); border-radius:var(--radius-pill); cursor:pointer; font-family:inherit; transition:var(--transition); }
    @media (hover:hover) { .legend-toggle:hover { background:var(--bg); } }
    .legend-toggle:active { transform:scale(0.96); }
    .legend-toggle.off { opacity:0.4; }
    .legend-toggle.off .chart-legend-label { text-decoration:line-through; }
    .legend-toggle:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
    /* Per-point tooltip: fades and scales in above the hovered/tapped dot. */
    .chart-tip {
      position:absolute; z-index:5; background:var(--surface-solid); border:1px solid var(--glass-border-dark);
      border-radius:var(--radius-sm); padding:var(--sp-1) var(--sp-2); font-size:var(--fs-14); font-weight:600; white-space:nowrap;
      pointer-events:none; box-shadow:var(--elev-2); opacity:0;
      transform:translate(-50%, -115%) scale(0.94);
      transition:opacity 150ms ease, transform 150ms cubic-bezier(0.16,1,0.3,1);
    }
    .chart-tip.show { opacity:1; transform:translate(-50%, -115%) scale(1); }
    @media (max-width:480px) {
      .chart-card { padding:14px; }
    }

    /* Flat secondary section: no card chrome, hairline separation.
       Padding 13 -> 22: One UI does not pack content densely, and each grouped
       section is supposed to get clear air around it. The hairline stays —
       in a data-dense financial app it still helps scanning, and air alone
       does not group as unambiguously as air plus a rule. */
    .section {
      padding:22px 2px; border-top:1px solid var(--glass-border);
      animation:enter 0.5s var(--ease-out) backwards;
    }
    #homeSection > .section:first-of-type { border-top:none; }

    .chip {
      padding:5px var(--sp-3); border-radius:var(--radius-pill); border:1px solid var(--glass-border-dark); background:var(--surface); color:var(--text-secondary);
      font-size:var(--fs-14); font-weight:500; cursor:pointer; white-space:nowrap; flex-shrink:0; transition:var(--transition); font-family:inherit;
    }
    @media (hover:hover) { .chip:hover { color:var(--text); background:var(--bg); } }
    .chip:active { background:var(--accent-soft); transform:scale(0.97); }
    .chip.on { background:var(--accent); color:var(--accent-inverse); border-color:var(--accent); transition:var(--ease-spring); animation:chipPop 0.3s cubic-bezier(0.22,0.25,0,1); }
    /* Monotonic, same reason as dockPop — no push past 1.0 and back. */
    @keyframes chipPop { 0% { transform:scale(0.92); } 100% { transform:scale(1); } }
    .add-chip.on { animation:chipPop 0.3s cubic-bezier(0.22,0.25,0,1); }
    .chip:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
    .chip-grid { display:flex; flex-wrap:wrap; gap:var(--sp-2); }

    /* ⓘ buttons on Home cards + their toggled explanation blurbs. */
    .info-btn {
      width:24px; height:24px; border:1.5px solid var(--glass-border-dark); border-radius:50%; background:transparent; color:var(--text-tertiary); cursor:pointer;
      padding:0; display:inline-flex; align-items:center; justify-content:center; margin-left:var(--sp-1); vertical-align:middle; flex-shrink:0;
    }
    .info-btn svg { width:13px; height:13px; display:block; }
    @media (hover:hover) { .info-btn:hover { color:var(--text); } }
    .info-btn:focus-visible { outline:2px solid var(--accent); outline-offset:2px; border-radius:50%; }
    /* ── Desktop hover affordances ────────────────────────────────────────
       Transaction rows and list cards are clickable but gave a mouse user no
       hover cue at all — on desktop that reads as "not interactive". Scoped
       to (hover:hover) so touch devices don't get a sticky stuck-on state
       after a tap. Keyboard users are covered separately by the existing
       :focus-visible rules, never by hover alone. */
    @media (hover:hover) {
      .tx-item:hover { background:var(--bg); }
      #eventsList .card:hover, #goalsList .card:hover, #trackList .card:hover {
        border-color:var(--glass-border-dark); box-shadow:var(--elev-2); transform:translateY(-1px);
      }
    }

    /* Tooltip for [data-tip] controls — replaces mouse-only native `title`.
       position:fixed because it's appended to <body> and positioned from
       viewport coords, so it can't be clipped by an overflow:hidden ancestor. */
    .tip {
      position:fixed; z-index:1500; pointer-events:none;
      background:var(--text); color:var(--surface-solid);
      font-size:var(--fs-12); font-weight:600; line-height:1.3;
      padding:5px var(--sp-2); border-radius:6px; max-width:220px;
      box-shadow:var(--elev-2);
      opacity:0; transform:translateY(2px);
      transition:opacity 120ms ease, transform 120ms cubic-bezier(0.16,1,0.3,1);
    }
    .tip.show { opacity:1; transform:translateY(0); }

    /* Shortcut list rows in the ? dialog. */
    .shortcut-row { display:flex; align-items:center; justify-content:space-between; gap:var(--sp-4); padding:var(--sp-2) 0; border-bottom:1px solid var(--glass-border-dark); font-size:var(--fs-14); font-weight:500; }
    .shortcut-row:last-of-type { border-bottom:none; }
    .shortcut-row kbd {
      display:inline-block; min-width:20px; text-align:center; padding:2px 6px; margin:0 1px;
      font-family:inherit; font-size:var(--fs-12); font-weight:600; color:var(--text-secondary);
      background:var(--bg); border:1px solid var(--glass-border-dark); border-bottom-width:2px; border-radius:5px;
    }

    /* ── Command palette (Ctrl/Cmd+K) ──────────────────────────────────────
       The desktop app's front door. The launcher lives in the header; the
       overlay reuses .modal for the layer stack but positions itself
       top-centre rather than as a bottom sheet. */

    /* Desktop-only header launcher. Hidden by default (mobile chrome stays as
       is), shown from 900px where there's room for it beside the brand. */
    .cmd-launcher { display:none; }
    /* Shown to a fine pointer that can hover — a keyboard-and-trackpad tablet
       at 820px included — rather than by width alone (round seven, catalogue). */
    @media (min-width:900px), (min-width:700px) and (hover:hover) and (pointer:fine) {
      .cmd-launcher {
        display:flex; align-items:center; gap:9px;
        margin:0 auto 0 20px; padding:var(--sp-2) var(--sp-3); min-width:280px; max-width:420px;
        background:var(--bg); border:1px solid var(--glass-border-dark);
        border-radius:var(--radius-md); color:var(--text-tertiary);
        font-family:inherit; font-size:var(--fs-14); font-weight:500; cursor:pointer;
        transition:var(--transition);
      }
      @media (hover:hover) { .cmd-launcher:hover { border-color:var(--text-tertiary); color:var(--text-secondary); background:var(--surface); } }
      .cmd-launcher:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
      .cmd-launcher svg { width:15px; height:15px; flex-shrink:0; }
      .cmd-launcher span { flex:1; text-align:left; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
      .cmd-launcher kbd {
        font-family:inherit; font-size:var(--fs-12); font-weight:600; letter-spacing:0.03em;
        padding:2px 6px; border-radius:5px; color:var(--text-tertiary);
        background:var(--surface); border:1px solid var(--glass-border-dark); flex-shrink:0;
      }
    }

    /* Position the palette top-centre. .modal is flex-column, so the panel is
       aligned rather than pinned to the bottom like .modal-panel. */
    .cmd-modal { align-items:center; }
    .cmd-panel {
      margin-top:12vh; width:min(640px, 92vw); max-height:70vh;
      display:flex; flex-direction:column; overflow:hidden;
      background:var(--surface); border:1px solid var(--glass-border);
      border-radius:var(--radius-xl); box-shadow:var(--elev-3);
      transform:translateY(-8px) scale(0.98); opacity:0;
      transition:transform 220ms cubic-bezier(0.22,0.25,0,1), opacity 160ms;
    }
    .cmd-modal.open .cmd-panel { transform:translateY(0) scale(1); opacity:1; }

    .cmd-search {
      display:flex; align-items:center; gap:10px; padding:var(--sp-4) 18px;
      border-bottom:1px solid var(--glass-border-dark); flex-shrink:0;
    }
    .cmd-search-icon { width:18px; height:18px; color:var(--text-tertiary); flex-shrink:0; }
    #cmdInput {
      flex:1; border:none; background:transparent; outline:none;
      font-family:inherit; font-size:var(--fs-16); font-weight:500; color:var(--text);
      /* 16px avoids iOS zoom-on-focus; also the right size for a prominent
         search field on desktop. */
    }
    #cmdInput::placeholder { color:var(--text-tertiary); font-weight:500; }
    .cmd-esc-hint {
      font-family:inherit; font-size:var(--fs-12); font-weight:600; color:var(--text-tertiary);
      padding:2px 6px; border-radius:5px; background:var(--bg);
      border:1px solid var(--glass-border-dark); flex-shrink:0;
    }

    .cmd-list { overflow-y:auto; -webkit-overflow-scrolling:touch; padding:var(--sp-2); flex:1; }
    .cmd-item {
      display:flex; align-items:center; gap:var(--sp-3); width:100%;
      padding:10px var(--sp-3); border:none; border-radius:var(--radius-md);
      background:transparent; color:var(--text); cursor:pointer;
      font-family:inherit; text-align:left; transition:background 120ms;
    }
    .cmd-item.sel { background:var(--accent-soft); }
    .cmd-item-icon { width:34px; height:34px; flex-shrink:0; display:flex; align-items:center; justify-content:center;
      border-radius:var(--radius-sm); background:var(--bg); color:var(--text-secondary); }
    .cmd-item.sel .cmd-item-icon { background:var(--accent); color:var(--accent-inverse); }
    .cmd-item-icon svg { width:17px; height:17px; }
    .cmd-item-body { flex:1; min-width:0; display:flex; flex-direction:column; gap:1px; }
    .cmd-item-label { font-size:var(--fs-16); font-weight:600; letter-spacing:-0.01em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
    .cmd-item-hint { font-size:var(--fs-12); font-weight:500; color:var(--text-tertiary); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
    .cmd-item-group { font-size:var(--fs-12); font-weight:600; text-transform:none; letter-spacing:0; color:var(--text-tertiary); flex-shrink:0; }
    .cmd-item-keys { display:flex; gap:3px; flex-shrink:0; }
    .cmd-item-keys kbd {
      font-family:inherit; font-size:var(--fs-12); font-weight:600; min-width:18px; text-align:center;
      padding:2px 5px; border-radius:5px; color:var(--text-secondary);
      background:var(--bg); border:1px solid var(--glass-border-dark);
    }
    .cmd-empty { padding:28px 18px; text-align:center; font-size:var(--fs-14); font-weight:500; color:var(--text-tertiary); }
    .cmd-foot {
      display:flex; gap:var(--sp-4); padding:10px 18px; flex-shrink:0;
      border-top:1px solid var(--glass-border-dark);
      font-size:var(--fs-12); font-weight:500; color:var(--text-tertiary);
    }
    .cmd-foot kbd {
      font-family:inherit; font-size:var(--fs-12); font-weight:600; padding:1px 5px; margin-right:2px;
      border-radius:4px; color:var(--text-secondary); background:var(--bg); border:1px solid var(--glass-border-dark);
    }
    @media (prefers-reduced-motion: reduce) {
      .cmd-panel { transition:none; }
    }

    /* ── Touch-target expanders ────────────────────────────────────────────
       These controls are drawn small on purpose (a 13px ⓘ, a 28px close) but
       were 15–28px of actual HIT area, well under the 44px floor. The ::after
       is absolutely positioned, so it enlarges the tap region WITHOUT changing
       layout or the drawn size — nothing shifts.

       Expansion is VERTICAL ONLY, deliberately: every one of these sits in a
       horizontal row with a 4–6px gap to its neighbour, so growing sideways
       would make adjacent hit areas overlap and steal each other's taps.
       Vertical is collision-free (nothing is stacked within 44px above or
       below them) and it's the dominant thumb-miss axis anyway. Widths that
       remain under 44 are recorded in the findings doc. */
    .info-btn, .modal-close, .icon-btn, .dock-btn, #profileChip, #monthChip,
    .chip, .danger-toggle-btn, .track-move-btn { position:relative; }
    .info-btn::after, .modal-close::after, .icon-btn::after,
    .dock-btn::after, #profileChip::after, #monthChip::after,
    .chip::after, .danger-toggle-btn::after, .track-move-btn::after {
      content:''; position:absolute; left:0; right:0;
      top:50%; transform:translateY(-50%); height:44px;
    }

    /* ── Width expanders ──────────────────────────────────────────────────
       Horizontal room is scarce in these rows, so each expander grows
       ASYMMETRICALLY — outward into whitespace, and only half-way into a gap
       shared with an interactive neighbour, so two expanders can never
       overlap. Values are derived from the real gaps (6px between the modal
       header buttons, 4px between the header chips). */
    .info-btn::after { left:-20px; right:-9px; }            /* 15 + 29 = 44; left runs under non-interactive title text */
    /* Only 1px into the 4px gap it shares with the month chip (which also
       takes 1px), so the two can't overlap; the rest grows right into the
       header's own padding. */
    .header-controls .icon-btn::after { left:-1px; right:-15px; }  /* 28 + 16 = 44 */
    /* Modal headers hold up to two of these 6px apart: the first (overflow)
       grows left under the title, the last (close) grows right into the
       panel's own padding. Each takes only 3px of the shared gap. */
    .modal-header .modal-close:not(:last-of-type)::after { left:-13px; right:-3px; }
    .modal-header .modal-close:last-of-type::after { left:-3px; right:-13px; }
    .chip::after { left:-1px; right:-1px; }
    #profileChip::after { left:-1px; right:-1px; }
    /* Lifecycle reorder arrows: a deliberate exception to the 44px floor.
       They sit INSIDE the stat cell that filters the list, 2px apart from
       each other. Reaching 44px would make each arrow blanket both the cell
       and its twin — trading a primary action (filter) and a sibling control
       for a secondary one. So: expand vertically only, and take just 1px of
       the 2px gap. Measured result ~18x32. Recorded as a per-control
       decision per §4 ("decide per control, record it"). */
    .track-move-btn::after { left:-1px; right:-1px; height:32px; }

    /* ── Minimum heights where the control IS the layout ──────────────────
       Unlike the expanders above, these rows have room to simply be taller,
       which is the cleaner fix than an overlay. */
    .collapse-toggle { min-height:44px; box-sizing:border-box; }
    .field .inp, .field input, .field select, .field textarea { min-height:44px; }
    .segmented-btn, .type-btn, .add-chip, .recurring-row, .btn { min-height:44px; }
    /* Flex/grid children need the box to actually grow rather than just
       reserving space, and chips must stay vertically centred. */
    .add-chip, .type-btn, .segmented-btn, .btn { display:inline-flex; align-items:center; justify-content:center; }
    /* Higher-specificity repeats: these two are overridden by their container's
       own rules, so the floor has to be restated at matching specificity.
       min-width catches short labels ("FY") that flex down to ~24px. */
    .add-quick-row .add-chip { min-height:44px; }
    /* Row tags (design prototypes, Add): a quiet name at the head of each
       chip row, so Type / Category / Mode / Recent read as different rows
       without the caption line D11 removed. */
    .add-row-tag {
      display:inline-flex; align-items:center; flex:0 0 auto; height:44px; padding:0 var(--sp-2) 0 2px;
      font-size:var(--fs-12); font-weight:600; color:var(--text-tertiary); text-transform:none; letter-spacing:0;
    }
    #txRecentChips:empty { display:none; }
    #txBudgetChips[hidden] { display:none; }
    /* Item on one tagged line, like the chip rows above it. */
    .add-item-row { display:flex; align-items:center; gap:6px; margin-bottom:var(--sp-2); }
    .add-item-wrap { flex:1; min-width:0; }
    .add-item-wrap #txItem { width:100%; box-sizing:border-box; }
    /* When · how: three pills on one line (round-two board 2). */
    .meta-strip { display:flex; align-items:center; gap:6px; margin-bottom:var(--sp-2); }
    .meta-pill {
      flex:1; min-width:0; height:40px; padding:0 10px 0 var(--sp-3); border-radius:var(--radius-pill);
      background:var(--bg); border:1px solid var(--glass-border-dark); color:var(--text);
      font:inherit; font-size:var(--fs-12); font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
      text-align:left; cursor:pointer;
    }
    .meta-pill--sub { flex:0.8; }
    .meta-pill:active { background:var(--accent-soft); }
    .meta-pill:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
    /* More: dashed chips that reveal one field each. */
    .more-row { display:flex; align-items:center; gap:6px; margin-bottom:var(--sp-2); }
    .more-row .add-row-tag { height:34px; }
    .more-chips { display:flex; flex-wrap:nowrap; gap:6px; flex:1; min-width:0; overflow-x:auto; -webkit-overflow-scrolling:touch; scrollbar-width:none; padding:5px 0; margin:-5px 0; }
    .more-chips::-webkit-scrollbar { display:none; }
    .more-chip {
      display:inline-flex; align-items:center; gap:5px; height:34px; padding:0 11px; border-radius:var(--radius-pill);
      border:1px dashed var(--glass-border-dark); background:transparent; color:var(--text-secondary);
      font:inherit; font-size:var(--fs-14); font-weight:600; white-space:nowrap; cursor:pointer; position:relative;
    }
    .more-chip::after { content:''; position:absolute; inset:-5px 0; }
    .more-chip.on { border-style:solid; border-color:var(--accent); background:var(--accent-soft); color:var(--accent); }
    .more-chip:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
    .more-chip[hidden] { display:none; }
    .more-panels { display:flex; flex-direction:column; gap:6px; }
    .more-panels:empty { display:none; }
    .more-panel { background:var(--surface); border:1px solid var(--glass-border); border-radius:var(--radius-lg); padding:10px var(--sp-3); }
    .more-panel[hidden] { display:none; }
    .more-panel .field:last-child { margin-bottom:0; }
    .more-body { }
    /* Room for the fixed Save bar over the form's tail. */
    .add-tail { height:96px; }
    /* Quick-add sheet (round-two board 1): #addSection as a bottom sheet
       over the current tab. Below the modals (z 1000) so the date and mode
       pickers open above it; above the dock, which hides meanwhile. */
    .quick-sheet-backdrop { position:fixed; inset:0; background:rgba(0,0,0,0.6); z-index:890; }
    .quick-sheet-backdrop[hidden] { display:none; }
    .quick-sheet-head { display:none; align-items:center; justify-content:space-between; gap:10px; margin:0 0 var(--sp-2); }
    .quick-sheet-head[hidden] { display:none; }
    .quick-sheet-handle { position:absolute; top:6px; left:50%; width:36px; height:4px; margin-left:-18px; border-radius:2px; background:var(--border); }
    .quick-sheet-title { font-size:var(--fs-16); font-weight:600; }
    .quick-sheet-full { display:inline-flex; align-items:center; gap:5px; min-height:36px; padding:0 6px; background:none; border:0; font:inherit; font-size:var(--fs-14); font-weight:600; color:var(--accent); cursor:pointer; }
    .quick-sheet-full svg { width:13px; height:13px; }
    body.quick-sheet #addSection {
      display:block !important; position:fixed; left:0; right:0; bottom:0; z-index:900; max-width:720px; margin:0 auto;
      max-height:min(88vh, 88dvh); overflow-y:auto; -webkit-overflow-scrolling:touch;
      background:var(--surface); border:1px solid var(--glass-border); border-bottom:0; border-radius:var(--radius-xl) var(--radius-xl) 0 0;
      padding:14px 16px calc(12px + env(safe-area-inset-bottom)); box-shadow:0 -8px 30px rgba(0,0,0,0.45);
      animation:sheetUp 260ms var(--ease-out);
    }
    @keyframes sheetUp { from { transform:translateY(24px); opacity:0; } to { transform:none; opacity:1; } }
    @media (prefers-reduced-motion: reduce) { body.quick-sheet #addSection { animation:none; } }
    body.quick-sheet #addSection .quick-sheet-head:not([hidden]) { display:flex; }
    body.quick-sheet #addSection .home-title,
    body.quick-sheet #addSection .more-row,
    body.quick-sheet #addSection .more-panels,
    body.quick-sheet #addSection .add-tail { display:none; }
    body.quick-sheet #addSection .add-sticky { position:static; padding:10px 0 0; max-width:none; }
    /* The dock's One UI variant is addressed by id further down the sheet;
       the sheet has to outrank that too. */
    body.quick-sheet .dock, body.quick-sheet #dockNav { display:none !important; }
    /* From / To on one line even at phone width — the generic .field-row
       stacks below 480px, but two short place names fit side by side. */
    .field-row.journey-row { flex-direction:row; gap:var(--sp-2); }
    .journey-hint { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; margin-top:6px; min-height:0; }
    .journey-hint:empty { display:none; }
    .segmented .segmented-btn { min-height:44px; min-width:44px; }
    .danger-toggle-btn::after { left:-6px; right:-6px; }

    .card-info {
      font-size:var(--fs-14); color:var(--text-secondary); font-weight:500; background:var(--bg);
      border-radius:var(--radius-sm); padding:var(--sp-2) 10px; margin:var(--sp-2) 0; line-height:1.5;
      animation:infoIn 0.2s cubic-bezier(0.16,1,0.3,1);
    }
    @keyframes infoIn { from { opacity:0; transform:translateY(-4px); } to { opacity:1; transform:translateY(0); } }
    /* Size modifier: compact chip for dense header/utility contexts. */
    .chip-sm { padding:var(--sp-1) 10px; font-size:var(--fs-12); }
    /* Round 8 (A1): the header pills read at the size they can be hit. */
    #profileChip, #monthChip { min-height:32px; padding:6px 12px; font-size:var(--fs-14); }
    .month-step { width:32px; height:32px; }
    .chip-36 { min-height:36px; padding:8px 12px; }

    .cat-header { display:flex; justify-content:space-between; align-items:center; margin-bottom:var(--sp-2); }
    .cat-title { font-size:var(--fs-14); font-weight:600; display:flex; align-items:center; gap:6px; letter-spacing:-0.01em; }
    .cat-badge { font-size:var(--fs-12); font-weight:600; color:var(--text-tertiary); background:var(--bg); padding:2px 6px; border-radius:11px; border:1px solid var(--glass-border-dark); }
    .info-btn {
      width:15px; height:15px; flex-shrink:0; border-radius:50%; border:1px solid var(--glass-border-dark);
      background:transparent; color:var(--text-tertiary); font-size:var(--fs-12); font-weight:600; font-style:normal;
      font-family:inherit; line-height:1; cursor:pointer; padding:0;
      display:inline-flex; align-items:center; justify-content:center; transition:var(--transition);
      vertical-align:middle; margin-left:5px; text-transform:none; letter-spacing:0; position:relative; top:-1px;
    }
    .info-btn:hover, .info-btn:active { background:var(--bg); color:var(--text-secondary); border-color:var(--text-tertiary); }
    .info-btn:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }

    .tx-item { display:flex; align-items:center; gap:10px; padding:var(--sp-2) 0; border-bottom:1px solid var(--glass-border-dark); min-height:44px; cursor:pointer; transition:background var(--transition); border-radius:var(--radius-sm); }
    .tx-item:last-child { border-bottom:none; }
    .tx-history-row:active { background:var(--accent-soft); }
    .tx-icon {
      width:32px; height:32px; border-radius:11px; background:var(--bg); color:var(--text-secondary); display:flex; align-items:center; justify-content:center;
      font-size:var(--fs-12); font-weight:600; flex-shrink:0; border:1px solid var(--glass-border-dark);
    }
    .tx-icon.type-badge { background:var(--tbg); color:var(--tfg); border-color:transparent; }
    [data-theme="dark"] .tx-icon.type-badge { background:var(--tbg-d); color:var(--tfg-d); }
    .tx-content { flex:1; min-width:0; }
    /* Flex, not a single truncating block: the item name shrinks and ellipses
       on its own, but the icon cluster never shrinks or gets clipped by that
       truncation — a long name can no longer silently hide a danger/refund/
       lifecycle icon that comes after it. */
    .tx-title { display:flex; align-items:center; font-weight:500; letter-spacing:-0.01em; min-width:0; }
    .tx-title-text { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0; flex-shrink:1; }
    .tx-title-icons { display:inline-flex; align-items:center; flex-shrink:0; white-space:nowrap; }
    .tx-meta { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; margin-top:2px; }
    .tx-amount { font-size:var(--fs-14); font-weight:600; font-variant-numeric:tabular-nums; flex-shrink:0; letter-spacing:-0.01em; }
    .tx-amount.income { color:var(--success); }
    .tx-amount.expense { color:var(--ink); }
    /* Shared, non-interactive status-icon formatting for every row indicator
       (lifecycle, refund/exchange initiated or completed, danger, split,
       mirror, transfer-in) — one wrapper, one size, one stroke, one base
       color, so none of them can drift, shrink, or look like a different
       component from the others. Only the inner SVG path (and, for danger,
       the color modifier) differs between meanings. */
    .expense-status-icon {
      width:18px; height:18px; display:inline-flex; align-items:center; justify-content:center;
      margin-left:7px; vertical-align:middle; color:var(--accent); flex-shrink:0;
      transition:filter 150ms ease;
    }
    /* Adaptive sizing — mobile 18px / tablet 19px / desktop 20px. stroke-width
       stays a constant "2" in the SVG's own 24-unit coordinate space, so it
       scales proportionally with the box for free; it never needs its own
       per-breakpoint value. */
    @media (min-width:768px) { .expense-status-icon { width:19px; height:19px; } }
    @media (min-width:1024px) { .expense-status-icon { width:20px; height:20px; } }
    .expense-status-icon svg { display:block; width:100%; height:100%; stroke-width:2; }
    /* Non-interactive, but a subtle color lift on desktop hover signals "this
       icon means something" without any size/shift animation. */
    @media (hover:hover) {
      .expense-status-icon:hover { filter:brightness(1.25); }
    }
    /* Danger is an alert, not an info marker — the one case where the whole
       glyph (not just an inner accent) recolors, so it still stands out. */
    .expense-status-icon--danger { color:var(--danger); }
    /* Status-based coloring only — shape, size, stroke, spacing all stay
       identical to the base .expense-status-icon; only `color` changes. */
    .expense-status-icon--refund-initiated { color:var(--danger); }
    .expense-status-icon--refund-completed { color:var(--success); }
    .expense-status-icon--exchange-initiated { color:var(--teal-blue); }
    .expense-status-icon--exchange-completed { color:var(--violet); }
    /* Delivery: warning while it is still coming, success once it lands —
       the same two-state colour logic the refund pair uses. */
    .expense-status-icon--delivery-pending { color:var(--warning); }
    .expense-status-icon--delivered { color:var(--success); }
    /* One marker for three independent statuses: the leading one's glyph and
       colour, with a count for the rest (round-four board 4). */
    .expense-status-icon--multi { position:relative; overflow:visible; }
    .expense-status-icon--multi .status-count {
      position:absolute; right:-7px; bottom:-6px; min-width:15px; height:15px; padding:0 3px;
      display:flex; align-items:center; justify-content:center; box-sizing:border-box;
      border-radius:6px; background:var(--surface); border:1px solid currentColor;
      font-size:var(--fs-12); font-weight:600; line-height:1; font-variant-numeric:tabular-nums;
    }
    /* The three headings inside the one Status panel. */
    .add-section-title.status-part { margin-top:14px; padding-top:var(--sp-3); border-top:1px solid var(--glass-border-dark); }

    /* Group headers. History groups by date, Lifecycle by category; they are
       the same object — a pill, a leader line, and a figure — so they share
       one set of rules rather than drifting apart. */
    .tx-date-header, .lc-cat-header { display:flex; align-items:center; justify-content:space-between; gap:var(--sp-2); padding:0; margin:14px 0 6px; }
    .tx-date-header:first-child, .lc-cat-header:first-child { margin-top:2px; }
    .tx-date-header .tx-date-label, .lc-cat-header .lc-cat-label {
      display:inline-block; padding:var(--sp-1) 10px; font-size:var(--fs-12); font-weight:600;
      color:var(--accent-inverse, #fff); background:var(--accent);
      border-radius:var(--radius-pill, 999px); text-transform:uppercase; letter-spacing:0.6px; white-space:nowrap;
      overflow:hidden; text-overflow:ellipsis; min-width:0; flex-shrink:1;
    }
    /* Dotted leader line filling the gap between the date pill and the total;
       shrinks on narrow screens but never collapses below min-width. */
    .tx-date-connector, .lc-cat-connector {
      flex:1 1 12px; min-width:12px; align-self:center; height:0;
      border-bottom:1px dotted var(--border); opacity:0.75;
    }
    /* Daily total: right-aligned on the same row as the date pill, non-interactive. */
    /* "N due" carries the full text colour rather than --warning: see
       renderTrack. The blob beside it is what says urgent. */
    .lc-cat-count.lc-cat-due { color:var(--text); display:inline-flex; align-items:center; }
    .tx-date-total, .lc-cat-count {
      font-size:var(--fs-16); font-weight:600; color:var(--text-secondary);
      font-variant-numeric:tabular-nums; white-space:nowrap; overflow:hidden;
      text-overflow:ellipsis; flex-shrink:0;
    }

    /* History rows: right-side column holds the ⋯ menu button (top, aligned
       with the title-line icons) and the amount (below) — a fixed structure
       that never shifts regardless of how many status icons the title shows. */
    /* The tap tint has to be rounded to the row's own corner or the flash
       reads as a hard rectangle sitting under soft content. */
    .tx-history-row { align-items:flex-start; position:relative; border-radius:var(--radius-md); }
    /* Clipped only while the body is displaced: a resting clip would cut the
       ⋮ button's hit-expander, which reaches past the row's edge on purpose. */
    .tx-history-row.tx-swiping, .tx-history-row.tx-swipe-open { overflow:hidden; }
    /* The swipe moves the row's BODY; the tray waits under it at the right
       edge and is only in the layout while swiping or parked open. */
    .tx-swipe-body { display:flex; align-items:flex-start; gap:10px; flex:1; min-width:0; }
    /* Above the tray only while the tray shows: a standing z-index would make
       the body a stacking context and sink the ⋮ hit-expander (z:-1) under
       the amount text at rest. */
    .tx-history-row.tx-swiping .tx-swipe-body, .tx-history-row.tx-swipe-open .tx-swipe-body { position:relative; z-index:1; }
    .tx-swipe-tray { display:none; position:absolute; top:0; bottom:0; right:0; width:192px; }
    .tx-history-row.tx-swiping .tx-swipe-tray, .tx-history-row.tx-swipe-open .tx-swipe-tray { display:flex; }
    .tx-history-row.tx-swiping .tx-swipe-body, .tx-history-row.tx-swipe-open .tx-swipe-body { background:var(--surface); }
    .tx-swipe-act {
      flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:2px;
      border:0; padding:0; font:inherit; font-size:var(--fs-14); font-weight:600; cursor:pointer; color:var(--text);
      background:var(--border);
    }
    .tx-swipe-act svg { width:16px; height:16px; }
    .tx-swipe-act--edit { background:var(--accent); color:var(--accent-inverse); }
    .tx-swipe-act--delete { background:var(--danger); color:#fff; }
    .tx-history-row.tx-swipe-open .tx-swipe-body { transition:transform 220ms cubic-bezier(0.22,0.25,0,1); }
    /* Day headers stay pinned while their rows scroll. The card's
       overflow:hidden would defeat position:sticky, so the list opts out. */
    #historyList.card { overflow:visible; }
    /* The 6px below the pill stays a margin (unpainted): as padding the
       header's box, one layer up, swallowed taps meant for the ⋮ button
       of the first row under it. */
    #historyList .tx-date-header { position:sticky; top:0; z-index:2; background:var(--surface); margin:0 0 6px; padding:14px 0 0; }
    #historyList .tx-date-header:first-child { padding-top:2px; }
    .tx-history-row .tx-side { display:flex; flex-direction:column; align-items:flex-end; gap:var(--sp-1); flex-shrink:0; margin-left:auto; }
    .tx-history-row .tx-amount { text-align:right; padding-bottom:1px; }
    .tx-history-row.tx-selected { background:var(--accent-soft, rgba(0,0,0,0.05)); border-radius:var(--radius-md, 10px); }
    .tx-history-row.tx-danger .tx-title, .tx-history-row.tx-danger .tx-meta, .tx-history-row.tx-danger .tx-amount { color:var(--danger-ink); font-weight:600; }

    /* Impulse-purchase toggle, shown next to the amount field on the add/edit form */
    .danger-toggle-btn {
      display:inline-flex; align-items:center; justify-content:center; gap:var(--sp-1); border:1px solid var(--glass-border-dark);
      background:var(--surface); color:var(--text-tertiary); border-radius:50%; width:36px; height:36px;
      padding:0; font-size:var(--fs-14); font-weight:600; cursor:pointer; font-family:inherit; line-height:1;
    }
    .danger-toggle-btn.on { background:var(--danger-soft); border-color:var(--danger); color:var(--danger-ink); }
    .danger-toggle-btn:focus-visible { outline:2px solid var(--danger); outline-offset:2px; }

    /* Per-expense ⋯ action-menu trigger — every item-level action (duplicate,
       transfer, export, delete) lives behind this one button now. Deep indigo
       at rest, violet on hover/active/focus, matching the rest of Color
       Schema 1's action-icon treatment. */
    /* 18px visual, 44px hit — the most-tapped small control in the app,
       sitting beside a swipe gesture. The expander deliberately steals the
       13px strip of row around the glyph: a near-miss on the ⋮ used to open
       the EDITOR (row tap), which reads as "the app did the wrong thing". */
    .tx-menu-btn {
      display:inline-flex; align-items:center; justify-content:center;
      width:18px; height:18px; flex-shrink:0; position:relative;
      border:none; background:transparent; color:var(--accent);
      line-height:1; cursor:pointer; border-radius:50%;
      padding:0; font-size:var(--fs-14); transition:var(--transition);
    }
    .tx-menu-btn::after { content:''; position:absolute; left:-13px; right:-13px; top:50%; transform:translateY(-50%); height:44px; }
    .tx-menu-btn svg { width:100%; height:100%; display:block; }
    .tx-menu-btn:hover, .tx-menu-btn:active { background:var(--violet-soft); color:var(--violet); }
    .tx-menu-btn:focus-visible { outline:2px solid var(--violet); outline-offset:1px; }

    /* Per-expense action menu rows (Duplicate/Transfer/Export/Delete) */
    .tx-action-item {
      display:flex; align-items:center; gap:var(--sp-3); width:100%;
      padding:13px 10px; font-size:var(--fs-16); font-weight:500; color:var(--text);
      background:none; border:none; text-align:left; cursor:pointer;
      border-radius:var(--radius-sm); font-family:inherit; transition:var(--transition);
    }
    .tx-action-item:hover, .tx-action-item:active { background:var(--bg); }
    .tx-action-item--danger { color:var(--danger-ink); }
    .tx-action-icon { width:18px; height:18px; flex-shrink:0; color:var(--accent); }
    .tx-action-item--danger .tx-action-icon { color:var(--danger); }
    .tx-action-icon svg { width:100%; height:100%; display:block; }

    /* Selection checkbox shown in multi-select mode */
    .tx-select-box {
      width:28px; height:28px; border-radius:11px; flex-shrink:0;
      border:2px solid var(--accent); background:transparent; color:var(--accent-inverse, #fff);
      display:flex; align-items:center; justify-content:center; font-size:var(--fs-16); font-weight:600;
    }
    .tx-history-row.tx-selected .tx-select-box { background:var(--accent); }

    /* Floating bulk-action bar */
    .history-selection-bar {
      position:fixed; left:50%; transform:translateX(-50%);
      /* Below #confirmModal (1200), so a confirm always sits on top of it (board 20). */
      bottom:calc(76px + env(safe-area-inset-bottom)); z-index:1190;
      display:flex; align-items:center; gap:10px; max-width:calc(100% - 24px);
      padding:var(--sp-2) 10px var(--sp-2) 14px; border-radius:var(--radius-pill, 999px);
      background:var(--surface-solid); border:1px solid var(--glass-border-dark);
      box-shadow:0 8px 28px rgba(0,0,0,0.18);
      animation:hsbIn 0.3s cubic-bezier(0.16,1,0.3,1);
    }
    /* Keyframes must restate the centering translateX — `transform` in a
       keyframe replaces the base value entirely rather than adding to it. */
    @keyframes hsbIn {
      from { opacity:0; transform:translateX(-50%) translateY(10px) scale(0.97); }
      to { opacity:1; transform:translateX(-50%) translateY(0) scale(1); }
    }
    .history-selection-bar .hsb-count { font-size:var(--fs-14); font-weight:600; color:var(--text); white-space:nowrap; }
    .history-selection-bar .hsb-actions { display:flex; align-items:center; gap:6px; }
    .history-selection-bar .hsb-btn {
      border:none; background:var(--bg); color:var(--text); font-size:var(--fs-14); font-weight:600;
      padding:6px 10px; border-radius:var(--radius-pill, 999px); cursor:pointer; white-space:nowrap;
    }
    .history-selection-bar .hsb-btn:active { opacity:0.7; }
    .history-selection-bar .hsb-danger { background:var(--danger-soft); color:var(--danger-ink); box-shadow:inset 0 0 0 1px var(--danger); }
    .history-selection-bar .hsb-close { background:transparent; color:var(--text-tertiary); font-size:var(--fs-16); padding:6px var(--sp-2); }

    .del-btn { width:26px; height:26px; border-radius:50%; border:none; background:transparent; color:var(--text-tertiary); display:flex; align-items:center; justify-content:center; cursor:pointer; transition:var(--transition); }
    .del-btn:active { background:var(--danger-soft); color:var(--danger); }
    .del-btn:focus-visible { outline:2px solid var(--danger); outline-offset:2px; }

    .empty { text-align:center; padding:48px var(--sp-4); color:var(--text-tertiary); animation:enter 0.5s var(--ease-out) backwards; }
    .empty p { font-size:var(--fs-16); font-weight:500; }
    .empty-icon {
      color:var(--text-tertiary); opacity:0.6; margin-bottom:var(--sp-3); display:inline-flex;
      animation:emptyFloat 3.5s ease-in-out infinite;
    }
    .empty-icon svg { display:block; }
    @keyframes emptyFloat { 0%,100% { transform:translateY(0); } 50% { transform:translateY(-5px); } }
    @media (prefers-reduced-motion: reduce) { .empty-icon { animation:none; } }

    .field { margin-bottom:var(--sp-3); }
    .field label { display:block; font-size:var(--fs-12); font-weight:600; color:var(--text-secondary); letter-spacing:0; margin-bottom:6px; }
    /* 16px is a hard floor on anything focusable for text entry: iOS Safari
       zooms the viewport on focus below that, which yanks the layout around
       and instantly reads as "not a native app". Applies to the .inp divs
       (picker triggers) too, so a trigger and the input beside it stay the
       same size. */
    .field input, .field textarea, .field select, .inp {
      width:100%; background:var(--bg); border:1px solid var(--glass-border-dark); border-radius:var(--radius-md); padding:10px var(--sp-3);
      color:var(--text); font-family:inherit; font-size:var(--fs-input); outline:none; transition:var(--transition); font-weight:500; box-shadow:var(--inset);
    }
    .field input:focus, .field textarea:focus, .field select:focus, .inp:focus { border-color:var(--text-secondary); box-shadow:none; }
    .field textarea { min-height:60px; resize:vertical; line-height:1.5; }
    .field-row { display:flex; gap:var(--sp-2); }
    .field-row .field { flex:1; margin-bottom:0; }
    @media (max-width:480px) { .field-row { flex-direction:column; gap:var(--sp-3); } }

    .btn {
      padding:var(--sp-2) 14px; border-radius:var(--radius-pill); border:1px solid var(--glass-border-dark); background:var(--surface); color:var(--text);
      font-weight:600; font-size:var(--fs-14); cursor:pointer; font-family:inherit; transition:var(--transition); letter-spacing:-0.01em;
 box-shadow:var(--elev-1);
    }
    /* One UI press feedback: a gentle scale plus a slight brightness dip,
       easing back out. Not a spring — the release should not bounce. */
    .btn:active { background:var(--bg); transform:scale(0.97); filter:brightness(0.94); }
    @media (hover:hover) {
      .btn:hover { transform:translateY(-1px); box-shadow:var(--elev-2); }
      .btn-primary:hover { transform:translateY(-1px); box-shadow:var(--elev-2); }
    }
    .btn-primary { background:var(--accent); color:var(--accent-inverse); border-color:var(--accent); box-shadow:var(--elev-1); }
    .btn-primary:active { opacity:0.88; }
    .btn-danger { border-color:var(--danger); color:var(--danger-ink); }
    .btn-danger:active { background:var(--danger-soft); }
    .btn:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }

    .slot {
      border:1.5px dashed var(--glass-border-dark); background:transparent; display:flex; align-items:center; justify-content:center;
      min-height:44px; cursor:pointer; color:var(--text-tertiary); gap:6px; font-weight:500; font-size:var(--fs-14);
      border-radius:var(--radius-lg); transition:var(--transition);
    }
    .slot:active { border-color:var(--text-secondary); color:var(--text); background:var(--surface); }
    .slot:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }

    /* Modal */
    .modal { position:fixed; inset:0; z-index:1000; display:flex; flex-direction:column; opacity:0; pointer-events:none; transition:opacity 200ms; }
    .modal.open { opacity:1; pointer-events:auto; }
    .modal-backdrop {
      position:absolute; inset:0; background:rgba(0,0,0,0.15);
      backdrop-filter:blur(0px); -webkit-backdrop-filter:blur(0px);
      transition:background 200ms, backdrop-filter 240ms ease, -webkit-backdrop-filter 240ms ease;
    }
    .modal.open .modal-backdrop { backdrop-filter:blur(4px); -webkit-backdrop-filter:blur(4px); }
    [data-theme="dark"] .modal-backdrop { background:rgba(0,0,0,0.35); }
    .modal-panel {
 position:relative; margin-top:auto; background:var(--surface);
      border:1px solid var(--glass-border); border-radius:var(--radius-2xl) var(--radius-2xl) 0 0; max-height:92vh; overflow:hidden;
      display:flex; flex-direction:column; transform:translateY(100%); box-shadow:var(--shadow-glass);
      /* Asymmetric window motion: the closed state's transition governs the
         CLOSE (quick ease-in exit); .modal.open overrides it for the OPEN.
         The open used to overshoot past its resting point (0.22,1.3,0.36,1)
         and rebound — bottom sheets are the surface One UI is most recognised
         by, and a sheet that bounces is the single loudest tell that this is
         not One UI. It now decelerates into place and stops. */
      transition:transform 220ms cubic-bezier(0.4,0,1,1);
    }
    .modal.open .modal-panel { transition:transform 380ms cubic-bezier(0.22,0.25,0,1); }
    /* Color-coded modal headers */
    .modal-panel.modal-budget .modal-header { border-top:3px solid var(--accent); }
    .modal-panel.modal-event .modal-header { border-top:3px solid var(--success); }
    .modal-panel.modal-goal .modal-header { border-top:3px solid var(--warning); }
    .modal-panel.modal-account .modal-header { border-top:3px solid var(--text-tertiary); }
    .modal-panel.modal-type .modal-header { border-top:3px solid var(--accent); }
    .modal-panel.modal-profile .modal-header { border-top:3px solid var(--text-tertiary); }
    .modal-panel.modal-backup .modal-header { border-top:3px solid var(--text-tertiary); }
    .modal-panel.modal-confirm .modal-header { border-top:3px solid var(--danger); }
    .modal-panel.modal-copy .modal-header { border-top:3px solid var(--accent); }


    .modal.open .modal-panel { transform:translateY(0); }
    @media (min-width:768px) {
      /* Centered dialog: rises and scales gently into place. Same de-bouncing
         as the sheet — it arrives and settles rather than overshooting. */
      .modal-panel {
        margin:auto auto var(--sp-6); border-radius:var(--radius-xl); max-height:85vh; width:100%; max-width:520px;
        transform:translateY(24px) scale(0.94);
        transition:transform 200ms cubic-bezier(0.4,0,1,1);
      }
      .modal.open .modal-panel { transform:translateY(0) scale(1); transition:transform 360ms cubic-bezier(0.22,0.25,0,1); }
    }
    /* Bottom-sheet drag handle. Real, not decorative — setupSheetDrag() in
       app.js drags the panel from this strip and dismisses it past a quarter
       of its height. A handle that cannot be dragged is a false affordance,
       which is worse than no handle.

       Gated at max-width rather than switched off in the min-width:768px
       block above, because that block sits EARLIER in the file and media
       queries add no specificity — the base rule would simply win and the
       handle would keep showing on a centred desktop dialog, which is
       exactly what happened on the first attempt. Scoping it positively
       makes source order irrelevant. */
    .modal-header { position:relative; padding:var(--sp-4) 20px 0; display:flex; justify-content:space-between; align-items:center; flex-shrink:0; touch-action:none; }
    @media (max-width:767px) {
      .modal-panel::before {
        content:''; position:absolute; top:9px; left:50%; transform:translateX(-50%);
        width:40px; height:4px; border-radius:2px; background:var(--border);
        z-index:3; pointer-events:none;
      }
      /* Room for the handle above the title. Must come AFTER the base
         .modal-header rule directly above, for the same source-order reason. */
      .modal-header { padding-top:var(--sp-6); }
    }
    .modal-header h3 { font-size:var(--fs-16); font-weight:600; letter-spacing:-0.02em; }
    .modal-close {
      width:28px; height:28px; border-radius:50%; border:none; background:var(--bg); color:var(--text-secondary);
      display:flex; align-items:center; justify-content:center; cursor:pointer; transition:var(--transition);
    }
    .modal-close:hover { background:var(--accent-soft); color:var(--text); }
    .modal-close:active { background:var(--accent-soft); transform:scale(0.95); }
    .modal-close:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
    .modal-overflow {
      position:absolute; top:calc(100% + 4px); right:0; z-index:10;
      background:var(--surface-solid); border:1px solid var(--glass-border-dark); border-radius:var(--radius-md);
      box-shadow:var(--shadow-glass); min-width:180px; display:none; flex-direction:column; padding:var(--sp-1);
      transform-origin:top right;
      animation:menuPop 0.28s cubic-bezier(0.22,0.25,0,1);
    }
    .modal-overflow.active { display:flex; }
    .modal-overflow-item {
      display:flex; align-items:center; gap:var(--sp-2); padding:var(--sp-2) 10px; border-radius:var(--radius-sm);
      background:transparent; border:none; color:var(--text-secondary); font-size:var(--fs-14); font-weight:500;
      cursor:pointer; font-family:inherit; transition:var(--transition); text-align:left; white-space:nowrap;
    }
    .modal-overflow-item:hover, .modal-overflow-item:active { background:var(--bg); color:var(--text); }
    .modal-overflow-item:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
    .modal-body { padding:var(--sp-4) 20px; overflow-y:auto; -webkit-overflow-scrolling:touch; flex:1; }
    .modal-footer {
      padding:10px 20px calc(10px + env(safe-area-inset-bottom)); display:flex; justify-content:flex-end; gap:var(--sp-2);
      border-top:1px solid var(--glass-border-dark); flex-shrink:0;
    }

    .segmented {
      display:flex; background:var(--bg); border-radius:var(--radius-md); padding:3px; gap:3px; margin-bottom:var(--sp-3); box-shadow:var(--inset);
    }
    .segmented-btn, .type-btn {
      flex:1; padding:6px; border:none; background:transparent; border-radius:var(--radius-sm); font-size:var(--fs-14); font-weight:600;
      color:var(--text-secondary); cursor:pointer; transition:var(--transition); font-family:inherit; letter-spacing:-0.01em;
      text-align:center; line-height:1.2;
    }
    .segmented-btn.on, .type-btn.on { background:var(--surface); color:var(--text); box-shadow:var(--elev-1); }
    .segmented-btn:focus-visible, .type-btn:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }

    /* Lifecycle tab stat cells — double as the status filter (replacing the
       removed pill bar) and carry small reorder controls. */
    .track-stat-cell {
      position:relative; padding:var(--sp-1) 2px 2px; border-radius:var(--radius-sm); cursor:pointer;
      border:1px solid transparent; transition:var(--transition);
    }
    @media (hover:hover) { .track-stat-cell:hover { background:var(--bg); } }
    .track-stat-cell:active { transform:scale(0.97); }
    .track-stat-cell.active { background:var(--accent-soft); border-color:var(--accent); }
    .track-stat-cell:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
    .track-stat-move {
      display:flex; justify-content:center; gap:2px; margin-bottom:2px; opacity:0.5; transition:var(--transition);
    }
    @media (hover:hover) { .track-stat-cell:hover .track-stat-move { opacity:1; } }
    .track-move-btn {
      width:16px; height:14px; border:none; background:transparent; color:var(--text-tertiary); cursor:pointer;
      font-size:var(--fs-12); line-height:1; border-radius:3px; font-family:inherit; padding:0;
    }
    @media (hover:hover) { .track-move-btn:hover:not(:disabled) { background:var(--surface); color:var(--text); } }
    .track-move-btn:disabled { opacity:0.25; cursor:default; }
    .track-move-btn:focus-visible { outline:2px solid var(--accent); outline-offset:1px; }

    .filter-bar { display:flex; align-items:center; gap:5px; margin-bottom:var(--sp-3); overflow-x:auto; -webkit-overflow-scrolling:touch; scrollbar-width:none; mask-image:linear-gradient(to right, #000 calc(100% - 20px), transparent); -webkit-mask-image:linear-gradient(to right, #000 calc(100% - 20px), transparent); }
    .filter-bar .hfilter-dd { min-height:40px; }
    .filter-bar::-webkit-scrollbar { display:none; }



    .item-row { display:flex; gap:6px; align-items:center; margin-bottom:6px; }
    .item-row .inp { flex:1; }

    .autocomplete-list {
      position:absolute; top:calc(100% + 4px); left:0; right:0; background:var(--surface-solid); border:1px solid var(--glass-border-dark);
      border-radius:var(--radius-md); box-shadow:var(--shadow-glass); max-height:180px; overflow-y:auto; z-index:50; display:none;
    }
    .autocomplete-list.active { display:block; transform-origin:top left; animation:menuPop 0.24s cubic-bezier(0.22,0.25,0,1); }
    .autocomplete-item { padding:var(--sp-2) var(--sp-3); cursor:pointer; font-size:var(--fs-14); font-weight:500; border-bottom:1px solid var(--glass-border-dark); transition:background 150ms; }
    .autocomplete-item:hover, .autocomplete-item.active { background:var(--bg); }
    .autocomplete-item:last-child { border-bottom:none; }

    .input-wrapper { position:relative; }
    .input-prefix { position:absolute; left:12px; top:50%; transform:translateY(-50%); color:var(--text-tertiary); font-weight:600; font-size:var(--fs-16); }
    .input-prefix + input { padding-left:28px; }

    .toast-container { position:fixed; top:12px; right:12px; z-index:2000; display:flex; flex-direction:column; gap:6px; pointer-events:none; }
    .toast {
 position:relative; padding:10px 14px 10px var(--sp-4); border-radius:var(--radius-lg); background:var(--surface);
      border:1px solid var(--glass-border); box-shadow:var(--shadow-glass); font-size:var(--fs-14); font-weight:600; animation:toastIn 320ms var(--ease-spring) forwards; pointer-events:auto; overflow:hidden;
    }
    .toast::before { content:''; position:absolute; left:0; top:0; bottom:0; width:3px; background:var(--success); }
    .toast.ok { color:var(--text); }
    .toast.ok::before { background:var(--success); }
    .toast.err { color:var(--danger); }
    .toast.err::before { background:var(--danger); }
    @keyframes toastIn { from { transform:translateX(16px) scale(0.96); opacity:0; } to { transform:translateX(0) scale(1); opacity:1; } }

    /* The One UI screen title. This class is the per-surface title and nothing
       else — exactly five uses, all in static markup — so it can carry the
       whole signature without leaking into card headings.

       The size jump from 15px is the point, not a side effect: One UI's look
       depends on a deliberate CONTRAST between a dominant screen title and a
       calm, smaller body scale. At 15px it was merely the largest thing on the
       screen; at 30px it anchors it. Not capped with nowrap/ellipsis on
       purpose — at max OS font scale it should wrap to two lines rather than
       truncate a screen's own name. */
    .home-title {
      font-size:var(--fs-28); font-weight:600; letter-spacing:-0.022em;
      margin:2px 0 18px; line-height:1.22; color:var(--text);
    }
    /* Galaxy-class and up gets the top of the 30-34 range; compact phones stay
       at 30 so a long title like "Product Lifecycle" still fits one line. */
    @media (min-width:400px) { .home-title { font-size:var(--fs-28); } }

    /* Group headings. Deliberately NOT taken to the brief's 20-22px "Section"
       size: this is a dense financial app where these repeat six-plus times per
       screen, and at 20px they would compete with the screen title instead of
       sitting under it. Going from a 9px uppercase micro-eyebrow to a 14px
       sentence-case heading is the change that matters — One UI does not
       use letterspaced all-caps eyebrows. */
    .section-title {
      font-size:var(--fs-16); font-weight:600; color:var(--text-secondary); text-transform:none;
      letter-spacing:-0.01em; margin-bottom:var(--sp-3);
      display:flex; align-items:center; gap:var(--sp-2);
    }
    .section-title::before { content:''; width:3px; height:14px; border-radius:2px; background:var(--accent); opacity:0.85; flex-shrink:0; }

    .type-label { display:block; font-size:var(--fs-12); font-weight:600; color:var(--text-secondary); letter-spacing:0; margin-bottom:var(--sp-2); }
    /* The frequency row: four pills that scroll rather than wrap, so "how
       often" stays one line and one question (round-four board 5). */
    .freq-row {
      display:flex; gap:var(--sp-1); background:var(--bg); border-radius:var(--radius-md); padding:var(--sp-1);
      box-shadow:var(--shadow-neu-inset); overflow-x:auto; -webkit-overflow-scrolling:touch; scrollbar-width:none;
    }
    .freq-row::-webkit-scrollbar { display:none; }
    .freq-row .type-btn { flex:0 0 auto; padding-left:var(--sp-3); padding-right:var(--sp-3); white-space:nowrap; }
    .freq-stop { margin-top:var(--sp-2); margin-bottom:0; }
    .freq-stop .picker-trigger { padding:10px var(--sp-3); font-size:var(--fs-14); }
    .split-body { margin-bottom:var(--sp-2); }

    .type-toggle {
      display:grid; grid-template-columns:repeat(3,1fr); gap:var(--sp-1); background:var(--bg); border-radius:var(--radius-md); padding:var(--sp-1); box-shadow:var(--shadow-neu-inset);
    }
    @media (min-width:560px) { .type-toggle { grid-template-columns:repeat(6,1fr); } .type-btn { font-size:var(--fs-14); } }

    .picker-trigger { cursor:pointer; display:flex; align-items:center; justify-content:space-between; }
    .picker-trigger::after { content:''; width:7px; height:7px; border-right:1.5px solid var(--text-tertiary); border-bottom:1.5px solid var(--text-tertiary); transform:rotate(45deg); margin-left:6px; transition:var(--transition); }
    .picker-trigger:active::after { border-color:var(--text-secondary); }
    .picker-list { display:flex; flex-direction:column; gap:2px; }
    .picker-item {
      padding:var(--sp-3) 14px; border-radius:var(--radius-md); font-size:var(--fs-16); font-weight:500; color:var(--text);
      cursor:pointer; transition:background 150ms; text-align:center; border:1px solid transparent;
    }
    .picker-item.on { background:var(--bg); font-weight:600; border-color:var(--glass-border-dark); }
    .picker-item:active { background:var(--surface-solid); }
    .picker-item:focus-visible { outline:2px solid var(--accent); outline-offset:-2px; }
    .picker-done { margin-top:10px; width:100%; }

    .date-cols { display:flex; gap:6px; height:260px; }
    .date-col { flex:1; overflow-y:auto; -webkit-overflow-scrolling:touch; border-right:1px solid var(--glass-border-dark); padding-right:3px; }
    .date-col:last-child { border-right:none; padding-right:0; }
    .date-col-label { text-align:center; font-size:var(--fs-12); font-weight:600; color:var(--text-secondary); text-transform:none; letter-spacing:0; padding:6px 0; position:sticky; top:0; background:var(--surface); z-index:5; }

    .backup-row { display:flex; align-items:center; gap:var(--sp-2); padding:10px 0; border-bottom:1px solid var(--glass-border-dark); }
    .backup-row:last-child { border-bottom:none; }
    .backup-info { flex:1; min-width:0; }
    .backup-name { font-size:var(--fs-14); font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; letter-spacing:-0.01em; }
    .backup-meta { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; margin-top:2px; }
    .backup-actions { display:flex; gap:5px; flex-shrink:0; }
    .backup-actions button { padding:5px var(--sp-2); border-radius:var(--radius-sm); border:1px solid var(--glass-border-dark); background:transparent; font-size:var(--fs-14); font-weight:600; cursor:pointer; font-family:inherit; transition:var(--transition); }
    .backup-actions button:active { transform:scale(0.96); }
    .backup-actions button:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
    .backup-actions .restore-btn { color:var(--success-ink); border-color:var(--success); }
    .backup-actions .restore-btn:active { background:var(--success-soft); }
    .backup-actions .del-btn2 { color:var(--danger-ink); border-color:var(--danger); }
    .backup-actions .del-btn2:active { background:var(--danger-soft); }

    .copy-filter-row { display:flex; gap:6px; margin-bottom:10px; flex-wrap:wrap; }
    /* Real <input>s — must clear the 16px zoom floor even though they're compact. */
    .copy-filter-row .inp { flex:1; min-width:100px; font-size:var(--fs-input); padding:var(--sp-2) 10px; }

    .copy-tx-row { display:flex; align-items:center; gap:var(--sp-2); padding:var(--sp-2) 0; border-bottom:1px solid var(--glass-border-dark); cursor:pointer; }
    .copy-tx-row:last-child { border-bottom:none; }
    .copy-tx-row .cb { width:16px; height:16px; min-width:16px; border-radius:4px; border:1.5px solid var(--glass-border-dark); display:flex; align-items:center; justify-content:center; cursor:pointer; transition:var(--transition); background:transparent; }
    .copy-tx-row .cb.on { background:var(--accent); border-color:var(--accent); color:var(--accent-inverse); }
    .copy-tx-info { flex:1; min-width:0; }
    .copy-tx-title { font-size:var(--fs-14); font-weight:500; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; letter-spacing:-0.01em; }
    .copy-tx-meta { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }
    .copy-tx-amt { font-size:var(--fs-14); font-weight:600; flex-shrink:0; letter-spacing:-0.01em; }

    /* History search chip (D6): collapsed to a 36px circle beside the filter
       chips; expands on tap and stays expanded while a query is present, so
       an active search is never invisible. */
    /* History title row with the month summary (design prototypes). */
    /* ── Accounts ── */
    .acc-row { display:flex; align-items:baseline; gap:10px; padding:7px 0; border-bottom:1px solid var(--glass-border-dark); }
    .acc-row:last-child { border-bottom:none; }
    .acc-name { flex:1; min-width:0; display:flex; flex-direction:column; font-size:var(--fs-14); font-weight:600; }
    .acc-sub { font-size:var(--fs-14); font-weight:500; color:var(--text-tertiary); }
    .acc-bal { font-size:var(--fs-14); font-weight:600; font-variant-numeric:tabular-nums; flex-shrink:0; }
    /* Owed is not held. The colour is the fastest way to stop a card reading
       like money in the bank. */
    .acc-bal.acc-owed, .acc-bal.acc-neg { color:var(--danger-ink); }
    .acc-divider {
      font-size:var(--fs-12); font-weight:600; letter-spacing:0; text-transform:none;
      color:var(--text-tertiary); margin:10px 0 2px;
    }
    .acc-total { border-top:1px solid var(--glass-border); border-bottom:none; margin-top:var(--sp-1); padding-top:9px; }
    .acc-total .acc-name { font-weight:600; }
    .acc-unassigned {
      display:block; width:100%; margin-top:var(--sp-2); padding:var(--sp-2) 10px; min-height:44px;
      border:1px dashed var(--glass-border-dark); border-radius:var(--radius-md);
      background:none; color:var(--text-secondary); font-family:inherit; font-size:var(--fs-14);
      font-weight:600; text-align:left; cursor:pointer;
    }
    @media (hover:hover) { .acc-unassigned:hover { color:var(--text); background:var(--bg); } }
    .acc-empty { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; padding:6px 0; line-height:1.5; }
    /* Where a bank account closes the month (round six, board 6). */
    .acc-proj { margin:-2px 0 6px; font-size:var(--fs-14); }
    .acc-proj-sum {
      display:flex; flex-wrap:wrap; align-items:center; gap:2px var(--sp-2); min-height:44px; padding:6px 0;
      list-style:none; cursor:pointer; color:var(--text-secondary); font-weight:500;
    }
    .acc-proj-sum::-webkit-details-marker { display:none; }
    .acc-proj-sum::after { content:'›'; margin-left:auto; color:var(--text-tertiary); transition:transform 200ms var(--ease-out); }
    .acc-proj[open] .acc-proj-sum::after { transform:rotate(90deg); }
    .acc-proj-sum:focus-visible { outline:2px solid var(--accent); outline-offset:2px; border-radius:var(--radius-sm); }
    .acc-proj-head b { color:var(--text); font-variant-numeric:tabular-nums; }
    .acc-proj-close { color:var(--text-tertiary); }
    .acc-proj-body { padding:2px 0 6px 10px; border-left:2px solid var(--glass-border-dark); }
    .acc-proj-title {
      font-size:var(--fs-14); font-weight:600; letter-spacing:0; text-transform:none;
      color:var(--text-tertiary); margin-bottom:2px;
    }
    .acc-proj-row { display:flex; align-items:baseline; gap:var(--sp-2); padding:2px 0; }
    .acc-proj-name { flex:1; min-width:0; color:var(--text-secondary); }
    .acc-proj-tag { margin-left:6px; font-size:var(--fs-12); font-weight:600; text-transform:none; letter-spacing:0; color:var(--text-tertiary); }
    .acc-proj-amt { font-weight:600; font-variant-numeric:tabular-nums; }
    .acc-proj-amt.neg { color:var(--text); }
    .acc-proj-amt.pos { color:var(--success-ink); }
    .acc-proj-note { margin:var(--sp-1) 0 0; font-size:var(--fs-14); color:var(--text-tertiary); line-height:1.5; }

    /* ── Accounts · the manager ── */
    .acc-item { border-bottom:1px solid var(--glass-border-dark); }
    .acc-item:last-of-type { border-bottom:none; }
    /* An archived account is still readable — its history did not go
       anywhere — it simply stops being offered. */
    .acc-item--archived { opacity:0.55; }
    .acc-item-main {
      display:flex; align-items:baseline; gap:10px; width:100%; min-height:48px; padding:10px var(--sp-1);
      border:none; background:none; font-family:inherit; color:var(--text); text-align:left; cursor:pointer;
      border-radius:var(--radius-sm);
    }
    @media (hover:hover) { .acc-item-main:hover, .acc-card-row:hover { background:var(--bg); } }
    .acc-item-name { flex:1; min-width:0; display:flex; flex-direction:column; font-size:var(--fs-14); font-weight:600; }
    /* The name and its tag are a ROW inside the column. As bare children of
       a flex column the tag became its own item and stretched the full width
       of the sheet. */
    .acc-item-title { display:flex; align-items:center; gap:6px; min-width:0; }
    .acc-tag {
      display:inline-block; font-size:var(--fs-12); font-weight:600; letter-spacing:0;
      text-transform:none; color:var(--text-tertiary); border:1px solid var(--glass-border-dark);
      padding:1px 5px; border-radius:var(--radius-sm);
    }
    /* A card is indented under the account it draws on, because that
       relationship is the whole point of it being a card. */
    .acc-card-row {
      display:flex; align-items:center; gap:10px; width:100%; min-height:44px; padding:6px var(--sp-1) 6px 18px;
      border:none; background:none; font-family:inherit; color:var(--text-secondary);
      text-align:left; cursor:pointer; border-radius:var(--radius-sm); font-size:var(--fs-14);
    }
    .acc-card-name { flex:1; min-width:0; font-weight:500; }
    .acc-card-go { font-size:var(--fs-14); font-weight:600; color:var(--accent); }
    .acc-add-row { display:flex; gap:var(--sp-2); margin-top:14px; }
    .acc-add-row .btn { flex:1; justify-content:center; min-height:44px; }
    .acc-offer {
      display:flex; flex-direction:column; gap:2px; width:100%; margin-bottom:var(--sp-3); padding:var(--sp-3);
      border:1px dashed var(--accent); border-radius:var(--radius-md); background:var(--accent-soft);
      font-family:inherit; text-align:left; cursor:pointer; min-height:44px;
    }
    .acc-offer-title { font-size:var(--fs-14); font-weight:600; color:var(--accent); }
    .acc-offer-sub { font-size:var(--fs-14); font-weight:500; color:var(--text-secondary); }
    .acc-kinds { display:grid; grid-template-columns:repeat(2,1fr); gap:var(--sp-1); }
    .acc-hint { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; line-height:1.5; margin:-2px 0 var(--sp-3); }
    .acc-archive { width:100%; justify-content:center; min-height:44px; margin-top:6px; }

    /* ── The month hand-off (board 6) ── */
    .review-carry {
      display:grid; grid-template-columns:minmax(0,1fr) auto; gap:2px 10px;
      padding:6px 0; border-bottom:1px solid var(--border);
    }
    .review-carry:last-of-type { border-bottom:0; }
    .review-carry-name { font-size:var(--fs-14); font-weight:600; }
    .review-carry-amt { font-size:var(--fs-14); font-weight:600; font-variant-numeric:tabular-nums; white-space:nowrap; }
    .review-carry-drop { color:var(--text-tertiary); font-weight:500; }
    /* The reason is the point. A change with no stated reason is a plan the
       app wrote for you, which is one you never read. */
    .review-carry-why { grid-column:1 / -1; font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }
    .review-carry-btn { width:100%; justify-content:center; margin-top:10px; min-height:44px; }

    /* ── Events carved out of the month's plan (board 4) ── */
    .plan-carve { font-size:var(--fs-14); font-weight:600; color:var(--text-secondary); margin:6px 0 0; }

    /* A UPI id sits in the card list because it is the same kind of thing —
       a name that draws on an account — so it says which it is. */
    .acc-tag--upi { background:var(--accent-soft); color:var(--accent); }

    /* ── Payment methods: ways to pay above, accounts & cards below ── */
    .pm-section + .pm-section { margin-top:22px; padding-top:14px; border-top:1px solid var(--glass-border); }
    .pm-section-title {
      margin:0 0 var(--sp-1); font-size:var(--fs-12); font-weight:600; letter-spacing:0;
      text-transform:none; color:var(--text-tertiary);
    }
    .pm-item { display:flex; align-items:center; gap:var(--sp-1); border-bottom:1px solid var(--glass-border-dark); }
    .pm-item[hidden] { display:none; }
    .pm-item:last-of-type { border-bottom:none; }
    .pm-item-main { flex:1; min-width:0; }
    /* Hidden or archived: still listed, still readable, visibly off. */
    .pm-item--off .pm-item-main { opacity:0.55; }
    /* A built-in is fixed on purpose. The lock says so, where greyed-out
       controls would only look broken. */
    .pm-tag-built { display:inline-flex; align-items:center; gap:3px; }
    .pm-lock { flex-shrink:0; }
    .pm-move { display:flex; flex-shrink:0; }
    .pm-move-btn {
      display:inline-flex; align-items:center; justify-content:center; width:44px; height:44px;
      border:none; background:none; color:var(--text-secondary); border-radius:var(--radius-sm); cursor:pointer;
    }
    .pm-move-btn:disabled { color:var(--text-tertiary); opacity:0.35; cursor:default; }
    .pm-move-btn:focus-visible { outline:2px solid var(--accent); outline-offset:-2px; }
    @media (hover:hover) { .pm-move-btn:not(:disabled):hover { background:var(--bg); color:var(--text); } }
    .pm-kinds { display:grid; grid-template-columns:repeat(2,1fr); gap:var(--sp-1); }
    .pm-kinds .type-btn { gap:5px; }
    .pm-tick { flex-shrink:0; }
    .pm-kinds .type-btn:disabled { cursor:default; }
    .pm-kinds .type-btn:disabled:not(.on) { opacity:0.5; }
    .pm-actions { display:flex; gap:var(--sp-2); margin-top:6px; }
    .pm-actions .btn { flex:1; justify-content:center; min-height:44px; }
    .pm-actions + .acc-hint, .pm-default + .acc-hint { margin-top:var(--sp-2); }
    /* The default for new entries, said where the ways to pay are kept. */
    .pm-default {
      display:flex; flex-direction:column; gap:var(--sp-2); margin-top:var(--sp-3); padding:10px var(--sp-3);
      border:1px solid var(--glass-border-dark); border-radius:var(--radius-md);
      font-size:var(--fs-14); color:var(--text-secondary); line-height:1.45;
    }
    .pm-default b { color:var(--text); }
    .pm-default.is-default { border-color:var(--accent); background:var(--accent-soft); }
    .pm-default-btn { justify-content:center; min-height:44px; }
    .pm-tag-default { background:var(--accent-soft); color:var(--accent); border-color:transparent; }
    /* A caption for a group of buttons, which a <label> cannot name. */
    .field .field-label { display:block; font-size:var(--fs-12); font-weight:600; color:var(--text-secondary); margin-bottom:6px; }
    .field-error { margin:var(--sp-1) 0 0; font-size:var(--fs-14); font-weight:600; color:var(--danger-ink); }
    .field-error::before { content:"! "; color:var(--danger); font-weight:600; }
    .field-error[hidden] { display:none; }

    /* A heading inside the picker. Not selectable, and not a tap target — it
       says what the group below it is, nothing more. */
    .picker-group {
      padding:10px var(--sp-4) var(--sp-1); font-size:var(--fs-12); font-weight:600;
      letter-spacing:0; text-transform:none; color:var(--text-tertiary);
      pointer-events:none;
    }
    .picker-group:first-child { padding-top:2px; }

    /* ── Setting a budget from what the ledger knows (board 3) ── */
    .prompt-amount { padding:var(--sp-2) var(--sp-1); display:flex; flex-direction:column; gap:var(--sp-3); }
    .prompt-amount-field .inp { padding-left:26px; font-size:var(--fs-input); }
    .prompt-suggest { display:flex; gap:6px; flex-wrap:wrap; }
    .prompt-chip { min-height:36px; font-variant-numeric:tabular-nums; }
    .prompt-hint { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; margin:0; line-height:1.4; }
    .prompt-amount-ok { width:100%; justify-content:center; }

    /* ── The default payment method, offered under the When · how strip ── */
    .tx-default { display:flex; align-items:center; gap:var(--sp-2); margin:2px 0 var(--sp-2); min-height:32px; }
    /* A class-level display beats the UA's [hidden], so hiding is said out
       loud — the pairing every flex row in this file carries. */
    .tx-default[hidden] { display:none; }
    /* On a short screen (an iPhone 13 shows 664px) the no-default NOTE pushed
       the More row under the Save bar; the "Paid with" pill already asks. The
       offer to make a choice the default is an action and always shows. */
    @media (max-height: 720px) { .tx-default.tx-default--hint { display:none; } }
    .tx-default-act {
      min-height:44px; padding:0 2px; border:0; background:none; cursor:pointer;
      font-family:inherit; font-size:var(--fs-14); font-weight:600; color:var(--accent);
      text-decoration:underline; text-underline-offset:2px; text-align:left;
    }
    .tx-default-hint { font-size:var(--fs-14); font-weight:500; color:var(--text-tertiary); line-height:1.35; }

    /* ── The plan, read back on the Add form (board 7) ── */
    .tx-plan-line {
      display:flex; align-items:center; gap:10px; justify-content:space-between;
      padding:var(--sp-2) 11px; border-radius:var(--radius-md); margin-top:2px;
      border:1px solid var(--border); background:var(--bg);
      font-size:var(--fs-14); font-weight:500; color:var(--text-secondary);
    }
    /* A class-level display beats the UA's [hidden], so hiding has to be said
       out loud — the same pairing .month-chips and #txBudgetChips carry. */
    .tx-plan-line[hidden] { display:none; }
    /* What an entry is linked to, or what it would do to a balance. */
    .tx-link-line {
      display:flex; align-items:center; gap:var(--sp-2); margin:6px 0 0; padding:var(--sp-2) 10px;
      border:1px solid var(--glass-border-dark); border-radius:var(--radius-md);
      font-size:var(--fs-14); font-weight:500; color:var(--text-secondary); line-height:1.45;
    }
    .tx-link-line[hidden] { display:none; }
    .tx-link-line b { color:var(--text); font-weight:600; }
    .tx-link-line--warn { border-color:var(--warning); background:var(--warning-soft); }
    .tx-link-text { flex:1; min-width:0; }
    .tx-link-clear {
      flex-shrink:0; min-height:44px; padding:0 var(--sp-3); border:1px solid var(--glass-border-dark);
      border-radius:var(--radius-pill); background:var(--surface); color:var(--accent);
      font-family:inherit; font-size:var(--fs-14); font-weight:600; cursor:pointer;
    }
    .tx-action-item[hidden] { display:none; }
    .tx-plan-txt { min-width:0; }
    .tx-plan-txt b { font-weight:600; color:var(--text); }
    /* Tight and over are warnings about a plan, not about the entry — they
       colour the figure, never the whole form. */
    .tx-plan-line--tight { border-color:var(--warning); }
    .tx-plan-line--tight .tx-plan-txt b { color:var(--warning-ink); }
    .tx-plan-line--over { border-color:var(--danger); }
    .tx-plan-line--over .tx-plan-txt b { color:var(--danger-ink); }
    .tx-plan-act {
      flex:0 0 auto; min-height:32px; padding:0 10px; border:0; border-radius:8px;
      background:var(--accent); color:#fff; font-family:inherit; font-size:var(--fs-14);
      font-weight:600; cursor:pointer;
    }

    /* ── The plan as a checklist (board 2) ── */
    .plan-line {
      display:grid; grid-template-columns:auto minmax(0,1fr) auto; gap:var(--sp-2);
      align-items:center; padding:5px 0;
    }
    .plan-line-bar { grid-column:2 / -1; }
    .plan-tick {
      width:16px; height:16px; border-radius:50%; display:grid; place-items:center;
      font-size:var(--fs-12); font-weight:600; line-height:1; flex:0 0 auto;
    }
    /* Done, part-done and not-yet are three different claims, so they get
       three different marks — colour alone would not survive a screenshot in
       greyscale or a reader who cannot tell green from amber. */
    .plan-tick.done { background:var(--success-soft); color:var(--success); border:1px solid var(--success); }
    .plan-tick.part { background:var(--warning-soft); color:var(--warning); border:1px solid var(--warning); }
    .plan-tick.none { background:none; color:var(--text-tertiary); border:1px dashed var(--border); }
    .plan-line-name { font-size:var(--fs-14); font-weight:600; min-width:0; display:flex; flex-direction:column; gap:1px; }
    .plan-line-dup { font-size:var(--fs-14); font-weight:500; color:var(--text-tertiary); }
    /* A committed line is not editable here — its amount comes from the
       repeating entry, which is the one place that should own it. */
    .plan-line-tag {
      align-self:flex-start; font-size:var(--fs-12); font-weight:600; letter-spacing:0.04em;
      padding:1px 5px; border-radius:4px; background:var(--accent-soft); color:var(--accent);
    }
    .plan-line-amt { font-size:var(--fs-14); font-weight:600; font-variant-numeric:tabular-nums; white-space:nowrap; }
    .plan-line-amt .of { color:var(--text-tertiary); font-weight:500; }
    .plan-line--rest .plan-line-name { color:var(--text-secondary); }

    /* ── Accounts feeding the rest of the app ── */
    /* Accounts is no longer a curiosity behind a disclosure — it is where the
       money is. The header carries its own padding, so the toggle gives its
       own back; .collapse-toggle is defined later in the file, hence the
       doubled class rather than a bare one that would lose to it. */
    .collapse-toggle.section-collapse { padding:0; }
    .section-collapse .section-collapse-head { margin-bottom:0; }
    .nw-edit-actions { display:flex; gap:var(--sp-2); flex-wrap:wrap; }
    /* .nw-add-btn is width:100% on its own — flex cannot beat that, so the
       width is handed back before the two share a row. */
    .nw-edit-actions .nw-add-btn { flex:1 1 0; width:auto; }
    /* A row that reads an account says so, quietly — it is provenance, not a
       warning, so it sits at label weight rather than shouting in a colour. */
    .nw-edit-live {
      margin-left:auto; font-size:var(--fs-14); font-weight:600; color:var(--teal-blue);
      text-transform:none; letter-spacing:0;
    }
    .plan-card-note {
      display:flex; flex-direction:column; gap:2px; width:100%; margin-top:10px;
      padding:9px 11px; border:1px solid var(--warning); border-radius:var(--radius-md);
      background:none; font-family:inherit; text-align:left; cursor:pointer;
    }
    .plan-card-note-main { font-size:var(--fs-14); font-weight:600; color:var(--text); }
    .plan-card-note-main::before { content:"⚠ "; color:var(--warning); }
    #planCardNote { margin:0 0 10px; }
    #planCardNote[hidden] { display:none; }
    #planCardNote .plan-card-note { margin-top:0; }
    .plan-card-note-sub { font-size:var(--fs-14); font-weight:500; color:var(--text-secondary); line-height:1.35; }
    .lc-ring-wrap { position:relative; display:inline-flex; flex-shrink:0; }
    .lc-ring-wrap .lc-ring { width:44px; height:44px; }
    .lc-ring-text { position:absolute; inset:0; display:grid; place-items:center; font-size:var(--fs-12); font-weight:600; color:var(--text); letter-spacing:-0.02em; }
    .delivery-wait { display:block; font-size:var(--fs-14); font-weight:600; color:var(--text); }
    .delivery-wait.urgent::before { content:''; display:inline-block; width:6px; height:6px; border-radius:50%; background:var(--warning); margin-right:5px; vertical-align:1px; }
    .goal-source { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }
    .goal-deadline { font-size:var(--fs-14); color:var(--text-secondary); font-weight:600; }
    .plan-strip-foot { display:flex; align-items:center; gap:var(--sp-2); margin-top:10px; font-size:var(--fs-14); color:var(--text-secondary); }
    .plan-strip-foot .plan-new { margin:0 0 0 auto; min-height:36px; }
    .hfilter-row[hidden] { display:none; }
    .empty--first { padding:40px var(--sp-4); }
    .empty--first .empty-icon svg { width:40px; height:40px; }
    .empty .empty-title { font-weight:600; color:var(--text); font-size:var(--fs-16); margin-bottom:2px; }
    .empty .empty-action { margin-top:var(--sp-3); min-height:44px; }
    .field-hint { font-size:var(--fs-14); color:var(--text-tertiary); margin-top:var(--sp-1); font-weight:500; }

    /* ── Card bills ── */
    .acc-pay {
      display:flex; align-items:center; gap:var(--sp-2); width:100%; min-height:44px; margin:2px 0 var(--sp-2);
      padding:var(--sp-2) 10px; border:1px solid var(--warning); border-radius:var(--radius-md);
      background:none; color:var(--warning-ink); font-family:inherit; font-size:var(--fs-14);
      font-weight:600; text-align:left; cursor:pointer;
    }
    .acc-pay span:first-child { flex:1; min-width:0; }
    .acc-pay--late { border-color:var(--danger); color:var(--danger-ink); }
    .acc-pay-go { font-weight:600; text-decoration:underline; flex-shrink:0; }
    .pay-summary { padding:10px var(--sp-3); margin-bottom:14px; border-radius:var(--radius-md); background:var(--bg); box-shadow:var(--inset); }
    .pay-line { display:flex; justify-content:space-between; gap:10px; font-size:var(--fs-14); padding:3px 0; font-variant-numeric:tabular-nums; }
    /* What was billed and what has since been charged are different claims.
       The second is muted so it cannot be mistaken for the amount to pay. */
    .pay-line--muted { color:var(--text-tertiary); font-weight:500; }
    .pay-due { margin-top:6px; font-size:var(--fs-14); font-weight:600; color:var(--warning-ink); }
    .pay-due--late { color:var(--danger-ink); }
    .pay-quick { display:flex; gap:6px; margin-top:var(--sp-2); flex-wrap:wrap; }
    .pay-quick .chip { min-height:36px; }

    /* ── Net worth ─────────────────────────────────────────────────────
       Home's language, not a new one: one hero card, then flat sections
       divided by the same hairline .section already draws. No new shadow
       tokens, no new type sizes, no colour outside the six-entry palette. */
    .nw-hero { text-align:left; }
    .nw-hero-label { font-size:var(--fs-12); font-weight:600; color:var(--text-tertiary); letter-spacing:0.02em; }
    .nw-hero-value {
      font-size:var(--fs-28); font-weight:600; letter-spacing:-0.03em; color:var(--text);
      font-variant-numeric:tabular-nums slashed-zero; margin:2px 0 6px; line-height:1.15;
    }
    /* Owing more than you hold is a real state, and it should read as one
       rather than as an ordinary figure that happens to have a minus. */
    .nw-hero-value.nw-negative, .nw-hist-net.nw-negative { color:var(--danger-ink); text-decoration:underline 3px var(--danger); text-underline-offset:6px; text-decoration-skip-ink:none; }
    .nw-delta { display:flex; align-items:baseline; gap:var(--sp-2); flex-wrap:wrap; font-size:var(--fs-14); font-weight:600; font-variant-numeric:tabular-nums; }
    .nw-delta.nw-up { color:var(--success-ink); }
    .nw-delta.nw-down { color:var(--danger-ink); }
    .nw-delta--none { color:var(--text-tertiary); font-weight:500; }
    .nw-delta-span { color:var(--text-tertiary); font-weight:500; font-size:var(--fs-14); }
    .nw-hero-split { display:flex; gap:10px; margin-top:14px; padding-top:var(--sp-3); border-top:1px solid var(--glass-border); }
    .nw-hero-cell { flex:1; min-width:0; }
    .nw-hero-cell-label { font-size:var(--fs-12); font-weight:500; color:var(--text-tertiary); }
    .nw-hero-cell-value { font-size:var(--fs-16); font-weight:600; letter-spacing:-0.02em; font-variant-numeric:tabular-nums; }
    .nw-hero-cell--liab .nw-hero-cell-value { color:var(--danger-ink); }

    /* A historical sheet is correct but it is not now. The tinted rail and
       the banner together make that impossible to miss at a glance. */
    .nw-hero--past { box-shadow:var(--elev-1), inset 3px 0 0 var(--violet); }
    .nw-historical {
      display:flex; align-items:center; gap:var(--sp-2); margin-bottom:10px; padding:9px var(--sp-3);
      border-radius:var(--radius-md); background:var(--violet-soft); color:var(--violet);
      font-size:var(--fs-14); font-weight:600;
    }
    .nw-historical svg { width:14px; height:14px; flex-shrink:0; }
    .nw-historical span { flex:1; min-width:0; }
    .nw-historical-btn {
      border:1px solid currentColor; background:none; color:inherit; font-family:inherit;
      font-size:var(--fs-14); font-weight:600; padding:3px 10px; border-radius:var(--radius-pill); cursor:pointer; flex-shrink:0;
    }

    .nw-section { padding-top:20px; }
    .nw-bar { display:flex; height:10px; border-radius:var(--radius-pill); overflow:hidden; background:var(--bg); box-shadow:var(--inset); }
    .nw-seg { display:block; height:100%; min-width:2px; }
    .nw-seg--other { background:var(--text-tertiary); opacity:0.35; }
    .nw-legend { margin-top:10px; display:flex; flex-direction:column; gap:6px; }
    .nw-leg-row { display:flex; align-items:center; gap:var(--sp-2); font-size:var(--fs-14); }
    .nw-leg-dot { width:8px; height:8px; border-radius:50%; flex-shrink:0; }
    .nw-leg-name { flex:1; min-width:0; color:var(--text-secondary); font-weight:500; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
    .nw-leg-val { font-weight:600; font-variant-numeric:tabular-nums; }
    .nw-leg-pct { width:46px; text-align:right; color:var(--text-tertiary); font-weight:500; font-variant-numeric:tabular-nums; }

    .nw-group + .nw-group { margin-top:14px; padding-top:var(--sp-3); border-top:1px solid var(--glass-border); }
    .nw-group-head { display:flex; align-items:center; gap:var(--sp-2); margin-bottom:6px; }
    .nw-group-dot { width:8px; height:8px; border-radius:2px; flex-shrink:0; }
    .nw-group-name { flex:1; min-width:0; font-size:var(--fs-14); font-weight:600; color:var(--text-secondary); }
    .nw-group-sub { font-size:var(--fs-14); font-weight:600; font-variant-numeric:tabular-nums; }
    .nw-hold-row { display:flex; align-items:baseline; gap:10px; padding:5px 0 5px var(--sp-4); }
    .nw-hold-name { flex:1; min-width:0; font-size:var(--fs-14); font-weight:500; display:flex; flex-direction:column; }
    .nw-hold-qty { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; font-variant-numeric:tabular-nums; }
    .nw-hold-val { font-size:var(--fs-14); font-weight:600; font-variant-numeric:tabular-nums; flex-shrink:0; }

    /* A holding row is a way into its own history now, so it reads as one:
       full width, a chevron, and a real target. */
    .nw-hold-row {
      width:100%; border:none; background:none; font-family:inherit; color:var(--text);
      text-align:left; cursor:pointer; border-radius:var(--radius-sm); min-height:44px;
    }
    @media (hover:hover) { .nw-hold-row:hover { background:var(--bg); } }
    .nw-hold-row:active { background:var(--accent-soft); }
    .nw-hold-chev { width:13px; height:13px; flex-shrink:0; color:var(--text-tertiary); }

    .nw-holding-head { display:flex; flex-direction:column; gap:2px; min-width:0; }
    .nw-holding-sub { display:flex; align-items:center; gap:6px; font-size:var(--fs-14); font-weight:600; color:var(--text-tertiary); }
    .nw-series-head { margin-bottom:var(--sp-3); }
    .nw-series-now { font-size:var(--fs-20); font-weight:600; letter-spacing:-0.02em; font-variant-numeric:tabular-nums; }
    .nw-series-note { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; margin-top:var(--sp-1); }
    .nw-series-list { margin-top:var(--sp-1); }
    .nw-series-row {
      display:flex; align-items:center; gap:10px; width:100%; min-height:44px; padding:var(--sp-2);
      border:none; background:none; border-radius:var(--radius-sm); font-family:inherit; color:var(--text);
      text-align:left; cursor:pointer;
    }
    .nw-series-row + .nw-series-row { border-top:1px solid var(--glass-border); border-radius:0; }
    @media (hover:hover) { .nw-series-row:hover { background:var(--bg); } }
    .nw-series-date { flex:1; min-width:0; display:flex; flex-direction:column; font-size:var(--fs-14); font-weight:500; }
    .nw-series-val { font-size:var(--fs-14); font-weight:600; font-variant-numeric:tabular-nums; }
    .nw-series-delta { width:92px; text-align:right; font-size:var(--fs-14); font-weight:600; font-variant-numeric:tabular-nums; color:var(--text-tertiary); }
    .nw-series-delta.nw-up { color:var(--success-ink); }
    .nw-series-delta.nw-down { color:var(--danger-ink); }
    .nw-series-gap, .nw-series-idkey { margin-top:var(--sp-3); line-height:1.5; }

    .nw-spark { width:100%; height:34px; display:block; margin-bottom:10px; overflow:visible; }
    .nw-spark-line { fill:none; stroke:var(--accent); stroke-width:1.5; vector-effect:non-scaling-stroke; stroke-linejoin:round; stroke-linecap:round; }
    .nw-spark-zero { stroke:var(--text-tertiary); stroke-width:1; stroke-dasharray:3 3; opacity:0.5; vector-effect:non-scaling-stroke; }
    .nw-spark-end { fill:var(--accent); }
    .nw-hist-row {
      display:flex; align-items:center; gap:10px; width:100%; padding:9px var(--sp-2); border:none; background:none;
      border-radius:var(--radius-sm); font-family:inherit; text-align:left; cursor:pointer; color:var(--text);
      min-height:44px;
    }
    .nw-hist-row + .nw-hist-row { border-top:1px solid var(--glass-border); border-radius:0; }
    .nw-hist-row.on { background:var(--accent-soft); }
    @media (hover:hover) { .nw-hist-row:hover { background:var(--bg); } }
    .nw-hist-date { flex:1; min-width:0; font-size:var(--fs-14); font-weight:500; }
    .nw-hist-net { font-size:var(--fs-14); font-weight:600; font-variant-numeric:tabular-nums; }
    .nw-hist-delta { width:96px; text-align:right; font-size:var(--fs-14); font-weight:600; font-variant-numeric:tabular-nums; }
    .nw-hist-delta.nw-up { color:var(--success-ink); }
    .nw-hist-delta.nw-down { color:var(--danger-ink); }
    .nw-hist-delta--none { color:var(--text-tertiary); font-weight:500; }

    /* ── Net worth · the editor ── */
    .nw-actions { display:flex; gap:var(--sp-2); margin-bottom:var(--sp-1); }
    .nw-actions .btn { flex:1; justify-content:center; min-height:44px; }
    .nw-action-edit { flex:0 1 auto; }
    .nw-empty-btn { margin-top:var(--sp-4); min-height:44px; justify-content:center; }

    /* The sheet adds up while it is being written, not only after saving. */
    .nw-edit-total {
      display:flex; align-items:baseline; gap:var(--sp-2); flex-wrap:wrap;
      padding:10px var(--sp-3); margin-bottom:var(--sp-3); border-radius:var(--radius-md);
      background:var(--bg); box-shadow:var(--inset);
    }
    .nw-edit-total-label { font-size:var(--fs-12); font-weight:600; color:var(--text-tertiary); }
    .nw-edit-total-value { font-size:var(--fs-16); font-weight:600; letter-spacing:-0.02em; font-variant-numeric:tabular-nums; margin-left:auto; }
    .nw-edit-total-value.nw-negative { color:var(--danger-ink); }
    .nw-edit-total-sub { width:100%; font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; font-variant-numeric:tabular-nums; text-align:right; }

    .nw-edit-row { padding:var(--sp-3) 0; border-top:1px solid var(--glass-border); }
    .nw-edit-row:first-child { border-top:none; padding-top:2px; }
    .nw-edit-head { display:flex; align-items:center; gap:var(--sp-2); margin-bottom:var(--sp-2); }
    .nw-edit-class {
      display:inline-flex; align-items:center; gap:6px; flex:1; min-width:0;
      padding:6px var(--sp-3); border:1px solid var(--glass-border-dark); border-radius:var(--radius-pill);
      background:var(--bg); color:var(--text); font-family:inherit; font-size:var(--fs-14); font-weight:600;
      cursor:pointer; text-align:left; min-height:44px;
    }
    .nw-edit-class svg { width:12px; height:12px; flex-shrink:0; color:var(--text-tertiary); }
    .nw-edit-move { display:flex; align-items:center; gap:var(--sp-1); flex-shrink:0; }
    /* 32px buttons with a 6px expander are 44px of target apiece. The inset
       is set explicitly because .icon-btn inherits a global ::after built for
       the month stepper — 22px above and below, which here bled over the rows
       on either side and made the neighbouring row's controls unreliable. */
    .nw-edit-move .icon-btn,
    .nw-edit-move .del-btn { width:32px; height:32px; font-size:var(--fs-16); position:relative; }
    .nw-edit-move .icon-btn::after,
    .nw-edit-move .del-btn::after { content:''; position:absolute; inset:-6px; }
    .nw-edit-row .field { margin-bottom:var(--sp-2); }
    .nw-edit-row .field:last-child { margin-bottom:0; }
    .nw-edit-row .inp { box-shadow:none; }
    .nw-edit-value label { display:flex; align-items:center; gap:var(--sp-2); }
    /* Override is one tap and says which way it goes — the product is usually
       the truth, and sometimes it is not. */
    .nw-edit-auto {
      position:relative; border:none; background:none; padding:2px 0; font-family:inherit; font-size:var(--fs-12);
      font-weight:600; color:var(--accent); cursor:pointer; text-decoration:underline; margin-left:auto;
    }
    /* A text link is the right shape here — it is a mode switch, not an
       action — but a 15px line is not a target. The expander grows into the
       label row's own space rather than changing the type. */
    .nw-edit-auto::after { content:''; position:absolute; inset:-14px -10px; }
    .nw-edit-flag {
      font-size:var(--fs-12); font-weight:600; letter-spacing:0; text-transform:none;
      color:var(--violet); background:var(--violet-soft); padding:2px 6px; border-radius:var(--radius-sm);
    }
    /* A locked value is derived, not disabled — it reads as a figure the app
       is keeping, rather than a field that has stopped working. */
    .nw-value-input[readonly] { background:var(--bg); color:var(--text-secondary); cursor:default; }
    .nw-add-btn { width:100%; justify-content:center; margin-top:var(--sp-3); min-height:44px; }
    .nw-edit-empty { padding:18px 0; text-align:center; }
    .modal-panel.modal-networth .modal-header { border-top:3px solid var(--teal-blue); }

    /* Desktop follows the same instinct as the rest of the ≥1100px block:
       less air, more in view. A legend stretched across 1060px puts a metre
       of nothing between a dot and its percentage. */
    @media (min-width:1100px) {
      .nw-legend { display:grid; grid-template-columns:1fr 1fr; column-gap:28px; row-gap:var(--sp-1); }
      .nw-actions .btn { flex:0 0 auto; min-width:170px; }
      .nw-hero-value { font-size:var(--fs-28); }
    }

    .nw-empty { text-align:center; padding:30px 18px; }
    .nw-empty .empty-icon svg { width:40px; height:40px; }
    .nw-empty-title { font-size:var(--fs-16); font-weight:600; margin-bottom:6px; }
    .nw-empty-sub { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; line-height:1.5; max-width:34ch; margin:0 auto; }
    .nw-note { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }

    .history-head { display:flex; align-items:flex-end; justify-content:space-between; gap:var(--sp-2); margin:2px 0 var(--sp-3); }
    .history-head .home-title { margin:0; }
    /* Home's title row, same shape as History's: the screen's name on the
       left, one thing on the right. Keeps .home-title's own 18px bottom
       margin so nothing below it moves. */
    .home-head { display:flex; align-items:flex-end; justify-content:space-between; gap:var(--sp-2); margin:2px 0 18px; }
    .home-head .home-title { margin:0; }
    /* A chip that goes somewhere, rather than one that toggles: the glyph
       says which screen, and it sits low enough to align with the title's
       baseline rather than its cap height. */
    .home-go { display:inline-flex; align-items:center; gap:5px; padding:6px var(--sp-3); margin-bottom:6px; }
    .home-go svg { width:13px; height:13px; flex-shrink:0; }
    .history-month-summary { text-align:right; padding-bottom:6px; flex-shrink:0; }
    .hms-unit { font-size:var(--fs-12); font-weight:500; color:var(--text-tertiary); }
    .hms-total { font-size:var(--fs-16); font-weight:600; letter-spacing:-0.02em; font-variant-numeric:tabular-nums; color:var(--text); }
    .hms-sub { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }
    .hms-down { color:var(--success-ink); font-weight:600; }
    .hms-up { color:var(--danger-ink); font-weight:600; }
    .hsearch { display:flex; align-items:center; flex:0 0 auto; gap:0; }
    .hsearch-btn {
      width:36px; height:36px; border-radius:var(--radius-pill); border:1px solid var(--glass-border-dark);
      background:var(--bg); color:var(--text-secondary); cursor:pointer; padding:0;
      display:inline-flex; align-items:center; justify-content:center; flex:0 0 auto;
    }
    .hsearch-btn svg { width:16px; height:16px; }
    .hsearch-input {
      width:0; opacity:0; padding:0; border:1px solid transparent; margin:0; height:36px;
      background:var(--bg); border-radius:var(--radius-pill); color:var(--text);
      font-family:inherit; font-size:var(--fs-input); font-weight:500; outline:none;
      transition:width var(--transition), opacity var(--transition), padding var(--transition);
    }
    .hsearch.open .hsearch-input, .hsearch-input:not(:placeholder-shown) {
      width:148px; opacity:1; padding:0 var(--sp-3); margin-left:6px; border-color:var(--glass-border-dark);
    }
    .hsearch-input:focus { border-color:var(--text-secondary); }
    .hsearch-input::placeholder { color:var(--text-tertiary); font-weight:500; }

    .recurring-row {
      display:flex; align-items:center; justify-content:space-between; padding:var(--sp-2) 0; border-top:1px solid var(--glass-border-dark); margin-top:var(--sp-2); cursor:pointer;
    }
    .recurring-label { font-size:var(--fs-14); font-weight:600; color:var(--text-secondary); letter-spacing:-0.01em; }
    /* One UI switches are noticeably larger and softer than the web default:
       a generous pill track with a thumb that fills most of its height.
       Grown from 40x22 with an 18px thumb. */
    .toggle {
      width:48px; height:28px; border-radius:14px; background:var(--border); position:relative; cursor:pointer; transition:var(--transition); flex-shrink:0; box-shadow:var(--shadow-neu-inset);
    }
    .toggle.on { background:var(--accent); }
    .toggle-knob {
      width:24px; height:24px; border-radius:50%; background:var(--surface-solid); position:absolute; top:2px; left:2px;
      /* transform, not `left` — `left` is a layout property, so animating it
         relayouts on every frame instead of running on the compositor. */
      transition:transform 280ms cubic-bezier(0.22,0.25,0,1); box-shadow:0 1px 3px rgba(0,0,0,0.15);
    }
    .toggle.on .toggle-knob { transform:translateX(20px); }


    /* Add Transaction Hero */
    .add-hero {
 background:var(--surface); border:1px solid var(--glass-border);
      border-radius:var(--radius-xl); padding:6px 10px; margin-bottom:var(--sp-2); box-shadow:var(--elev-1); text-align:center;
    }
    .add-hero-label { font-size:var(--fs-12); font-weight:600; color:var(--text-secondary); text-transform:none; letter-spacing:0; margin-bottom:2px; }
    .add-hero-input {
      width:100%; background:transparent; border:none; border-bottom:2px solid var(--glass-border-dark); padding:2px 0;
      color:var(--text); font-family:inherit; font-size:var(--fs-28); line-height:1.05; font-weight:600; text-align:center; outline:none; transition:var(--transition); letter-spacing:-0.02em;
    }
    .add-hero-input:focus { border-bottom-color:var(--accent); }
    .add-hero-input::placeholder { color:var(--text-tertiary); font-weight:600; }
    /* Quantity beside the amount: same underline language, compact. */
    .qty-x { font-size:var(--fs-16); font-weight:600; color:var(--text-tertiary); }
    .qty-input {
      width:42px; background:transparent; border:none; border-bottom:2px solid var(--glass-border-dark); padding:var(--sp-1) 0;
      color:var(--text); font-family:inherit; font-size:var(--fs-input); font-weight:600; text-align:center; outline:none;
      transition:var(--transition); font-feature-settings:'tnum' 1; font-variant-numeric:tabular-nums;
    }
    .qty-input:focus { border-bottom-color:var(--accent); }
    .qty-input::placeholder { color:var(--text-tertiary); font-weight:600; }
    .qty-hint { font-size:var(--fs-14); font-weight:600; color:var(--text-secondary); text-align:center; margin-top:6px; animation:infoIn 0.2s cubic-bezier(0.16,1,0.3,1); }

    /* Attach-a-bill button, sitting beside the impulse-purchase toggle. */
    .bill-attach-btn {
      width:32px; height:32px; border-radius:50%; border:none; background:transparent; font-size:var(--fs-14);
      color:var(--text-tertiary); cursor:pointer; display:inline-flex; align-items:center;
      justify-content:center; flex-shrink:0; transition:var(--transition); position:relative;
    }
    .bill-attach-btn svg { width:17px; height:17px; }
    .bill-attach-btn::after { content:''; position:absolute; left:-6px; right:-6px; top:50%; transform:translateY(-50%); height:44px; }
    @media (hover:hover) { .bill-attach-btn:hover { color:var(--text); background:var(--bg); } }
    .bill-attach-btn:active { transform:scale(0.94); }
    .bill-attach-btn:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }

    /* Chips for bills staged on the form. */
    .bill-chips { display:flex; flex-wrap:wrap; gap:6px; justify-content:center; margin-top:var(--sp-2); }
    .bill-chip {
      display:inline-flex; align-items:center; gap:5px; max-width:100%;
      background:var(--bg); border:1px solid var(--glass-border-dark); border-radius:var(--radius-pill);
      padding:5px 6px 5px 9px; font-size:var(--fs-14); font-weight:600; color:var(--text-secondary);
      animation:infoIn 0.2s cubic-bezier(0.16,1,0.3,1);
    }
    .bill-chip svg { width:12px; height:12px; flex-shrink:0; }
    .bill-chip-name { max-width:150px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
    .bill-chip-x {
      border:none; background:transparent; color:var(--text-tertiary); cursor:pointer;
      font-size:var(--fs-16); line-height:1; padding:0 3px; border-radius:50%; font-family:inherit;
    }
    @media (hover:hover) { .bill-chip-x:hover { color:var(--danger); } }
    .bill-chip-x:focus-visible { outline:2px solid var(--accent); outline-offset:1px; }

    /* The bill indicator is the one row icon that's interactive, so unlike its
       aria-hidden siblings it's a real button and needs its chrome stripped. */
    button.expense-status-icon { border:none; background:transparent; padding:0; cursor:pointer; font-family:inherit; }
    .expense-status-icon--bill { color:var(--text-tertiary); }
    @media (hover:hover) { .expense-status-icon--bill:hover { color:var(--accent); } }
    .expense-status-icon--bill:focus-visible { outline:2px solid var(--accent); outline-offset:2px; border-radius:4px; }

    /* Quick-add indicator: the second interactive row icon, sharing the bill
       icon's button reset above. --warning, not --danger — the entry is
       unfinished, not wrong, and reserving red for real problems keeps red
       meaningful. */
    .expense-status-icon--pending { color:var(--warning); }
    @media (hover:hover) { .expense-status-icon--pending:hover { color:var(--accent); } }
    .expense-status-icon--pending:focus-visible { outline:2px solid var(--accent); outline-offset:2px; border-radius:4px; }
    /* Whole-row tint, deliberately faint. These rows are scanned past far more
       often than acted on, so they should be findable, not shouty. */
    .tx-history-row.tx-pending { background:var(--warning-soft); }

    /* Home banner. The only place the uncategorised money is accounted for,
       so it is a button, not a notice — reading it should lead straight to
       fixing it. */
    .pending-banner {
      display:flex; align-items:center; gap:10px; width:100%; text-align:left;
      margin-bottom:14px; padding:14px var(--sp-4); cursor:pointer; font-family:inherit;
      background:var(--warning-soft); border:1px solid var(--warning);
      border-radius:var(--radius-lg); color:var(--text);
      font-size:var(--fs-14); font-weight:600; letter-spacing:-0.01em;
      transition:var(--transition);
    }
    .pending-banner svg { width:20px; height:20px; flex-shrink:0; color:var(--warning); }
    .pending-banner:active { transform:scale(0.99); filter:brightness(0.97); }
    @media (hover:hover) { .pending-banner:hover { background:color-mix(in srgb, var(--warning) 16%, transparent); } }
    .pending-banner:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }

    /* Pre-commit warning on the Add screen. */
    .quick-add-note {
      margin-top:10px; padding:var(--sp-2) var(--sp-3); border-radius:var(--radius-sm);
      background:var(--warning-soft); color:var(--text-secondary);
      font-size:var(--fs-14); font-weight:600; line-height:1.35; text-align:center;
    }

    .add-quick-row {
      display:flex; gap:6px; overflow-x:auto; -webkit-overflow-scrolling:touch; scrollbar-width:none; margin-bottom:6px; padding-bottom:2px;
    }
    .add-quick-row::-webkit-scrollbar { display:none; }

    .add-chip {
      padding:5px 10px; border-radius:var(--radius-pill); border:1px solid var(--glass-border-dark); background:var(--surface); color:var(--text-secondary);
      font-size:var(--fs-14); font-weight:500; cursor:pointer; white-space:nowrap; flex-shrink:0; transition:var(--transition);
 font-family:inherit;
    }
    .add-chip:active { background:var(--accent-soft); transform:scale(0.97); }
    .add-chip.on { background:var(--accent); color:var(--accent-inverse); border-color:var(--accent); }
    .add-chip:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }

    .add-section-title {
      font-size:var(--fs-12); font-weight:600; color:var(--text-secondary); letter-spacing:0; margin:6px 0 var(--sp-1) 2px;
    }

    .add-glass {
 background:var(--surface); border:1px solid var(--glass-border);
      border-radius:var(--radius-lg); padding:var(--sp-2) 10px; margin-bottom:6px;
    }
    #addSection .field { margin-bottom:var(--sp-2); }
    #addSection .home-title { margin-bottom:6px; }

    .add-sticky {
      position:fixed; bottom:calc(74px + env(safe-area-inset-bottom)); left:0; right:0;
      background:transparent; border-top:none;
      padding:10px 14px; display:flex; gap:10px; z-index:90; max-width:720px; margin:0 auto;
    }
    .add-sticky .btn { justify-content:center; height:46px; font-size:var(--fs-16); }
    /* Save is the primary action — give it dominant width; Clear is a quiet secondary. */
    .add-sticky .btn-clear { flex:0 0 90px; color:var(--text-secondary); }
    .add-sticky .btn-save { flex:1; font-weight:600; }

    .collapsible { max-height:0; overflow:hidden; transition:max-height 320ms cubic-bezier(0.16,1,0.3,1); padding:0 !important; margin:0 !important; }
    .collapsible.open { max-height:2000px; padding:2px 0 !important; }
    .collapse-toggle {
      display:flex; align-items:center; justify-content:space-between; padding:var(--sp-2) 0; cursor:pointer;
      font-size:var(--fs-14); font-weight:600; color:var(--text-secondary);
    }
    .collapse-toggle::after {
      content:''; width:6px; height:6px; border-right:1.5px solid var(--text-tertiary); border-bottom:1.5px solid var(--text-tertiary);
      transform:rotate(45deg); transition:var(--transition);
    }
    .collapse-toggle.open::after { transform:rotate(-135deg); }

    /* Budget Modal Category Grouping */
    .bm-category-group { margin-bottom:var(--sp-2); border:1px solid var(--glass-border-dark); border-radius:var(--radius-md); overflow:hidden; }
    .bm-category-header { display:flex; align-items:center; gap:var(--sp-2); padding:var(--sp-2) 10px; background:var(--bg); cursor:pointer; user-select:none; }
    .bm-category-header .arrow { display:inline-block; width:14px; text-align:center; font-size:var(--fs-12); color:var(--text-tertiary); transition:transform 200ms ease; }
    .bm-category-header.open .arrow { transform:rotate(0deg); }
    .bm-cat-name { font-size:var(--fs-14); font-weight:600; flex:1; }
    .bm-cat-badge { font-size:var(--fs-12); color:var(--text-tertiary); background:var(--surface); padding:1px 5px; border-radius:8px; border:1px solid var(--glass-border-dark); }
    .bm-cat-subtotal { font-size:var(--fs-14); font-weight:600; font-variant-numeric:tabular-nums; margin-left:6px; }
    .bm-cat-freq { font-size:var(--fs-14); color:var(--text-secondary); background:var(--surface); padding:1px 5px; border-radius:8px; border:1px solid var(--glass-border-dark); margin-left:var(--sp-1); }
    .bm-category-rows { padding:6px; display:flex; flex-direction:column; gap:6px; }
    .bm-item-row { display:flex; align-items:center; gap:6px; padding:6px; background:var(--surface); border-radius:var(--radius-sm); border:1px solid var(--glass-border-dark); }
    .bm-item-freq { padding:var(--sp-1) var(--sp-2); border-radius:var(--radius-pill); border:1px solid var(--glass-border-dark); background:var(--bg); color:var(--text-secondary); font-size:var(--fs-14); font-weight:600; cursor:pointer; white-space:nowrap; font-family:inherit; transition:var(--transition); flex-shrink:0; }
    .bm-item-freq:active { transform:scale(0.96); }

    /* Reports */
    /* Reports (design prototypes, board 6): one period row, tabs beneath,
       an even 3×2 stat strip, bars in the type list, one export button. */
    .report-range-row { display:flex; gap:6px; overflow-x:auto; scrollbar-width:none; padding:2px 0; margin-bottom:10px; }
    .report-range-row::-webkit-scrollbar { display:none; }
    .report-range-row .chip { flex:0 0 auto; }
    .report-custom { padding:var(--sp-3) 14px; margin-bottom:10px; }
    .report-grid { display:grid; grid-template-columns:repeat(3,1fr); gap:var(--sp-2); margin-bottom:10px; }
    .report-type-row { padding:var(--sp-2) 0; border-bottom:1px solid var(--glass-border-dark); }
    .report-type-row:last-child { border-bottom:none; }
    .report-type-head { display:flex; justify-content:space-between; font-size:var(--fs-14); margin-bottom:6px; }
    .report-type-head span:first-child { font-weight:600; }
    .report-type-head span:last-child { font-weight:600; font-variant-numeric:tabular-nums; }
    .report-export { display:flex; align-items:center; gap:6px; margin-top:var(--sp-2); }
    .report-export-main { flex:1; }
    .report-export-menu { width:46px; height:46px; flex-shrink:0; border-radius:50%; border:1px solid var(--glass-border-dark); background:var(--surface); color:var(--text); display:flex; align-items:center; justify-content:center; cursor:pointer; }
    .report-export-menu svg { width:16px; height:16px; }
    /* Where it went (round-two board 6): category rows with bars. */
    /* The money card (round-three board 1): four words, one bar, three facts. */
    .money-card { padding:var(--sp-4); margin-bottom:10px; }
    .money-grid { display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:var(--sp-3) 10px; }
    .money-cell { border-left:2px solid var(--border); padding-left:10px; min-width:0; }
    .money-label { font-size:var(--fs-12); font-weight:600; color:var(--text-tertiary); text-transform:none; letter-spacing:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
    .money-value { font-size:var(--fs-16); font-weight:600; letter-spacing:-0.03em; margin-top:var(--sp-1); font-variant-numeric:tabular-nums; white-space:nowrap; }
    .money-sub { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; margin-top:2px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
    .money-stack { display:flex; height:8px; border-radius:var(--radius-pill); overflow:hidden; background:var(--border); margin-top:14px; box-shadow:var(--inset); }
    .money-stack > div { transition:width 600ms var(--ease-out); }
    .money-legend { display:flex; flex-wrap:wrap; gap:var(--sp-1) var(--sp-3); margin-top:6px; font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }
    .money-legend i { display:inline-block; width:7px; height:7px; border-radius:50%; margin-right:var(--sp-1); }
    .money-foot { display:grid; grid-template-columns:repeat(3,1fr); gap:10px; text-align:center; margin-top:var(--sp-3); padding-top:10px; border-top:1px solid var(--glass-border); }
    .money-foot-value { font-size:var(--fs-16); font-weight:600; margin-top:3px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
    .money-note { font-size:var(--fs-14); color:var(--text-tertiary); line-height:1.5; margin:0 0 10px; padding:0 2px; }
    .money-note b { color:var(--text-secondary); font-weight:600; }
    .money-note-link {
      border:none; background:none; padding:0; font:inherit; font-weight:600;
      color:var(--accent); cursor:pointer;
    }

    /* ── Money in that is not income (round six, board 1) ── */
    .money-aside { margin-top:var(--sp-3); padding-top:10px; border-top:1px solid var(--glass-border-dark); }
    .money-aside-head {
      font-size:var(--fs-14); font-weight:600; letter-spacing:0; text-transform:none;
      color:var(--text-tertiary); margin-bottom:var(--sp-1);
    }
    .money-aside-row { display:flex; align-items:baseline; gap:var(--sp-2); padding:3px 0; font-size:var(--fs-14); }
    .money-kind {
      flex-shrink:0; font-size:var(--fs-14); font-weight:600; letter-spacing:0; text-transform:none;
      color:var(--text-tertiary); border:1px solid var(--glass-border-dark); border-radius:var(--radius-sm); padding:1px 5px;
    }
    .money-aside-name { flex:1; min-width:0; font-weight:600; }
    .money-aside-amt { font-weight:600; font-variant-numeric:tabular-nums; }
    .money-aside-note { margin:var(--sp-1) 0 0; font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }
    /* A headline changed under someone's feet; this says so, once. */
    .income-notice {
      margin-bottom:10px; padding:var(--sp-3); border:1px solid var(--accent); border-radius:var(--radius-md);
      background:var(--accent-soft); font-size:var(--fs-14); line-height:1.5; color:var(--text-secondary);
    }
    .income-notice p { margin:0 0 var(--sp-2); }
    .income-notice b { color:var(--text); }
    .income-notice-actions { display:flex; gap:var(--sp-2); }
    .income-notice-actions .btn { flex:1; justify-content:center; min-height:44px; }
    .attention-chip--info { border-color:var(--accent); background:var(--accent-soft); }
    .money-in-intro { margin:0 0 10px; font-size:var(--fs-14); line-height:1.5; color:var(--text-secondary); }
    .money-in-month { margin:0 0 var(--sp-3); font-size:var(--fs-14); color:var(--text-secondary); }
    .money-in-row { padding:10px 0; border-bottom:1px solid var(--glass-border-dark); }
    .money-in-row:last-of-type { border-bottom:none; }
    .money-in-name { display:flex; flex-direction:column; font-size:var(--fs-14); font-weight:600; margin-bottom:6px; }
    .money-in-kinds { grid-template-columns:repeat(2,1fr); }
    @media (min-width:560px) { .money-in-kinds { grid-template-columns:repeat(4,1fr); } }
    /* Month by month (round-three board 4) */
    .month-row { padding:9px 0; border-top:1px solid var(--glass-border); }
    .month-row:first-of-type { border-top:0; }
    .month-head { display:flex; align-items:center; gap:var(--sp-2); }
    .month-name { width:52px; flex-shrink:0; font-size:var(--fs-14); font-weight:600; }
    .month-bar { flex:1; min-width:0; }
    .month-bar .progress-track { display:block; height:6px; }
    .month-bar .progress-fill { display:block; }
    .month-spent { width:66px; text-align:right; font-size:var(--fs-14); font-weight:600; font-variant-numeric:tabular-nums; }
    .month-sub { display:flex; flex-wrap:wrap; gap:var(--sp-1) var(--sp-3); margin:var(--sp-1) 0 0 60px; font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }
    .month-sub b { color:var(--text-secondary); font-weight:600; }
    .month-sub .month-noplan { font-style:italic; opacity:0.85; }
    /* Against the plan, not against zero: separate from month-pos/neg, which
       colour the net. */
    .month-sub .month-under { color:var(--success-ink); }
    .month-sub .month-over { color:var(--danger-ink); }
    .month-pos { color:var(--success-ink) !important; } .month-neg { color:var(--danger-ink) !important; }
    .month-hint {
      display:flex; align-items:center; gap:9px; padding:10px var(--sp-3); margin-bottom:10px;
      border-radius:var(--radius-sm); background:var(--surface); border:1px dashed var(--glass-border-dark);
      font-size:var(--fs-14); color:var(--text-tertiary); line-height:1.45;
    }
    .month-hint > svg { width:15px; height:15px; flex-shrink:0; }
    .month-hint span { flex:1; min-width:0; }
    .month-hint-btn {
      min-height:32px; padding:0 10px; border-radius:var(--radius-pill); border:1px solid var(--accent);
      background:none; color:var(--accent); font:inherit; font-size:var(--fs-14); font-weight:600;
      white-space:nowrap; cursor:pointer; flex-shrink:0;
    }
    /* Delivery (round-three board 5) */
    .delivery-strip {
      display:flex; align-items:center; gap:10px; min-height:44px; padding:var(--sp-2) var(--sp-3); margin-bottom:var(--sp-3);
      border-radius:var(--radius-sm); background:var(--warning-soft); border:1px solid var(--warning);
      font-size:var(--fs-14); font-weight:600; width:100%; color:var(--text); font-family:inherit; text-align:left; cursor:pointer;
    }
    .delivery-strip.on { background:var(--warning); color:var(--accent-inverse); }
    .delivery-strip.on .delivery-strip-age { color:var(--accent-inverse); opacity:0.8; }
    .delivery-strip.on > svg { color:var(--accent-inverse); }
    .delivery-strip > svg { width:16px; height:16px; flex-shrink:0; color:var(--warning); }
    .delivery-strip-text { flex:1; min-width:0; }
    .delivery-strip-age { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; white-space:nowrap; }
    .delivery-row { display:flex; align-items:center; gap:var(--sp-2); border-top:1px solid var(--glass-border); }
    .delivery-row:first-of-type { border-top:0; }
    .delivery-open {
      flex:1; min-width:0; display:flex; align-items:center; gap:10px; min-height:52px; padding:6px 0;
      background:none; border:0; color:inherit; font:inherit; text-align:left; cursor:pointer;
    }
    .delivery-dot { width:8px; height:8px; border-radius:50%; flex-shrink:0; }
    .delivery-main { flex:1; min-width:0; display:flex; flex-direction:column; gap:2px; }
    .delivery-name { font-size:var(--fs-14); font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
    .delivery-meta-line { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
    .delivery-amt { font-size:var(--fs-14); font-weight:600; font-variant-numeric:tabular-nums; white-space:nowrap; }
    .delivery-act {
      flex-shrink:0; min-height:32px; padding:0 10px; border-radius:var(--radius-pill);
      border:1px solid var(--glass-border-dark); background:var(--bg); color:var(--text);
      font:inherit; font-size:var(--fs-14); font-weight:600; white-space:nowrap; cursor:pointer; position:relative;
    }
    .delivery-act::after { content:''; position:absolute; inset:-6px -2px; }
    .delivery-fold {
      display:flex; align-items:center; gap:9px; width:100%; min-height:44px; padding:10px var(--sp-3); margin-bottom:10px;
      border-radius:var(--radius-sm); background:var(--surface); border:1px solid var(--glass-border);
      color:var(--text-secondary); font:inherit; font-size:var(--fs-14); font-weight:500; text-align:left; cursor:pointer;
    }
    .delivery-fold > svg:first-child { width:15px; height:15px; flex-shrink:0; color:var(--success); }
    .delivery-fold span { flex:1; min-width:0; }
    .delivery-fold-chev { width:14px; height:14px; flex-shrink:0; color:var(--text-tertiary); }
    .report-flow { display:flex; gap:2px; padding:2px; background:var(--bg); border-radius:var(--radius-pill); }
    .report-flow-btn { min-height:24px; padding:2px 9px; border-radius:var(--radius-pill); border:0; background:none; color:var(--text-tertiary); font:inherit; font-size:var(--fs-14); font-weight:600; cursor:pointer; position:relative; }
    .report-flow-btn::after { content:''; position:absolute; inset:-10px -2px; }
    .report-flow-btn.on { background:var(--surface); color:var(--text); }
    .report-cat-row { display:flex; align-items:center; gap:10px; padding:5px 0; font-size:var(--fs-14); }
    .report-cat-name { width:96px; flex-shrink:0; font-weight:500; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
    .report-cat-bar { flex:1; } .report-cat-bar .progress-track { height:8px; }
    .report-cat-amt { width:66px; text-align:right; font-weight:600; font-variant-numeric:tabular-nums; white-space:nowrap; }
    .report-cat-pct { width:34px; text-align:right; font-size:var(--fs-14); color:var(--text-tertiary); font-variant-numeric:tabular-nums; }
    .report-cat-count { width:20px; text-align:right; font-size:var(--fs-14); color:var(--text-tertiary); font-variant-numeric:tabular-nums; }
    .report-more-link { display:flex; align-items:center; min-height:44px; background:none; border:0; padding:0; font:inherit; font-size:var(--fs-14); font-weight:600; color:var(--accent); cursor:pointer; }
    .report-empty-flow { font-size:var(--fs-14); color:var(--text-tertiary); padding:6px 0; }
    .report-months { display:flex; align-items:flex-end; gap:var(--sp-2); height:64px; }
    .report-month { flex:1; display:flex; flex-direction:column; align-items:center; justify-content:flex-end; gap:var(--sp-1); height:100%; min-width:0; }
    .report-month-bar { width:100%; border-radius:4px 4px 1px 1px; background:var(--border); }
    .report-month.now .report-month-bar { background:var(--accent); }
    .report-month-gap { width:100%; height:0; border-top:1px dashed var(--glass-border-dark); }
    .report-month-lbl { font-size:var(--fs-12); color:var(--text-tertiary); font-weight:500; line-height:1; }
    .report-month.now .report-month-lbl { color:var(--text); font-weight:600; }
    @media (max-width:400px) { .report-cat-name { width:80px; } }
    .report-export-main { display:flex; align-items:center; justify-content:center; gap:var(--sp-2); min-height:46px; font-size:var(--fs-16); }
    .report-export-main svg { width:16px; height:16px; }
    .report-export-more { display:flex; gap:var(--sp-2); }
    .report-export-more .btn { flex:1; justify-content:center; font-size:var(--fs-14); color:var(--text-secondary); }
    .report-card {
 background:var(--surface); border:1px solid var(--glass-border);
      border-radius:var(--radius-lg); padding:var(--sp-3); text-align:center;
      transition:transform var(--transition), box-shadow var(--transition);
    }
    @media (hover:hover) { .report-card:hover { box-shadow:var(--elev-2); transform:translateY(-1px); } }
    .report-card .report-label { font-size:var(--fs-12); font-weight:600; color:var(--text-secondary); letter-spacing:0; margin-bottom:6px; }
    .report-card .report-value { font-size:var(--fs-20); font-weight:600; letter-spacing:-0.03em; line-height:1; }
    .report-card .report-sub { font-size:var(--fs-14); color:var(--text-tertiary); margin-top:var(--sp-1); font-weight:500; }

    .report-table { width:100%; border-collapse:separate; border-spacing:0; font-size:var(--fs-14); }
    .report-table th, .report-table td { padding:var(--sp-2) 6px; text-align:left; border-bottom:1px solid var(--glass-border-dark); }
    .report-table th { font-weight:600; color:var(--text-tertiary); font-size:var(--fs-14); text-transform:none; letter-spacing:0; position:sticky; top:0; background:var(--bg); z-index:10; }
    .report-table td { font-weight:500; color:var(--text); }
    .report-table tr:last-child td { border-bottom:none; }
    .report-table .num { text-align:right; font-variant-numeric:tabular-nums; }

    .bar-chart { display:flex; align-items:flex-end; gap:var(--sp-1); height:120px; padding:10px 0; }
    .bar-item { flex:1; display:flex; flex-direction:column; align-items:center; gap:var(--sp-1); min-width:0; }
    .bar-fill { width:100%; max-width:32px; border-radius:5px 5px 2px 2px; background:linear-gradient(180deg, var(--accent), color-mix(in srgb, var(--accent) 78%, transparent)); min-height:2px; transition:height 500ms var(--ease-out); transform-origin:bottom; }
    .bar-label { font-size:var(--fs-12); color:var(--text-tertiary); font-weight:600; text-align:center; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; width:100%; }
    .bar-value { font-size:var(--fs-14); color:var(--text-secondary); font-weight:600; }

    .report-pill {
      display:inline-flex; align-items:center; gap:var(--sp-1); padding:3px var(--sp-2); border-radius:var(--radius-pill);
      background:var(--bg); border:1px solid var(--glass-border-dark); font-size:var(--fs-12); font-weight:600; color:var(--text-secondary); margin:2px;
    }
    .report-pill .dot { width:6px; height:6px; border-radius:50%; background:var(--accent); }

    .warning { color:var(--warning); }
    .warning .progress-fill { background:var(--warning); }

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

    @media (prefers-reduced-motion:reduce) { *,*::before,*::after { animation-duration:0.01ms !important; transition-duration:0.01ms !important; } }
    /* ═══════════════════════════════════════════════════════════════════════
       DESKTOP DENSITY SCALE  (≥1100px)
       ───────────────────────────────────────────────────────────────────────
       The inverse of the One UI mobile scale. On a phone the big titles and
       tall touch-rows earn their space — thumb reach, glanceability, an
       arm's-length viewing distance. With a mouse and a close screen, a
       desktop app wants the opposite: smaller type, shorter rows, more
       information per screen, less scrolling. Everything below 1100px keeps
       the One UI scale exactly as it is; this steps it down only where a
       desktop pointer is in play (1100px is also where the multi-column shell
       already begins, so type and layout shift together).

       Placement: this block sits at the END of the stylesheet on purpose. A
       media query carries no extra specificity, so it must follow every base
       rule it overrides — the same source-order trap that has bitten the
       desktop rail, the sheet handle and the FAB earlier in this file.
       ═══════════════════════════════════════════════════════════════════════ */
    @media (min-width:1100px) {
      /* Screen title: still the dominant element, no longer phone-sized. */
      .home-title { font-size:var(--fs-20); line-height:1.22; margin:0 0 14px; }

      /* Headline metrics come down a notch to match. */
      .progress-value { font-size:var(--fs-20); }

      /* Tighter surfaces — less air than One UI's generous mobile spacing. */
      .card { padding:13px; }
      .hero-card { padding:var(--sp-4); }
      .section { padding:15px 2px; }

      /* Denser list rows — the single biggest "this is a desktop app" change.
         min-height drops (a mouse doesn't need a 44px target); the vertical
         padding is set inline in the row template, so it takes !important to
         win. The row's HEIGHT is set by its tallest child, which is the side
         column (⋮ button + amount stacked), so the win comes from tightening
         line-heights there and in the title/meta, not from padding alone. Font
         SIZES are already small and are left as-is — this is about vertical
         rhythm, not shrinking text. Net: ~53px → ~45px, so ~15 rows become
         ~18 in the same viewport. */
      .tx-item { min-height:34px; padding:5px 0 !important; gap:11px; }
      .tx-history-row .tx-title { line-height:1.25; }
      .tx-history-row .tx-meta { line-height:1.3; margin-top:1px; }
      .tx-history-row .tx-side { gap:2px; }
      .tx-history-row .tx-amount { line-height:1.2; }
    }

    /* ═══════════════════════════════════════════════════════════════════════
       DESKTOP MASTER-DETAIL — History list + docked editor  (≥1100px)
       ───────────────────────────────────────────────────────────────────────
       On a wide screen, History stops being one-view-at-a-time and becomes a
       two-pane layout: the transaction list on the left, the selected row's
       editor docked on the right, so a whole month can be worked through
       without the list vanishing on every edit. The class is toggled by
       _syncHistorySplit(); #addSection (normally a separate tab) is shown as
       the right pane only while it's set. Below 1100px none of this applies —
       the mobile tab model is untouched.
       ═══════════════════════════════════════════════════════════════════════ */
    @media (min-width:1100px) {
      #mainScroll.history-split {
        display:grid;
        grid-template-columns:minmax(360px, 440px) 1fr;
        gap:var(--sp-6);
        align-items:start;
      }
      /* Reveal the editor pane. setTab sets #addSection to display:none while
         History is active; this !important override — scoped inside the ≥1100
         media query — is what shows it as the pane, and it automatically stops
         applying below 1100px, so the pane hides itself on a narrow window with
         no JS involved. */
      #mainScroll.history-split > #addSection { display:block !important; }

      /* #addSection precedes #historySection in the DOM, so columns are pinned
         explicitly — list left, editor right — rather than left to source order. */
      #mainScroll.history-split > #historySection { grid-column:1; grid-row:1; max-width:none; margin:0; min-width:0; }
      #mainScroll.history-split > #addSection      { grid-column:2; grid-row:1; max-width:none; margin:0; min-width:0; }

      /* The editor stays put while the list scrolls past it. Not height-capped:
         a capped, overflow-scrolled pane would clip the item-autocomplete and
         picker popovers; the Save bar is made static below so it rides with the
         form instead of floating at the viewport bottom. */
      #mainScroll.history-split > #addSection {
        position:sticky; top:4px; align-self:start;
        padding-left:var(--sp-6); border-left:1px solid var(--glass-border-dark);
      }
      /* The Save/Clear bar is position:fixed for the mobile full-screen form;
         inside the pane it must sit inline at the foot of the form instead. */
      #mainScroll.history-split #addSection .add-sticky {
        position:static; max-width:none; margin:0; padding:14px 0 2px;
      }

      /* Selected row — the classic master-detail accent bar. */
      #mainScroll.history-split .tx-history-row.tx-open {
        background:var(--accent-soft);
        box-shadow:inset 3px 0 0 var(--accent);
        border-radius:var(--radius-md);
      }
    }

    /* ═══════════════════════════════════════════════════════════════════════
       DESKTOP MASTER-DETAIL — Plan → Events & Goals  (≥1100px)
       ───────────────────────────────────────────────────────────────────────
       The same list+editor-side-by-side pattern as History, but the editors
       here are modals. On a wide Plan Events/Goals view the modal panel is
       reparented into #planDetailPane (by _openPlanInline) and the sheet chrome
       is stripped so it reads as an inline pane. Everything is gated on
       body.plan-detail — set only on desktop — so the mobile modal path is
       completely untouched. #planDetailPane is display:none until then.
       ═══════════════════════════════════════════════════════════════════════ */
    #planDetailPane { display:none; }
    @media (min-width:1100px) {
      body.plan-detail #planSplit {
        display:grid;
        grid-template-columns:minmax(340px, 460px) 1fr;
        gap:var(--sp-6);
        align-items:start;
      }
      body.plan-detail #planEvents,
      body.plan-detail #planGoals { grid-column:1; grid-row:1; margin:0; min-width:0; }
      body.plan-detail #planDetailPane {
        display:block; grid-column:2; grid-row:1; min-width:0;
        position:sticky; top:4px; align-self:start;
        padding-left:var(--sp-6); border-left:1px solid var(--glass-border-dark);
      }

      /* The reparented editor panel: strip its bottom-sheet/dialog chrome so it
         flows as plain inline content in the pane. */
      body.plan-detail #planDetailPane .modal-panel {
        position:static; transform:none; box-shadow:none; border:none;
        border-radius:0; background:transparent;
        max-width:none; width:auto; margin:0;
        /* The pane is sticky, so an editor taller than the window (type and
           category, lines, the budget row) would push its Save bar below the
           fold with no way to reach it: the panel is capped to the window and
           its body scrolls, the footer stays in view — as in the sheet. */
        max-height:calc(100vh - var(--pane-top, 120px) - 16px);
      }
      body.plan-detail #planDetailPane .modal-panel::before { display:none; }  /* no drag handle */
      body.plan-detail #planDetailPane .modal-body { overflow-y:auto; }
      /* The header/footer keep their own padding; drop the top padding so the
         editor's title lines up with the list's first card. */
      body.plan-detail #planDetailPane .modal-header { padding-top:0; }

      /* Empty state — shown only when no editor is docked. */
      body.plan-detail #planDetailPane.has-editor .plan-detail-hint { display:none; }
      body.plan-detail #planDetailPane .plan-detail-hint {
        color:var(--text-tertiary); font-size:var(--fs-14); font-weight:500;
        padding:32px var(--sp-2); text-align:center; line-height:1.5;
      }

      /* Selected card — the master-detail accent bar, matching History rows. */
      body.plan-detail .card.plan-open {
        background:var(--accent-soft);
        box-shadow:inset 3px 0 0 var(--accent);
      }
    }

    /* Month stepper — arrows flanking the month chip. The adjacent-month hop is
       the common case (Aug→Jul); the label still opens the full picker for a
       distant jump. Kept as one visual unit so it reads as a single control and
       costs the crowded header as little width as possible. */
    .month-nav { display:flex; align-items:center; gap:1px; flex-shrink:0; }
    .month-step {
      display:flex; align-items:center; justify-content:center;
      width:26px; height:26px; padding:0; flex-shrink:0;
      border:none; background:transparent; color:var(--text-secondary);
      border-radius:var(--radius-sm); cursor:pointer; transition:var(--transition);
      position:relative;
    }
    .month-step svg { width:14px; height:14px; }
    /* Touch-target expander, matching the convention used by the other small
       header controls — the visual button stays compact, the tap area doesn't. */
    .month-step::after { content:''; position:absolute; top:-9px; bottom:-9px; left:-4px; right:-4px; }
    @media (hover:hover) { .month-step:hover { background:var(--bg); color:var(--text); } }
    .month-step:active { background:var(--accent-soft); transform:scale(0.92); }
    .month-step:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
    /* Compact phones: shrink the arrows to match the other reduced header
       controls, so the stepper costs a crowded 360px header as little as
       possible. (Measured: the ~12px of header scroll at that width is
       PRE-EXISTING — removing the stepper entirely leaves it unchanged — so
       this is polish, not a fix for something the arrows caused.)

       This block MUST sit after the base .month-step rules directly above it.
       A media query carries no extra specificity, and putting it in the
       existing max-width:480px block far earlier in the file silently lost to
       the base rule — the fourth time that trap has bitten this stylesheet.

       The expander is re-tuned with the shrink: a fixed -9px inset gave the
       26px button a 44px target but leaves the 20px one at 38px. Visual size
       and expander have to move together or the target quietly regresses. */
    @media (max-width:480px) {
      .month-step { width:20px; height:20px; }
      .month-step svg { width:12px; height:12px; }
      .month-step::after { top:-12px; bottom:-12px; }
    }


    /* Swipe-to-delete on History rows.
       The row slides left under the finger and REDDENS as it goes; crossing the
       threshold deepens the tint and ticks a haptic, and releasing routes into
       the normal confirm flow rather than deleting outright.

       Tinting the row itself, rather than revealing a red panel behind it, is
       deliberate. The row is the element being translated, so any pseudo-
       element inside it travels with it — a "backdrop" would have to be
       counter-translated from JS and layered under the row's own background to
       stay put, which is fragile for no real gain. Colour on the moving row
       says the same thing and cannot break. */
    .tx-history-row.tx-swiping .tx-swipe-body {
      transition:transform 220ms cubic-bezier(0.22,0.25,0,1), background 160ms;
      will-change:transform;
    }
    /* Armed: past the delete threshold, so releasing will act. */
    .tx-history-row.tx-swipe-armed .tx-swipe-body {
      background:color-mix(in srgb, var(--danger) 26%, var(--surface));
    }
    /* Direct manipulation itself isn't "motion" to suppress, but the snap-back
       animation is — drop it and the row simply returns. */
    @media (prefers-reduced-motion: reduce) {
      .tx-history-row.tx-swiping .tx-swipe-body, .tx-history-row.tx-swipe-open .tx-swipe-body { transition:none; }
    }

    /* ═══════════════════════════════════════════════════════════════════════
       DESKTOP TABLE-DENSE HISTORY ROWS  (≥1100px)
       ───────────────────────────────────────────────────────────────────────
       The density pass got rows from 57px to 48px by tightening line-heights,
       and stopped there because the remaining height is structural: the row
       stacks title over meta, and stacks ⋮ over amount. A desktop list row is a
       LINE, not a card — so above 1100px both stacks are unstacked and the row
       reads as a table row:

           [icon]  Item name        category · mode · date        ₹amount   ⋮

       Pure CSS on the existing markup: renderHistory is untouched, so mobile
       keeps its stacked card rows exactly as the One UI pass left them.

       Safe without list virtualisation: History renders only
       `historyMonthsShown` months (starts at 1, Load More adds one), so the DOM
       row count is bounded by a month's transactions — tens, not thousands.
       Appended at the END of the file, after every base .tx-* rule it
       overrides, for the specificity reason documented four times above. */
    @media (min-width:1100px) {
      /* Title and meta side by side instead of stacked. */
      #historyList .tx-history-row .tx-content {
        display:flex; align-items:baseline; gap:14px; min-width:0;
      }
      /* The item name takes what it needs and truncates; the meta line fills
         the rest. Both need min-width:0 or flex refuses to shrink them and the
         amount gets pushed out of the row. */
      #historyList .tx-history-row .tx-title { flex:0 1 auto; min-width:0; }
      #historyList .tx-history-row .tx-meta {
        flex:1 1 auto; min-width:0; margin-top:0;
        overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
      }
      /* Amount and ⋮ side by side. row-reverse because the DOM order is
         menu-then-amount, and a table row wants the amount before the menu. */
      #historyList .tx-history-row .tx-side {
        flex-direction:row-reverse; align-items:center; gap:10px;
      }
      /* Nothing stacks any more, so the row can close down to a line. */
      #historyList .tx-history-row { min-height:0; padding:var(--sp-1) 0 !important; }
    }

    /* ═══════════════════════════════════════════════════════════════════════
       S PEN HOVER  (body.pen-active)
       ───────────────────────────────────────────────────────────────────────
       The S24 Ultra is touch-primary, so `(hover:hover)` is false and every
       hover affordance in this file is inert on it — despite the device
       shipping a stylus that genuinely hovers. setupPenHover() flags <body>
       when a hovering pen is seen, and these rules mirror the important hover
       states for it. The flag drops on the first finger tap, so a touch session
       can never inherit a stuck hover.

       Only the affordances that carry information are mirrored — what you are
       about to act on, and what an icon-only control means. Reproducing all 23
       hover rules would be noise on a pen, which has no cursor to follow. */
    body.pen-active #historyList .tx-history-row:hover {
      background:var(--accent-soft);
    }
    body.pen-active .card:hover,
    body.pen-active #eventsList .card:hover,
    body.pen-active #goalsList .card:hover {
      border-color:var(--glass-border-dark);
    }
    body.pen-active .dock-btn:hover,
    body.pen-active .icon-btn:hover,
    body.pen-active .chip:hover,
    body.pen-active .month-step:hover {
      background:var(--bg); color:var(--text);
    }
    /* A hovering pen is a pointer without a click, so the cursor affordance is
       the only cue that something is interactive until it lands. */
    body.pen-active .tx-history-row { cursor:pointer; }

    /* Date-group header, desktop weight.
       The density pass took rows from 57px to 37px but left this pill at full
       mobile weight — a solid --accent block (a very dark indigo in light mode)
       24px tall against a 37px row, i.e. 65% of the row height versus 42% on
       mobile. It stopped reading as a group header and started dominating the
       list. Same element, same shape, weight-appropriate for a dense list: a
       soft tint with accent text instead of a heavy filled block. */
    @media (min-width:1100px) {
      #historyList .tx-date-header { margin:var(--sp-3) 0 var(--sp-1); }
      #historyList .tx-date-header:first-child { margin-top:0; }
      #historyList .tx-date-label {
        background:var(--accent-soft);
        color:var(--accent);
        padding:2px 9px;
        letter-spacing:0.07em;
      }
    }

    /* Cloud-sync status line. Colour-coded by whether the user can act on it:
       err = needs action (misconfigured server, signed out), warn = transient
       (offline, will retry), ok = healthy. */
    .sync-status {
      margin-top:var(--sp-2); padding:var(--sp-2) 10px; border-radius:var(--radius-sm);
      font-size:var(--fs-14); font-weight:600; line-height:1.4;
    }
    .sync-status.ok   { background:var(--success-soft); color:var(--success-ink); box-shadow:inset 0 0 0 1px var(--success); }
    .sync-status.warn { background:var(--warning-soft); color:var(--warning-ink); box-shadow:inset 0 0 0 1px var(--warning); }
    .sync-status.err  { background:var(--danger-soft);  color:var(--danger-ink); box-shadow:inset 0 0 0 1px var(--danger); }
    /* Sync banner reuses the pending-banner shape but reads as a problem, not
       a nudge — this one means data is not leaving the device. */
    .pending-banner.sync-banner {
      background:var(--danger-soft); border-color:var(--danger);
    }
    .pending-banner.sync-banner svg { color:var(--danger); }

    /* ── History filter bar ───────────────────────────────────────────
       Replaces the "Filters" button + modal. The bar IS the filter state:
       every axis shows its own selection, so nothing has to be opened to
       read back what is applied.
       Appended at the end of the file deliberately — the desktop overrides
       below carry no extra specificity, so they only win from source order. */
    .hfilter-row {
      display:flex; gap:6px; align-items:center; margin-bottom:var(--sp-2); min-width:0;
    }
    .hfilter-bar {
      flex:1; min-width:0; display:flex; gap:6px; overflow-x:auto;
      scrollbar-width:none; -webkit-overflow-scrolling:touch;
      /* 6px of room above and below so each 36px pill's 44px hit area is
         not clipped by the scroller (round seven, board 32). */
      padding:6px 0; margin:-4px 0; scroll-padding-inline:8px;
    }
    .hfilter-bar::-webkit-scrollbar { display:none; }
    .hfilter-dd {
      flex:0 0 auto; display:inline-flex; align-items:center; gap:6px;
      height:36px; padding:0 13px; border-radius:var(--radius-pill);
      white-space:nowrap; cursor:pointer; font-family:inherit;
      font-size:var(--fs-14); font-weight:500;
      background:var(--surface); color:var(--text);
      border:1px solid var(--glass-border-dark);
      transition:var(--transition);
    }
    .hfilter-dd.on {
      background:var(--accent); color:var(--accent-inverse); border-color:var(--accent);
    }
    .hfilter-dd:active { transform:scale(0.97); }
    .hfilter-dd:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
    /* Caret rotates to point up while that axis's menu is open. */
    .hfilter-cv {
      width:6px; height:6px; flex:0 0 auto; opacity:0.55;
      border-right:2px solid currentColor; border-bottom:2px solid currentColor;
      transform:rotate(45deg) translate(-1px,-1px);
      transition:transform var(--transition);
    }
    .hfilter-dd[aria-expanded="true"] .hfilter-cv {
      transform:rotate(-135deg) translate(-1px,-1px);
    }
    .hfilter-clear { border-style:dashed; color:var(--text-secondary); }
    .hfilter-select { height:36px; flex:0 0 auto; }

    .hfilter-pop {
      background:var(--surface); border:1px solid var(--glass-border-dark);
      border-radius:var(--radius-md); padding:var(--sp-3) 14px; margin-bottom:var(--sp-2);
    }
    /* Only on the render that first opens an axis — see renderHistoryFilterMenu. */
    .hfilter-pop.is-opening { animation:hfilterPop 0.22s cubic-bezier(0.22,0.25,0,1); }
    @keyframes hfilterPop { 0% { opacity:0; transform:translateY(-4px); } 100% { opacity:1; transform:none; } }
    .hfilter-pop-head {
      display:flex; align-items:center; justify-content:space-between; gap:10px;
      margin-bottom:10px; font-size:var(--fs-14); font-weight:600;
      text-transform:none; letter-spacing:0; color:var(--text-secondary);
    }
    .hfilter-mini {
      background:none; border:0; padding:0; cursor:pointer; font-family:inherit;
      color:var(--accent); font-size:var(--fs-14); font-weight:600;
      text-transform:none; letter-spacing:0;
    }
    .hfilter-mini:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
    .hfilter-opts {
      display:flex; flex-wrap:wrap; gap:6px;
      max-height:196px; overflow-y:auto;
    }
    /* Size and layout only. Setting a background here would tie with .chip.on
       at (0,2,0) and — being later in the file — silently win, killing the
       selected state. inline-flex is what puts a gap between label and count. */
    .hfilter-opts .chip {
      display:inline-flex; align-items:center; gap:6px;
      font-size:var(--fs-14); padding:var(--sp-2) 13px;
    }
    .hfilter-dates { display:flex; gap:6px; margin-top:10px; }
    .hfilter-dates .inp { flex:1; padding:9px 11px; font-size:var(--fs-14); }
    .hfilter-empty { font-size:var(--fs-14); color:var(--text-secondary); }

    @media (prefers-reduced-motion: reduce) {
      .hfilter-pop.is-opening { animation:none; }
    }

    /* Desktop: there is room for every axis at once, so the bar wraps instead
       of hiding its tail behind a horizontal scroll. */
    @media (min-width:1100px) {
      /* One line (round seven, board 18): four rows of axes put the first
         entry at 340px against 201px on a phone. */
      .hfilter-bar { flex-wrap:nowrap; overflow-x:visible; }
      .hfilter-dd--extra { display:none; }
      .hfilter-opts { max-height:none; }
      .hsearch-input { width:180px; opacity:1; padding-left:var(--sp-3); padding-right:var(--sp-3); margin-left:6px; border-color:var(--glass-border-dark); }
    }
    .hfilter-more { display:none; }
    @media (min-width:1100px) { .hfilter-more { display:inline-flex; border-style:dashed; } }

    /* (The old `display:contents` here made the Clear button a direct child
       of the filter row. The chip row that replaced it is its own row below
       the bar — see the rule near .hfilter-chip — so this override is gone;
       leaving it would have collapsed the chips back into the row and taken
       width from the scrolling bar again.) */

    /* ── Desktop filter rail (≥1100px) ────────────────────────────────────
       Direction B, adopted for the wide layout only. The panel's markup is
       identical on every viewport — a rail of axes plus an options pane, each
       option carrying a checkbox and a facet count. Below 1100px CSS hides the
       rail, the boxes and the counts, and the options stay the chip pills the
       phone already had. Nothing here is switched in JS, so crossing the
       breakpoint is correct without a resize listener, the same bargain
       _syncHistorySplit makes for the detail pane. */
    .hfilter-rail { display:none; }
    .hfilter-box { display:none; }

    /* Facet counts ride the pill on a phone too. 12px clears the 11px floor
       the font-floor pass set. The selected colour is deliberate: a pill that
       is .on is filled with --accent, so --text-secondary would be grey on
       accent — the count has to come from the same token pair as the label it
       sits beside. */
    .hfilter-n {
      flex:0 0 auto;
      font-size:var(--fs-12); font-weight:600;
      color:var(--text-secondary);
      font-variant-numeric:tabular-nums;
    }
    /* 0.85, not a rounder 0.75: --accent-inverse at 75%% over --accent
       composites to 4.07:1 in dark mode, under the 4.5 floor for 12px bold.
       0.85 measures 4.88 and still reads lighter than the 5.98 label. */
    .hfilter-opts .chip.on .hfilter-n { color:var(--accent-inverse); opacity:0.85; }

    /* An option no current combination can return. It is disabled in the
       markup, which is what makes this fade legitimate: WCAG 1.4.3 exempts
       inactive controls, and without that exemption there was nowhere to fade
       to — --text-secondary measures 5.33:1 in light mode, less than a stop
       above the 4.5 floor. Dropping the pill alone was not enough of a signal
       either, since a light-mode pill is white on white behind a 6%-black
       hairline. Never applied to .on: a selected option can read zero, that
       being exactly when the list is empty, and disabling it would leave no
       way to click back out. */
    .hfilter-opts .chip[data-empty]:not(.on) {
      color:var(--text-tertiary);
      border-color:transparent;
      background:transparent;
      opacity:0.5;
      cursor:default;
    }
    .hfilter-opts .chip[data-empty]:not(.on):active { transform:none; }

    @media (min-width:1100px) {
      .hfilter-pop {
        display:grid;
        grid-template-columns:142px minmax(0, 1fr);
        padding:0;
        overflow:hidden;
      }
      .hfilter-rail {
        display:flex; flex-direction:column; gap:1px;
        padding:var(--sp-2) 0; border-right:1px solid var(--glass-border-dark);
        background:var(--bg); min-width:0;
      }
      .hfilter-railitem {
        display:flex; align-items:center; gap:6px;
        padding:9px var(--sp-3) 9px 14px; min-height:38px;
        border:0; border-left:3px solid transparent; background:transparent;
        font:inherit; font-size:var(--fs-14); font-weight:500; text-align:left;
        color:var(--text-secondary); cursor:pointer;
        transition:color var(--transition), background var(--transition);
      }
      .hfilter-railitem:hover { color:var(--text); }
      .hfilter-railitem[aria-selected="true"] {
        color:var(--text); font-weight:600;
        background:var(--surface); border-left-color:var(--accent);
      }
      .hfilter-railitem:focus-visible { outline:2px solid var(--accent); outline-offset:-2px; }
      .hfilter-railname {
        flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
      }
      .hfilter-raildot {
        flex:0 0 auto; width:6px; height:6px; border-radius:50%; background:var(--accent);
      }

      .hfilter-pane { padding:var(--sp-3) 14px var(--sp-3) var(--sp-4); min-width:0; }
      .hfilter-opts {
        display:flex; flex-direction:column; gap:1px;
        /* The pill layout above sets flex-wrap:wrap. Left alone, a column
           flex box with a capped height wraps rows into side-by-side
           COLUMNS instead of scrolling — which reads as a tidy panel that
           has silently hidden most of its options. */
        flex-wrap:nowrap;
        max-height:236px; overflow-y:auto;
      }
      /* The pill becomes a checkbox row. Every one of these needs (0,3,0) to
         clear .chip.on, which is (0,2,0) and defined earlier in the file —
         a plain `.hfilter-opts .chip` would tie and lose on the properties
         .chip.on also sets. */
      .hfilter-opts .chip,
      .hfilter-opts .chip.on {
        display:flex; align-items:center; gap:10px; width:100%;
        padding:var(--sp-2) var(--sp-2) var(--sp-2) 6px; min-height:38px;
        border:0; border-radius:11px; background:transparent;
        color:var(--text); font-size:var(--fs-14); font-weight:500;
        animation:none; transform:none; text-align:left;
      }
      .hfilter-opts .chip:hover, .hfilter-opts .chip.on:hover { background:var(--bg); }
      .hfilter-opts .chip::after { content:none; }  /* the touch hit-expander */
      .hfilter-box {
        display:flex; align-items:center; justify-content:center;
        flex:0 0 auto; width:18px; height:18px; border-radius:5px;
        border:2px solid var(--glass-border-dark);
        transition:background var(--transition), border-color var(--transition);
      }
      .hfilter-opts .chip.on .hfilter-box {
        background:var(--accent); border-color:var(--accent);
      }
      /* Drawn with a border rather than an svg so it inherits the token. */
      .hfilter-opts .chip.on .hfilter-box::after {
        content:''; width:4px; height:8px; margin-top:-2px;
        border:solid var(--accent-inverse); border-width:0 2px 2px 0;
        transform:rotate(45deg);
      }
      .hfilter-lbl {
        flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
      }
      /* The row layout leaves the chip unfilled, so the selected count reads
         as the accent itself rather than needing the inverse. */
      .hfilter-n { font-weight:500; }
      .hfilter-opts .chip.on .hfilter-n { color:var(--accent); font-weight:600; opacity:1; }
      /* The row layout has no fill to mute, so the empty state is carried by
         the text and a hollowed checkbox. (0,3,0) to clear the row rules. */
      .hfilter-opts .chip[data-empty]:not(.on) {
        background:transparent; color:var(--text-tertiary);
      }
      .hfilter-opts .chip[data-empty]:not(.on):hover { background:transparent; }
      .hfilter-opts .chip[data-empty]:not(.on) .hfilter-box { opacity:0.45; }
      .hfilter-pop-head { margin-bottom:var(--sp-2); }
      .hfilter-dates { padding-top:2px; }
      .hfilter-empty { padding:var(--sp-1) 2px; }
    }

    /* Lifecycle group headers inside the desktop multicol flow (≥1100px).
       #trackList is column-count:2 there, and a header is just another block
       in that flow — so the column break can fall immediately after one,
       stranding the category pill at the foot of the left column with every
       one of its items at the top of the right. Measured: 2 of 10 realistic
       category shapes did exactly that. break-after:avoid moves the header
       down with its first row.
       Appended at the end of the file because the multicol rule it refines
       sits near the top and media queries carry no extra specificity. */
    @media (min-width:1100px) {
      #trackSection > #trackList > .lc-cat-header {
        break-after:avoid; -webkit-column-break-after:avoid; page-break-after:avoid;
      }
    }

    /* ── Sign-in sheet ──────────────────────────────────────────────────── */
    .auth-intro {
      font-size:var(--fs-14); color:var(--text-secondary);
      margin:0 0 14px; line-height:1.5;
    }
    .auth-error {
      margin-top:var(--sp-3); padding:10px var(--sp-3); border-radius:var(--radius-md);
      background:var(--danger-soft); color:var(--danger-ink); border:1px solid var(--danger);
      font-size:var(--fs-14); font-weight:500; line-height:1.45;
    }
    .auth-who {
      display:flex; align-items:center; justify-content:space-between; gap:10px;
      font-size:var(--fs-14);
    }
    .auth-who .auth-email {
      color:var(--text); font-weight:600; min-width:0;
      overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
    }

    /* ── Sign-in gate ───────────────────────────────────────────────────
       Above every layer the app has (modals sit well below 9000). Opaque on
       purpose: its job is to stand between a signed-out session and the
       data, so nothing may show through it. */
    #authGate {
      position:fixed; inset:0; z-index:9999;
      display:flex; align-items:center; justify-content:center;
      background:var(--bg); padding:20px;
      padding-top:calc(20px + env(safe-area-inset-top));
      padding-bottom:calc(20px + env(safe-area-inset-bottom));
    }
    .auth-gate-panel { width:100%; max-width:420px; padding:22px 18px; }
    .auth-gate-brand { display:flex; align-items:center; gap:var(--sp-3); margin-bottom:10px; }
    .auth-gate-brand h3 { font-size:var(--fs-20); font-weight:600; letter-spacing:-0.01em; }
    .auth-gate-actions { display:flex; justify-content:space-between; gap:var(--sp-2); margin-top:14px; }

    /* ── Notes on expenses ──────────────────────────────────────────────
       Icon matches the bill icon's interactive treatment; the expansion is a
       quiet quoted block under the row's meta line. 0.75rem clears the 11px
       font floor. pre-wrap keeps the user's own line breaks. */
    .expense-status-icon--note { color:var(--text-tertiary); }
    @media (hover:hover) { .expense-status-icon--note:hover { color:var(--accent); } }
    .expense-status-icon--note:focus-visible { outline:2px solid var(--accent); outline-offset:2px; border-radius:4px; }
    .tx-note {
      font-size:var(--fs-14); color:var(--text-secondary);
      background:var(--bg); border-left:2px solid var(--accent);
      border-radius:0 8px 8px 0; padding:6px 10px; margin-top:5px;
      white-space:pre-wrap; word-break:break-word; max-width:56ch;
    }

    /* Amount-expression error: the hero input has no border to recolor, so
       the state is an outline plus the danger ink on the digits themselves. */
    #txAmount.amount-error {
      outline:2px solid var(--danger); outline-offset:3px;
      border-radius:11px; color:var(--danger);
    }

    /* ── Round seven, board 32: 44px hit areas where the drawn control is
       smaller. The expander is invisible; the control keeps its look. ── */
    .hsearch-btn, .hfilter-dd, .quick-sheet-full { position:relative; }
    .hsearch-btn::after, .hfilter-dd::after, .quick-sheet-full::after { content:''; position:absolute; inset:-4px; }
    .qty-input { min-height:44px; }

    /* ── Round seven, board 7: the hero in three one-line bands ── */
    .hero-line { display:flex; align-items:baseline; justify-content:space-between; gap:10px; margin-top:var(--sp-3); font-size:var(--fs-16); font-variant-numeric:tabular-nums; }
    .hero-spent b { font-weight:600; color:var(--text); }
    .hero-of { color:var(--text-secondary); }
    .hero-left { font-weight:600; white-space:nowrap; padding-left:var(--sp-2); border-left:3px solid var(--border); }
    .hero-left.danger { border-left-color:var(--danger); }
    .hero-left.warning { border-left-color:var(--warning); }
    #homeSection .hero-today { margin:6px 0 0; font-size:var(--fs-14); }
    .hero-trend { margin-top:10px; padding-top:10px; }
    .hero-trend-text { display:flex; align-items:baseline; justify-content:space-between; flex-wrap:wrap; gap:var(--sp-1) 10px; width:100%; }
    .hero-trend-value { margin-top:0; font-size:var(--fs-14); font-weight:600; }
    .hero-trend-value .hero-trend-label { text-transform:none; letter-spacing:0; font-size:var(--fs-14); font-weight:500; color:var(--text-secondary); }
    .hero-trend-link { position:relative; font-size:var(--fs-14); }
    .hero-card[hidden], .first-run[hidden] { display:none; }
    /* ── Round seven, board 6: first steps ── */
    .first-run { display:flex; flex-direction:column; gap:2px; margin-bottom:var(--sp-3); }
    .first-run-title { font-size:var(--fs-16); font-weight:600; margin-bottom:6px; }
    .first-run-step { display:flex; align-items:center; gap:10px; min-height:48px; border-top:1px solid var(--glass-border); }
    .first-run-tick { width:22px; height:22px; border-radius:50%; border:2px solid var(--border); display:grid; place-items:center; font-size:var(--fs-12); font-weight:600; flex-shrink:0; }
    .first-run-step.done .first-run-tick { border-color:var(--success); background:var(--success-soft); }
    .first-run-label { flex:1; font-size:var(--fs-16); font-weight:500; }
    .first-run-step.done .first-run-label { color:var(--text-secondary); }
    .first-run-step .plan-set { margin:0; }
    .first-run-done { font-size:var(--fs-14); color:var(--text-secondary); font-weight:600; }
    .first-run-sub { margin:var(--sp-2) 0 0; font-size:var(--fs-14); color:var(--text-secondary); }

    /* ── Round seven, board 11: a signed change and inflow bars ── */
    .tracked-comp { font-size:var(--fs-14); font-weight:600; padding:1px 5px; border-radius:6px; border:1px solid var(--glass-border-dark); color:var(--text); font-variant-numeric:tabular-nums; }
    .tracked-comp.up { border-color:var(--danger); background:var(--danger-soft); }
    .tracked-comp.down { border-color:var(--success); background:var(--success-soft); }
    .tracked-comp.same { color:var(--text-secondary); }
    .tracked-fixed { font-size:var(--fs-14); color:var(--text-secondary); font-weight:600; background:var(--bg); padding:1px 5px; border-radius:8px; border:1px solid var(--glass-border-dark); }
    .tracked-empty { color:var(--text-secondary); font-size:var(--fs-14); padding:6px 0; }
    .progress-fill.inflow { background:var(--teal-blue); }
    /* ── Round seven, board 10: all accounts, one tap away ── */
    .acc-all { display:flex; align-items:center; width:100%; min-height:44px; padding:0; border:0; border-top:1px solid var(--glass-border); background:none; font:inherit; font-size:var(--fs-14); font-weight:600; color:var(--accent); cursor:pointer; text-align:left; }

    /* ── Round seven, board 29: search, recent, desktop popover ── */
    .picker-search { width:100%; margin:0 0 10px; }
    .picker-item.active { background:var(--accent-soft); }
    .picker-item[hidden], .picker-group[hidden], .picker-none[hidden] { display:none; }
    .picker-none { padding:var(--sp-4) var(--sp-1); color:var(--text-secondary); font-size:var(--fs-14); }
    @media (min-width:1100px) {
      #pickerModal.picker-anchored { align-items:flex-start; justify-content:flex-start; }
      #pickerModal.picker-anchored .modal-backdrop { background:transparent; backdrop-filter:none; -webkit-backdrop-filter:none; }
      #pickerModal.picker-anchored .modal-panel {
        position:fixed; top:var(--pk-top); left:var(--pk-left); margin:0; width:340px; max-width:340px;
        max-height:min(460px, 60vh); border-radius:var(--radius-lg); box-shadow:var(--elev-3); transform:none;
      }
      #pickerModal.picker-anchored .modal-header { padding-top:10px; padding-bottom:6px; }
    }
    /* ── Round seven, board 16: the eight categories you use, then All ── */
    .add-chip[hidden] { display:none; }
    .add-chip--all { border-style:dashed; }
    /* ── Round seven, board 14: pills wrap to a second line, never truncate ── */
    .meta-strip { flex-wrap:wrap; }
    .meta-pill { flex:1 1 auto; min-width:min-content; overflow:visible; }
    .meta-pill--sub { flex:1 1 auto; }
    /* ── Round seven, board 13: a neutral plan line before any amount ── */
    .tx-plan-line--neutral .tx-plan-txt b { color:var(--text); }

    /* ── Round seven, board 4: sync state in the header ── */
    .sync-chip { display:inline-flex; align-items:center; gap:5px; height:28px; padding:0 10px; border-radius:var(--radius-pill); border:1px solid var(--warning); background:var(--warning-soft); color:var(--text); font:inherit; font-size:var(--fs-14); font-weight:600; white-space:nowrap; cursor:pointer; flex-shrink:0; position:relative; }
    .sync-chip::after { content:''; position:absolute; inset:-8px -2px; }
    .sync-chip[hidden] { display:none; }
    .sync-chip-dot { width:7px; height:7px; border-radius:50%; background:var(--warning); }
    .sync-chip--bad { border-color:var(--danger); background:var(--danger-soft); }
    .sync-chip--bad .sync-chip-dot { background:var(--danger); }
    @media (max-width:480px) { .header-bar.has-sync-chip .brand-text { display:none; } }
    @media (max-width:380px) { .sync-chip-text { position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0,0,0,0); } .sync-chip { padding:0 var(--sp-2); } }
    /* ── Round seven, board 37: whose data ── */
    .title-profile { font-weight:500; color:var(--text-secondary); }
    .profile-flash { position:fixed; left:50%; top:calc(env(safe-area-inset-top) + 56px); transform:translateX(-50%); z-index:900; padding:6px var(--sp-3); border-radius:var(--radius-pill); background:var(--text); color:var(--surface); font-size:var(--fs-14); font-weight:600; box-shadow:var(--elev-2); pointer-events:none; }
    .profile-flash[hidden] { display:none; }

    /* ── Round seven, board 18: Select in the title row ── */
    .history-select { min-height:36px; padding:0 var(--sp-3); border:1px solid var(--glass-border-dark); border-radius:var(--radius-pill); background:var(--surface); color:var(--text); font:inherit; font-size:var(--fs-14); font-weight:600; cursor:pointer; position:relative; align-self:center; }
    .history-select::after { content:''; position:absolute; inset:-4px; }
    .history-select[aria-pressed="true"] { background:var(--accent); color:var(--accent-inverse); border-color:transparent; }

    /* ── Round seven, board 20: desktop row actions and keys ── */
    .tx-row-acts { display:none; }
    @media (min-width:1100px) and (hover:hover) {
      .tx-row-acts { display:none; gap:2px; margin-right:var(--sp-1); }
      .tx-history-row:hover .tx-row-acts, .tx-history-row:focus-within .tx-row-acts, .tx-history-row.tx-kb .tx-row-acts { display:inline-flex; }
      .tx-history-row:hover .tx-menu-btn, .tx-history-row:focus-within .tx-menu-btn, .tx-history-row.tx-kb .tx-menu-btn { display:none; }
    }
    .tx-row-act { width:30px; height:30px; display:grid; place-items:center; border:0; border-radius:8px; background:transparent; color:var(--text-secondary); cursor:pointer; }
    .tx-row-act svg { width:15px; height:15px; }
    .tx-row-act:hover, .tx-row-act:focus-visible { background:var(--bg); color:var(--text); }
    .tx-row-act[data-act="undo-delete"]:hover { color:var(--danger-ink); box-shadow:inset 0 0 0 1px var(--danger); }
    .tx-history-row.tx-kb { box-shadow:inset 3px 0 0 var(--accent); background:var(--accent-soft); outline:none; }
    .toast--action { display:flex; align-items:center; gap:var(--sp-3); }
    .toast-act { border:0; background:none; font:inherit; font-weight:600; color:inherit; text-decoration:underline; cursor:pointer; min-height:32px; padding:0 var(--sp-1); }

    /* Round seven, board 18, in the History split: the list column is ~440px,
       so the search stays a magnifier and the one line may wrap once rather
       than run under the pane. */
    @media (min-width:1100px) {
      #mainScroll.history-split .hfilter-bar { flex-wrap:wrap; }
      #mainScroll.history-split .hsearch-input { width:0; opacity:0; padding:0; margin:0; border-color:transparent; }
      #mainScroll.history-split .hsearch.open .hsearch-input,
      #mainScroll.history-split .hsearch-input:not(:placeholder-shown) { width:148px; opacity:1; padding:0 var(--sp-3); margin-left:6px; border-color:var(--glass-border-dark); }
    }

    /* ── Round seven, board 33: a skip link, and a ring on every stop ── */
    .skip-link { position:fixed; left:12px; top:-60px; z-index:2000; padding:10px 14px; border-radius:var(--radius-md); background:var(--accent); color:var(--accent-inverse); font-weight:600; font-size:var(--fs-16); text-decoration:none; }
    .skip-link:focus { top:10px; outline:2px solid var(--text); outline-offset:2px; }
    #mainScroll:focus { outline:none; }
    :where(button, a[href], summary, [role="button"], [tabindex]:not([tabindex="-1"])):focus-visible { outline:2px solid var(--accent); outline-offset:2px; }

    /* Round seven, board 14, on a narrow phone: the strip's tag is a label for
       the eye only (the group carries it for a screen reader), and its 72px
       were what pushed the sub-mode pill onto a second line and the More row
       under the Save bar on a 390 × 664 iPhone. */
    @media (max-width:400px) { .meta-strip > .add-row-tag { display:none; } }

    /* ── Round seven, board 23: This month reads, and splits on desktop ── */
    .plan-edit-toggle { margin:2px 0 var(--sp-2) 30px; }
    .plan-row:not(.editing) .plan-editor { display:none; }
    @media (max-width:480px) { .plan-edit-toggle { margin-left:0; } }
    @media (min-width:1100px) {
      #planSection .segmented { max-width:480px; }
      #planSection.plan-month-split { display:grid; grid-template-columns:minmax(0, 400px) minmax(0, 1fr); column-gap:28px; align-items:start; }
      #planSection.plan-month-split > .home-title, #planSection.plan-month-split > .plan-head, #planSection.plan-month-split > .segmented { grid-column:1 / -1; }
      #planSection.plan-month-split > #planStrip { grid-column:1; grid-row:3; position:sticky; top:4px; margin-bottom:var(--sp-3); }
      #planSection.plan-month-split > #planCardNote { grid-column:1; grid-row:4; }
      #planSection.plan-month-split > #planCategories { grid-column:2; grid-row:3 / span 3; min-width:0; }
      #planSection.plan-month-split > #planNetWorth, #planSection.plan-month-split > #planSplit { grid-column:1 / -1; }
      #planSection.plan-month-split .plan-bar, #planSection.plan-month-split .plan-cats, #planSection.plan-month-split .plan-note { max-width:560px; }
    }

    /* ── Round seven, board 9: Home as three areas that start on one line ──
       Multicol packed cards by column-break luck: at 1440 the left column ran
       2.5 screens while the right ended at 540px. Forced breaks put the hero
       and what needs you left, the month by type in the middle, and accounts
       and what is coming up on the right. The DOM order — and so the reading
       and Tab order — is unchanged. */
    @media (min-width:1100px) {
      #homeSection { column-count:3; column-gap:20px; }
      #homeSection > .home-head, #homeSection > #quickAddBanner, #homeSection > #syncBanner, #homeSection > #dashReview { column-span:all; }
      #homeSection > .section:has(#dashTracked) { break-before:column; }
      #homeSection > #dashComingUpSection:not([hidden]) { break-before:column; }
      #homeSection > #dashComingUpSection[hidden] + .section { break-before:column; }
    }

    /* ── Round seven, board 30: one handle per way to pay ── */
    .pm-handle { width:44px; height:44px; flex:0 0 auto; display:grid; place-items:center; border:0; background:none; color:var(--text-secondary); border-radius:var(--radius-sm); cursor:grab; touch-action:none; }
    .pm-handle:focus-visible { outline:2px solid var(--accent); outline-offset:-2px; }
    .pm-item.pm-dragging { position:relative; z-index:2; background:var(--surface); outline:1px solid var(--glass-border-dark); border-radius:var(--radius-md); }
    .pm-default-line { display:flex; align-items:center; flex-wrap:wrap; gap:6px 10px; padding:10px var(--sp-3); margin:0 0 10px; border:1px solid var(--glass-border-dark); border-radius:var(--radius-md); font-size:var(--fs-14); color:var(--text-secondary); }
    .pm-default-line b { color:var(--text); }
    .pm-default-line .plan-set { margin:0 0 0 auto; }

    /* ── Round seven, board 26: Reports on a wide screen, and its chart colours ── */
    .report-cat-row .progress-fill { background:var(--text-secondary); }
    .report-month.now .report-month-bar { background:var(--text); }
    .money-label { text-transform:none; letter-spacing:0; font-size:var(--fs-12); color:var(--text-secondary); }
    @media (min-width:1100px) {
      .money-grid { grid-template-columns:repeat(4, minmax(0, 1fr)); gap:var(--sp-3) 18px; }
      .report-cat-bar { max-width:520px; }
      .report-months { justify-content:center; gap:28px; }
      .report-month { flex:0 0 48px; }
      #reportsSection .segmented { max-width:480px; }
    }

    /* ── Round seven, board 36: first-use hints ── */
    .hint { display:flex; align-items:center; gap:var(--sp-2); margin:0 0 10px; padding:var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-3); border:1px dashed var(--glass-border-dark); border-radius:var(--radius-md); font-size:var(--fs-14); color:var(--text-secondary); background:var(--surface); }
    .hint-text { flex:1; min-width:0; line-height:1.4; }
    .hint-act { flex:0 0 auto; min-height:32px; padding:0 10px; border:1px solid var(--border); border-radius:var(--radius-pill); background:var(--surface); color:var(--text); font:inherit; font-size:var(--fs-14); font-weight:600; cursor:pointer; }
    .hint-dismiss { flex:0 0 auto; width:32px; height:32px; border:0; border-radius:50%; background:none; color:var(--text-secondary); cursor:pointer; position:relative; }
    .hint-dismiss::after { content:''; position:absolute; inset:-6px; }
    #txHint[hidden] { display:none; }
    #txHint .hint { margin-top:var(--sp-1); }

    /* Round seven, board 34: the category pill reads in sentence case; only the
       short day pill keeps capitals. */
    .lc-cat-header .lc-cat-label { text-transform:none; letter-spacing:0; }
    /* One choose-one pattern per job (board 34): the type buttons no longer
       change size at 560px. */
    @media (min-width:560px) { .type-btn { font-size:var(--fs-14); } }

    /* ── Round seven, board 34: Backup & Restore without inline styles ── */
    .bk-tabs { margin-bottom:var(--sp-3); }
    .bk-check { width:15px; height:15px; accent-color:var(--accent); }
    .bk-pointer { cursor:pointer; }
    .bk-start-hidden { display:none; }
    .bk-card { padding:14px; margin-bottom:var(--sp-3); }
    .bk-pad { padding:14px; }
    .bk-card-center { padding:14px; text-align:center; }
    .bk-mt-2 { margin-top:2px; } .bk-mt-10 { margin-top:10px; }
    .bk-mb-0 { margin-bottom:0; } .bk-mb-6 { margin-bottom:6px; } .bk-mb-8 { margin-bottom:var(--sp-2); } .bk-mb-16 { margin-bottom:var(--sp-4); }
    .bk-full { width:100%; }
    .bk-grow { flex:1; } .bk-grow-100 { flex:1; min-width:100px; } .bk-half { flex:1; margin-bottom:0; }
    .bk-picker { padding:10px var(--sp-3); font-size:var(--fs-14); }
    .bk-intro { font-size:var(--fs-14); color:var(--text-secondary); margin-bottom:10px; line-height:1.4; }
    .bk-lead { font-size:var(--fs-14); color:var(--text-secondary); margin-bottom:var(--sp-2); }
    .bk-lead-plain { font-size:var(--fs-14); color:var(--text-secondary); }
    .bk-desc { font-size:var(--fs-14); color:var(--text-secondary); margin-bottom:var(--sp-2); font-weight:500; }
    .bk-label { font-size:var(--fs-12); font-weight:600; color:var(--text-secondary); }
    .bk-note { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }
    .bk-note-after { font-size:var(--fs-14); color:var(--text-tertiary); margin-top:var(--sp-2); font-weight:500; }
    .bk-note-before { font-size:var(--fs-14); color:var(--text-tertiary); margin-bottom:var(--sp-2); font-weight:500; }
    .bk-note-end { font-size:var(--fs-14); color:var(--text-tertiary); margin-bottom:var(--sp-4); font-weight:500; }
    .bk-meter { font-size:var(--fs-14); color:var(--text-tertiary); margin-bottom:10px; font-weight:500; }
    .bk-mini { font-size:var(--fs-14); padding:3px var(--sp-2); }
    .bk-row-head { display:flex; justify-content:space-between; align-items:center; margin-bottom:6px; }
    .bk-row-foot { display:flex; justify-content:space-between; align-items:center; margin-top:6px; }
    .bk-month-list { max-height:220px; overflow-y:auto; border:1px solid var(--glass-border-dark); border-radius:var(--radius-md); padding:6px; display:flex; flex-direction:column; gap:var(--sp-1); }
    .bk-box { border:1px solid var(--glass-border-dark); border-radius:var(--radius-md); padding:var(--sp-2); display:flex; flex-direction:column; gap:2px; }
    .bk-flush-head { border-top:none; margin-top:0; padding-top:0; }
    .bk-pair { display:flex; gap:var(--sp-2); margin-bottom:var(--sp-2); }
    .bk-actions { display:flex; gap:6px; margin-bottom:var(--sp-3); }
    .bk-wrap { flex-wrap:wrap; }
    #backupModal .bk-tabs .segmented-btn { white-space:nowrap; }

    /* ── Round seven, board 34: static inline styles retired from the Add
       form, the budget sheet and the Plan, Goals, Events, Lifecycle and
       Reports templates. Named for what they set; generated once, then kept
       by hand like any other rule. ── */
    .addf-t22-w700-ter { font-size:var(--fs-20); font-weight:600; color:var(--text-tertiary); }
    .addf-x { width:150px; }
    .addf-t12-ter-p { font-size:var(--fs-14); color:var(--text-tertiary); padding:6px 0; }
    .addf-m { margin-bottom:8px; }
    .addf-x-2 { box-shadow:none; }
    .addf-bd-p-full { box-shadow:none; border:1px solid var(--glass-border-dark); padding:10px 12px; width:100%; }
    .addf-x-3 { resize:vertical; min-height:44px; box-shadow:none; }
    .addf-m-full-t12 { margin-top:6px; width:100%; font-size:var(--fs-14); }
    .addf-t11-sec-w600 { font-size:var(--fs-14); color:var(--text-secondary); font-weight:600; }
    .addf-t13-w700 { font-size:var(--fs-14); font-weight:600; }
    .addf-p-t13 { padding:10px 12px; font-size:var(--fs-14); }
    .addf-bd-m-p { border-top:none; margin-top:0; padding-top:0; }
    .addf-t11-ter-m-w500 { font-size:var(--fs-14); color:var(--text-tertiary); margin-top:2px; font-weight:500; }
    .addf-m-2 { margin-bottom:0; }
    .addf-bg-sec-t13-ptr { background:var(--bg); color:var(--text-secondary); font-size:var(--fs-14); box-shadow:var(--shadow-neu-inset); cursor:default; }
    .addf-w500-acc-t11-m { font-weight:500; color:var(--accent); font-size:var(--fs-12); margin-left:4px; }
    .addf-t11-ter-m-w500-2 { font-size:var(--fs-14); color:var(--text-tertiary); margin-top:6px; font-weight:500; }
    .bdg-x { position:relative; }
    .bdg-x-2 { width:28px; height:28px; }
    .bdg-m { margin-bottom:12px; }
    .bdg-m-p-bg-bd { margin-bottom:12px; padding:10px; background:var(--bg); border:none; box-shadow:var(--shadow-neu-inset); }
    .bdg-t11-sec-w700 { font-size:var(--fs-14); color:var(--text-secondary); font-weight:600; }
    .bdg-t12-w600 { font-size:var(--fs-14); font-weight:600; }
    .bdg-x-3 { width:22px; height:22px; }
    .bdg-t11-w600-sec { font-size:var(--fs-14); font-weight:600; color:var(--text-secondary); }
    .bdg-t11-p { font-size:var(--fs-14); padding:3px 8px; }
    .bdg-t11-ter-w500 { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }
    .bdg-full-m-dan { width:100%; margin-top:8px; color:var(--danger); }
    .bitems-ter-t12-p { color:var(--text-tertiary); font-size:var(--fs-14); padding:8px 0; }
    .bitems-m-bd { margin-bottom:8px; border:1px solid var(--glass-border-dark); border-radius:var(--radius-md); overflow:hidden; }
    .bitems-t12-w600-fx { font-size:var(--fs-14); font-weight:600; flex:1; }
    .bitems-t11-ter-bg-p { font-size:var(--fs-12); color:var(--text-tertiary); background:var(--surface); padding:1px 5px; border-radius:8px; border:1px solid var(--glass-border-dark); }
    .bitems-t11-w600-m { font-size:var(--fs-14); font-weight:600; font-variant-numeric:tabular-nums; margin-left:6px; }
    .bitems-t11-sec-bg-p { font-size:var(--fs-12); color:var(--text-secondary); background:var(--surface); padding:1px 5px; border-radius:8px; border:1px solid var(--glass-border-dark); margin-left:4px; }
    .bitems-bg-bd { overflow-x:auto; -webkit-overflow-scrolling:touch; background:var(--surface); border-radius:var(--radius-md); border:1px solid var(--glass-border-dark); }
    .bitems-fx { flex-shrink:0; }
    .bitems-x { white-space:nowrap; }
    .bitems-fx-t15-p { box-shadow:none; flex:0 0 auto; width:160px; font-size:var(--fs-16); padding:8px 10px; }
    .bitems-p-bd-bg-sec { padding:6px 10px; border-radius:var(--radius-pill); border:1px solid var(--glass-border-dark); background:var(--bg); color:var(--text-secondary); font-size:var(--fs-14); font-weight:600; cursor:pointer; white-space:nowrap; font-family:inherit; flex:0 0 auto; }
    .bitems-fx-2 { width:100px; flex:0 0 auto; }
    .bitems-p-t15-right { padding-left:26px; box-shadow:none; font-size:var(--fs-16); text-align:right; }
    .bitems-t11-ok-bg-p { font-size:var(--fs-12); color:var(--success-ink); background:var(--success-soft); padding:2px 5px; border-radius:4px; font-weight:600; flex:0 0 auto; }
    .bitems-fx-3 { width:30px; height:30px; flex:0 0 auto; }
    .goal-p { padding:32px 16px; }
    .goal-x { width:40px; height:40px; }
    .goal-t11-ok-w600 { font-size:var(--fs-14); color:var(--success-ink); font-weight:600; }
    .goal-m-ptr { margin-bottom:8px; cursor:pointer; }
    .goal-bg-ok { background:var(--success-soft); color:var(--success-ink); }
    .goal-t15-w600 { font-size:var(--fs-16); font-weight:600; }
    .goal-m { margin-bottom:6px; }
    .goal-t11-sec-w500 { font-size:var(--fs-14); color:var(--text-secondary); font-weight:500; }
    .goal-row { display:flex; justify-content:space-between; align-items:center; margin-top:4px; }
    .goal-row--tight { margin-top:0; margin-bottom:3px; }
    /* Pills wrap under a long name at 360 rather than squeezing it. */
    #goalsList .cat-title { flex-wrap:wrap; row-gap:4px; }
    .goal-modal-pills { display:inline-flex; gap:6px; margin-left:8px; vertical-align:middle; }
    /* A goal in the budget: its sentence and the actions (goal budget). */
    .goal-bud { margin-top:var(--sp-2); }
    .goal-bud-sum { margin:0 0 6px; font-size:var(--fs-14); color:var(--text-secondary); }
    .goal-bud-actions { display:flex; flex-wrap:wrap; gap:6px; }
    .goal-bud-actions .plan-set { margin:0; min-height:36px; }
    .goal-bud--editor { margin:0 0 var(--sp-3); }
    .goal-bud-note { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; align-self:center; }
    .goal-bud-actions .goal-ev-btn { min-height:44px; }
    .goal-bg-spent { background:var(--accent-soft); color:var(--accent); border-color:transparent; }
    /* Plan › Goals: the Done group of goals spent through an event. */
    .goal-done { margin-top:var(--sp-3); }
    .goal-done-head { display:flex; align-items:center; gap:8px; width:100%; min-height:44.5px; /* 44px lands on 43.9999 at some fractional offsets */ padding:8px 10px; border:none; background:var(--bg); border-radius:var(--radius-md); font:inherit; color:var(--text); cursor:pointer; text-align:left; }
    .goal-done-head:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
    .goal-done-title { font-size:var(--fs-14); font-weight:600; }
    .goal-done-sub { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; margin-left:auto; }
    .goal-done-list { margin-top:var(--sp-2); }
    /* The event card's provenance line (goal → event). */
    .plan-card-from { display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:6px; margin:4px 0 6px; font-size:var(--fs-14); color:var(--text-secondary); }
    .plan-card-from b { color:var(--text); }
    .plan-card-from .plan-set { margin:0; min-height:32px; }
    .review-funded { margin-top:4px; }
    /* Goal → event: the editor's provenance header. */
    .ev-from-goal { margin:0 0 var(--sp-3); padding:var(--sp-2) var(--sp-3); background:var(--accent-soft); border-radius:var(--radius-md); }
    .ev-from-goal[hidden] { display:none; }
    .ev-from-goal-line { margin:0; font-size:var(--fs-14); color:var(--text-secondary); display:flex; flex-wrap:wrap; align-items:center; gap:6px; }
    .ev-from-goal-line b { color:var(--text); }
    .ev-from-goal-short { font-size:var(--fs-14); color:var(--warning-ink); font-weight:600; }
    .ev-from-goal-open { margin:0; min-height:32px; }
    .ev-from-goal-choice { margin-top:6px; }
    .ev-from-goal-choice .gb-chip { min-height:44px; }
    /* A spread's dialog sits at editor level; a share's row says what it is. */
    #spreadModal { z-index:1100; }
    .bitem-spread { font-size:var(--fs-14); color:var(--text-secondary); font-weight:500; padding:0 8px 8px 8px; }
    .bitem-spread--was { color:var(--text-tertiary); }
    .bitem-dup { width:44px; height:44px; flex:0 0 auto; }
    .bitem-sort { display:inline-flex; gap:3px; padding:3px; margin:var(--sp-2) 8px; background:var(--bg); border-radius:var(--radius-md); box-shadow:var(--inset); }
    .bitem-group-head--sort { cursor:default; }
    .sd-ask { margin:0 0 var(--sp-2); }
    #confirmBody .gb-chips .plan-set { margin:0; min-height:44px; }
    .gb-hint--stop { color:var(--warning-ink); }
    /* Salary & employer: the sheet (manager level) and its editor above. */
    #salaryModal { z-index:1050; }
    #salaryEditModal { z-index:1100; }
    .sal-empty { padding:var(--sp-3) 0; }
    .sal-empty p { margin:0 0 var(--sp-3); font-size:var(--fs-14); color:var(--text-secondary); }
    .sal-sum { padding:var(--sp-3); border:1px solid var(--glass-border-dark); border-radius:var(--radius-lg); background:var(--bg); margin-bottom:var(--sp-3); }
    .sal-sum-who { font-size:var(--fs-16); font-weight:600; }
    .sal-sum-when { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; margin-top:2px; }
    .sal-sum-ctc { margin-top:var(--sp-2); font-size:var(--fs-14); color:var(--text-secondary); }
    .sal-sum-ctc b { font-size:var(--fs-20); color:var(--text); font-variant-numeric:tabular-nums; margin-right:4px; }
    .sal-sum-note { display:block; font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }
    .sal-sum-grid { display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:var(--sp-2); margin-top:var(--sp-2); }
    .sal-sum-cell { padding:8px 10px; border-radius:var(--radius-md); background:var(--surface); border:1px solid var(--glass-border); min-width:0; }
    .sal-sum-cell b { display:block; font-size:var(--fs-14); font-variant-numeric:tabular-nums; overflow-wrap:anywhere; }
    .sal-sum-cell--take { border-left:3px solid var(--accent); }
    .sal-sum-label { display:block; font-size:var(--fs-12); color:var(--text-tertiary); font-weight:600; }
    .sal-formula { margin:var(--sp-2) 0 0; font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; line-height:1.4; }
    .sal-group { margin-bottom:var(--sp-2); }
    .sal-group-head { display:flex; justify-content:space-between; align-items:baseline; gap:var(--sp-2); font-size:var(--fs-12); font-weight:600; color:var(--text-tertiary); letter-spacing:0.02em; padding:8px 0 4px; position:sticky; top:0; background:var(--surface); }
    .sal-group-head--edit { position:static; }
    .sal-group-tot { font-weight:600; font-variant-numeric:tabular-nums; white-space:nowrap; }
    .sal-row { display:flex; justify-content:space-between; align-items:baseline; gap:var(--sp-2); padding:6px 0; border-bottom:1px solid var(--glass-border); font-size:var(--fs-14); min-height:36px; }
    .sal-row-name { min-width:0; overflow-wrap:anywhere; }
    .sal-row-per { display:inline-block; margin-left:6px; font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }
    .sal-row--dup .sal-row-per { color:var(--warning-ink); }
    .sal-row-amt { text-align:right; font-variant-numeric:tabular-nums; white-space:nowrap; font-weight:600; }
    .sal-row-sub { display:block; font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }
    .sal-cmp { margin-top:var(--sp-2); }
    .sal-actions { display:flex; gap:var(--sp-2); margin:var(--sp-2) 0 var(--sp-3); }
    .sal-actions .btn { flex:1; }
    .sal-revs { margin-top:var(--sp-2); }
    .sal-rev { all:unset; display:flex; flex-direction:column; gap:2px; width:100%; box-sizing:border-box; padding:10px 12px; border:1px solid var(--glass-border-dark); border-radius:var(--radius-md); margin-bottom:6px; cursor:pointer; min-height:44px; }
    .sal-rev.on { border-color:var(--accent); }
    .sal-rev:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
    .sal-rev-who { font-size:var(--fs-14); font-weight:600; display:flex; flex-wrap:wrap; align-items:center; gap:6px; }
    .sal-rev-when { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }
    .sal-date { display:flex; align-items:center; gap:6px; }
    .sal-date .picker-trigger { flex:1; min-width:0; }
    .sal-date .plan-set { margin:0; min-width:44px; min-height:44px; justify-content:center; }
    .sal-payday { max-width:120px; }
    .sal-totals { display:flex; flex-wrap:wrap; gap:4px 12px; }
    .sal-totals b { color:var(--text); font-variant-numeric:tabular-nums; }
    .sal-head .ev-line-meta .plan-set { min-height:32px; }
    /* An offer: the reason, then the one tap that applies it. */
    .sal-offer { display:block; font-size:var(--fs-14); color:var(--text-secondary); margin:0 0 var(--sp-2); }
    .sal-offer--strip { display:inline; margin:0; }
    .sal-offer .plan-set { margin:0 0 0 6px; min-height:32px; }
    .sal-offers { margin-bottom:var(--sp-2); }
    /* The transform dialog: an editor above the goal sheet (z-index ladder). */
    #goalBudgetModal { z-index:1100; }
    .gb-chips { display:flex; flex-wrap:wrap; gap:6px; }
    .gb-chip { margin:0; min-height:36px; font-variant-numeric:tabular-nums; }
    .gb-chip.on { background:var(--accent-soft); border-color:transparent; color:var(--accent); }
    .gb-months { display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-2); }
    .gb-months-input { width:88px; text-align:center; font-variant-numeric:tabular-nums; }
    .gb-start { display:flex; align-items:center; gap:var(--sp-2); }
    .gb-start .plan-set { margin:0; min-width:44px; min-height:44px; justify-content:center; }
    .gb-start-label { font-size:var(--fs-14); min-width:84px; text-align:center; }
    .gb-preview { margin-top:var(--sp-2); }
    .gb-sum { margin:0 0 var(--sp-2); font-size:var(--fs-14); color:var(--text-secondary); }
    .gb-sum b { color:var(--text); font-variant-numeric:tabular-nums; }
    .gb-rows { border:1px solid var(--glass-border-dark); border-radius:var(--radius-md); overflow:hidden; max-height:40vh; overflow-y:auto; }
    .gb-row { display:grid; grid-template-columns:72px minmax(0,1fr) auto; gap:6px 8px; align-items:center; padding:6px 10px; border-bottom:1px solid var(--glass-border); font-size:var(--fs-14); min-height:36px; }
    .gb-row:last-child { border-bottom:0; }
    .gb-row-m { color:var(--text-secondary); font-weight:600; }
    .gb-row-what { min-width:0; }
    .gb-row-note { display:block; font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }
    .gb-row-tot { font-variant-numeric:tabular-nums; color:var(--text-secondary); white-space:nowrap; }
    .gb-row-tot b { color:var(--text); }
    .gb-row--skip { color:var(--text-tertiary); }
    .gb-row--skip .gb-row-note, .gb-row--adopt .gb-row-note { color:var(--warning-ink); }
    .gb-hint { margin:var(--sp-2) 0 0; font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }
    .lcy-p { padding:12px; }
    .lcy-bg { background:var(--danger); }
    .rsum-center-p { text-align:center; padding:32px 16px; }
    .rsum-ter-t15-w500 { color:var(--text-tertiary); font-size:var(--fs-16); font-weight:500; }
    .rsum-bg { background:var(--teal-blue); }
    .rsum-m { margin-bottom:10px; }
    .pedit-p-bd-bg-sec { padding:6px 10px; border-radius:var(--radius-pill); border:1px solid var(--glass-border-dark); background:var(--bg); color:var(--text-secondary); font-size:var(--fs-14); font-weight:600; cursor:pointer; white-space:nowrap; flex:0 0 auto; }
    .pgroup-ter-t12-p-center { color:var(--text-tertiary); font-size:var(--fs-14); padding:10px 0; text-align:center; font-weight:500; }
    .pgroup-t11-ter { font-size:var(--fs-12); color:var(--text-tertiary); width:12px; }
    .pgroup-t11-w600 { font-size:var(--fs-14); font-weight:600; font-variant-numeric:tabular-nums; }
    .evt-ok { color:var(--success-ink); }
    .evt-dan { color:var(--danger-ink); }
    .evt-bg-ok-bd { background:var(--success-soft); color:var(--success-ink); border-color:var(--success); }
    .evt-bg-acc-bd { background:var(--accent-soft); color:var(--accent); border-color:var(--accent); }

    /* ── Round seven, catalogue rows ── */
    /* The quantity field is "× 1" at rest; the amount gets the width back. */
    .qty-input:placeholder-shown:not(:focus) { width:28px; }
    .plan-card-share { font-size:var(--fs-14); color:var(--text-secondary); margin:2px 0 6px; }
    @media (min-width:1100px) { #trackSection > #trackList.lc-few { column-count:1; max-width:640px; } }
    .settings-foot { margin:6px 4px 0; font-size:var(--fs-14); color:var(--text-secondary); }
    .report-export-why { margin:6px 2px 0; font-size:var(--fs-14); color:var(--text-secondary); }
    .report-export-why[hidden] { display:none; }
    .report-export-main:disabled { opacity:0.5; cursor:not-allowed; }
    .money-in-row { flex-wrap:wrap; }
    .money-in-current { margin-left:auto; min-height:36px; padding:0 12px; border:1px solid var(--border); border-radius:var(--radius-pill); background:var(--surface); color:var(--text); font:inherit; font-size:var(--fs-14); font-weight:600; cursor:pointer; position:relative; }
    .money-in-current::after { content:''; position:absolute; inset:-4px; }
    .money-in-row:not(.open) .money-in-kinds { display:none; }
    .money-in-row.open .money-in-kinds { flex-basis:100%; }

    /* ── Round seven, catalogue: the dock steps aside while you read ── */
    @media (max-width:1099px) {
      .dock { transition:transform 220ms cubic-bezier(0.16,1,0.3,1), opacity 180ms; }
      body.dock-away .dock { transform:translate(-50%, calc(100% + 24px)); }
    }
    @media (max-width:1099px) and (prefers-reduced-motion: reduce) {
      body.dock-away .dock { transform:translateX(-50%); opacity:0; pointer-events:none; }
    }

    /* ── Event lines (the editor) ── */
    .ev-add-expenses { width:100%; }
    .ev-add-expenses[hidden], .ev-delete[hidden] { display:none; }
    .ev-delete { margin-right:auto; }
    .ev-lines { display:flex; flex-direction:column; gap:var(--sp-2); }
    .ev-line { display:grid; grid-template-columns:44px minmax(0,1fr) 108px 44px; grid-template-areas:"handle name price del" "meta meta meta meta"; align-items:center; gap:2px 6px; padding:6px 0 8px; border-bottom:1px solid var(--glass-border-dark); }
    .ev-line:last-child { border-bottom:0; }
    .ev-line.ev-line--qty { grid-template-columns:44px minmax(0,1fr) 44px; grid-template-areas:"handle name del" "meta meta meta"; }
    .ev-line-handle { grid-area:handle; width:44px; height:44px; display:grid; place-items:center; border:0; background:none; color:var(--text-secondary); border-radius:var(--radius-sm); cursor:grab; touch-action:none; }
    .ev-line-handle:focus-visible { outline:2px solid var(--accent); outline-offset:-2px; }
    .ev-line.ev-dragging { position:relative; z-index:2; background:var(--surface); outline:1px solid var(--glass-border-dark); border-radius:var(--radius-md); }
    .ev-line-name { grid-area:name; min-width:0; }
    .ev-line-price { grid-area:price; }
    .ev-line .input-wrapper input { padding-left:26px; text-align:right; font-variant-numeric:tabular-nums; }
    .ev-line-del { grid-area:del; width:44px; height:44px; border-radius:50%; border:0; background:none; color:var(--text-tertiary); display:grid; place-items:center; cursor:pointer; }
    .ev-line-del:focus-visible { outline:2px solid var(--danger); outline-offset:-2px; }
    .ev-line-meta { grid-area:meta; display:flex; flex-wrap:wrap; align-items:center; gap:4px 6px; padding-left:44px; }
    .ev-line-meta .plan-set { margin:0; min-height:32px; }
    .ev-line-meta .plan-set.on { background:var(--accent-soft); border-color:transparent; }
    .ev-line-qty { display:flex; align-items:center; gap:6px; font-size:var(--fs-14); color:var(--text-secondary); }
    .ev-line-qty input { text-align:right; font-variant-numeric:tabular-nums; }
    .ev-line-qty input[data-f="qty"] { width:56px; }
    .ev-line-qty .input-wrapper { width:118px; }
    .ev-line-qty .input-wrapper input { width:100%; }
    .ev-line-qty b { color:var(--text); font-variant-numeric:tabular-nums; white-space:nowrap; }
    .ev-line-tbd { font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }
    .ev-lines-foot { display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-2) var(--sp-3); margin-top:var(--sp-2); }
    .ev-line-add { border-style:dashed; min-height:44px; }
    .ev-lines-total { flex:1 1 160px; font-size:var(--fs-14); color:var(--text-secondary); display:flex; flex-wrap:wrap; align-items:center; gap:4px 8px; }
    .ev-lines-total b { color:var(--text); font-variant-numeric:tabular-nums; }
    .ev-lines-total .plan-set { margin:0; }
    .ev-lines-total--over b.ev-over { color:var(--danger-ink); }
    .ev-lines-total--over { border-left:2px solid var(--danger); padding-left:8px; }
    .ev-lines-dup { flex-basis:100%; font-size:var(--fs-14); color:var(--text-tertiary); }
    @media (max-width:400px) {
      .ev-line { grid-template-columns:32px minmax(0,1fr) 100px 40px; }
      .ev-line-handle { width:32px; }
      .ev-line-meta { padding-left:32px; }
    }

    /* ── Event lines on the card and in the editor ── */
    .ev-card-toggle { margin:var(--sp-2) 0 0; }
    .ev-checklist { margin-top:var(--sp-2); padding-top:4px; border-top:1px dashed var(--glass-border-dark); cursor:default; }
    .ev-line-spent { font-size:var(--fs-14); color:var(--text-secondary); font-weight:600; white-space:nowrap; }
    .ev-line-spent.over { color:var(--danger-ink); border-left:2px solid var(--danger); padding-left:5px; }

    /* ── Event lines on the Add form and in the link modal ── */
    #txEventChips[hidden], #txGoalChips[hidden] { display:none; }
    #txEventChips .add-chip .of, #txGoalChips .add-chip .of { color:var(--text-tertiary); font-weight:500; margin-left:4px; }
    #txEventChips .add-chip.on .of, #txGoalChips .add-chip.on .of { color:inherit; opacity:0.8; }
    .ev-link-line { display:flex; align-items:center; flex-wrap:wrap; gap:6px 8px; margin-bottom:var(--sp-2); font-size:var(--fs-14); color:var(--text-secondary); }
    .ev-link-line[hidden] { display:none; }
    .ev-link-line .plan-set { margin:0; }
    .ev-link-search { margin-bottom:var(--sp-2); }
    .ev-again { margin:0 0 0 6px; min-height:32px; }
    .ev-link-list { max-height:300px; overflow-y:auto; }
    .ev-link-empty { color:var(--text-tertiary); font-size:var(--fs-14); padding:12px 0; text-align:center; }
    .ev-link-row { min-height:44px; }
    .ev-link-cb { width:18px; height:18px; accent-color:var(--accent); flex-shrink:0; }
    .ev-link-main { flex:1; min-width:0; }
    .ev-link-title { display:block; font-size:var(--fs-14); font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
    .ev-link-sub { display:block; font-size:var(--fs-14); color:var(--text-tertiary); font-weight:500; }
    .ev-link-amt { font-size:var(--fs-14); font-weight:600; flex-shrink:0; font-variant-numeric:tabular-nums; }
    .ev-link-amt.goal-out { color:var(--danger-ink); }
    /* A budget item's row in the inline editor: addressed by the item's id. */
    .bitem-row { display:flex; align-items:center; gap:8px; padding:8px; width:max-content; min-width:100%; }
    .bitem-group-head { display:flex; align-items:center; gap:8px; padding:8px 10px; background:var(--bg); cursor:pointer; user-select:none; }
    .bitem-group-name { font-size:var(--fs-14); font-weight:600; flex:1; display:flex; align-items:center; gap:5px; }
    .bitem-group-rows { display:flex; flex-direction:column; gap:8px; padding:8px; }
    .bitem-group-rows[hidden] { display:none; }
    .bitem-cat { padding:6px 10px; font-size:var(--fs-14); flex:0 0 auto; white-space:nowrap; display:flex; align-items:center; gap:5px; }

    /* ── Year grid (Plan · This month, read as a year) ── */
    /* The head wraps: the toggle sits beside the title only while the title
       keeps its full width (a 360 px phone with a wide fallback font drops
       the toggle to its own row). The title still wraps at a large OS font
       scale, when it is alone on its line. */
    .plan-head { align-items:center; flex-wrap:wrap; }
    .plan-mode { margin-left:auto; }
    /* Its own class, not .segmented: tests and code that read Plan's
       four-way control by ".segmented" must not see this one. */
    .plan-mode { display:flex; flex:0 0 auto; gap:3px; padding:3px; background:var(--bg); border-radius:var(--radius-md); box-shadow:var(--inset); }
    .plan-mode-btn { min-width:64px; min-height:44px; padding:6px 10px; border:none; background:transparent; border-radius:var(--radius-sm); font:inherit; font-size:var(--fs-14); font-weight:600; color:var(--text-secondary); cursor:pointer; letter-spacing:-0.01em; }
    .plan-mode-btn.on { background:var(--surface); color:var(--text); box-shadow:var(--elev-1); }
    .plan-mode-btn:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
    .plan-mode[hidden] { display:none; }
    #planGrid[hidden] { display:none; }
    #planSection.plan-year > #planStrip, #planSection.plan-year > #planCardNote, #planSection.plan-year > #planCategories { display:none !important; }
    .yg-bar { display:flex; align-items:center; flex-wrap:wrap; gap:var(--sp-2); margin-bottom:var(--sp-3); }
    .yg-title { font-size:var(--fs-16); font-weight:600; min-width:96px; text-align:center; }
    .yg-step { width:44px; height:44px; border-radius:50%; border:1px solid var(--glass-border-dark); background:var(--surface); color:var(--text); font-size:var(--fs-16); cursor:pointer; display:grid; place-items:center; }
    .yg-step:focus-visible, .yg-quarters .plan-set:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
    .yg-bar .segmented { margin:0 0 0 auto; width:auto; }
    .yg-bar .segmented .segmented-btn { min-width:44px; padding:6px 10px; }
    .yg-quarters { display:flex; gap:6px; margin-bottom:var(--sp-2); }
    .yg-quarters .plan-set { margin:0; flex:1; justify-content:center; min-height:36px; }
    .yg-quarters .plan-set.on { background:var(--accent-soft); border-color:transparent; color:var(--accent); }
    .yg-wrap { overflow-x:auto; -webkit-overflow-scrolling:touch; border:1px solid var(--glass-border-dark); border-radius:var(--radius-lg); background:var(--surface); }
    table.yg-table { border-collapse:separate; border-spacing:0; font-size:var(--fs-12); font-variant-numeric:tabular-nums; width:max-content; min-width:100%; }
    .yg-table th, .yg-table td { padding:6px 8px; border-bottom:1px solid var(--glass-border); white-space:nowrap; text-align:right; vertical-align:middle; }
    .yg-table th { position:sticky; top:0; z-index:3; background:var(--surface); font-size:var(--fs-12); font-weight:600; color:var(--text-secondary); }
    .yg-table th:first-child, .yg-table td:first-child { position:sticky; left:0; z-index:2; text-align:left; background:var(--surface); min-width:96px; max-width:150px; overflow:hidden; text-overflow:ellipsis; box-shadow:1px 0 0 var(--glass-border); }
    .yg-table th:first-child { z-index:4; }
    .yg-table th.yg-m { min-width:72px; }
    .yg-table th.yg-m button { all:unset; display:block; width:100%; cursor:pointer; text-align:right; min-height:44px; box-sizing:border-box; padding:4px 0; }
    .yg-table th.yg-m button:focus-visible { outline:2px solid var(--accent); outline-offset:-2px; }
    .yg-table th.yg-m small { display:block; font-weight:500; color:var(--text-tertiary); }
    .yg-table th.yg-m.on { color:var(--accent); box-shadow:inset 0 -2px 0 var(--accent); }
    .yg-table th.yg-m.past { color:var(--text-tertiary); }
    .yg-table th.yg-y, .yg-table td.yg-y { min-width:84px; background:var(--bg); font-weight:600; }
    .yg-table tr.yg-type > td:first-child { font-weight:600; }
    .yg-table tr.yg-type > td { background:var(--bg); }
    .yg-table tr.yg-cat > td:first-child { padding-left:22px; font-weight:600; color:var(--text-secondary); }
    .yg-table tr.yg-item > td:first-child { padding-left:36px; color:var(--text-secondary); }
    .yg-table tr.yg-total > td { font-weight:600; border-top:2px solid var(--glass-border-dark); }
    .yg-table tr.yg-group > td { font-size:var(--fs-12); font-weight:600; color:var(--text-tertiary); text-align:left; background:var(--surface); padding-top:10px; }
    .yg-table td.on { background:var(--accent-soft); }
    .yg-toggle { all:unset; display:inline-flex; align-items:center; gap:6px; cursor:pointer; min-height:32px; width:100%; box-sizing:border-box; }
    .yg-toggle:focus-visible { outline:2px solid var(--accent); outline-offset:-2px; }
    .yg-caret { display:inline-block; width:10px; color:var(--text-tertiary); font-size:var(--fs-12); }
    /* The first column's words are capped so the column is, whatever the
       font: a table cell's max-width does not bind its column, an inline
       block's does. */
    .yg-lbl { display:inline-block; max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; vertical-align:bottom; }
    .yg-toggle .yg-lbl { min-width:0; flex:0 1 auto; }
    .yg-plan { display:block; color:var(--text); }
    .yg-act { display:block; font-size:var(--fs-12); color:var(--text-tertiary); }
    .yg-act.over { color:var(--danger-ink); border-right:2px solid var(--danger); padding-right:4px; }
    .yg-dash { color:var(--text-tertiary); }
    .yg-tag { font-size:var(--fs-12); font-weight:600; letter-spacing:0.04em; padding:0 4px; border-radius:4px; background:var(--accent-soft); color:var(--accent); margin-left:4px; }
    .yg-empty { text-align:center; color:var(--text-secondary); padding:32px var(--sp-4); }
    .yg-empty .btn { margin-top:var(--sp-3); }
    .yg-key { font-size:var(--fs-12); color:var(--text-tertiary); margin-top:var(--sp-2); }
    /* A phone reads a quarter: the sticky first column is capped and three
       month columns fit beside it inside 328 px whatever the font's width
       (120 + 3 × 66 = 318). A wider amount still widens its column. */
    @media (max-width:1099px) {
      .yg-table th:first-child, .yg-table td:first-child { max-width:120px; }
      .yg-table th.yg-m { min-width:66px; }
      .yg-table tr.yg-type .yg-toggle, .yg-table tr.yg-group .yg-lbl, .yg-table tr.yg-total .yg-lbl { max-width:104px; }
      .yg-table tr.yg-cat .yg-toggle, .yg-table tr.yg-cat .yg-lbl { max-width:90px; }
      .yg-table tr.yg-item .yg-lbl { max-width:76px; }
    }
    @media (min-width:1100px) {
      .yg-quarters { display:none; }
      .yg-table th:first-child, .yg-table td:first-child { min-width:120px; max-width:160px; }
      .yg-table .yg-toggle, .yg-table .yg-lbl { max-width:144px; }
      .yg-table tr.yg-cat .yg-toggle, .yg-table tr.yg-cat .yg-lbl { max-width:130px; }
      .yg-table tr.yg-item .yg-lbl { max-width:116px; }
      .yg-table th.yg-m { min-width:66px; }
    }

    /* ── Year grid: editing ── */
    .yg-table td.yg-edit, .yg-table td.yg-made, .yg-table td.yg-fixed { cursor:pointer; }
    .yg-table td.yg-edit:focus-visible, .yg-table td.yg-made:focus-visible, .yg-table td.yg-fixed:focus-visible, .yg-add:focus-visible { outline:2px solid var(--accent); outline-offset:-2px; }
    .yg-table td.yg-rb .yg-plan::after { content:'↻'; font-size:var(--fs-12); color:var(--text-tertiary); margin-left:3px; }
    .yg-table td.yg-fixed .yg-plan { color:var(--text-secondary); }
    .yg-table td.yg-share .yg-plan::after { content:'⋯'; font-size:var(--fs-12); color:var(--text-tertiary); margin-left:3px; }
    .yg-table td.yg-editing { padding:2px; position:relative; }
    .yg-input { width:88px; box-sizing:border-box; min-height:40px; padding:4px 6px; border:1px solid var(--accent); border-radius:var(--radius-sm); background:var(--surface); color:var(--text); font:inherit; font-size:var(--fs-input); text-align:right; font-variant-numeric:tabular-nums; outline:none; }
    .yg-input--name { text-align:left; width:140px; }
    .yg-scope { position:absolute; left:0; top:100%; z-index:5; display:flex; flex-wrap:wrap; gap:4px; padding:6px; background:var(--surface); border:1px solid var(--glass-border-dark); border-radius:var(--radius-md); box-shadow:var(--elev-2); white-space:nowrap; }
    .yg-scope .plan-set { margin:0; }
    .yg-scope-note { font-size:var(--fs-14); color:var(--text-secondary); font-weight:500; }
    .yg-add { all:unset; cursor:pointer; color:var(--accent); font-weight:600; font-size:var(--fs-12); min-height:32px; display:inline-flex; align-items:center; }
    .yg-table tr.yg-new > td { border-bottom:1px solid var(--glass-border); }
    .yg-copy { margin:0; min-height:36px; }
    .yg-table td.yg-editing { scroll-margin:80px 0 140px; }

    /* Round 8, batch 1: scrolling chip rows say there is more (D5); the Same-as
       chips carry their amount (D6); the goal editor's buttons (X5); the
       day headers (B5); the goal card's More (B9); the editors' z-index. */
    .add-quick-row { mask-image:linear-gradient(to right, #000 calc(100% - 20px), transparent); -webkit-mask-image:linear-gradient(to right, #000 calc(100% - 20px), transparent); }
    .add-chip-amt { margin-left:6px; color:var(--text-tertiary); font-weight:500; }
    .modal-z-editor { z-index:1050; }
    #historyList .tx-date-label--date, .tx-date-label--date { background:transparent; color:var(--text-tertiary); border:none; padding-left:0; letter-spacing:0.04em; font-weight:600; }
    #reportsSection .chip { min-height:36px; }
    .goal-more-btn { min-height:44px; }

    /* ── Round 8, batch 2: the first screen of each tab ── */
    /* B1 · Home hero: today under the spent line, the trend under that, no rule between. */
    #homeSection .hero-line { margin-top:10px; }
    #homeSection .hero-today { margin:4px 0 0; }
    #homeSection .hero-trend { margin-top:6px; padding-top:0; border-top:0; }
    #homeSection .hero-trend-text { display:grid; grid-template-columns:minmax(0,1fr) auto; align-items:center; gap:0 8px; }
    @media (max-width:480px) { .hero-card { padding:14px var(--sp-4) 12px; margin-bottom:10px; } }
    /* H2 · the ratio chips read as one sentence that wraps; nothing scrolls off. */
    #dashRatios { display:block; overflow:visible; white-space:normal; font-size:var(--fs-14); line-height:1.5; color:var(--text-secondary); padding:0 2px; margin:-4px 0 var(--sp-3); }
    #dashRatios .month-chip { display:inline; padding:0; border:0; background:none; font-size:var(--fs-14); font-weight:500; white-space:normal; color:var(--text-secondary); }
    #dashRatios .month-chip--good { color:var(--success-ink); font-weight:600; }
    #dashRatios .month-chip--bad { color:var(--danger-ink); font-weight:600; }
    #dashRatios .month-chip + .month-chip::before { content:' · '; color:var(--text-tertiary); font-weight:400; }
    /* B6 · Plan strip: one line of label–value pairs; the bar is the key's toggle. */
    .plan-strip { padding:12px var(--sp-4); }
    .plan-strip-grid { display:flex; flex-wrap:wrap; align-items:baseline; gap:2px 16px; }
    .plan-strip-cell { display:inline-flex; flex-wrap:wrap; align-items:baseline; gap:0 5px; border-left:0; padding-left:0; }
    .plan-strip-label { font-size:var(--fs-12); }
    .plan-strip-value { font-size:var(--fs-14); margin-top:0; }
    .plan-income-in { flex-basis:100%; width:100%; margin-top:3px; }
    .plan-stack-btn { display:block; width:100%; background:none; border:0; padding:8px 0 2px; margin:0; cursor:pointer; position:relative; font:inherit; }
    .plan-stack-btn::after { content:''; position:absolute; inset:-10px 0; }
    .plan-stack-btn:disabled { cursor:default; }
    .plan-stack-btn .plan-stack { margin-top:0; }
    .plan-stack-btn:focus-visible { outline:2px solid var(--accent); outline-offset:2px; border-radius:var(--radius-sm); }
    .plan-stack-btn[aria-expanded="true"] .plan-stack { box-shadow:0 0 0 2px var(--accent-soft); }
    .plan-key-hint { margin-left:auto; font-size:var(--fs-12); font-weight:600; color:var(--text-tertiary); }
    .plan-key-hint[hidden] { display:none; }
    /* P5 · the rebalance offer says the result and is 36px tall. */
    .plan-offer { min-height:36px; }
    /* B7 · an opened row reads; its buttons sit on one 44px line; the rollup's Set is in the editor. */
    .plan-actions { display:flex; flex-wrap:wrap; gap:var(--sp-2); margin:2px 0 var(--sp-2) 30px; }
    .plan-actions .plan-set, .plan-actions .plan-edit-toggle { min-height:44px; margin:0; padding:0 14px; }
    .plan-cats--editor { padding-left:0; margin-bottom:var(--sp-2); }
    .plan-cats--editor .plan-cat { min-height:44px; }
    .plan-cats--editor .plan-cat-set { min-height:36px; padding:0 12px; }
    @media (max-width:480px) { .plan-actions { margin-left:0; } }
    /* B8 · the item row stacks on phones: name and amount, then category · frequency · copy · remove. */
    @media (max-width:480px) {
      .bitems-bg-bd { overflow-x:visible; }
      .bitem-row { display:grid; grid-template-columns:minmax(0,1fr) auto auto 30px 100px; grid-template-areas:"name name name name amt" "cat freq flag dup del"; gap:6px 8px; width:auto; min-width:0; }
      .bitem-row .bitems-fx-t15-p { grid-area:name; width:auto; min-width:0; }
      .bitem-row .bitems-fx-2 { grid-area:amt; width:100px; }
      .bitem-row .bitem-cat { grid-area:cat; min-width:0; }
      .bitem-row .bitem-cat .bitems-x { overflow:hidden; text-overflow:ellipsis; }
      .bitem-row .pedit-p-bd-bg-sec { grid-area:freq; white-space:nowrap; }
      .bitem-row .bitems-t11-ok-bg-p { grid-area:flag; }
      .bitem-row .bitem-dup { grid-area:dup; }
      .bitem-row .bitems-fx-3 { grid-area:del; justify-self:end; }
    }
    /* C2 · Lifecycle: the stat card is one line of "word count" cells under a tighter switch. */
    .track-stat-grid { display:grid; grid-template-columns:repeat(4, minmax(0,1fr)); gap:6px; text-align:center; }
    .track-stat-cell { display:flex; align-items:baseline; justify-content:center; gap:5px; min-height:36px; padding:var(--sp-1) 2px; }
    .track-stat-count { font-size:var(--fs-16); font-weight:600; }
    .track-stat-count--ok { color:var(--success-ink); }
    .track-stat-count--bad { color:var(--danger-ink); }
    .track-stats.reordering .track-stat-cell { flex-wrap:wrap; }
    #trackViewSwitch { margin-bottom:var(--sp-2); }
    /* R2 · Reports summary: entries, per day and biggest as one line under the bar. */
    .money-foot { display:flex; flex-wrap:wrap; gap:2px 0; text-align:left; font-size:var(--fs-14); }
    .money-foot > div { display:inline; }
    .money-foot > div + div::before { content:'·'; margin:0 8px; color:var(--text-tertiary); }
    .money-foot .money-label { display:inline; }
    .money-foot .money-foot-value { display:inline; font-size:var(--fs-14); margin:0; white-space:normal; }
    /* Round 8 fixes after batch 2's suite: the money alert keeps its own line; the count chips share the next
       with their action word; 44px targets get half a pixel so a fractional offset never reads 43.99. */
    .attention-row .attention-chip--half { flex:1 1 calc(50% - 3px); min-width:0; }
    .attention-chip--half .attention-text { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0; }
    .goal-bud-actions .plan-set, .goal-more-btn { min-height:44.5px; }

    /* ── Round 8, batch 3: one control, one size ── */
    /* X2 · one segmented control: 44px, 13px labels — Plan's Budget/Events/Goals/Net worth and Month | Year,
       Reports' Summary/Categories/Monthly, Lifecycle | Delivery, the editor's Added order | End year. */
    .segmented, .plan-mode, .bitem-sort { padding:0; gap:3px; border-radius:var(--radius-md); }
    .segmented .segmented-btn, .plan-mode-btn { min-height:44px; padding:6px 10px; font-size:var(--fs-14); border-radius:var(--radius-md); }
    /* X1 · a control's visible box is never under 32px (control-floor.spec holds the ceiling at zero). */
    .info-btn { width:32px; height:32px; }
    .info-btn svg { width:14px; height:14px; }
    .tx-menu-btn { width:32px; height:32px; }
    .tx-menu-btn svg { width:18px; height:18px; }
    .del-btn, .bitems-fx-3 { width:32px; height:32px; }
    .pedit-p-bd-bg-sec { min-height:32px; }
    .report-flow-btn { min-height:32px; }
    .money-note-link { min-height:32px; display:inline-flex; align-items:center; }
    .qty-input:placeholder-shown:not(:focus) { width:32px; }
    .chip { min-height:32px; }
    .plan-stack-btn { display:flex; flex-direction:column; align-items:stretch; gap:6px; min-height:32px; padding:8px 0 0; text-align:left; color:inherit; }
    .plan-stack-btn .plan-stack { display:flex; width:100%; }
    .plan-stack-btn .plan-job-line { display:flex; align-items:center; gap:var(--sp-2); margin:0; flex-wrap:wrap; min-height:18px; }
    .plan-stack-btn .plan-job-note { display:block; }
    .plan-stack-btn .plan-job-note[hidden] { display:none; }
    @media (max-width:480px) {
      .bitem-row { grid-template-columns:minmax(0,1fr) auto auto 32px 100px; }
    }
    /* A6 · the month chip: "Sep" over "2026" in the 32px pill on phones; no truncation at 360. */
    .month-label { display:inline-flex; align-items:baseline; gap:4px; white-space:nowrap; }
    @media (max-width:480px) {
      .month-label { flex-direction:column; align-items:center; gap:0; line-height:1; }
      .month-label .mc-m { font-size:var(--fs-12); font-weight:600; }
      .month-label .mc-y { font-size:var(--fs-12); font-weight:600; color:var(--text-tertiary); }
      #monthChip { padding:2px 10px; }
    }
    /* X1 · the row's note / status icons: a 32px box around an 18px glyph. The filter bar gives back 4px so the first row keeps its place. */
    .expense-status-icon { width:32px; height:32px; padding:7px; box-sizing:border-box; }
    .filter-bar { margin-bottom:var(--sp-2); }
    /* The Duplicate button keeps its 44px box (budget-spread-dup-sort); only Remove sits at 32. */
    .bitem-dup { width:44px; height:44px; }
    @media (max-width:480px) { .bitem-row { grid-template-columns:minmax(0,1fr) auto auto 44px 100px; } }

    /* ── Round 8, batch 4: desktop is a desktop ── */
    .rail-seat { display:none; }
    #planAside[hidden], #txReadPane[hidden] { display:none; }
    .more-toggle[hidden] { display:none; }
    @media (max-width:1099px) { #planAside, #txReadPane, #txMoreToggle { display:none !important; } }
    @media (min-width:1100px) {
      /* B11 / A4 · the rail is the shell's left column from 1100px; the phone dock is gone. */
      .app { display:grid; grid-template-columns:84px minmax(0, 1fr); grid-template-rows:auto minmax(0, 1fr); }
      .app-header { grid-column:2; grid-row:1; }
      .main-scroll { grid-column:2; grid-row:2; min-height:0; padding-bottom:32px; }
      .dock, body.quick-sheet .dock, body.quick-sheet #dockNav {
        display:flex !important; position:static; transform:none; left:auto; top:auto; bottom:auto;
        grid-column:1; grid-row:1 / 3; flex-direction:column; align-items:center; justify-content:flex-start; gap:6px;
        width:84px; height:100%; border:0; border-right:1px solid var(--glass-border-dark); border-radius:0;
        background:var(--surface); box-shadow:none; padding:14px 6px calc(14px + env(safe-area-inset-bottom));
      }
      .dock-btn { width:72px; height:50px; }
      .dock-btn::after { left:-4px; right:-4px; height:50px; }
      .dock-fab { width:50px; height:50px; margin:4px 0; margin-top:4px; }
      .rail-seat {
        display:flex; position:relative; width:72px; height:50px; border-radius:var(--radius-pill); border:none; background:transparent;
        color:var(--text-secondary); flex-direction:column; align-items:center; justify-content:center; gap:1px; cursor:pointer;
        font-family:inherit; font-size:var(--fs-12); font-weight:600; letter-spacing:0.03em; transition:color var(--transition), background var(--ease-spring);
      }
      .rail-seat--foot { margin-top:auto; }
      .rail-seat.on { background:var(--accent); color:var(--accent-inverse); box-shadow:var(--shadow-soft); }
      .rail-seat:hover { color:var(--text); background:var(--bg); }
      .rail-seat:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
      #headerMenuBtn { display:none; }
      /* H5 · Home as a grid: hero, alerts and what is coming up in column one where the space is. */
      #homeSection { column-count:auto; display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:0 20px; align-content:start; grid-auto-rows:min-content; grid-auto-flow:row dense; }
      #homeSection > .home-head, #homeSection > #quickAddBanner, #homeSection > #syncBanner, #homeSection > #dashReview, #homeSection > #dashFirstRun { grid-column:1 / -1; }
      #homeSection > #dashHero, #homeSection > #dashAttention, #homeSection > #dashRatios, #homeSection > #dashChartCard, #homeSection > #dashComingUpSection { grid-column:1; break-before:auto; }
      #homeSection > .section:has(#dashTracked) { grid-column:2; grid-row:2 / span 12; break-before:auto; }
      #homeSection > .section:has(#dashAccountsWrap) { grid-column:3; grid-row:2 / span 12; break-before:auto; }
      /* P4 · the aside under the strip. */
      #planSection.plan-month-split > #planAside { grid-column:1; grid-row:5; }
      .plan-aside { padding:var(--sp-3) var(--sp-4); margin-bottom:var(--sp-3); }
      .plan-aside-title { font-size:var(--fs-12); font-weight:600; color:var(--text-tertiary); letter-spacing:0.04em; margin-bottom:var(--sp-2); }
      .plan-aside-line { margin:0; font-size:var(--fs-14); color:var(--text-secondary); line-height:1.5; }
      .plan-aside-line b { color:var(--text); }
      .plan-aside .goal-need { margin:0; }
      /* G5 · goal and event cards in two columns until an editor docks. */
      body.plan-detail #planSplit:not(:has(#planDetailPane.has-editor)) { grid-template-columns:minmax(0, 1fr) 260px; }
      body.plan-detail #planSplit:not(:has(#planDetailPane.has-editor)) #eventsList,
      body.plan-detail #planSplit:not(:has(#planDetailPane.has-editor)) #goalsList { display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:0 14px; align-items:start; }
      body.plan-detail #planSplit:not(:has(#planDetailPane.has-editor)) #goalsList > :not(.card),
      body.plan-detail #planSplit:not(:has(#planDetailPane.has-editor)) #eventsList > :not(.card) { grid-column:1 / -1; }
      /* B12 / L4 · the read pane. */
      #mainScroll.history-split.reading > #txReadPane {
        display:block; grid-column:2; grid-row:1; min-width:0;
        position:sticky; top:4px; align-self:start; padding-left:var(--sp-6); border-left:1px solid var(--glass-border-dark);
      }
      #mainScroll.history-split.reading > #addSection { display:none !important; }
      .tx-read-head { display:flex; align-items:baseline; justify-content:space-between; gap:var(--sp-3); margin-bottom:var(--sp-3); }
      .tx-read-title { font-size:var(--fs-20); font-weight:600; letter-spacing:-0.02em; min-width:0; overflow-wrap:anywhere; }
      .tx-read-amount { font-size:var(--fs-20); font-weight:600; font-variant-numeric:tabular-nums; white-space:nowrap; }
      .tx-read-body { display:flex; flex-direction:column; gap:2px; }
      .tx-read-line { display:grid; grid-template-columns:96px minmax(0, 1fr); gap:var(--sp-3); padding:8px 0; border-top:1px solid var(--glass-border); font-size:var(--fs-14); }
      .tx-read-label { color:var(--text-tertiary); font-weight:600; }
      .tx-read-value { color:var(--text); overflow-wrap:anywhere; }
      .tx-read-actions { display:flex; gap:var(--sp-2); margin-top:var(--sp-4); }
      .tx-read-actions .btn { min-height:44px; justify-content:center; }
      .tx-read-actions .tx-read-edit { flex:1; }
      /* D7 · in the pane: More folds, Save docks to the pane's bottom edge. */
      #mainScroll.history-split #txMoreToggle { display:inline-flex; align-items:center; min-height:36px; margin-bottom:var(--sp-2); padding:0 12px; border:1px solid var(--border); border-radius:var(--radius-pill); background:var(--surface); color:var(--text); font:inherit; font-size:var(--fs-14); font-weight:600; cursor:pointer; }
      #mainScroll.history-split #addSection:not(.more-open) .more-row { display:none; }
      #mainScroll.history-split #addSection .add-sticky { position:sticky; bottom:8px; background:var(--surface); border-top:1px solid var(--glass-border); padding:12px 0 4px; }
      /* S3 · two-pane Settings. */
      #settingsModal .modal-panel { max-width:980px; width:min(980px, calc(100vw - 64px)); }
      #settingsModal .settings-body { display:grid; grid-template-columns:340px minmax(0, 1fr); gap:0 24px; align-items:start; }
      #settingsPage[hidden] { display:block; }
      #settingsPage { position:sticky; top:0; min-height:320px; border-left:1px solid var(--glass-border-dark); padding-left:24px; }
      #settingsPage .settings-page-hint { color:var(--text-tertiary); font-size:var(--fs-14); font-weight:500; padding:32px var(--sp-2); text-align:center; line-height:1.5; }
      #settingsPage.has-page .settings-page-hint { display:none; }
      #settingsPage .modal-panel { position:static; transform:none; box-shadow:none; border:none; border-radius:0; background:transparent; max-width:none; width:auto; margin:0; max-height:none; }
      #settingsPage .modal-panel::before { display:none; }
      #settingsPage .modal-header { padding-top:0; }
      #settingsPage .modal-body { overflow:visible; }
      #settingsBody .settings-row.on { background:var(--accent-soft); box-shadow:inset 3px 0 0 var(--accent); }
    }
    #planSection:not(.plan-month-split) #planAside { display:none !important; }
    /* The rail is inside the frame, so the frame grows by the rail: the page keeps its 1100px (1280px at 1600). */
    @media (min-width:1100px) { .app { max-width:1184px; } }
    @media (min-width:1600px) { .app { max-width:1364px; } }

    /* ── Round 8, batch 5: the title collapses, the travel row folds ── */
    /* B2 / A2 · the large title collapses into the header after 40px (phones and tablets). */
    .header-page-title { display:none; }
    @media (max-width:1099px) {
      .home-title { transition:opacity 160ms var(--ease-out); }
      body.title-collapsed .main-scroll .home-title { opacity:0; }
      body.title-collapsed .brand-text { display:block; }
      body.title-collapsed .brand-text h1 { display:none; }
      body.title-collapsed .header-page-title { display:block; font-size:var(--fs-16); font-weight:600; letter-spacing:-0.02em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
    }
    /* B4 · the journey row waits behind the Travel by chip. */
    #travelModeSection .journey-row[hidden] { display:none; }
    /* P6 · the year hint's action reads as a link inside the hint. */
    .hint-act { border:0; background:none; padding:0 4px; font:inherit; font-size:var(--fs-14); font-weight:600; color:var(--accent); cursor:pointer; min-height:32px; }
    /* C1 · the empty state's button. */
    .lc-empty-add { min-height:36px; vertical-align:middle; }
    /* X4 · the standing Undo chip: above the dock on phones, bottom-right on desktop. */
    .undo-chip {
      position:fixed; left:50%; transform:translateX(-50%); bottom:calc(84px + env(safe-area-inset-bottom)); z-index:95;
      min-height:44px; padding:0 18px; border-radius:var(--radius-pill); border:1px solid var(--glass-border-dark);
      background:var(--surface-solid); color:var(--text); font:inherit; font-size:var(--fs-14); font-weight:600; box-shadow:var(--shadow-glass); cursor:pointer;
    }
    .undo-chip[hidden] { display:none; }
    .undo-chip:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
    @media (min-width:1100px) { .undo-chip { left:auto; right:24px; bottom:24px; transform:none; } }

    /* ── Quiet Ledger, batch A ── */
    /* Bold means one thing: titles and the hero figure. <b> and <strong> follow the three-weight rule. */
    b, strong { font-weight:600; }
    /* Every control speaks the app's face, and every field is 16px so iOS never zooms on focus
       (the Item field rendered at the browser default 13.3px). Class rules still set their own sizes. */
    input, select, textarea, button { font-family:inherit; }
    input, select, textarea { font-size:var(--fs-input); }
    /* Segment labels at 14px stay on one line ("Net worth" wrapped at 360 and made the track 46px). */
    .segmented .segmented-btn, .plan-mode-btn { white-space:nowrap; padding-inline:4px; }
    /* The stacked item row at 14px: the category keeps a readable width, the amount spans copy and remove. */
    @media (max-width:480px) {
      .bitem-row { grid-template-columns:minmax(72px,1fr) auto auto 44px 56px; grid-template-areas:"name name name amt amt" "cat freq flag dup del"; }
      .bitem-row .bitems-fx-2 { width:auto; }
    }
    /* Anything scrolled into view (keyboard focus, a tapped field, a test's scroll) stops above the
       phone dock rather than under it. */
    @media (max-width:1339px) { .main-scroll { scroll-padding-bottom:calc(96px + env(safe-area-inset-bottom)); scroll-padding-top:8px; } }

    /* ══ Quiet Ledger, batch B: surfaces, Plan, Reports ══ */
    /* One surface per group: cards lose their outline and lift; radius 16. */
    .card { border-color:transparent; border-radius:16px; box-shadow:none; }
    @media (hover:hover) { .card:hover { border-color:transparent; } }
    /* Chips are filled, not outlined: white on the page ground, ground-grey inside a surface. */
    .chip { border-color:transparent; background:var(--surface); color:var(--text); font-weight:500; }
    .card .chip, .modal .chip, .modal-panel .chip { background:var(--bg); }
    .chip.on { border-color:transparent; }
    /* Text buttons: offers, row actions and small commands read as accent words, not pills. */
    .plan-set, .plan-edit-toggle { border:0; background:none; color:var(--accent); font-weight:500; font-size:var(--fs-14); padding:0 8px; border-radius:var(--radius-sm); }
    [data-theme="dark"] .plan-set, [data-theme="dark"] .plan-edit-toggle { color:var(--accent); }
    .plan-set:hover, .plan-edit-toggle:hover { background:var(--accent-soft); }
    .plan-set.on, .plan-edit-toggle[aria-expanded="true"] { background:var(--accent-soft); }
    .plan-set:focus-visible, .plan-edit-toggle:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
    .plan-note .plan-set { min-height:36px; margin:0 0 0 -8px; }
    /* The type dot: the badge's colour on 8px; the name beside it says the type. */
    .tx-icon.type-badge.type-dot { width:8px; height:8px; min-width:8px; border-radius:50%; background:var(--tdot); padding:0; flex:0 0 8px; overflow:hidden; }
    [data-theme="dark"] .tx-icon.type-badge.type-dot { background:var(--tdot-d); }

    /* Plan · Budget: each group is one surface; a row reads name and amount at 16, detail at 14. */
    .plan-group { font-size:var(--fs-12); font-weight:500; color:var(--text-secondary); margin:24px 4px 8px; }
    .plan-group:first-child { margin-top:8px; }
    .plan-row { background:var(--surface); border-top:1px solid var(--glass-border); padding:0 16px; }
    .plan-group + .plan-row, #planCategories > .plan-row:first-child { border-top:0; border-radius:16px 16px 0 0; padding-top:4px; }
    .plan-row:has(+ .plan-group), #planCategories > .plan-row:last-child { border-radius:0 0 16px 16px; padding-bottom:4px; }
    .plan-group + .plan-row:has(+ .plan-group), .plan-group + .plan-row:last-child { border-radius:16px; }
    .plan-head { gap:12px; min-height:52px; }
    .plan-name { font-size:var(--fs-16); font-weight:500; }
    .plan-amt { font-size:var(--fs-16); font-weight:500; }
    .plan-note { font-size:var(--fs-14); font-weight:400; color:var(--text-secondary); margin:-6px 0 10px 20px; line-height:1.45; }
    .plan-note .of { color:var(--text-secondary); }
    .plan-note--over { font-weight:400; }
    .plan-bar { margin:0 0 8px 20px; }
    .plan-bar.progress-track { height:3px; }
    .plan-editor, .plan-cats, .plan-actions, .plan-edit-toggle { margin-left:20px; }
    .plan-actions { gap:4px; }
    .plan-actions .plan-set, .plan-actions .plan-edit-toggle { padding:0 8px; }
    .plan-line { font-size:var(--fs-14); }
    .plan-line-name { font-size:var(--fs-14); font-weight:500; }
    .plan-line-dup { font-size:var(--fs-14); font-weight:400; color:var(--text-secondary); }
    .plan-line-amt { font-size:var(--fs-14); font-weight:500; }
    .plan-line-amt .of, .plan-cat-amt .of { color:var(--text-secondary); font-weight:400; }
    .plan-cat { font-size:var(--fs-14); min-height:36px; }
    .plan-cat-name { color:var(--text); }
    .plan-cat-amt { font-weight:500; }
    @media (max-width:480px) { .plan-editor, .plan-cats, .plan-actions, .plan-bar, .plan-note, .plan-edit-toggle { margin-left:20px; } .plan-note { margin-top:-6px; } }
    /* The strip: three figures over their captions; the bar opens the key, which is named in words. */
    .plan-strip { padding:16px; }
    .plan-strip-grid { display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:12px; }
    .plan-strip-cell { display:flex; flex-direction:column; gap:0; }
    .plan-strip-cell .plan-strip-value { order:1; font-size:var(--fs-16); font-weight:600; margin:0; color:var(--text); }
    .plan-strip-cell .plan-strip-label { order:2; font-size:var(--fs-12); font-weight:500; color:var(--text-secondary); white-space:normal; }
    .plan-strip-cell .plan-income-in { order:3; }
    .plan-strip-cell--income .plan-strip-value, .plan-strip-cell--free .plan-strip-value { color:var(--text); }
    .plan-strip-cell--free.over .plan-strip-value { color:var(--danger-ink); }
    .plan-key-hint { font-size:var(--fs-14); font-weight:500; color:var(--accent); }
    .plan-stack-btn .plan-job-line { min-height:36px; }
    .plan-job-note { font-size:var(--fs-14); }

    /* Reports: figures at 20 in ink, a colour dot on the caption, the foot as one sentence. */
    .report-head { display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:0 12px; margin:2px 0 18px; }
    .report-head .home-title { margin:0; }
    .report-head .report-export { margin:0; gap:0; }
    .report-head .report-export-main { flex:0 0 auto; min-height:44px; background:none; border:0; box-shadow:none; color:var(--accent); font-size:var(--fs-14); font-weight:500; padding:0 8px; gap:6px; }
    .report-head .report-export-main:disabled { color:var(--text-secondary); opacity:1; }
    .report-head .report-export-menu { width:44px; height:44px; border:0; background:none; color:var(--accent); }
    .report-head .report-export-why { flex-basis:100%; margin:0 0 8px; }
    .money-card { padding:16px; }
    .money-grid { gap:16px 12px; }
    .money-cell { border-left:0; padding-left:0; display:grid; gap:2px; }
    .money-label { font-size:var(--fs-12); font-weight:500; color:var(--text-secondary); display:flex; align-items:center; gap:6px; }
    .money-dot { display:inline-block; width:8px; height:8px; border-radius:50%; flex:0 0 8px; }
    .money-value { font-size:var(--fs-20); font-weight:600; letter-spacing:-0.01em; margin:0; color:var(--text); }
    .money-sub { font-size:var(--fs-14); font-weight:400; color:var(--text-secondary); margin:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
    .money-stack { height:6px; box-shadow:none; margin-top:16px; }
    .money-legend { font-size:var(--fs-12); color:var(--text-secondary); gap:4px 14px; margin-top:8px; }
    .money-legend i { width:8px; height:8px; margin-right:6px; }
    .money-foot { display:block; text-align:left; font-size:var(--fs-14); color:var(--text-secondary); border-top:1px solid var(--glass-border); margin-top:12px; padding-top:12px; }
    .money-foot > div { display:inline; }
    .money-foot > div + div::before { content:', '; margin:0; color:inherit; }
    .money-foot > div:last-child::after { content:'.'; }
    .money-foot .money-foot-value { font-size:var(--fs-14); font-weight:500; color:var(--text); }
    .report-cat-row { display:grid; grid-template-columns:minmax(0, 1fr) auto; grid-template-areas:"name amt" "pct pct" "bar bar"; gap:0 12px; padding:10px 0; border-top:1px solid var(--glass-border); }
    .report-cat-row:first-of-type { border-top:0; }
    .report-cat-row--count { grid-template-areas:"name amt" "pct count" "bar bar"; }
    .report-cat-name { grid-area:name; width:auto; font-size:var(--fs-16); font-weight:500; }
    .report-cat-amt { grid-area:amt; width:auto; font-size:var(--fs-16); font-weight:500; align-self:center; }
    .report-cat-pct { grid-area:pct; width:auto; text-align:left; font-size:var(--fs-14); color:var(--text-secondary); }
    .report-cat-count { grid-area:count; justify-self:end; font-size:var(--fs-14); color:var(--text-secondary); }
    .report-cat-count::after { content:' entries'; }
    .report-cat-bar { grid-area:bar; margin-top:6px; max-width:none; }
    .report-cat-bar .progress-track { height:3px; }

    /* ══ Quiet Ledger, batch C: History and Add ══ */
    /* History head: title and Select on one line, the month's total under the title. */
    .history-head { display:grid; grid-template-columns:minmax(0,1fr) auto; grid-template-areas:"title select" "sum sum"; align-items:center; gap:2px 12px; margin:2px 0 12px; }
    .history-head .home-title { grid-area:title; }
    .history-head .history-month-summary { grid-area:sum; text-align:left; justify-self:start; }
    .history-head .history-select { grid-area:select; border:0; background:none; color:var(--accent); font-weight:500; min-height:44px; padding:0 8px; margin-right:-8px; }
    .history-head .history-select[aria-pressed="true"] { background:var(--accent-soft); color:var(--accent); }
    /* Search is a field you can see; the filters are filled chips under it. */
    @media (max-width:1099px) {
      .hfilter-row { flex-wrap:wrap; gap:8px; }
      .hsearch { flex:1 1 100%; }
      .hsearch-btn { display:none; }
      .hsearch-input, .hsearch.open .hsearch-input, .hsearch-input:not(:placeholder-shown) { width:100%; opacity:1; height:44px; margin:0; padding:0 12px; border:1px solid transparent; border-radius:var(--radius-sm); background:var(--surface); }
      .hsearch-input:focus { border-color:var(--text-secondary); }
      .hfilter-bar { flex:1 1 100%; }
    }
    .hfilter-dd { border-color:transparent; }
    .hfilter-dd.on { border-color:transparent; }
    /* Day headers: a quiet caption with the day's total; each day is one surface. */
    .tx-date-header .tx-date-label, #historyList .tx-date-label, #historyList .tx-date-label--date, .tx-date-label--date {
      background:none; color:var(--text-secondary); border:0; padding:0; text-transform:none; letter-spacing:0; font-size:var(--fs-12); font-weight:500; border-radius:0;
    }
    #historyList.card { background:transparent; padding:0 !important; overflow:visible; }
    #historyList .tx-date-header { margin:20px 4px 8px; background:var(--bg); }
    #historyList .tx-date-header:first-child { margin-top:4px; }
    #historyList .tx-history-row { background:var(--surface); padding:12px 16px !important; border-radius:0; border-bottom:0; border-top:1px solid var(--glass-border); gap:12px; align-items:center; }
    #historyList .tx-date-header + .tx-history-row, #historyList > .tx-history-row:first-child { border-top:0; border-radius:16px 16px 0 0; }
    #historyList .tx-history-row:has(+ .tx-date-header), #historyList .tx-history-row:last-child { border-radius:0 0 16px 16px; }
    #historyList .tx-date-header + .tx-history-row:has(+ .tx-date-header), #historyList .tx-date-header + .tx-history-row:last-child { border-radius:16px; }
    #historyList .tx-history-row .tx-title { font-weight:500; }
    #historyList .tx-history-row .tx-meta { color:var(--text-secondary); font-weight:400; }
    #historyList .tx-history-row .tx-amount { font-weight:500; }
    .tx-amount.income { color:var(--success-ink); }
    #historyList .tx-history-row > .tx-swipe-body { gap:12px; align-items:center; }
    #historyList .tx-history-row .tx-swipe-body > .type-dot { align-self:center; }

    /* Add: the typed amount is the one figure at 40, on an underline, not in a box. */
    .add-hero { background:none; border:0; box-shadow:none; padding:4px 0 8px; text-align:left; }
    .add-hero-label { font-size:var(--fs-12); font-weight:500; }
    .add-hero-input { font-size:var(--fs-figure); line-height:1.1; text-align:left; border-bottom:2px solid var(--accent); }
    /* Each chip row's name sits above it, so the chips get the whole width. */
    .add-quick-row { display:grid; grid-auto-flow:column; grid-auto-columns:max-content; grid-template-rows:auto auto; column-gap:8px; row-gap:6px; margin-bottom:12px; align-items:center; }
    .add-quick-row > .add-row-tag { grid-row:1; grid-column:1; width:0; overflow:visible; white-space:nowrap; position:sticky; left:0; font-size:var(--fs-12); font-weight:500; color:var(--text-secondary); height:auto; }
    .add-quick-row > :not(.add-row-tag) { grid-row:2; }
    .add-quick-row > .add-row-tag:only-child { grid-row:1; }
    .add-chip { border-color:transparent; background:var(--bg); color:var(--text); min-height:36px; }
    .add-chip.on { border-color:transparent; }
    .add-chip--all { border:1px dashed var(--glass-border-dark); }
    /* When · how: a caption above three 48px pickers at 16px. */
    .meta-strip { display:flex; flex-wrap:wrap; gap:6px 8px; }
    .meta-strip > .add-row-tag { flex:0 0 100%; font-size:var(--fs-12); font-weight:500; color:var(--text-secondary); height:auto; }
    .meta-strip > .meta-pill { flex:1 1 auto; min-width:min-content; text-overflow:clip; }
    .meta-pill { height:48px; border-radius:var(--radius-sm); border-color:transparent; font-size:var(--fs-16); font-weight:500; min-width:0; overflow:hidden; }
    /* The plan line is a sentence, not a box. */
    .tx-plan-line { border:0; background:none; padding:4px 0; font-size:var(--fs-14); font-weight:400; }
    .tx-default-hint { color:var(--text-secondary); font-weight:400; }
    .tx-default-act { text-decoration:none; font-weight:500; padding:0 8px; }
    /* Save is a docked bar; Clear is a word. */
    .add-sticky { background:var(--surface); border-top:1px solid var(--glass-border); padding:12px 16px calc(12px + env(safe-area-inset-bottom)); }
    .add-sticky .btn { height:52px; border-radius:14px; }
    .add-sticky .btn-clear { flex:0 0 auto; border:0; background:none; box-shadow:none; color:var(--accent); font-weight:500; padding:0 12px; }
    body.quick-sheet #addSection .add-sticky { position:sticky; bottom:0; padding:12px 0 calc(12px + env(safe-area-inset-bottom)); margin-top:8px; }
    /* Desktop History keeps its table density (table-rows.spec): 5px rows, 12px sides. */
    @media (min-width:1100px) { #historyList .tx-history-row { padding:5px 12px !important; } }

    /* ══ Quiet Ledger, batch D: header, Home, dock ══ */
    /* Header: text buttons at 14; the month reads "Sep 2026" on one line. */
    #profileChip, #monthChip { background:none; border-color:transparent; font-size:var(--fs-14); font-weight:500; color:var(--text); padding:6px 8px; }
    @media (max-width:480px) {
      .month-label { flex-direction:row; align-items:baseline; gap:4px; line-height:inherit; }
      .month-label .mc-m, .month-label .mc-y { font-size:var(--fs-14); font-weight:500; color:var(--text); }
      #monthChip { padding:6px 8px; }
      .header-controls .chip { font-size:var(--fs-14) !important; }
    }
    /* Title row: Reports is a text button beside the page title. */
    .home-head { align-items:center; }
    .home-go { background:none; border-color:transparent; color:var(--accent); font-weight:500; min-height:44px; padding:0 8px; margin:0 -8px 0 0; }
    .home-go svg { display:none; }
    /* Hero: what is left is the 28px figure; the percentage, spent-of and today follow at 14. */
    #dashHero { display:grid; grid-template-columns:minmax(0, 1fr) auto; column-gap:12px; row-gap:8px; align-items:baseline; padding:16px; }
    #dashHero > .progress-header, #dashHero > .hero-line { display:contents; }
    #dashHero .progress-label { grid-column:1 / -1; grid-row:1; font-size:var(--fs-12); font-weight:500; margin:0; }
    #dashHero .hero-left { grid-column:1; grid-row:2; border:0; padding:0; font-size:var(--fs-28); font-weight:600; letter-spacing:-0.02em; line-height:1.2; color:var(--text); white-space:nowrap; }
    #dashHero .hero-left.danger { color:var(--danger-ink); }
    #dashHero .progress-value { grid-column:2; grid-row:2; font-size:var(--fs-14); font-weight:400; color:var(--text-secondary); letter-spacing:0; line-height:1.4; }
    #dashHero > .progress-track { grid-column:1 / -1; grid-row:3; height:6px; margin:0; }
    #dashHero .hero-spent { grid-column:1 / -1; grid-row:4; font-size:var(--fs-14); color:var(--text-secondary); }
    #dashHero .hero-spent b { font-weight:400; color:var(--text-secondary); }
    #dashHero .hero-of { color:var(--text-secondary); }
    #dashHero > .hero-today { grid-column:1 / -1; grid-row:5; display:flex; justify-content:space-between; gap:12px; margin:0; padding-top:8px; border-top:1px solid var(--glass-border); font-size:var(--fs-14); color:var(--text-secondary); }
    #dashHero > .hero-today:empty { display:none; }
    #dashHero .hero-today .kv-v, #dashHero .hero-today b { color:var(--text); font-weight:500; }
    #dashHero > .hero-payday { grid-column:1 / -1; grid-row:6; margin:0; }
    #dashHero > .hero-trend { grid-column:1 / -1; grid-row:7; margin:0; padding:0; border:0; }
    #homeSection .hero-trend-text { grid-template-columns:minmax(0, 1fr) auto; }
    .hero-trend-value, .hero-trend-value .hero-trend-label { font-size:var(--fs-14); font-weight:400; color:var(--text-secondary); }
    .hero-trend-link { background:none; border-color:transparent; color:var(--accent); font-weight:500; min-height:44px; padding:0 8px; margin-right:-8px; }
    /* Sections: spacing, not rules, between them; titles at 20. */
    .section { border-top:0; padding:24px 0 8px; }
    .cat-title { font-size:var(--fs-20); font-weight:600; }
    .cat-header { margin-bottom:12px; }
    #dashRatios, #dashRatios .month-chip { font-size:var(--fs-14); }

    /* The phone dock: a flat bar along the bottom edge, labels at 12, the seat you are on filled behind its icon. */
    @media (max-width:1099px) {
      .dock { left:0; right:0; bottom:0; transform:none; border-radius:0; border:0; border-top:1px solid var(--glass-border); box-shadow:none; justify-content:space-around; align-items:center; padding:6px 8px calc(8px + env(safe-area-inset-bottom)); gap:0; }
      .dock-btn { flex:1 1 0; width:auto; height:52px; background:none; color:var(--text-secondary); font-size:var(--fs-12); font-weight:500; letter-spacing:0; gap:2px; border-radius:var(--radius-sm); }
      .dock-btn .dock-icon { width:52px; height:30px; border-radius:15px; }
      .dock-btn.on { background:none; color:var(--text); box-shadow:none; }
      .dock-btn.on .dock-icon { background:var(--bg); transform:none; animation:none; }
      .dock-fab { width:52px; height:52px; border-radius:16px; margin:0 4px; margin-top:0; box-shadow:none; }
      .add-sticky { bottom:calc(66px + env(safe-area-inset-bottom)); }
    }
    /* Text buttons change colour with the theme at once: a colour fade left "Reports" in the light accent on black for a frame. */
    .home-go, .hero-trend-link, .history-select, .plan-set, .plan-edit-toggle { transition:none; }
    /* History rows on phones: amount and the ··· menu share the first line, so a row is one title line and one meta line. */
    @media (max-width:1099px) {
      #historyList .tx-history-row .tx-side { flex-direction:row-reverse; align-items:center; gap:0; align-self:center; }
      #historyList .tx-history-row .tx-menu-btn { margin-right:-8px; }
    }
    /* Home's type rows keep their round 8 form (owner's choice); when the change and fixed-share pills wrap
       under the name, the amount stays on the name's line. */
    #dashTracked .tracked-head { align-items:flex-start; }
    #dashTracked .tracked-amt { padding-top:2px; }
    /* The Reports sentence: items sit flush so each comma follows its word, not a space. */
    .money-foot { display:flex; flex-wrap:wrap; }
    .money-foot > div { display:block; white-space:pre-wrap; }
    .money-foot > div + div::before { content:',\00a0'; }
    /* Date, way to pay and sub-mode fit one line at 360: 8px sides and a 6px gap, so the More chips stay above Save. */
    .meta-strip { column-gap:6px; }
    .meta-strip > .meta-pill { padding:0 8px; }
    .add-quick-row { margin-bottom:10px; }
    /* Short phones (under 700px tall, an iPhone 13 at 390×664): each chip row's name returns to the row's left
       and the "Amount" caption hides, so a fresh form keeps Save and the More chips on the first screen. */
    @media (max-height:700px) and (max-width:1099px) {
      .add-quick-row { display:flex; grid-template-rows:none; align-items:center; margin-bottom:8px; }
      .add-quick-row > .add-row-tag { position:static; width:auto; flex:0 0 auto; min-width:58px; }
      .add-hero-label { position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; }
      .add-hero { padding:0 0 4px; }
    }
