/* ============================================================================
   DoubleEntry — design system
   Calm, professional, data-first. Built for accountants who live in this all day.

   Principles
   ----------
   1. Numbers are the hero. Tabular figures everywhere money appears, so digits
      line up in columns and the eye can scan a ledger.
   2. Restraint. One accent colour. Colour is reserved for MEANING (money in/out,
      confidence, risk) — never decoration.
   3. Quiet chrome. Subtle borders over heavy shadows; the data should be the
      loudest thing on the page.
   4. Full light/dark parity — every token is themed.
   ========================================================================== */

:root {
    /* ---- Neutrals (slate) ---- */
    --c-bg:            #f7f8fa;
    --c-surface:       #ffffff;
    --c-surface-2:     #f2f4f7;
    --c-surface-hover: #f7f8fa;
    --c-border:        #e3e6ea;
    --c-border-strong: #cfd4da;

    --c-text:          #12161c;
    --c-text-muted:    #5c6572;
    --c-text-subtle:   #8b939f;

    /* ---- Accent (single, restrained) ---- */
    --c-accent:        #3355e0;
    --c-accent-hover:  #2944c4;
    --c-accent-soft:   #eef1fd;
    --c-accent-text:   #ffffff;

    /* ---- Semantic — used for MEANING only ---- */
    --c-pos:           #0f7a4d;   /* money in */
    --c-pos-soft:      #e6f5ee;
    --c-neg:           #c0392f;   /* money out */
    --c-neg-soft:      #fdeceb;
    --c-warn:          #a86400;
    --c-warn-soft:     #fdf3e3;
    --c-info:          #1f6f8b;
    --c-info-soft:     #e8f3f7;

    /* ---- Radii / shadow / spacing ---- */
    --r-sm: 6px;
    --r-md: 9px;
    --r-lg: 14px;

    --shadow-sm: 0 1px 2px rgba(16, 24, 40, .05);
    --shadow-md: 0 4px 12px rgba(16, 24, 40, .07);
    --shadow-lg: 0 12px 32px rgba(16, 24, 40, .12);

    --sidebar-w: 244px;
    --topbar-h: 58px;

    --font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
            "Helvetica Neue", Arial, sans-serif;
    --font-mono: "SF Mono", ui-monospace, "Cascadia Mono", Menlo, Consolas, monospace;
}

/* Dark mode: follow the OS by default... */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --c-bg:            #0e1116;
        --c-surface:       #161a21;
        --c-surface-2:     #1d222b;
        --c-surface-hover: #1f242e;
        --c-border:        #272d38;
        --c-border-strong: #39414f;

        --c-text:          #e8eaee;
        --c-text-muted:    #99a2b0;
        --c-text-subtle:   #6d7686;

        --c-accent:        #6b86f5;
        --c-accent-hover:  #839af7;
        --c-accent-soft:   #1c2440;
        --c-accent-text:   #0e1116;

        --c-pos:           #3ecf8e;
        --c-pos-soft:      #10291f;
        --c-neg:           #f0736a;
        --c-neg-soft:      #2c1917;
        --c-warn:          #e0a44a;
        --c-warn-soft:     #2a2114;
        --c-info:          #5bb3ce;
        --c-info-soft:     #13252c;

        --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
        --shadow-md: 0 4px 12px rgba(0, 0, 0, .45);
        --shadow-lg: 0 12px 32px rgba(0, 0, 0, .55);
    }
}

/* ...but an explicit toggle always wins, in both directions. */
:root[data-theme="dark"] {
    --c-bg:            #0e1116;
    --c-surface:       #161a21;
    --c-surface-2:     #1d222b;
    --c-surface-hover: #1f242e;
    --c-border:        #272d38;
    --c-border-strong: #39414f;

    --c-text:          #e8eaee;
    --c-text-muted:    #99a2b0;
    --c-text-subtle:   #6d7686;

    --c-accent:        #6b86f5;
    --c-accent-hover:  #839af7;
    --c-accent-soft:   #1c2440;
    --c-accent-text:   #0e1116;

    --c-pos:           #3ecf8e;
    --c-pos-soft:      #10291f;
    --c-neg:           #f0736a;
    --c-neg-soft:      #2c1917;
    --c-warn:          #e0a44a;
    --c-warn-soft:     #2a2114;
    --c-info:          #5bb3ce;
    --c-info-soft:     #13252c;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow-md: 0 4px 12px rgba(0, 0, 0, .45);
    --shadow-lg: 0 12px 32px rgba(0, 0, 0, .55);
}

/* ============================================================================
   Base
   ========================================================================== */

* { box-sizing: border-box; }

body {
    font-family: var(--font);
    background: var(--c-bg);
    color: var(--c-text);
    font-size: 14px;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
    margin: 0;
}

h1, h2, h3, h4, h5, h6 {
    color: var(--c-text);
    font-weight: 600;
    letter-spacing: -0.011em;
    margin: 0;
}

h1 { font-size: 1.5rem; }
h2 { font-size: 1.25rem; }
h3 { font-size: 1.0625rem; }
h4, h5, h6 { font-size: .9375rem; }

a { color: var(--c-accent); text-decoration: none; }
a:hover { color: var(--c-accent-hover); text-decoration: underline; }

hr { border-color: var(--c-border); opacity: 1; }

code {
    font-family: var(--font-mono);
    font-size: .85em;
    background: var(--c-surface-2);
    border: 1px solid var(--c-border);
    padding: .1em .38em;
    border-radius: 4px;
    color: var(--c-text);
}

::selection { background: var(--c-accent-soft); }

/* THE most important rule in an accounting app: digits must line up. */
.num, .money, td.num, th.num,
table.data td:last-child, .stat-value {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.money-pos { color: var(--c-pos); }
.money-neg { color: var(--c-neg); }

.text-muted   { color: var(--c-text-muted) !important; }
.text-subtle  { color: var(--c-text-subtle) !important; }
.text-pos     { color: var(--c-pos) !important; }
.text-neg     { color: var(--c-neg) !important; }
.text-warn    { color: var(--c-warn) !important; }

.mono { font-family: var(--font-mono); }

/* ============================================================================
   App shell
   ========================================================================== */

.app {
    display: flex;
    min-height: 100vh;
}

.sidebar {
    width: var(--sidebar-w);
    flex: 0 0 var(--sidebar-w);
    background: var(--c-surface);
    border-right: 1px solid var(--c-border);
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    height: 100vh;

    /* Custom properties don't transition, so animate the real properties.
       Slight ease-out so it decelerates into place rather than stopping dead. */
    transition:
        width .24s cubic-bezier(.32, .72, 0, 1),
        flex-basis .24s cubic-bezier(.32, .72, 0, 1);
}

.sidebar-brand-row {
    display: flex;
    align-items: center;
    height: var(--topbar-h);
    border-bottom: 1px solid var(--c-border);
    padding-right: .5rem;
}

.sidebar-brand {
    display: flex;
    align-items: center;
    gap: .6rem;
    flex: 1;
    min-width: 0;
    height: 100%;
    padding: 0 1.1rem;
    font-weight: 650;
    font-size: .98rem;
    letter-spacing: -.01em;
    color: var(--c-text);
}
.sidebar-brand:hover { text-decoration: none; color: var(--c-text); }

/* Collapse control */
.nav-collapse {
    width: 24px; height: 24px;
    flex: 0 0 24px;
    display: grid; place-items: center;
    border: 0;
    background: transparent;
    color: var(--c-text-subtle);
    border-radius: 5px;
    cursor: pointer;
    padding: 0;
    font-size: .78rem;
    transition: background .12s ease, color .12s ease;
}
.nav-collapse:hover { background: var(--c-surface-hover); color: var(--c-text); }

.sidebar-brand .mark {
    width: 26px; height: 26px;
    border-radius: 7px;
    background: var(--c-accent);
    color: var(--c-accent-text);
    display: grid; place-items: center;
    font-weight: 700; font-size: .78rem;
    flex: 0 0 26px;
}

.sidebar-nav {
    padding: .75rem .6rem;
    overflow-y: auto;
    flex: 1;
}

.nav-section {
    font-size: .68rem;
    text-transform: uppercase;
    letter-spacing: .07em;
    font-weight: 600;
    color: var(--c-text-subtle);
    padding: .9rem .55rem .35rem;
}

.nav-item-link {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .48rem .55rem;
    border-radius: var(--r-sm);
    color: var(--c-text-muted);
    font-weight: 500;
    font-size: .875rem;
    margin-bottom: 1px;
    transition: background .12s ease, color .12s ease;
}
.nav-item-link:hover {
    background: var(--c-surface-hover);
    color: var(--c-text);
    text-decoration: none;
}
.nav-item-link.active {
    background: var(--c-accent-soft);
    color: var(--c-accent);
    font-weight: 600;
}
.nav-item-link i { font-size: 1rem; width: 18px; text-align: center; }

.nav-item-link .count {
    margin-left: auto;
    font-size: .72rem;
    font-weight: 600;
    background: var(--c-surface-2);
    color: var(--c-text-muted);
    border-radius: 20px;
    padding: .05rem .42rem;
    font-variant-numeric: tabular-nums;
}
.nav-item-link .count.alert {
    background: var(--c-neg-soft);
    color: var(--c-neg);
}

.sidebar-foot {
    border-top: 1px solid var(--c-border);
    padding: .6rem;
}

/* Sign out sits alongside the theme toggle. */
.foot-row {
    display: flex;
    align-items: center;
    gap: .35rem;
}
.foot-row .icon-btn { flex: 0 0 32px; }

/* ============================================================================
   Collapsed sidebar — an icon rail.
   Labels are hidden rather than removed, so the DOM (and screen readers) are
   unaffected; native title tooltips carry the names.
   ========================================================================== */

:root[data-nav="collapsed"] {
    --sidebar-w: 62px;
}

/* Labels collapse rather than vanish, so the transition has something to animate.
   (display:none can't be tweened.) They fade a touch faster than the rail moves,
   which stops the text visibly squashing as the width shrinks. */
.sidebar .label {
    max-width: 170px;
    overflow: hidden;
    white-space: nowrap;
    opacity: 1;
    transition:
        max-width .24s cubic-bezier(.32, .72, 0, 1),
        opacity .14s ease;
}
[data-nav="collapsed"] .sidebar .label {
    max-width: 0;
    opacity: 0;
}

[data-nav="collapsed"] .sidebar-brand-row {
    flex-direction: column;
    justify-content: center;
    gap: .2rem;
    height: auto;
    padding: .55rem 0;
}
[data-nav="collapsed"] .sidebar-brand {
    padding: 0;
    justify-content: center;
    gap: 0;
}

/* Brand: the wordmark logo when expanded, the DE monogram when collapsed (the
   wordmark can't fit the narrow rail). Both are dark-on-white, so they sit in a
   small white chip to stay legible on either theme. */
.sidebar-logo {
    height: 36px; width: auto;
    background: #fff;
    padding: 5px 10px;
    border-radius: 8px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .08);
}
.sidebar-logo-mini { display: none; }
[data-nav="collapsed"] .sidebar-logo { display: none; }
[data-nav="collapsed"] .sidebar-logo-mini {
    display: block;
    height: 34px; width: auto;
    background: #fff;
    padding: 4px;
    border-radius: 7px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .08);
}

[data-nav="collapsed"] .sidebar-nav { padding: .75rem .5rem; }

.nav-item-link { transition: background .12s ease, color .12s ease, gap .24s cubic-bezier(.32,.72,0,1); }

[data-nav="collapsed"] .nav-item-link {
    justify-content: center;
    padding: .55rem 0;
    gap: 0;
}
[data-nav="collapsed"] .nav-item-link i { width: auto; font-size: 1.05rem; }

/* The chevron rotates rather than swapping glyphs — reads as one continuous motion. */
.nav-collapse i { transition: transform .24s cubic-bezier(.32, .72, 0, 1); }

/* A section heading with no text would just be dead space - swap it for a rule. */
[data-nav="collapsed"] .nav-section {
    padding: .65rem .5rem .35rem;
    border-top: 1px solid var(--c-border);
    margin-top: .35rem;
    height: 0;
    overflow: hidden;
}

/* Counts can't fit, so surface unread/alert state as a dot on the icon. */
[data-nav="collapsed"] .nav-item-link .count { display: none; }
[data-nav="collapsed"] .nav-item-link:has(.count.alert) { position: relative; }
[data-nav="collapsed"] .nav-item-link:has(.count.alert)::after {
    content: "";
    position: absolute;
    top: .42rem; right: .78rem;
    width: 6px; height: 6px;
    border-radius: 50%;
    background: var(--c-neg);
    box-shadow: 0 0 0 2px var(--c-surface);
}

[data-nav="collapsed"] .foot-row { flex-direction: column; gap: .25rem; }
[data-nav="collapsed"] .foot-row .grow { width: 100%; }

/* --- Main column --- */
.main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.topbar {
    height: var(--topbar-h);
    background: var(--c-surface);
    border-bottom: 1px solid var(--c-border);
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0 1.35rem;
    position: sticky;
    top: 0;
    z-index: 20;
}

.topbar .spacer { flex: 1; }

.page {
    padding: 1.5rem 1.75rem 3rem;
    max-width: 1440px;
    width: 100%;

    /* Without this the content hugs the left edge of the main column and leaves
       dead space on the right on wide screens. Centre it in the available area. */
    margin-inline: auto;
}

.page-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.25rem;
}
.page-title { font-size: 1.375rem; font-weight: 650; letter-spacing: -.015em; }
.page-sub { color: var(--c-text-muted); font-size: .875rem; margin-top: .12rem; }

/* Breadcrumb */
.crumbs { font-size: .8rem; color: var(--c-text-subtle); margin-bottom: .3rem; }
.crumbs a { color: var(--c-text-muted); }
.crumbs .sep { margin: 0 .35rem; opacity: .5; }

/* ============================================================================
   Icon button / theme toggle
   ========================================================================== */

.icon-btn {
    width: 32px; height: 32px;
    display: grid; place-items: center;
    border-radius: var(--r-sm);
    border: 1px solid var(--c-border);
    background: var(--c-surface);
    color: var(--c-text-muted);
    cursor: pointer;
    transition: all .12s ease;
    padding: 0;
}
.icon-btn:hover {
    background: var(--c-surface-hover);
    color: var(--c-text);
    border-color: var(--c-border-strong);
}

/* ============================================================================
   Cards / surfaces
   ========================================================================== */

.card,
.panel {
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--r-md);
    box-shadow: var(--shadow-sm);
}

.panel-head {
    padding: .85rem 1.1rem;
    border-bottom: 1px solid var(--c-border);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
}
.panel-title { font-weight: 600; font-size: .9375rem; }
.panel-body { padding: 1.1rem; }
.panel-body.tight { padding: 0; }

/* --- Stat tiles --- */
.stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: .85rem;
    margin-bottom: 1.35rem;
}

.stat {
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--r-md);
    padding: .9rem 1rem;
    box-shadow: var(--shadow-sm);
}
.stat-label {
    font-size: .75rem;
    color: var(--c-text-muted);
    font-weight: 500;
    display: flex; align-items: center; gap: .3rem;
    margin-bottom: .25rem;
}
.stat-value {
    font-size: 1.375rem;
    font-weight: 650;
    letter-spacing: -.02em;
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
}
.stat-hint { font-size: .74rem; color: var(--c-text-subtle); margin-top: .15rem; }

.stat.pos .stat-value { color: var(--c-pos); }
.stat.neg .stat-value { color: var(--c-neg); }
.stat.warn .stat-value { color: var(--c-warn); }

/* Coloured left edge + soft tint on full-size KPI cards (the dashboard row), the
   same status treatment stats-compact gives the overview deadline strip - here
   without the compact shrink, so the cards keep their size. */
.stats-edge .stat { border-left: 3px solid var(--c-border); }
.stats-edge .stat.pos  { border-left-color: var(--c-pos);  background: var(--c-pos-soft); }
.stats-edge .stat.warn { border-left-color: var(--c-warn); background: var(--c-warn-soft); }
.stats-edge .stat.neg  { border-left-color: var(--c-neg);  background: var(--c-neg-soft); }

/* Overview sub-tabs — Transactions vs Fixed assets. A light underline segmented
   control below the deadline cards; only shown when the client has a register. */
.ov-subtabs {
    display: flex;
    gap: .1rem;
    margin-bottom: 1rem;
    border-bottom: 1px solid var(--c-border);
}
.ov-subtab {
    appearance: none;
    background: none;
    border: 0;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    padding: .5rem .85rem;
    font-size: .875rem;
    font-weight: 550;
    color: var(--c-text-muted);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: .4rem;
}
.ov-subtab:hover { color: var(--c-text); }
.ov-subtab.is-active { color: var(--c-text); border-bottom-color: var(--c-accent); }

/* Chart-style toggle (line / bar / doughnut) in a chart panel header. */
.chart-toggle { display: inline-flex; gap: 2px; }
.chart-toggle .asset-chart-type {
    appearance: none;
    border: 1px solid var(--c-border);
    background: var(--c-surface);
    color: var(--c-text-muted);
    width: 30px; height: 28px;
    display: inline-flex; align-items: center; justify-content: center;
    cursor: pointer;
    font-size: .85rem;
}
.chart-toggle .asset-chart-type:first-child { border-radius: var(--r-sm, 6px) 0 0 var(--r-sm, 6px); }
.chart-toggle .asset-chart-type:last-child  { border-radius: 0 var(--r-sm, 6px) var(--r-sm, 6px) 0; }
.chart-toggle .asset-chart-type + .asset-chart-type { border-left: 0; }
.chart-toggle .asset-chart-type:hover { color: var(--c-text); }
.chart-toggle .asset-chart-type.is-active {
    color: var(--c-accent-text, #fff);
    background: var(--c-accent);
    border-color: var(--c-accent);
}

/* ============================================================================
   Tables — the workhorse
   ========================================================================== */

.table-wrap {
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--r-md);
    overflow: hidden;
    box-shadow: var(--shadow-sm);
}
.table-scroll { overflow-x: auto; }

table.data {
    width: 100%;
    border-collapse: collapse;
    font-size: .8125rem;
}

table.data thead th {
    background: var(--c-surface-2);
    border-bottom: 1px solid var(--c-border);
    padding: .58rem .85rem;
    text-align: left;
    font-weight: 600;
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .045em;
    color: var(--c-text-muted);
    white-space: nowrap;
    position: sticky;
    top: 0;
    z-index: 1;
}

table.data tbody td {
    padding: .62rem .85rem;
    border-bottom: 1px solid var(--c-border);
    vertical-align: middle;
    color: var(--c-text);
}
table.data tbody tr:last-child td { border-bottom: 0; }
table.data tbody tr:hover { background: var(--c-surface-hover); }

table.data td.right, table.data th.right { text-align: right; }

/* Sortable column header: looks like the header, not a link. */
a.th-sort {
    color: inherit;
    text-decoration: none;
    cursor: pointer;
    white-space: nowrap;
}
a.th-sort:hover { color: var(--c-accent); }
.th-sort-icon { font-size: .68rem; margin-left: .12rem; opacity: .3; vertical-align: -1px; }
a.th-sort:hover .th-sort-icon { opacity: .65; }
.th-sort-icon.active { opacity: 1; color: var(--c-accent); }
table.data td.amount {
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-weight: 550;
    white-space: nowrap;
}

table.data tr.row-flag { background: var(--c-neg-soft); }
table.data tr.row-flag:hover { background: var(--c-neg-soft); filter: brightness(.98); }

table.data tr.selected { background: var(--c-accent-soft); }

/* Focused row for keyboard nav */
table.data tr.kb-focus {
    box-shadow: inset 3px 0 0 var(--c-accent);
    background: var(--c-surface-hover);
}

.cell-primary { font-weight: 500; }
.cell-sub { font-size: .74rem; color: var(--c-text-subtle); margin-top: .1rem; }

/* ============================================================================
   Badges / pills
   ========================================================================== */

.pill {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    font-size: .7rem;
    font-weight: 600;
    padding: .13rem .48rem;
    border-radius: 20px;
    white-space: nowrap;
    line-height: 1.5;
    border: 1px solid transparent;
}
.pill-neutral { background: var(--c-surface-2); color: var(--c-text-muted); border-color: var(--c-border); }
.pill-accent  { background: var(--c-accent-soft); color: var(--c-accent); }
.pill-pos     { background: var(--c-pos-soft); color: var(--c-pos); }
.pill-neg     { background: var(--c-neg-soft); color: var(--c-neg); }
.pill-warn    { background: var(--c-warn-soft); color: var(--c-warn); }
.pill-info    { background: var(--c-info-soft); color: var(--c-info); }

/* Confidence, given its own scale so it reads at a glance */
.conf-strong { background: var(--c-pos-soft); color: var(--c-pos); }
.conf-medium { background: var(--c-warn-soft); color: var(--c-warn); }
.conf-weak   { background: var(--c-warn-soft); color: var(--c-warn); opacity: .8; }
.conf-none   { background: var(--c-surface-2); color: var(--c-text-muted); border-color: var(--c-border); }
.conf-manual { background: var(--c-accent-soft); color: var(--c-accent); }

/* ============================================================================
   Buttons (override Bootstrap)
   ========================================================================== */

.btn {
    font-size: .8125rem;
    font-weight: 550;
    border-radius: var(--r-sm);
    padding: .38rem .8rem;
    border: 1px solid transparent;
    transition: all .12s ease;
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    line-height: 1.5;
}
.btn:focus, .btn:focus-visible {
    outline: 2px solid var(--c-accent);
    outline-offset: 1px;
    box-shadow: none;
}

.btn-primary {
    background: var(--c-accent);
    border-color: var(--c-accent);
    color: var(--c-accent-text);
}
.btn-primary:hover {
    background: var(--c-accent-hover);
    border-color: var(--c-accent-hover);
    color: var(--c-accent-text);
}

.btn-secondary,
.btn-outline-secondary {
    background: var(--c-surface);
    border-color: var(--c-border-strong);
    color: var(--c-text);
}
.btn-secondary:hover,
.btn-outline-secondary:hover {
    background: var(--c-surface-hover);
    border-color: var(--c-text-subtle);
    color: var(--c-text);
}

.btn-danger {
    background: var(--c-neg);
    border-color: var(--c-neg);
    color: #fff;
}
.btn-danger:hover { filter: brightness(.92); color: #fff; }

.btn-ghost {
    background: transparent;
    border-color: transparent;
    color: var(--c-text-muted);
}
.btn-ghost:hover { background: var(--c-surface-hover); color: var(--c-text); }

.btn-sm { font-size: .75rem; padding: .28rem .6rem; }
.btn-lg { font-size: .9rem; padding: .55rem 1.1rem; }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn.disabled { opacity: .4; pointer-events: none; }

/* Reusable confirm modal (window.confirmDialog). */
.modal-backdrop {
    position: fixed;
    inset: 0;
    z-index: 400;
    background: rgba(15, 23, 42, .5);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    animation: modalFade .12s ease;
}
.modal-backdrop[hidden] { display: none; }
.modal-card {
    width: 100%;
    max-width: 380px;
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-lg);
    padding: 1.6rem 1.5rem 1.35rem;
    text-align: center;
    animation: modalPop .14s ease;
}
.modal-icon {
    width: 46px;
    height: 46px;
    margin: 0 auto .85rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    font-size: 1.35rem;
    background: var(--c-accent-soft);
    color: var(--c-accent);
}
.modal-icon.danger { background: var(--c-neg-soft); color: var(--c-neg); }
.modal-title { margin: 0 0 .35rem; font-size: 1.05rem; font-weight: 650; color: var(--c-text); }
.modal-msg { margin: 0 0 1.35rem; font-size: .85rem; color: var(--c-text-muted); line-height: 1.5; }
.modal-actions { display: flex; gap: .55rem; justify-content: center; }
.modal-actions .btn { min-width: 96px; justify-content: center; }
@keyframes modalFade { from { opacity: 0; } }
@keyframes modalPop { from { opacity: 0; transform: translateY(8px) scale(.97); } }

/* Per-row actions kebab (⋮) and its menu. The menu is position:fixed and lives
   outside the scrolling table, so it is never clipped. */
.kebab-cell { text-align: center; }
.kebab-trigger {
    background: none;
    border: 0;
    padding: .2rem .35rem;
    line-height: 1;
    border-radius: var(--r-sm);
    color: var(--c-text-subtle);
    cursor: pointer;
}
.kebab-trigger:hover { color: var(--c-text); background: var(--c-surface-hover); }

.rowmenu-pop {
    position: fixed;
    z-index: 200;
    min-width: 160px;
    background: var(--c-surface);
    border: 1px solid var(--c-border-strong);
    border-radius: var(--r-sm);
    box-shadow: var(--shadow-lg);
    padding: 4px;
}
.rowmenu-pop[hidden] { display: none; }
.rowmenu-pop button {
    display: block;
    width: 100%;
    text-align: left;
    background: none;
    border: 0;
    padding: .42rem .55rem;
    border-radius: var(--r-sm);
    cursor: pointer;
    font-size: .8125rem;
    color: var(--c-text);
}
.rowmenu-pop button[hidden] { display: none; }
.rowmenu-pop button:hover { background: var(--c-surface-hover); }
.rowmenu-pop button.danger { color: var(--c-neg); }

/* In-page refresh: gently dim the results while the swap is in flight. */
#registerResults.is-loading { opacity: .55; transition: opacity .1s ease; pointer-events: none; }

/* Standard pagination (the shared _Pagination partial). */
.pager {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 1.25rem;
    margin-top: 1rem;
    padding-bottom: 1rem;
}
.pager-size {
    display: flex;
    align-items: center;
    gap: .4rem;
    margin: 0;
}
.pager-size-label { font-size: .75rem; color: var(--c-text-subtle); }
.pager-size select { width: auto; }
.pager-nav {
    display: flex;
    align-items: center;
    gap: .6rem;
}
.pager-status {
    font-size: .8rem;
    color: var(--c-text-subtle);
    min-width: 9ch;
    text-align: center;
}

/* ============================================================================
   Forms
   ========================================================================== */

.form-label {
    font-size: .78rem;
    font-weight: 550;
    color: var(--c-text-muted);
    margin-bottom: .28rem;
}

.form-control,
.form-select {
    background: var(--c-surface);
    border: 1px solid var(--c-border-strong);
    border-radius: var(--r-sm);
    color: var(--c-text);
    font-size: .8125rem;
    padding: .4rem .6rem;
    transition: border-color .12s ease, box-shadow .12s ease;
}
.form-control::placeholder { color: var(--c-text-subtle); }

/* A required <select> still on its empty placeholder option reads muted, like an
   input placeholder - so it doesn't look like a chosen value. */
.form-select:required:invalid { color: var(--c-text-subtle); }
.form-select:required:invalid option { color: var(--c-text); }
.form-control:focus,
.form-select:focus {
    background: var(--c-surface);
    color: var(--c-text);
    border-color: var(--c-accent);
    box-shadow: 0 0 0 3px var(--c-accent-soft);
    outline: none;
}
.form-control-sm, .form-select-sm { font-size: .78rem; padding: .28rem .5rem; }

.form-text { font-size: .74rem; color: var(--c-text-subtle); }

/* Combobox: a free-text input with a capped, scrollable suggestion list.
   Replaces the native <datalist>, whose dropdown height the browser controls. */
.combo { position: relative; }
.combo-menu {
    position: absolute;
    z-index: 40;
    left: 0;
    right: 0;
    top: calc(100% + 4px);
    max-height: 260px;
    overflow-y: auto;
    background: var(--c-surface);
    border: 1px solid var(--c-border-strong);
    border-radius: var(--r-sm);
    box-shadow: var(--shadow-lg);
    padding: 4px;
}
.combo-menu[hidden] { display: none; }
.combo-option {
    padding: .4rem .55rem;
    border-radius: var(--r-sm);
    cursor: pointer;
    font-size: .8125rem;
    color: var(--c-text);
    line-height: 1.25;
}
.combo-option[hidden] { display: none; }
.combo-option:hover,
.combo-option.active { background: var(--c-surface-hover); }
.combo-option .combo-hint {
    display: block;
    font-size: .7rem;
    color: var(--c-text-subtle);
}
.combo-empty {
    padding: .5rem .55rem;
    font-size: .78rem;
    color: var(--c-text-subtle);
}

.form-check-input {
    border-color: var(--c-border-strong);
    background-color: var(--c-surface);
}
.form-check-input:checked {
    background-color: var(--c-accent);
    border-color: var(--c-accent);
}
.form-check-input:focus {
    border-color: var(--c-accent);
    box-shadow: 0 0 0 3px var(--c-accent-soft);
}
.form-check-label { font-size: .8125rem; color: var(--c-text); }

/* Filter bar */
.filters {
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--r-md);
    padding: .75rem .9rem;
    margin-bottom: 1rem;
    box-shadow: var(--shadow-sm);
}
.filters .row { --bs-gutter-x: .6rem; --bs-gutter-y: .5rem; }

/* ============================================================================
   Alerts / callouts
   ========================================================================== */

.callout {
    border: 1px solid var(--c-border);
    border-left: 3px solid var(--c-text-subtle);
    background: var(--c-surface);
    border-radius: var(--r-sm);
    padding: .75rem .95rem;
    font-size: .8125rem;
    margin-bottom: 1rem;
    box-shadow: var(--shadow-sm);
}
.callout-title { font-weight: 600; margin-bottom: .15rem; }

.callout-accent { border-left-color: var(--c-accent); background: var(--c-accent-soft); }
.callout-pos    { border-left-color: var(--c-pos);    background: var(--c-pos-soft); }
.callout-neg    { border-left-color: var(--c-neg);    background: var(--c-neg-soft); }
.callout-warn   { border-left-color: var(--c-warn);   background: var(--c-warn-soft); }
.callout-info   { border-left-color: var(--c-info);   background: var(--c-info-soft); }

/* 2FA nudge — an inset card prompting the user to turn on two-factor. */
.tfa-nudge {
    display: flex;
    align-items: center;
    gap: .85rem;
    padding: .8rem .9rem;
    margin-bottom: 1.5rem;
    border: 1px solid var(--c-border);
    border-radius: var(--r-lg);
    background: var(--c-surface);
    box-shadow: var(--shadow-sm);
}
.tfa-nudge-icon {
    flex: 0 0 auto;
    width: 40px;
    height: 40px;
    display: grid;
    place-items: center;
    border-radius: 11px;
    background: var(--c-accent-soft);
    color: var(--c-accent);
    font-size: 1.15rem;
}
.tfa-nudge-body { min-width: 0; display: flex; flex-direction: column; gap: .1rem; }
.tfa-nudge-title { font-weight: 600; font-size: .875rem; }
.tfa-nudge-sub { font-size: .8rem; color: var(--c-text-muted); }
.tfa-nudge .btn { margin-left: auto; flex: 0 0 auto; }
.tfa-nudge-x {
    flex: 0 0 auto;
    background: none;
    border: 0;
    color: var(--c-text-muted);
    font-size: 1.15rem;
    line-height: 1;
    cursor: pointer;
    padding: .15rem .35rem;
    border-radius: var(--r-sm);
}
.tfa-nudge-x:hover { background: var(--c-surface-hover); color: var(--c-text); }

@media (max-width: 620px) {
    .tfa-nudge-sub { display: none; }
}

/* Authenticator QR — scale QRCoder's fixed-size SVG down to the box. */
.qr-box {
    flex: 0 0 auto;
    width: 176px;
    height: 176px;
    padding: 8px;
    background: #fff;
    border: 1px solid var(--c-border);
    border-radius: var(--r-sm);
}
.qr-box svg { display: block; width: 100%; height: 100%; }

/* Segmented control — a full-width two-option mode switch (pill group). */
.seg {
    display: flex;
    gap: .2rem;
    padding: .2rem;
    background: var(--c-surface-2);
    border: 1px solid var(--c-border);
    border-radius: var(--r-md);
}
.seg-btn {
    flex: 1 1 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .4rem;
    padding: .45rem .8rem;
    border: 0;
    background: none;
    border-radius: calc(var(--r-md) - 3px);
    font-size: .8125rem;
    font-weight: 550;
    color: var(--c-text-muted);
    cursor: pointer;
}
.seg-btn:hover { color: var(--c-text); }
.seg-btn.active {
    background: var(--c-surface);
    color: var(--c-text);
    box-shadow: var(--shadow-sm);
}

/* Bootstrap alert fallbacks, themed */
.alert {
    border-radius: var(--r-sm);
    font-size: .8125rem;
    border: 1px solid var(--c-border);
    border-left-width: 3px;
    padding: .7rem .9rem;
}
.alert-info    { background: var(--c-info-soft);  color: var(--c-text); border-left-color: var(--c-info); }
.alert-success { background: var(--c-pos-soft);   color: var(--c-text); border-left-color: var(--c-pos); }
.alert-danger  { background: var(--c-neg-soft);   color: var(--c-text); border-left-color: var(--c-neg); }
.alert-warning { background: var(--c-warn-soft);  color: var(--c-text); border-left-color: var(--c-warn); }
.alert-light   { background: var(--c-surface-2);  color: var(--c-text-muted); }

/* ============================================================================
   Toasts
   ========================================================================== */

.toast-stack {
    position: fixed;
    bottom: 1.25rem;
    right: 1.25rem;
    z-index: 1080;
    display: flex;
    flex-direction: column;
    gap: .55rem;
}

.toast-item {
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-left: 3px solid var(--c-accent);
    border-radius: var(--r-sm);
    box-shadow: var(--shadow-lg);
    padding: .7rem .9rem;
    font-size: .8125rem;
    min-width: 280px;
    max-width: 420px;
    display: flex;
    gap: .55rem;
    align-items: flex-start;
    animation: toast-in .22s cubic-bezier(.2,.9,.3,1);
}
.toast-item.pos  { border-left-color: var(--c-pos); }
.toast-item.neg  { border-left-color: var(--c-neg); }
.toast-item.warn { border-left-color: var(--c-warn); }
.toast-item .close {
    margin-left: auto; background: none; border: 0;
    color: var(--c-text-subtle); cursor: pointer; padding: 0 .1rem;
    line-height: 1;
}

@keyframes toast-in {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
}

/* ============================================================================
   Empty states — never show a blank box
   ========================================================================== */

.empty {
    text-align: center;
    padding: 3rem 1.5rem;
    color: var(--c-text-muted);
}
.empty .glyph {
    width: 46px; height: 46px;
    border-radius: var(--r-md);
    background: var(--c-surface-2);
    border: 1px solid var(--c-border);
    display: grid; place-items: center;
    margin: 0 auto .85rem;
    font-size: 1.25rem;
    color: var(--c-text-subtle);
}
.empty h3 { font-size: .9375rem; margin-bottom: .3rem; color: var(--c-text); }
.empty p { font-size: .8125rem; margin: 0 auto 1rem; max-width: 380px; }

/* ============================================================================
   Tabs (client workspace)
   ========================================================================== */

.tabs {
    display: flex;
    gap: .15rem;
    border-bottom: 1px solid var(--c-border);
    margin-bottom: 1.35rem;

    /* overflow-x:auto alone makes overflow-y compute to auto as well, and the
       -1px margin on .tab (which lets the active underline sit on this border)
       overflows by exactly that pixel - enough to summon a vertical scrollbar.
       Pin the y axis shut. */
    overflow-x: auto;
    overflow-y: hidden;

    /* Only show the horizontal bar when the tabs genuinely don't fit. */
    scrollbar-width: thin;
}
.tabs::-webkit-scrollbar { height: 4px; }
.tabs::-webkit-scrollbar-thumb {
    background: var(--c-border-strong);
    border-radius: 4px;
}
.tabs::-webkit-scrollbar-track { background: transparent; }
.tab {
    padding: .55rem .85rem;
    font-size: .8125rem;
    font-weight: 550;
    color: var(--c-text-muted);
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    white-space: nowrap;
    display: flex;
    align-items: center;
    gap: .4rem;
}
.tab:hover { color: var(--c-text); text-decoration: none; }
.tab.active { color: var(--c-accent); border-bottom-color: var(--c-accent); }
.tab .count {
    font-size: .7rem; font-weight: 600;
    background: var(--c-surface-2); color: var(--c-text-muted);
    border-radius: 20px; padding: 0 .38rem;
    font-variant-numeric: tabular-nums;
}
.tab.active .count { background: var(--c-accent-soft); color: var(--c-accent); }
.tab .count.alert { background: var(--c-neg-soft); color: var(--c-neg); }

/* ============================================================================
   Progress / meter
   ========================================================================== */

.meter {
    height: 5px;
    border-radius: 20px;
    background: var(--c-surface-2);
    overflow: hidden;
}
.meter > span {
    display: block;
    height: 100%;
    background: var(--c-accent);
    border-radius: 20px;
}
.meter.pos > span  { background: var(--c-pos); }
.meter.warn > span { background: var(--c-warn); }
.meter.neg > span  { background: var(--c-neg); }

/* Profit & loss statement (vertical): section headers, subtotals, net line. */
table.data.pnl tbody tr:hover { background: transparent; }
table.data.pnl tbody tr:not(.pnl-head):not(.pnl-subtotal):not(.pnl-net):not(.pnl-spacer):hover {
    background: var(--c-surface-hover);
}
.pnl-section-title {
    font-weight: 700;
    text-transform: uppercase;
    font-size: .7rem;
    letter-spacing: .05em;
}
.pnl-head td { border-bottom: 0; padding-bottom: .3rem; }

/* Line items sit indented under their section heading (Income / Expenses /
   Assets / Liabilities / Equity), so the hierarchy reads at a glance.
   Subtotal and total rows stay flush left. Applies to the P&L and the
   balance sheet alike. */
table.data.pnl tbody td.pnl-item,
table.data.bs-table tbody td.pnl-item { padding-left: 1.85rem; }

/* Freeze the label column when the year columns scroll sideways, so you never lose
   which row a figure belongs to. Backgrounds are opaque so scrolled cells can't
   bleed through; z-index keeps the (already sticky) header row and the corner above
   the frozen column. */
table.data.bs-table th:first-child,
table.data.bs-table td:first-child {
    position: sticky;
    left: 0;
    background: var(--c-surface);
    z-index: 1;
}
table.data.bs-table tbody tr:hover td:first-child { background: var(--c-surface-hover); }
table.data.bs-table thead th { z-index: 2; }
table.data.bs-table thead th:first-child { z-index: 3; background: var(--c-surface-2); }

/* Section headers span every column, so the cell itself can't stick (a full-width
   sticky cell has no room to shift). Pin the label TEXT instead, aligned with the
   frozen column's labels. */
table.data.bs-table .pnl-section-title .bs-sec {
    position: sticky;
    left: .85rem;
    display: inline-block;
}

/* Drill-down links from a report line/section to the matching transactions. Inherit
   their surrounding colour (so section headers keep their pos/neg tint) and only
   reveal themselves as links on hover, to keep the report calm. */
.pnl-drill { color: inherit; text-decoration: none; }
.pnl-drill:hover { color: inherit; text-decoration: underline; }
.pnl-drill .bi { opacity: 0; transition: opacity .1s; font-size: .9em; }
.pnl-section-title:hover .pnl-drill .bi,
.pnl-item:hover .pnl-drill .bi { opacity: .6; }
.pnl-subtotal td { border-top: 1px solid var(--c-border-strong); border-bottom: 0; font-weight: 650; }
.pnl-subtotal td.amount { font-weight: 750; }
.pnl-spacer td { height: 1rem; border: 0; padding: 0; }
.pnl-net td {
    border-top: 2px solid var(--c-border-strong);
    border-bottom: 0;
    font-weight: 700;
    /* Horizontal padding stated explicitly: the base .85rem only targets tbody td,
       so a .pnl-net row placed in <tfoot> (the trial balance total) would otherwise
       have zero side padding and sit flush against the table edge. */
    padding: .7rem .85rem;
}
.pnl-net.pos td.amount { color: var(--c-pos); }
.pnl-net.neg td.amount { color: var(--c-neg); }
.pnl-margin { text-align: right; font-size: .75rem; font-weight: 500; color: var(--c-text-subtle); }
.pnl-bar { vertical-align: middle; }
.pnl-bar .meter { margin: 0; }

/* ============================================================================
   Auth pages (centred, no shell)
   ========================================================================== */

.auth-wrap {
    min-height: 100vh;
    display: grid;
    place-items: center;
    padding: 2rem 1rem;
    background: var(--c-bg);
}
.auth-card {
    width: 100%;
    max-width: 400px;
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-md);
    padding: 1.85rem;
}
.auth-brand {
    display: flex; align-items: center; justify-content: center;
    gap: .55rem; margin-bottom: 1.35rem;
    font-weight: 650; font-size: 1.05rem;
}
.auth-brand .mark {
    width: 30px; height: 30px; border-radius: 8px;
    background: var(--c-accent); color: var(--c-accent-text);
    display: grid; place-items: center; font-weight: 700; font-size: .82rem;
}
/* The logo is a dark-text wordmark on white, so it sits in a white "chip" to stay
   legible on any theme (the auth pages follow light/dark). */
.auth-logo {
    height: 44px; width: auto;
    background: #fff;
    padding: 9px 15px;
    border-radius: 10px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .12);
}

/* ============================================================================
   Keyboard shortcut hints
   ========================================================================== */

kbd {
    font-family: var(--font-mono);
    font-size: .68rem;
    background: var(--c-surface-2);
    border: 1px solid var(--c-border-strong);
    border-bottom-width: 2px;
    border-radius: 4px;
    padding: .06rem .3rem;
    color: var(--c-text-muted);
}

.shortcut-bar {
    display: flex; gap: .9rem; flex-wrap: wrap;
    font-size: .72rem; color: var(--c-text-subtle);
    padding: .5rem .1rem 0;
}
.shortcut-bar span { display: inline-flex; align-items: center; gap: .28rem; }

/* ============================================================================
   Utilities
   ========================================================================== */

.stack   { display: flex; flex-direction: column; gap: 1rem; }
.row-gap { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.grow    { flex: 1; }
.divider { height: 1px; background: var(--c-border); margin: 1rem 0; }

/* Labeled divider: a centered word between two rules (e.g. "or"). */
.divider-label {
    display: flex;
    align-items: center;
    gap: .75rem;
    margin: 1rem 0;
    color: var(--c-text-muted);
    font-size: .75rem;
    text-transform: uppercase;
    letter-spacing: .05em;
}
.divider-label::before,
.divider-label::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--c-border);
}

.sr-only {
    position: absolute; width: 1px; height: 1px;
    padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

/* ============================================================================
   Accessibility — honour a reduced-motion preference
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
    *,
    .sidebar,
    .sidebar .label,
    .nav-item-link,
    .nav-collapse i {
        transition: none !important;
        animation: none !important;
    }
}

/* ============================================================================
   Responsive — sidebar collapses on small screens
   ========================================================================== */

@media (max-width: 900px) {
    .sidebar {
        position: fixed;
        left: 0; top: 0;
        z-index: 100;
        transform: translateX(-100%);
        transition: transform .2s ease;
        box-shadow: var(--shadow-lg);
    }
    .sidebar.open { transform: none; }
    .page { padding: 1.1rem 1rem 2.5rem; }
    .stats { grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); }
}

@media (min-width: 901px) {
    /* The topbar only existed to hold the mobile menu button and the theme
       toggle. The toggle now lives in the sidebar, so on desktop the topbar is
       dead space - reclaim it. */
    .topbar { display: none; }
    .sidebar-toggle { display: none; }
}

/* -------------------------------------------------------------------------
   Statement coverage grid (gap detection on the client Overview)
   ------------------------------------------------------------------------- */
.cov-scroll { overflow-x: auto; }

.cov-grid { border-collapse: collapse; width: 100%; }
.cov-grid th,
.cov-grid td { text-align: center; padding: .25rem .3rem; font-size: .75rem; }
.cov-grid thead th { color: var(--c-text-subtle); font-weight: 600; }
.cov-grid td.cov-acc,
.cov-grid th.cov-acc { text-align: left; white-space: nowrap; font-weight: 600; padding-right: .75rem; }
.cov-grid td.cov-note,
.cov-grid th.cov-note { text-align: left; white-space: nowrap; padding-left: .75rem; font-size: .72rem; }

.cov-cell {
    display: inline-block;
    width: 15px;
    height: 15px;
    border-radius: 3px;
    vertical-align: middle;
    background: var(--c-surface-hover);
    border: 1px solid var(--c-border);
}

/* Compact variant for the top-row coverage card: smaller cells and tighter
   padding so a long history shows more months before it has to scroll. */
.cov-grid-compact th,
.cov-grid-compact td { padding: .12rem .1rem; font-size: .64rem; }
.cov-grid-compact .cov-acc { padding-right: .5rem; font-size: .72rem; }
.cov-grid-compact .cov-cell { width: 11px; height: 11px; border-radius: 2px; }
.cov-covered { background: var(--c-pos); border-color: var(--c-pos); }
.cov-gap { background: var(--c-warn); border-color: var(--c-warn); }
.cov-pending { background: var(--c-surface-hover); border-color: var(--c-border); }

.cov-legend {
    display: flex;
    gap: 1.1rem;
    margin-top: .7rem;
    font-size: .72rem;
    color: var(--c-text-subtle);
    flex-wrap: wrap;
}
.cov-legend span { display: inline-flex; align-items: center; gap: .35rem; }
.cov-legend .cov-cell { width: 12px; height: 12px; }

/* Offer to shorten a rule whose pattern still carries a payment reference.
   Sits under the pattern in the rules table, deliberately quiet - it is a
   suggestion, not a warning. */
.rule-shorten {
    display: flex;
    align-items: center;
    gap: .35rem;
    flex-wrap: wrap;
    margin-top: .3rem;
    font-family: var(--font);
    font-size: .75rem;
    color: var(--c-text-muted);
}
.rule-shorten code {
    font-size: .75rem;
    color: var(--c-accent);
}
.rule-shorten .btn { padding: .05rem .4rem; font-size: .72rem; }

/* Inline rule-pattern editor (Rules table). */
.rule-edit-form {
    display: flex;
    align-items: center;
    gap: .3rem;
    flex-wrap: wrap;
}
.rule-edit-form input[name="pattern"] {
    font-family: var(--font-mono);
    font-size: .78rem;
    max-width: 18rem;
}
.rule-edit-form .btn { padding: .1rem .45rem; font-size: .72rem; }

/* ---- Review-matches modal (rule suggestion) ----
   The base .modal-card is a narrow, centred confirmation box; this variant is a
   wide, left-aligned data panel with its own scroll so a long match list never
   pushes the action buttons off screen. */
.modal-card.modal-wide {
    max-width: 720px;
    text-align: left;
}
.modal-card.modal-wide .modal-actions { justify-content: flex-end; }

.rule-matches-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    flex-wrap: wrap;
    font-size: .8125rem;
    margin-bottom: .5rem;
}

.rule-matches-list {
    max-height: 48vh;
    overflow-y: auto;
    border: 1px solid var(--c-border);
    border-radius: var(--r-sm);
}
.rule-matches-list table { margin: 0; }
.rule-matches-list td { font-size: .8125rem; padding: .35rem .5rem; }

/* Locked (hand-categorised) rows are visibly inert. */
.rule-matches-list tr.is-locked { background: var(--c-surface-2); }
.rule-matches-list tr.is-locked td { color: var(--c-text-subtle); }

.rule-matches-link {
    margin-left: .5rem;
    font-size: .78rem;
    text-decoration: underline;
}

/* Outcome summary above the match list. */
.rule-matches-summary {
    display: flex;
    gap: .4rem;
    flex-wrap: wrap;
    margin-bottom: .5rem;
}

/* A row that would be MOVED off a category someone already chose - the one case
   in this list that can quietly undo an earlier decision. */
.rule-matches-list tr.is-move td { background: var(--c-warn-soft); }

/* A number that behaves as a link (the rules hits count) without becoming an <a>:
   it opens a dialog rather than navigating, so a button is the honest element. */
.btn-linklike {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    font-weight: 600;
    color: var(--c-accent);
    cursor: pointer;
    text-decoration: none;
}
.btn-linklike:hover {
    color: var(--c-accent-hover);
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* ---- Overview trend charts ----
   A fixed-height box is required: Chart.js with maintainAspectRatio:false grows to
   fill its parent, and a parent with no height grows to fit the canvas - which
   loops and the chart creeps taller on every resize. */
.chart-box {
    position: relative;
    height: 260px;
}
.chart-box canvas { display: block; }

.chart-fallback {
    padding: 2rem 1rem;
    text-align: center;
    font-size: .8125rem;
    color: var(--c-text-subtle);
}

/* A KPI card that is also a link (the deadline cards on the client overview).
   Inherits .stat, so it keeps the tile look; these overrides just stop it
   picking up anchor styling and give it a hover affordance. */
a.stat-link {
    display: block;
    color: inherit;
    text-decoration: none;
    transition: border-color .12s ease, box-shadow .12s ease;
}
a.stat-link:hover {
    color: inherit;
    text-decoration: none;
    border-color: var(--c-border-strong);
    box-shadow: var(--shadow-sm);
}

/* ---- Companies House identity, beside the client name ----
   Pills rather than label/value pairs: these are three short facts, and a stack of
   uppercase labels over a wrapping address read as ragged next to a big title.
   Quiet by design - context about who the client is, not data to be scanned. */
.ch-identity {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: .35rem;
    flex-wrap: wrap;
}

.ch-pill {
    font-weight: 500;
    /* An address can be long - cap it and ellipsis rather than widening the header. */
    max-width: 24rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ch-pill i { opacity: .7; margin-right: .1rem; }

/* Under the title on narrow screens, where right-aligning just looks broken. */
@media (max-width: 900px) {
    .ch-identity { justify-content: flex-start; }
    .ch-pill { max-width: 100%; }
}

/* ---- Compact KPI cards (the deadline row on a client overview) ----
   Half the footprint of a .stat: deadlines are reference information, and at full
   size they out-shouted the money figures they sit above. Cards size to content
   rather than stretching, so three deadlines don't span the whole page. */
.stats-compact {
    grid-template-columns: repeat(auto-fill, minmax(190px, 220px));
    justify-content: start;
    gap: .5rem;
    margin-bottom: .9rem;
}
.stats-compact .stat { padding: .45rem .6rem; }
.stats-compact .stat-label { font-size: .68rem; margin-bottom: .1rem; }
.stats-compact .stat-value { font-size: .875rem; line-height: 1.25; }
.stats-compact .stat-hint { font-size: .68rem; margin-top: 0; }

/* Red / amber / green by urgency. A coloured edge plus a soft tint, so the status
   is legible at a glance without the card shouting - the soft tokens are themed,
   so this stays readable in dark mode.
   Specificity note: these are 3 classes deep, so they beat a.stat-link:hover
   (2 classes + pseudo) and the left edge survives hovering. */
.stats-compact .stat { border-left: 3px solid var(--c-border); }

.stats-compact .stat.neg  { border-left-color: var(--c-neg);  background: var(--c-neg-soft); }
.stats-compact .stat.warn { border-left-color: var(--c-warn); background: var(--c-warn-soft); }
.stats-compact .stat.pos  { border-left-color: var(--c-pos);  background: var(--c-pos-soft); }

/* The date itself stays neutral - the edge and tint already carry the status, and
   a coloured date on a tinted card is hard to read. */
.stats-compact .stat.neg .stat-value,
.stats-compact .stat.warn .stat-value,
.stats-compact .stat.pos .stat-value { color: var(--c-text); }

.stats-compact .stat.neg .stat-hint  { color: var(--c-neg); font-weight: 600; }
.stats-compact .stat.warn .stat-hint { color: var(--c-warn); font-weight: 600; }
.stats-compact .stat.pos .stat-hint  { color: var(--c-pos); }

/* ---- Expense pie ----
   A pie needs categorical colour, which this design system otherwise avoids. So
   it's a MONOCHROMATIC ramp off the accent rather than a rainbow: darkest slice
   is the biggest cost, and the ordering itself carries the meaning. Themed, so
   the ramp inverts sensibly in dark mode. */
:root {
    --c-cat-1: #24409c;
    --c-cat-2: #3355e0;
    --c-cat-3: #5b78e8;
    --c-cat-4: #8299ef;
    --c-cat-5: #a8b8f4;
    --c-cat-6: #ccd6f9;
    --c-cat-7: #b9c0cc;   /* "Other" — deliberately neutral, not part of the ramp */
}
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --c-cat-1: #b9c9fb;
        --c-cat-2: #94aaf8;
        --c-cat-3: #6b86f5;
        --c-cat-4: #5069c9;
        --c-cat-5: #3b4e97;
        --c-cat-6: #2a3768;
        --c-cat-7: #4a5262;
    }
}
:root[data-theme="dark"] {
    --c-cat-1: #b9c9fb;
    --c-cat-2: #94aaf8;
    --c-cat-3: #6b86f5;
    --c-cat-4: #5069c9;
    --c-cat-5: #3b4e97;
    --c-cat-6: #2a3768;
    --c-cat-7: #4a5262;
}

.pie-box { position: relative; height: 190px; margin-bottom: .75rem; }

.pie-legend {
    list-style: none;
    margin: 0;
    padding: 0;
    font-size: .78rem;
}
.pie-legend li {
    display: flex;
    align-items: center;
    gap: .45rem;
    padding: .18rem 0;
}
.pie-swatch {
    width: 10px; height: 10px;
    border-radius: 2px;
    flex: 0 0 10px;
}
.pie-swatch[data-slice="0"] { background: var(--c-cat-1); }
.pie-swatch[data-slice="1"] { background: var(--c-cat-2); }
.pie-swatch[data-slice="2"] { background: var(--c-cat-3); }
.pie-swatch[data-slice="3"] { background: var(--c-cat-4); }
.pie-swatch[data-slice="4"] { background: var(--c-cat-5); }
.pie-swatch[data-slice="5"] { background: var(--c-cat-6); }
.pie-swatch[data-slice="6"] { background: var(--c-cat-7); }

/* Name takes the slack; the figures stay right-aligned so they scan as a column. */
.pie-name   { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pie-amount { flex: 0 0 auto; }
.pie-pct    { flex: 0 0 2.5rem; text-align: right; }

/* ---- Client overview top bar ----
   Deadline cards and the period picker on one row. The picker is pushed right with
   margin-left:auto rather than space-between, so it stays right-aligned even when
   the client has no deadlines and the left side is empty. */
.overview-topbar {
    display: flex;
    align-items: stretch;
    gap: .75rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
}

/* Deadlines size to their tiles; coverage takes the rest. A flex row of
   fixed-width tiles (not the auto-fill grid) so the block is exactly as wide as
   its cards and doesn't fight the coverage panel for width. */
.overview-deadlines {
    margin-bottom: 0;
    display: flex;
    flex: 0 0 auto;
    flex-wrap: wrap;
    gap: .5rem;
    align-content: flex-start;
}
.overview-deadlines .stat {
    flex: 0 0 auto;
    width: 172px;
}

/* Coverage fills the remaining width. min-width:0 lets the inner grid scroll
   rather than push the flex item wider than the row. */
.overview-coverage {
    flex: 1 1 320px;
    min-width: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
}
.overview-coverage .cov-scroll { width: 100%; }

/* Compact to match the deadline tiles beside it: small title, tight padding,
   no head border - the card should read as one of the KPI tiles, not a full panel. */
.overview-coverage .panel-head {
    padding: .3rem .7rem .1rem;
    border-bottom: 0;
}
.overview-coverage .panel-title { font-size: .78rem; }
.overview-coverage .panel-body { padding: 0 .7rem .35rem; }
.overview-coverage .cov-grid th { padding: 0 .3rem; font-size: .68rem; line-height: 1.1; }
.overview-coverage .cov-grid td { padding: .02rem .3rem; font-size: .7rem; }
.overview-coverage .cov-cell { width: 12px; height: 12px; }

/* Legend keyed to the bottom of the card. Everything above is squeezed so the
   whole card stays exactly as short as the deadline tiles beside it. */
.cov-legend-compact {
    margin-top: .2rem;
    gap: .8rem;
    font-size: .64rem;
}
.cov-legend-compact .cov-cell { width: 9px; height: 9px; }

/* Its own row now, right-aligned so it lands above the Categorised card. */
.overview-period-row {
    display: flex;
    justify-content: flex-end;
    margin-bottom: .6rem;
}
.overview-period {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: .45rem;
}
.overview-period .form-label {
    margin: 0;
    white-space: nowrap;
}
.overview-period .form-select { width: auto; }

/* Account link in the sidebar foot: practice/person name above the email, with the
   email truncated so a long address can't widen or overflow the sidebar. */
.account-link { align-items: flex-start; }
.account-link i { margin-top: .1rem; }

.account-identity {
    display: flex;
    flex-direction: column;
    min-width: 0;          /* lets the children actually truncate */
    line-height: 1.25;
}
.account-name {
    color: var(--c-text);
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.account-email {
    font-size: .72rem;
    font-weight: 400;
    color: var(--c-text-subtle);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Report sub-nav (Income & expenditure | Trial balance) - a tighter tab strip than
   the client workspace tabs it sits under. */
.report-tabs { margin-top: -.35rem; margin-bottom: 1rem; font-size: .82rem; }

/* The bank contra row on the trial balance: separated from the account lines above
   with a rule, since it's the balancing figure, not another account. */
.tb-bank td { border-top: 2px solid var(--c-border-strong); font-weight: 600; }

/* Reconciliation table: highlight an out-of-balance statement and a continuity gap. */
.recon-off td { background: var(--c-neg-soft); }
.recon-gap td { background: var(--c-warn-soft); border-top: 1px solid var(--c-warn); }
