﻿/* ===== DESIGN TOKENS (Swiss / Brutalist) ===== */
:root {
    /* Easily changeable accent color */
    --accent: #0055FF;
    --accent-hover: #0044CC;
    --accent-light: rgba(0, 85, 255, 0.1);
    /* What reads on top of --accent. The light theme's accent is dark enough for white; the dark
       theme's is light enough that white on it is nearly illegible, so it takes near-black instead. */
    --accent-contrast: #FFFFFF;

    /* Backgrounds */
    --bg-app: #F5F5F0;
    --bg-card: #FFFFFF;
    --bg-sidebar: #FFFFFF;
    --bg-hover: #EBEBEB;
    --bg-input: #FFFFFF;

    /* Text & Borders */
    --text-primary: #1A1A1A;
    --text-secondary: #666666;
    --border-color: #1A1A1A;
    --border-light: #CCCCCC;
    --border-width: 2px;
    
    /* Semantic Colors */
    --color-positive: #007A33;
    --color-negative: #CC0000;
    --color-warning: #CC7700;
    --color-info: #0055FF;

    /* Chart Colors (retaining custom theming for ApexCharts) */
    --chart-pln: #0055FF;
    --chart-ike: #007A33;
    --chart-usd: #CC7700;
    --chart-eur: #CC0000;

    /* Typography */
    --font-ui: 'Space Grotesk', system-ui, -apple-system, sans-serif;
    --font-mono: 'JetBrains Mono', 'Consolas', monospace;

    /* Geometry */
    --radius: 0px;
    --shadow: none;

    /* The top bar and the sidebar's brand box are one horizontal line across the screen, so they are
       one number. They were two, and drifted: the brand box added up to 66px against the bar's 64,
       and the two bottom borders missed each other by 2px exactly where they meet. */
    --header-height: 64px;

    /* Every control in the top bar's right-hand cluster — language, theme, account, logout. They are
       read as one row, so one of them being a few pixels shorter than the rest is read as one of them
       being wrong, and each used to arrive at its own height by its own means. */
    --control-height: 36px;

    /* Spacing Grid (8px base) */
    --spacing-xs: 4px;
    --spacing-sm: 8px;
    --spacing-md: 16px;
    --spacing-lg: 24px;
    --spacing-xl: 32px;
    --spacing-2xl: 48px;
}

[data-theme="dark"] {
    --bg-app: #0A0A0A;
    --bg-card: #141414;
    --bg-sidebar: #0F0F0F;
    --bg-hover: #222222;
    --bg-input: #1A1A1A;

    --text-primary: #F0F0F0;
    --text-secondary: #999999;
    --border-color: #F0F0F0;
    --border-light: #333333;

    /* If we use #0055FF for light, maybe a brighter variant for dark, but let's stick to the plan: */
    --accent: #4488FF;
    --accent-hover: #6699FF;
    --accent-light: rgba(68, 136, 255, 0.15);
    --accent-contrast: #0A0A0A;

    --color-positive: #00CC55;
    --color-negative: #FF3333;
    --color-warning: #FFAA00;
    --color-info: #4488FF;

    --chart-pln: #4488FF;
    --chart-ike: #00CC55;
    --chart-usd: #FFAA00;
    --chart-eur: #FF3333;
}

/* ===== BASE STYLES ===== */
*, *::before, *::after { 
    box-sizing: border-box; 
}
html, body {
    font-family: var(--font-ui);
    background-color: var(--bg-app);
    color: var(--text-primary);
    margin: 0; 
    padding: 0;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    line-height: 1.5;
}
h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-ui);
    font-weight: 700;
    margin-top: 0;
    margin-bottom: var(--spacing-md);
    color: var(--text-primary);
    letter-spacing: -0.02em;
}
a { 
    color: var(--accent); 
    text-decoration: none; 
}
a:hover { 
    color: var(--accent-hover); 
    text-decoration: underline; 
}

/* ===== LOADER (Brutalist style) ===== */
.brutalist-loader {
    width: 64px;
    height: 64px;
    background: var(--text-primary);
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    animation: brutalist-pulse 1s infinite alternate;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--bg-app);
    font-family: var(--font-mono);
    font-weight: bold;
    font-size: 10px;
}
@keyframes brutalist-pulse {
    0% { transform: translate(-50%, -50%) scale(1); }
    100% { transform: translate(-50%, -50%) scale(0.8); }
}

/* ===== BLAZOR ERROR UI ===== */
#blazor-error-ui {
    background: var(--bg-card);
    border: var(--border-width) solid var(--color-negative);
    bottom: 0;
    display: none;
    left: 0;
    padding: var(--spacing-md);
    position: fixed;
    width: 100%;
    z-index: 1000;
    color: var(--text-primary);
    font-family: var(--font-mono);
}
#blazor-error-ui .dismiss { 
    cursor: pointer; 
    position: absolute; 
    right: var(--spacing-md); 
    top: var(--spacing-md); 
    color: var(--text-primary);
}
.blazor-error-boundary {
    background: var(--color-negative);
    padding: var(--spacing-md);
    color: #fff;
    border: var(--border-width) solid var(--border-color);
}
.blazor-error-boundary::after { content: "An error has occurred."; }

/* ===== APP LAYOUT & NAVIGATION ===== */
.app-layout {
    display: flex;
    min-height: 100vh;
}

.sidebar {
    width: 250px;
    height: 100vh;
    position: fixed;
    top: 0;
    left: 0;
    z-index: 100;
    background: var(--bg-sidebar);
    border-right: var(--border-width) solid var(--border-color);
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    transition: transform 0.25s ease;
}

/* Pinned to the bottom of the sidebar, always (Docs/TODO.md F15). `margin-top: auto` and not
   `position: absolute`: a menu long enough to scroll should push these below it rather than have them
   sit on top of its last item. */
.sidebar-footer {
    margin-top: auto;
    padding: 0.75rem 0.9rem 1rem;
    border-top: var(--border-width) solid var(--border-color);
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.sidebar-footer__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    min-height: 2rem;
}

.sidebar-footer__label {
    font-size: 0.8rem;
    color: var(--text-secondary);
}

.sidebar-overlay {
    display: none;
}

.main-wrapper {
    flex: 1;
    margin-left: 250px;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

.top-header {
    position: sticky;
    top: 0;
    z-index: 50;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-md);
    padding: 0 var(--spacing-lg);
    height: var(--header-height);
    background: var(--bg-card);
    border-bottom: var(--border-width) solid var(--border-color);
}

.header-left, .header-right {
    display: flex;
    align-items: center;
    gap: var(--spacing-md);
}

/* The current page's name sat visibly above the middle of the bar. `align-items: center` centres a
   flex item's *margin* box, and this is an h1 — so it was carrying the global heading
   `margin-bottom: 16px`, and centring a box 16px taller than the text pushed the text up by half of
   that. Nothing about the bar was wrong; the heading brought spacing meant for a page body into it.

   Scoped to the bar on purpose: `.page-title` is also an h2 in the Calendar page's body, where the
   bottom margin is doing the job it was written for. */
.top-header .page-title {
    margin: 0;
}

.mobile-menu-btn {
    display: none;
    background: none;
    border: var(--border-width) solid var(--border-color);
    color: var(--text-primary);
    cursor: pointer;
    padding: var(--spacing-xs) var(--spacing-sm);
    font-family: var(--font-mono);
    text-transform: uppercase;
    font-size: 0.75rem;
}

.mobile-menu-btn:hover {
    background: var(--text-primary);
    color: var(--bg-card);
}

.theme-toggle-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: var(--control-height);
    height: var(--control-height);
    border: var(--border-width) solid var(--border-color);
    background: var(--bg-card);
    color: var(--text-primary);
    cursor: pointer;
    transition: all 0.15s;
    border-radius: var(--radius);
}

.theme-toggle-btn:hover {
    background: var(--text-primary);
    color: var(--bg-card);
}

.user-badge {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
    height: var(--control-height);
    padding: 0 var(--spacing-sm);
    border: var(--border-width) solid var(--border-color);
    background: var(--bg-card);
    color: var(--text-primary);
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    white-space: nowrap;
}

/* The two buttons the header ends with. Both classes were written into MainLayout and defined
   nowhere, so logout rendered as a bare user-agent <button> — grey bevel, system font, its own idea
   of a size — sitting between two controls this stylesheet had drawn. It did not look misplaced by
   accident; it was the only thing in the row the design had never been applied to.

   Same box as .user-badge and .theme-toggle-btn beside them, so the row reads as one set of
   controls. */
.btn-header {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-sm);
    height: var(--control-height);
    padding: 0 var(--spacing-sm);
    border: var(--border-width) solid var(--border-color);
    background: var(--bg-card);
    color: var(--text-primary);
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    font-weight: 600;
    text-transform: uppercase;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    transition: all 0.15s;
}

.btn-header:hover {
    background: var(--text-primary);
    color: var(--bg-card);
    text-decoration: none;
}

/* Logout. Outlined rather than filled: it is the one destructive control in a row of harmless ones,
   and a solid red block in the corner of every page reads as an alarm rather than as a way out. */
.btn-header--danger {
    border-color: var(--color-negative);
    color: var(--color-negative);
}

.btn-header--danger:hover {
    background: var(--color-negative);
    border-color: var(--color-negative);
    color: #fff;
}

/* What a signed-out visitor sees in the same corner — also used and never defined. Filled, because
   here it is the one thing on the page we are asking them to do. */
.btn-new-txn {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-sm);
    height: var(--control-height);
    padding: 0 var(--spacing-md);
    border: var(--border-width) solid var(--border-color);
    background: var(--accent);
    color: #fff;
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    font-weight: 600;
    text-transform: uppercase;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    transition: all 0.15s;
}

.btn-new-txn:hover {
    background: var(--accent-hover);
    color: #fff;
    text-decoration: none;
}

/* Height rather than vertical padding, and the two are not interchangeable here. Padding made the box
   as tall as whatever it happened to contain — 16 + a 32px icon + 16, plus its own 2px border, which
   is 66 against the bar's 64. `box-sizing: border-box` is already global, so the border is inside the
   64 and the two rules end on the same pixel. `flex: none` keeps the sidebar's column layout from
   compressing it when the menu is long. */
.nav-brand {
    display: flex;
    flex: none;
    align-items: center;
    gap: var(--spacing-sm);
    height: var(--header-height);
    padding: 0 var(--spacing-lg);
    border-bottom: var(--border-width) solid var(--border-color);
    color: var(--text-primary);
    text-decoration: none;
}
.nav-brand:hover {
    text-decoration: none;
}

.brand-icon {
    width: 32px;
    height: 32px;
    background: var(--text-primary);
    color: var(--bg-card);
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-mono);
    font-weight: bold;
}

.brand-text {
    font-size: 1rem;
    font-weight: 700;
    text-transform: uppercase;
}

.nav-menu {
    display: flex;
    flex-direction: column;
    padding: var(--spacing-md);
    gap: var(--spacing-xs);
}

.nav-item-wrap .nav-link {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
    padding: var(--spacing-sm) var(--spacing-md);
    color: var(--text-primary);
    font-size: 0.875rem;
    font-weight: 500;
    text-decoration: none;
    border: var(--border-width) solid transparent;
}

.nav-item-wrap .nav-link:hover {
    border-color: var(--border-color);
    background: var(--bg-hover);
}

.nav-item-wrap .nav-link.active {
    border-color: var(--accent);
    background: var(--accent-light);
    color: var(--accent);
    font-weight: 700;
}

/* A group header. It is a <button>, so it needs the typography stated for the same reason `.btn` does
   — see the note there — and `width: 100%` because a button shrink-wraps its text where the NavLink
   beside it fills the sidebar, which would leave the chevron floating mid-menu. */
.nav-item-wrap .nav-link--group {
    width: 100%;
    background: none;
    font-family: inherit;
    font-size: 0.875rem;
    line-height: 1.5;
    text-align: left;
    cursor: pointer;
}

/* Turns to point down when the group is open, so the control says which way it will go. */
.nav-chevron {
    width: 16px;
    height: 16px;
    margin-left: auto;
    transform: rotate(-90deg);
    transition: transform 0.15s;
}

.nav-link--open .nav-chevron {
    transform: rotate(0deg);
}

/* The rule is the whole indent: a left border traces the group's extent, so it is visible where the
   children begin and end rather than being inferred from how far the text has moved. */
.nav-children {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-xs);
    margin: var(--spacing-xs) 0 var(--spacing-xs) var(--spacing-md);
    padding-left: var(--spacing-sm);
    border-left: var(--border-width) solid var(--border-light);
}

.main-content {
    flex: 1;
    padding: var(--spacing-xl);
}

/* `.main-wrapper` is a min-height:100vh column and `.main-content` takes `flex: 1`, so on a short page
   the footer is pushed to the bottom of the viewport rather than floating under the last paragraph —
   and on a long one it stays below the content instead of pinning itself over it. */
.app-footer {
    padding: var(--spacing-xl);
    border-top: var(--border-width) solid var(--border-color);
    background: var(--bg-card);
    color: var(--text-secondary);
    font-family: var(--font-mono);
    font-size: 0.75rem;
}

/* auto-fit and minmax rather than a column count, so the four columns become two and then one on the
   way down to a phone without a media query deciding where. 180px is the width at which the longest
   label here — "Earnings Calendar" — stops wrapping. */
.app-footer__columns {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--spacing-lg);
}

/* Wider than the link columns, because it holds a sentence and they hold single words. */
.app-footer__brand {
    grid-column: span 2;
    max-width: 40ch;
}

.app-footer__wordmark {
    display: block;
    font-size: 1rem;
    font-weight: 400;
    text-transform: uppercase;
    color: var(--text-primary);
    margin-bottom: var(--spacing-sm);
}

.app-footer__wordmark strong {
    font-weight: 700;
    color: var(--accent);
}

.app-footer__tagline {
    margin: 0;
    line-height: 1.6;
}

.app-footer__group {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--spacing-sm);
}

/* An h2 for the outline, reset because the global heading rule is written for page bodies and would
   put 16px under a four-word label in a link list. */
.app-footer__heading {
    margin: 0;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-primary);
}

.app-footer__group a {
    color: var(--text-secondary);
}

.app-footer__group a:hover {
    color: var(--accent);
}

.app-footer__baseline {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: var(--spacing-sm) var(--spacing-md);
    margin-top: var(--spacing-xl);
    padding-top: var(--spacing-md);
    border-top: var(--border-width) solid var(--border-light);
}

/* ===== Phone navigation =====================================================================
   Hidden above the breakpoint, where the sidebar is permanently visible and a second copy of the
   same links would be noise. Everything below lives inside the existing 768px query rather than a
   new one, so there is one place that decides what "a phone" means. */
.bottom-tabs { display: none; }

@media (max-width: 768px) {
    .sidebar { transform: translateX(-100%); }
    .sidebar.sidebar--open { transform: translateX(0); }
    .sidebar-overlay { display: block; position: fixed; inset: 0; z-index: 90; background: rgba(0, 0, 0, 0.4); }
    .main-wrapper { margin-left: 0; }
    .mobile-menu-btn { display: block; }
    .main-content { padding: var(--spacing-md); }
    .btn-text-hide { display: none; }

    .bottom-tabs {
        display: flex;
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 95;
        background: var(--bg-sidebar);
        border-top: var(--border-width) solid var(--border-color);
        /* The home indicator on a modern iPhone sits over the last few pixels of the viewport, so a
           bar flush to the bottom puts its labels underneath it. */
        padding-bottom: env(safe-area-inset-bottom, 0);
    }

    .bottom-tab {
        flex: 1 1 0;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 2px;
        /* 52px, not the 44 usually quoted as the minimum: a thumb reaching the bottom of a phone is
           less accurate than a finger on a tablet, and this row is the one people hit most. */
        min-height: 52px;
        padding: 6px 2px;
        border: 0;
        background: none;
        color: var(--text-secondary);
        text-decoration: none;
        font: inherit;
        cursor: pointer;
    }

    .bottom-tab.active { color: var(--accent); }

    .bottom-tab__label {
        font-size: 0.65rem;
        line-height: 1;
        max-width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* Room for the bar, so the last row of a table or the final button is reachable rather than
       sitting permanently underneath the navigation. It moved from .main-content to the footer when
       the footer was added: the clearance belongs on whatever is last on the page, and leaving it on
       the content would have put a tab bar over the legal links while opening a gap above them. */
    .app-footer {
        padding: var(--spacing-lg) var(--spacing-md)
                 calc(52px + env(safe-area-inset-bottom, 0px) + var(--spacing-md));
    }

    /* ===== Fluid content ====================================================================
       A table with eight columns cannot become narrow, so it scrolls inside its own box instead of
       widening the page — a body that scrolls sideways moves the navigation off screen with it. */
    .table-responsive, .card .table { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }
    .table { font-size: 0.8rem; }
    .table th, .table td { white-space: nowrap; }

    /* Anything laid out as fixed columns collapses to one. */
    .row, .form-row { flex-direction: column; }

    /* Touch targets, and inputs at 16px so iOS stops zooming the page when one is focused. */
    .btn { min-height: 44px; }
    input, select, textarea { font-size: 16px; }
}

/* ===== NEW DESIGN SYSTEM COMPONENTS (Phase 2+) ===== */
.dialog-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.8);
    z-index: 1050;
    display: flex;
    align-items: center;
    justify-content: center;
}

.dialog {
    background: var(--bg-card);
    border: var(--border-width) solid var(--border-color);
    padding: var(--spacing-lg);
    width: 100%;
    max-width: 400px;
}

.dialog h3 {
    margin-top: 0;
    font-family: var(--font-mono);
    text-transform: uppercase;
}

.dialog-actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--spacing-md);
    margin-top: var(--spacing-xl);
}

.toast-container-box {
    position: fixed;
    top: var(--spacing-lg);
    right: var(--spacing-lg);
    z-index: 1100;
    display: flex;
    flex-direction: column;
    gap: var(--spacing-sm);
}

.toast {
    background: var(--bg-card);
    border: var(--border-width) solid var(--border-color);
    padding: var(--spacing-md) var(--spacing-lg);
    min-width: 300px;
    box-shadow: 4px 4px 0 var(--border-color);
    position: relative;
    overflow: hidden;
    animation: slideIn 0.2s ease-out;
}

.toast--success { border-left: 8px solid var(--color-positive); }
.toast--error { border-left: 8px solid var(--color-negative); }
.toast--warning { border-left: 8px solid var(--color-warning); }
.toast--info { border-left: 8px solid var(--color-info); }

.toast-timer {
    position: absolute;
    bottom: 0;
    left: 0;
    height: 4px;
    background: var(--text-primary);
    animation: shrinkTimer 4s linear forwards;
}
.toast--success .toast-timer { background: var(--color-positive); }
.toast--error .toast-timer { background: var(--color-negative); }
.toast--warning .toast-timer { background: var(--color-warning); }

@keyframes slideIn {
    from { transform: translateX(100%); }
    to { transform: translateX(0); }
}
@keyframes shrinkTimer {
    from { width: 100%; }
    to { width: 0%; }
}

.skeleton-row {
    height: 20px;
    background: var(--border-light);
    margin-bottom: 8px;
    animation: pulse 1.5s infinite alternate;
}
@keyframes pulse {
    0% { opacity: 0.6; }
    100% { opacity: 1; }
}

/* Custom Dropdown adjustments */
.custom-dropdown-container { position: relative; z-index: 60; }
.custom-dropdown-selected {
    display: flex; align-items: center; gap: 8px;
    padding: 6px 10px; border: var(--border-width) solid var(--border-color);
    background: var(--bg-card); color: var(--text-primary);
    font-size: 0.8125rem; font-weight: 500; cursor: pointer;
    height: var(--control-height); user-select: none;
}
.custom-dropdown-selected:hover { background: var(--bg-hover); }
.custom-dropdown-container.open .custom-dropdown-selected { border-color: var(--accent); }
.custom-dropdown-chevron { width: 16px; height: 16px; color: var(--text-primary); }
.custom-dropdown-options {
    position: absolute; top: calc(100% + 4px); right: 0; min-width: 130px;
    background: var(--bg-card); border: var(--border-width) solid var(--border-color);
    padding: 4px; display: flex; flex-direction: column; gap: 2px;
}
.custom-dropdown-option { padding: 8px 12px; cursor: pointer; font-size: 0.8125rem; color: var(--text-primary); }
.custom-dropdown-option:hover { background: var(--bg-hover); }
.custom-dropdown-option.selected { background: var(--accent); color: var(--accent-contrast); }

/* Opens upwards. Without this the control is unusable anywhere near the bottom of the viewport: the
   list is positioned below it and simply leaves the screen. */
.custom-dropdown-options--up { top: auto; bottom: calc(100% + 4px); }
.custom-dropdown-container--up .custom-dropdown-chevron { transform: rotate(180deg); }

.kpi-hero-section {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-xl);
    margin-bottom: var(--spacing-2xl);
    padding: var(--spacing-xl) 0;
}
.kpi-primary-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-2xl);
    justify-content: space-around;
}
.kpi-secondary-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-lg);
    justify-content: space-around;
    padding-top: var(--spacing-lg);
}
.kpi-data-block {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--spacing-sm);
}
.kpi-block-label {
    font-weight: 700;
    font-size: 1.5rem;
    color: var(--text-primary);
}
.kpi-block-value-wrap {
    display: flex;
    align-items: baseline;
    gap: var(--spacing-xs);
}
.kpi-block-value {
    font-family: var(--font-mono);
    font-size: 1.75rem;
    font-weight: 700;
    color: var(--text-primary);
}
.kpi-block-currency {
    font-size: 1rem;
    color: var(--text-secondary);
}

.kpi-data-block--small .kpi-block-label {
    font-size: 1rem;
}
.kpi-data-block--small .kpi-block-value {
    font-size: 1.25rem;
}

.filter-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--spacing-md); margin-bottom: var(--spacing-lg); }
.filter-left, .filter-right { display: flex; flex-wrap: wrap; gap: var(--spacing-md); align-items: center; }

/* The dashboard's currency picker, which was a bare operating-system dropdown in the middle of a page
   with square corners and a 2px black rule around everything: rounded, bevelled, system font, native
   arrow. Not because anybody chose that — `.filter-control`, `.filter-label` and `.filter-select` were
   written into the markup and defined nowhere, so the browser's own idea of a <select> was all there
   was. Same defect as the logout button in b0e4322.

   Still a real <select>. A div pretending to be one loses the keyboard behaviour for free, and on a
   phone it gives up the OS picker — which is the better control on a touch screen, not a compromise.
   So the box is restyled and the element is left alone. */
.filter-control {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
}

/* 0.875rem to match the toggle labels it shares the row with — .toggle-switch sets that on itself and
   .toggle-text inherits it, so this is the number that makes the row one size rather than a new one. */
.filter-label {
    font-family: var(--font-mono);
    font-size: 0.875rem;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--text-secondary);
    white-space: nowrap;
}

.filter-select {
    height: var(--control-height);
    padding: 0 calc(var(--spacing-lg) + var(--spacing-xs)) 0 var(--spacing-sm);
    border: var(--border-width) solid var(--border-color);
    border-radius: var(--radius);
    background: var(--bg-card);
    color: var(--text-primary);
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    font-weight: 600;
    cursor: pointer;

    /* The native arrow is the last part that still looks like the operating system, and it cannot be
       styled — so it is removed and redrawn as the same chevron the language dropdown in the header
       uses. Inline SVG rather than a file: it is four lines, and it has to follow currentColor
       through the theme switch. `appearance: none` also drops the bevel on Safari. */
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='%23666666'%3E%3Cpath fill-rule='evenodd' d='M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z' clip-rule='evenodd'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right var(--spacing-sm) center;
    background-size: 16px 16px;
}

.filter-select:hover { background-color: var(--bg-hover); }
.filter-select:focus { outline: none; border-color: var(--accent); }

/* A data URI cannot read a custom property, so the arrow's colour is baked in and the dark theme
   needs its own copy. Both are --text-secondary; if that token moves, these move with it by hand. */
[data-theme="dark"] .filter-select {
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='%23999999'%3E%3Cpath fill-rule='evenodd' d='M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z' clip-rule='evenodd'/%3E%3C/svg%3E");
}

/* .toggle-text needs no rule of its own: .toggle-switch already sets the font, size and casing on the
   label that wraps it, and the span inherits all three. It is in the "used but never defined" list
   only because nothing declares it by name. */
/* `width: fit-content` is not cosmetic here. This control draws its dividers by letting its own
   background show through the gaps, so any width beyond the pills is painted in --border-color and
   reads as a black offcut hanging off the end. Hugging the content makes that impossible. */
.segment-control { display: flex; width: fit-content; gap: var(--border-width); border: var(--border-width) solid var(--border-color); background: var(--border-color); }
.segment-pill { padding: 4px 12px; background: var(--bg-card); color: var(--text-primary); border: none; font-weight: 600; cursor: pointer; }
/* The accent, not --text-primary. In both themes --text-primary and --border-color are the *same*
   value (#1A1A1A light, #F0F0F0 dark), and .segment-control paints its own border and the gaps between
   pills with --border-color — so a selected pill was drawn in exactly the colour of the frame holding
   it and read as merged with it rather than as chosen.

   The accent is already this interface's word for "on": .toggle-slider::after uses it when checked. */
.segment-pill--active { background: var(--accent); color: var(--accent-contrast); }

/* Wrapping needs a different mechanism, not just `flex-wrap`. `.segment-control` draws the lines
   between pills by showing its own background through one-pixel gaps — which works exactly as long as
   the pills fill the row. The moment they wrap, the unused end of every row shows that background as a
   black block, and the control looks like it has offcuts stuck to it.

   So this variant stops painting the container at all and gives each pill its own outline, with a gap
   wide enough to read as separate chips rather than as a broken strip. */
.segment-control--wrap {
    flex-wrap: wrap;
    gap: 0.35rem;
    background: transparent;
    border: none;
}

.segment-control--wrap .segment-pill {
    border: var(--border-width) solid var(--border-color);
}

.segment-control--wrap .segment-pill--active {
    border-color: var(--accent);
}

/* A pill that cannot be clicked says so. Two of them exist by design — the always-shown indicators on
   /account/dashboard — and without this they are indistinguishable from the ones that respond. */
.segment-pill:disabled { cursor: default; opacity: 0.55; }
.segment-pill--active:disabled { opacity: 0.75; }
.toggle-switch { display: flex; align-items: center; gap: var(--spacing-sm); cursor: pointer; font-family: var(--font-mono); font-size: 0.875rem; text-transform: uppercase; }
.toggle-switch input[type="checkbox"] { display: none; }
.toggle-slider { width: 32px; height: 16px; border: var(--border-width) solid var(--border-color); background: var(--bg-card); position: relative; }
.toggle-slider::after { content: ''; position: absolute; width: 12px; height: 12px; background: var(--text-primary); top: 0; left: 0; transition: transform 0.2s; }
.toggle-switch input:checked + .toggle-slider::after { transform: translateX(16px); background: var(--accent); }

.chart-card { border: var(--border-width) solid var(--border-color); padding: var(--spacing-lg); margin-bottom: var(--spacing-lg); background: var(--bg-card); }
.chart-container { width: 100%; min-height: 400px; }
.chart-container { position: relative; }

/* Sits over the chart during a refetch instead of replacing it, so the JavaScript chart instance is
   never torn down and rebuilt mid-initialisation (l1-defect-log #26). */
.chart-loading--overlay { position: absolute; inset: 0; height: auto; z-index: 2;
    background: color-mix(in srgb, var(--color-surface, #fff) 60%, transparent); }

.chart-loading, .chart-empty, .chart-error { display: flex; align-items: center; justify-content: center; height: 200px; font-family: var(--font-mono); text-align: center; padding: 0 var(--spacing-md); }
.chart-empty, .chart-error { max-width: 60ch; margin: 0 auto; height: auto; min-height: 200px; line-height: 1.6; }
.chart-error { color: var(--color-negative); }
.spinner { width: 32px; height: 32px; border: 4px solid var(--text-primary); border-top-color: transparent; animation: spin 1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

.quick-actions-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--spacing-md); margin-bottom: var(--spacing-lg); }
.quick-action-card { border: var(--border-width) solid var(--border-color); padding: var(--spacing-lg); text-align: center; color: var(--text-primary); text-decoration: none; display: flex; flex-direction: column; align-items: center; gap: var(--spacing-sm); }
.quick-action-card:hover { background: var(--bg-hover); color: var(--text-primary); text-decoration: none; border-color: var(--accent); }
.quick-action-icon { width: 48px; height: 48px; border: var(--border-width) solid var(--border-color); display: flex; align-items: center; justify-content: center; font-size: 1.5rem; font-family: var(--font-mono); }
.quick-action-title { font-weight: 700; text-transform: uppercase; }
.quick-action-desc { font-size: 0.875rem; color: var(--text-secondary); }

.breakdown-panel { margin-top: var(--spacing-md); border: var(--border-width) solid var(--border-color); background: var(--bg-card); }
.breakdown-header { display: flex; justify-content: space-between; padding: var(--spacing-sm) var(--spacing-md); border-bottom: var(--border-width) solid var(--border-color); }
.breakdown-table { width: 100%; border-collapse: collapse; font-family: var(--font-mono); font-size: 0.875rem; }
.breakdown-table th, .breakdown-table td { padding: var(--spacing-sm); border-bottom: var(--border-width) solid var(--border-light); text-align: left; }
.breakdown-close { background: none; border: none; cursor: pointer; font-size: 1.2rem; font-weight: bold; color: var(--text-primary); }


/* ===== BRUTALIST UI UTILITY CLASSES ===== */
/* These semantic utility classes (spacing, grids, buttons) power the UI layouts across the application. */
.container { width: 100%; max-width: 1200px; margin: 0 auto; padding: 0 var(--spacing-md); }
.row { display: flex; flex-wrap: wrap; margin-left: calc(var(--spacing-md) * -0.5); margin-right: calc(var(--spacing-md) * -0.5); }
.row > [class^="col-"] { padding-left: calc(var(--spacing-md) * 0.5); padding-right: calc(var(--spacing-md) * 0.5); width: 100%; }
@media (min-width: 768px) {
    .col-md-2 { width: 16.666667%; }
    .col-md-4 { width: 33.333333%; }
    .col-md-5 { width: 41.666667%; }
    .col-md-6 { width: 50%; }
    .col-md-8 { width: 66.666667%; }
}
@media (min-width: 992px) {
    .col-lg-6 { width: 50%; }
}
.d-flex { display: flex; }
.d-block { display: block; }
.justify-content-between { justify-content: space-between; }
.justify-content-center { justify-content: center; }
.align-items-center { align-items: center; }
.align-items-end { align-items: flex-end; }
.flex-wrap { flex-wrap: wrap; }
.gap-3 { gap: var(--spacing-md) !important; }
.g-2 { gap: var(--spacing-sm) !important; }
/* Asked for by four pages and defined by none of them until 2026-08-27, so the plan cards on /pricing
   sat flush against each other — a gutter class that silently does nothing looks exactly like a layout
   with no gutter, which is what it is. Sized like .g-2 above it, one step of the spacing scale up.
   `gap` covers both axes, which is what the stacked case needs: on a phone .row becomes a column and
   the horizontal padding on .col-* does nothing at all. */
.g-3 { gap: var(--spacing-md) !important; }

.mx-auto { margin-left: auto !important; margin-right: auto !important; }
.mb-0 { margin-bottom: 0 !important; }
.mb-1 { margin-bottom: var(--spacing-xs) !important; }
.mb-2 { margin-bottom: var(--spacing-sm) !important; }
.mb-3 { margin-bottom: var(--spacing-md) !important; }
.mb-4 { margin-bottom: var(--spacing-lg) !important; }
.mt-1 { margin-top: var(--spacing-xs) !important; }
.mt-2 { margin-top: var(--spacing-sm) !important; }
.mt-3 { margin-top: var(--spacing-md) !important; }
.mt-4 { margin-top: var(--spacing-lg) !important; }
.mt-5 { margin-top: var(--spacing-xl) !important; }
.me-1 { margin-right: var(--spacing-xs) !important; }
.me-2 { margin-right: var(--spacing-sm) !important; }
.ms-2 { margin-left: var(--spacing-sm) !important; }
.p-0 { padding: 0 !important; }
.p-3 { padding: var(--spacing-md) !important; }
.p-4 { padding: var(--spacing-lg) !important; }
.p-5 { padding: var(--spacing-xl) !important; }
.px-4 { padding-left: var(--spacing-lg) !important; padding-right: var(--spacing-lg) !important; }
.pb-3 { padding-bottom: var(--spacing-md) !important; }
.pt-4 { padding-top: var(--spacing-lg) !important; }
.ps-2 { padding-left: var(--spacing-sm) !important; }
.py-4 { padding-top: var(--spacing-lg) !important; padding-bottom: var(--spacing-lg) !important; }
.py-5 { padding-top: var(--spacing-xl) !important; padding-bottom: var(--spacing-xl) !important; }
.h-100 { height: 100% !important; }
.w-100 { width: 100% !important; }
.position-relative { position: relative !important; }

/* Cards */
.card, .card-modern {
    background: var(--bg-card);
    border: var(--border-width) solid var(--border-color);
    display: flex;
    flex-direction: column;
}
.card-header {
    background: var(--bg-hover);
    border-bottom: var(--border-width) solid var(--border-color);
    padding: var(--spacing-md);
    font-weight: bold;
    text-transform: uppercase;
}
.card-body { padding: var(--spacing-md); flex: 1; }
.card-title { margin-bottom: var(--spacing-sm); font-size: 1.25rem; font-weight: 700; }
.card-text { margin-bottom: var(--spacing-md); }

/* Buttons */

/* A <button> does not inherit the page's font the way an <a> does: the user-agent sheet gives it a
   `font` shorthand of its own, which resets font-size to about 13.3px and line-height to `normal`.
   This rule used to name font-family and font-weight but neither of those two, so `.btn` on a button
   measured 13.3px/normal and the identical `.btn` on a link measured 16px/1.5 — a nine-pixel height
   difference between Save and Cancel where they sit side by side on the transaction form. Both are
   stated here, so the class decides the size rather than the element type.

   inline-flex for the same reason in the other direction: with inline-block, the 44px touch minimum
   the phone breakpoint sets pushed the label to the top of the box instead of centring it. */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--spacing-sm);
    vertical-align: middle;
    padding: 8px 16px;
    font-family: var(--font-mono);
    font-size: 0.875rem;
    line-height: 1.5;
    font-weight: bold;
    text-transform: uppercase;
    text-align: center;
    border: var(--border-width) solid var(--border-color);
    background: var(--bg-card);
    color: var(--text-primary);
    cursor: pointer;
    transition: all 0.15s;
    text-decoration: none;
}
.btn:hover { background: var(--text-primary); color: var(--bg-card); text-decoration: none; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
.btn-primary { background: var(--accent); color: #fff; border-color: var(--border-color); }
.btn-primary:hover { background: var(--accent-hover); color: #fff; border-color: var(--border-color); }
.btn-success { background: var(--color-positive); color: #fff; border-color: var(--border-color); }
.btn-success:hover { background: #009944; color: #fff; border-color: var(--border-color); }
.btn-secondary { background: var(--border-light); color: var(--text-primary); }
.btn-danger { background: var(--color-negative); color: #fff; border-color: var(--border-color); }
.btn-danger:hover { background: #E60000; color: #fff; border-color: var(--border-color); }
.btn-outline-primary { color: var(--accent); border-color: var(--accent); }
.btn-outline-primary:hover { background: var(--accent); color: #fff; }
.btn-outline-secondary { color: var(--text-primary); border-color: var(--text-primary); }
.btn-outline-secondary:hover { background: var(--text-primary); color: var(--bg-card); }
.btn-outline-info { color: var(--color-info); border-color: var(--color-info); }
.btn-outline-info:hover { background: var(--color-info); color: #fff; }
.btn-outline-danger { color: var(--color-negative); border-color: var(--color-negative); }
.btn-outline-danger:hover { background: var(--color-negative); color: #fff; }
.btn-sm { padding: 4px 8px; font-size: 0.75rem; }
.btn-lg { padding: 12px 24px; font-size: 1.125rem; }
.btn-close { 
    background: transparent; border: none; font-size: 1.25rem; font-weight: bold; 
    color: var(--text-primary); cursor: pointer; opacity: 0.5; padding: 0;
}
.btn-close::before { content: "X"; }
.btn-close:hover { opacity: 1; }

/* Tables */
.table { width: 100%; border-collapse: collapse; margin-bottom: var(--spacing-md); font-family: var(--font-mono); font-size: 0.875rem; }
.table th, .table td { padding: var(--spacing-sm); border-bottom: var(--border-width) solid var(--border-color); text-align: left; }
.table th { font-weight: bold; text-transform: uppercase; background: var(--bg-hover); color: var(--text-primary); border-bottom: calc(var(--border-width) * 2) solid var(--border-color); }
.table-responsive { overflow-x: auto; }
.table-striped tbody tr:nth-of-type(odd) { background-color: var(--bg-app); }
.table-hover tbody tr:hover { background-color: var(--bg-hover); }
.table-dark { background-color: var(--text-primary); color: var(--bg-card); }
.table-dark th { background-color: var(--text-primary); color: var(--bg-card); border-color: var(--bg-card); }
.table-sm th, .table-sm td { padding: 4px; }
.table-warning { background-color: rgba(204, 119, 0, 0.1); }

/* Forms */
.form-label { display: inline-block; margin-bottom: var(--spacing-xs); font-weight: bold; font-family: var(--font-mono); text-transform: uppercase; font-size: 0.875rem; }
.form-control, .form-select { 
    display: block; width: 100%; padding: 8px 12px; font-size: 1rem; 
    font-family: var(--font-mono); color: var(--text-primary); 
    background-color: var(--bg-input); border: var(--border-width) solid var(--border-color); 
}
.form-control:focus, .form-select:focus { outline: none; border-color: var(--accent); }
.form-select-sm { padding: 4px 8px; font-size: 0.875rem; }
/* Top-aligned rather than centred: a consent label long enough to wrap would otherwise put the box
   halfway down its own paragraph, which reads as belonging to the second line. */
.form-check { display: flex; align-items: flex-start; gap: var(--spacing-sm); margin-bottom: var(--spacing-sm); }
.form-check-input {
    /* Nudged down so the box sits on the first line's text rather than above it. */
    margin-top: 0.15rem;
    width: 16px; height: 16px; border: var(--border-width) solid var(--border-color);
    background-color: var(--bg-input); cursor: pointer; appearance: none;

    /* In a flex row a fixed width is only a starting size: the item may still be squeezed below it.
       This box was the sole shrinkable thing on the line, so the longest label in the application --
       the investment-disclaimer consent on the registration page -- pressed the square into a
       rectangle, while its two shorter siblings above it stayed square. Nothing about the checkbox
       differed; the text beside it did. */
    flex-shrink: 0;
}
.form-check-input:checked { background-color: var(--accent); border-color: var(--border-color); }
.form-check-label { font-weight: normal; cursor: pointer; }
.input-group { display: flex; width: 100%; }
.input-group > * { border-radius: 0; margin-left: calc(var(--border-width) * -1); }
.input-group > *:first-child { margin-left: 0; }
.input-group-text { padding: 8px 12px; background-color: var(--bg-hover); border: var(--border-width) solid var(--border-color); font-family: var(--font-mono); }
.input-group-sm > .form-control, .input-group-sm > .input-group-text, .input-group-sm > .btn { padding: 4px 8px; font-size: 0.875rem; }

/* Alerts */
.alert { padding: var(--spacing-md); margin-bottom: var(--spacing-md); border: var(--border-width) solid var(--border-color); font-family: var(--font-mono); }
.alert-danger { background-color: rgba(204, 0, 0, 0.1); border-left: 8px solid var(--color-negative); }
.alert-success { background-color: rgba(0, 122, 51, 0.1); border-left: 8px solid var(--color-positive); }
.alert-warning { background-color: rgba(204, 119, 0, 0.1); border-left: 8px solid var(--color-warning); }
.alert-info { background-color: rgba(0, 85, 255, 0.1); border-left: 8px solid var(--color-info); }
.alert-dismissible { display: flex; justify-content: space-between; align-items: center; }

/* Badges */
.badge { display: inline-block; padding: 4px 8px; font-family: var(--font-mono); font-size: 0.75rem; font-weight: bold; text-transform: uppercase; border: 1px solid var(--border-color); background: var(--bg-card); color: var(--text-primary); }
.bg-success { background-color: var(--color-positive) !important; color: #fff !important; }
.bg-danger { background-color: var(--color-negative) !important; color: #fff !important; }
.bg-secondary { background-color: var(--border-light) !important; color: var(--text-primary) !important; }
.bg-info { background-color: var(--color-info) !important; color: #fff !important; }
.bg-warning { background-color: var(--color-warning) !important; color: #fff !important; }
.bg-white { background-color: var(--bg-card) !important; }
.bg-light { background-color: var(--bg-hover) !important; }
.bg-surface { background-color: var(--bg-card) !important; }

/* Typography */
.text-center { text-align: center !important; }
.text-end { text-align: right !important; }
.text-muted { color: var(--text-secondary) !important; }
.text-danger { color: var(--color-negative) !important; }
.text-success { color: var(--color-positive) !important; }
.text-warning { color: var(--color-warning) !important; }
.text-break { word-wrap: break-word !important; }
.text-dark, .text-foreground, .text-primary { color: var(--text-primary) !important; }
.text-decoration-none { text-decoration: none !important; }
.fw-bold { font-weight: 700 !important; }
.fw-semibold { font-weight: 600 !important; }
.fs-6 { font-size: 1rem !important; }
.small { font-size: 0.875rem !important; }
.lead { font-size: 1.25rem !important; font-weight: 300; }

/* Spinners */
.spinner-border { display: inline-block; width: 2rem; height: 2rem; vertical-align: text-bottom; border: .25em solid currentColor; border-right-color: transparent; border-radius: 50%; animation: spinner-border .75s linear infinite; }
.spinner-border-sm { width: 1rem; height: 1rem; border-width: .2em; }
@keyframes spinner-border { to { transform: rotate(360deg); } }
.visually-hidden { position: absolute !important; width: 1px !important; height: 1px !important; padding: 0 !important; margin: -1px !important; overflow: hidden !important; clip: rect(0,0,0,0) !important; white-space: nowrap !important; border: 0 !important; }

/* Other */
.shadow, .shadow-sm { box-shadow: none !important; }
.rounded-3 { border-radius: 0 !important; }
.border-bottom { border-bottom: var(--border-width) solid var(--border-color) !important; }
.border-secondary { border-color: var(--border-color) !important; }
.border-danger { border-color: var(--color-negative) !important; }
.border-warning { border-color: var(--color-warning) !important; }
.border-success { border-color: var(--color-positive) !important; }
.border-start { border-left: var(--border-width) solid var(--border-color) !important; }
.border-3 { border-width: calc(var(--border-width) * 1.5) !important; }

/* Form Validations */
.valid.modified:not([type=checkbox]) { border-color: var(--color-positive); }
.invalid { border-color: var(--color-negative); }
.validation-message { color: var(--color-negative); font-size: 0.875rem; font-family: var(--font-mono); margin-top: 4px; }

/* ── Subscription state in the header (2026-08-19) ─────────────────────────────────────────────
   The badge accents itself rather than growing a pill beside it. The header row is already four
   controls wide and adds a credit counter below; a fifth element would push the identity off a
   narrow viewport, which is the one thing in that row nobody can afford to lose.

   Marking, never hiding — the same rule EntitlementAvailability states. A free account gets the
   ordinary badge, not a diminished one: "you are not paying" is not a status worth styling. */
.user-badge--subscribed {
    border-color: var(--accent-primary, currentColor);
    box-shadow: inset 0 0 0 1px var(--accent-primary, currentColor);
}

.user-badge__tier-mark {
    color: var(--accent-primary, currentColor);
    flex-shrink: 0;
}

/* The credit counter. Same box as its neighbours so the row stays one set of controls, and a link
   rather than a label because a number somebody is watching go down should be one click from the
   page that explains it and the page that tops it up. */
.credit-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-sm);
    height: var(--control-height);
    padding: 0 var(--spacing-sm);
    border: var(--border-width) solid var(--border-color);
    background: var(--bg-card);
    color: var(--text-primary);
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    text-decoration: none;
    white-space: nowrap;
    transition: all 0.15s;
}

.credit-badge:hover {
    border-color: var(--accent-primary, currentColor);
    color: var(--text-primary);
}

.credit-badge__count {
    font-weight: 600;
}

/* Below the counter the number is the point, so the word goes first to a phone's narrow row. */
@media (max-width: 640px) {
    .credit-badge__label {
        display: none;
    }
}

/* A cell that is also a control. It has to read as text first — a table full of buttons looks like a
   form — so it carries no chrome until the pointer is on it. */
.btn-link-plain {
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    color: inherit;
    cursor: pointer;
    text-align: left;
}

.btn-link-plain:hover { text-decoration: underline; }

/* The expanded working under a tax event. It was an inline background reading
   var(--surface-2, #fafafa) — and --surface-2 is defined nowhere in this stylesheet, so it always fell
   back to near-white, including in dark mode where the text on top of it is light. Same colour as the
   font, which is what the operator saw. --bg-hover is the variable that actually exists and actually
   changes with the theme. */
.tax-working { background: var(--bg-hover); }

/* ── The chart's hover point, which ApexCharts leaves invisible on some renders ──────────────────
   With `markers.size = 0` ApexCharts draws no markers and instead puts one dynamic point per series
   inside `.apexcharts-series-markers-wrap` and moves it under the pointer. That wrap is created
   carrying `apexcharts-element-hidden` — opacity 0 — and is revealed by `showDelayedElements`, which
   runs on the render paths that animate and is skipped on the ones that do not. Which path a chart
   takes depends on the render, so the hover point appeared at some ranges and not at others.

   Measured rather than reasoned: the browser reported the value chart holding
   `wrapClass: "apexcharts-series-markers-wrap apexcharts-element-hidden", wrapOpacity: "0",
   dynamicPoints: 12, hiddenWraps: 12` while the comparison chart beside it, from the same markup, was
   `apexcharts-hidden-element-shown` at opacity 1.

   Safe because these charts ask for no markers at all: the only thing in that wrap is the hover point
   this rule exists to show. Nothing else the library hides with `apexcharts-element-hidden` — data
   labels, bar goals — is touched (Docs/l1-defect-log.md #37). */
.apexcharts-canvas .apexcharts-series-markers-wrap.apexcharts-element-hidden {
    opacity: 1;
}

/* The composition panel's own empty state — the click landed, the day simply has nothing stored. */
.breakdown-empty {
    margin: 0;
    padding: 0.75rem 0;
    color: var(--text-secondary, #64748B);
}

/* The name of the line a composition table belongs to. One per wallet when the chart draws them apart;
   a single one reading "all wallets" when it aggregates them. */
.breakdown-wallet {
    margin: 1rem 0 0.35rem;
    font-family: var(--font-mono, inherit);
    text-transform: uppercase;
    font-size: 0.8rem;
    letter-spacing: 0.04em;
    color: var(--text-secondary, #64748B);
}

.breakdown-wallet:first-of-type {
    margin-top: 0;
}
