:root{--navy:#1f7a3d;--blue:#418E5A;--ink:#172033;--muted:#697386;--line:#dfe4eb;--paper:#fff;--bg:#f4f6f9;--red:#b42318;--green:#1f7a3d;--amber:#8a5c00;--shadow:0 14px 35px rgba(24,53,99,.08);
  /* --navy/--blue were this app's original navy/blue accent pair -- every
     tab's own primary buttons, active toggles, category/bill titles,
     checkboxes, and links, not just Home/chrome. Reported directly after
     the Home-only rebrand: "some of the blue is still there... the budget
     tab is still in that blue color from before" -- so both now hold a
     Groundhog Budgeting green instead of new app-wide colors invented
     separately from the palette already chosen for Home. Every other
     tab's own IA/functionality is still untouched -- this is a color-only
     change, the same scope as every rebrand round before it, just finally
     covering the accent color everywhere rather than only inside
     #panel-home.

     --navy is deliberately this app's own pre-existing --green
     (#1f7a3d), not the brighter #2F8F5E Home first shipped with --
     reported directly, a round after the app-wide switch above: "the
     green itself is too bright/loud" next to --red, which sits beside it
     constantly (an overspent envelope, an overdue bill, a negative
     amount). --green has coexisted with --red in this exact app since
     before any rebrand work -- every positive/negative amount pair on
     Register and Budget already used this combination with no complaint
     -- so reusing it here, rather than inventing a third green to
     season-to-taste, is the one shade already proven not to clash.
     --gb-accent below is the same color for the same reason: one green
     across the whole app, not a brighter one on Home and a muted one
     everywhere else. */
  /* "Groundhog Budgeting" -- complete rebrand from "Snapshot Budgeting"/
     Midnight Gold, requested directly with a new design-canvas reference
     (Groundhog_Budgeting.dc.html) and a delivered logo (the circular
     groundhog-and-coin medallion, public/brand-mark.png and the
     icon/favicon set built from it). Scoped the same way the prior
     rebrand was: the app's persistent chrome (topbar, both nav bars) and
     the Home tab specifically -- every other tab's own panel content
     stays untouched, including the renamed "Dens" nav label, which is a
     label + color change only, not a rebuild of the Budget tab's own
     functionality.

     Switched from the dark palette to light here -- reported directly
     ("i dont like the dark green with red in dark mode at all"), against
     a second reference file (Groundhog_Budgeting - standalone.html) that
     carried both a dark and a light variant of these same two screens.
     Every --gb-* value below is the light variant's own token, read
     directly off that file, not a guess at what "light" should be. The
     red used for negative/overspent figures is this app's own existing
     --red (already the negative-amount color everywhere else in this
     file) rather than a fourth invented red, since the light reference
     doesn't show an overspent example of its own to copy one from. */
  --gb-bg:#F5FAF6;--gb-surface:#FFFFFF;--gb-surface-border:#E1EEE4;--gb-nav-border:#E1EEE4;
  --gb-ink:#1C2E22;--gb-muted:#6E8577;--gb-inactive:#A3B6AB;--gb-accent:#1f7a3d;--gb-track:#E1EEE4}
*{box-sizing:border-box}
/* Self-hosted (not linked to fonts.googleapis.com) -- this app's own CSP is
   default-src 'self' with no exception carved out for a font CDN, and
   self-hosting means the Home tab's own Poppins text never depends on a
   third-party request succeeding at all, matching the CSP's own existing
   "nothing here but this origin" posture rather than loosening it. Only
   the latin subset: this app's own UI text is plain English throughout.
   Poppins ships as one static file per weight (no variable-font build the
   way Sora had), hence five @font-face rules instead of one. */
@font-face{font-family:'Poppins';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/poppins-400.woff2) format('woff2')}
@font-face{font-family:'Poppins';font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/poppins-500.woff2) format('woff2')}
@font-face{font-family:'Poppins';font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/poppins-600.woff2) format('woff2')}
@font-face{font-family:'Poppins';font-style:normal;font-weight:700;font-display:swap;src:url(/fonts/poppins-700.woff2) format('woff2')}
@font-face{font-family:'Poppins';font-style:normal;font-weight:800;font-display:swap;src:url(/fonts/poppins-800.woff2) format('woff2')}
body{margin:0;background:var(--bg);color:var(--ink);font:15px/1.45 Inter,ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif}
/* Persistent chrome (topbar + both nav bars) carries the Groundhog
   Budgeting light palette on every tab, not just Home -- it's the one set
   of elements that's always on screen regardless of which panel is
   showing, so there's no way to reskin it for "Home only" without it
   visibly flipping style as you switch tabs. Every other tab's own panel
   body is untouched -- see the Home section far below for where the
   system actually starts. */
.topbar{height:70px;padding:0 clamp(16px,4vw,48px);display:flex;align-items:center;justify-content:space-between;background:var(--gb-bg);border-bottom:1px solid var(--gb-nav-border);position:sticky;top:0;z-index:10;font-family:'Poppins',sans-serif}
.brand{display:flex;gap:9px;align-items:center;color:var(--gb-ink);text-decoration:none}
/* A real photo (the delivered groundhog-and-coin medallion,
   public/brand-mark.png) now, not a CSS glyph -- circular per the
   reference mockup's own <img style="border-radius:50%">, object-fit:cover
   so the square source fills the circle without distorting it. */
.brand-mark{display:block;width:34px;height:34px;border-radius:50%;object-fit:cover;flex-shrink:0}
.brand strong,.brand small{display:block}
.brand strong{font-size:16px;font-weight:800;letter-spacing:-.2px;color:var(--gb-ink)}
.brand small{font-size:9.5px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;color:var(--gb-muted);margin-top:1px}
/* Four pills now (Checking/Cash/Savings/Ready to Assign, up from two) --
   wrap rather than force one row, so a narrow viewport gets a clean 2x2
   instead of either overflowing or each pill getting squeezed unreadably
   thin to fit. */
.topbar-totals{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
main{width:min(1100px,calc(100% - 32px));margin:auto;padding:28px 0 64px}

.button,select,input{font:inherit}
/* Every input/select on this page inherited whatever font-size its
   container happened to set -- 13px from a table td for .assigned-input,
   12px from a dialog label for every dialog field -- because .font:inherit
   above copies the ancestor's size along with everything else. iOS Safari
   zooms the whole page in the instant a text field under 16px gets focus,
   with no CSS way to opt out short of the field itself being >=16px:
   reported from a real phone, where tapping the Assigned box or any dialog
   field zoomed in every time. One rule at the element level, after the
   ancestor-inheriting one above so it wins on equal specificity, instead of
   a font-size added to every ancestor that happens to hold a field today. */
input,select,textarea{font-size:16px}
.button{border:1px solid transparent;border-radius:9px;padding:9px 13px;cursor:pointer;font-weight:700;font-size:13px;white-space:nowrap}
.primary{background:var(--navy);color:#fff}.primary:hover{background:#195F30}
.secondary{background:#fff;color:var(--navy);border-color:#ccd4df}.secondary:hover{background:#f5f7fa}
.danger{background:#fff;color:var(--red);border-color:#f0b7b3}
.icon-button{border:0;background:#f1f3f6;width:32px;height:32px;border-radius:50%;font-size:16px;cursor:pointer;color:var(--navy)}

.section-tabs{display:flex;gap:6px;margin:0 0 16px;padding:5px;background:var(--gb-surface);border-radius:12px;width:max-content;font-family:'Poppins',sans-serif}
.section-tab{border:0;border-radius:9px;padding:10px 18px;background:transparent;color:var(--gb-inactive);font:750 13px/1 inherit;cursor:pointer}
.section-tab.active{background:var(--gb-bg);color:var(--gb-accent);box-shadow:none}

/* Hidden above the mobile breakpoint (see the 640px query below), where
   .section-tabs above is the real navigation -- a fixed bottom bar makes
   sense on a phone held in one hand, not on a desktop pointer. Uses the
   same .section-tab class as the top tabs (see initTabs() in app.js), so
   both stay in sync without a second switching implementation. */
.bottom-nav{display:none}
/* Reported directly: "Bottom row of icons needs to be larger." Icons
   themselves are sized in index.html (the <svg width/height> -- 22px to
   27px); this is the rest of the row growing to match, so the larger
   icons don't just crowd the same box. main's own padding-bottom below
   (in the phone-width media query) is bumped by the same amount this grew
   by, or the taller bar would start covering the last row of whatever
   panel is showing. */
.bottom-nav-item{flex:1;display:flex;flex-direction:column;align-items:center;gap:3px;padding:9px 4px 7px;background:transparent;color:var(--gb-inactive);font:700 11px/1.1 'Poppins',sans-serif}
.bottom-nav-item.active{color:var(--gb-accent)}

.panel{background:var(--paper);border-radius:16px;box-shadow:var(--shadow);border:1px solid var(--line);overflow:hidden}
.panel[hidden]{display:none}
.panel-head{padding:18px 22px;display:flex;gap:16px;justify-content:space-between;align-items:center;border-bottom:1px solid var(--line);flex-wrap:wrap}
h2{font:600 21px/1.2 Georgia,serif;margin:0}
.actions{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.actions select{border:1px solid #ccd4df;border-radius:9px;padding:8px 10px;background:#fff}

.month-switch{display:flex;align-items:center;gap:10px}
.month-picker{position:relative;min-width:150px}
.month-label{display:flex;align-items:center;justify-content:center;gap:5px;width:100%;border:0;background:transparent;cursor:pointer;font:600 21px/1.2 Georgia,serif;color:var(--ink);padding:4px 6px;border-radius:8px}
.month-label:hover{background:#f1f3f6}
.month-label .chevron{font-size:12px;color:var(--muted);margin-top:2px}
/* position:fixed, not absolute -- .month-picker's own position:relative
   would put this inside .panel's box, and .panel{overflow:hidden} (needed
   for its rounded corners) clips anything of its children that runs past
   the panel's own edge. top/left are set in JS from the button's own
   getBoundingClientRect() each time this opens, not from CSS, since a
   fixed-position element has no containing-block relationship to the
   button it's supposed to sit under. */
.month-dropdown{position:fixed;transform:translateX(-50%);z-index:20;background:#fff;border:1px solid var(--line);border-radius:12px;box-shadow:var(--shadow);padding:6px;display:flex;flex-direction:column;gap:2px;max-height:280px;overflow-y:auto;min-width:170px}
/* This class's own display:flex above is an author rule, and author rules
   always beat the browser's default [hidden]{display:none} regardless of
   the hidden attribute actually being set -- so toggling .hidden in JS
   (openMonthDropdown/closeMonthDropdown) never visually hid this element
   at all. It sat rendered, empty, at its last (or, before ever opened,
   default) position on every page and every tab, a thin box easy to miss
   most of the time and, on a real phone, landing squarely over the bottom
   nav's Budget button. Live since the month picker itself shipped --
   verified then that opening positioned it correctly, never that closing
   (or never opening it at all) actually hid it. */
.month-dropdown[hidden]{display:none}
.month-option{border:0;background:transparent;text-align:left;padding:8px 12px;border-radius:8px;font:600 13px/1.2 inherit;color:var(--ink);cursor:pointer;white-space:nowrap}
.month-option:hover{background:#f1f3f6}
.month-option.active{background:var(--navy);color:#fff}

/* Ready to Assign lives in the topbar (see .topbar-total below), not here
   any more -- it used to be a banner inside the Budget panel, invisible on
   every other tab, which is exactly the "renters side" (Harp-Budget's own
   "House Owes" topbar tile) pattern this was changed to match. */
.topbar-total{display:flex;flex-direction:column;line-height:1.15;padding:6px 12px;border-radius:8px;background:var(--gb-surface);color:var(--gb-ink);white-space:nowrap}
.topbar-total b{font-size:9px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;color:var(--gb-muted)}
.topbar-total strong{font:700 16px/1.15 'Poppins',sans-serif;color:var(--gb-ink)}
/* Ready to Assign is the one pill with a real positive/negative/zero
   distinction (renderTopbarBalances/the RTA-specific block in app.js) --
   gold on top of good news, same as every other gold accent this system
   uses, not a fourth color invented just for this one figure. */
.topbar-total.positive strong{color:var(--gb-accent)}
.topbar-total.negative{background:rgba(180,35,24,.12)}
.topbar-total.negative strong{color:var(--red)}
.topbar-total.zero{background:rgba(31,122,61,.14)}
.topbar-total.zero strong{color:var(--gb-accent)}

.table-wrap{overflow-x:auto}
table{border-collapse:collapse;width:100%;min-width:640px}
th{padding:11px 14px;background:#f7f8fa;color:#596274;font-size:10px;text-transform:uppercase;letter-spacing:.06em;text-align:left;border-bottom:1px solid var(--line)}
td{padding:10px 14px;border-bottom:1px solid #e8ebef;vertical-align:middle;font-size:13px}
tbody tr:hover{background:#fafbfd}
.num{text-align:right;font-variant-numeric:tabular-nums}
.available-cell.positive{color:var(--green);font-weight:700}
.available-cell.negative{color:var(--red);font-weight:700}
.available-cell.zero{color:var(--muted)}
/* No font-size here on purpose -- a class selector would beat the plain
   input,select,textarea{font-size:16px} rule above regardless of source
   order (class specificity always outranks an element selector), silently
   re-opening the exact iOS Safari zoom-on-focus bug that rule exists to
   close. This is not theoretical: this class did carry font-size:13px
   here for a while, and the account-settings Opening Balance field (also
   .assigned-input) zoomed the whole page on tap on a real phone until it
   was found and removed. Widen .assigned-input's own width below instead
   of shrinking its font if a value ever needs more visual room. */
.assigned-input{width:84px;border:1px solid #ccd4df;border-radius:7px;padding:5px 7px;text-align:right;font-variant-numeric:tabular-nums}
.envelope-name{display:flex;align-items:center;gap:6px;min-width:0;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.envelope-rename{border:0;background:transparent;color:#a9b2bf;cursor:pointer;font-size:12px}
.envelope-rename:hover{color:var(--navy)}
/* Same pencil, one level up -- a category's own name, editable from
   either the Budget or the Bills group header (both read the same
   state.categories, so either pencil opens the identical row). */
.category-rename{flex:0 0 auto;border:0;background:transparent;color:#a9b2bf;cursor:pointer;font-size:13px}
.category-rename:hover{color:var(--navy)}

/* Collapsible categories, each envelope a compact 2-line row -- same shape
   as the Bills tab's own .bill-group/.bill-row (see renderBills' own
   comment), applied here from the same complaint pattern: "the car[ds]
   need to be compacted... categor[ies] collapsible." Replaces the old
   Envelope/Assigned/Activity/Available table, which gave every envelope
   three full-height cells even on a phone. */
.budget-list{display:flex;flex-direction:column;gap:10px;padding:14px 22px}
.budget-group{border:1px solid var(--line);border-left:4px solid transparent;border-radius:14px;background:#fafbfd;overflow:hidden}
.budget-group-head{display:flex;align-items:center;gap:8px;padding:10px 14px}
.budget-group-toggle{flex:1 1 auto;min-width:0;display:flex;align-items:center;gap:8px;border:0;background:transparent;padding:0;font:inherit;text-align:left;cursor:pointer}
.budget-group-title{flex:1 1 auto;min-width:0;font-weight:750;color:var(--navy);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.budget-group-count{flex:0 0 auto;color:var(--muted);font-size:12px;background:#eef1f5;border-radius:999px;padding:1px 8px}
.budget-group-available{flex:0 0 auto;font-size:13px}
.cat-add{flex:0 0 auto;font-size:11px;font-weight:700;color:var(--blue);background:none;border:0;cursor:pointer;padding:4px 2px}
.budget-group-rows{display:flex;flex-direction:column}
.budget-group.collapsed .budget-group-rows{display:none}
/* Same red-accent language as Bills' own .bill-group-attention (line
   424) -- "why does the underfund section not appear with a different
   look," reported directly, against a category whose net Available read
   positive because other envelopes offset one overspent one. Checked
   per-envelope in app.js (hasOverspentEnvelope), not derived from this
   card's own rolled-up total, so it still shows even collapsed.
   A left accent bar, not a background/border tint on the whole card --
   reported directly, against a side-by-side with Home's own pinned-card
   style (plain white card, red confined to the amount text and its own
   progress bar): a full pink wash put this card's own green title
   directly on a red background, which is what was actually clashing, not
   the shade of either color. */
.budget-group.has-overspent{border-left-color:var(--red)}

/* .envelope-row-compact is now a flex row (handle + content) rather than a
   plain block, so the border/padding that used to sit directly on it moved
   onto .envelope-row-content -- the handle spans the row's full height
   without its own top/bottom padding pushing it out of line with the
   content next to it. */
.envelope-row-compact{display:flex;align-items:stretch;border-top:1px solid var(--line);border-left:3px solid transparent}
.budget-group-rows .envelope-row-compact:first-child{border-top:0}
/* Same red accent as .budget-group.has-overspent, one level down -- the
   row itself, not just the category card around it. */
.envelope-row-compact.overspent{border-left-color:var(--red)}
.envelope-row-content{flex:1 1 auto;min-width:0;padding:9px 14px}
.envelope-row-top{display:flex;align-items:center;justify-content:space-between;gap:10px}
.envelope-available{flex:0 0 auto;font-size:14px}
/* Spent-vs-assigned bar -- the one element kept from the reference
   screenshot the owner sent of a different budgeting app (its per-envelope
   icon was explicitly declined). Fraction and color come from
   envelopeProgressBar() in app.js; the bar itself is empty markup, so a
   0%-width fill never needs its own "hide when zero" rule. */
.envelope-progress{margin-top:6px;height:4px;border-radius:999px;background:#eef1f5;overflow:hidden}
.envelope-progress-fill{height:100%;background:var(--blue);border-radius:999px}
.envelope-progress-fill.over{background:var(--red)}
.envelope-row-bottom{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:6px}
.envelope-assigned-inline{display:flex;align-items:center;gap:6px;font-size:11px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.03em}
.envelope-assigned-inline .assigned-input{text-transform:none;letter-spacing:normal;font-weight:400}

/* Drag-to-reorder -- same "3-bar grip handle" shape as PoultryPath's own
   stop-reorder (the household's other app, the explicit reference for
   this), scaled to this row's own height instead of a fixed 44px column.
   touch-action:none stops the browser's own scroll gesture from fighting
   the drag on a phone. */
.drag-handle{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;flex:0 0 auto;width:30px;background:none;border:0;border-right:1px solid var(--line);color:var(--muted);cursor:grab;touch-action:none}
.drag-handle:active{cursor:grabbing}
.drag-handle:hover,.drag-handle:focus-visible{background:#eef1f5;color:var(--navy)}
.drag-handle .bar{width:14px;height:2px;background:currentColor;border-radius:1px}
.envelope-row-compact.dragging{background:var(--paper);box-shadow:var(--shadow);border-radius:9px}
.envelope-row-placeholder{border-top:1px dashed #ccd4df;background:#f4f6f9}

/* One level up from .drag-handle above -- reordering the categories
   themselves, reported directly: "Want to be able to reorder the budget
   categories as well by drag bar." Sized for sitting inline as the first
   child of .budget-group-head (already a flex row) rather than spanning a
   row's full height the way .drag-handle does for an envelope row, so no
   border-right/fixed width in the same way. */
.category-drag-handle{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;flex:0 0 auto;width:20px;height:20px;background:none;border:0;border-radius:6px;color:var(--muted);cursor:grab;touch-action:none}
.category-drag-handle:active{cursor:grabbing}
.category-drag-handle:hover,.category-drag-handle:focus-visible{background:#eef1f5;color:var(--navy)}
.category-drag-handle .bar{width:12px;height:2px;background:currentColor;border-radius:1px}
.budget-group.dragging{box-shadow:var(--shadow);border-radius:14px}
.budget-group-placeholder{border:1px dashed #ccd4df;border-radius:14px;background:#f4f6f9}
/* Sits where .category-drag-handle would, in Alphabetical/Priority mode
   (and inside a Priority group's own nested categories) -- an empty
   same-size box, not a hidden handle, so the header's own layout never
   shifts sideways just because dragging isn't available right now. */
.drag-handle-spacer{flex:0 0 auto;width:20px;height:20px}

/* "I do like how the budget section is split up into three main
   categories so that way I can look at them in order of importance...
   a toggle for the three different sort features," reported directly.
   Segmented-control shape, not a <select> -- three fixed options, always
   visible, one tap to switch, same instinct as a tab strip. */
/* "Put manage groups in the line with the others," reported directly
   against a phone screenshot where it wrapped to its own row below the
   toggle -- nowrap plus a horizontal scroll as the fallback (not another
   wrap) so it's always literally one line, on any width; the toggle and
   "Manage groups" were also both shrunk (tighter padding, "Manage
   groups" now sized like a toggle segment instead of a full .button) so
   the common case fits without ever needing to scroll. */
.budget-sort-row{display:flex;align-items:center;justify-content:space-between;gap:5px;flex-wrap:nowrap;overflow-x:auto;padding:0 22px 14px}
.budget-sort-toggle{display:inline-flex;flex:0 0 auto;border:1px solid var(--line);border-radius:10px;overflow:hidden}
.budget-sort-btn{border:0;background:var(--paper);color:var(--muted);font:inherit;font-size:10px;font-weight:700;padding:6px 7px;cursor:pointer;white-space:nowrap}
.budget-sort-btn+.budget-sort-btn{border-left:1px solid var(--line)}
.budget-sort-btn.active{background:var(--navy);color:#fff}
.budget-sort-manage{flex:0 0 auto;border:1px solid var(--line);border-radius:8px;background:#fff;color:var(--navy);font:inherit;font-size:10px;font-weight:700;padding:6px 7px;cursor:pointer;white-space:nowrap}
.budget-sort-manage:hover{background:#f5f7fa}

/* One level up from .category-drag-handle -- Priority mode's own groups,
   reordered "so I can look at them in order of importance," reported
   directly. Same shape and size as .category-drag-handle: it sits in the
   identical spot in .budget-group-head, just a tier higher in the tree. */
.group-drag-handle{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;flex:0 0 auto;width:20px;height:20px;background:none;border:0;border-radius:6px;color:var(--muted);cursor:grab;touch-action:none}
.group-drag-handle:active{cursor:grabbing}
.group-drag-handle:hover,.group-drag-handle:focus-visible{background:#eef1f5;color:var(--navy)}
.group-drag-handle .bar{width:12px;height:2px;background:currentColor;border-radius:1px}

/* Priority mode's own group rows -- same shape as .budget-group one tier
   up, so a group and a category read as the same kind of thing at a
   glance, just nested. */
.budget-priority-group{border:1px solid var(--line);border-left:4px solid transparent;border-radius:14px;background:#fafbfd;overflow:hidden}
.budget-priority-group-body{display:flex;flex-direction:column;gap:10px;padding:10px}
.budget-priority-group.collapsed .budget-priority-group-body{display:none}
.budget-priority-group-empty{padding:6px 4px;margin:0;font-size:13px;text-align:left}
/* Same left-accent treatment as .budget-group.has-overspent, one tier
   up -- Bills' own billGroupRowHtml shares this class but never sets this
   modifier (bills have no envelopes to be overspent), so this only ever
   fires on Budget's own priority-mode group card. */
.budget-priority-group.has-overspent{border-left-color:var(--red)}

/* "Manage groups" list -- a name and an edit-pencil, nothing else (a
   group carries no financial figure of its own to show here). */
.settings-row{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:9px 4px;border-top:1px solid var(--line)}
.settings-row:first-child{border-top:0}
.settings-row-name{font-weight:600;color:var(--navy)}
/* Opens #calculatorDialog -- see its own comment in index.html for why a
   phone's decimal keypad alone can't do "add $50 to this." */
.assigned-calc{flex:0 0 auto;border:1px solid #ccd4df;background:#fff;color:var(--muted);cursor:pointer;font-size:13px;font-weight:700;width:22px;height:22px;border-radius:6px;line-height:1;text-transform:none;letter-spacing:normal}
.assigned-calc:hover{color:var(--navy);border-color:var(--navy)}

/* Opens #nearbyDialog -- same "wrap input + one small button" shape as
   .amount-field above, so the Payee field keeps its full grid/label width
   and the pin button doesn't need a column of its own. */
.payee-field{display:flex;gap:6px}
.payee-field input{min-width:0}
.payee-nearby:hover{border-color:var(--navy)}
.payee-nearby,.split-toggle{flex:0 0 auto;border:1px solid #ccd4df;background:#fff;cursor:pointer;font-size:14px;width:32px;height:32px;border-radius:8px;line-height:1}

/* Envelope <select> + its "Split" toggle -- same shape as .payee-field
   above, just a wider button since "Split"/"Use one category" is a word,
   not a glyph. */
.envelope-field{display:flex;gap:6px}
.envelope-field select{min-width:0}
.split-toggle{width:auto;padding:0 10px;font-weight:700;white-space:nowrap}
.split-toggle:hover{border-color:var(--navy);color:var(--navy)}

/* #txnSplitEditor -- one row per category, built in JS (see addSplitRow in
   app.js); .split-amount reuses the same min-width:0 fix .amount-field
   input needed for the identical reason (a flex item's default min-width
   refuses to shrink below its own content). */
.split-editor{margin-top:-4px}
.split-rows{display:flex;flex-direction:column;gap:8px;margin-bottom:10px}
.split-row{display:flex;gap:8px;align-items:center}
.split-row .split-envelope{flex:1 1 auto;min-width:0}
.split-row .split-amount{flex:0 0 100px;min-width:0;text-align:right}
.split-remaining{margin:0;font-size:12px;font-weight:700;color:var(--muted)}
.split-remaining.split-remaining-done{color:var(--green)}
.split-remaining.split-remaining-over{color:var(--red)}

/* "Split (N)" in the Register's Envelope column -- .bill-pill's own shape
   (see the Bills tab), just its own blue tint: this is informational, not
   a warning the way "Category needed" (severity-critical, red) is. */
.split-pill{color:var(--blue)}

/* "Transfer: <other account>" -- same informational, non-warning shape as
   split-pill above, a distinct color only so the two read apart at a
   glance (a transfer is never split, so they never appear together, but
   this Register also isn't scoped to one account at a time). */
.transfer-pill{color:var(--green)}

/* "Tracking" next to the account name in the Register's Account column --
   reported directly: a HELOC's Set Balance adjustment showed up in the
   Register with nothing marking it as a tracking account's own entry, so
   a large "Interest/fees" line (the balance simply being declared, not
   real spending) read like an ordinary transaction. var(--muted) rather
   than a warning color: this isn't flagging a problem the way
   severity-critical does, only stating a fact about the account, the same
   register that "Tracking account" checkbox already states in Settings. */
.tracking-pill{color:var(--muted)}

/* "Pay to apply" on a Cash Flow bill row -- same informational,
   non-warning shape as tracking-pill above: this states a fact about the
   bill (not on autopay, so its amount is a fact about what's coming, not
   an event this projection has applied yet), not a problem to fix the
   way severity-critical is. */
.pending-pill{color:var(--muted)}

/* A real keypad, not a typed shorthand -- see #calculatorDialog's own
   comment in index.html for why. Sized for a thumb, four to a row. */
.calc-display{font:700 22px/1.3 Georgia,serif;text-align:right;padding:10px 12px;background:#f4f6f9;border-radius:9px;margin-bottom:12px;color:var(--navy);overflow-x:auto;white-space:nowrap}
.calc-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}
.calc-btn{padding:14px 0;font-size:18px;font-weight:600;border:1px solid #ccd4df;border-radius:9px;background:#fff;color:var(--navy);cursor:pointer}
.calc-btn:active{background:#eef1f5}
.calc-btn.calc-op{background:#eef1f5;color:var(--blue);font-weight:750}
.calc-btn.calc-zero{grid-column:span 3}

/* #nearbyDialog's result list -- one wide tappable button per business, the
   name on the left and distance/kind on the right, same idea as a native
   picker sheet rather than a plain <select> (Overpass's kind values, e.g.
   "convenience" or "fast_food", read fine as a subtitle but not as an
   option label on their own). */
.nearby-list{list-style:none;margin:0;padding:0;max-height:340px;overflow-y:auto}
.nearby-list li+li{border-top:1px solid var(--line)}
.nearby-list button{display:flex;justify-content:space-between;align-items:center;gap:10px;width:100%;border:0;background:none;padding:11px 4px;font:inherit;font-weight:650;color:var(--ink);text-align:left;cursor:pointer}
.nearby-list button:hover{color:var(--blue)}
.nearby-kind{flex:0 0 auto;font-size:12px;font-weight:600;color:var(--muted);text-transform:capitalize}
.envelope-activity{flex:0 0 auto;font-size:12px;color:var(--muted)}
/* Both reset a <button>'s own default border/background/padding/font back
   to how the plain <span> they replace always looked -- .available-cell's
   color/weight rules still apply on top, since those classes stay. Dotted
   underline is the only new visual, marking "this number is clickable." */
.envelope-available.cover-overspend,.envelope-activity-link{border:0;background:none;padding:0;font:inherit;cursor:pointer;text-decoration:underline dotted;text-underline-offset:2px}
.envelope-available.cover-overspend:hover,.envelope-activity-link:hover{opacity:.7}
.empty{text-align:center;padding:40px;color:var(--muted)}

/* Register balance -- see renderRegisterBalance() in app.js for why this
   is two figures, not one: "not what's in the banking app, but what I know
   it's going to be" (registerBalance) alongside the number that SHOULD
   match the banking app right now (cleared), with Reconcile the bridge
   between the two. */
.register-balance{display:flex;align-items:center;gap:18px;padding:12px 22px;border-bottom:1px solid var(--line);background:#fafbfd;flex-wrap:wrap}
.register-balance-figures{display:flex;align-items:center;gap:18px;flex-wrap:wrap;flex:1 1 auto}
.register-balance-figure{display:flex;flex-direction:column;line-height:1.2}
.register-balance-label{font-size:10px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
.register-balance-amount{font:700 20px/1.2 Georgia,serif;color:var(--navy)}
.register-balance-figure.secondary .register-balance-amount{font-size:15px;color:var(--muted);font-weight:600}
/* "All accounts" -- one tile per type instead of the single blended pair
   above, same Checking/Cash/Savings split the header already uses (see
   renderRegisterBalance's own comment in app.js for why the blended
   number read as unreconciled). Deliberately its own compact look, not
   a reuse of .register-balance-figure: three of those side by side would
   repeat the words "Actual balance" three times, where the type label
   alone already says what each number is. */
.register-balance-type{display:flex;flex-direction:column;line-height:1.2;padding:4px 10px;border-radius:8px;background:#eef1f5}
.register-balance-type-label{font-size:10px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
.register-balance-type-amount{font:700 17px/1.3 Georgia,serif;color:var(--navy)}
.register-balance-type-cleared{font-size:11px;color:var(--muted)}
.register-balance #reconcileButton{margin-left:auto}
@media(max-width:640px){.register-balance{gap:14px}.register-balance #reconcileButton{margin-left:0;width:100%;order:3}}

/* A native checkbox now (reported directly: "make it a checkbox") --
   unchecked/checked cycles uncleared <-> cleared the same way the glyph
   button it replaced did (see renderTransactions' own CLEARED_TITLE in
   app.js); reconciled stays checked too, just its own accent color, since
   un-reconciling lands back on cleared, not unchecked. Sized up from a
   native checkbox's own tiny default -- this is a tap target on the one
   line the Register always shows, not a form field nobody's in a hurry
   to hit. */
.cleared-checkbox{width:20px;height:20px;cursor:pointer;accent-color:var(--blue)}
.cleared-checkbox.cleared-reconciled{accent-color:var(--green)}
/* Opens/closes one row's own details -- reported directly: "Register
   needs to be 1 line with a show/hide toggle for details." Hidden at
   desktop widths on purpose: the table there already shows every column
   in one row, so there's nothing to expand. .chevron is the same bold
   navy arrow already fixed for Budget/Bills' own collapse toggles. */
.cell-toggle,.th-toggle{display:none}
.row-toggle{border:0;background:transparent;padding:0;width:100%;height:100%;display:flex;align-items:center;justify-content:center;cursor:pointer}

/* Toggle for the form below -- "still blends in too much," reported
   directly, against the chevron+row version above: a collapsed
   transaction row already uses that exact chevron-plus-bold-label shape
   (tr.transaction-row's own row-toggle), so this read as just another
   list row, not a distinct control. Now a real .button.secondary, same
   bordered pill "Reconcile"/"+ Account" already use, sitting in its own
   margin rather than a flush full-width bar -- and a +/- glyph instead of
   a chevron, this app's own established "add a new thing" vocabulary
   (+ Account, + Category, + Envelope, + Income) rather than the
   "expand existing content" one a chevron already means elsewhere. */
.quick-add-toggle{display:inline-flex;align-items:center;gap:6px;margin:14px 22px}
.quick-add-toggle-icon{font-weight:800;font-size:15px;line-height:1}
.quick-add{display:grid;grid-template-columns:130px 1.4fr 1fr 1fr 150px 1fr auto;gap:8px;padding:16px 22px;border-bottom:1px solid var(--line);background:#fafbfd;align-items:center}
/* .quick-add's own display:grid above is an author rule, and an author
   rule always beats the browser's default [hidden]{display:none} at equal
   specificity regardless of the hidden attribute actually being set --
   the exact gotcha already caught once on .month-dropdown (see that
   class's own comment above) and again on a dialog label further down.
   Without this, toggling the quick-add form off would have left it
   rendered, empty of visible effect, the same silent failure both of
   those were. */
.quick-add[hidden]{display:none}
.quick-add input,.quick-add select{border:1px solid #ccd4df;border-radius:8px;padding:9px 10px;background:#fff;width:100%}
.amount-field{display:flex;gap:6px}
/* min-width:0 -- same fix as .form-grid label above, one level deeper: a
   flex item defaults to min-width:auto too, so the amount input refused to
   shrink inside the edit-transaction dialog's half-width column (the only
   place .amount-field has ever lived inside .form-grid; quick-add's own
   copy has a whole grid column to itself and never hit this). Caught by
   screenshot, not by describing the layout -- the input's right edge ran
   off the dialog on a real phone width. */
.amount-field input{text-align:right;min-width:0}
.flow-toggle{border:1px solid #ccd4df;border-radius:8px;padding:0 10px;background:#fff;font-weight:750;font-size:12px;cursor:pointer;color:var(--red);min-width:44px}
.flow-toggle[data-flow="in"]{color:var(--green)}
@media(max-width:900px){.quick-add{grid-template-columns:1fr 1fr}}
/* Below 640px this still fell back to the 900px 2-column rule above --
   never got its own phone-width pass the way the Budget/Register/Bills
   tables did. Seven children auto-placed two-per-row left the Add button
   alone in the last row, at half width, dangling on the left -- reported
   from a real phone. One column, with Add stretched full width as the
   actual primary action, instead of leaving it looking like an
   accidentally-unfinished row. */
@media(max-width:640px){.quick-add{grid-template-columns:1fr}.quick-add button[type="submit"]{width:100%}}

.amount-out{color:var(--red)}.amount-in{color:var(--green)}
.row-action{border:0;background:transparent;color:#7b8492;font-size:16px;cursor:pointer;padding:4px 8px;border-radius:6px}
.row-action:hover{background:var(--gb-surface-border);color:var(--navy)}
/* An outflow with no envelope -- see needsCategory() in app.js. Background
   tint only, not a border: tr.needs-category renders under both the
   desktop table (border-collapse:collapse, where a border on the row
   itself is unreliable across browsers) and the mobile grid layout below,
   and a tint is the one thing that works the same in both. */
tr.transaction-row.needs-category{background:#fff7f7}
/* Tapping a row opens the edit dialog (see registerBody's click handler in
   app.js); the cleared-toggle and delete buttons inside it keep their own
   default pointer either way, so this is just the discoverability cue. */
tr.transaction-row{cursor:pointer}
.transaction-group-row th{padding:10px 14px;background:var(--gb-surface-border);color:var(--navy);border-top:1px solid var(--line);border-bottom:1px solid var(--line);font-size:12px;letter-spacing:.03em;text-transform:none}
.transaction-group-row:first-child th{border-top:0}
.transaction-group-row.pending th{background:#fff7e6;color:#7a5200}
.transaction-group-label{font-weight:800}

/* Was a 2-column grid of always-expanded cards -- on a phone that showed
   two or three bills at a time (a real complaint: "I can only see three
   bills at a time"). Replaced with one compact row per bill (.bill-row,
   below), grouped by category the same way the Budget tab already groups
   envelopes, so a whole household's worth of bills fits without scrolling
   past every one just to find the one you want. Everything the old card
   showed inline -- amount detail, Pay/New statement/History, the edit
   pencil -- moved behind a tap, into #billDetailDialog. */
.bill-list{display:flex;flex-direction:column;gap:10px;padding:14px 22px}
.bill-group{border:1px solid var(--line);border-left:4px solid transparent;border-radius:14px;background:#fafbfd;overflow:hidden}
/* Bills used to group by category, each its own collapsible .bill-group
   with a .bill-group-toggle header (matching the Budget tab's own
   category groups) -- reported directly: "should be sorted by due date
   only." Category grouping (and its toggle/collapse/rename) is gone from
   everything except "Needs attention," which never had a toggle to begin
   with -- see renderBills in app.js. .bill-group-head, -title, -count,
   and -owed live on here only for that one remaining header. */
.bill-group-head{display:flex;align-items:center;gap:8px;padding:10px 14px}
/* Reported directly: the Budget tab's own show/collapse arrows were too
   hard to see -- 11px, muted gray, barely wider than the glyph itself.
   Bigger, bold, and navy (the same color category/envelope titles already
   use) rather than muted, so it reads as part of the row's own controls,
   not a faint decoration next to it. Bills no longer has a chevron of its
   own to fix (see above), but the class stays shared in case that ever
   changes -- .budget-group-toggle is the only renderer of it now. */
.chevron{flex:0 0 auto;color:var(--navy);font-size:16px;font-weight:700;width:14px}
.bill-group-title{flex:1 1 auto;font-weight:750;color:var(--navy)}
.bill-group-count{flex:0 0 auto;color:var(--muted);font-size:12px;background:#eef1f5;border-radius:999px;padding:1px 8px}
/* Rolled-up owed total, same visual weight as .budget-group-available --
   see billsOwedTotal() in app.js for why this is plain text, no color
   coding: "owed" has no positive/negative sense the way Available does. */
.bill-group-owed{flex:0 0 auto;font-size:13px;color:var(--navy);font-weight:700}
.bill-group-rows{display:flex;flex-direction:column}
/* Left accent bar, not a background/border tint on the whole card --
   reported directly, against a side-by-side with Home's own pinned-card
   style: a full pink wash put a category card's own green title directly
   on a red background, which was the actual clash, not either color's
   own shade. Same fix as Budget's .budget-group.has-overspent. */
.bill-group-attention{border-left-color:var(--red)}
.bill-group-attention .bill-group-title{color:var(--red)}

.bill-row{display:flex;align-items:center;gap:10px;padding:9px 14px;border-top:1px solid var(--line);cursor:pointer;border-left:3px solid transparent}
.bill-group-rows .bill-row:first-child{border-top:0}
.bill-row:hover{background:#f4f6fa}
/* Manual mode's own drag handle (see initBillReorder in app.js) -- same
   shape and size as .category-drag-handle, one tier down (a bill, not a
   category). Sits beside the row's own content rather than inside it, so
   .bill-row's own click-opens-detail-dialog listener can tell the two
   apart (see initBills's own comment on why that guard exists here and
   not on Budget's tab). */
.bill-drag-handle{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;flex:0 0 auto;width:20px;height:20px;background:none;border:0;border-radius:6px;color:var(--muted);cursor:grab;touch-action:none}
.bill-drag-handle:active{cursor:grabbing}
.bill-drag-handle:hover,.bill-drag-handle:focus-visible{background:#eef1f5;color:var(--navy)}
.bill-drag-handle .bar{width:12px;height:2px;background:currentColor;border-radius:1px}
.bill-row.dragging{background:var(--paper);box-shadow:var(--shadow);border-radius:10px}
.bill-row-name{flex:1 1 auto;min-width:0;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bill-row-due{flex:0 0 auto;font-size:12px;font-weight:750;color:var(--muted)}
.bill-row-amount{flex:0 0 auto;font-weight:700;font-size:13px;min-width:64px;text-align:right}
.bill-row.overdue .bill-row-due{color:var(--red)}
.bill-row.due-soon .bill-row-due{color:var(--amber)}
/* Severity shows as a left-border accent here, rather than severityPill()'s
   text pill -- a row is too narrow for a pill without pushing the amount
   off the edge on a phone; the pill still runs in the detail dialog, where
   a full line is available. */
.bill-row.severity-critical{border-left-color:var(--red)}
.bill-row.severity-low{border-left-color:#ccd4df}

/* Same pattern as .envelope-rename on the Budget tab -- a visible pencil,
   not just an unmarked clickable name/due-date. Originally the bill card's
   own edit affordance; now the detail dialog's, reached after tapping a
   row. Reported from a real phone as "no way to edit a bill": the
   whole-card click-to-edit fallback still worked underneath, but touch has
   no hover state to reveal it, so nothing on screen said so. */
.bill-edit{border:0;background:transparent;color:#a9b2bf;cursor:pointer;font-size:14px;padding:0 2px;vertical-align:2px}
.bill-edit:hover{color:var(--navy)}
.bill-meta{display:flex;flex-wrap:wrap;gap:7px;color:var(--muted);font-size:12px;margin-bottom:8px}
.bill-pill{display:inline-flex;border-radius:999px;padding:3px 9px;background:var(--gb-surface-border);color:var(--navy);font-size:11px;font-weight:750}
/* Standalone now (used only inside #billDetailBody, not nested under a
   removed .bill-card) -- status color is its own class rather than an
   ancestor selector, since the row that used to carry b.status is gone by
   the time this renders. */
.bill-due{font-weight:750}
.bill-due.overdue{color:var(--red)}
.bill-due.due-soon{color:var(--amber)}
.bill-due.upcoming{color:var(--muted)}

/* Only critical and low get a pill at all (see severityPill() in app.js) --
   critical reuses the same red as an overdue bill, on purpose: both mean
   "this one can't just wait". Low is muted grey rather than any semantic
   color, since a missed low-severity bill is deliberately not an alarm. */
.severity-critical{background:#fde6e6;color:var(--red)}
.severity-low{background:#eef0f3;color:var(--muted)}

/* ------------------------------------------------------------ Spending -- */
.spending-chart-wrap{padding:18px 22px 6px}
/* A plain viewBox scaled to the container's width rather than
   preserveAspectRatio="none" -- stretching bars to fill an odd container
   width would distort their proportions; letting the SVG scale
   uniformly keeps a $200 bar reading as twice a $100 one no matter how
   wide the panel is. */
.spending-chart{display:block;width:100%;height:140px}
.spending-bar{fill:var(--navy)}
.spending-bar-label{fill:var(--muted);font-size:9px;text-anchor:middle;font-family:inherit}
.spending-months{display:flex;flex-direction:column;gap:10px;padding:14px 22px}
/* Same card shape as .budget-group/.bill-group -- not collapsible (a top-3
   list is already short enough not to need it), just a static breakdown
   per month, most recent first. */
.spending-month{border:1px solid var(--line);border-radius:14px;background:#fafbfd;padding:12px 14px}
.spending-month-head{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:8px}
.spending-month-name{font-weight:750;color:var(--navy)}
.spending-month-total{font-weight:700}
.spending-month-categories{display:flex;flex-direction:column;gap:2px}
.spending-category-row{display:flex;justify-content:space-between;padding:4px 0;border-top:1px solid var(--line);font-size:13px}
.spending-month-categories .spending-category-row:first-child{border-top:0}
.spending-category-name{color:#4d5665}
.spending-category-amount{font-weight:600}
.spending-month-empty{padding:0;font-size:13px}
.cashflow-summary{padding:16px 22px;border-bottom:1px solid var(--line);display:flex;flex-direction:column;gap:8px}
.cashflow-start{color:#4d5665;font-size:13px}
.shortfall-banner{background:#fde6e6;color:var(--red);border:1px solid #f0b7b3;border-radius:10px;padding:9px 13px;font-weight:700;font-size:13px}
.shortfall-ok{background:#e5f3e6;color:var(--green);border-radius:10px;padding:9px 13px;font-weight:700;font-size:13px}
tr.cashflow-negative{background:#fff7f7}
.cashflow-balance-negative{color:var(--red);font-weight:700}
/* "(due Sep 5)" next to a floated bill's item name -- muted and small on
   purpose, the same instinct as .bill-planned-note below: this is a
   reminder the household floated it on purpose, not a second warning. */
.cashflow-due-note{color:var(--muted);font-size:11px;font-weight:600}

.deduction-log{border-top:1px solid var(--line);margin-top:6px}
.deduction-log-head{padding:18px 22px 4px;display:flex;gap:12px;align-items:center;flex-wrap:wrap}
.deduction-log-head h3{margin:0;font:600 17px/1.2 Georgia,serif;flex:1}
.deduction-total{color:var(--navy);font-weight:750;font-size:13px;background:var(--gb-surface-border);border-radius:999px;padding:4px 12px}
.deduction-log .dialog-note{padding:0 22px}
.deduction-log .table-wrap{padding:0 4px}

.settings-section{padding:18px 22px}
.settings-section h3{margin:0 0 10px;font:600 17px/1.2 Georgia,serif}
.settings-signed-in{display:flex;align-items:center;justify-content:space-between;gap:12px}
.settings-signed-in span{color:var(--muted);font-size:13px}
.settings-section .dialog-note{margin-bottom:14px}
.settings-section .table-wrap{padding:0}
/* "Why is Delete on a second line?" reported directly, against the desktop
   accounts table -- Set balance and Delete are two inline-block buttons
   with nothing stopping them wrapping like words once this column's own
   auto-sized width (squeezed by six other columns ahead of it: name,
   type, balance, two checkboxes, opening balance, date) fell below their
   combined width. nowrap forces the column to size for both buttons
   instead, the same "grow the column, let the row scroll" rule this
   table's own overflow-x:auto (see .table-wrap above) already applies to
   everything else in it. */
.cell-account-actions{white-space:nowrap}
.opening-balance-date{border:1px solid #ccd4df;border-radius:7px;padding:6px 8px}
.checkbox-inline{display:flex;align-items:center;gap:6px;font-size:12px;font-weight:700;color:#3c4657;white-space:nowrap}
.checkbox-inline input{width:15px;height:15px;accent-color:var(--navy)}

.bill-last-billed{color:var(--muted);font-size:12px;margin-top:-2px;margin-bottom:6px}
.bill-weekly{color:var(--muted);font-size:12px;margin:-4px 0 8px}
/* "Floating to Sep 20 for Cash Flow" -- muted, not a warning color: the
   real due date right above already carries whatever urgency it has
   (see .bill-due's own status colors), this is only a reminder that the
   projection date was chosen on purpose, not a second alarm. */
.bill-planned-note{color:var(--muted);font-size:12px;margin-top:-2px;margin-bottom:6px}
/* flex-wrap, not a fixed 3-up row: Log payment shows on every fixed bill,
   plus History on one with more than one recorded amount -- two real
   buttons squeezed into one row on a phone reads as unreadable slivers,
   so a wide enough card keeps them in a line and a narrow one wraps to two
   rows instead. A tracked bill's own actions (New statement, History) wrap
   the same way; its per-statement Pay buttons live in .bill-cycles below,
   not here. */
.bill-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
.bill-actions .button{flex:1 1 100px}

/* One row per open statement on a tracked bill (see
   migrations/0006_bill_cycles.sql) -- the label and amount need to stay
   readable next to their own Pay button even at phone width, so the label
   is the only column allowed to shrink (min-width:0, same fix as
   .form-grid label below) rather than the amount or the button. */
.bill-cycles{display:flex;flex-direction:column;gap:6px;margin-top:8px}
.bill-cycle-row{display:flex;align-items:center;gap:8px;background:#f4f6fa;border-radius:8px;padding:8px 10px}
/* .bill-cycle-label is itself a flex row (not a plain span) so its edit
   pencil sits right after the statement's own name -- the same "name
   [pencil]" reading order as .envelope-rename and the bill-detail title's
   own edit button. It was a flex SIBLING of this span before, and this
   span's own flex-grow filled the row's leftover width with blank space
   before the pencil ever appeared, stranding it down by the dollar amount
   instead: reported directly ("still don't see a way to edit") after a
   real phone showed exactly that gap. */
.bill-cycle-label{flex:1 1 auto;min-width:0;display:flex;align-items:center;gap:4px;font-weight:600;font-size:13px}
.bill-cycle-label-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bill-cycle-amount{flex:0 0 auto;font-weight:700;font-size:13px}
.bill-cycle-pay{flex:0 0 auto;padding:6px 14px;font-size:13px}

/* outline:none -- openDialog() in app.js focuses the dialog itself
   (tabindex="-1" in index.html) right after showModal(), on purpose, so
   the browser's own default "focus the first form field" never summons a
   keyboard or native picker the instant a dialog opens. A visible focus
   ring around the whole modal card would be a strange, unexplained
   consequence of that fix, not something anyone tabbed to. */
dialog{width:min(560px,calc(100% - 24px));border:0;border-radius:16px;padding:0;box-shadow:0 30px 90px rgba(10,25,50,.3);outline:none}
dialog::backdrop{background:rgba(12,24,45,.55)}
dialog form{padding:22px}
/* table's own min-width:640px (below) is sized for the full-page
   Budget/Register tables -- a dialog tops out at 560px, so the Amount
   history dialog's table demanded more width than the dialog had and
   rendered its second column off the visible edge, invisible with no
   scrollbar in view. First table placed inside a dialog in this codebase;
   caught by a screenshot showing only a Date column, not by reading the
   table markup, which looked completely correct on its own. */
dialog table{min-width:0}
.dialog-head{margin-bottom:16px}
.dialog-head h3{margin:0;font:600 19px Georgia,serif}
.dialog-note{margin:0 0 14px;color:#4d5665;font-size:13px}
dialog label{display:flex;flex-direction:column;gap:6px;font-size:12px;font-weight:750;color:#4d5665;margin-bottom:14px}
/* Same gotcha as .month-dropdown[hidden] elsewhere in this file: an author
   rule -- dialog label{display:flex} above -- always wins over the
   browser's own [hidden]{display:none} default, so toggling a label's
   `hidden` property (billAmountLabel, for an existing tracked bill -- see
   openBillDialog in app.js) silently did nothing without this explicit
   override. Caught by getComputedStyle(), not the screenshot alone: the
   rendered Amount field looked plausible enough (a real number in it) that
   the bug was only obvious once display was checked directly. */
dialog label[hidden]{display:none}
dialog input,dialog select{border:1px solid #ccd4df;border-radius:9px;padding:9px 11px;color:var(--ink);background:#fff}
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px 16px}
/* min-width:0 -- a grid item defaults to min-width:auto, which refuses to
   shrink below its content's own intrinsic width. billEnvelope's <select>
   options ("Utilities: Duke Energy") are wide enough that, without this,
   that column demanded more than half the dialog's real width and pushed
   the whole row (and the paired Amount/due-date/autopay fields next to
   it) past the dialog's own right edge, with nothing to catch the
   overflow -- cut off at the screen edge on a real phone, not wrapped.
   The bill dialog is the only one using .form-grid's two-column layout,
   which is why every other dialog's plain single-column fields never hit
   this. */
.form-grid label{margin-bottom:0;min-width:0}
.form-grid .wide{grid-column:1/-1}
.checkbox-field span{display:flex;align-items:center;gap:8px;font-size:13px;font-weight:700;color:#3c4657}
.checkbox-field input{width:16px;height:16px;accent-color:var(--navy)}
.dialog-actions{display:flex;gap:9px;align-items:center}
.dialog-actions span{flex:1}
.reconcile-candidates{margin:0 0 14px;padding:0;list-style:none;display:flex;flex-direction:column;gap:6px}
.reconcile-candidates li{background:#f4f6fa;border-radius:8px;padding:8px 11px;font-size:12.5px;color:#3c4657}

.toast{position:fixed;bottom:22px;left:50%;transform:translate(-50%,20px);background:#172033;color:#fff;padding:11px 17px;border-radius:9px;opacity:0;pointer-events:none;transition:.2s;box-shadow:var(--shadow);z-index:30}
.toast.show{opacity:1;transform:translate(-50%,0)}

/* .brand small used to be dropped here entirely: back when the wordmark
   was "Ledger" it carried a ~180px subtitle ("harpbudget.com -- envelope
   budgeting"), not "Ledger" itself, that set the brand block's width and
   left no room for it on a real phone once .topbar-total became a third
   topbar child. The Groundhog Budgeting rebrand's own subtitle is just
   "BUDGETING" (nine characters, ~55px at this size) -- reported directly
   as "cut off in the header" once it was hidden here unconditionally, so
   it stays now; the width problem this rule existed to solve no longer
   applies to a subtitle this short.
   Actual Balance (reported directly: "actual balance listed first...")
   made that pair two pills, not one -- brand plus both pills no longer fit
   on one line at any font size worth reading (true even now that the old
   reciprocal "Harp Budget" link, once the topbar's third child, is gone --
   the wordmark and four pills alone are still too wide for a phone), so
   .topbar itself wraps: brand keeps the first row alone, and
   .topbar-totals drops to a full-width second row, still Actual Balance
   before Ready to Assign, just stacked under the row it used to share.
   Verified at 390px alongside the
   .topbar-total shrink below.
   .topbar-total b no longer shrinks to 8px here -- reported directly as
   looking "fuzzy" on a phone, against this exact row of labels; it now
   stays the same 9px this rule already gives it above 620px, since 8px
   of a custom webfont (Poppins isn't hinted for sizes this small the way
   a system UI font is) is right at the edge of where small custom-webfont
   text reads as soft on iOS. Not independently confirmed against a real
   iPhone -- this environment has no way to render actual WebKit text
   rasterization to compare before/after -- so this is a reasoned mitigation
   of a well-documented class of problem, not a verified fix. */
@media(max-width:620px){.topbar{flex-wrap:wrap;height:auto;min-height:60px;row-gap:8px;padding-top:10px;padding-bottom:10px}.topbar-totals{order:3;flex:1 1 100%}main{width:min(100% - 20px,1100px);padding-top:16px}.panel-head{align-items:flex-start;flex-direction:column}.topbar-total{padding:5px 9px}.topbar-total strong{font-size:14px}}

/* Register (and Cash Flow, Deductions, Settings) become stacked cards
   instead of a horizontally scrolling table below this width -- reported
   against a real deployed screen, not assumed from a narrow window.
   table-wrap's own overflow-x:auto (see above) is still correct for anyone
   wider than this, so it stays; below it, every cell drops to a block and
   each table's own rule below turns that block flow into a small grid per
   row instead. (Budget used to be one of these tables too -- see
   .budget-list/.budget-group above instead; it's a compact collapsible
   list now, not a table, so none of this block applies to it anymore.) */
@media(max-width:640px){
  /* Bottom nav swaps in for the top .section-tabs below this width -- one
     hand, one thumb, reachable at the bottom of the screen instead of a
     stretch to the top. main's padding-bottom clears the fixed bar itself
     (its real height plus the iPhone home-indicator safe area) so the last
     row of a panel doesn't end up hidden behind it. */
  .section-tabs{display:none}
  .bottom-nav{display:flex;position:fixed;left:0;right:0;bottom:0;z-index:15;background:var(--gb-bg);border-top:1px solid var(--gb-nav-border);padding:2px 4px calc(2px + env(safe-area-inset-bottom))}
  main{padding-bottom:84px}

  /* Scoped by the .table-wrap ancestor class, not #budgetTable/#registerTable
     IDs -- an ID selector outranks any number of classes no matter how the
     rules are ordered, so the first version of this block's own reset
     (#budgetTable td{...}) silently out-specified every card-layout rule
     below it: no rule here actually took effect, everything fell back to
     plain top-to-bottom block stacking, and an empty, still-labelled Memo
     cell sat visually between Account and the unlabelled Amount that
     followed it in DOM order -- read as "Amount labelled Memo" on a real
     screen. Caught by checking computed styles, not by the screenshot
     alone: block-stacked labels looked plausible enough that the mistake
     was invisible until getComputedStyle() proved display was never
     actually grid. */
  .table-wrap{overflow-x:visible}
  .table-wrap table{min-width:0;width:100%}
  .table-wrap thead{display:none}
  .table-wrap tbody,.table-wrap tr,.table-wrap td{display:block;width:auto}
  .table-wrap td{padding:0;border:0}

  /* The card-stacking rules above assume a `tr.*-row` class supplies a grid
     layout and data-label per cell -- true of every remaining full-page
     table (Register, Cash Flow, Deductions, Settings) but never true of
     billHistoryDialog's own plain <tr><td> rows, which have neither. Left
     unscoped, this bill's amount/statement history rendered with its
     header row hidden and every cell unlabelled, several stacked numbers
     with no indication which column each belonged to -- caught by reading
     the dialog's own rendered HTML, not by the screenshot alone, the same
     way the envelope-row mis-specificity bug above was. A dialog is
     already narrow enough (max 560px, see the dialog{} rule) that a
     genuine two-or-three-column table fits without card-stacking at all,
     so this restores real table semantics for every table inside a
     dialog instead of inventing per-cell labels for one more row class. */
  dialog .table-wrap thead{display:table-header-group}
  dialog .table-wrap tbody{display:table-row-group}
  dialog .table-wrap tr{display:table-row}
  dialog .table-wrap td,dialog .table-wrap th{display:table-cell;width:auto;padding:8px 6px;border-bottom:1px solid #eef1f5}

  /* Reported directly: "Register needs to be 1 line with a show/hide
     toggle for details. Leave the cleared button visible on the line,
     and make it a checkbox." Row 1 (toggle, payee, amount, cleared) is
     always shown; the rest -- envelope, date, account, memo, delete --
     only when .expanded (see the row-toggle click handler in app.js).
     Same "hide the detail grid-areas" idea as :not(.collapsed) elsewhere
     in this file, just per-row instead of per-category. */
  /* row-gap:0 here, not 5px -- a collapsed row's own grid-template-areas
     still declare three more named rows (envelope/account/actions) for
     the detail content .expanded reveals, and CSS Grid inserts row-gap
     between every track boundary regardless of whether either side has
     content: three 0-height tracks still cost 3 * row-gap, invisibly,
     on every single collapsed row. "These lines could be tighter by
     eliminating this extra space," reported directly, against a real
     phone screenshot -- measured at 15px of dead space per row (3 * 5px)
     before this fix, confirmed via getComputedStyle, not assumed from
     the CSS alone. .expanded below restores the gap where it's actually
     doing something: real visible space between real detail rows. */
  tr.transaction-row{display:grid;grid-template-columns:24px 1fr auto auto;grid-template-areas:"toggle payee amount cleared" "envelope envelope envelope date" "account account account memo" "actions actions actions actions";row-gap:0;column-gap:12px;padding:12px 4px;border-bottom:1px solid #e8ebef;align-items:center}
  tr.transaction-row.expanded{row-gap:5px}
  tr.transaction-row .cell-toggle{grid-area:toggle;display:flex;padding:0}
  tr.transaction-row .cell-payee{grid-area:payee;font-weight:700;font-size:14px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  tr.transaction-row .cell-amount{grid-area:amount;font-size:15px;font-weight:700;text-align:right}
  tr.transaction-row .cell-cleared{grid-area:cleared;display:flex;align-items:center}
  tr.transaction-row .cell-envelope{grid-area:envelope;font-size:13px}
  tr.transaction-row .cell-date{grid-area:date;text-align:right;color:var(--muted);font-size:12px}
  tr.transaction-row .cell-account{grid-area:account;color:var(--muted);font-size:12px}
  tr.transaction-row .cell-memo{grid-area:memo;text-align:right;color:var(--muted);font-size:12px}
  tr.transaction-row .cell-memo:empty{display:none}
  tr.transaction-row .cell-actions{grid-area:actions;text-align:right}
  tr.transaction-row:not(.expanded) .cell-envelope,
  tr.transaction-row:not(.expanded) .cell-date,
  tr.transaction-row:not(.expanded) .cell-account,
  tr.transaction-row:not(.expanded) .cell-memo,
  tr.transaction-row:not(.expanded) .cell-actions{display:none}
  tr.transaction-row [data-label]::before{content:attr(data-label) ": ";font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.04em;color:var(--muted)}
  tr.transaction-row .cell-payee::before,tr.transaction-row .cell-amount::before,tr.transaction-row .cell-date::before,tr.transaction-row .cell-cleared::before{content:none}
  tr.transaction-group-row{display:block;width:auto}
  tr.transaction-group-row th{display:flex;width:auto;align-items:center;padding:10px 12px}

  tr.cashflow-row,tr.deduction-row{display:grid;grid-template-columns:1fr auto;grid-template-areas:"item amount" "date balance" "actions actions";gap:5px 12px;padding:12px 4px;border-bottom:1px solid #e8ebef}
  tr.deduction-row{grid-template-areas:"item amount" "date date" "actions actions"}
  tr.cashflow-row .cell-item,tr.deduction-row .cell-item{grid-area:item;font-weight:700;font-size:14px}
  tr.cashflow-row .cell-amount,tr.deduction-row .cell-amount{grid-area:amount;font-size:15px;font-weight:700;text-align:right}
  tr.cashflow-row .cell-date,tr.deduction-row .cell-date{grid-area:date;color:var(--muted);font-size:12px}
  tr.cashflow-row .cell-balance{grid-area:balance;text-align:right;color:var(--muted);font-size:12px}
  tr.cashflow-row .cell-actions,tr.deduction-row .cell-actions{grid-area:actions;text-align:right}
  tr.cashflow-row [data-label]::before,tr.deduction-row [data-label]::before{content:attr(data-label) ": ";font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.04em;color:var(--muted)}
  tr.cashflow-row .cell-item::before,tr.cashflow-row .cell-amount::before,tr.deduction-row .cell-item::before,tr.deduction-row .cell-amount::before{content:none}

  /* Reported directly: "this just looks cluttered and out of order with
     the things we've added" -- Tracking account and Show in register
     had each been bolted onto whatever row still had a free slot
     (tracking squeezed next to Current balance, register alone on its
     own full-width row) as they shipped, one at a time, rather than as
     a single considered layout. Current balance now gets its own
     full-width row right under the account's name (the number someone
     opens this table to check), and the two checkboxes -- both boolean
     settings for this account, nothing else -- sit together on the row
     right after it. Same cells, same data, no behavior change: this is
     grid-area placement only, so the desktop <table>'s own column order
     (index.html) is untouched. */
  tr.settings-account-row{display:grid;grid-template-columns:1fr 1fr;grid-template-areas:"name type" "current current" "tracking register" "balance date";gap:7px 12px;padding:12px 4px;border-bottom:1px solid #e8ebef}
  tr.settings-account-row .cell-name{grid-area:name;font-weight:700;font-size:14px}
  tr.settings-account-row .cell-type{grid-area:type;text-align:left;color:var(--muted);font-size:13px}
  tr.settings-account-row .cell-current{grid-area:current;text-align:left}
  tr.settings-account-row .cell-tracking{grid-area:tracking;text-align:left}
  tr.settings-account-row .cell-register{grid-area:register;text-align:left}
  tr.settings-account-row .cell-balance{grid-area:balance;text-align:left}
  tr.settings-account-row .cell-balance .opening-balance-input{width:100%}
  tr.settings-account-row .cell-date{grid-area:date;text-align:left}
  tr.settings-account-row .cell-date .opening-balance-date{width:100%}
  tr.settings-account-row [data-label]::before{content:attr(data-label);display:block;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);margin-bottom:2px}
  tr.settings-account-row .cell-tracking[data-label]::before,
  tr.settings-account-row .cell-register[data-label]::before{content:none}
}


/* ---------------------------------------------------------------- Home -- */
/* Groundhog Budgeting's own palette starts here -- an ID selector already
   outranks .panel's own class rule regardless of source order, so this is
   the one override that needs no !important and no risk of a later .panel
   edit winning back. See the topbar comment above for why the chrome above
   this carries the same palette on every tab but everything below here is
   Home-only. */
#panel-home{background:var(--gb-bg);color:var(--gb-ink);font-family:'Poppins',sans-serif}
#panel-home h2{font:700 12.5px/1.3 'Poppins',sans-serif;margin:0;text-transform:none;letter-spacing:0}
.home-section{padding:18px 22px;border-bottom:1px solid var(--gb-nav-border)}
.home-section:last-child{border-bottom:0}
.home-section-head{margin-bottom:10px}
.home-nudge{margin:0;font-size:15px;font-weight:600;color:var(--gb-ink)}
/* Same red-warning language as .shortfall-banner and the Bills tab's own
   "Needs attention" group -- a plain sentence otherwise reads as neutral
   status, which is the opposite of what "something needs a look" should
   look like. */
.home-nudge-attention{color:var(--red)}
/* Four figures, two columns even on a phone -- "Assigned"/"Spent" carry no
   attention color of their own (neither is inherently good or bad news the
   way an overspent envelope is), but "Bills paid" and "Bills due" borrow
   the same green/red language as .available-cell so a glance answers "am I
   caught up" without reading the numbers. */
.home-summary-grid{display:grid;grid-template-columns:1fr 1fr;gap:7px}
.home-summary-card{display:flex;flex-direction:column;gap:5px;padding:12px;border-radius:10px;background:var(--gb-surface);border:1px solid var(--gb-surface-border)}
.home-summary-label{font-size:10.5px;font-weight:600;color:var(--gb-muted);text-transform:none;letter-spacing:0}
.home-summary-amount{font:700 15px/1.2 'Poppins',sans-serif;color:var(--gb-ink)}
.home-summary-amount.attention{color:var(--red)}
.home-summary-amount.ok{color:var(--gb-accent)}
.pinned-list{display:flex;flex-direction:column;gap:7px}
/* Reported directly, matching the reference mockup: a row (name, category,
   available) is now its own card, not a divided list line -- the exact
   same shape as .home-summary-card and .goal-card, since all three are
   "a card of Home-tab data" now rather than two different treatments. */
.pinned-row{display:flex;flex-direction:column;gap:7px;padding:11px 13px;border-radius:10px;background:var(--gb-surface);border:1px solid var(--gb-surface-border)}
.pinned-row-top{display:flex;justify-content:space-between;align-items:baseline;gap:10px}
.pinned-name{font-weight:700;font-size:12.5px;color:var(--gb-ink)}
.pinned-category{color:var(--gb-muted);font-weight:400;font-size:12px}
.pinned-available{font-weight:600;font-size:11px;color:var(--gb-muted);font-family:'Poppins',sans-serif}
/* Reuses envelopeProgressBar()'s own markup (see renderHome in app.js) --
   the Budget tab's own blue/red progress bar, one selector deep so it
   reads gold-on-track here without a second copy of that function. */
.pinned-row .envelope-progress{margin-top:0;background:var(--gb-track)}
.pinned-row .envelope-progress-fill{background:var(--gb-accent)}
.pinned-row .envelope-progress-fill.over{background:var(--red)}
#panel-home .empty{color:var(--gb-muted)}
#panel-home .goal-empty .button.primary{background:var(--gb-accent);color:var(--gb-bg)}
#panel-home .goal-empty .button.primary:hover{background:#195F30}
.goal-card{padding:13px;border-radius:10px;background:var(--gb-surface);border:1px solid var(--gb-surface-border)}
.goal-head{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:8px;gap:8px}
.goal-name{font-weight:700;font-size:13px;color:var(--gb-ink)}
.goal-percent{font-weight:700;font-size:11px;color:var(--gb-accent);white-space:nowrap}
.goal-bar{height:6px;border-radius:3px;background:var(--gb-track);overflow:hidden}
.goal-bar-fill{height:100%;background:var(--gb-accent);border-radius:3px}
.goal-amounts{margin-top:7px;color:var(--gb-muted);font-size:11px;font-weight:600;font-family:'Poppins',sans-serif}
#panel-home .bill-edit{color:var(--gb-muted)}
#panel-home .bill-edit:hover{color:var(--gb-ink)}
/* Pin toggle next to envelope-rename on the Budget tab -- unpinned is the
   same muted grey as .envelope-rename; .pinned turns navy so a glance down
   the envelope list shows which ones are pinned without opening Home.
   Budget's own tab, deliberately outside every #panel-home rule above --
   this class lives in this file's "Home" section only because it's
   thematically about pinning, not because it renders inside panel-home. */
.envelope-pin{border:0;background:transparent;color:#a9b2bf;cursor:pointer;font-size:12px;padding:0 2px}
.envelope-pin:hover{color:var(--navy)}
.envelope-pin.pinned{color:var(--navy)}
