/* BPD custom styles — overrides on top of Bootstrap 5.

   Theme: Berry / Plum / Mint, taken from the office logo (a puzzle-piece
   tooth in a pink → purple → green gradient). Deep plum sidebar, berry
   primary accent, mint as the friendly secondary, amber reserved for
   financial emphasis. Noah (indigo) and CellHub (blue/grey) are the siblings. Semantic status
   colors (good/warn/bad on badges, stat tiles) are separate from the brand
   accent — see docs/00_PROJECT.md.
   ───────────────────────────────────────────────────────────────────────── */

@import url('https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&family=Public+Sans:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap');

:root {
    --bpd-ink:         #1f1424;   /* body text */
    --bpd-paper:       #faf6f9;   /* body background */
    --bpd-sub:         #75667a;   /* muted text */
    --bpd-border:      #efe3ec;

    --bpd-accent:      #c0267e;   /* primary accent — berry */
    --bpd-accent-dark: #9e1c67;   /* hover/active */
    --bpd-accent-tint: #fbe7f2;   /* chip background */

    --bpd-plum:        #6d2c91;   /* secondary — purple */
    --bpd-mint:        #1f9d74;   /* secondary — green */
    --bpd-mint-tint:   #e3f6ef;

    --bpd-gold:        #b45309;   /* financial emphasis, secondary accent */

    /* Semantic — deliberately distinct from the brand accent above */
    --bpd-good:        #15803d;
    --bpd-good-tint:   #eafaf0;
    --bpd-bad:         #b91c1c;
    --bpd-bad-tint:    #fdecec;
    --bpd-warn:        #b45309;
    --bpd-warn-tint:   #fdf3e7;
}

/* Body background + base typography */
body {
    background-color: var(--bpd-paper);
    color: var(--bpd-ink);
    font-family: 'Public Sans', system-ui, sans-serif;
}
h1, h2, h3, h4, h5, h6 {
    font-family: 'Sora', system-ui, sans-serif;
    font-weight: 700;
    letter-spacing: -0.01em;
}
.navbar-text {
    font-family: 'Sora', system-ui, sans-serif;
    font-weight: 700 !important;
}

/* Tabular figures — dollar amounts, dates, references, IDs. Apply this
   class wherever columns of numbers/dates need to line up. */
.mono {
    font-family: 'IBM Plex Mono', ui-monospace, monospace;
    font-variant-numeric: tabular-nums;
}

/* Re-skin Bootstrap's primary to berry so buttons, links, and badges that
   use .btn-primary / .text-primary / .bg-primary inherit the BPD accent
   without touching every template. */
.btn-primary {
    --bs-btn-bg: var(--bpd-accent);
    --bs-btn-border-color: var(--bpd-accent);
    --bs-btn-hover-bg: var(--bpd-accent-dark);
    --bs-btn-hover-border-color: var(--bpd-accent-dark);
    --bs-btn-active-bg: var(--bpd-accent-dark);
    --bs-btn-active-border-color: var(--bpd-accent-dark);
    --bs-btn-disabled-bg: var(--bpd-accent);
    --bs-btn-disabled-border-color: var(--bpd-accent);
}
.text-primary { color: var(--bpd-accent) !important; }
.bg-primary   { background-color: var(--bpd-accent) !important; }
.link-primary, a.text-primary { color: var(--bpd-accent) !important; }
.btn { border-radius: .5rem; }

/* Cards — softer border + layered shadow instead of Bootstrap's flat shadow-sm */
.card {
    border: 1px solid var(--bpd-border) !important;
    border-radius: .85rem !important;
    box-shadow: 0 1px 2px rgba(24,23,44,.03), 0 6px 20px -14px rgba(24,23,44,.25) !important;
}
.card-header { background: #fff !important; }

/* Badges → dot + tinted-pill chips. Zero template changes required: every
   existing .badge.bg-* across all modules picks this up automatically. */
.badge {
    font-weight: 600;
    font-size: .72rem;
    padding: .32em .65em .32em .55em;
    border-radius: 999px;
    display: inline-flex;
    align-items: center;
    gap: .35em;
}
.badge::before {
    content: '';
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    flex: none;
}
.badge.bg-success { background: var(--bpd-good-tint) !important; color: var(--bpd-good) !important; }
.badge.bg-danger  { background: var(--bpd-bad-tint)  !important; color: var(--bpd-bad)  !important; }
.badge.bg-warning { background: var(--bpd-warn-tint) !important; color: var(--bpd-warn) !important; }
.badge.bg-info    { background: var(--bpd-accent-tint) !important; color: var(--bpd-accent) !important; }
.badge.bg-primary { background: var(--bpd-accent-tint) !important; color: var(--bpd-accent) !important; }
.badge.bg-secondary,
.badge.bg-light {
    background: var(--bpd-paper) !important;
    color: var(--bpd-sub) !important;
    border: 1px solid var(--bpd-border);
}

/* Count pill for card-header section counts, e.g. "Repair History (3)" */
.count-pill {
    background: var(--bpd-paper);
    border: 1px solid var(--bpd-border);
    color: var(--bpd-sub);
    font-size: .68rem;
    font-weight: 700;
    padding: .1rem .55rem;
    border-radius: 999px;
}

/* Data tables — quiet uppercase headers, hover row, tabular alignment */
.table thead th {
    text-transform: uppercase;
    font-size: .68rem;
    letter-spacing: .06em;
    font-weight: 700;
    color: var(--bpd-sub);
    background: transparent !important;
    border-bottom: 1px solid var(--bpd-border) !important;
}
.table > :not(caption) > * > td {
    border-bottom-color: var(--bpd-border);
}
.table-hover > tbody > tr:hover > * {
    --bs-table-hover-bg: #faf9fe;
}

/* Scorecard stat tiles — accent-striped, replaces plain centered columns.
   acc-{bad,good,warn,neutral} sets which edge color; semantic, not brand. */
.stat-tile {
    border: 1px solid var(--bpd-border);
    border-left: 3px solid var(--bpd-border);
    border-radius: .65rem;
    padding: .7rem .8rem;
    height: 100%;
}
.stat-tile.acc-bad     { border-left-color: var(--bpd-bad); }
.stat-tile.acc-good    { border-left-color: var(--bpd-good); }
.stat-tile.acc-warn    { border-left-color: var(--bpd-warn); }
.stat-tile.acc-neutral { border-left-color: var(--bpd-accent); }
.stat-tile .lbl {
    font-size: .65rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--bpd-sub);
    font-weight: 700;
}
.stat-tile .val {
    font-family: 'IBM Plex Mono', ui-monospace, monospace;
    font-variant-numeric: tabular-nums;
    font-size: 1.2rem;
    font-weight: 600;
    margin-top: .3rem;
}
.stat-tile .val.text-danger  { color: var(--bpd-bad) !important; }
.stat-tile .val.text-success { color: var(--bpd-good) !important; }
.stat-tile .sub {
    font-size: .7rem;
    color: var(--bpd-bad);
    margin-top: .15rem;
    font-weight: 600;
}

/* Sticky table headers need an OPAQUE background — the quiet-header rule
   above sets `background: transparent !important`, which on a sticky header
   lets the scrolling rows show straight through it. */
.sticky-head thead th {
    position: sticky; top: 0; z-index: 3;
    background: #f2f0fb !important;
    box-shadow: inset 0 -1px 0 var(--bpd-border, #efe3ec);
}
.sticky-head tfoot td {
    position: sticky; bottom: 0; z-index: 3;
    background: #f2f0fb !important;
    box-shadow: inset 0 1px 0 var(--bpd-border, #efe3ec);
}

/* A panel the attention queue jumped to, so the eye lands on it. */
@keyframes flash-attn { 0%, 100% { background: transparent; } 30% { background: #fff3cd; } }
.flash-attn { animation: flash-attn 1.4s ease-in-out; }

/* Remove number-input spinner buttons site-wide (Chrome/Edge/Safari + Firefox). */
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
}
input[type="number"] {
    -moz-appearance: textfield;
    appearance: textfield;
}

/* Sidebar background — deep plum gradient. */
nav.bpd-sidebar {
    background: linear-gradient(180deg, #3a1745, #24102c);
}

/* Sidebar active link highlight (top-level nav). */
.sidebar .nav-link.active {
    background-color: rgba(242, 123, 182, 0.18);   /* soft berry */
    border-left: 3px solid #f27bb6;
    padding-left: calc(1rem - 3px);                /* default nav-link px is 1rem */
    color: #fff !important;
    font-weight: 600;
}

/* Sub-nav (ms-3 children) get the same accent at a lighter tint. */
.sidebar .nav-link.sb-sub-active {
    background-color: rgba(129, 123, 255, 0.14);
    border-left: 3px solid #f27bb6;
    padding-left: calc(0.75rem - 3px);
    color: #fff !important;
    font-weight: 500;
}

/* Sidebar hover */
.sidebar .nav-link:hover:not(.disabled):not(.active):not(.sb-sub-active) {
    background-color: rgba(255, 255, 255, 0.08);
}

/* Sidebar — default (expanded) state */
nav.sidebar {
    width: 240px;
    min-height: 100vh;
    transition: width .15s ease;
}

/* Toggle chevron button — visible in both states */
#sb-toggle {
    background: transparent;
    border: none;
    color: rgba(255, 255, 255, .55);
    padding: .15rem .35rem;
    border-radius: .25rem;
    cursor: pointer;
    line-height: 1;
}
#sb-toggle:hover {
    color: #fff;
    background: rgba(255, 255, 255, .08);
}

/* ─── Collapsed state ───────────────────────────────────────────────
   Desktop only. Below lg the sidebar is a drawer and 'collapsed' has no
   meaning — see THE PHONE at the foot of this file, which undoes these
   for narrow viewports rather than duplicating the fence here. */
html.sb-collapsed nav.sidebar {
    width: 64px;
    padding-left: .5rem !important;
    padding-right: .5rem !important;
}
html.sb-collapsed nav.sidebar .sb-brand { display: none !important; }
html.sb-collapsed nav.sidebar .sb-brand-row { justify-content: center !important; }
html.sb-collapsed nav.sidebar .nav-link {
    font-size: 0 !important;
    text-align: center;
    padding-left: 0 !important;
    padding-right: 0 !important;
}
html.sb-collapsed nav.sidebar .nav-link > i {
    font-size: 1.1rem !important;
    margin-right: 0 !important;
}
html.sb-collapsed nav.sidebar .nav-link > span,
html.sb-collapsed nav.sidebar .nav-link > .badge,
html.sb-collapsed nav.sidebar .sb-hide,
html.sb-collapsed nav.sidebar hr {
    display: none !important;
}
html.sb-collapsed nav.sidebar li.ms-3 { margin-left: 0 !important; }
html.sb-collapsed nav.sidebar li.ms-3 .nav-link > i {
    font-size: .9rem !important;
    opacity: .85;
}

/* Make flash messages slightly compact */
.alert {
    padding: 0.5rem 0.75rem;
}

/* The main content column, beside the sidebar.

   min-width:0 is load-bearing, not tidying. A flex item defaults to
   min-width:auto, meaning it refuses to shrink below its content's
   min-content width — so one nowrap child (a tab strip, a balance strip, a
   wide table) makes the entire page wider than the window rather than
   scrolling inside its own box, and `overflow-x:auto` on that child cannot
   prevent it, because the child is not what grew. */
.bpd-main { min-width: 0; }

/* ─── CFO: branch tab strip ───────────────────────────────────────────
   The sidebar says which part of CFO; these say which screen inside it.
   Kept visually quieter than Bootstrap's default tabs — this is a strip
   inside a page, not the page's own identity. */
.cfo-tabs {
    border-bottom: 1px solid var(--bs-border-color);
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
}
.cfo-tabs::-webkit-scrollbar { display: none; }
.cfo-tabs .nav-link {
    color: #6c757d;
    border: 0;
    border-bottom: 2px solid transparent;
    border-radius: 0;
    padding: .4rem .85rem;
    white-space: nowrap;
    font-size: .9rem;
}
.cfo-tabs .nav-link:hover { color: #495057; background: rgba(0, 0, 0, .03); }
.cfo-tabs .nav-link.active {
    color: #6f42c1;
    background: transparent;
    border-bottom-color: #f27bb6;
    font-weight: 600;
}
.cfo-tabs .badge { font-size: .68rem; vertical-align: .1em; }

/* ─── CFO: one-row indicator strip ────────────────────────────────────
   Banking's balances + progress in a single ~76px band. It scrolls
   sideways rather than wrapping: the register below is already a long
   page, and a strip that wraps to three rows is the four-card block this
   replaced. */
.cfo-strip {
    display: flex;
    gap: .5rem;
    align-items: stretch;
    overflow-x: auto;
    padding-bottom: .25rem;
    scrollbar-width: thin;
}
.cfo-strip-gap { flex: 1 0 .5rem; }        /* pushes the stats to the right */

.cfo-chip {
    flex: 0 0 auto;
    min-width: 8.5rem;
    /* Capped so an account with a long name cannot push the rest off-screen
       on its own — the label ellipsises instead. */
    max-width: 11rem;
    padding: .4rem .7rem;
    border: 1px solid var(--bs-border-color);
    border-radius: .5rem;
    background: #fff;
    text-decoration: none;
    color: inherit;
    transition: border-color .12s ease, box-shadow .12s ease;
}
.cfo-chip:hover { border-color: #f27bb6; box-shadow: 0 1px 4px rgba(0, 0, 0, .07); }
.cfo-chip.is-on { border-color: #f27bb6; background: rgba(134, 131, 240, .07); }
.cfo-chip-stat { min-width: 7.5rem; }
/* Same thin-mark treatment as the landing page's account bars. */
.cfo-chip-bar {
    height: 3px; border-radius: 2px; background: var(--cfo-trk); margin-top: .3rem;
}
.cfo-chip-bar > span {
    display: block; height: 100%; border-radius: 2px; background: var(--cfo-good);
}

.cfo-chip-k {
    font-size: .68rem;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: #6c757d;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.cfo-chip-v { font-size: 1.25rem; line-height: 1.2; font-weight: 600; }
.cfo-chip-s {
    font-size: .68rem;
    color: #6c757d;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ─── CFO: financial standing ─────────────────────────────────────────
   Status steps are the fixed four — never themed, never reused as a
   series colour. They pair with an icon and a label everywhere they are
   used, because warning and serious sit under 3:1 on a light surface by
   design and colour may never be the only thing carrying the meaning.
   The blue is the sequential ramp: 500 for a fill, 100 for its track. */
:root {
    /* FILL steps — for marks (bars, icons, rules). The fixed status four. */
    --cfo-good: #0ca30c;
    --cfo-warn: #fab219;
    --cfo-bad:  #d03b3b;

    /* INK steps — for TEXT, and they must be different steps. The fill amber
       sits at 1.83:1 on white: legal on a bar the icon and label also
       identify, unreadable as a numeral. These three clear 4.5:1 (7.54 /
       5.54 / 6.69), so a figure stays legible without leaning on its label. */
    --cfo-good-ink: #006300;
    --cfo-warn-ink: #8a6100;
    --cfo-bad-ink:  #b02525;

    --cfo-seq:  #256abf;   /* sequential blue, step 500 */
    --cfo-trk:  #cde2fb;   /* same ramp, step 100 — the unfilled track */
}

.cfo-standing {
    display: grid;
    /* 13rem, not 15: the health row is FIVE cards, and at 15rem the fifth
       wrapped alone onto a second line — which reads as a separate, lesser
       thing rather than the fifth of five equals. */
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    gap: .75rem;
    align-items: stretch;
}

/* Hero figure — the single number the page leads with. Proportional
   figures, not tabular: at display sizes tabular-nums gives every digit
   the width of a 0 and the number reads loose. */
.cfo-hero {
    grid-column: span 2;
    padding: 1rem 1.25rem;
    border: 1px solid var(--bs-border-color);
    border-left: 4px solid var(--cfo-seq);
    border-radius: .5rem;
    background: #fff;
}
.cfo-hero-k {
    font-size: .72rem; text-transform: uppercase; letter-spacing: .05em;
    color: #6c757d;
}
.cfo-hero-v { font-size: 3rem; line-height: 1.05; font-weight: 600; }
.cfo-hero-s { font-size: .8rem; color: #6c757d; margin-top: .15rem; }
.cfo-hero-flow {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem 1.1rem;
    margin-top: .9rem;
    padding-top: .7rem;
    border-top: 1px solid var(--bs-border-color);
    font-size: .82rem;
}
.cfo-flow-in  { color: var(--cfo-good-ink); }
.cfo-flow-out { color: var(--cfo-bad-ink); }
.cfo-flow-net { margin-left: auto; }

.cfo-tile {
    padding: .7rem .9rem;
    border: 1px solid var(--bs-border-color);
    border-radius: .5rem;
    background: #fff;
    display: flex;
    flex-direction: column;
}
.cfo-tile-k {
    font-size: .72rem; text-transform: uppercase; letter-spacing: .04em;
    color: #6c757d; font-weight: 600;
}
.cfo-tile-v { font-size: 1.6rem; line-height: 1.15; font-weight: 600; }
.cfo-tile-accts { margin: .5rem 0 .35rem; }
.cfo-tile-s { font-size: .72rem; margin-top: auto; padding-top: .35rem; }

.cfo-acct { font-size: .75rem; margin-bottom: .4rem; }
/* 3px is the "thin mark" spec: the bar is context for the figure beside
   it, never the thing being read. */
.cfo-acct-bar {
    height: 3px; border-radius: 2px; background: var(--cfo-trk); margin-top: .15rem;
}
.cfo-acct-bar > span {
    display: block; height: 100%; border-radius: 2px; background: var(--cfo-seq);
}

/* Meter — a ratio against a real limit. Nothing unbounded goes in one. */
.cfo-meter {
    padding: .7rem .9rem;
    border: 1px solid var(--bs-border-color);
    border-radius: .5rem;
    background: #fff;
    text-decoration: none;
    color: inherit;
    display: block;
}
.cfo-meter:hover { border-color: #f27bb6; }
.cfo-meter-k {
    font-size: .72rem; text-transform: uppercase; letter-spacing: .04em;
    color: #6c757d; font-weight: 600;
}
.cfo-meter-v { font-size: 1.6rem; line-height: 1.15; font-weight: 600; }
.cfo-meter-track {
    height: 8px; border-radius: 4px; background: var(--cfo-trk); margin: .3rem 0 .25rem;
}
.cfo-meter-fill { height: 100%; border-radius: 4px; }
.cfo-meter-s { font-size: .72rem; color: #6c757d; }

/* Health count — status colour, always with an icon and a label. */
.cfo-health {
    padding: .7rem .9rem;
    border: 1px solid var(--bs-border-color);
    border-left: 4px solid transparent;
    border-radius: .5rem;
    background: #fff;
    text-decoration: none;
    color: inherit;
    display: block;
}
.cfo-health:hover { box-shadow: 0 1px 4px rgba(0, 0, 0, .07); }
.cfo-health.is-ok  { border-left-color: var(--cfo-good); }
.cfo-health.is-ok  i,
.cfo-health.is-ok  .cfo-health-n { color: var(--cfo-good-ink); }
.cfo-health.is-bad { border-left-color: var(--cfo-bad); }
.cfo-health.is-bad i,
.cfo-health.is-bad .cfo-health-n { color: var(--cfo-bad-ink); }
.cfo-health-n { font-size: 1.6rem; line-height: 1.15; font-weight: 600; }
.cfo-health-k { font-size: .78rem; font-weight: 600; }
.cfo-health-s { font-size: .72rem; color: #6c757d; }

@media (max-width: 700px) {
    .cfo-hero { grid-column: span 1; }
    .cfo-hero-v { font-size: 2.25rem; }
}

/* ── The mark ───────────────────────────────────────────────────────────────
   Drawn by the macro in templates/_brand.html from app/brand.py. It fills
   with currentColor and carries no ground of its own, so it takes the colour
   of whatever it is dropped into. */
.bpd-mark { flex: none; vertical-align: -0.15em; }

/* The wordmark. Sora at a tightened tracking — the mark is compact, and a
   default-tracked word beside it reads as two unrelated objects. */
.bpd-word {
    font-family: 'Sora', system-ui, sans-serif;
    font-weight: 700;
    letter-spacing: -0.02em;
}
.bpd-lockup { display: inline-flex; align-items: center; gap: .5rem; }

/* ── Sidebar brand ───────────────────────────────────────────────────────── */
.sb-mark { margin-right: .55rem; }

/* Collapsed, the brand row was the toggle chevron alone — 64px of sidebar
   with no sign of which app it belongs to. Stack instead: mark over chevron. */
html.sb-collapsed nav.sidebar .sb-brand { display: flex !important; }
html.sb-collapsed nav.sidebar .sb-brand .sb-lbl { display: none !important; }
html.sb-collapsed nav.sidebar .sb-mark { margin-right: 0; }
html.sb-collapsed nav.sidebar .sb-brand-row {
    flex-direction: column;
    gap: .4rem;
}

/* ── The front door ─────────────────────────────────────────────────────────
   Sign in and request access. Two panels; one column below 860px. */
.auth-split { display: flex; min-height: 100vh; }

.auth-brand {
    flex: 0 0 44%;
    max-width: 520px;
    background: linear-gradient(165deg, #c0267e 0%, #6d2c91 48%, #2a1235 100%);
    color: #fff;
    padding: 2.5rem 2.5rem 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.auth-brand-lockup { color: #fff; text-decoration: none; }
.auth-brand-lockup:hover { color: #fff; opacity: .85; }

.auth-line {
    font-family: 'Sora', system-ui, sans-serif;
    font-size: 1.5rem;
    font-weight: 600;
    line-height: 1.3;
    letter-spacing: -0.015em;
    max-width: 14ch;
    margin: auto 0 1rem;        /* auto top — sits just above the art */
    text-wrap: balance;
}

/* The big faded tooth at the foot of the brand panel — decoration only. */
.auth-art {
    position: relative;
    height: 200px;
    margin: 0 -2.5rem;
    overflow: hidden;
}
.auth-art .bpd-mark {
    position: absolute; right: -24px; bottom: -40px;
    color: rgba(255, 255, 255, .14);
    animation: bpd-float 7s ease-in-out infinite;
}
.auth-art .dot {
    position: absolute; border-radius: 50%;
    background: rgba(255, 255, 255, .16);
    animation: bpd-float 6s ease-in-out infinite;
}
.auth-art .dot.d1 { width: 14px; height: 14px; left: 18%; top: 30%; background: rgba(126, 231, 190, .55); }
.auth-art .dot.d2 { width: 9px;  height: 9px;  left: 34%; top: 62%; animation-delay: -2s; }
.auth-art .dot.d3 { width: 20px; height: 20px; left: 8%;  top: 70%; background: rgba(255, 179, 217, .45); animation-delay: -4s; }
@keyframes bpd-float {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-10px); }
}
@media (prefers-reduced-motion: reduce) {
    .auth-art .bpd-mark, .auth-art .dot { animation: none; }
}

.auth-form {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #fff;
    padding: 2.5rem 1.5rem;
}
.auth-form-inner { width: 100%; max-width: 360px; }
.auth-form-inner.wide { max-width: 460px; }

.auth-h { font-size: 1.65rem; margin-bottom: .15rem; }
.auth-sub { color: var(--bpd-sub); font-size: .92rem; margin-bottom: 1.75rem; }
.auth-alt { margin: 1.5rem 0 0; font-size: .875rem; color: var(--bpd-sub); }
.auth-alt a { color: var(--bpd-accent); font-weight: 600; text-decoration: none; }
.auth-alt a:hover { text-decoration: underline; }

@media (max-width: 860px) {
    .auth-split { flex-direction: column; }
    .auth-brand { flex: none; max-width: none; padding: 1.5rem 1.5rem 0; }
    .auth-line { font-size: 1.15rem; max-width: none; margin: 1rem 0 1.25rem; }
    /* Capped and cropped from the bottom: on a phone the panel is a band, and
       a full-height illustration would push the password field off-screen. */
    .auth-ark {
        width: calc(100% + 3rem);
        margin: 0 -1.5rem -1px;
        max-height: 104px;
        object-fit: cover;
        object-position: bottom;
    }
    .auth-form { padding: 2rem 1.25rem 3rem; }
}

/* Forced change-password — inside the app shell, not the split panel, but
   wearing the same mark so the first three screens read as one app. */
.pw-mark { color: var(--bpd-accent); display: inline-block; }

/* ── Dashboard ──────────────────────────────────────────────────────────── */
.dash-greet {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: .5rem;
}
.dash-hello { font-size: 1.5rem; margin: 0; }
.dash-date { color: var(--bpd-sub); font-size: .82rem; margin: .25rem 0 0; }
.dash-empty-mark { color: var(--bpd-border); display: inline-block; }

/* Module cards. A tinted tile per module rather than one indigo glyph six
   times over: colour is what the eye learns, and a row of identical cards
   makes the reader read all six labels on every visit. The hues are
   decorative only — every card still carries its name, so nothing depends
   on telling them apart. */
.mod-card {
    --mod: var(--bpd-accent);
    --mod-tint: var(--bpd-accent-tint);
    display: flex;
    align-items: center;
    gap: .9rem;
    height: 100%;
    padding: 1.1rem 1.15rem;
    background: #fff;
    border: 1px solid var(--bpd-border);
    border-radius: .85rem;
    box-shadow: 0 1px 2px rgba(24,23,44,.03), 0 6px 20px -14px rgba(24,23,44,.25);
    text-decoration: none;
    color: inherit;
    transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.mod-card:hover {
    transform: translateY(-2px);
    border-color: var(--mod);
    box-shadow: 0 2px 4px rgba(24,23,44,.04), 0 18px 34px -20px rgba(24,23,44,.45);
    color: inherit;
}
.mod-card:focus-visible { outline: 3px solid var(--mod); outline-offset: 2px; }
.mod-ico {
    flex: none;
    width: 42px;
    height: 42px;
    border-radius: .65rem;
    display: grid;
    place-items: center;
    background: var(--mod-tint);
    color: var(--mod);
    font-size: 1.2rem;
}
.mod-body { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
.mod-name {
    font-family: 'Sora', system-ui, sans-serif;
    font-weight: 700;
    font-size: .98rem;
    letter-spacing: -0.01em;
}
.mod-blurb { font-size: .8rem; color: var(--bpd-sub); line-height: 1.35; }
.mod-go {
    margin-left: auto;
    flex: none;
    color: var(--bpd-border);
    transition: color .18s ease, transform .18s ease;
}
.mod-card:hover .mod-go { color: var(--mod); transform: translateX(2px); }

.mod-card[data-hue="indigo"] { --mod: #4f46e5; --mod-tint: #eceafd; }
.mod-card[data-hue="berry"]  { --mod: #c0267e; --mod-tint: #fbe7f2; }
.mod-card[data-hue="plum"]   { --mod: #6d2c91; --mod-tint: #f2e8f8; }
.mod-card[data-hue="mint"]   { --mod: #1f9d74; --mod-tint: #e3f6ef; }
.mod-card[data-hue="slate"]  { --mod: #475569; --mod-tint: #eef1f5; }
.mod-card[data-hue="amber"]  { --mod: #b45309; --mod-tint: #fdf3e7; }
.mod-card[data-hue="teal"]   { --mod: #0f766e; --mod-tint: #e6f6f4; }
.mod-card[data-hue="green"]  { --mod: #15803d; --mod-tint: #eafaf0; }
.mod-card[data-hue="rose"]   { --mod: #be123c; --mod-tint: #fdecf0; }
.mod-card[data-hue="violet"] { --mod: #6d28d9; --mod-tint: #f1ebfd; }

/* ── Error pages ────────────────────────────────────────────────────────── */
.err-body {
    background: var(--bpd-paper);
    color: var(--bpd-ink);
    font-family: 'Public Sans', system-ui, sans-serif;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    margin: 0;
}
.err-wrap { max-width: 30rem; padding: 2rem 1.5rem; text-align: center; }
.err-mark { color: var(--bpd-accent); display: inline-block; }
.err-code {
    display: block;
    font-family: 'IBM Plex Mono', ui-monospace, monospace;
    font-size: .78rem;
    font-weight: 600;
    letter-spacing: .18em;
    color: var(--bpd-sub);
    margin: 1rem 0 .35rem;
}
.err-headline { font-size: 1.5rem; margin: 0 0 .6rem; }
.err-detail { color: var(--bpd-sub); font-size: .95rem; margin: 0 0 1.5rem; }

/* ── The small print ────────────────────────────────────────────────────────
   The places nobody designs, which is exactly why they give an app away. */
::selection { background: var(--bpd-accent-tint); color: var(--bpd-ink); }

:focus-visible {
    outline: 3px solid rgba(79, 70, 229, .45);
    outline-offset: 2px;
}
.form-control:focus, .form-select:focus {
    border-color: var(--bpd-accent);
    box-shadow: 0 0 0 .2rem rgba(79, 70, 229, .16);
}

@media (prefers-reduced-motion: reduce) {
    .mod-card, .mod-go { transition: none; }
    .mod-card:hover { transform: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   THE PHONE — drawer, top bar, tab bar
   Added 2026-09-19. BPD is ONE responsive app: no device detection, no
   user-agent sniffing, no parallel mobile templates. The breakpoint is
   Bootstrap's `lg` (992px) throughout, because that is what `offcanvas-lg`
   and every `d-lg-none` in the markup already use — one number, or the
   drawer and the chrome disagree about when they exist.
   See docs/modules/brand/01_mobile.md.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── The rail's collapsed state is a DESKTOP preference ─────────────────────
   `bpd-sb` in localStorage follows the person, not the device. Collapsing the
   rail on a laptop used to narrow a drawer nobody could see on the phone —
   the stored flag has no meaning below lg, so it is fenced off here rather
   than in JavaScript, where the pre-paint script would still have applied it. */
@media (max-width: 991.98px) {
    html.sb-collapsed nav.sidebar { width: auto; padding: 1rem !important; }
    html.sb-collapsed nav.sidebar .sb-brand .sb-lbl,
    html.sb-collapsed nav.sidebar .sb-hide,
    html.sb-collapsed nav.sidebar hr { display: block !important; }
    html.sb-collapsed nav.sidebar .sb-brand-row { flex-direction: row; }
    html.sb-collapsed nav.sidebar .sb-mark { margin-right: .55rem; }
    html.sb-collapsed nav.sidebar .nav-link { font-size: inherit !important;
        text-align: left; padding-left: 1rem !important; padding-right: 1rem !important; }
    html.sb-collapsed nav.sidebar .nav-link > i { font-size: inherit !important;
        margin-right: .5rem !important; }
    html.sb-collapsed nav.sidebar .nav-link > span,
    html.sb-collapsed nav.sidebar .nav-link > .badge { display: inline !important; }
    html.sb-collapsed nav.sidebar li.ms-3 { margin-left: 1rem !important; }
}

/* ── The drawer ─────────────────────────────────────────────────────────── */
@media (max-width: 991.98px) {
    /* Bootstrap's default offcanvas is 400px — wider than an iPhone 12 mini.
       280 leaves a strip of the page visible, which is what tells you the
       drawer is a layer over the page and not a new screen. */
    nav.bpd-sidebar.offcanvas-lg { --bs-offcanvas-width: 280px; width: 280px; }
    nav.bpd-sidebar .nav-link { padding-top: .6rem; padding-bottom: .6rem; }
}

/* ── The top bar ────────────────────────────────────────────────────────── */
.nb-icon {
    background: transparent; border: none; color: var(--bpd-sub);
    width: 40px; height: 40px; border-radius: .5rem; flex: none;
    display: grid; place-items: center; font-size: 1.25rem; padding: 0;
}
.nb-icon:hover { background: var(--bpd-paper); color: var(--bpd-ink); }
.nb-brand { color: var(--bpd-accent); display: grid; place-items: center; flex: none; }
.nb-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

@media (max-width: 991.98px) {
    .bpd-topbar { padding-left: .5rem !important; padding-right: .5rem !important;
                   gap: .35rem !important; flex-wrap: nowrap; }
    .nb-title { font-size: .95rem; }

    /* The search box is 320px of chrome in a 390px bar, so on a phone it hides
       behind an icon and takes the whole bar when opened. The form is the same
       form — the HTMX panel, the keyboard path and the no-JS GET fallback are
       untouched. */
    .us-box { display: none; }
    .bpd-topbar.us-open .us-box {
        display: block; position: absolute; inset: 0; z-index: 5;
        background: #fff; padding: .5rem .6rem;
        margin: 0 !important;
    }
    .bpd-topbar.us-open .us-box .position-relative { height: 100%; }
    .bpd-topbar.us-open #us-input { height: 100%; }
    .us-kbd { display: none; }
}

/* ── The tab bar ────────────────────────────────────────────────────────── */
.bpd-tabbar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 1030;
    display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
    background: rgba(255, 255, 255, .94);
    -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
    border-top: 1px solid var(--bpd-border);
    /* The home indicator sits in the bottom inset. Without this the last row
       of labels is under it, and taps near the bar open the app switcher. */
    padding-bottom: env(safe-area-inset-bottom, 0px);
}
.nt-item {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 2px; padding: .45rem .25rem .5rem;
    min-height: 50px;                       /* 44px target plus the inset */
    color: var(--bpd-sub); text-decoration: none;
    font-size: .66rem; font-weight: 600; line-height: 1.1;
    -webkit-tap-highlight-color: transparent;
}
.nt-item i { font-size: 1.15rem; line-height: 1; }
.nt-item.nt-on { color: var(--bpd-accent); }
.nt-item.nt-on i { transform: translateY(-1px); }
.nt-item:active { background: var(--bpd-paper); }

/* The bar floats over the page, so the page has to end above it. */
@media (max-width: 991.98px) {
    .bpd-main > main { padding-bottom: calc(64px + env(safe-area-inset-bottom, 0px)) !important; }
}

/* ── The four things that bite every web app on iOS ─────────────────────── */
@media (max-width: 991.98px) {
    /* 1. Safari zooms the whole page when a focused input is under 16px, and
          there is no way back out except a pinch. Every field in BPD was
          .875rem. This is the single most-felt fix in this block. */
    .form-control, .form-select, input[type="text"], input[type="number"],
    input[type="date"], input[type="search"], input[type="password"],
    input[type="email"], textarea, select {
        font-size: 16px;
    }

    /* 2. Anything you tap needs 44px. The board's rank buttons and the table
          row actions were nearer 28. */
    .btn:not(.btn-close):not(.btn-sm) { min-height: 44px; }
    .btn-sm { min-height: 38px; }
    .nav-link { min-height: 40px; }

    /* 3. A 4px gutter on a phone is a rounding error. Page padding comes down
          from 1.5rem but never to nothing. */
    .bpd-main > main,
    .bpd-main > .px-4 { padding-left: 1rem !important; padding-right: 1rem !important; }
    .bpd-topbar { position: sticky; top: 0; z-index: 1020; }

    /* 4. The grey flash on every tap reads as a bug on a standalone app. */
    a, button, .nav-link, .card { -webkit-tap-highlight-color: rgba(79, 70, 229, .12); }
}

/* Tables already scroll sideways in 32 templates. Make that the rule rather
   than the exception, and let the scroll be discoverable. */
@media (max-width: 991.98px) {
    .table-responsive { -webkit-overflow-scrolling: touch; }
    .bpd-main table:not(.table-borderless) { font-size: .82rem; }
}

/* ── Screens that want a bigger window ──────────────────────────────────────
   Reconciliation is spreadsheet-shaped work, and squeezing a matching grid
   onto 390px produces something nobody can use. The owner confirmed on
   2026-09-19 that seed-and-match, the bank register and the statement imports
   are not wanted on a phone. Saying so is more respectful than a bad squeeze —
   add `.wide-only` to such a screen's main panel and `.wide-notice` sits in
   its place below lg. */
.wide-notice { display: none; }
@media (max-width: 991.98px) {
    .wide-only { display: none !important; }
    .wide-notice {
        display: block; text-align: center;
        border: 1px dashed var(--bpd-border); border-radius: .85rem;
        padding: 2rem 1.25rem; background: #fff; color: var(--bpd-sub);
    }
    .wide-notice .wn-mark { color: var(--bpd-border); }
    .wide-notice h6 { font-family: 'Sora', system-ui, sans-serif; color: var(--bpd-ink);
                      margin: .75rem 0 .35rem; }
    .wide-notice p { font-size: .88rem; margin: 0 auto; max-width: 30ch; }
}

/* ── Column-filter popovers (app/services/grid_filter.py) ───────────────────
   Ported from CellHub with the engine, 2026-11-13. A bounded flex column, so
   a long chip list scrolls INSIDE itself while Sort (top) and Apply (bottom)
   stay pinned. Flex is scoped to `.show` so a closed menu stays hidden. */
.gf-filter-dropdown {
    max-height: 85vh;
    max-width: min(26em, 90vw);   /* a long label must not push it off-screen */
    overflow: hidden;
    overscroll-behavior: contain;
}
.gf-filter-dropdown .gf-chip-row > span,
.gf-filter-dropdown .gf-search-chip > span { min-width: 0; }
.gf-th-open { z-index: 1080 !important; }   /* raised by grid_filter.js */
.gf-filter-dropdown.show { display: flex; flex-direction: column; }
.gf-filter-dropdown .gf-popover-body,
.gf-filter-dropdown .gf-popover-form {
    display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0;
}
.gf-filter-dropdown .gf-chip-list,
.gf-filter-dropdown .gf-search-chips {
    flex: 1 1 auto; min-height: 4rem; max-height: none !important;
    overflow-y: auto; overscroll-behavior: contain;
}
.gf-filter-dropdown .gf-popover-form > .d-flex.justify-content-end {
    flex: 0 0 auto;
    background: var(--bs-body-bg, #fff);
    border-top: 1px solid var(--bs-border-color, #dee2e6);
    padding-top: .5rem; margin-top: .25rem;
}
.gf-popover-form .gf-popover-bulk { display: inline-flex; gap: .25rem; }
.gf-popover-form .gf-popover-bulk .btn { padding: .05rem .5rem; font-size: .75rem; }

/* ── The Ledger grid's view pills (book_service.VIEWS) ─────────────────── */
.cfo-pill {
    display: inline-flex; align-items: center;
    padding: .2rem .6rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 50rem;
    font-size: .8rem;
    color: var(--bpd-sub);
    text-decoration: none;
    background: var(--bs-body-bg, #fff);
    transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.cfo-pill:hover { background: var(--bpd-accent-tint); color: var(--bpd-accent-dark); }
.cfo-pill.active {
    background: var(--bpd-accent-tint); color: var(--bpd-accent-dark);
    border-color: var(--bpd-accent); font-weight: 600;
}

/* ─── CFO refresh (2026-11-14) ────────────────────────────────────────
   Owner, on the Ledger beside CellHub's Bill Pay: "see how dry the page
   looks". Borrowed treatments only, no new colours: an icon tile and a
   one-line summary at the head of a page, tiles tinted by what they count,
   section cards with a tinted header, a progress ring, and five small
   motions. Everything that moves stops under prefers-reduced-motion. */
:root { --cfo-spring: cubic-bezier(.34, 1.56, .64, 1); }

.cfo-head { display: flex; align-items: center; gap: .9rem; margin-bottom: 1rem; flex-wrap: wrap; }
.cfo-logo {
    width: 44px; height: 44px; border-radius: 12px; flex: none;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 1.3rem; color: #fff;
    background: linear-gradient(135deg, var(--bpd-accent), #312e81);
    box-shadow: 0 6px 16px -6px rgba(49, 46, 129, .6), inset 0 1px 0 rgba(255, 255, 255, .3);
}
.cfo-summary { font-size: .85rem; color: var(--bpd-sub); font-variant-numeric: tabular-nums; }
.cfo-summary b { color: var(--bpd-ink); }
.cfo-summary b.is-bad  { color: var(--cfo-bad-ink); }
.cfo-summary b.is-good { color: var(--cfo-good-ink); }

/* The Ledger's strip fits now that the account chips are on Today: it
   wraps instead of scrolling, and its tiles share the width. */
.cfo-strip-fit { overflow-x: visible; flex-wrap: wrap; }
.cfo-strip-fit .cfo-chip { flex: 1 1 9.5rem; max-width: none; }

/* Tiles tinted by what they count: a coloured top edge fading into white. */
.cfo-chip { border-radius: .75rem; }
.cfo-chip[class*="cfo-tone-"] {
    --tone: var(--bpd-border); --tint: #faf9fe;
    background: linear-gradient(180deg, var(--tint), #fff 65%);
    box-shadow: inset 0 3px 0 var(--tone), 0 1px 2px rgba(0, 0, 0, .04);
}
.cfo-chip.cfo-tone-ink    { --tone: #c9c5de; --tint: #f8f7fc; }
.cfo-chip.cfo-tone-good   { --tone: var(--bpd-good);   --tint: var(--bpd-good-tint); }
.cfo-chip.cfo-tone-bad    { --tone: var(--bpd-bad);    --tint: var(--bpd-bad-tint); }
.cfo-chip.cfo-tone-indigo { --tone: var(--bpd-accent); --tint: var(--bpd-accent-tint); }
.cfo-chip-k i { font-size: .8rem; margin-right: .1rem; }
a.cfo-chip, .cfo-pill, .cfo-meter, .cfo-health {
    transition: transform .18s var(--cfo-spring), box-shadow .18s ease, border-color .12s ease;
}
a.cfo-chip:hover, .cfo-meter:hover, .cfo-health:hover {
    transform: translateY(-2px); box-shadow: 0 8px 18px -12px rgba(49, 46, 129, .45);
}
.cfo-pill:hover { transform: translateY(-1px); }

/* Progress ring: fills from empty on load. @property lets the angle animate. */
@property --p { syntax: '<number>'; inherits: false; initial-value: 0; }
.cfo-chip-ringed { display: flex; align-items: center; justify-content: space-between; gap: .6rem; }
.cfo-ring {
    width: 48px; height: 48px; border-radius: 50%; position: relative; flex: none;
    background: conic-gradient(var(--bpd-accent) calc(var(--p) * 1%), var(--bpd-accent-tint) 0);
    animation: cfo-ring-fill .9s cubic-bezier(.22, 1, .36, 1);
}
.cfo-ring.is-done { background: conic-gradient(var(--bpd-good) calc(var(--p) * 1%), var(--bpd-good-tint) 0); }
.cfo-ring::before { content: ''; position: absolute; inset: 5px; border-radius: 50%; background: #fff; }
.cfo-ring span {
    position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
    font-weight: 700; font-size: .78rem; font-variant-numeric: tabular-nums; color: var(--bpd-ink);
}
@keyframes cfo-ring-fill { from { --p: 0; } }

/* Count chips on the view pills. */
.cfo-count {
    margin-left: .35rem; border-radius: 999px; padding: 0 .45rem;
    font-size: .72rem; font-weight: 700; font-variant-numeric: tabular-nums;
}
.cfo-count.is-bad  { background: var(--bpd-bad); color: #fff; }
.cfo-count.is-warn { background: #fff4d6; color: #7a5200; }

.cfo-grid-card { border-radius: .9rem; overflow: hidden; border-color: var(--bpd-border);
                 box-shadow: 0 1px 2px rgba(0, 0, 0, .04), 0 10px 24px -18px rgba(49, 46, 129, .4); }

/* Section card with a tinted header — Today's three blocks. */
.cfo-sec {
    background: #fff; border: 1px solid var(--bpd-border); border-radius: .9rem;
    margin-bottom: 1.25rem; overflow: hidden;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .04), 0 10px 24px -20px rgba(49, 46, 129, .45);
}
.cfo-sec-h {
    display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap;
    padding: .65rem 1rem; font-family: 'Sora', system-ui, sans-serif; font-weight: 700;
    color: var(--bpd-accent-dark);
    background: linear-gradient(90deg, var(--bpd-accent-tint), #fff 70%);
    border-bottom: 1px solid var(--bpd-border); border-left: 4px solid var(--bpd-accent);
}
.cfo-sec-sub { font-family: 'Public Sans', system-ui, sans-serif; font-weight: 400;
               font-size: .8rem; color: var(--bpd-sub); }
.cfo-sec-b { padding: 1rem; }
.cfo-sec-b > .table:last-child { margin-bottom: 0; }
.cfo-alldone {
    padding: 1.25rem; text-align: center; color: var(--bpd-sub);
    border: 1px dashed var(--bpd-border); border-radius: .75rem;
}
.cfo-alldone i { display: block; font-size: 1.8rem; color: var(--bpd-good); margin-bottom: .2rem;
                 animation: cfo-pop .6s var(--cfo-spring); }
.cfo-acct-warn { font-size: .7rem; color: var(--cfo-bad-ink); margin-top: .15rem; }

/* Seed & match's two tally cards: tinted from the left like a Bill Pay band. */
.cfo-tint { border-radius: .75rem; border: 1px solid var(--bpd-border); border-left-width: 4px; }
.cfo-tint-success   { border-left-color: var(--bpd-good);
                      background: linear-gradient(90deg, var(--bpd-good-tint), #fff 45%); }
.cfo-tint-secondary { border-left-color: #9ca3af;
                      background: linear-gradient(90deg, #f3f4f6, #fff 45%); }

/* The motions. */
@keyframes cfo-pop  { 0% { transform: scale(1); } 40% { transform: scale(1.25); } 100% { transform: scale(1); } }
@keyframes cfo-glow { 0% { box-shadow: 0 0 0 0 rgba(21, 128, 61, .55); } 100% { box-shadow: 0 0 0 12px rgba(21, 128, 61, 0); } }
@keyframes cfo-hl   { 0% { background: #c9f0d8; } 100% { background: transparent; } }
@keyframes cfo-in   { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
.cfo-balanced { display: inline-block; font-weight: 600; animation: cfo-pop .5s var(--cfo-spring); }
.cfo-ready    { animation: cfo-glow .9s ease; }
.cfo-saved    { animation: cfo-hl 1.4s ease; }
tr.lg-in > td { animation: cfo-in .3s cubic-bezier(.22, 1, .36, 1) both;
                animation-delay: calc(var(--i, 0) * 25ms); }

@media (prefers-reduced-motion: reduce) {
    .cfo-ring, .cfo-balanced, .cfo-ready, .cfo-saved, tr.lg-in > td, .cfo-alldone i { animation: none !important; }
    a.cfo-chip, .cfo-pill, .cfo-meter, .cfo-health { transition: none; }
    a.cfo-chip:hover, .cfo-meter:hover, .cfo-health:hover, .cfo-pill:hover { transform: none; }
}

/* ─── CFO v2 (BPD): overview, bank lines, dictionary, P&L ─────────────
   Colorful on purpose (owner, 2026-11-14): one hue per source of meaning,
   one color per person, numbers that count up, cards that rise in. The
   dense tables stay plain so a long list still reads. */
.cfo2-head { display: flex; align-items: center; gap: .75rem; margin-bottom: .75rem; flex-wrap: wrap; }
.cfo2-books { display: inline-flex; gap: .25rem; padding: .25rem; border-radius: 999px;
    background: #fff; border: 1px solid var(--bpd-border); }
.cfo2-book { display: inline-flex; align-items: center; gap: .4rem; padding: .35rem .9rem;
    border-radius: 999px; color: var(--bpd-sub); text-decoration: none; font-size: .88rem;
    font-weight: 600; transition: background .2s, color .2s; }
.cfo2-book:hover { color: var(--bpd-ink); background: var(--bpd-paper); }
.cfo2-book.is-on[data-book="bpd"]   { background: var(--bpd-accent); color: #fff; }
.cfo2-book.is-on[data-book="trust"] { background: var(--bpd-plum); color: #fff; }
.cfo2-build i { display: inline-block; transition: transform .6s; }
.cfo2-build:hover i { transform: rotate(180deg); }

.cfo2-grid { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); gap: .9rem; }
@media (max-width: 900px) { .cfo2-grid { grid-template-columns: 1fr; } }
.cfo2-hero { padding: 1.2rem 1.4rem; border-radius: .9rem; color: #fff;
    background: linear-gradient(135deg, var(--bpd-accent), var(--bpd-plum) 70%, #2a1235);
    box-shadow: 0 8px 24px rgba(109, 44, 145, .18); }
.cfo2-hero .cfo2-k, .cfo2-hero .cfo2-s { color: rgba(255, 255, 255, .78); }
.cfo2-k { font-size: .72rem; text-transform: uppercase; letter-spacing: .06em; color: var(--bpd-sub); font-weight: 600; }
.cfo2-v { font-size: 2.6rem; line-height: 1.1; font-weight: 700; margin: .2rem 0; }
.cfo2-s { font-size: .8rem; }

.cfo2-ring-card { display: flex; gap: 1rem; align-items: center; padding: 1rem 1.2rem;
    border-radius: .9rem; background: #fff; border: 1px solid var(--bpd-border); }
.cfo2-ring { --pct: 0; flex: 0 0 6.2rem; height: 6.2rem; border-radius: 50%; display: grid;
    place-items: center; font-size: 1.5rem; font-weight: 700; position: relative;
    background: conic-gradient(var(--bpd-mint) calc(var(--pct) * 1%), var(--bpd-mint-tint) 0);
    animation: cfo2-spin-in .9s ease-out both; }
.cfo2-ring::before { content: ""; position: absolute; inset: .55rem; border-radius: 50%; background: #fff; }
.cfo2-ring > * { position: relative; }
.cfo2-ring small { font-size: .8rem; margin-left: 1px; }
.cfo2-src { display: flex; flex-wrap: wrap; gap: .3rem; margin-top: .45rem; }

.cfo2-pill { --h: var(--bpd-accent); --t: var(--bpd-accent-tint);
    display: inline-flex; align-items: center; gap: .3rem; padding: .1rem .5rem; border-radius: 999px;
    font-size: .72rem; font-weight: 600; color: var(--h); background: var(--t);
    text-decoration: none; white-space: nowrap; transition: transform .15s; }
a.cfo2-pill:hover { transform: translateY(-1px); color: var(--h); }
.cfo2-pill[data-hue="mint"]  { --h: #1f9d74; --t: #e3f6ef; }
.cfo2-pill[data-hue="plum"]  { --h: #6d2c91; --t: #f2e8f8; }
.cfo2-pill[data-hue="berry"] { --h: #c0267e; --t: #fbe7f2; }
.cfo2-pill[data-hue="amber"] { --h: #b45309; --t: #fdf3e7; }
.cfo2-pill[data-hue="teal"]  { --h: #0f766e; --t: #e6f6f4; }
.cfo2-pill[data-hue="rose"]  { --h: #be123c; --t: #fdecf0; }
.cfo2-pill[data-hue="slate"] { --h: #475569; --t: #eef1f5; }

.cfo2-h { margin: 1.4rem 0 .6rem; font-weight: 700; display: flex; align-items: center; gap: .45rem; }
.cfo2-h > i { color: var(--bpd-accent); }

.cfo2-accts { display: grid; grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr)); gap: .75rem; }
.cfo2-acct { --h: var(--bpd-mint); --t: var(--bpd-mint-tint);
    display: flex; gap: .8rem; padding: .9rem 1rem; border-radius: .8rem; background: #fff;
    border: 1px solid var(--bpd-border); color: inherit; text-decoration: none;
    transition: transform .18s, box-shadow .18s; }
.cfo2-acct[data-hue="plum"] { --h: var(--bpd-plum); --t: #f2e8f8; }
.cfo2-acct:hover { transform: translateY(-2px); box-shadow: 0 6px 18px rgba(31, 20, 36, .08); color: inherit; }
.cfo2-acct-ico { flex: 0 0 2.6rem; height: 2.6rem; border-radius: .7rem; display: grid; place-items: center;
    background: var(--t); color: var(--h); font-size: 1.25rem; }
.cfo2-acct-body { display: flex; flex-direction: column; min-width: 0; }
.cfo2-acct-name { font-weight: 600; font-size: .9rem; }
.cfo2-acct-v { font-size: 1.45rem; font-weight: 700; line-height: 1.2; }
.cfo2-acct-s { font-size: .74rem; color: var(--bpd-sub); }

.cfo2-people { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: .75rem; }
.cfo2-person { --p: #475569; --pt: #eef1f5;
    display: flex; gap: .75rem; align-items: center; padding: .8rem 1rem; border-radius: .8rem;
    background: #fff; border: 1px solid var(--bpd-border); color: inherit; text-decoration: none;
    transition: transform .18s, box-shadow .18s; }
.cfo2-person:hover { transform: translateY(-2px); box-shadow: 0 6px 18px rgba(31, 20, 36, .08); color: inherit; }
.cfo2-avatar { flex: 0 0 2.4rem; height: 2.4rem; border-radius: 50%; display: grid; place-items: center;
    font-weight: 700; color: #fff; background: var(--p); }
.cfo2-bar { display: block; height: 6px; border-radius: 3px; background: var(--pt); margin: .3rem 0 .15rem; overflow: hidden; }
.cfo2-bar > span { display: block; height: 100%; width: var(--w); border-radius: 3px; background: var(--p);
    animation: cfo2-grow 1s cubic-bezier(.2, .8, .2, 1) both; }
/* One color per person, everywhere they appear. */
[data-person="family"]   { --p: #1f9d74; --pt: #e3f6ef; }
[data-person="jack"]     { --p: #2563eb; --pt: #e5edfd; }
[data-person="claudine"] { --p: #c0267e; --pt: #fbe7f2; }
[data-person="michael"]  { --p: #b45309; --pt: #fdf3e7; }
.cfo2-who { display: inline-block; padding: 0 .45rem; border-radius: 999px; font-size: .72rem; font-weight: 600;
    color: var(--p, #475569); background: var(--pt, #eef1f5); }

.cfo2-filters { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; margin-bottom: .6rem; }
.cfo2-table-wrap { background: #fff; border: 1px solid var(--bpd-border); border-radius: .7rem; }
.cfo2-table { margin: 0; font-size: .85rem; }
.cfo2-table thead th { font-size: .72rem; text-transform: uppercase; letter-spacing: .04em; color: var(--bpd-sub);
    background: var(--bpd-paper); position: sticky; top: 0; }
.cfo2-desc { max-width: 26rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cfo2-row[data-src="open"] td:first-child { box-shadow: inset 3px 0 0 #be123c; }
.cfo2-in { color: var(--cfo-good-ink); font-weight: 600; }
.cfo2-off td { opacity: .55; }
.cfo2-file-row > td { background: var(--bpd-paper); }
.cfo2-file { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
.cfo2-file > select, .cfo2-file > input[name="payee"] { width: auto; min-width: 11rem; }
.cfo2-file-cat { min-width: 18rem; flex: 1 1 18rem; }
.cfo2-detail { animation: cfo2-rise .25s ease-out both; }
.cfo2-empty { text-align: center; padding: 3rem 1rem; background: #fff; border: 1px dashed var(--bpd-border);
    border-radius: .9rem; color: var(--bpd-sub); }
.cfo2-empty i { font-size: 2.2rem; color: var(--bpd-mint); display: block; margin-bottom: .4rem;
    animation: cfo2-twinkle 2.4s ease-in-out infinite; }

.cfo2-pnl { margin: 0; font-size: .8rem; }
.cfo2-pnl th, .cfo2-pnl td { text-align: right; white-space: nowrap; }
.cfo2-pnl thead th { background: var(--bpd-paper); color: var(--bpd-sub); font-size: .7rem; text-transform: uppercase; }
.cfo2-sec td { text-align: left !important; font-weight: 700; padding-top: .7rem; font-family: inherit; }
.cfo2-sec[data-sec="earnings"] td { color: var(--bpd-mint); }
.cfo2-sec[data-sec="expense"] td  { color: var(--bpd-accent); }
.cfo2-sec[data-sec="other"] td    { color: var(--bpd-sub); }
.cfo2-sub td { font-weight: 600; border-top: 1px solid var(--bpd-border); }
.cfo2-net td { font-weight: 700; background: var(--bpd-accent-tint); }
.cfo2-neg { color: var(--cfo-bad-ink); }

.cfo2-rise { animation: cfo2-rise .5s cubic-bezier(.2, .8, .2, 1) both; animation-delay: var(--d, 0s); }
@keyframes cfo2-rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes cfo2-grow { from { width: 0; } }
@keyframes cfo2-spin-in { from { transform: rotate(-90deg) scale(.9); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes cfo2-twinkle { 50% { transform: scale(1.15) rotate(8deg); } }
@media (prefers-reduced-motion: reduce) {
    .cfo2-rise, .cfo2-bar > span, .cfo2-ring, .cfo2-empty i, .cfo2-detail { animation: none; }
    .cfo2-acct, .cfo2-person, .cfo2-build i { transition: none; }
}

/* Deposit opened in place: the checks behind one bank line. */
.cfo2-kids-btn { cursor: pointer; }
.cfo2-chev { transition: transform .2s; }
.cfo2-kids-btn[aria-expanded="true"] .cfo2-chev { transform: rotate(180deg); }
.cfo2-kids-row > td { background: #fbf7fb; padding: .25rem .5rem .6rem 2rem; }
.cfo2-kids { font-size: .8rem; background: transparent; }
.cfo2-kids thead th { font-size: .66rem; text-transform: uppercase; color: var(--bpd-sub); background: transparent; }
.cfo2-kids tbody tr { animation: cfo2-rise .3s ease-out both; animation-delay: var(--d, 0s); }
.cfo2-kids tfoot td { border-top: 1px solid var(--bpd-border); }
@media (prefers-reduced-motion: reduce) { .cfo2-kids tbody tr { animation: none; } .cfo2-chev { transition: none; } }

/* Ledger grid (ported from CellHub): dense, plain, sticky header. */
.lg-grid-body { max-height: calc(100vh - 360px); min-height: 18rem; overflow: auto; border-radius: .7rem; }
.lg-table { font-size: .82rem; }
.lg-table th, .lg-table td { padding: .3rem .5rem; vertical-align: middle; }
.lg-table thead th { position: sticky; top: 0; z-index: 2; background: var(--bpd-paper);
    font-weight: 600; color: var(--bpd-sub); border-bottom: 1px solid var(--bpd-border); }
.lg-table td.num { font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
.lg-table .lg-bank { font-size: .72rem; color: var(--bpd-sub); }
.lg-table .lg-clip { max-width: 16rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lg-table tr.lg-head td { background: #fbf7fb; }
.lg-table tr.lg-part td:first-child { border-left: 3px solid var(--bpd-mint); }
.lg-table tr.lg-part td.lg-indent { padding-left: 1.4rem; }
.lg-table tr.lg-open td:first-child { box-shadow: inset 3px 0 0 #be123c; }
.lg-table tr.lg-hist td { color: #5f5463; }
.lg-tag { font-size: .66rem; font-weight: 600; padding: .12rem .4rem; background: var(--bpd-accent-tint); color: var(--bpd-accent); }
.lg-strip { display: grid; grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)); gap: .5rem; }
.lg-tile { padding: .55rem .8rem; background: #fff; border: 1px solid var(--bpd-border); border-radius: .6rem;
    animation: cfo2-rise .4s ease-out both; }
.lg-v { font-size: 1.15rem; font-weight: 700; }
.lg-edit { background: var(--bpd-accent-tint); border-color: #f1c2dd !important; }

/* Bank feed strip on the CFO overview. */
.cfo2-feed { display: flex; gap: .8rem; align-items: center; margin-top: .9rem; padding: .8rem 1rem;
    background: #fff; border: 1px solid var(--bpd-border); border-radius: .8rem; }
.cfo2-feed .cfo2-acct-ico { background: var(--t); color: var(--h); }

/* ── Maimonides billing (/maimo) — phone first, one number, one button ── */
.mm { max-width: 46rem; margin: 0 auto; }
.mm-hero { border-radius: 1.1rem; padding: 1.3rem 1.4rem; color: #fff; margin-bottom: 1rem;
           background: linear-gradient(135deg, var(--bpd-accent) 0%, var(--bpd-plum) 100%);
           box-shadow: 0 10px 24px -14px rgba(109, 44, 145, .7); animation: mm-in .4s ease both; }
.mm-hero.is-clear { background: linear-gradient(135deg, var(--bpd-mint) 0%, #0f766e 100%); }
.mm-hero-lbl { font-size: .8rem; text-transform: uppercase; letter-spacing: .08em; opacity: .85; font-weight: 700; }
.mm-hero-num { font-family: 'IBM Plex Mono', ui-monospace, monospace; font-size: 2.6rem;
               font-weight: 700; line-height: 1.1; margin: .15rem 0; }
.mm-hero-sub { font-size: .8rem; opacity: .85; }
.mm-add { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; margin-bottom: 1.25rem; }
.mm-date { flex: 1 1 10rem; border-radius: .8rem; padding: .6rem .8rem; }
.mm-go { flex: 0 0 auto; border-radius: .8rem; padding: .6rem 1.1rem; font-weight: 700; color: #fff;
         background: var(--bpd-mint); border: 0; transition: transform .15s ease, box-shadow .15s ease; }
.mm-go:hover, .mm-go:focus-visible { color: #fff; background: #198a65; transform: translateY(-1px);
                                     box-shadow: 0 6px 14px -8px var(--bpd-mint); }
.mm-more { flex-basis: 100%; font-size: .75rem; color: var(--bpd-sub); }
.mm-more summary { cursor: pointer; width: max-content; }
.mm-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr)); gap: .75rem; }
.mm-card { --c: var(--bpd-bad); --t: var(--bpd-bad-tint);
           background: #fff; border: 1px solid var(--bpd-border); border-top: 4px solid var(--c);
           border-radius: .9rem; padding: .75rem .85rem .6rem; animation: mm-in .35s ease both; }
.mm-card[data-status="part"] { --c: var(--bpd-warn); --t: var(--bpd-warn-tint); }
.mm-card[data-status="paid"] { --c: var(--bpd-good); --t: var(--bpd-good-tint); }
.mm-card-top { display: flex; align-items: baseline; gap: .5rem; }
.mm-mon { font-weight: 700; }
.mm-amt { margin-left: auto; font-family: 'IBM Plex Mono', ui-monospace, monospace; font-weight: 600; color: var(--c); }
.mm-chips { display: flex; flex-wrap: wrap; gap: .3rem; margin: .55rem 0 .6rem; }
.mm-chip { --c: var(--bpd-bad); --t: var(--bpd-bad-tint);
           display: inline-flex; align-items: center; gap: .25rem; font-size: .78rem; font-weight: 600;
           padding: .15rem .55rem; border-radius: 999px; background: var(--t); color: var(--c); }
.mm-chip[data-status="part"] { --c: var(--bpd-warn); --t: var(--bpd-warn-tint); }
.mm-chip[data-status="paid"] { --c: var(--bpd-good); --t: var(--bpd-good-tint); }
.mm-chip form { display: inline; margin: 0; }
.mm-chip button { border: 0; background: none; color: inherit; opacity: .5; padding: 0 0 0 .1rem; line-height: 1; }
.mm-chip button:hover { opacity: 1; }
.mm-card-foot { display: flex; align-items: center; border-top: 1px dashed var(--bpd-border); padding-top: .45rem; font-size: .82rem; }
.mm-card-foot a { text-decoration: none; color: var(--bpd-plum); font-weight: 600; }
.mm-card-foot a:hover { color: var(--bpd-accent); }
.mm-last { font-size: .75rem; color: var(--bpd-sub); text-align: center; margin-top: 1.25rem; }
@keyframes mm-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .mm-hero, .mm-card { animation: none; } .mm-go { transition: none; } }
.mm-h { margin: .5rem 0 .6rem; font-weight: 700; color: var(--bpd-plum); }
.mm-pays { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; }
.mm-pays > li { display: flex; gap: .85rem; align-items: flex-start; background: #fff;
                border: 1px solid var(--bpd-border); border-left: 4px solid var(--bpd-good);
                border-radius: .9rem; padding: .65rem .85rem; font-size: .85rem; animation: mm-in .35s ease both; }
.mm-pay-amt { font-family: 'IBM Plex Mono', ui-monospace, monospace; font-weight: 700; font-size: 1.1rem;
              color: var(--bpd-good); min-width: 4.5rem; }
.mm-pay-body { display: flex; flex-direction: column; }
@media (prefers-reduced-motion: reduce) { .mm-pays > li { animation: none; } }
.mm-filter { display: inline-flex; gap: .25rem; padding: .25rem; margin-bottom: .75rem;
             background: #fff; border: 1px solid var(--bpd-border); border-radius: 999px; }
.mm-filter a { text-decoration: none; color: var(--bpd-sub); font-weight: 600; font-size: .82rem;
               padding: .3rem .8rem; border-radius: 999px; transition: background .15s ease, color .15s ease; }
.mm-filter a span { font-size: .7rem; opacity: .75; margin-left: .15rem; }
.mm-filter a:hover { color: var(--bpd-ink); }
.mm-filter a.is-on { color: #fff; background: var(--bpd-plum); }
.mm-filter a.is-on[data-key="unpaid"] { background: var(--bpd-bad); }
.mm-filter a.is-on[data-key="paid"] { background: var(--bpd-good); }
@media (prefers-reduced-motion: reduce) { .mm-filter a { transition: none; } }
.mm-sec-head { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin-top: 1.5rem; }
.mm-sec-head .mm-h { margin: 0 0 .75rem; }
/* Invoices and Payments each scroll inside their own box, so the page stays
   summary → invoices → payments however many months pile up. */
.mm-scroll { max-height: 24rem; overflow-y: auto; overscroll-behavior: contain;
             padding: .15rem .25rem 1.25rem 0; scrollbar-width: thin;
             -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 1.25rem), transparent);
                     mask-image: linear-gradient(to bottom, #000 calc(100% - 1.25rem), transparent); }
.mm-scroll:focus-visible { outline: 2px solid var(--bpd-plum); outline-offset: 2px; border-radius: .9rem; }
@media (max-width: 575.98px) { .mm-scroll { max-height: 20rem; } }
