      /* DM Sans (variable, 300–700) and DM Serif Display, self-hosted from
         /fonts/. Two woff2 files per family: the latin subset covers German
         (incl. ä/ö/ü/ß and €); latin-ext adds Polish / Czech / Turkish glyphs
         so transaction descriptions don't drop into the system font for
         non-German names. font-display: swap keeps text visible while the
         file loads, even though both files are precached by the service
         worker for offline use. */
      @font-face {
        font-family: 'DM Sans';
        font-style: normal;
        font-weight: 300 700;
        font-display: swap;
        src: url('/fonts/dm-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: 'DM Sans';
        font-style: normal;
        font-weight: 300 700;
        font-display: swap;
        src: url('/fonts/dm-sans-latin-ext.woff2') format('woff2');
        unicode-range:
          U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
          U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
          U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
      }
      @font-face {
        font-family: 'DM Serif Display';
        font-style: normal;
        font-weight: 400;
        font-display: swap;
        src: url('/fonts/dm-serif-display-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: 'DM Serif Display';
        font-style: normal;
        font-weight: 400;
        font-display: swap;
        src: url('/fonts/dm-serif-display-latin-ext.woff2') format('woff2');
        unicode-range:
          U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
          U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
          U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
      }

      :root {
        /* Grouped page background (Apple systemGroupedBackground): the flat
           canvas behind the cards. A touch darker than --bg-canvas so cards
           read as elevated surfaces, like iOS grouped lists. */
        --bg-grouped: #f2f2f7;
        /* Card / elevated surface — pure white, so cards lift cleanly off the
           cool grouped canvas (Apple secondarySystemGroupedBackground). */
        --bg-canvas: #ffffff;

        /* Glass materials — light (white-based to match the neutral canvas) */
        --glass-thin: rgba(255, 255, 255, 0.45);
        --glass-chrome: rgba(255, 255, 255, 0.92);
        /* Header material — a translucent tint of the grouped canvas so the
           sticky header blends into the page (separated only by a hairline, no
           drop shadow) instead of reading as a floating bar. Resolves per
           theme via --bg-grouped; falls back to opaque in the no-backdrop /
           reduced-transparency blocks below. */
        --glass-header: color-mix(in srgb, var(--bg-grouped) 82%, transparent);

        /* Glass borders & highlights — g300-based */
        --hairline: rgba(209, 207, 197, 0.9);
        --hairline-soft: rgba(209, 207, 197, 0.55);
        --edge-dark: rgba(20, 20, 19, 0.07);

        /* Shadows */
        --shadow-soft:
          inset 0 0.5px 0 rgba(255, 255, 255, 0.85), inset 0 -0.5px 0 rgba(20, 20, 19, 0.05),
          0 1px 2px rgba(20, 20, 19, 0.04), 0 6px 24px -8px rgba(20, 20, 19, 0.12);
        --shadow-elevated:
          inset 0 0.5px 0 rgba(255, 255, 255, 0.95), inset 0 -0.5px 0 rgba(20, 20, 19, 0.06),
          0 2px 6px rgba(20, 20, 19, 0.06), 0 18px 60px -12px rgba(20, 20, 19, 0.22);
        --shadow-floating:
          inset 0 1px 0 rgba(255, 255, 255, 0.9), 0 4px 16px rgba(20, 20, 19, 0.08),
          0 28px 80px -16px rgba(20, 20, 19, 0.28);

        /* Text — slate scale from html-effectiveness */
        --text: #141413;
        --text2: #3d3d3a;
        --text3: #87867f;

        /* Accents — clay & olive from html-effectiveness */
        --accent: #d97757;
        --accent-2: #c4694a;
        --accent-tint: rgba(217, 119, 87, 0.15);
        --green: #788c5d;
        --green-2: #96a87a;
        --red: #c0392b;
        --red-2: #ec6b5b;
        --blue: #2a78d8;

        /* Foreground color for text/icons on filled accent/green/red surfaces. */
        --on-accent: #ffffff;

        /* Subtle tinted surface for pills/chips inside opaque cards.
       Auto-adapts to light/dark via --text. */
        --surface-tint: color-mix(in oklab, var(--text) 6%, transparent);

        /* Radii (concentric, generous) */
        --r-xl: 28px;
        --r-lg: 22px;
        --r-md: 16px;
        --r-sm: 12px;
        --r-xs: 8px;
        --r-pill: 999px;


        /* Fonts */
        --font-display: 'DM Serif Display', serif;
        --font-body: 'DM Sans', sans-serif;

        /* Type scale — DESIGN_CONVENTIONS.md §Typografie.
       Change a value here once and the whole app follows. */
        --fs-display: 2.25rem; /* 36px – Saldo / Hero */
        --fs-title: 1.5rem; /* 24px – Modal-/Screen-Titel */
        --fs-title-sm: 1.25rem; /* 20px – kompakter Titel (Panel-Header, Confirm) */
        --fs-headline: 1.125rem; /* 18px – Card-Überschrift */
        --fs-body: 1rem; /* 16px – Fließtext, Form-Inputs */
        --fs-callout: 0.9375rem; /* 15px – Buttons, sekundäre Labels */
        --fs-footnote: 0.875rem; /* 14px – sekundärer Body */
        --fs-caption: 0.8125rem; /* 13px – Meta, Hinweise */
        --fs-micro: 0.75rem; /* 12px – kleinste Marker, Tag-Pills */

        /* Icon-Skala für Emoji-/Picto-Glyphen außerhalb der Chrome-Buttons —
       Listen-Reihen, FAB-Inhalt, Empty-State-Hero. */
        --fs-icon-sm: 1.0625rem; /* 17px – Listen-Glyph (cat-icon) */
        --fs-icon-md: 1.375rem; /* 22px – Section-Glyph (cat-view-icon, fab.search-exit) */
        --fs-icon-lg: 1.625rem; /* 26px – FAB-Plus */
        --fs-icon-xl: 3.25rem; /* 52px – Empty-State-Hero */

        /* Button tokens — chrome icons share a single source of truth.
       FAB and chrome buttons can be re-sized centrally here. */
        --btn-chrome-size: 44px; /* Hamburger / Modal-Back / Drawer-Close */
        --btn-fab-size: 50px; /* FAB + Search-Bar Höhe */
        --btn-icon-size: 1.25rem; /* Glyph in Chrome-Buttons (‹ ✕ ⌕ …) */

        /* Element-specific sizes that are visual constants outside the
       spacing scale. Each one is a single design decision. */
        --icon-list-md: 42px; /* .t-icon / .cat-view-icon (list-row icon container) */
        --icon-list-sm: 38px; /* .cat-icon (category-breakdown icon) */
        --swipe-action-w: 92px; /* .tx-action reveal width on swipe-to-delete */
        --cat-bar-h: 5px; /* .cat-bar progress-bar height */
        --bottom-bar-clearance: 66px; /* space content panels reserve under the floating bottom bar */

        /* Adaptive layout — tablet/desktop shell. The breakpoints themselves
           must be literal px in @media queries (CSS limitation), so the
           single source of truth lives in the comment below; if they ever
           change, search-and-replace `768px` / `1024px` across this file
           AND the matchMedia() calls in app.js.
           Breakpoints: 768px (tablet, sidebar appears) — 1024px (desktop,
           wider content + larger charts). */
        --app-sidebar-width: 260px;

        /* Layering — semantic z-index tiers. Intra-component stacks
       (cards, transactions, modals' inner gradient) keep literal 1/2. */
        --z-toolbar: 100; /* Header */
        --z-floating: 200; /* Bottom-Bar (Search + FAB) */
        --z-drawer-backdrop: 400; /* Drawer-Overlay (Dimmer) */
        --z-drawer: 401; /* Drawer-Panel über seinem Backdrop */
        --z-modal: 500; /* Modal-Overlay + Inhalt */
        --z-toast: 800; /* Toasts / System-Meldungen */

        /* Motion durations — common timings only. Odd values (0.22, 0.28,
       0.35, 0.45 …) bleiben literal, weil sie zu spezifischen
       Animationen gehören. */
        --dur-fast: 0.15s;
        --dur-base: 0.2s;
        --dur-medium: 0.25s;
        --dur-slow: 0.3s;
        --dur-progress: 0.7s; /* .cat-bar width fill */
        --dur-pulse: 1.2s; /* .sync-dot syncing animation */

        /* Focus ring — gleiches Aussehen für alle fokussierten Inputs/Buttons. */
        --focus-ring: 0 0 0 3px var(--accent-tint);

        /* Border shortcuts — 0.5px Hairlines sind Standard, 1px nur für
       destruktive Akzent-Outlines. Farbe weiter über --hairline*. */
        --border-hairline: 0.5px solid var(--hairline-soft);
        --border-hairline-strong: 0.5px solid var(--hairline);

        /* Spacing scale — Zahl im Namen = px-Wert. 4-px-Raster plus 10 / 14
       als gängige iOS-Zwischenstufen und 2 / 56 für Sonderfälle
       (.tag-pill negative, .empty-state Padding). Halbschritte wurden
       in Phase 3 auf das Raster zusammengezogen. */
        --space-2: 2px;
        --space-4: 4px;
        --space-8: 8px;
        --space-10: 10px;
        --space-12: 12px;
        --space-14: 14px;
        --space-16: 16px;
        --space-20: 20px;
        --space-24: 24px;
        --space-56: 56px;
        --nav-icon-size: 30px;

        /* Motion */
        --ease-spring: cubic-bezier(0.32, 0.72, 0, 1);
        --ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
        --ease-soft: cubic-bezier(0.4, 0, 0.2, 1);

        /* Glass blur */
        --blur-dim: blur(8px) saturate(140%); /* Dimmer overlays (drawer/modal backdrop) */
        --blur-regular: blur(28px) saturate(180%);
        --blur-thick: blur(40px) saturate(200%);
        --blur-overlay: blur(4px); /* Weak blur for the drawer scrim — see .drawer-overlay */

        /* Overlay scrims — modal/drawer backdrops on top of content. Dark
           enough to dim, soft enough to keep underlying content recognisable. */
        --overlay-bg: rgba(20, 14, 8, 0.35);
        /* Themed shadows used outside of the generic --shadow-* set. */
        --shadow-floating-strip:
          inset 0 0.5px 0 rgba(255, 255, 255, 0.65),
          0 2px 8px rgba(20, 20, 19, 0.06),
          0 8px 24px -4px rgba(20, 20, 19, 0.1);

        /* Liquid Glass materials — Tier 1 (modal + drawer) + Tier 2 (nav cards).
           All three are color-mix() expressions derived from existing surface
           tokens, so they auto-adapt to dark mode when --bg-grouped /
           --bg-canvas are overridden in html[data-dark='true']. */
        --glass-modal: color-mix(in srgb, var(--bg-grouped) 88%, transparent);
        --glass-drawer: color-mix(in srgb, var(--bg-grouped) 85%, transparent);
        --glass-card: color-mix(in srgb, var(--bg-canvas) 90%, transparent);
      }

      /* ============================================================
         DARK THEME — single source of truth.
         The inline <head> script computes data-dark from system pref
         + manual override and sets it on <html>. All dark theming
         (tokens, glass fallbacks) lives in
         html[data-dark='true'] selectors. Light values stay in
         :root above and are the default when data-dark='false'.
         ============================================================ */
      html[data-dark='true'] {
        color-scheme: dark;
        /* Grouped model in dark: the page keeps the familiar warm near-black,
           cards sit a step lighter so they lift off the canvas (mirrors the
           light-mode grouped look, iOS-style). */
        --bg-grouped: #0f0e0c;
        --bg-canvas: #221e19;

        --glass-thin: rgba(38, 35, 30, 0.45);
        --glass-chrome: rgba(22, 20, 17, 0.88);

        --hairline: rgba(209, 207, 197, 0.14);
        --hairline-soft: rgba(209, 207, 197, 0.07);
        --edge-dark: rgba(0, 0, 0, 0.4);

        --shadow-soft:
          inset 0 0.5px 0 rgba(209, 207, 197, 0.12), inset 0 -0.5px 0 rgba(0, 0, 0, 0.4),
          0 1px 2px rgba(0, 0, 0, 0.5), 0 6px 24px -8px rgba(0, 0, 0, 0.6);
        --shadow-elevated:
          inset 0 0.5px 0 rgba(209, 207, 197, 0.16), inset 0 -0.5px 0 rgba(0, 0, 0, 0.5),
          0 2px 6px rgba(0, 0, 0, 0.4), 0 18px 60px -12px rgba(0, 0, 0, 0.7);
        --shadow-floating:
          inset 0 1px 0 rgba(209, 207, 197, 0.18), 0 4px 16px rgba(0, 0, 0, 0.5),
          0 28px 80px -16px rgba(0, 0, 0, 0.85);

        /* Text — inverted slate scale */
        --text: #f0eee6;
        --text2: #b0ada6;
        --text3: #87867f;

        /* Accents — lighter clay & olive for dark backgrounds */
        --accent: #e8926e;
        --accent-2: #f0aa88;
        --accent-tint: rgba(232, 146, 110, 0.2);
        --green: #9ab07a;
        --green-2: #b3c895;

        /* Darker specular for dark mode — white at 65% reads as a harsh
           bright edge on near-black glass; 25% keeps the depth cue without glare. */
        --shadow-floating-strip:
          inset 0 0.5px 0 rgba(255, 255, 255, 0.25),
          0 2px 8px rgba(0, 0, 0, 0.4),
          0 8px 24px -4px rgba(0, 0, 0, 0.5);
      }

      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
        -webkit-tap-highlight-color: transparent;
      }

      html {
        background: var(--bg-grouped);
        color-scheme: light dark;
        /* Horizontal-Clip absichtlich hier, nicht auf body: sonst wird body
           zum Scroll-Container und `position: sticky` auf .header pinnt an
           den (mitscrollenden) Body-Anfang statt an den Viewport-Anfang. */
        overflow-x: hidden;
        /* Rubber-Band-Overscroll am Root unterdrücken — iOS würde sonst beim
           Swipe-Down am Listen-Anfang den gesamten Compositor-Layer mit nach
           unten ziehen, inklusive des Sticky-Headers. Safari ≥ 16 respektiert
           overscroll-behavior auf der Root, was PocketLog ohnehin voraussetzt. */
        overscroll-behavior-y: none;
      }

      body {
        font-family: var(--font-body);
        color: var(--text);
        min-height: 100dvh;
        max-width: 430px;
        margin: 0 auto;
        position: relative;
        background: transparent;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
      }

      /* Flat grouped canvas — no ambient gradient or drifting orb. The page is
         a single calm tone (--bg-grouped) and the cards provide the only
         layering, Apple-grouped-list style. */

      /* Dark mode: category palette is tuned for light backgrounds, so
         glyph contrast collapses on the dark canvas (a dark brown / forest
         icon on near-black looks black). Override the icon color to
         --text (same hue as the note next to it) so the glyph reads
         clearly; the cat-color stays as the background tint, keeping
         categories visually distinguishable. */
      html[data-dark='true'] .t-icon,
      html[data-dark='true'] .cat-view-icon,
      html[data-dark='true'] .cat-icon {
        color: var(--text);
      }

      body > *,
      .app-shell > * {
        position: relative;
        z-index: 1;
      }

      /* Tablet/desktop turns this into the grid stage; on mobile it stays
         transparent so the existing body-level layout is unchanged. */
      .app-shell {
        display: contents;
      }

      /* Visually hidden — for screen-reader-only labels */
      .visually-hidden {
        position: absolute;
        width: 1px;
        height: 1px;
        padding: 0;
        margin: -1px;
        overflow: hidden;
        clip: rect(0, 0, 0, 0);
        white-space: nowrap;
        border: 0;
      }

      /* ====== HEADER ====== */
      .header {
        position: sticky;
        top: 0;
        padding: max(env(safe-area-inset-top), var(--space-14)) var(--space-20) var(--space-14);
        z-index: var(--z-toolbar);
        /* Grouped-list chrome: the header shares the canvas tone and is set off
           only by a hairline — no drop shadow — so it reads as part of the page
           instead of a floating bar. The blur still frosts cards that scroll
           underneath. */
        background: var(--glass-header);
        -webkit-backdrop-filter: var(--blur-regular);
        backdrop-filter: var(--blur-regular);
        border-bottom: var(--border-hairline);
      }
      .header-top {
        display: flex;
        justify-content: space-between;
        align-items: center;
        gap: var(--space-8);
        padding-top: var(--space-8);
      }
      .month-nav {
        display: flex;
        align-items: center;
        gap: var(--space-4);
        margin: 0;
        padding: 0;
        background: transparent;
        border: none;
        width: fit-content;
      }
      .month-nav button {
        background: transparent;
        border: none;
        width: var(--btn-chrome-size);
        height: var(--btn-chrome-size);
        border-radius: 50%;
        cursor: pointer;
        color: var(--text);
        font-size: var(--fs-title);
        font-weight: 600;
        display: flex;
        align-items: center;
        justify-content: center;
        transition: transform var(--dur-medium) var(--ease-spring);
      }
      .month-nav button:active {
        color: var(--text);
        transform: scale(0.94);
      }
      /* :hover guarded so touch devices don't get a sticky hover state
         after tap; touch gets feedback via :active above. */
      @media (hover: hover) and (pointer: fine) {
        .month-nav button:hover {
          color: var(--text);
          transform: scale(0.94);
        }
      }
      .month-nav button:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
      }
      .month-label {
        font-size: var(--fs-footnote);
        font-weight: 600;
        color: var(--text);
        min-width: 124px;
        text-align: center;
        letter-spacing: -0.01em;
      }

      .sync-btn {
        position: relative;
        background: transparent;
        border: none;
        border-radius: 50%;
        width: var(--btn-chrome-size);
        height: var(--btn-chrome-size);
        padding: 0;
        font-family: var(--font-body);
        color: var(--text2);
        cursor: pointer;
        transition: transform var(--dur-base) var(--ease-spring);
        display: flex;
        align-items: center;
        justify-content: center;
        flex-shrink: 0;
      }
      .sync-btn:active {
        transform: scale(0.94);
      }
      @media (hover: hover) and (pointer: fine) {
        .sync-btn:hover {
          transform: scale(0.94);
        }
      }
      .sync-btn:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
      }
      .sync-dot {
        width: var(--space-14);
        height: var(--space-14);
        border-radius: 50%;
        background: var(--green);
        box-shadow: 0 0 var(--space-8) var(--green);
      }
      .sync-dot.syncing {
        background: var(--accent);
        box-shadow: 0 0 var(--space-8) var(--accent);
        animation: pulse var(--dur-pulse) ease-in-out infinite;
      }
      .sync-dot.error {
        background: var(--red);
        box-shadow: 0 0 var(--space-8) var(--red);
      }
      .sync-badge {
        position: absolute;
        top: calc(var(--space-2) * -1);
        right: calc(var(--space-2) * -1);
        min-width: var(--space-20);
        height: var(--space-20);
        padding: 0 var(--space-4);
        border-radius: var(--r-pill);
        background: var(--accent);
        color: var(--on-accent);
        font-size: var(--fs-micro);
        font-weight: 700;
        line-height: 1;
        display: flex;
        align-items: center;
        justify-content: center;
        box-shadow: 0 0 0 var(--space-2) var(--bg-grouped);
        font-variant-numeric: tabular-nums;
      }
      .sync-badge[hidden] {
        display: none;
      }
      @keyframes pulse {
        0%,
        100% {
          opacity: 1;
          transform: scale(1);
        }
        50% {
          opacity: 0.4;
          transform: scale(0.85);
        }
      }

      /* ====== SUMMARY CARDS ====== */
      .summary {
        padding: var(--space-10) var(--space-20) var(--space-8);
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: var(--space-10);
        isolation: isolate;
        flex-shrink: 0;
      }
      /* Same chrome as a .transaction row — plain bg-canvas, hairline,
         soft shadow. The earlier tinted background and specular sheen
         made the summary cards read as a different material than the
         list rows directly below them. */
      .summary-card {
        position: relative;
        background: var(--bg-canvas);
        border: var(--border-hairline);
        border-radius: var(--r-md);
        padding: var(--space-10) var(--space-14);
        box-shadow: var(--shadow-soft);
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: var(--space-8);
      }
      .summary-card .label {
        font-size: var(--fs-micro);
        color: var(--text);
        font-weight: 600;
        flex-shrink: 0;
      }
      .summary-card .amount {
        font-family: var(--font-display);
        font-size: var(--fs-headline);
        color: var(--text);
        line-height: 1.25;
        letter-spacing: -0.02em;
        text-align: right;
        font-variant-numeric: tabular-nums;
      }
      .summary-card .amount.positive {
        background: linear-gradient(135deg, var(--green), var(--green-2));
        -webkit-background-clip: text;
        background-clip: text;
        color: transparent;
      }
      .summary-card .amount.negative {
        background: linear-gradient(135deg, var(--accent), var(--accent-2));
        -webkit-background-clip: text;
        background-clip: text;
        color: transparent;
      }

      /* ====== PANELS ====== */
      .panel {
        display: none;
        padding: var(--space-8) var(--space-20)
          calc(var(--bottom-bar-clearance) + max(var(--space-16), env(safe-area-inset-bottom)));
      }
      .panel.active {
        display: block;
      }

      /* ====== SEARCH MODE ====== */
      .month-nav,
      .summary {
        transition:
          opacity var(--dur-base) var(--ease-soft),
          max-height var(--dur-medium) var(--ease-soft),
          padding var(--dur-medium) var(--ease-soft),
          margin var(--dur-medium) var(--ease-soft);
        max-height: 300px;
        overflow: hidden;
      }
      body.searching .month-nav,
      body.searching .summary {
        max-height: 0;
        opacity: 0;
        padding-top: 0;
        padding-bottom: 0;
        margin: 0;
        pointer-events: none;
      }

      /* ====== CATEGORY VIEW ====== */
      /* Card-styled row, same chrome as .transaction so the
         Kategorien-Übersicht reads as the same surface family as the
         Buchungs-Übersicht. */
      .cat-view-row {
        position: relative;
        background: var(--bg-canvas);
        border: var(--border-hairline);
        border-radius: var(--r-md);
        padding: var(--space-12) var(--space-14);
        margin-bottom: var(--space-8);
        display: flex;
        align-items: center;
        gap: var(--space-12);
        box-shadow: var(--shadow-soft);
        cursor: pointer;
      }
      /* No :active feedback — touchstart fires the state immediately,
         which made rows flash on scroll. Same call as .transaction.
         Keyboard activation still gets visual feedback via the
         is-key-active class set by handleRowActivate(). */
      .cat-view-row.is-key-active {
        opacity: 0.55;
        transition: opacity var(--dur-fast) ease;
      }
      .cat-view-row:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
        border-radius: var(--r-md);
      }
      .cat-view-icon {
        width: var(--icon-list-md);
        height: var(--icon-list-md);
        border-radius: var(--r-sm);
        display: flex;
        align-items: center;
        justify-content: center;
        flex-shrink: 0;
        background: color-mix(in oklab, var(--cat-color, var(--text)) 13%, transparent);
        color: var(--cat-color, var(--text));
        box-shadow:
          inset 0 0.5px 0 rgba(255, 255, 255, 0.6),
          inset 0 -0.5px 0 rgba(0, 0, 0, 0.04);
        border: var(--border-hairline);
      }
      .cat-view-icon .cat-glyph {
        width: 70%;
        height: 70%;
      }
      .cat-view-name {
        flex: 1;
        font-size: var(--fs-callout);
        color: var(--text);
      }
      .cat-view-amount {
        font-size: var(--fs-callout);
        font-weight: 600;
        font-variant-numeric: tabular-nums;
      }
      .cat-view-amount.negative {
        color: var(--accent);
      }
      .cat-view-amount.positive {
        color: var(--green);
      }
      .cat-view-more {
        width: var(--btn-chrome-size);
        height: var(--btn-chrome-size);
        margin-right: calc(-1 * var(--space-10));
        border: none;
        background: transparent;
        border-radius: 50%;
        /* Match the chrome buttons (hamburger etc.): full --text color
           and --fs-title icon size, so the drill-down affordance has
           the same visual weight as the rest of the toolbar chrome. */
        color: var(--text);
        font-size: var(--fs-title);
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        flex-shrink: 0;
        -webkit-tap-highlight-color: transparent;
        transition: background var(--dur-base) var(--ease-spring);
      }
      .cat-view-more:active {
        background: var(--surface-tint);
      }
      .cat-view-more:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
      }

      /* ====== TRANSACTIONS ====== */
      .section-title {
        font-size: var(--fs-caption);
        color: var(--text3);
        font-weight: 600;
        margin: var(--space-20) var(--space-4) var(--space-8);
      }
      .tx-row {
        position: relative;
        overflow: hidden;
        border-radius: var(--r-md);
        margin-bottom: var(--space-8);
      }
      .tx-row .transaction {
        margin-bottom: 0;
        position: relative;
        z-index: 2;
        touch-action: pan-y;
        will-change: transform;
        transition: transform var(--dur-slow) var(--ease-spring);
      }
      .tx-row.dragging .transaction {
        transition: none;
      }
      .tx-row.swiped .transaction {
        transform: translateX(calc(-1 * var(--swipe-action-w)));
      }

      .tx-action {
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        width: var(--swipe-action-w);
        background: linear-gradient(135deg, var(--red), var(--red-2));
        color: var(--on-accent);
        font-weight: 600;
        font-size: var(--fs-footnote);
        display: flex;
        align-items: center;
        justify-content: center;
        z-index: 1;
        cursor: pointer;
        border: none;
        border-radius: var(--r-md);
        box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
        letter-spacing: -0.01em;
        /* Hidden until the row is being interacted with so neither
           sub-pixel rounding at the rounded right corner nor a
           transient transform during inertial scroll can reveal a
           red sliver behind the card. */
        visibility: hidden;
        pointer-events: none;
      }
      .tx-row.swiped .tx-action,
      .tx-row.dragging .tx-action {
        visibility: visible;
        pointer-events: auto;
      }
      .tx-action:focus-visible {
        outline: 2px solid var(--text);
        outline-offset: -4px;
      }

      .transaction {
        position: relative;
        background: var(--bg-canvas);
        border: var(--border-hairline);
        border-radius: var(--r-md);
        padding: var(--space-12) var(--space-14);
        display: flex;
        align-items: center;
        gap: var(--space-12);
        box-shadow: var(--shadow-soft);
        overflow: hidden;
      }
      /* No :active transform — scaling on touch-start briefly shrinks
         the opaque card and exposes a sliver of the red delete action
         behind it during inertial scroll. */

      .t-icon {
        width: var(--icon-list-md);
        height: var(--icon-list-md);
        border-radius: var(--r-sm);
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: var(--btn-icon-size);
        flex-shrink: 0;
        /* --cat-color is set inline per row. Background stays a soft tint
           in both themes; the glyph itself reads as cat-color in light
           mode and switches to --text in dark mode (override below) so
           the dark-on-dark category palette doesn't disappear. */
        background: color-mix(in oklab, var(--cat-color, var(--text)) 13%, transparent);
        color: var(--cat-color, var(--text));
        box-shadow:
          inset 0 0.5px 0 rgba(255, 255, 255, 0.6),
          inset 0 -0.5px 0 rgba(0, 0, 0, 0.04);
        border: var(--border-hairline);
      }
      .t-info {
        flex: 1;
        min-width: 0;
        display: flex;
        flex-direction: column;
        gap: var(--space-4);
      }
      .t-note {
        font-size: var(--fs-micro);
        font-weight: 500;
        color: var(--text);
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        letter-spacing: -0.01em;
        min-height: 1.2em;
        min-width: 0;
        max-width: 100%;
      }
      .t-tags {
        display: flex;
        gap: var(--space-4);
        flex-wrap: wrap;
        align-items: center;
        min-width: 0;
      }
      .t-tag {
        background: var(--surface-tint);
        border: var(--border-hairline);
        border-radius: var(--r-xs);
        padding: var(--space-2) var(--space-8);
        font-size: var(--fs-micro);
        font-weight: 500;
        color: var(--text);
        line-height: 1.4;
      }
      .t-amount {
        font-family: var(--font-display);
        font-size: var(--fs-headline);
        font-weight: 400;
        flex-shrink: 0;
        letter-spacing: -0.02em;
        font-variant-numeric: tabular-nums;
      }
      .t-amount.out {
        color: var(--accent);
      }
      .t-amount.in {
        color: var(--green);
      }

      /* ====== CATEGORY BREAKDOWN ====== */
      .cat-row {
        display: flex;
        align-items: center;
        gap: var(--space-12);
        margin-bottom: var(--space-14);
      }
      .cat-icon {
        width: var(--icon-list-sm);
        height: var(--icon-list-sm);
        border-radius: var(--r-sm);
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: var(--fs-icon-sm);
        flex-shrink: 0;
        background: color-mix(in oklab, var(--cat-color, var(--text)) 13%, transparent);
        color: var(--cat-color, var(--text));
        box-shadow: inset 0 0.5px 0 rgba(255, 255, 255, 0.6);
        border: var(--border-hairline);
      }
      .cat-info {
        flex: 1;
      }
      .cat-name {
        font-size: var(--fs-footnote);
        font-weight: 600;
        letter-spacing: -0.01em;
      }
      .cat-bar-wrap {
        height: var(--cat-bar-h);
        background: var(--hairline-soft);
        border-radius: var(--r-pill);
        margin-top: var(--space-8);
        overflow: hidden;
      }
      .cat-bar {
        height: var(--cat-bar-h);
        border-radius: var(--r-pill);
        transition: width var(--dur-progress) var(--ease-spring);
      }
      .cat-amount {
        font-family: var(--font-display);
        font-size: var(--fs-body);
        color: var(--accent);
        letter-spacing: -0.02em;
        font-variant-numeric: tabular-nums;
      }

      /* ====== BOTTOM BAR (search + FAB) ====== */
      .bottom-bar {
        position: fixed;
        bottom: max(var(--space-16), env(safe-area-inset-bottom));
        left: 50%;
        transform: translateX(-50%);
        /* App-max width (430) minus horizontal page padding on both sides. */
        width: min(calc(430px - 2 * var(--space-16)), calc(100vw - 2 * var(--space-16)));
        display: flex;
        align-items: center;
        gap: var(--space-10);
        z-index: var(--z-floating);
      }
      .search-wrap {
        flex: 1;
        display: flex;
        align-items: center;
        gap: var(--space-8);
        height: var(--btn-fab-size);
        padding: 0 var(--space-16);
        background: var(--glass-thin);
        -webkit-backdrop-filter: var(--blur-regular);
        backdrop-filter: var(--blur-regular);
        border: var(--border-hairline);
        border-radius: var(--r-pill);
        box-shadow: var(--shadow-floating-strip);
      }
      .search-icon {
        color: var(--text3);
        font-size: var(--fs-title);
        flex-shrink: 0;
        line-height: 1;
      }
      .search-input {
        flex: 1;
        background: none;
        border: none;
        outline: none;
        font-family: var(--font-body);
        font-size: var(--fs-callout);
        color: var(--text);
        min-width: 0;
      }
      .search-input::placeholder {
        color: var(--text3);
      }
      .search-wrap:focus-within {
        border-color: var(--accent);
        box-shadow:
          inset 0 0.5px 0 var(--hairline),
          var(--focus-ring);
      }
      .search-form {
        display: contents;
      }

      /* ====== FAB (liquid glass) ====== */
      .fab {
        width: var(--btn-fab-size);
        height: var(--btn-fab-size);
        flex-shrink: 0;
        background: var(--glass-thin);
        -webkit-backdrop-filter: var(--blur-regular);
        backdrop-filter: var(--blur-regular);
        /* Match the search-wrap shape — both share the same floating
           glass capsule, so the FAB is the circular end-cap of that
           strip (Apple-Mail / Notes style). */
        border-radius: var(--r-pill);
        border: var(--border-hairline);
        /* Match the search-icon tone in the adjoining search-wrap so the
           floating chrome on the bottom bar reads as a single object. */
        color: var(--text3);
        font-size: var(--fs-icon-lg);
        font-weight: 300;
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        transition: transform var(--dur-medium) var(--ease-bounce);
        box-shadow: var(--shadow-floating-strip);
        overflow: hidden;
        isolation: isolate;
        position: relative;
      }
      .fab:active {
        transform: scale(0.92);
      }
      .fab:focus-visible {
        outline: none;
        box-shadow: var(--shadow-floating-strip), var(--focus-ring);
      }
      .fab.search-exit {
        font-size: var(--fs-icon-md);
        font-weight: 400;
      }

      /* ====== BOTTOM NAV (floating liquid glass capsule) ====== */
      .bottom-nav {
        display: none;
      }

      /* SVG-Glyph aus dem Sprite — Größe folgt font-size des umgebenden
         Buttons (1em), Farbe via currentColor. */
      .ui-icon {
        width: 1em;
        height: 1em;
        flex-shrink: 0;
        vertical-align: middle;
      }

      /* ====== HAMBURGER ====== */
      .hamburger-btn,
      .sidebar-toggle-btn {
        width: var(--btn-chrome-size);
        height: var(--btn-chrome-size);
        border: none;
        background: transparent;
        cursor: pointer;
        color: var(--text);
        font-size: var(--fs-title);
        display: inline-flex;
        align-items: center;
        justify-content: center;
        border-radius: var(--r-sm);
        padding: 0;
        flex-shrink: 0;
        transition: opacity var(--dur-base);
      }
      .hamburger-btn:active,
      .sidebar-toggle-btn:active {
        opacity: 0.6;
      }
      .hamburger-btn:focus-visible,
      .sidebar-toggle-btn:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
      }
      /* Sidebar toggle is tablet-only; the hamburger covers the same slot
         on phones, so this button stays hidden below 768px. */
      .sidebar-toggle-btn {
        display: none;
      }
      /* State-dependent icons (Apple Mail pattern). The button keeps both
         glyphs in the DOM and CSS picks one to show based on the
         sidebar-collapsed class on <html>. */
      .sidebar-toggle-btn .st-expand {
        display: none;
      }
      html.sidebar-collapsed .sidebar-toggle-btn .st-collapse {
        display: none;
      }
      html.sidebar-collapsed .sidebar-toggle-btn .st-expand {
        display: inline;
      }

      /* ====== DRAWER ====== */
      .drawer-overlay {
        position: fixed;
        inset: 0;
        z-index: var(--z-drawer-backdrop);
        background: var(--overlay-bg);
        /* Deliberately weaker than --blur-dim: the drawer overlay only
           needs to hint at the inert content underneath without obscuring it. */
        -webkit-backdrop-filter: var(--blur-overlay);
        backdrop-filter: var(--blur-overlay);
        opacity: 0;
        pointer-events: none;
        transition: opacity var(--dur-slow) ease;
      }
      .drawer-overlay.open {
        opacity: 1;
        pointer-events: auto;
      }

      .drawer {
        position: fixed;
        top: 0;
        left: 0;
        bottom: 0;
        width: min(300px, 88vw);
        z-index: var(--z-drawer);
        background: var(--glass-drawer);
        -webkit-backdrop-filter: blur(40px) saturate(180%);
        backdrop-filter: blur(40px) saturate(180%);
        border-right: var(--border-hairline-strong);
        overflow: hidden;
        transform: translateX(-100%);
        transition: transform 0.35s var(--ease-spring);
        display: flex;
        flex-direction: column;
      }
      .drawer.open {
        transform: translateX(0);
        box-shadow: var(--shadow-floating);
      }
      .drawer.sub-active .drawer-head {
        display: none;
      }
      .drawer-content {
        position: relative;
        flex: 1;
        min-height: 0;
        overflow: hidden;
      }
      .drawer-panel {
        position: absolute;
        inset: 0;
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
        transition:
          transform 0.32s var(--ease-spring),
          opacity 0.22s ease;
        will-change: transform;
        padding-bottom: calc(env(safe-area-inset-bottom) + var(--space-24));
      }
      .drawer-panel[data-state='active'] {
        transform: translateX(0);
        opacity: 1;
        pointer-events: auto;
      }
      .drawer-panel[data-state='left'] {
        transform: translateX(-28%);
        opacity: 0;
        pointer-events: none;
      }
      .drawer-panel[data-state='right'] {
        transform: translateX(100%);
        opacity: 0;
        pointer-events: none;
      }

      .drawer-head {
        position: sticky;
        top: 0;
        z-index: 1;
        background: var(--glass-modal);
        -webkit-backdrop-filter: blur(20px) saturate(150%);
        backdrop-filter: blur(20px) saturate(150%);
        padding: calc(env(safe-area-inset-top) + var(--space-16)) var(--space-20) var(--space-12);
        border-bottom: var(--border-hairline);
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: var(--space-12);
      }
      .drawer-head-title {
        font-family: var(--font-display);
        font-size: var(--fs-title);
        font-weight: 400;
        color: var(--text);
        letter-spacing: -0.015em;
        line-height: 1.25;
      }
      .drawer-head-title span {
        background: linear-gradient(135deg, var(--accent), var(--accent-2));
        -webkit-background-clip: text;
        background-clip: text;
        color: transparent;
      }
      .drawer-close-btn {
        width: var(--btn-chrome-size);
        height: var(--btn-chrome-size);
        border: var(--border-hairline);
        background: var(--bg-canvas);
        cursor: pointer;
        color: var(--text2);
        font-size: var(--btn-icon-size);
        display: flex;
        align-items: center;
        justify-content: center;
        border-radius: 50%;
        transition: background var(--dur-fast);
        -webkit-tap-highlight-color: transparent;
      }
      .drawer-close-btn:hover,
      .drawer-close-btn:active {
        background: var(--surface-tint);
        color: var(--text);
      }
      .drawer-close-btn:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
      }

      .drawer-section {
        padding: var(--space-16) var(--space-20) 0;
      }
      .drawer-section + .drawer-section {
        padding-top: var(--space-24);
      }
      .drawer-section-divider {
        height: 0.5px;
        background: var(--hairline-soft);
        margin: var(--space-24) var(--space-20) 0;
      }
      .drawer-section h3 {
        font-size: var(--fs-caption);
        font-weight: 600;
        color: var(--text3);
        margin-bottom: var(--space-12);
      }
      .info-list {
        margin: 0;
        padding: 0;
      }
      .info-row {
        display: flex;
        justify-content: space-between;
        align-items: baseline;
        gap: var(--space-16);
        padding: var(--space-8) 0;
        border-bottom: var(--border-hairline);
      }
      .info-row:last-child {
        border-bottom: none;
      }
      .info-row dt {
        color: var(--text3);
        font-size: var(--fs-caption);
        flex: 0 0 auto;
      }
      .info-row dd {
        margin: 0;
        color: var(--text);
        font-size: var(--fs-caption);
        text-align: right;
        word-break: break-word;
      }
      .info-row-stack {
        flex-direction: column;
        align-items: stretch;
        gap: var(--space-4);
      }
      .info-row-stack dd {
        text-align: left;
        font-size: var(--fs-micro);
        color: var(--text2);
      }
      .drawer-nav {
        margin: var(--space-16);
        background: var(--glass-card);
        -webkit-backdrop-filter: blur(20px);
        backdrop-filter: blur(20px);
        border: var(--border-hairline);
        border-radius: var(--r-md);
        overflow: hidden;
        box-shadow: var(--shadow-soft);
      }
      .drawer-nav + .drawer-nav {
        margin-top: 0;
      }
      .drawer-nav-item {
        position: relative;
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: var(--space-12);
        width: 100%;
        min-height: 50px;
        padding: var(--space-12) var(--space-16);
        background: none;
        border: none;
        font-family: var(--font-body);
        font-size: var(--fs-body);
        color: var(--text);
        cursor: pointer;
        text-align: left;
        transition: background var(--dur-fast);
      }
      .drawer-nav-item:not(:last-child)::after {
        content: '';
        position: absolute;
        bottom: 0;
        left: var(--sep-left, var(--space-16));
        right: 0;
        height: 0.5px;
        background: var(--hairline-soft);
      }
      .drawer-nav-icon-wrap {
        width: var(--nav-icon-size);
        height: var(--nav-icon-size);
        border-radius: var(--r-xs);
        background: var(--nav-icon-bg, var(--text3));
        color: var(--on-accent);
        display: flex;
        align-items: center;
        justify-content: center;
        flex-shrink: 0;
      }
      .drawer-nav-label {
        flex: 1;
      }
      .drawer-nav-item:active {
        background: var(--surface-tint);
      }
      .drawer-nav-item:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
      }
      .drawer-nav-item.active {
        color: var(--accent);
        font-weight: 600;
      }
      .drawer-nav-item.active:focus-visible {
        box-shadow: var(--focus-ring);
      }
      .drawer-nav-chevron {
        color: var(--text3);
        font-size: var(--btn-icon-size);
        line-height: 1;
        font-weight: 300;
      }
      .drawer-sub-head {
        position: sticky;
        top: 0;
        z-index: 1;
        background: var(--glass-modal);
        -webkit-backdrop-filter: blur(20px) saturate(150%);
        backdrop-filter: blur(20px) saturate(150%);
        padding: calc(env(safe-area-inset-top) + var(--space-8)) var(--space-20) var(--space-8);
        border-bottom: var(--border-hairline);
        display: flex;
        align-items: center;
        justify-content: center;
        min-height: calc(env(safe-area-inset-top) + 60px);
      }
      .drawer-back-btn {
        position: absolute;
        left: 12px;
        top: calc(env(safe-area-inset-top) + 8px);
        width: var(--btn-chrome-size);
        height: var(--btn-chrome-size);
        border-radius: 50%;
        border: var(--border-hairline);
        background: var(--bg-canvas);
        color: var(--text2);
        font-size: var(--btn-icon-size);
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        transition: background var(--dur-fast);
        -webkit-tap-highlight-color: transparent;
      }
      .drawer-back-btn:hover,
      .drawer-back-btn:active {
        background: var(--surface-tint);
        color: var(--text);
      }
      .drawer-sub-title {
        font-family: var(--font-body);
        font-size: var(--fs-body);
        font-weight: 600;
        color: var(--text);
      }

      .bn-item {
        display: none;
      }
      .bn-icon {
        display: none;
      }

      /* ====== MODAL ====== */
      .modal-overlay {
        display: none;
        position: fixed;
        inset: 0;
        background: var(--overlay-bg);
        -webkit-backdrop-filter: var(--blur-dim);
        backdrop-filter: var(--blur-dim);
        z-index: var(--z-modal);
        align-items: flex-end;
        justify-content: center;
      }
      .modal-overlay.open {
        display: flex;
        animation: overlay-in var(--dur-slow) var(--ease-soft);
      }
      @keyframes overlay-in {
        from {
          opacity: 0;
        }
        to {
          opacity: 1;
        }
      }

      .modal {
        background: var(--glass-modal);
        -webkit-backdrop-filter: blur(40px) saturate(180%);
        backdrop-filter: blur(40px) saturate(180%);
        border: var(--border-hairline);
        border-bottom: 0;
        border-radius: var(--r-xl) var(--r-xl) 0 0;
        padding: var(--space-14) var(--space-20) 0;
        width: 100%;
        max-width: 430px;
        animation: slideUp 0.45s var(--ease-spring);
        box-shadow: var(--shadow-floating);
        position: relative;
        max-height: calc(100dvh - env(safe-area-inset-top) - 12px);
        display: flex;
        flex-direction: column;
      }
      @keyframes slideUp {
        from {
          transform: translateY(100%);
          opacity: 0.4;
        }
        to {
          transform: translateY(0);
          opacity: 1;
        }
      }

      .modal h2 {
        font-family: var(--font-display);
        font-size: var(--fs-title);
        margin-bottom: var(--space-20);
        letter-spacing: -0.02em;
      }
      .modal-header {
        display: flex;
        align-items: center;
        justify-content: center;
        position: relative;
        margin-bottom: var(--space-20);
      }
      .modal-header h2 {
        margin-bottom: 0;
      }
      .modal-cancel-btn {
        position: absolute;
        right: 0;
        width: var(--btn-chrome-size);
        height: var(--btn-chrome-size);
        border-radius: 50%;
        border: var(--border-hairline);
        background: var(--bg-canvas);
        color: var(--text2);
        font-size: var(--btn-icon-size);
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        transition: background var(--dur-fast);
        -webkit-tap-highlight-color: transparent;
      }
      .modal-cancel-btn:hover,
      .modal-cancel-btn:active {
        background: var(--surface-tint);
        color: var(--text);
      }

      .modal-body {
        flex: 0 1 auto;
        min-height: 0;
        overflow-y: auto;
        margin: 0 calc(-1 * var(--space-20));
        padding: 0 var(--space-20) var(--space-4);
        scrollbar-width: none;
        -webkit-overflow-scrolling: touch;
        overscroll-behavior: contain;
      }
      .modal-body::-webkit-scrollbar {
        display: none;
      }
      .modal-footer {
        flex: 0 0 auto;
        margin: var(--space-8) calc(-1 * var(--space-20)) 0;
        padding: var(--space-4) var(--space-20) max(var(--space-20), env(safe-area-inset-bottom));
        border-top: var(--border-hairline);
      }

      .type-toggle {
        display: flex;
        background: var(--bg-canvas);
        border: var(--border-hairline);
        border-radius: var(--r-pill);
        padding: var(--space-4);
        margin-bottom: var(--space-24);
        gap: var(--space-4);
      }
      .type-btn {
        flex: 1;
        padding: var(--space-12);
        min-height: 44px;
        border: none;
        border-radius: var(--r-pill);
        font-family: var(--font-body);
        font-size: var(--fs-footnote);
        font-weight: 600;
        cursor: pointer;
        transition: all var(--dur-slow) var(--ease-spring);
        background: transparent;
        color: var(--text3);
        letter-spacing: -0.01em;
      }
      .type-btn.active.out {
        background: linear-gradient(135deg, var(--accent), var(--accent-2));
        color: var(--on-accent);
        box-shadow:
          0 2px 8px color-mix(in oklab, var(--accent) 35%, transparent),
          inset 0 0.5px 0 var(--hairline);
      }
      .type-btn.active.in {
        background: linear-gradient(135deg, var(--green), var(--green-2));
        color: var(--on-accent);
        box-shadow:
          0 2px 8px color-mix(in oklab, var(--green) 35%, transparent),
          inset 0 0.5px 0 var(--hairline);
      }
      .type-btn:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
      }
      .type-btn.active.out:focus-visible {
        box-shadow:
          0 2px 8px color-mix(in oklab, var(--accent) 35%, transparent),
          inset 0 0.5px 0 var(--hairline),
          var(--focus-ring);
      }
      .type-btn.active.in:focus-visible {
        box-shadow:
          0 2px 8px color-mix(in oklab, var(--green) 35%, transparent),
          inset 0 0.5px 0 var(--hairline),
          var(--focus-ring);
      }

      .form-group {
        margin-bottom: var(--space-16);
      }
      .form-group label {
        display: block;
        font-size: var(--fs-caption);
        color: var(--text3);
        font-weight: 600;
        margin-bottom: var(--space-8);
        padding-left: var(--space-4);
      }
      .form-group input,
      .form-group select {
        width: 100%;
        background: var(--bg-canvas);
        border: var(--border-hairline);
        border-radius: var(--r-md);
        padding: var(--space-14) var(--space-16);
        font-size: var(--fs-body);
        font-family: var(--font-body);
        color: var(--text);
        outline: none;
        transition: all var(--dur-base) var(--ease-spring);
        -webkit-appearance: none;
      }
      .form-group input:focus,
      .form-group select:focus {
        border-color: var(--accent);
        box-shadow:
          var(--focus-ring),
          inset 0 0.5px 0 var(--hairline);
      }
      .form-group input.amount-input {
        font-family: var(--font-display);
        font-size: var(--fs-title);
        text-align: center;
        letter-spacing: -0.02em;
        padding: var(--space-12) var(--space-16);
        font-variant-numeric: tabular-nums;
      }

      .tags-input-wrap {
        display: flex;
        flex-wrap: wrap;
        gap: var(--space-8);
        align-items: center;
        padding: var(--space-8) var(--space-10);
        background: var(--bg-canvas);
        border: var(--border-hairline);
        border-radius: var(--r-md);
        min-height: 48px;
      }
      .tag-pill {
        background: var(--bg-grouped);
        border: var(--border-hairline);
        border-radius: var(--r-pill);
        padding: var(--space-4) var(--space-12);
        font-size: var(--fs-micro);
        font-weight: 500;
        display: flex;
        align-items: center;
        gap: var(--space-4);
      }
      .tag-pill button {
        background: none;
        border: none;
        cursor: pointer;
        color: var(--text3);
        font-size: var(--fs-footnote);
        padding: var(--space-8);
        margin: calc(-1 * var(--space-8));
        line-height: 1;
      }

      .tag-add-btn {
        margin-left: auto;
        width: var(--btn-chrome-size);
        height: var(--btn-chrome-size);
        border-radius: 50%;
        border: var(--border-hairline);
        background: var(--bg-grouped);
        color: var(--text2);
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        flex-shrink: 0;
        transition: transform var(--dur-base) var(--ease-spring);
        -webkit-tap-highlight-color: transparent;
      }
      .tag-add-btn:active {
        transform: scale(0.92);
      }
      .tag-add-btn:focus-visible {
        outline: none;
        box-shadow:
          inset 0 0.5px 0 var(--hairline),
          var(--focus-ring);
      }

      .tag-create-row {
        display: flex;
        gap: var(--space-8);
        align-items: center;
      }
      .tag-create-row input {
        flex: 1;
        min-width: 0;
      }

      .tag-picker-search {
        height: var(--btn-fab-size);
        padding: 0 var(--space-16);
        margin-bottom: var(--space-12);
      }
      /* The picker's filter input lives inside .form-group, whose generic
         input styling would otherwise paint a second pill inside the
         search bar. Strip it so the search-wrap reads as a single field. */
      .form-group .tag-picker-search .search-input {
        background: none;
        border: none;
        box-shadow: none;
        padding: 0;
        height: auto;
        border-radius: 0;
      }

      .tag-picker-chips {
        display: flex;
        flex-wrap: wrap;
        gap: var(--space-8);
        align-content: flex-start;
        align-items: flex-start;
      }
      .tag-picker-chips:empty::after {
        content: 'Keine Tags gefunden.';
        color: var(--text3);
        font-size: var(--fs-caption);
        padding: var(--space-8) var(--space-4);
      }
      .tag-picker-chip {
        background: transparent;
        border: var(--border-hairline-strong);
        border-radius: var(--r-pill);
        padding: var(--space-10) var(--space-14);
        font-size: var(--fs-micro);
        font-weight: 500;
        color: var(--text2);
        cursor: pointer;
        font-family: inherit;
        transition:
          background var(--dur-base) var(--ease-spring),
          color var(--dur-base) var(--ease-spring),
          border-color var(--dur-base) var(--ease-spring);
        min-height: var(--btn-chrome-size);
      }
      .tag-picker-chip.selected {
        background: color-mix(in oklab, var(--accent) 18%, transparent);
        border-color: var(--accent);
        color: var(--text);
      }
      .tag-picker-chip:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
      }

      .cat-pill-edit {
        cursor: pointer;
        user-select: none;
        -webkit-user-select: none;
        transition: transform var(--dur-fast) var(--ease-spring);
      }
      .cat-pill-edit:active,
      .cat-pill-edit.is-key-active {
        transform: scale(0.94);
      }
      .cat-pill-edit:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
      }

      .color-swatches {
        display: flex;
        flex-wrap: wrap;
        gap: var(--space-10);
        align-items: center;
      }
      .color-swatch {
        width: var(--btn-chrome-size);
        height: var(--btn-chrome-size);
        border-radius: 50%;
        border: 2px solid transparent;
        cursor: pointer;
        padding: 0;
        box-shadow:
          inset 0 1px 0 rgba(255, 255, 255, 0.5),
          0 2px 6px rgba(0, 0, 0, 0.08);
        transition: transform var(--dur-base) var(--ease-bounce);
      }
      .color-swatch:active {
        transform: scale(0.9);
      }
      .color-swatch.active {
        border-color: var(--text);
        transform: scale(1.08);
      }
      .color-swatch-custom {
        width: var(--btn-chrome-size);
        height: var(--btn-chrome-size);
        border-radius: 50%;
        border: 2px dashed var(--text3);
        padding: 0;
        background: var(--bg-canvas);
        cursor: pointer;
        overflow: hidden;
      }
      .color-swatch-custom input[type='color'] {
        width: 200%;
        height: 200%;
        transform: translate(-25%, -25%);
        border: none;
        padding: 0;
        cursor: pointer;
        background: none;
      }

      /* Category icon picker (Phosphor sprite, see frontend/icons/categories/sprite.svg).
         The sprite sets fill="currentColor" on its outer <svg>, but <use>
         clones the <symbol> shadow tree without inheriting attributes
         from the sprite's outer wrapper — so the cloned <path> falls
         back to SVG's default fill (black). Pinning fill: currentColor
         here on the rendering <svg> lets the glyph pick up the color
         we set on its container (.t-icon, .cat-view-icon, .cat-icon),
         which is also what the dark-mode override depends on. */
      .cat-glyph {
        width: 60%;
        height: 60%;
        display: block;
        fill: currentColor;
      }
      .cat-pill-glyph {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 1em;
        height: 1em;
        flex: 0 0 auto;
      }
      .cat-pill-glyph .cat-glyph {
        width: 100%;
        height: 100%;
      }
      .icon-trigger {
        display: flex;
        align-items: center;
        gap: var(--space-12);
        width: 100%;
        padding: var(--space-10) var(--space-14);
        background: var(--bg-canvas);
        border: var(--border-hairline);
        border-radius: var(--r-md);
        cursor: pointer;
        color: var(--text);
        font: inherit;
        text-align: left;
        transition: background var(--dur-base) var(--ease-soft);
      }
      .icon-trigger:hover,
      .icon-trigger:focus-visible {
        background: var(--bg-grouped);
        outline: none;
      }
      .icon-trigger:focus-visible {
        box-shadow: var(--focus-ring);
      }
      .icon-trigger-glyph {
        width: 36px;
        height: 36px;
        border-radius: var(--r-sm);
        display: flex;
        align-items: center;
        justify-content: center;
        flex: 0 0 auto;
        background: color-mix(in oklab, currentColor 10%, transparent);
      }
      .icon-trigger-label {
        flex: 1 1 auto;
        color: var(--text2);
        font-size: var(--fs-body);
      }
      .icon-trigger .ui-icon {
        flex: 0 0 auto;
        color: var(--text3);
      }

      .icon-picker-section + .icon-picker-section {
        margin-top: var(--space-20);
      }
      .icon-picker-section-title {
        color: var(--accent);
        font-size: var(--fs-title-sm);
        font-weight: 600;
        margin-bottom: var(--space-12);
        letter-spacing: -0.01em;
      }
      .icon-picker-grid {
        display: grid;
        grid-template-columns: repeat(6, 1fr);
        gap: var(--space-8);
      }
      .icon-picker-cell {
        aspect-ratio: 1;
        display: flex;
        align-items: center;
        justify-content: center;
        border: 1px dashed var(--hairline);
        border-radius: var(--r-sm);
        background: transparent;
        color: var(--text);
        cursor: pointer;
        padding: 0;
        transition:
          background var(--dur-base) var(--ease-soft),
          border-color var(--dur-base) var(--ease-soft),
          transform var(--dur-base) var(--ease-bounce);
        -webkit-tap-highlight-color: transparent;
      }
      .icon-picker-cell:active {
        transform: scale(0.92);
      }
      .icon-picker-cell.active {
        border-style: solid;
        border-color: var(--accent);
        background: color-mix(in oklab, var(--accent) 12%, transparent);
        color: var(--accent);
      }
      .icon-picker-cell:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
      }
      .icon-picker-cell .cat-glyph {
        width: 58%;
        height: 58%;
      }

      .tag-suggestions {
        display: flex;
        flex-wrap: wrap;
        gap: var(--space-8);
        margin-top: var(--space-10);
      }
      .tag-suggestions:empty {
        display: none;
      }
      .tag-suggestion {
        background: transparent;
        border: 1px dashed var(--text3);
        border-radius: var(--r-pill);
        padding: var(--space-10) var(--space-14);
        font-size: var(--fs-micro);
        font-weight: 500;
        color: var(--text2);
        cursor: pointer;
        font-family: inherit;
        transition: all var(--dur-base) var(--ease-spring);
      }
      .tag-suggestion:hover,
      .tag-suggestion:active {
        background: var(--bg-canvas);
        border-style: solid;
        border-color: var(--hairline-soft);
        color: var(--text);
      }

      .submit-btn {
        width: 100%;
        background: linear-gradient(135deg, var(--accent), var(--accent-2));
        color: var(--on-accent);
        border: 0.5px solid var(--hairline);
        border-radius: var(--r-md);
        padding: var(--space-16);
        font-size: var(--fs-body);
        font-weight: 700;
        font-family: var(--font-body);
        cursor: pointer;
        margin-top: var(--space-10);
        transition: transform var(--dur-base) var(--ease-spring);
        letter-spacing: -0.01em;
        box-shadow:
          inset 0 0.5px 0 var(--hairline),
          inset 0 -0.5px 0 var(--edge-dark),
          0 6px 18px -4px color-mix(in oklab, var(--accent) 50%, transparent);
      }
      .submit-btn:active {
        transform: scale(0.985);
      }
      .submit-btn:focus-visible {
        outline: none;
        box-shadow:
          inset 0 0.5px 0 var(--hairline),
          inset 0 -0.5px 0 var(--edge-dark),
          var(--focus-ring),
          0 6px 18px -4px color-mix(in oklab, var(--accent) 50%, transparent);
      }
      .submit-btn.green {
        background: linear-gradient(135deg, var(--green), var(--green-2));
        box-shadow:
          inset 0 0.5px 0 var(--hairline),
          inset 0 -0.5px 0 var(--edge-dark),
          0 6px 18px -4px color-mix(in oklab, var(--green) 50%, transparent);
      }
      .submit-btn.btn-destructive,
      .save-btn.btn-destructive {
        margin-top: var(--space-8);
        background: transparent;
        color: var(--accent);
        border: 1px solid var(--accent);
        box-shadow: none;
      }

      /* Inline label + radio rows in Drawer-Sections (Darstellung, Startansicht). */
      .radio-row {
        display: flex;
        align-items: center;
        gap: var(--space-10);
        padding: var(--space-8) 0;
        cursor: pointer;
      }
      .radio-row input[type='radio'] {
        accent-color: var(--accent);
      }

      /* Settings selects (Appearance, Start view, Language, Currency) —
         one labelled <select> per preference, sharing the .form-group
         field look for a harmonious settings list. */
      .settings-field {
        margin-bottom: var(--space-16);
      }
      .settings-field:last-child {
        margin-bottom: 0;
      }
      .settings-field-label {
        display: block;
        font-size: var(--fs-caption);
        color: var(--text3);
        font-weight: 600;
        margin-bottom: var(--space-8);
        padding-left: var(--space-4);
      }
      .settings-select {
        width: 100%;
        background: var(--bg-canvas);
        border: var(--border-hairline);
        border-radius: var(--r-md);
        padding: var(--space-14) var(--space-16);
        font-size: var(--fs-body);
        font-family: var(--font-body);
        color: var(--text);
        outline: none;
        -webkit-appearance: none;
        appearance: none;
        transition: all var(--dur-base) var(--ease-spring);
      }
      .settings-select:focus {
        border-color: var(--accent);
        box-shadow:
          var(--focus-ring),
          inset 0 0.5px 0 var(--hairline);
      }

      /* ====== SETTINGS ====== */
      .settings-section {
        margin-bottom: var(--space-24);
      }
      .settings-section h3 {
        font-size: var(--fs-caption);
        color: var(--text3);
        font-weight: 600;
        margin-bottom: var(--space-10);
        padding-left: var(--space-4);
      }
      .settings-row {
        background: var(--bg-canvas);
        border: var(--border-hairline);
        border-radius: var(--r-md);
        padding: var(--space-14) var(--space-16);
        margin-bottom: var(--space-8);
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: var(--space-12);
        box-shadow: var(--shadow-soft);
      }
      .settings-row label {
        font-size: var(--fs-footnote);
        font-weight: 600;
        letter-spacing: -0.01em;
      }
      .settings-row input {
        background: var(--bg-grouped);
        border: var(--border-hairline);
        border-radius: var(--r-sm);
        padding: var(--space-8) var(--space-12);
        font-size: var(--fs-footnote);
        font-family: var(--font-body);
        color: var(--text);
        width: 200px;
        outline: none;
        transition: all var(--dur-base) var(--ease-spring);
      }
      .settings-row input:focus {
        border-color: var(--accent);
        box-shadow: var(--focus-ring);
      }
      .settings-row input[type='password'] {
        letter-spacing: 2px;
      }

      .save-btn {
        width: 100%;
        background: var(--bg-canvas);
        border: var(--border-hairline);
        border-radius: var(--r-md);
        padding: var(--space-14);
        font-size: var(--fs-body);
        font-weight: 600;
        font-family: var(--font-body);
        color: var(--text);
        cursor: pointer;
        transition: all var(--dur-base) var(--ease-spring);
        margin-top: var(--space-4);
        box-shadow: var(--shadow-soft);
        letter-spacing: -0.01em;
      }
      .save-btn:active {
        transform: scale(0.985);
      }
      @media (hover: hover) and (pointer: fine) {
        .save-btn:hover {
          color: var(--accent);
        }
      }
      .save-btn.primary {
        background: linear-gradient(135deg, var(--accent), var(--accent-2));
        color: var(--on-accent);
        border-color: var(--hairline);
        box-shadow:
          inset 0 0.5px 0 var(--hairline),
          0 6px 18px -4px color-mix(in oklab, var(--accent) 45%, transparent);
      }
      @media (hover: hover) and (pointer: fine) {
        .save-btn.primary:hover {
          color: var(--on-accent);
        }
      }

      .status-msg {
        font-size: var(--fs-micro);
        text-align: center;
        margin-top: var(--space-8);
        min-height: 16px;
        color: var(--green);
        font-weight: 500;
      }
      .status-msg.err,
      .status-msg.error {
        color: var(--red);
      }
      .status-msg.ok {
        color: var(--green);
      }
      /* Per-row CSV import errors (translated from backend codes). Capped in
         JS; scrolls if a file has many failed rows. */
      .import-error-list {
        list-style: none;
        margin: var(--space-8) 0 0;
        padding: 0;
        text-align: left;
        max-height: 9.5rem;
        overflow-y: auto;
        color: var(--text2);
        font-weight: 400;
      }
      .import-error-list li {
        padding: var(--space-4) 0;
        border-top: var(--border-hairline);
        word-break: break-word;
      }

      .empty-state {
        text-align: center;
        padding: var(--space-56) var(--space-24);
        color: var(--text3);
      }
      .empty-state .icon {
        display: block;
        width: var(--fs-icon-xl);
        height: var(--fs-icon-xl);
        margin: 0 auto var(--space-14);
        color: var(--text3);
        opacity: 0.75;
      }
      .empty-state p {
        font-size: var(--fs-footnote);
        line-height: 1.4;
      }

      /* Drawer list chips (categories / tags) – horizontal wrap with
         add-button below; used in #catList and #tagList. */
      .drawer-chip-list {
        display: flex;
        flex-wrap: wrap;
        gap: var(--space-8);
        margin-bottom: var(--space-12);
      }

      /* Sub-message used for "Noch keine …" hints inside drawer sections
         and breakdown lists. */
      .empty-state-hint {
        font-size: var(--fs-caption);
        color: var(--text3);
      }
      .empty-state-hint.center {
        text-align: center;
        padding: var(--space-16);
      }

      /* ====== REPORTS ====== */
      body.in-report .month-nav,
      body.in-report .summary {
        max-height: 0;
        opacity: 0;
        padding-top: 0;
        padding-bottom: 0;
        margin: 0;
        pointer-events: none;
      }

      .report-head {
        padding: var(--space-4) 0 0;
      }
      .report-title {
        font-family: var(--font-display);
        font-size: var(--fs-title);
        letter-spacing: -0.02em;
        margin: 0;
        color: var(--text);
      }
      .report-subtitle {
        font-size: var(--fs-caption);
        color: var(--text3);
        margin: var(--space-2) 0 0;
      }

      .range-picker {
        padding: var(--space-12) 0;
        display: flex;
        flex-direction: column;
        gap: var(--space-10);
      }
      .segmented {
        display: flex;
        gap: var(--space-2);
        padding: var(--space-4);
        background: var(--surface-tint);
        border-radius: var(--r-pill);
        border: var(--border-hairline);
      }
      .segmented button {
        flex: 1;
        border: none;
        background: transparent;
        color: var(--text2);
        font-size: var(--fs-caption);
        font-weight: 600;
        padding: var(--space-8) var(--space-10);
        border-radius: var(--r-pill);
        cursor: pointer;
        transition: background var(--dur-base) var(--ease-soft),
          color var(--dur-base) var(--ease-soft);
        font-variant-numeric: tabular-nums;
      }
      .segmented button.is-active {
        background: var(--bg-canvas);
        color: var(--text);
        box-shadow: var(--shadow-soft);
      }
      .segmented button[disabled],
      .segmented button[aria-disabled='true'] {
        opacity: 0.4;
        cursor: not-allowed;
      }
      .segmented button:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
      }

      .range-stepper {
        display: flex;
        align-items: center;
        justify-content: center;
        gap: var(--space-8);
        padding: var(--space-4);
        background: var(--bg-canvas);
        border: var(--border-hairline);
        border-radius: var(--r-pill);
        width: fit-content;
        align-self: center;
      }
      .range-stepper button {
        background: transparent;
        border: none;
        border-radius: 50%;
        width: var(--btn-chrome-size);
        height: var(--btn-chrome-size);
        cursor: pointer;
        color: var(--text2);
        display: flex;
        align-items: center;
        justify-content: center;
        transition: all var(--dur-base) var(--ease-spring);
      }
      .range-stepper button:hover,
      .range-stepper button:active {
        background: var(--bg-grouped);
        color: var(--text);
        transform: scale(0.94);
      }
      .range-stepper span {
        font-size: var(--fs-footnote);
        font-weight: 600;
        min-width: 148px;
        text-align: center;
        letter-spacing: -0.01em;
        color: var(--text);
      }

      .range-custom {
        display: grid;
        grid-template-columns: 1fr 1fr;
        align-items: stretch;
        padding: var(--space-4);
        background: var(--bg-canvas);
        border: var(--border-hairline);
        border-radius: var(--r-pill);
        width: fit-content;
        align-self: center;
      }
      .range-custom[hidden] {
        display: none;
      }
      .range-stepper[hidden] {
        display: none;
      }

      /* Trend-Analyse: globaler Range-Picker komplett ausgeblendet —
         Trend rendert einen eigenen Jahres-Picker inline im Report-Body. */
      body[data-report='trend'] #rangeKindTabs,
      body[data-report='trend'] #rangeStepper,
      body[data-report='trend'] #rangeCustom {
        display: none;
      }

      /* Trend-eigener Jahres-Picker: volle Breite wie die Sections darunter.
         <select> übernimmt das Styling der .range-custom-field-Inputs und
         öffnet auf iOS den nativen Wheel-Picker (auf Desktop ein Dropdown).
         font-size bewusst 16px — alles darunter triggert iOS-Auto-Zoom beim
         Fokus auf <select>. */
      .trend-year-picker {
        width: 100%;
        margin-bottom: var(--space-14);
      }
      .trend-year-picker select {
        flex: 1;
        min-width: 0;
        background: transparent;
        border: none;
        padding: 0 var(--space-12) 0 0;
        font-size: var(--fs-body);
        font-weight: 600;
        color: var(--text);
        font-family: inherit;
        font-variant-numeric: tabular-nums;
        letter-spacing: -0.01em;
        -webkit-appearance: none;
        appearance: none;
        text-align: right;
        text-align-last: right;
        cursor: pointer;
        background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
        background-repeat: no-repeat;
        background-position: right center;
        background-size: 12px 12px;
      }
      .trend-year-picker select:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
        border-radius: var(--r-xs);
      }
      .range-custom-field {
        display: flex;
        flex-direction: row;
        align-items: center;
        gap: var(--space-8);
        padding: 0 var(--space-12);
        min-height: var(--btn-chrome-size);
        font-size: var(--fs-footnote);
        font-weight: 600;
        letter-spacing: -0.01em;
      }
      .range-custom-field + .range-custom-field {
        border-left: var(--border-hairline);
      }
      .range-custom-field > span {
        color: var(--text3);
        font-weight: 500;
      }
      .range-custom-field input {
        flex: 1;
        min-width: 0;
        background: transparent;
        border: none;
        padding: 0;
        font-size: var(--fs-footnote);
        font-weight: 600;
        color: var(--text);
        font-family: inherit;
        font-variant-numeric: tabular-nums;
        letter-spacing: -0.01em;
      }
      .range-custom-field input::-webkit-calendar-picker-indicator {
        margin-left: var(--space-4);
        opacity: 0.55;
        cursor: pointer;
      }

      #reportBody {
        padding: 0;
      }

      .report-section {
        background: var(--bg-canvas);
        border: var(--border-hairline);
        border-radius: var(--r-lg);
        padding: var(--space-16) var(--space-16);
        margin-bottom: var(--space-14);
        box-shadow: var(--shadow-soft);
        overflow: hidden;
      }
      .report-section-title {
        font-size: var(--fs-footnote);
        color: var(--text3);
        margin: 0 0 var(--space-12);
        font-weight: 600;
      }

      .report-kpis {
        display: grid;
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: var(--space-8);
        margin-bottom: var(--space-14);
      }
      .report-kpis .summary-card {
        flex-direction: column;
        align-items: stretch;
        gap: var(--space-4);
        padding: var(--space-10) var(--space-12);
      }
      .report-kpis .summary-card .label {
        font-size: var(--fs-micro);
        color: var(--text3);
      }
      .report-kpis .summary-card .amount {
        font-size: var(--fs-headline);
        text-align: left;
      }

      .report-canvas-wrap {
        max-height: 280px;
      }
      .report-canvas-wrap canvas {
        max-height: 280px;
      }

      /* ====== TREND REPORT ====== */
      .trend-active-row {
        display: flex;
        align-items: center;
        gap: var(--space-12);
        margin-top: var(--space-12);
      }
      .trend-active-row[hidden],
      .trend-picker-open[hidden] {
        display: none;
      }
      .trend-active-info {
        display: flex;
        align-items: center;
        gap: var(--space-12);
        flex: 1;
        min-width: 0;
      }
      .trend-active-dot {
        width: 12px;
        height: 12px;
        border-radius: var(--r-pill);
        flex-shrink: 0;
      }
      .trend-active-text {
        min-width: 0;
        flex: 1;
      }
      .trend-active-label {
        font-size: var(--fs-body);
        font-weight: 600;
        letter-spacing: -0.01em;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
      }
      .trend-active-sub {
        display: block;
        font-size: var(--fs-caption);
        color: var(--text3);
        margin-top: 2px;
      }
      .trend-switch-btn {
        background: transparent;
        border: 0;
        color: var(--accent);
        font-family: inherit;
        font-size: var(--fs-callout);
        font-weight: 600;
        cursor: pointer;
        padding: var(--space-8) var(--space-4);
        min-height: var(--btn-chrome-size);
        flex-shrink: 0;
      }
      .trend-switch-btn:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
        border-radius: var(--r-sm);
      }
      .trend-picker-open {
        margin-top: var(--space-12);
        display: flex;
        flex-direction: column;
        gap: var(--space-12);
      }
      .trend-picker-open .search-wrap {
        background: var(--surface-tint);
        border-radius: var(--r-pill);
        display: flex;
        align-items: center;
        gap: var(--space-8);
        padding: 0 var(--space-12);
        min-height: var(--btn-chrome-size);
      }
      .trend-picker-open .search-wrap .ui-icon {
        width: 16px;
        height: 16px;
        color: var(--text3);
        flex-shrink: 0;
      }
      .trend-picker-open .search-wrap input {
        flex: 1;
        background: transparent;
        border: 0;
        outline: 0;
        font-family: inherit;
        font-size: var(--fs-callout);
        color: var(--text);
        padding: var(--space-8) 0;
      }
      .trend-chip {
        display: inline-flex;
        align-items: center;
        gap: var(--space-8);
        background: transparent;
        border: var(--border-hairline-strong);
        border-radius: var(--r-pill);
        padding: var(--space-8) var(--space-12);
        font-size: var(--fs-footnote);
        font-weight: 500;
        color: var(--text);
        cursor: pointer;
        font-family: inherit;
        min-height: var(--btn-chrome-size);
      }
      .trend-chip .dot {
        width: 10px;
        height: 10px;
        border-radius: var(--r-pill);
        flex-shrink: 0;
      }
      .trend-chip.is-selected {
        background: color-mix(in oklab, var(--accent) 18%, transparent);
        border-color: var(--accent);
        font-weight: 600;
      }
      .trend-chip:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
      }
      .trend-stats {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: var(--space-8);
        margin-bottom: var(--space-14);
      }
      .trend-stats .stat-card {
        background: var(--bg-canvas);
        border: var(--border-hairline);
        border-radius: var(--r-lg);
        padding: var(--space-12) var(--space-14);
        box-shadow: var(--shadow-soft);
      }
      .trend-stats .stat-card.wide {
        grid-column: 1 / -1;
      }
      .trend-stat-label {
        font-size: var(--fs-micro);
        color: var(--text3);
        font-weight: 500;
        margin-bottom: var(--space-4);
      }
      .trend-stat-value {
        font-family: var(--font-display);
        font-size: var(--fs-headline);
        line-height: 1.1;
        color: var(--text);
        letter-spacing: -0.02em;
      }
      .trend-stat-sub {
        font-size: var(--fs-caption);
        color: var(--text2);
        margin-top: var(--space-4);
      }
      .trend-stat-delta {
        display: inline-flex;
        align-items: center;
        font-size: var(--fs-footnote);
        font-weight: 600;
        color: var(--accent-2);
        background: var(--accent-tint);
        padding: 2px var(--space-8);
        border-radius: var(--r-pill);
        margin-left: var(--space-8);
        vertical-align: middle;
        font-family: var(--font-body);
        letter-spacing: 0;
      }


      .report-tx-row {
        display: flex;
        align-items: center;
        gap: var(--space-12);
        padding: var(--space-10) 0;
        border-bottom: var(--border-hairline);
        cursor: pointer;
      }
      .report-tx-row:last-child {
        border-bottom: none;
      }
      .report-tx-row:focus-visible {
        box-shadow: var(--focus-ring);
        border-radius: var(--r-sm);
      }
      .report-tx-main {
        flex: 1;
        min-width: 0;
      }
      .report-tx-desc {
        font-size: var(--fs-footnote);
        font-weight: 600;
        color: var(--text);
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
      }
      .report-tx-meta {
        font-size: var(--fs-caption);
        color: var(--text3);
      }
      .report-tx-amount {
        font-family: var(--font-display);
        font-size: var(--fs-body);
        letter-spacing: -0.02em;
        font-variant-numeric: tabular-nums;
      }
      .report-tx-amount.negative {
        color: var(--accent);
      }
      .report-tx-amount.positive {
        color: var(--green);
      }


      .donut-wrap {
        position: relative;
        max-width: 240px;
        margin: 0 auto;
        aspect-ratio: 1;
      }
      .donut-center {
        position: absolute;
        inset: 0;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        pointer-events: none;
      }
      .donut-center-value {
        font-family: var(--font-display);
        font-size: var(--fs-title-sm);
        letter-spacing: -0.02em;
        color: var(--text);
        font-variant-numeric: tabular-nums;
      }
      .donut-center-label {
        font-size: var(--fs-caption);
        color: var(--text3);
        margin-top: var(--space-2);
      }

      .forecast-card {
        text-align: center;
        padding: var(--space-8) 0;
      }
      .forecast-card-label {
        font-size: var(--fs-caption);
        color: var(--text3);
        margin-bottom: var(--space-4);
      }
      .forecast-card-value {
        font-family: var(--font-display);
        font-size: var(--fs-display);
        letter-spacing: -0.02em;
        color: var(--text);
        line-height: 1.1;
        font-variant-numeric: tabular-nums;
      }
      .forecast-card-hint {
        font-size: var(--fs-caption);
        color: var(--text3);
        margin-top: var(--space-8);
      }

      .forecast-table {
        width: 100%;
        border-collapse: collapse;
        font-size: var(--fs-footnote);
      }
      .forecast-table th {
        text-align: left;
        font-weight: 600;
        font-size: var(--fs-caption);
        color: var(--text3);
        padding: 0 var(--space-8) var(--space-8) 0;
        border-bottom: var(--border-hairline);
      }
      .forecast-table td {
        padding: var(--space-10) var(--space-8) var(--space-10) 0;
        border-bottom: var(--border-hairline);
        color: var(--text);
      }
      .forecast-table tr:last-child td {
        border-bottom: none;
      }
      .forecast-table tr.is-clickable {
        cursor: pointer;
        transition: background var(--dur-base) var(--ease-soft);
      }
      .forecast-table tr.is-clickable:active {
        background: var(--surface-tint);
      }
      @media (hover: hover) and (pointer: fine) {
        .forecast-table tr.is-clickable:hover {
          background: var(--surface-tint);
        }
      }
      .forecast-table tr.is-clickable:focus-visible {
        box-shadow: var(--focus-ring);
        border-radius: var(--r-sm);
      }
      .forecast-table .num {
        text-align: right;
        font-variant-numeric: tabular-nums;
      }
      .forecast-cat-name {
        display: inline-flex;
        align-items: center;
        gap: var(--space-8);
      }
      .forecast-cat-dot {
        width: 10px;
        height: 10px;
        border-radius: 50%;
        flex-shrink: 0;
      }
      .forecast-status {
        font-size: var(--fs-caption);
        font-weight: 600;
      }
      .forecast-status.is-ok {
        color: var(--green);
      }
      .forecast-status.is-neutral {
        color: var(--text3);
      }
      .forecast-status.is-warn {
        color: var(--accent);
      }

      /* iOS-style hidden scrollbar inside modal */
      .modal::-webkit-scrollbar {
        display: none;
      }
      .modal {
        scrollbar-width: none;
      }

      #catList .cat-pill-edit,
      #tagList > * {
        font-size: var(--fs-body);
        line-height: 1.4;
        padding: var(--space-10) var(--space-16);
      }
      /* No extra top gap when button is the first element in a section */
      .drawer-section > .save-btn:first-child {
        margin-top: 0;
      }
      /* Spacing between top button and chip list below */
      .drawer-section .save-btn + .drawer-chip-list {
        margin-top: var(--space-12);
      }
      /* Categories: drawer-nav card style */
      #catList.drawer-chip-list {
        flex-direction: column;
        gap: 0;
        background: var(--bg-canvas);
        border: var(--border-hairline);
        border-radius: var(--r-md);
        overflow: hidden;
        box-shadow: var(--shadow-soft);
        margin-bottom: 0;
      }
      #catList .cat-pill-edit {
        width: 100%;
        justify-content: flex-start;
        gap: var(--space-12);
        min-height: 50px;
        border-radius: 0 !important;
        background: none !important;
        border: none !important;
        box-shadow: none !important;
        padding: var(--space-12) var(--space-16) !important;
        position: relative;
        transform: none;
        transition: background var(--dur-fast);
      }
      #catList .cat-pill-edit:not(:last-child)::after {
        content: '';
        position: absolute;
        bottom: 0;
        left: calc(var(--nav-icon-size) + var(--space-12) + var(--space-16));
        right: 0;
        height: 0.5px;
        background: var(--hairline-soft);
      }
      #catList .cat-pill-edit:active,
      #catList .cat-pill-edit.is-key-active {
        background: var(--surface-tint) !important;
        transform: none;
      }
      /* Tags: same drawer-nav card style, no icons */
      #tagList.drawer-chip-list {
        flex-direction: column;
        gap: 0;
        background: var(--bg-canvas);
        border: var(--border-hairline);
        border-radius: var(--r-md);
        overflow: hidden;
        box-shadow: var(--shadow-soft);
        margin-bottom: 0;
      }
      #tagList .cat-pill-edit {
        width: 100%;
        justify-content: flex-start;
        min-height: 50px;
        border-radius: 0 !important;
        background: none !important;
        border: none !important;
        box-shadow: none !important;
        padding: var(--space-12) var(--space-16) !important;
        position: relative;
        transform: none;
        transition: background var(--dur-fast);
      }
      #tagList .cat-pill-edit:not(:last-child)::after {
        content: '';
        position: absolute;
        bottom: 0;
        left: var(--space-16);
        right: 0;
        height: 0.5px;
        background: var(--hairline-soft);
      }
      #tagList .cat-pill-edit:active,
      #tagList .cat-pill-edit.is-key-active {
        background: var(--surface-tint) !important;
        transform: none;
      }

      /* ====== TOASTS ====== */
      .toast-host {
        position: fixed;
        top: max(env(safe-area-inset-top), 14px);
        left: 16px;
        right: 16px;
        margin: 0 auto;
        max-width: 430px;
        z-index: var(--z-toast);
        pointer-events: none;
        display: flex;
        flex-direction: column;
        gap: var(--space-8);
      }
      .toast {
        background: var(--glass-chrome);
        -webkit-backdrop-filter: var(--blur-thick);
        backdrop-filter: var(--blur-thick);
        border: var(--border-hairline-strong);
        border-radius: var(--r-lg);
        padding: var(--space-12) var(--space-16);
        font-size: var(--fs-footnote);
        line-height: 1.4;
        color: var(--text);
        box-shadow: var(--shadow-elevated);
        pointer-events: auto;
        animation: toast-in 0.28s var(--ease-spring);
      }
      .toast.error {
        border-color: var(--accent);
      }
      .toast.leaving {
        animation: toast-out 0.22s var(--ease-soft) forwards;
      }
      @keyframes toast-in {
        from {
          transform: translateY(-16px);
          opacity: 0;
        }
        to {
          transform: translateY(0);
          opacity: 1;
        }
      }
      @keyframes toast-out {
        from {
          transform: translateY(0);
          opacity: 1;
        }
        to {
          transform: translateY(-12px);
          opacity: 0;
        }
      }

      /* ====== CONFIRM DIALOG ====== */
      .confirm-msg {
        font-size: var(--fs-footnote);
        color: var(--text2);
        line-height: 1.4;
        margin: 0 0 var(--space-20);
      }
      .confirm-modal {
        max-width: 360px;
        padding-bottom: max(var(--space-20), env(safe-area-inset-bottom));
        border-radius: var(--r-xl);
        border-bottom: var(--border-hairline);
      }
      .confirm-modal h2 {
        font-size: var(--fs-title-sm);
      }
      .confirm-cancel {
        width: 100%;
        margin-top: var(--space-8);
        background: transparent;
        color: var(--text2);
        border: 1px solid var(--hairline);
        border-radius: var(--r-md);
        padding: var(--space-14);
        font-family: var(--font-body);
        font-size: var(--fs-callout);
        font-weight: 600;
        cursor: pointer;
        transition: background var(--dur-base) var(--ease-soft);
      }
      .confirm-cancel:hover,
      .confirm-cancel:active {
        background: var(--surface-tint);
      }

      /* ====== MATERIAL FALLBACKS ====== */
      /* When the browser cannot blur, or the user prefers reduced transparency,
     fall back to nearly-opaque canvas tints (DESIGN_CONVENTIONS §5). */
      @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
        :root {
          --glass-thin: rgba(255, 255, 255, 0.92);
          --glass-chrome: rgba(255, 255, 255, 1);
          --glass-header: var(--bg-grouped);
          --glass-modal: var(--bg-grouped);
          --glass-drawer: var(--bg-grouped);
          --glass-card: var(--bg-canvas);
        }
        html[data-dark='true'] {
          --glass-thin: rgba(38, 35, 30, 0.92);
          --glass-chrome: rgba(22, 20, 17, 1);
        }
      }
      @media (prefers-reduced-transparency: reduce) {
        :root {
          --glass-thin: rgba(255, 255, 255, 0.92);
          --glass-chrome: rgba(255, 255, 255, 1);
          --glass-header: var(--bg-grouped);
          --glass-modal: var(--bg-grouped);
          --glass-drawer: var(--bg-grouped);
          --glass-card: var(--bg-canvas);
        }
        html[data-dark='true'] {
          --glass-thin: rgba(38, 35, 30, 0.92);
          --glass-chrome: rgba(22, 20, 17, 1);
        }
      }

      /* ====== ADAPTIVE LAYOUT (≥768px tablet, ≥1024px desktop) ======
         Mobile-first base above is untouched. Two literal breakpoints
         (CSS limitation; tokens documented in :root above). */

      @keyframes fadeScaleIn {
        from {
          opacity: 0;
          transform: scale(0.96);
        }
        to {
          opacity: 1;
          transform: scale(1);
        }
      }

      @media (min-width: 768px) {
        /* Body lets the shell take over centering; the flat grouped canvas
           lives on <html>, so it always fills the viewport regardless of the
           body box width. */
        body {
          max-width: none;
        }

        /* Reserve a column on the left for the sidebar — no grid, no
           max-width on the shell so landscape iPads don't show canvas
           margins. The drawer itself is position: fixed and lives
           outside the normal flow, so this padding is the only thing
           that keeps the content from sliding under it.
           display: block overrides the mobile `display: contents`, which
           would otherwise swallow the padding (contents-elements don't
           generate their own box). */
        .app-shell {
          display: block;
          padding-left: var(--app-sidebar-width);
        }

        /* Drawer = persistent sidebar pinned to the viewport edge. The
           transform/left/padding-left transitions for the collapse
           toggle are defined further down in this block. */
        .drawer {
          position: fixed;
          top: 0;
          left: 0;
          bottom: 0;
          width: var(--app-sidebar-width);
          height: 100dvh;
          min-height: 100vh; /* iPad-Safari 100dvh quirk fallback */
          transform: none;
          box-shadow: none;
          border-right: var(--border-hairline-strong);
        }
        .drawer.open {
          transform: none;
          box-shadow: none;
        }
        /* Mobile overlay, hamburger trigger and the drawer-head's close
           button are no longer needed. The "PocketLog" title stays —
           it's the sidebar's brand mark, and the new sidebar-toggle
           button (Apple Mail style) takes the hamburger's slot in the
           header. */
        .drawer-overlay,
        .hamburger-btn,
        .drawer-close-btn {
          display: none;
        }
        .sidebar-toggle-btn {
          display: inline-flex;
        }
        .drawer-head {
          justify-content: flex-start;
        }

        /* Header / summary / panels keep their natural block flow inside
           the padded shell and take the full content-pane width — Apple
           HIG doesn't cap list / table widths (Mail, Notes, Files all
           let rows fill the secondary pane), so neither do we. The
           header-top is a 3-column grid so the month nav stays
           visually centered regardless of how wide the column gets. */
        .header-top {
          display: grid;
          grid-template-columns: var(--btn-chrome-size) 1fr var(--btn-chrome-size);
          align-items: center;
        }
        .header-top > .month-nav {
          justify-self: center;
        }
        .header-top > .sync-btn {
          justify-self: end;
        }

        /* Bottom bar mirrors the iPhone insets — 16px from each visual
           edge — so it doesn't clip to the sidebar on the left or to
           the viewport edge on the right. No max-width: the bar tracks
           the content column above it. */
        .bottom-bar {
          left: calc(var(--app-sidebar-width) + var(--space-16));
          right: var(--space-16);
          transform: none;
          width: auto;
          max-width: none;
          margin-inline: auto;
        }

        /* Modal switches from bottom-sheet to centered card. */
        .modal-overlay {
          align-items: center;
        }
        .modal {
          max-width: 560px;
          border: var(--border-hairline);
          border-radius: var(--r-xl);
          max-height: 85dvh;
          animation: fadeScaleIn var(--dur-medium) var(--ease-spring);
        }

        /* Sidebar collapse (Apple-Mail style toggle). The class lives on
           <html> because the inline boot script in <head> sets it before
           <body> exists, which avoids a flash of expanded sidebar on
           every page load. Drawer slides out left, content reclaims the
           reserved column, bottom bar follows. */
        .drawer,
        .app-shell,
        .bottom-bar {
          transition:
            transform var(--dur-slow) var(--ease-spring),
            padding-left var(--dur-slow) var(--ease-spring),
            left var(--dur-slow) var(--ease-spring);
        }
        html.sidebar-collapsed .drawer {
          transform: translateX(calc(-1 * var(--app-sidebar-width)));
        }
        html.sidebar-collapsed .app-shell {
          padding-left: 0;
        }
        html.sidebar-collapsed .bottom-bar {
          left: var(--space-16);
        }
      }

      @media (min-width: 1024px) {
        /* On larger displays the chart canvas gets a bit more vertical
           breathing room; the list / bar widths are unrestricted from
           the 768 px block onwards. */
        .report-canvas-wrap,
        .report-canvas-wrap canvas {
          max-height: 420px;
        }
      }

      /* ====== AUTH VIEWS (Login, Setup, Force-Change-Password) ====== */
      /* Full-viewport centered card. Shares form-group styling with the
         transaction modal so a single source of truth governs the inputs.
         Stays inside the app's design tokens — no hex/px literals. */
      .auth-view {
        position: fixed;
        inset: 0;
        background: var(--bg-grouped);
        display: flex;
        align-items: flex-start;
        justify-content: center;
        padding: max(var(--space-56), env(safe-area-inset-top)) var(--space-20)
          max(var(--space-56), env(safe-area-inset-bottom));
        z-index: var(--z-modal, 1000);
        overflow-y: auto;
      }
      /* Class selector beats the user-agent [hidden]{display:none} rule by
         specificity, so without this override every .auth-view stays
         visible and the last one in the DOM (forcePwView) covers the
         others — making _showAuthView()'s toggle a no-op. */
      .auth-view[hidden] {
        display: none;
      }
      .auth-card {
        width: 100%;
        max-width: 420px;
        /* Same card recipe as the rest of the app, so the login card lifts off
           the grouped canvas like every other surface. */
        background: var(--bg-canvas);
        border: var(--border-hairline);
        border-radius: var(--r-xl);
        padding: var(--space-24) var(--space-20) var(--space-20);
        box-shadow: var(--shadow-elevated);
      }
      .auth-brand {
        font-family: 'DM Serif Display', serif;
        font-weight: 400;
        font-size: var(--fs-title);
        color: var(--text);
        margin: 0 0 var(--space-4);
        text-align: center;
      }
      .auth-brand span {
        color: var(--accent);
      }
      .auth-headline {
        font-size: var(--fs-headline);
        color: var(--text);
        margin: 0 0 var(--space-16);
        text-align: center;
        font-weight: 600;
      }
      .auth-intro {
        font-size: var(--fs-footnote);
        color: var(--text2);
        line-height: 1.45;
        margin: 0 0 var(--space-20);
        text-align: center;
      }
      .auth-form {
        display: flex;
        flex-direction: column;
        gap: var(--space-16);
      }
      .auth-form .form-group {
        margin: 0;
      }
      .auth-remember {
        display: flex;
        align-items: center;
        gap: var(--space-8);
        font-size: var(--fs-footnote);
        color: var(--text2);
        margin: 0;
        padding-left: var(--space-4);
        cursor: pointer;
      }
      .auth-remember input[type='checkbox'] {
        width: auto;
        margin: 0;
      }
      .auth-error {
        font-size: var(--fs-footnote);
        color: var(--red, #b3261e);
        background: var(--accent-tint);
        padding: var(--space-8) var(--space-12);
        border-radius: var(--r-md, 12px);
        margin: 0;
        line-height: 1.4;
      }
      /* ====== ADMIN USER LIST ====== */
      .admin-user-row {
        display: flex;
        flex-direction: column;
        gap: var(--space-4);
        padding: var(--space-12) var(--space-14);
        background: var(--bg-canvas);
        border: var(--border-hairline);
        border-radius: var(--r-md);
        margin-bottom: var(--space-8);
      }
      .admin-user-row-head {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: var(--space-8);
      }
      .admin-user-name {
        font-weight: 600;
        color: var(--text);
        font-size: var(--fs-body);
      }
      .admin-user-tags {
        display: flex;
        flex-wrap: wrap;
        gap: var(--space-4);
        font-size: var(--fs-micro);
      }
      .admin-user-tag {
        background: var(--surface-tint);
        color: var(--text2);
        padding: var(--space-2) var(--space-8);
        border-radius: var(--r-pill);
      }
      .admin-user-tag.admin {
        background: var(--accent-tint);
        color: var(--accent);
      }
      .admin-user-tag.inactive {
        opacity: 0.7;
      }
      .admin-user-actions {
        display: flex;
        flex-wrap: wrap;
        gap: var(--space-8);
        margin-top: var(--space-8);
      }
      .admin-user-actions button {
        flex: 0 0 auto;
        font-size: var(--fs-caption);
        background: var(--surface);
        color: var(--text);
        border: 1px solid var(--surface-tint);
        padding: var(--space-8) var(--space-12);
        border-radius: var(--r-md, 12px);
        cursor: pointer;
        min-height: var(--btn-chrome-size);
      }
      .admin-user-actions button.btn-destructive {
        color: var(--red, #b3261e);
        border-color: var(--red, #b3261e);
      }
      .admin-user-actions button:disabled {
        opacity: 0.45;
        cursor: not-allowed;
      }

      /* Admin-only menu entries collapse to display:none when the
         body doesn't carry the .is-admin class. Cleaner than juggling
         `hidden` from JS, and survives view re-renders. */
      body:not(.is-admin) .admin-only {
        display: none !important;
      }

      /* Reduced motion */
      @media (prefers-reduced-motion: reduce) {
        *,
        *::before,
        *::after {
          transition-duration: 0.01ms !important;
          animation-duration: 0.01ms !important;
        }
      }
