:root {
    --ynab-blue: #2d6da2;
    --ynab-primary: #3b5bdb;
    --ynab-green: #2f9e44;
    --ynab-red: #e03131;
    --ynab-yellow: #f08c00;
    --ynab-bg: #f4f6f8;
    --ynab-nav: #1f2d3d;
}

/* Full-screen gate shown only until AppBootstrapper's first EnsureReadyAsync call finishes this
   session (see AppState.BootstrapComplete) — i.e. right after a real page load/F5, never again
   during normal SPA navigation since that flag is in-memory only. */
.splashscreen {
    position: fixed; inset: 0; z-index: 2000;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1.5rem;
    background: linear-gradient(135deg, #2f9e44, var(--ynab-nav) 65%);
    color: #fff;
}
.splash-word { font-size: 2rem; font-weight: 700; letter-spacing: .04em; }
.splash-spinner {
    width: 2rem; height: 2rem; border-radius: 50%;
    border: 3px solid rgba(255,255,255,.3); border-top-color: #fff;
    animation: splash-spin .8s linear infinite;
}
@keyframes splash-spin { to { transform: rotate(360deg); } }

/* Bootstrap's default stack falls back to bare, unhinted Roboto on Android with no smoothing —
   this pins a proper system-font stack (matches Bootstrap's own choice on platforms that have it)
   and asks the renderer to smooth/hint it, which is what actually fixes the coarse look. */
html { -webkit-text-size-adjust: 100%; }
body {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
    font-size: .9375rem;
}

/* 100vh on mobile/tablet browsers is the *layout* viewport — it includes the space the address
   bar/tabs UI covers before it collapses on scroll, which is taller than what's actually visible.
   .ynab-shell being sized to that inflated value is exactly what let the whole page (not just the
   intended inner scroll regions) become genuinely scrollable: the real content did fit, but the box
   holding it was laid out taller than the true screen. 100dvh (dynamic viewport height) tracks the
   real visible height as browser chrome shows/hides; the plain 100vh line stays first as a fallback
   for browsers that don't support dvh, which simply ignore the second declaration. */
.ynab-shell { display: flex; flex-direction: column; height: 100vh; height: 100dvh; background: var(--ynab-bg); }

.ynab-syncbar {
    display: flex; align-items: center; gap: .75rem;
    background: var(--ynab-nav); color: #fff; padding: .5rem 1rem;
}
.ynab-syncbar .flex-spacer { flex: 1; }
.ynab-syncbar .status.online { color: #8ce99a; }
.ynab-syncbar .status.offline { color: #ffc9c9; }
.ynab-syncbar .last { color: #adb5bd; }

.ynab-main { display: flex; flex: 1; min-height: 0; }
.ynab-nav { position: relative; width: 230px; flex-shrink: 0; background: #26374a; color: #d5dde5; overflow-y: auto; overscroll-behavior: contain; }
.ynab-nav .nav-link { color: #d5dde5; padding: .4rem 0; display: block; }
.ynab-nav .nav-link.active { color: #fff; font-weight: 600; }
.ynab-content { flex: 1; overflow: auto; overscroll-behavior: contain; background: var(--ynab-bg); min-width: 0; display: flex; flex-direction: column; }

.nav-toggle { display: none; background: none; border: none; color: #fff; font-size: 1.35rem; cursor: pointer; padding: 0 .35rem; line-height: 1; }
.nav-backdrop { display: none; }
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; container-type: inline-size; }

.ynab-nav.collapsed { padding: 0 !important; overflow: hidden; border: none; }
.ynab-nav.collapsed .nav-resize-handle { display: none; }
/* Small round tab straddling the nav/content boundary — reclaims the sidebar's width for the
   register table on demand instead of only being able to resize it. Fixed-positioned (not a normal
   nav child) so it stays reachable even once the collapsed nav itself is width:0. */
.nav-collapse-toggle {
    position: fixed; top: 72px; z-index: 1100; width: 24px; height: 24px; border-radius: 50%;
    background: #26374a; color: #fff; border: 1px solid rgba(255,255,255,.25);
    display: flex; align-items: center; justify-content: center; font-size: .72rem; line-height: 1;
    cursor: pointer; padding: 0; transition: left .15s ease;
}
.nav-collapse-toggle:hover { background: #33465c; }
@media (max-width: 820px) { .nav-collapse-toggle { display: none; } } /* mobile already has its own off-canvas nav toggle */

/* ── Mobile: sidebar becomes an off-canvas drawer, content goes full width ── */
@media (max-width: 820px) {
    .nav-toggle { display: inline-block; }

    .ynab-nav {
        position: fixed; top: 0; left: 0; bottom: 0; width: 250px !important; z-index: 1200;
        transform: translateX(-100%); transition: transform .2s ease; overflow-y: auto;
    }
    .nav-resize-handle { display: none; }
    .ynab-shell.nav-open .ynab-nav { transform: translateX(0); }
    .ynab-shell.nav-open .nav-backdrop {
        display: block; position: fixed; inset: 0; z-index: 1150; background: rgba(0,0,0,.45);
    }

    .ynab-content { width: 100%; }
    .balance-header { flex-wrap: wrap; gap: .5rem 1rem; }
    .balance-header .bh-op { display: none; }
    .auth-card { margin: 1.5rem auto; max-width: 92%; }

    /* Wide tables scroll horizontally instead of squeezing. .register-table is deliberately NOT
       included here — its columns shrink/truncate to fit instead, see the fixed-layout rules below. */
    .budget-table { min-width: 640px; }
}

/* .register-table: fixed column widths (see the <th style="width:…"> in AccountRegister.razor,
   which serves both the single-account and all-accounts routes) so the table always fits its
   container at any width instead of growing
   with content and forcing .table-scroll to scroll horizontally — long payee/category/memo text
   truncates with an ellipsis (.truncate) instead, and the full value is still available via the
   cell's title attribute (native browser tooltip on hover/long-press). */
.register-table { table-layout: fixed; width: 100%; }
.register-table td.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.auth-card {
    max-width: 380px; margin: 3rem auto; background: #fff;
    padding: 2rem; border-radius: .75rem; box-shadow: 0 6px 24px rgba(0,0,0,.08);
}

.boot-error {
    max-width: 380px; margin: 3rem auto; background: #fff; text-align: center;
    padding: 2rem; border-radius: .75rem; box-shadow: 0 6px 24px rgba(0,0,0,.08);
}
.boot-error p { color: #495057; margin-bottom: 1rem; }

/* Shown once the service worker has a new version installed and waiting — lets the user swap to it
   on tap instead of only picking it up after fully closing every open tab (the default SW lifecycle). */
.pwa-update-banner {
    position: fixed; top: 0; left: 0; right: 0; z-index: 1500;
    display: flex; align-items: center; justify-content: center; gap: .75rem;
    background: #12151c; color: #fff; padding: .5rem 1rem; font-size: .85rem;
    box-shadow: 0 2px 10px rgba(0,0,0,.25);
}
.pwa-update-banner button {
    background: #4c6ef5; color: #fff; border: none; border-radius: .4rem;
    padding: .3rem .8rem; font-weight: 600; cursor: pointer; white-space: nowrap;
}
.pwa-update-banner button:hover { background: #3b5bdb; }

.rta-badge {
    padding: .35rem 1rem; border-radius: .5rem; color: #fff; text-align: center;
}
.rta-badge.pos { background: var(--ynab-green); }
.rta-badge.neg { background: var(--ynab-red); }
.rta-badge .amount { font-weight: 700; font-size: 1.1rem; }
.rta-badge .label { font-size: .7rem; opacity: .9; }

.budget-table .group-row td { background: #e9ecef; font-weight: 600; }
.assign-input { width: 110px; text-align: right; border: 1px solid #ced4da; border-radius: .25rem; padding: .1rem .4rem; }
.pill { padding: .1rem .5rem; border-radius: 1rem; font-weight: 600; }
.pill.pos { background: #d3f9d8; color: #2b8a3e; }
.pill.neg { background: #ffe3e3; color: #c92a2a; }
.pill.zero { background: #e9ecef; color: #495057; }

.ynab-nav .acct-group-header {
    display: flex; justify-content: space-between; align-items: baseline;
    font-size: .68rem; letter-spacing: .06em; text-transform: uppercase; font-weight: 700;
    color: #8fa0b3; margin: .9rem 0 .25rem;
}
/* Fixed-width arrow so the label text lines up with account names below regardless of glyph width. */
.ynab-nav .acct-group-header .ggh-arrow { display: inline-block; width: 1rem; }
.ynab-nav .acct-row {
    position: relative; display: flex; align-items: center; padding: .2rem 0;
    cursor: grab; box-shadow: 0 -2px 0 0 transparent; transition: box-shadow .1s ease;
}
.ynab-nav .acct-row.drag-over { box-shadow: 0 -2px 0 0 #74c0fc; }
.ynab-nav .acct-row a {
    display: flex; flex: 1; min-width: 0; justify-content: space-between; gap: .4rem; text-decoration: none;
    color: #d5dde5; font-size: .9rem; padding-left: 1rem;
}
.ynab-nav .acct-row a:hover { color: #fff; }
.ynab-nav .acct-row a.active { color: #fff; font-weight: 600; }
.ynab-nav .acct-row .nm { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ynab-nav .acct-row .amount { flex-shrink: 0; }
.ynab-nav .acct-row .amount.neg { color: #ffa8a8; }
.ynab-nav .acct-edit-btn {
    position: absolute; left: -1rem; top: 50%; transform: translateY(-50%);
    background: none; border: none; color: #8fa0b3; font-size: .8rem; line-height: 1;
    padding: .15rem .25rem; opacity: 0; cursor: pointer; z-index: 1;
}
.ynab-nav .acct-row:hover .acct-edit-btn { opacity: 1; }
.ynab-nav .acct-edit-btn:hover { color: #fff; }
.ynab-nav .acct-group-header { cursor: pointer; }
.ynab-nav .acct-add-btn {
    display: block; width: 100%; text-align: left; background: none; border: 1px dashed #445267;
    color: #8fa0b3; border-radius: .3rem; padding: .4rem .5rem; margin-top: .5rem; font-size: .85rem;
}
.ynab-nav .acct-add-btn:hover { color: #fff; border-color: #8fa0b3; }
.ynab-nav .nav-version { font-size: .68rem; color: #5c6b80; text-align: left; margin-top: .4rem; }
.ynab-nav .lang-switch { display: flex; gap: .25rem; }

.nav-resize-handle { position: absolute; top: 0; right: 0; bottom: 0; width: 6px; cursor: col-resize; z-index: 5; }
.nav-resize-handle:hover { background: rgba(255,255,255,.12); }
.nav-resize-overlay { position: fixed; inset: 0; z-index: 1400; cursor: col-resize; }

/* Register: unapproved transactions stand out (bold), approve/clear affordances */
.tx-unapproved td { font-weight: 700; }
/* Light green accent for reconciled rows — set on cells to beat Bootstrap's --bs-table-bg. */
.register-table tbody tr.tx-reconciled td { background-color: #ebfbee !important; }
/* Selected (checkbox-ticked) rows get the same yellow as an open editor row; wins over reconciled green. */
.register-table tbody tr.row-selected td, .upcoming-row.row-selected td { background-color: #fff8e1 !important; }
.cleared-toggle { cursor: pointer; background: none; border: none; padding: 0; font-weight: 700; }
.cleared-toggle.cleared { color: #2f9e44; }
.cleared-toggle.uncleared { color: #adb5bd; }
.cleared-toggle.reconciled { color: #1971c2; }

.approve-bar {
    display: flex; justify-content: space-between; align-items: center;
    background: #dbe4ff; color: #1c2b4a; padding: .5rem 1rem;
    border-radius: .4rem; margin-bottom: .75rem;
}

.tx-action-ico { background: none; border: none; cursor: pointer; padding: 0; font-size: .95rem; line-height: 1; color: #2f9e44; }

/* Small chip marking a row that collapses 2+ linked transactions into one. */
.link-badge { display: inline-block; margin-left: .4rem; font-size: .72rem; color: #3b5bdb; background: #eef0ff; border-radius: 1rem; padding: .05rem .5rem; white-space: nowrap; }

/* Floating bulk-action bar (register pages): appears at the bottom once one or more rows are checked. */
.bulk-bar {
    position: fixed; left: 50%; bottom: 1.25rem; transform: translateX(-50%); z-index: 1002;
    display: flex; align-items: center; gap: .4rem;
    background: #12151c; color: #fff; border-radius: .6rem; padding: .5rem .6rem;
    box-shadow: 0 8px 24px rgba(0,0,0,.35);
}
/* Being position:fixed, the bulk bar reserves no space of its own — without this, it floats on top
   of (and makes unclickable) whatever row happens to be at the bottom of the table once one or more
   rows are selected. Reserves roughly the bar's own height + its bottom offset so the last row
   always clears it. */
.table-scroll.has-bulk-bar { padding-bottom: 4.5rem; }

/* Shown below the register table whenever a search/filter is active — matches real YNAB's own
   "some transactions are hidden" wording, giving an explicit, discoverable way back to the full
   list beyond the small ✕ in the search box. */
.search-hidden-notice { display: flex; align-items: center; gap: .5rem; padding: .5rem 0; color: #6c757d; font-size: .85rem; }
.bulk-bar .bulk-count { font-weight: 700; padding: 0 .6rem 0 .3rem; white-space: nowrap; }
.bulk-bar button { background: none; border: none; color: #fff; font-weight: 600; padding: .4rem .8rem; border-radius: .4rem; cursor: pointer; white-space: nowrap; }
.bulk-bar button:hover { background: rgba(255,255,255,.14); }
.bulk-bar .bulk-close { color: #adb5bd; font-weight: 400; padding: .4rem .5rem; }

/* "Flag" / "More" flyouts off the bulk bar — anchored to their own trigger button, opening upward
   since the bulk bar itself is pinned to the bottom of the viewport. */
.bulk-more-wrap { position: relative; }
.bulk-more-menu {
    position: absolute; bottom: calc(100% + .5rem); right: 0; z-index: 1003; min-width: 230px;
    background: #fff; border-radius: .5rem; box-shadow: 0 10px 30px rgba(0,0,0,.3); padding: .35rem 0;
    color: #212529;
}
.bulk-more-menu .bm-item {
    display: flex; align-items: center; gap: .6rem; width: 100%; text-align: left; border: none;
    background: none; padding: .55rem .9rem; font-size: .85rem; font-weight: 500; color: #212529;
    cursor: pointer; white-space: nowrap;
}
.bulk-more-menu .bm-item:hover { background: #f1f3f5; }
.bulk-more-menu .bm-item:disabled { color: #adb5bd; cursor: default; }
.bulk-more-menu .bm-item:disabled:hover { background: none; }
.bulk-more-menu .bm-item.bm-danger { color: #e03131; }
.bulk-more-menu .bm-icon { width: 1.1rem; text-align: center; flex-shrink: 0; }
.bulk-more-menu .bm-arrow { margin-left: auto; color: #adb5bd; }
.bulk-more-menu .bm-sep { border: none; border-top: 1px solid #e9ecef; margin: .3rem 0; }
.bulk-more-menu .bm-submenu { background: #f8f9fa; padding: .2rem 0; }
.bulk-more-menu .bm-subitem { padding-left: 2.3rem; font-weight: 400; }
.flag-swatch { display: inline-block; width: .85rem; height: .85rem; border-radius: 50%; flex-shrink: 0; }

.balance-header { display: flex; align-items: center; gap: 1.25rem; }
.balance-header .bh-item .amount { font-weight: 700; font-size: 1.1rem; color: #2f9e44; }
.balance-header .bh-item .amount.neg { color: #e03131; }
.balance-header .bh-item .label { font-size: .72rem; color: #868e96; text-transform: uppercase; }
.balance-header .bh-op { font-size: 1.2rem; color: #adb5bd; }

.upcoming { border: 1px solid #e9ecef; border-radius: .4rem; margin-bottom: .75rem; }
.upcoming-header { width: 100%; text-align: left; background: #f1f3f5; border: none; padding: .4rem .75rem; font-weight: 600; border-radius: .4rem; }
.upcoming-row td { color: #495057; font-style: italic; }

/* Not scoped to .register-table — the same editor row is shared with the Gepland (scheduled) list's
   table too (see AccountRegister.razor's editorRow), which doesn't have that class. Split rows keep
   the same background as their parent editor row (previously overridden back to near-white here,
   which visually disconnected them from the row they belong to). */
.editor-row td, .split-row td { background: #fff8e1; padding: .5rem; }

/* The whole editor lives in one colspan'd <td> (see AccountRegister.razor) — a <tr>/<td> with
   display:flex overridden directly shrinks to its content width instead of the table's width (a
   <tr> inside a table-row-group doesn't stretch to 100% the way a block element would), which
   collapsed the editor into a single narrow column. Flexing this wrapper div instead sidesteps
   the table layout algorithm entirely, same as .scheduled-editor below. */
.tx-editor, .scheduled-editor { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; padding: .4rem 0; }
/* .register-table lives inside .table-scroll (overflow-x: auto) and is genuinely wider than the
   screen — the OTHER (read-only) rows' column widths force that, regardless of what the editor row
   itself does, so flex-wrap alone still wraps at that wide table's width, not the screen's. Pinning
   .tx-editor to the scroll container's own left edge and sizing it to that container's own (i.e.
   the un-scrolled, actually-visible) width via a container query makes it wrap at a sane width and
   stay fully on-screen, using all of the space actually available, without the user ever needing to
   scroll .table-scroll sideways to reach it. (.scheduled-editor doesn't need this — its table isn't
   in a .table-scroll, so it's never wider than the screen to begin with.) The min(94vw, …) is a
   fallback for browsers without container query support — cqw silently overrides it where supported. */
.tx-editor { position: sticky; left: 0; width: min(94vw, 460px); width: 100cqw; box-sizing: border-box; }
.tx-editor > select, .tx-editor > input, .tx-editor > span, .tx-editor > .category-picker-trigger,
.scheduled-editor > select, .scheduled-editor > input, .scheduled-editor > .category-picker-trigger { flex: 1 1 140px; min-width: 110px; }
.tx-editor > .date-repeat-wrap, .scheduled-editor > .date-repeat-wrap { flex: 0 0 auto; min-width: 150px; }
.tx-editor > .tx-editor-payee { flex: 1 1 170px; min-width: 140px; position: relative; }
/* Outflow/inflow are short, fixed-content fields — they don't need to grow like the text fields
   above, and giving them flex-grow: 1 like everything else meant that when the row was one field too
   wide to fit (6 fields is tight even on a full-width table), whichever amount field wrapped to its
   own line had nothing to share that line with and grew to fill it entirely. flex-grow: 0 keeps them
   compact regardless; the smaller basis also means the row overall needs less width to fit all its
   fields on one line before wrapping is needed at all. */
.tx-editor > input.amount-field, .scheduled-editor > input.amount-field { flex: 0 1 90px; min-width: 80px; }
.tx-editor > .tx-editor-actions, .scheduled-editor > .tx-editor-actions { flex: 1 0 100%; display: flex; gap: .4rem; flex-wrap: wrap; }

.payee-cell { position: relative; }
.payee-cell.open { z-index: 1050; }               /* lift the cell above the click-catcher backdrop */
.pd-backdrop { position: fixed; inset: 0; z-index: 1040; background: transparent; }
.payee-dropdown {
    position: absolute; z-index: 1051; top: 100%; left: 0; min-width: 240px; max-height: 280px; overflow-y: auto;
    background: #fff; border: 1px solid #dee2e6; border-radius: .4rem; box-shadow: 0 6px 20px rgba(0,0,0,.12); padding: .25rem 0;
}
/* .pd-* rules aren't scoped under .payee-dropdown — they're also reused by the category picker
   below, which lives inside a centered Popup rather than an anchored dropdown, so it can't share
   .payee-dropdown's own position:absolute (that would place it relative to the Popup card instead
   of the trigger, off-screen). Standalone classes let both contexts use the same look. */
.pd-create { display: block; width: 100%; text-align: left; border: none; background: none; color: #3b5bdb; font-weight: 600; padding: .4rem .75rem; }
.pd-item {
    display: flex; align-items: center; justify-content: space-between; gap: .5rem;
    width: 100%; text-align: left; border: none; background: none; padding: .35rem .75rem; color: #212529;
}
.pd-item:hover, .pd-create:hover { background: #f1f3f5; }
.pd-item.selected { background: #eef2ff; font-weight: 600; }
.pd-amount { color: #868e96; font-variant-numeric: tabular-nums; white-space: nowrap; flex: 0 0 auto; }
.pd-section { font-size: .68rem; text-transform: uppercase; letter-spacing: .05em; color: #868e96; padding: .4rem .75rem .15rem; }
.pd-manage { display: block; padding: .4rem .75rem; color: #3b5bdb; border-top: 1px solid #f1f3f5; margin-top: .25rem; }
.pd-actions { padding: .4rem .75rem; border-top: 1px solid #f1f3f5; margin-top: .25rem; }

/* Category picker popup (see AccountRegister.razor's CategoryPickerBody): "+ New category" and the
   search field stay in normal (non-scrolling) flow above the list, Split stays below it — only
   .category-picker-list itself scrolls, so neither pinned action can end up out of reach behind a
   long category list. Negative margin cancels .popup-body's own padding so .pd-item rows can hug
   the popup's edges edge-to-edge, matching how they look inside .payee-dropdown. */
.category-picker-list { max-height: 40vh; overflow-y: auto; margin: 0 -1rem; }
.category-picker-newbtn { border-radius: .3rem; }
.category-picker-split { border-top: 1px solid #f1f3f5; margin: .5rem -1rem 0; padding: .6rem 1rem 0; }

/* Register toolbar's smart search — reuses .payee-dropdown's look via .search-dropdown so
   suggestions read consistently with the payee autocomplete elsewhere in the register. */
.search-wrap { position: relative; width: 220px; max-width: 60vw; }
.search-clear { position: absolute; right: .4rem; top: 50%; transform: translateY(-50%); background: none; border: none; color: #868e96; cursor: pointer; padding: 0; line-height: 1; }
.search-dropdown { left: auto; right: 0; width: 100%; min-width: 260px; }
.search-dropdown .pd-field-label { color: #868e96; font-size: .78rem; margin-right: .25rem; }

/* Date field's repeat toggle — the "Repeat" picker stays hidden until the user opens it, matching
   real YNAB where it lives inside the date popup rather than as a persistently-visible extra field. */
.date-repeat-wrap { position: relative; display: flex; align-items: center; gap: .3rem; }
.date-repeat-wrap input[type="date"] { flex: 1; min-width: 0; }
.date-repeat-toggle { background: none; border: none; cursor: pointer; padding: .1rem .2rem; font-size: .9rem; line-height: 1; opacity: .45; border-radius: .3rem; }
.date-repeat-toggle:hover { opacity: .8; background: #f1f3f5; }
.date-repeat-toggle.active { opacity: 1; }
.date-repeat-popup {
    position: absolute; z-index: 1051; top: 100%; left: 0; margin-top: .2rem; min-width: 200px;
    background: #fff; border: 1px solid #dee2e6; border-radius: .4rem; box-shadow: 0 6px 20px rgba(0,0,0,.12); padding: .5rem;
}

/* Reusable centered popup/modal (no Bootstrap JS in this app — pure CSS + Blazor toggles) */
.popup-backdrop { position: fixed; inset: 0; z-index: 1300; background: rgba(0,0,0,.45); }
.popup-card {
    position: fixed; z-index: 1301; top: 50%; left: 50%; transform: translate(-50%, -50%);
    background: #fff; border-radius: .6rem; box-shadow: 0 12px 40px rgba(0,0,0,.25);
    width: min(420px, 92vw); max-height: 88vh; overflow-y: auto;
}
.popup-card.category-activity-popup {
    width: min(750px, 92vw);
}
/* Category Activity Popup Table — fixed layout + truncation mirrors .register-table so the
   table always fits the 750px popup instead of forcing a horizontal scrollbar. Full values
   remain available via each truncated cell's title attribute. */
.category-activity-table {
    table-layout: fixed;
    width: 100%;
    border-collapse: collapse;
    font-size: 0.875rem;
}

.category-activity-table thead th {
    background-color: #f5f5f5;
    font-weight: 600;
    text-transform: uppercase;
    font-size: 0.75rem;
    letter-spacing: 0.05em;
    padding: 0.5rem 0.75rem;
    border-bottom: 2px solid #e0e0e0;
    text-align: left;
}

/* Column widths for desktop (750px popup) */
.category-activity-table thead th:nth-child(1) { width: 12%; }
.category-activity-table thead th:nth-child(2) { width: 24%; }
.category-activity-table thead th:nth-child(3) { width: 18%; }
.category-activity-table thead th:nth-child(4) { width: 32%; }
.category-activity-table thead th:nth-child(5) { width: 14%; }

.category-activity-table tbody td {
    padding: 0.625rem 0.75rem;
    border-bottom: 1px solid #f0f0f0;
    vertical-align: middle;
}

.category-activity-table td.truncate {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.category-activity-table td.nowrap {
    white-space: nowrap;
}

.category-activity-table tbody tr:hover {
    background-color: #fafafa;
}

.category-activity-table tfoot td {
    font-weight: 600;
    padding: 0.75rem;
    border-top: 2px solid #e0e0e0;
}

.category-activity-table .neg { color: var(--ynab-red); }
.category-activity-table .pos { color: var(--ynab-green); }

.category-activity-footer {
    display: flex;
    justify-content: flex-end;
    margin-top: 1rem;
    padding-top: 1rem;
    border-top: 1px solid #e0e0e0;
}

.category-activity-footer .btn {
    padding: 0.5rem 1.5rem;
}

/* Credit Card Activity window (a Payment category's Activity popup): a small account-name
   header, a 2×2 summary grid, and a 4-column table (DATE | MEMO | CATEGORY | AMOUNT). */
.cc-activity-account {
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: #868e96;
    margin-bottom: 0.5rem;
}
.cc-activity-summary {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}
.cc-activity-metric {
    background: #f8f9fa;
    border: 1px solid #e9ecef;
    border-radius: 0.4rem;
    padding: 0.5rem 0.7rem;
    display: flex;
    flex-direction: column;
}
.cc-activity-label {
    font-size: 0.7rem;
    color: #868e96;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-bottom: 0.15rem;
}
.cc-activity-value {
    font-weight: 700;
    font-size: 1rem;
    white-space: nowrap;
}
.cc-activity-value.neg { color: var(--ynab-red); }
.cc-activity-value.pos { color: var(--ynab-green); }
.cc-activity-breakdown {
    display: flex;
    gap: 0.75rem;
    font-size: 0.72rem;
    color: #868e96;
    margin-top: 0.2rem;
}

/* The credit-card table drops the Payee/Account columns, so its four columns rebalance to the
   DATE/MEMO/CATEGORY/AMOUNT mix instead of inheriting the generic 5-column widths above. */
.cc-activity-table thead th:nth-child(1) { width: 14%; }
.cc-activity-table thead th:nth-child(2) { width: 34%; }
.cc-activity-table thead th:nth-child(3) { width: 34%; }
.cc-activity-table thead th:nth-child(4) { width: 18%; }

/* Phone / narrow MAUI window: 5 columns is too cramped — drop the context-only Account
   column and redistribute widths to avoid horizontal overflow. Also reduce cell padding. */
@media (max-width: 600px) {
    .category-activity-table .account-col {
        display: none;
    }
    .category-activity-table thead th,
    .category-activity-table tbody td {
        padding-left: 0.4rem;
        padding-right: 0.4rem;
    }
    .category-activity-table thead th:nth-child(1) { width: 27%; }
    .category-activity-table thead th:nth-child(2) { width: 26%; }
    .category-activity-table thead th:nth-child(4) { width: 26%; }
    .category-activity-table thead th:nth-child(5) { width: 21%; }
    /* The credit-card table is 4 columns, so it can't inherit the generic widths above — give it
       its own mobile mix (DATE/MEMO/CATEGORY/AMOUNT) that sums to 100% in the fixed layout. */
    .category-activity-table.cc-activity-table thead th:nth-child(1) { width: 24%; }
    .category-activity-table.cc-activity-table thead th:nth-child(2) { width: 26%; }
    .category-activity-table.cc-activity-table thead th:nth-child(3) { width: 28%; }
    .category-activity-table.cc-activity-table thead th:nth-child(4) { width: 22%; }
}
/* The move-money popup's category dropdown is an absolutely-positioned overlay that can extend
   past the popup card's own height — it has its own internal scroll, so let it escape the card's
   clipping instead of being cut off. */
.popup-card:has(.move-dropdown-wrap) { overflow: visible; }
.popup-card:has(.filtered-category-selector) { overflow: visible; }
.popup-header { display: flex; align-items: center; justify-content: space-between; padding: .9rem 1rem; border-bottom: 1px solid #e9ecef; }
.popup-title { font-weight: 700; }
.popup-close { background: none; border: none; font-size: 1rem; color: #868e96; cursor: pointer; line-height: 1; padding: .2rem; }
.popup-close:hover { color: #212529; }
.popup-body { padding: 1rem; }

/* Header (SyncBar) budget/account switcher */
.acct-menu-trigger { display: flex; flex-direction: column; align-items: flex-start; background: none; border: none; color: #fff; cursor: pointer; padding: 0; line-height: 1.15; }
.acct-menu-trigger .bn { font-weight: 700; font-size: .95rem; }
.acct-menu-trigger .em { font-size: .72rem; color: #adb5bd; }
.acct-menu-wrap { position: relative; }
.acct-menu {
    position: absolute; z-index: 1301; top: 100%; left: 0; margin-top: .4rem; min-width: 220px;
    background: #fff; border-radius: .5rem; box-shadow: 0 6px 20px rgba(0,0,0,.2); padding: .3rem 0; color: #212529;
}
.acct-menu button { display: block; width: 100%; text-align: left; border: none; background: none; padding: .5rem .9rem; font-size: .88rem; color: #212529; }
.acct-menu button:hover { background: #f1f3f5; }
.acct-menu hr { margin: .3rem 0; border-color: #e9ecef; }

.plan-list { list-style: none; margin: 0; padding: 0; }
.plan-list li button { display: block; width: 100%; text-align: left; border: none; background: #f8f9fa; border-radius: .4rem; padding: .6rem .8rem; margin-bottom: .4rem; }
.plan-list li button:hover { background: #e9ecef; }
.plan-list li button.active { background: #dbe4ff; font-weight: 600; }

.payee-list { max-height: 70vh; overflow-y: auto; }
.rules-box { border: 1px solid #e9ecef; border-radius: .4rem; padding: .75rem; }

.net-worth { color: #495057; }
.bar { height: 14px; background: var(--ynab-primary); border-radius: 3px; }

/* ===================== YNAB-style mobile app UI ===================== */
:root { --ynab-green2: #8bc34a; --ynab-red2: #e53935; }

/* Bottom tab bar (mobile only) */
.bottom-tabs { display: none; }
@media (max-width: 820px) {
    .bottom-tabs {
        display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 1000;
        background: #12151c; border-top: 1px solid #23283400; padding: .25rem 0 .35rem;
    }
    .bottom-tabs a {
        flex: 1; text-align: center; text-decoration: none; color: #8a93a3; font-size: .68rem;
        display: flex; flex-direction: column; align-items: center; gap: .1rem; padding: .15rem 0;
    }
    .bottom-tabs a .ico { font-size: 1.15rem; }
    .bottom-tabs a.active { color: #fff; }
    .ynab-content { padding-bottom: 4.5rem !important; }
}

/* Plan header: month selector + Ready to Assign pill */
.plan-header { display: flex; align-items: center; gap: .75rem; margin-bottom: .75rem; }
.month-select { display: flex; align-items: center; gap: .5rem; font-weight: 700; font-size: 1.05rem; }
.month-select button { background: none; border: none; color: inherit; font-size: 1.3rem; line-height: 1; cursor: pointer; padding: 0 .25rem; }
.rta-pill {
    display: flex; align-items: center; justify-content: space-between; flex: 1;
    border-radius: 2rem; padding: .6rem 1.1rem; color: #12321a; font-weight: 700;
    background: var(--ynab-green2);
}
.rta-pill.neg { background: var(--ynab-red2); color: #fff; }
.rta-pill .rta-amount { font-size: 1.15rem; }
.rta-pill .rta-label { font-weight: 600; opacity: .85; }

.overspent-banner {
    display: flex; align-items: center; justify-content: space-between; gap: .5rem;
    background: #2a2140; color: #fff; border-radius: .6rem; padding: .5rem .9rem; margin-bottom: .75rem;
}
.overspent-banner .count { background: var(--ynab-red2); border-radius: 1rem; padding: .05rem .55rem; font-weight: 700; margin-right: .4rem; }
.overspent-banner .cover { background: #3b3170; color: #c9c2ff; border: none; border-radius: 1.2rem; padding: .3rem 1rem; font-weight: 600; }

/* Category groups + rows */
.cat-group-h {
    display: flex; align-items: center; justify-content: space-between;
    padding: .6rem .25rem .3rem; font-weight: 700; cursor: pointer;
}
.cat-group-h .sub { font-size: .68rem; color: #8a93a3; text-align: right; font-weight: 500; line-height: 1.1; }
.cat-card { padding: .55rem .25rem; border-top: 1px solid #e9ecef; }
.cat-top { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.cat-name { font-weight: 600; }
.cat-avail {
    min-width: 74px; text-align: center; border-radius: 1.2rem; padding: .15rem .7rem; font-weight: 700; white-space: nowrap;
    background: #e9ecef; color: #495057;
}
.cat-avail.pos { background: var(--ynab-green2); color: #12321a; }
.cat-avail.neg { background: var(--ynab-red2); color: #fff; }
.cat-progress { height: 6px; border-radius: 3px; background: #e0e3e8; margin: .4rem 0 .2rem; overflow: hidden; }
.cat-progress > span { display: block; height: 100%; background: var(--ynab-green2); }
.cat-progress.over > span { background: var(--ynab-red2); }
.cat-status { font-size: .72rem; color: #8a93a3; }
.assign-inline { display: flex; gap: .4rem; align-items: center; margin-top: .5rem; }
.assign-inline input { width: 130px; text-align: right; }

/* Spending list */
.spend-banner {
    display: flex; align-items: center; justify-content: space-between;
    background: #1b2130; color: #dfe4ee; border-radius: .8rem; padding: .6rem 1rem; margin-bottom: .6rem;
}
.spend-banner .n { background: #34406a; border-radius: 1rem; padding: .05rem .55rem; font-weight: 700; margin-right: .5rem; }
.spend-banner .action { background: #3b3170; color: #cdd3ff; border: none; border-radius: 1.2rem; padding: .3rem 1rem; font-weight: 600; }
.spend-secondary { display:flex; align-items:center; justify-content:space-between; background:#161b26; color:#aeb6c4; border-radius:.8rem; padding:.55rem 1rem; margin-bottom:.6rem; }
.spend-date { font-weight: 700; margin: .8rem .1rem .35rem; color: #495057; }
.spend-card { display: flex; gap: .1rem; flex-direction: column; padding: .6rem .1rem; border-bottom: 1px solid #e9ecef; border-left: 3px solid transparent; }
.spend-card.unapproved { border-left-color: var(--ynab-primary); }
.spend-row1 { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.spend-payee { font-weight: 600; }
.spend-amt.neg { color: var(--ynab-red2); font-weight: 600; }
.spend-amt.pos { color: #2f9e44; font-weight: 600; }
.spend-row2 { display: flex; align-items: center; justify-content: space-between; gap: .5rem; color: #8a93a3; font-size: .82rem; }
.chip { background: #eef0f3; color: #495057; border-radius: 1rem; padding: .1rem .6rem; font-size: .78rem; }
.cleared-dot { width: 18px; height: 18px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-size: .7rem; font-weight: 700; }
.cleared-dot.c { background: #d3f9d8; color: #2b8a3e; }
.cleared-dot.u { border: 1px solid #ced4da; color: #ced4da; }
.cleared-dot.r { background: #d0ebff; color: #1971c2; }

.fab {
    position: fixed; right: 1rem; bottom: 4.6rem; z-index: 1001;
    background: var(--ynab-primary); color: #fff; border: none; border-radius: 2rem;
    padding: .7rem 1.2rem; font-weight: 700; box-shadow: 0 6px 18px rgba(0,0,0,.25);
}
@media (min-width: 821px) { .fab { bottom: 1.5rem; } }

/* Accounts (YNAB style) */
.acct-total-h { display: flex; align-items: center; justify-content: space-between; font-weight: 700; margin: 1rem .1rem .35rem; }
.acct-total-h .sum { color: #2f9e44; }
.acct-list-item { display: flex; align-items: center; gap: .75rem; padding: .7rem .25rem; border-top: 1px solid #e9ecef; text-decoration: none; color: inherit; }
.acct-ico { width: 34px; height: 34px; border-radius: 50%; background: #2f5e2f22; color: #2f9e44; display: inline-flex; align-items: center; justify-content: center; }
.acct-list-item .nm { flex: 1; font-weight: 500; }
.acct-list-item .bal { font-weight: 700; color: #2f9e44; }
.acct-list-item .bal.neg { color: var(--ynab-red2); }
.acct-unappr-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--ynab-primary); }

/* Overview ("Home") page. The hero banner is the one deliberately dark, gradient-branded surface
   outside the nav/sync bar — everything below it (Pinned/Goal/Summary/Future cards) stays in the
   app's normal light card style so the rest of the page doesn't fork the whole app's theme. Not
   scoped to any width — like most pages, Overview is the same mobile-app-style layout throughout. */
.ov-hero {
    background: linear-gradient(135deg, var(--ynab-green), var(--ynab-nav) 75%);
    color: #fff; border-radius: .6rem; padding: 1rem 1.1rem; margin-bottom: 1rem;
}
.ov-greeting { font-size: 1.15rem; font-weight: 700; }
.ov-subtitle { color: rgba(255,255,255,.75); font-size: .85rem; margin-bottom: .75rem; }
.ov-todo-row {
    display: flex; align-items: center; justify-content: space-between; gap: .5rem;
    background: rgba(255,255,255,.08); border-radius: .5rem; padding: .55rem .75rem; margin-bottom: .5rem;
}
.ov-todo-row:last-child { margin-bottom: 0; }
.ov-badge {
    display: inline-block; background: rgba(255,255,255,.16); border-radius: 1rem;
    padding: .1rem .55rem; font-weight: 700; margin-right: .4rem; font-size: .85rem;
}
.ov-badge-money { background: var(--ynab-green); }
.ov-pill {
    background: var(--ynab-primary); color: #fff; border: none; border-radius: 1rem;
    padding: .35rem .9rem; font-weight: 600; font-size: .85rem; white-space: nowrap;
}

.ov-card-header { font-weight: 700; margin-bottom: .5rem; }
.ov-empty { text-align: center; padding: .5rem 0 .25rem; }
.ov-empty-title { font-weight: 600; margin-bottom: .2rem; }
.ov-empty-body { color: #868e96; font-size: .85rem; margin-bottom: .6rem; }
.ov-pinned-row { display: flex; justify-content: space-between; padding: .4rem 0; border-bottom: 1px solid #f1f3f5; }
.ov-pinned-row:last-of-type { border-bottom: none; }
.ov-pinned-row .neg { color: var(--ynab-red); }

.ov-goal-name { font-weight: 600; margin-bottom: .4rem; }
.ov-goal-bar { background: #f1f3f5; border-radius: 1rem; height: .5rem; overflow: hidden; margin-bottom: .35rem; }
.ov-goal-fill { background: var(--ynab-green); height: 100%; border-radius: 1rem; }
.ov-goal-detail { color: #868e96; font-size: .85rem; }

.ov-stat-grid { display: grid; grid-template-columns: 1fr 1fr; gap: .6rem; }
.ov-stat-card { background: #fff; border: 1px solid #e9ecef; border-radius: .5rem; padding: .7rem .8rem; }
.ov-stat-label { color: #868e96; font-size: .78rem; margin-bottom: .2rem; }
.ov-stat-value { font-weight: 700; font-size: 1.05rem; }
.ov-stat-value.neg { color: var(--ynab-red); }

/* ===================== Plan page: desktop table layout ===================== */
/* Mobile-first: the desktop block only takes over at the 1024px breakpoint below.
   Below that width the existing card-based .plan-mobile markup (above) is unchanged. */
.plan-desktop { display: none; }

@media (min-width: 1024px) {
    .plan-mobile { display: none; }
    /* .ynab-content is the page's own scrolling viewport (it has real, bounded height via flexbox —
       see .ynab-shell/.ynab-main). Rather than juggling several independently-`position: sticky`
       elements (which fought each other and leaked a sliver of scrolled-past content through
       .ynab-content's own padding), .plan-desktop fills that viewport exactly and only
       .plan-table-rows scrolls internally — the toolbar, table header, and side panel are all in
       normal, non-scrolling flow, so nothing needs a hand-measured "stick below this" offset.
       flex: 1 (not height: 100%) deliberately — a percentage height only resolves once every
       ancestor up to .ynab-shell has an unambiguous definite height, and .plan-desktop ended up
       taller than the real viewport in practice (its sticky toolbar's own height wasn't being
       subtracted, pushing the bottom rows below the visible area with no way to scroll to them).
       flex: 1 makes .ynab-content (now itself display:flex; flex-direction:column) hand .plan-desktop
       exactly its remaining space directly via the flex algorithm, sidestepping that resolution
       entirely — .plan-mobile is display:none at this breakpoint, so .plan-desktop is the only flex
       item actually competing for that space. */
    .plan-desktop { display: flex; flex-direction: column; flex: 1; min-height: 0; }

    .plan-sticky-toolbar { flex: 0 0 auto; }
    .plan-toolbar-top { display: flex; align-items: center; gap: 1rem; margin-bottom: .75rem; }
    .plan-month-switch { display: flex; align-items: center; gap: .35rem; font-weight: 700; font-size: 1.05rem; flex-shrink: 0; }
    .plan-month-switch button { background: none; border: none; color: inherit; cursor: pointer; }
    .plan-month-switch .plan-month-label { font-weight: 700; font-size: 1.05rem; padding: .1rem .4rem; border-radius: .3rem; }
    .plan-month-switch .plan-month-label:hover { background: #e9ecef; }
    .plan-note { flex: 1; min-width: 0; }
    .plan-note-text { color: #868e96; cursor: text; }
    .plan-note-text:hover { color: #495057; }
    .plan-toolbar-top .rta-pill { flex: 0 0 auto; min-width: 220px; }

    .plan-filter-bar { display: flex; gap: .4rem; margin-bottom: .6rem; flex-wrap: wrap; }
    .plan-toolbar { display: flex; align-items: center; gap: .25rem; margin-bottom: .5rem; }
    .plan-toolbar .flex-spacer { flex: 1; }
    .plan-view-toggle { display: flex; gap: .25rem; }

    .plan-main { display: flex; gap: 1rem; align-items: stretch; flex: 1; min-height: 0; }
    .plan-table {
        flex: 1; min-width: 0; display: flex; flex-direction: column; min-height: 0;
        background: #fff; border-radius: .5rem; box-shadow: 0 1px 3px rgba(0,0,0,.08);
    }
    .plan-table-header, .plan-group-row, .plan-category-row {
        display: grid; grid-template-columns: minmax(0,2fr) repeat(3, minmax(0,1fr)); align-items: center; gap: .5rem;
    }
    .plan-table-header {
        flex: 0 0 auto; padding: .5rem .9rem; font-size: .72rem; text-transform: uppercase; letter-spacing: .04em; color: #868e96;
        border-bottom: 1px solid #e9ecef; background: #fff; border-top-left-radius: .5rem; border-top-right-radius: .5rem;
    }
    /* Only the rows scroll — the toolbar, table header, and side panel all stay in normal flow
       above/beside this, so no sticky-offset coordination between them is needed at all. */
    /* overscroll-behavior: contain stops wheel/touch scroll from chaining out to .ynab-content (and
       from there potentially to the page) once this list hits its own top/bottom — without it, the
       last row could feel like it "escapes" into the ynab-content/page scroll instead of stopping
       cleanly at the bottom of this list. */
    .plan-table-rows { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; border-bottom-left-radius: .5rem; border-bottom-right-radius: .5rem; }
    .plan-col-num { text-align: right; }
    .plan-group-row { padding: .5rem .9rem; background: #f1f3f5; font-weight: 700; cursor: pointer; }
    .plan-category-row { padding: .45rem .9rem; border-top: 1px solid #f1f3f5; cursor: pointer; }
    .plan-category-row:hover { background: #f8f9fa; }
    .plan-category-row.selected { background: #dbe4ff; }
    .plan-category-row .plan-col-num.neg { color: var(--ynab-red); }
    .plan-category-row .plan-col-num.pos { color: var(--ynab-green); }
    .plan-category-row .plan-col-num.status-funded { color: var(--ynab-green); }
    .plan-category-row .plan-col-num.status-underfunded { color: var(--ynab-yellow); }
    .plan-category-row .plan-col-num.status-overspent { color: var(--ynab-red); }

    /* Available column pill badges (YNAB-style): a colored, rounded chip around the amount instead
       of just colored text, with a small icon for goal states that need one at a glance. */
    .plan-available-badge {
        display: inline-flex; align-items: center; gap: .3rem; padding: .2rem .65rem;
        border-radius: 1rem; font-weight: 600; background: #f3ede4; color: #6b6355;
    }
    .plan-available-icon { font-size: .8em; line-height: 1; }
    /* Fills in (like a pie timer) as the goal's percent-funded climbs, rather than a static icon. */
    .plan-available-radial {
        width: .85em; height: .85em; border-radius: 50%; flex-shrink: 0;
        background: conic-gradient(currentColor calc(var(--pct, 0) * 1%), rgba(0,0,0,.15) 0);
    }
    .plan-available-badge.badge-overspent { background: #fadbd8; color: var(--ynab-red); }
    .plan-available-badge.badge-funded, .plan-available-badge.badge-snoozed { background: #d3f9d8; color: var(--ynab-green); }
    .plan-available-badge.badge-underfunded { background: #fff3bf; color: #a97a00; }

    /* Single, non-segmented bar — used for goals with 0 or 1 period this month (Monthly/Yearly/
       Custom-RepeatingFunding/Custom-Balance). */
    .plan-progress-bar { height: 4px; border-radius: 2px; background: #e0e3e8; margin-top: .1rem; overflow: hidden; }
    /* Make the name cell a flex row so the checkbox and the name-line sit side-by-side
       on a single line (previously the block-level .plan-row-name-line wrapped below
       the inline checkbox). gap:0 — spacing is per-element so the progress bar can sit
       closer to the name line. The progress bar wraps to its own line and is indented
       past the checkbox so it aligns under the name, not under the checkbox. */
    .plan-category-row .plan-col-name { display: flex; align-items: center; gap: 0; min-width: 0; flex-wrap: wrap; }
    .plan-row-name-line { display: flex; justify-content: space-between; align-items: baseline; gap: .5rem; flex: 1 1 auto; min-width: 0; }
    .plan-category-row .plan-col-name .plan-progress-bar { flex: 0 0 calc(100% - 3rem); margin-left: 3rem; }
    .plan-row-name-wrap { display: inline-flex; align-items: baseline; gap: .3rem; flex: 1 1 auto; min-width: 0; overflow: hidden; }
    .plan-row-name-wrap > span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .plan-row-status { flex: 0 0 auto; font-size: .72rem; color: #868e96; text-align: right; white-space: nowrap; }
    .plan-row-status.status-funded { color: var(--ynab-green); }
    .plan-row-status.status-underfunded { color: var(--ynab-yellow); }
    .plan-progress-bar > span { display: block; height: 100%; background: var(--ynab-primary); }
    .plan-progress-bar.status-funded > span { background: var(--ynab-green); }
    .plan-progress-bar.status-underfunded > span { background: var(--ynab-yellow); }
    .plan-progress-bar.status-overspent > span { background: var(--ynab-red); }

    /* Segmented bar — one block per period (e.g. one per Saturday for a weekly goal), so you can
       see at a glance how many of this month's periods are funded. A block whose due date has
       already passed renders hollow (outline only) instead of filled — its funding state stops
       being tracked once the period itself is over. */
    .plan-progress-bar.segmented { display: flex; gap: 3px; background: none; overflow: visible; }
    .plan-progress-bar.segmented .plan-segment {
        flex: 1; height: 100%; border-radius: 1px; border: 1.5px solid #ced4da;
        background: transparent; position: relative; overflow: hidden; box-sizing: border-box;
    }
    .plan-progress-bar.segmented .plan-segment::after {
        content: ""; position: absolute; inset: 0; width: calc(var(--fill, 0) * 100%); background: currentColor;
    }
    .plan-progress-bar.segmented.status-funded .plan-segment { border-color: var(--ynab-green); color: var(--ynab-green); }
    .plan-progress-bar.segmented.status-underfunded .plan-segment { border-color: var(--ynab-yellow); color: var(--ynab-yellow); }
    .plan-progress-bar.segmented.status-overspent .plan-segment { border-color: var(--ynab-red); color: var(--ynab-red); }
    .plan-progress-bar.segmented .plan-segment.passed::after { display: none; }

    .plan-table.compact .plan-progress-bar { display: none; }

    .plan-clickable { cursor: pointer; border-radius: .25rem; padding: .1rem .3rem; margin: -.1rem -.3rem; }
    .plan-clickable:hover { background: #e9ecef; }
    .plan-inline-input { width: 100%; text-align: right; font-size: inherit; padding: .1rem .3rem; border: 1px solid var(--ynab-primary); border-radius: .25rem; }

    /* Selection checkboxes + collapse-all icon, same visual language as the register page's own
       checkbox column (form-check-input) — the header/group/category rows are CSS grids, so these
       just sit inline at the start of the name column rather than needing a dedicated grid column. */
    .plan-table-header .form-check-input, .plan-group-row .form-check-input {
        margin-right: .5rem; vertical-align: middle; flex: 0 0 auto;
    }
    /* Category checkboxes indent to align with group names (after the collapse icon + its margin) */
    .plan-category-row .form-check-input {
        margin-left: 1.5rem; margin-right: .5rem; vertical-align: middle; flex: 0 0 auto;
    }
    .plan-collapse-all {
        background: none; border: none; padding: 0 .3rem 0 0; color: #868e96; cursor: pointer; font-size: .8rem; vertical-align: middle;
    }
    .plan-collapse-all:hover { color: #212529; }
    .plan-row-options {
        background: none; border: none; padding: 0 .2rem; color: #adb5bd; cursor: pointer; line-height: 1; flex: 0 0 auto;
    }
    .plan-row-options:hover { color: #212529; }

    /* Group row alignment — collapse icon sits in a fixed-width spacer so checkbox and name
       align exactly with category rows below */
    .plan-group-toggle {
        display: inline-flex; align-items: center; justify-content: center;
        width: 1rem; margin-right: .25rem;
        color: #868e96; font-size: .8rem; flex: 0 0 auto;
    }
    .plan-group-name {
        flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }

    /* Plus button for adding categories to a group (desktop) */
    .plan-add-category-btn {
        display: inline-flex; align-items: center; justify-content: center;
        width: 1.4rem; height: 1.4rem; border-radius: .25rem;
        background: var(--ynab-primary); color: #fff;
        border: none; font-size: 1rem; line-height: 1;
        margin-left: .25rem; opacity: 0; visibility: hidden;
        transition: opacity .15s ease, visibility .15s ease;
        flex: 0 0 auto;
    }
    .plan-group-row:hover .plan-add-category-btn {
        opacity: 1; visibility: visible;
    }
    .plan-add-category-btn:hover {
        background: var(--ynab-green);
    }

    .plan-side { flex: 0 0 320px; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
    .plan-detail-panel { background: #fff; border-radius: .5rem; padding: 1rem; box-shadow: 0 1px 3px rgba(0,0,0,.08); }
    .plan-detail-header { display: flex; align-items: center; justify-content: space-between; }
    .plan-detail-header h5 { margin: 0 0 .75rem; }
    .plan-detail-section { margin-bottom: 1rem; }
    .plan-detail-section:last-child { margin-bottom: 0; }

    /* Bulk selection panel (2+ categories checked) */
    .bulk-selected-names { color: #495057; font-size: .85rem; margin-bottom: 1rem; }
    .bulk-assign-row {
        display: flex; justify-content: space-between; align-items: center; width: 100%;
        background: none; border: none; padding: .4rem .3rem; border-radius: .3rem; text-align: left; color: #212529;
    }
    .bulk-assign-row:hover { background: #f1f3f5; }
    .bulk-assign-row:disabled { opacity: .5; cursor: default; }
    .bulk-assign-row span:last-child { font-weight: 600; }
    .plan-upcoming { background: #fff8e1; border-radius: .4rem; padding: .6rem .75rem; }
    .plan-target-section .neg { color: var(--ynab-red); }

    /* "Cost to Be Me" bars: Targets (blue, with a red overflow segment once it exceeds Expected
       Income) and Expected Income (green, filling as real income comes in) — see
       PlanMonthSummaryPanel's TargetsBlueFraction/TargetsRedFraction/IncomeGreenFraction for the
       scale/fill math these widths come from. display:flex so the two Targets segments sit side by
       side instead of stacking (the single-span .plan-progress-bar pattern only fits one segment). */
    .plan-cost-bar { display: flex; height: 6px; border-radius: 3px; background: #e0e3e8; margin-top: .3rem; overflow: hidden; }
    .plan-cost-bar .seg-blue { background: var(--ynab-primary); height: 100%; }
    .plan-cost-bar .seg-red { background: var(--ynab-red); height: 100%; }
    .plan-cost-bar .seg-green { background: var(--ynab-green); height: 100%; }

    .plan-goal-ring {
        --pct: 0; width: 84px; height: 84px; border-radius: 50%; margin: 0 auto .5rem;
        display: flex; align-items: center; justify-content: center; font-weight: 700;
        background: conic-gradient(var(--ynab-primary) calc(var(--pct) * 1%), #e9ecef 0);
    }
    .plan-goal-ring::before { content: ""; }
    .plan-goal-ring span { background: #fff; width: 64px; height: 64px; border-radius: 50%; display: flex; align-items: center; justify-content: center; }
    .plan-target-summary { text-align: center; font-weight: 600; }

    .month-picker-year { display: flex; align-items: center; justify-content: center; gap: 1rem; font-weight: 700; margin-bottom: .75rem; }
    .month-picker-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: .5rem; }

    .recent-moves-user { display: flex; align-items: center; gap: .5rem; margin-bottom: .75rem; color: #495057; }
    .recent-moves-user .avatar {
        width: 28px; height: 28px; border-radius: 50%; background: var(--ynab-primary); color: #fff;
        display: inline-flex; align-items: center; justify-content: center; font-weight: 700; font-size: .8rem;
    }
    .recent-moves-day { font-weight: 700; margin: .75rem 0 .3rem; color: #495057; font-size: .8rem; text-transform: uppercase; }
    .recent-moves-row { display: flex; justify-content: space-between; padding: .3rem 0; border-top: 1px solid #f1f3f5; font-size: .88rem; }
    .recent-moves-row .neg { color: var(--ynab-red); }
    .recent-moves-row .pos { color: var(--ynab-green); }

    .move-dropdown-wrap { position: relative; }
    .move-dropdown-trigger { text-align: left; background: #fff; cursor: pointer; }
    .move-dropdown, .category-filter-dropdown {
        position: absolute; z-index: 1310; top: 100%; left: 0; right: 0; margin-top: .25rem; max-height: 280px; overflow-y: auto;
        background: #fff; border: 1px solid #dee2e6; border-radius: .5rem; box-shadow: 0 6px 20px rgba(0,0,0,.15); padding: .4rem 0;
    }
    .move-dropdown-title { font-weight: 700; padding: .3rem .8rem .5rem; }
    .move-dropdown-group { font-size: .68rem; text-transform: uppercase; letter-spacing: .05em; color: #868e96; padding: .5rem .8rem .15rem; }
    .move-dropdown-item, .filtered-category-selector .move-dropdown-item {
        display: flex; justify-content: space-between; width: 100%; border: none; background: none;
        padding: .35rem .8rem; text-align: left; color: #212529;
    }
    .move-dropdown-item:hover, .filtered-category-selector .move-dropdown-item:hover { background: #f1f3f5; }
    .move-dropdown-item .neg, .filtered-category-selector .neg { color: var(--ynab-red); }
    .move-dropdown-item .pos, .filtered-category-selector .pos { color: var(--ynab-green); }
    .filtered-category-selector { position: relative; }
    .filtered-category-selector input.form-control { cursor: pointer; }
}
