/* ------------------------------------------------------------------ */
/* Theme: "Dimension" - charcoal glass panels over a photographic      */
/* background. Palette distilled from ingogoabattoir.co.za (HTML5 UP). */
/* ------------------------------------------------------------------ */
:root {
    /* Solid page background (replaces the photo so there is no iOS chrome-bar
       gap; theme-color in base.html matches this exactly so the bars blend).
       A subtle vignette is layered over this on <html> for depth, plus a
       vertical dark-edge gradient (--page-bg-edge) so the iOS status/address
       bars (which sample page content, ignoring theme-color) take a darker
       tone and blend in. */
    --page-bg: #0d47a1;        /* DEEP AZURE (centre fill) */
    --page-bg-edge: #082b62;   /* darker tone at top/bottom edges (iOS bars) */

    /* charcoal glass tints laid over the background */
    --bg: #1b1f22;
    --card: rgba(27, 31, 34, 0.80);
    --card2: rgba(255, 255, 255, 0.075);
    --ink: #ffffff;
    --muted: rgba(255, 255, 255, 0.55);
    --accent: #ffffff;             /* the signature white outline / ink accents */
    --good: #7fd1a8;
    --bad: #e74c3c;
    --warn: #ffb454;
    --line: rgba(255, 255, 255, 0.18);
    --line-strong: rgba(255, 255, 255, 0.35);
    --wash-2: rgba(255, 255, 255, 0.12);
    --tint-strong: rgba(27, 31, 34, 0.92);
    /* silver button surface - softer than pure white, reads as brushed metal */
    --silver: #c7ccd4;
    --silver-hi: #dde1e7;          /* top of the gradient / hover */
    --silver-lo: #aab0ba;          /* bottom of the gradient */
    --silver-edge: rgba(255, 255, 255, 0.55);
    /* charcoal drop shadow for headings that sit directly on the photo */
    --head-shadow: 0 2px 10px rgba(13, 15, 17, 0.85), 0 1px 3px rgba(13, 15, 17, 0.9);
}

@import url("https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,300italic,600,600italic");

* { box-sizing: border-box; }

/* Solid page background on the ROOT element. A background on <html> paints
   the whole canvas on every browser - including behind the iOS status bar and
   address bar - so it fills edge to edge with no chrome-bar gap.

   iOS note: on recent iOS Safari the status/address bars are drawn as a SOLID
   fill derived from the page content behind them, and the theme-color meta is
   ignored. So instead of theme-color we darken the actual page content at the
   top and bottom edges with a vertical gradient (dark -> azure -> dark). The
   bars then take that darker edge tone, blending in. Layers, top to bottom:
     1) vertical dark-edge gradient (the bit the iOS bars sample)
     2) radial vignette for depth
     3) solid azure fill (background-color) */
html {
    background-color: var(--page-bg);
    background-image:
        linear-gradient(to bottom,
            var(--page-bg-edge) 0%,
            rgba(0, 0, 0, 0) 14%,
            rgba(0, 0, 0, 0) 86%,
            var(--page-bg-edge) 100%),
        radial-gradient(ellipse at 50% 35%,
            rgba(0, 0, 0, 0) 30%,
            rgba(0, 0, 0, 0.55) 100%);
    background-repeat: no-repeat;
    background-attachment: fixed;   /* pin so the dark bands stay at the screen
                                       edges while content scrolls */
}

body {
    margin: 0;
    font-family: "Source Sans Pro", -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    font-weight: 300;
    color: var(--ink);
    font-size: 16px;
    line-height: 1.4;
    min-height: 100vh;
    /* transparent so the solid page background on <html> shows through */
    background: transparent;
    /* dark colour scheme so native controls (select popups, date pickers,
       scrollbars) composite against a dark backdrop instead of white */
    color-scheme: dark;
    /* stop iOS Safari auto-inflating text (a cause of control overflow) */
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

/* Top bar: frosted glass strip */
.topbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    padding: 12px 18px;
    /* with viewport-fit=cover the bar can sit under the iOS status bar; add the
       top safe-area inset so its content stays clear while the glass (and the
       background behind it) still extends to the very top edge. */
    padding-top: calc(12px + env(safe-area-inset-top, 0px));
    background: var(--card);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--line);
    position: sticky;
    top: 0;
    z-index: 10;
}
.topbar .brand { flex: 1; }
.topbar .brand a {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-weight: 600;
    color: var(--ink);
    text-transform: uppercase;
    letter-spacing: 4px;
    font-size: 0.95rem;
}
.topbar .brand a:hover { text-decoration: none; }
.topbar .brand img { width: 22px; height: 22px; object-fit: contain; }
.topbar .topnav { display: flex; gap: 20px; flex-wrap: wrap; }
.topbar .topnav a {
    color: var(--ink);
    opacity: 0.75;
    font-weight: 600;
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 2px;
    padding-bottom: 3px;
    border-bottom: 1px dotted transparent;
}
.topbar .topnav a:hover { opacity: 1; text-decoration: none; border-bottom-color: var(--line-strong); }
.topbar .who { color: var(--muted); font-size: 0.85rem; }

/* Nav: inline links on desktop, CSS-only hamburger dropdown on mobile.
   Uses a hidden checkbox + label (no <details>, no JS) so it renders
   consistently across browsers. Desktop hides the toggle entirely. */
.nav-toggle { display: none; }
.nav-burger { display: none; }

main { max-width: 900px; margin: 0 auto; padding: 16px; }

.foot {
    text-align: center;
    color: var(--ink);
    opacity: 0.75;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 3px;
    padding: 24px 0;
    text-shadow: var(--head-shadow);
}

/* Cards: frosted glass panels */
.card {
    background: var(--card);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid var(--line);
    border-radius: 4px;
    padding: 20px 22px;
    margin-bottom: 16px;
}
.card h2 {
    margin: 0 0 16px;
    font-size: 1rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 5px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--line);
}
.card h3 { margin: 16px 0 8px; font-size: 0.8rem; letter-spacing: 0.08em;
           text-transform: uppercase; color: var(--muted); }

/* Summary tiles: glass wash with the template's left-accent bar */
.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px,1fr)); gap: 12px; }
.tile {
    background: var(--card2);
    border: 1px solid var(--line);
    border-left: 3px solid var(--ink);
    border-radius: 4px;
    padding: 14px 16px;
}
.tile .label { color: var(--muted); font-size: 0.75rem; text-transform: uppercase;
               letter-spacing: 0.05em; }
.tile .value { font-size: 1.4rem; font-weight: 600; margin-top: 4px; }
.tile .value.big { font-size: 1.8rem; }
.value.good { color: var(--good); }
.value.bad { color: var(--bad); }
.value.warn { color: var(--warn); }
/* small sub-label under a tile value, e.g. "outstanding" beneath the Fixed
   settlement amount. Kept small so it does not inflate the tile on mobile. */
.tile .settle-note { font-size: 0.7rem; text-transform: uppercase;
                     letter-spacing: 0.05em; margin-top: 2px; }
.tile .settle-note.bad { color: var(--bad); }

/* Tables */
table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 8px 6px; border-bottom: 1px solid var(--line); }
th { color: var(--muted); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }

/* Progress bars. The empty track uses a darker charcoal tint (not the pale
   --card2 wash, which read as a near-white strip over the glass panels). */
.bar { background: rgba(13, 15, 17, 0.55); border-radius: 6px; height: 8px; overflow: hidden; margin-top: 4px; min-width: 80px; }
.bar > span { display: block; height: 100%; background: var(--accent); }
.bar.over > span { background: var(--bad); }

/* Gradient fill: colour reflects how full the bar is (green -> blue -> red).
   Technique: the TRACK carries the full green->blue->red gradient at its true
   width. The fill <span> is an opaque cover sitting over the UNFILLED portion
   (from --pct across to the right), so the gradient shows through only on the
   left up to the fill level. At 20% you see green, at ~50% blue, near 100% red. */
.bar-grad {
    overflow: hidden;
    background-image: linear-gradient(to right,
        var(--good) 0%,
        #3fb0ff 50%,
        var(--bad) 100%);
}
.bar-grad > span {
    /* cover the remainder to the right of the fill. MUST be opaque, otherwise
       the green->blue->red gradient on the track bleeds through and the bar
       looks far fuller (and redder) than it is. */
    width: calc(100% - var(--pct));
    margin-left: var(--pct);
    background: #15191d;
}
/* over budget: whole bar reads solid red */
.bar-grad.over { background-image: none; background-color: var(--bad); }
.bar-grad.over > span { width: 0; margin-left: 100%; }
/* keep the progress column wide enough that the bar is a bar, not a dot */
.dash-table .bar-col { width: 28%; min-width: 120px; }

/* Forms */
label { display: block; font-size: 0.8rem; color: var(--muted); margin-bottom: 4px; }
input, select, button {
    font: inherit;
    padding: 10px 12px;
    border-radius: 4px;
    border: 1px solid var(--line);
    background: var(--card2);
    color: var(--ink);
    width: 100%;
    max-width: 100%;        /* never exceed the container (iOS Safari fix) */
    box-sizing: border-box;
    min-height: 44px;       /* shared control height so date/select/text match */
}
/* checkboxes/radios are not full-height controls */
input[type="checkbox"], input[type="radio"] {
    width: auto;
    min-height: 0;
}
/* iOS Safari sizes native <select> to its widest option and ignores flex
   shrink; normalise the control so it respects its container. We remove the
   native chevron and draw our own so every select looks consistent. */
select {
    -webkit-appearance: none;
    appearance: none;
    text-overflow: ellipsis;
    padding-right: 30px;
    /* keep the same glass wash as the other inputs so controls match; the
       chevron is drawn on top via the two linear-gradient slivers. */
    background-image:
        linear-gradient(45deg, transparent 50%, var(--muted) 50%),
        linear-gradient(135deg, var(--muted) 50%, transparent 50%);
    background-position:
        calc(100% - 16px) calc(50% - 2px),
        calc(100% - 11px) calc(50% - 2px);
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
    /* theme ONLY the native option popup dark (not the closed control):
       color-scheme + explicit option colours, honoured by Chromium/Firefox. */
    color-scheme: dark;
}
/* charcoal option list (honoured by Chromium/Firefox; Safari ignores).
   Covers plain options, the disabled "Choose..." placeholder, and the
   <optgroup> label/rows - all of which otherwise render as white bands. */
select option,
select optgroup {
    background-color: #1b1f22;
    color: var(--ink);
}
select option:disabled,
select option:disabled:checked {
    background-color: #1b1f22;
    color: var(--muted);
}
select optgroup {
    font-weight: 600;
    color: var(--muted);
}
/* highlight the selected/hovered row with an OPAQUE lighter charcoal - a
   translucent white here composites against the popup's white backdrop and
   renders as a near-white band, which is the "still white" artifact. */
select option:checked,
select option:hover {
    background-color: #2c3238;
    color: var(--ink);
}
input:focus, select:focus { outline: 2px solid var(--accent); border-color: transparent; }

/* iOS Safari renders <input type=date/time/month> with a native control that
   has its own intrinsic height and centres its text, so it ends up taller than
   a sibling <select>. Normalise it to match the other controls exactly. */
input[type="date"],
input[type="month"],
input[type="time"],
input[type="datetime-local"] {
    -webkit-appearance: none;
    appearance: none;
    height: 44px;                 /* exact parity with select/text controls */
    min-height: 44px;             /* stop iOS inflating it */
    line-height: 1.4;
    text-align: left;
    display: block;
}
/* iOS wraps the value in these pseudo-elements; stop them adding height and
   force left alignment instead of the default centring. */
input[type="date"]::-webkit-date-and-time-value,
input[type="month"]::-webkit-date-and-time-value {
    text-align: left;
    margin: 0;
}
input[type="date"]::-webkit-datetime-edit,
input[type="month"]::-webkit-datetime-edit {
    padding: 0;
    line-height: 1.4;
}
/* keep the native calendar picker indicator tidy and visible on the dark theme */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="month"]::-webkit-calendar-picker-indicator {
    filter: invert(0.7);
    cursor: pointer;
}

.field { margin-bottom: 12px; }
.row { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px,1fr)); gap: 12px; }

/* Buttons: brushed-silver primary, hairline ghost outline (Dimension signature) */
button, .btn {
    background: linear-gradient(to bottom, var(--silver-hi), var(--silver-lo));
    color: #1b1f22;
    border: 1px solid var(--silver-edge);
    border-radius: 4px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 2px;
    font-size: 0.78rem;
    cursor: pointer;
    width: auto;
    /* inline-flex + min-height so anchor .btns (e.g. "Done") match the height
       of real <button>s, which get min-height:44px from the shared control
       rule. Without this, .btn anchors render shorter (BUG-004).
       flex:none stops the button stretching to fill a wrapping flex row (e.g.
       the .actions header on mobile), so it always sizes to its content. */
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    padding: 10px 18px;
    text-align: center;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45);
    transition: filter 0.2s, box-shadow 0.2s;
}
button:hover, .btn:hover {
    filter: brightness(1.05);
    text-decoration: none;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.6), 0 2px 10px rgba(0, 0, 0, 0.25);
}
button.ghost, .btn.ghost {
    background: transparent;
    border: 1px solid var(--line-strong);
    color: var(--ink);
    box-shadow: none;
}
button.ghost:hover, .btn.ghost:hover {
    filter: none;
    background: var(--card2);
    box-shadow: 0 0 0 1px var(--line-strong);
}
button.danger { background: transparent; border: 1px solid var(--bad); color: var(--bad); padding: 6px 10px; letter-spacing: 1px; }
button.danger:hover { filter: none; background: rgba(231, 57, 44, 0.12); }
.inline-form { display: inline; }

/* On the budget-edit screen the "Left to budget" pill is fixed over the top of
   main. Pad main down on pages that contain the pill so the flash message and
   heading start below it and are never obscured (BUG-003 follow-up). Scoped via
   :has() so other screens keep their normal spacing. */
main:has(#left-to-budget) { padding-top: calc(64px + env(safe-area-inset-top, 0px)); }

/* Flash messages */
.flashes { margin-bottom: 16px; }
.flash { padding: 10px 14px; border-radius: 10px; margin-bottom: 8px; }
.flash.ok { background: rgba(53,196,139,0.15); border: 1px solid var(--good); }
.flash.error { background: rgba(255,107,107,0.15); border: 1px solid var(--bad); }

/* Auth screens */
.auth-wrap { max-width: 360px; margin: 8vh auto; }

/* Brand mark (auth screens): circular logo badge above the name, with the
   name flanked by two hairlines - echoing the original Dimension header. */
.brand-mark { text-align: center; margin-bottom: 22px; }
.brand-badge {
    width: 84px;
    height: 84px;
    margin: 0 auto 16px;
    border: 1px solid var(--line-strong);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    background: var(--card2);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.35);
}
.brand-badge img { width: 54px; height: 54px; object-fit: contain; }
.brand-title {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 16px;
    margin: 0;
    font-weight: 600;
    font-size: 1.6rem;
    text-transform: uppercase;
    letter-spacing: 8px;
    text-shadow: var(--head-shadow);
}
/* the two white lines on either side of the word */
.brand-title::before,
.brand-title::after {
    content: "";
    height: 1px;
    flex: 1 1 auto;
    max-width: 70px;
    background: var(--line-strong);
}
/* nudge the word to sit optically centred despite the letter-spacing */
.brand-title span { padding-left: 8px; }

.center-note { text-align: center; color: var(--ink); opacity: 0.85; margin-top: 16px; text-shadow: var(--head-shadow); }

/* Centre the primary action on auth screens (login / register / rate-limit) */
.auth-wrap form > button[type="submit"],
.auth-wrap form > .form-actions { display: block; margin-left: auto; margin-right: auto; }
.auth-wrap .form-actions { display: flex; justify-content: center; }

.pill { font-size: 0.7rem; padding: 2px 8px; border-radius: 999px; background: var(--card2); color: var(--muted); }
.muted { color: var(--muted); }
.actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
/* Budget edit header: heading on the left, Done on the right (desktop). */
.budget-head { justify-content: space-between; }
/* On mobile the heading wraps to its own line; centre the Done button on the
   line below it so it reads as an intentional action, not a stray left-aligned
   button (BUG-004 mobile follow-up). */
@media (max-width: 640px) {
    .budget-head { justify-content: center; }
    .budget-head h2 { flex: 1 1 100%; text-align: center; }
    .budget-head .btn { flex: 0 0 auto; }
}
/* The month/period selector lives in a .actions header next to an <h2>.
   Let its form shrink and cap the select width so it can't balloon or overlap
   the heading on iOS Safari (where native selects ignore flex shrink). */
.actions form { min-width: 0; flex: 0 1 auto; }
.actions select {
    min-width: 0;
    width: auto;
    max-width: 55vw;
}

/* sticky add-expense bar on mobile */
.quick-add { position: sticky; bottom: 0; background: var(--card); border-top: 1px solid var(--line);
             padding: 12px; margin: 16px -16px -16px; }

/* brief green pulse on a row after an in-place (AJAX) save */
@keyframes savedPulse {
    0%   { background: rgba(53,196,139,0.28); }
    100% { background: transparent; }
}
tr.just-saved td { animation: savedPulse 1s ease-out; }

/* fixed-expense checklist (card list, responsive) */
.status { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.04em; }
.status.done { color: var(--good); }
.status.open { color: var(--warn); }
.status.over { color: var(--bad); }
.mini-bar { background: rgba(13, 15, 17, 0.55); border-radius: 6px; height: 6px; overflow: hidden; margin-top: 4px; }
.mini-bar > span { display: block; height: 100%; background: var(--good); }
.mini-bar.over > span { background: var(--bad); }

.fixed-list { display: flex; flex-direction: column; gap: 10px; }
.fixed-item {
    background: var(--card2);
    border: 1px solid var(--line);
    border-left: 3px solid var(--line);
    border-radius: 12px;
    padding: 12px;
}
.fixed-item.done { border-left-color: var(--good); }
.fixed-item.over { border-left-color: var(--bad); }
.fixed-item.open { border-left-color: var(--warn); }
.fixed-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 12px;
    flex-wrap: wrap;
}
.fixed-name { display: flex; flex-direction: column; gap: 2px; }
.fixed-figures {
    display: flex;
    flex-direction: column;
    gap: 2px;
    text-align: right;
    font-size: 0.85rem;
    font-variant-numeric: tabular-nums;
}
.fixed-controls { display: flex; gap: 8px; align-items: flex-end; margin-top: 10px; flex-wrap: wrap; }
.fixed-log { display: flex; gap: 8px; flex: 1; min-width: 0; margin: 0; align-items: end; }
.fixed-log input[type="date"] { flex: 1 1 140px; min-width: 0; }
.fixed-log input[type="number"] { flex: 1 1 100px; min-width: 0; }
.fixed-log button { white-space: nowrap; }
.fixed-controls .inline-form { display: flex; }

@media (max-width: 560px) {
    .fixed-figures { text-align: left; }
    /* log controls sit on their own full-width row, button below the inputs */
    .fixed-log { flex-wrap: wrap; }
    .fixed-log input[type="date"],
    .fixed-log input[type="number"] { flex: 1 1 100%; }
    .fixed-log button { flex: 1 1 100%; }
    .fixed-controls { gap: 10px; }
    .fixed-controls > .inline-form,
    .fixed-controls > .inline-form button { flex: 1 1 100%; }
}

/* "show all" expander */
.expander { margin-top: 8px; }
.expander > summary {
    cursor: pointer;
    color: var(--accent);
    font-weight: 600;
    font-size: 0.85rem;
    padding: 6px 0;
    list-style-position: inside;
}
.expander > summary:hover { text-decoration: underline; }

/* ------------------------------------------------------------------ */
/* Mobile layout                                                       */
/* ------------------------------------------------------------------ */
@media (max-width: 640px) {
    /* --- Top navigation: CSS-only hamburger dropdown --- */
    .topbar { position: relative; }
    /* show the burger button, hide the inline nav until toggled */
    .nav-burger {
        display: inline-block;
        order: 3;
        cursor: pointer;
        padding: 8px 12px;
        border-radius: 10px;
        border: 1px solid var(--line);
        background: var(--card2);
        color: var(--ink);
        font-weight: 700;
        font-size: 0.85rem;
        width: auto;
        margin: 0;
    }
    .topbar .topnav { display: none; }
    /* checkbox checked -> reveal the dropdown panel */
    .nav-toggle:checked ~ .topnav {
        display: flex;
        flex-direction: column;
        gap: 2px;
        position: absolute;
        top: 100%;
        left: 8px;
        right: 8px;
        background: var(--tint-strong);
        backdrop-filter: blur(12px);
        -webkit-backdrop-filter: blur(12px);
        border: 1px solid var(--line);
        border-radius: 4px;
        padding: 8px;
        margin-top: 6px;
        z-index: 20;
        box-shadow: 0 10px 30px rgba(0,0,0,0.4);
    }
    .nav-toggle:checked ~ .topnav a { padding: 10px 12px; border-radius: 4px; border-bottom: none; }
    .nav-toggle:checked ~ .topnav a:hover { background: var(--wash-2); }
    /* the duplicate inline logout isn't needed once Logout is in the menu */
    .topbar .who { display: none; }

    /* --- Stacky tables: turn rows into labelled cards --- */
    table.stacky thead { display: none; }
    table.stacky, table.stacky tbody, table.stacky tfoot,
    table.stacky tr, table.stacky td {
        display: block;
        width: 100%;
    }
    table.stacky tr {
        background: var(--card2);
        border: 1px solid var(--line);
        border-radius: 12px;
        padding: 8px 12px;
        margin-bottom: 10px;
    }
    table.stacky td {
        border: none;
        padding: 4px 0;
        text-align: right;
        display: flex;
        justify-content: space-between;
        align-items: center;
        gap: 12px;
    }
    table.stacky td[data-label]::before {
        content: attr(data-label);
        color: var(--muted);
        font-size: 0.72rem;
        text-transform: uppercase;
        letter-spacing: 0.05em;
        font-weight: 600;
        text-align: left;
    }
    /* a cell with no label (e.g. the delete X) right-justifies its control */
    table.stacky td:not([data-label]) { justify-content: flex-end; }
    /* totals footer reads as its own labelled card with a "Total" heading */
    table.stacky tfoot th {
        display: block;
        padding: 2px 0 6px;
        color: var(--ink);
        font-size: 0.72rem;
        text-transform: uppercase;
        letter-spacing: 0.05em;
    }
    /* progress bar gets a full-width row of its own so it's a real bar */
    .dash-table.stacky td.bar-col { display: block; width: 100%; }
    .dash-table.stacky td.bar-col::before { display: block; margin-bottom: 4px; }
    .dash-table.stacky .bar { width: 100%; min-width: 0; height: 10px; margin-top: 0; }

    /* --- Budget edit tables: stack each row into a card --- */
    .budget-table thead { display: none; }
    .budget-table, .budget-table tbody, .budget-table tfoot { display: block; width: 100%; }
    .budget-table tr {
        display: block;
        background: var(--card2);
        border: 1px solid var(--line);
        border-radius: 12px;
        padding: 10px 12px;
        margin-bottom: 10px;
    }
    .budget-table td {
        display: block;
        width: 100%;
        border: none;
        padding: 6px 0;
        text-align: left;
    }
    .budget-table td[data-label]::before {
        content: attr(data-label);
        display: block;
        color: var(--muted);
        font-size: 0.72rem;
        text-transform: uppercase;
        letter-spacing: 0.05em;
        font-weight: 600;
        margin-bottom: 4px;
    }
    /* inputs fill the row; numbers left-align when stacked for easier typing */
    .budget-table td input { width: 100%; }
    .budget-table td input.num { text-align: left; }
    /* Save + delete/remove land on one tidy full-width row of buttons */
    .budget-table td.actions {
        display: flex;
        gap: 8px;
        padding-top: 10px;
    }
    .budget-table td.actions button { flex: 1; width: auto; }
    .budget-table td.actions .inline-form { display: flex; flex: 1; }
    .budget-table td.actions .inline-form button { width: 100%; }
    /* totals footer row reads as a small summary card */
    .budget-table tfoot tr { background: transparent; border: none; padding: 4px 0; }
    .budget-table tfoot th { display: block; padding: 0 0 4px; }
}

/* ------------------------------------------------------------------ */
/* Collapsible sections                                                */
/* ------------------------------------------------------------------ */
.collapse-toggle {
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    user-select: none;
}
.collapse-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px; }
.collapse-toggle .chevron {
    flex: 0 0 auto;
    width: 10px;
    height: 10px;
    border-right: 2px solid var(--muted);
    border-bottom: 2px solid var(--muted);
    transform: rotate(45deg);               /* points down = expanded */
    transition: transform 0.2s ease;
    margin-right: 2px;
}
.is-collapsed .collapse-toggle .chevron {
    transform: rotate(-45deg);              /* points right = collapsed */
}
.collapse-body {
    overflow: hidden;
    transition: max-height 0.25s ease;
}
.collapse-body.collapsed { max-height: 0 !important; }

/* ------------------------------------------------------------------ */
/* Return-to-top floating button                                       */
/* ------------------------------------------------------------------ */
.to-top {
    position: fixed;
    right: 16px;
    bottom: 16px;
    width: 44px;
    height: 44px;
    padding: 0;
    border-radius: 50%;
    border: 1px solid var(--line-strong);
    background: var(--tint-strong);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    color: var(--ink);
    font-size: 1.2rem;
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    box-shadow: 0 6px 20px rgba(0,0,0,0.35);
    opacity: 0;
    visibility: hidden;
    transform: translateY(8px);
    transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s, background-color 0.2s, box-shadow 0.2s;
    z-index: 30;
}
.to-top.show { opacity: 0.95; visibility: visible; transform: translateY(0); }
.to-top:hover { opacity: 1; background: var(--wash-2); box-shadow: 0 0 0 1px var(--ink), 0 6px 20px rgba(0,0,0,0.35); }
.to-top:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
/* respect iOS safe area and keep clear of the bottom edge on phones */
@supports (padding: max(0px)) {
    .to-top { bottom: max(16px, env(safe-area-inset-bottom)); }
}

/* ------------------------------------------------------------------ */
/* "Left to budget" floating chip (budget-edit page only)              */
/* ------------------------------------------------------------------ */
/* Fixed to the top-centre of the viewport, stays put while scrolling, */
/* and shows the live unassigned-pot figure as amounts are edited.     */
.left-to-budget {
    position: fixed;
    /* Sit BELOW the sticky top bar, not over it, so it never obscures or
       intercepts the navigation (BUG-003). The bar is ~56px tall; add the iOS
       safe-area inset so the offset is correct on notched devices too. */
    top: calc(64px + env(safe-area-inset-top, 0px));
    left: 50%;
    transform: translateX(-50%);
    display: inline-flex;
    align-items: baseline;
    gap: 8px;
    padding: 9px 18px;
    border-radius: 999px;
    border: 1px solid var(--line-strong);
    background: var(--tint-strong);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    color: var(--ink);
    box-shadow: 0 6px 20px rgba(0,0,0,0.35);
    /* below the sticky top bar (z-index:10) so it can never intercept nav
       clicks; it no longer overlaps the bar vertically in any case. */
    z-index: 9;
    white-space: nowrap;
    max-width: calc(100vw - 24px);
}
.left-to-budget .ltb-label {
    font-size: 0.8rem;
    color: var(--muted, #9aa);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.left-to-budget .ltb-value {
    font-size: 1.05rem;
    font-weight: 700;
}
/* over-budget: more assigned than available. Turn the whole chip red so it
   is impossible to miss that the pot is over-committed. */
.left-to-budget.over {
    background: #c0392b;
    border-color: #e74c3c;
    color: #fff;
}
.left-to-budget.over .ltb-label {
    color: rgba(255, 255, 255, 0.85);
}
/* on narrow screens keep it compact so it never covers the whole width */
@media (max-width: 480px) {
    .left-to-budget { padding: 6px 12px; gap: 6px; }
    .left-to-budget .ltb-label { font-size: 0.7rem; }
    .left-to-budget .ltb-value { font-size: 0.95rem; }
}
/* keep clear of the sticky top bar AND the iOS safe area at the top */
@supports (padding: max(0px)) {
    .left-to-budget { top: calc(64px + max(0px, env(safe-area-inset-top))); }
}

/* ------------------------------------------------------------------ */
/* Category balance indicator (shown when picking a category to log)   */
/* ------------------------------------------------------------------ */
.cat-balance {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;   /* spread the three figures across the block */
    gap: 10px 16px;
    width: 100%;
    margin: 0 0 12px;                 /* sits as its own block under date+category */
    padding: 12px 14px;
    background: var(--card2);
    border: 1px solid var(--line);
    border-radius: 10px;
    font-size: 0.9rem;
    font-variant-numeric: tabular-nums;
}
.cat-balance .cb-item { display: inline-flex; flex-direction: column; gap: 3px; }
.cat-balance .cb-label {
    color: var(--muted);
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.cat-balance .good { color: var(--good); }
.cat-balance .bad { color: var(--bad); }
.cat-balance .cb-value { font-weight: 700; }

/* single credit checkbox on the log entry form */
.credit-check { margin: 0 0 14px; }
.credit-check span { font-size: 0.88rem; }

/* ------------------------------------------------------------------ */
/* Daily allowance category picker (Settings)                          */
/* ------------------------------------------------------------------ */
.allowance-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: 8px 16px;
}
.check-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    background: var(--card2);
    border: 1px solid var(--line);
    border-radius: 10px;
    cursor: pointer;
    margin: 0;
}
.check-row input[type="checkbox"] {
    width: 18px;
    height: 18px;
    flex: 0 0 auto;
    accent-color: var(--accent);
    cursor: pointer;
}
.check-row span { color: var(--ink); font-size: 0.9rem; }

/* ------------------------------------------------------------------ */
/* Segmented control (entry type: Expense / Credit)                    */
/* ------------------------------------------------------------------ */
.segmented { display: flex; gap: 8px; flex-wrap: wrap; }
.seg-opt {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 12px;
    background: var(--card2);
    border: 1px solid var(--line);
    border-radius: 10px;
    cursor: pointer;
    margin: 0;
    flex: 1 1 auto;
}
.seg-opt input[type="radio"] { width: 16px; height: 16px; flex: 0 0 auto; accent-color: var(--accent); margin: 0; }
.seg-opt span { color: var(--ink); font-size: 0.88rem; }
/* highlight the selected option */
.seg-opt:has(input:checked) { border-color: var(--accent); background: var(--wash-2); }

/* credit badge in the expense log */
.pill-credit { background: rgba(53,196,139,0.18); color: var(--good); margin-left: 4px; }

/* ------------------------------------------------------------------ */
/* Months page: per-month row with starting-balance editor            */
/* ------------------------------------------------------------------ */
.month-row {
    background: var(--card2);
    border: 1px solid var(--line);
    border-radius: 12px;
    padding: 12px;
    margin-bottom: 10px;
}
.month-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 10px;
}
/* Month row action buttons: generous, consistent padding so View / Edit feel
   like intentional primary actions rather than cramped afterthoughts. */
.month-head .actions { gap: 10px; }
.month-head .actions .btn {
    padding: 11px 22px;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
}

.startbal-form {
    display: flex;
    gap: 8px;
    align-items: flex-end;
    flex-wrap: wrap;
}
.startbal-form button { white-space: nowrap; }

/* ------------------------------------------------------------------ */
/* Modal (budget transfer popup)                                       */
/* ------------------------------------------------------------------ */
.modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    z-index: 50;
}
.modal-backdrop[hidden] { display: none; }
body.modal-open { overflow: hidden; }           /* stop background scroll */
.modal {
    background: var(--tint-strong);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border: 1px solid var(--line);
    border-radius: 4px;
    padding: 16px;
    width: 100%;
    max-width: 460px;
    max-height: 90vh;
    overflow-y: auto;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}
.modal-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 8px;
}
.modal-close {
    width: auto;
    min-height: 0;
    padding: 6px 10px;
    background: transparent;
    border: 1px solid var(--line);
    color: var(--muted);
    border-radius: 8px;
}
.modal-close:hover { color: var(--ink); }
.modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 4px;
}

/* right-justified action row (e.g. the log form's Add entry button) */
.form-actions { display: flex; justify-content: flex-end; }
