:root {
    --ae-primary: #0da69f;
    --ae-primary-hover: #078983;
    --rz-primary: var(--ae-primary);
    --rz-primary-dark: #078983;
    --rz-primary-darker: #066d68;
    --rz-primary-light: #34bcb5;
    --rz-primary-lighter: rgba(13, 166, 159, 0.16);
    --rz-on-primary: #fff;
    --rz-on-primary-dark: #fff;
    --rz-on-primary-darker: #fff;
    --rz-on-primary-light: #fff;
    --rz-on-primary-lighter: #076f6a;

    /* Material-3 direction: larger shape + system Roboto-first stack.
       The Radzen Material themes ship Roboto in their font token; this keeps
       body text aligned without a webfont download. */
    --rz-border-radius: 12px;

    /* Every dialog's title bar. Radzen's Material themes give the title bar the same
       background as the dialog body, so a dialog reads as one flat panel with no header,
       and in dark mode its close button is black on near-black. This is the app's own
       scheme instead, applied to every dialog: the deep blue of the brand mark (#1f28db,
       sampled from brand-logo.png), which carries white text in light mode.
       Deliberately not --rz-secondary: that is not one color - #e31c65 in light and
       #01a299 in dark - where a title bar wants the same identity in both themes. */
    --ae-dialog-titlebar-bg: #1f28db;
    --ae-dialog-titlebar-fg: #ffffff;
}

/* The same blue, taken down for dark mode. At full strength it is the brightest thing on a
   dark screen, which makes every dialog read as an alert rather than as a panel - and a title
   bar only has to name the dialog and hold the close button. The hue stays the brand's, so the
   two themes are still recognisably the same application. */
:root[data-theme="dark"] {
    --ae-dialog-titlebar-bg: #2b3178;
    --ae-dialog-titlebar-fg: #e8eafb;
}


html, body {
    font-family: Roboto, 'Helvetica Neue', Helvetica, Arial, sans-serif;
    background-color: var(--rz-body-background-color, var(--rz-base-background-color));
    color: var(--rz-text-color);
}

h1:focus {
    outline: none;
}

a {
    color: var(--ae-primary-hover);
}

.content {
    padding-top: 1.1rem;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid red;
}

.validation-message {
    color: red;
}

#blazor-error-ui {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.loading-progress {
    position: relative;
    display: block;
    width: 8rem;
    height: 8rem;
    margin: 20vh auto 1rem auto;
}

    .loading-progress circle {
        fill: none;
        stroke: #e0e0e0;
        stroke-width: 0.6rem;
        transform-origin: 50% 50%;
        transform: rotate(-90deg);
    }

        .loading-progress circle:last-child {
            stroke: var(--ae-primary);
            stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
            transition: stroke-dasharray 0.05s ease-in-out;
        }

.loading-progress-text {
    position: absolute;
    text-align: center;
    font-weight: bold;
    inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
}

    .loading-progress-text:after {
        content: var(--blazor-load-percentage-text, "Loading");
    }

code {
    color: #c02d76;
}

/* -----------------------------------------------------------------------------
   Shared page chrome (used by all feature pages).
   ----------------------------------------------------------------------------- */
.page-title {
    margin: 0;
    font-size: 1.6rem;
}

.page-subtitle {
    margin: 0.25rem 0 0;
    opacity: 0.7;
}

/* A page's command bar: the row of filters and buttons that sits under, or beside, its heading.
   Defined once here rather than page by page, because it is the same rule everywhere - and because
   it has to reach inside Radzen components, where a page-scoped rule cannot go: the input is rendered
   by RadzenDatePicker or RadzenTextBox, not by our markup.

   Radzen sizes a control's text from --rz-input-font-size and --rz-label-font-size, and both default
   to the body size (1rem), where a small button is 0.75rem. Left alone, a bar therefore reads as a row
   of fields set two sizes larger than the buttons beside them. The label is in here for the same
   reason: left alone it stands a third size above the field it labels. */
.command-bar .rz-inputtext,
.command-bar .rz-dropdown-label,
.command-bar .rz-label {
    font-size: 0.875rem;
    line-height: 1.25rem;
}

.page-error {
    border-left: 4px solid #d13438;
}

/* -----------------------------------------------------------------------------
   Dialog chrome (all dialogs, both themes).
   The title bar is what makes a panel read as a dialog rather than as part of the
   page behind it, and Radzen's themes leave it the same color as the dialog body.
   This is the app's own scheme: the brand blue with white text, laid out like a
   desktop dialog - title and close button on one line, centerd in the bar.

   The colors come from --ae-dialog-titlebar-bg / -fg, set once in :root.
   ----------------------------------------------------------------------------- */
.rz-dialog-titlebar {
    display: flex;
    align-items: center;
    padding: 0.6rem 1rem;
    background-color: var(--ae-dialog-titlebar-bg);
    color: var(--ae-dialog-titlebar-fg);
}

.rz-dialog-titlebar .rz-dialog-title {
    /* Centerd against the close button rather than sitting on the bar's baseline. */
    color: inherit;
    align-self: center;
    line-height: 1.4;
}

/* The glyph is an element of its own (.rzi-times) and the theme gives it its own gray,
   which is what left the close button looking absent until it was hovered - the button
   had inherited a readable color and the icon inside it had not. Set both. */
.rz-dialog-titlebar-close,
.rz-dialog-titlebar-close .rzi,
.rz-dialog-titlebar-close i,
.rz-dialog-titlebar-close span,
.rz-dialog-titlebar-close svg {
    color: inherit;
    fill: currentColor;
}

.rz-dialog-titlebar-close:hover {
    background-color: rgba(255, 255, 255, 0.18);
}

/* -----------------------------------------------------------------------------
   Account badge + status. Defined globally because account-type badges are
   rendered on several pages (accounts, trial balance, general ledger, ...).
   ----------------------------------------------------------------------------- */
.account-badge {
    display: inline-block;
    padding: 0.15rem 0.6rem;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    white-space: nowrap;
}

.account-badge--asset { background: #e3f2fd; color: #0d47a1; }
.account-badge--liability { background: #fff3e0; color: #e65100; }
.account-badge--equity { background: #e8f5e9; color: #1b5e20; }
.account-badge--revenue { background: #ede7f6; color: #4527a0; }
.account-badge--expense { background: #fce4ec; color: #b71c1c; }

.account-status {
    font-size: 0.8rem;
    font-weight: 600;
}

.account-status.is-active { color: #107c10; }
.account-status.is-inactive { color: #8a8a8a; }

/* -----------------------------------------------------------------------------
   Radzen dialogs render in a portal outside page components, so every style
   used inside a dialog is global (page-scoped CSS cannot reach them).
   ----------------------------------------------------------------------------- */
.dialog-error {
    padding: 0.5rem 0.75rem;
    border-radius: 4px;
    border-left: 4px solid #d13438;
    background: #fdecea;
    color: #b71c1c;
}

.gj-lines-list {
    max-height: 320px;
    overflow-y: auto;
}

.gj-totals {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}

.gj-totals.is-unbalanced {
    color: #d13438;
}

.gj-footer-number {
    display: block;
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.gj-lines-grid {
    max-height: 320px;
}

.gj-lines-grid .rz-data-grid-data td {
    vertical-align: top;
}

.gj-amount-input input,
.gj-amount-input .rz-inputtext {
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.source-tx-amounts-list {
    max-height: 320px;
    overflow-y: auto;
}

.source-tx-hint {
    margin: 0;
    font-size: 0.8rem;
    opacity: 0.7;
}

.source-rule-lines-list {
    max-height: 320px;
    overflow-y: auto;
}

.source-rule-line {
    padding: 0.25rem 0;
}

.source-rule-lines-empty {
    opacity: 0.7;
    margin: 0;
    font-size: 0.85rem;
}

/* -----------------------------------------------------------------------------
   Financial statements: one section block per statement section (e.g. "Current
   Assets"). A block is a heading with its subtotal followed by a DataGrid of the
   accounts that make up the section. Defined globally (like the .gj-* rules
   above) because these styles must reach inside Radzen components: the grid
   <table>/<thead>/<tr> markup is rendered by RadzenDataGrid, not by our markup.
   ----------------------------------------------------------------------------- */
.fs-section-head {
    border-bottom: 1px solid #d8dee4;
    padding-bottom: 0.3rem;
}

.fs-section-head h3 {
    margin: 0;
    font-size: 0.95rem;
    font-weight: 700;
    color: #24292f;
}

/* Compact, chromeless statement grid: the heading above already carries the
   title and subtotal, so the grid only needs light row separators. */
.fs-section-grid {
    width: 100%;
    font-variant-numeric: tabular-nums;
}

.fs-section-grid .rz-grid-table {
    border: none;
}

/* Radzen pins every grid header to the top of its scroll container
   (.rz-grid-table thead { position: sticky; top: 0; z-index: 2 }). These section
   grids stack several to a page and have no inner scrollbar, so sticking would
   make each section's header float over the page content while scrolling. */
.fs-section-grid .rz-grid-table thead {
    position: static;
}

.fs-section-grid .rz-grid-table thead th {
    background: transparent;
    color: #57606a;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    border-bottom: 1px solid #d8dee4;
}

.fs-section-grid .rz-grid-table td {
    padding: 0.15rem 0.25rem;
    border-bottom: 1px solid #f0f2f4;
    vertical-align: baseline;
}

/* Radzen's cell wrapper is nowrap + hidden-overflow, which would clip long
   account names ("Accumulated Depreciation - Office Equip") to an ellipsis.
   Statement rows read better wrapped, so the wrapper is reset here. */
.fs-section-grid .rz-grid-table td .rz-cell-data {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
}

.fs-section-grid .rz-grid-table tbody tr:last-child td {
    border-bottom: none;
}

.fs-section-grid .rz-grid-table tbody tr:hover td {
    background: #f6f8fa;
}

/* Account / item cell: account code followed by the account name. */
.fs-account-cell {
    display: inline-flex;
    align-items: baseline;
    gap: 0.5rem;
    width: 100%;
}

/* Only rows tied to an account can be opened in the general ledger. */
.fs-grid-link {
    cursor: pointer;
}

.fs-grid-link:hover .stk-name {
    color: #1a73e8;
    text-decoration: underline;
}

/* Row states, applied by SectionBlock/CashFlowSectionBlock. The modifier class
   sits on the cell element itself (and on the amount span), so the rules must
   match the element carrying the class as well as its children. */
.fs-section-grid .is-header {
    font-weight: 700;
}

.fs-section-grid .is-contra {
    opacity: 0.75;
    font-style: italic;
}

/* Hierarchy indent: a parent account, then its children. */
.fs-indent-0 { padding-left: 0; }
.fs-indent-1 { padding-left: 0.9rem; }
.fs-indent-2 { padding-left: 1.8rem; }
.fs-indent-3 { padding-left: 2.7rem; }

/* One section block (heading + grid). min-width:0 keeps the grid from
   overflowing the flex column it lives in. */
.stk-block {
    min-width: 0;
}

/* Shared amount/code/name cells (statement headings and grid cells). */
.stk-code {
    display: inline-block;
    min-width: 3.5rem;
    opacity: 0.65;
    font-family: "Cascadia Code", Consolas, monospace;
    font-size: 0.8rem;
}

.stk-name {
    flex: 1 1 auto;
    min-width: 0;
}

.stk-amount {
    white-space: nowrap;
}

/* -----------------------------------------------------------------------------
   Accounting Books feature (books / transaction sources / book-source links).
   Page-scoped CSS cannot reach dialog or tab-component markup, so the shared
   classes live here, next to the other global feature styles.
   -----------------------------------------------------------------------------
*/
.accounting-books-grid-card {
    overflow-x: auto;
}

.data-grid-link {
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--ae-primary-hover);
    cursor: pointer;
    font-weight: 600;
    text-align: left;
}

.data-grid-link:hover,
.data-grid-link:focus-visible {
    text-decoration: underline;
}

.accounting-books-code {
    font-family: "Cascadia Code", Consolas, monospace;
    font-size: 0.85rem;
}

.accounting-books-muted {
    opacity: 0.65;
}

/* The asset name in the register opens the row using the shared .data-grid-link above, as every
   other Book page does. It had its own .asset-link rule until this page was brought into line;
   the shared class already resets the button and gives it the same focus and hover treatment. */

/* The day this session is working on, shown in the header only while it is not the real
   date. Deliberately visible: a register that refuses to post a month reads as a fault
   until you can see the session has not reached that month yet. A button, because the day
   is a choice the user made and will want to change; the background and font are reset so
   it is a chip rather than a control. Uses the brand color as a border and text rather
   than a fill, so it reads on both the light and dark stylesheets without a second rule. */
.session-working-date {
    display: inline-block;
    padding: 0.1rem 0.55rem;
    border: 1px solid var(--ae-primary);
    border-radius: 999px;
    background: transparent;
    color: var(--ae-primary);
    font-family: inherit;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: inherit;
    white-space: nowrap;
    cursor: pointer;
}

.accounting-books-chip-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
}

.accounting-books-chip-row-list {
    max-height: 260px;
    overflow-y: auto;
}

.accounting-books-chip {
    display: inline-block;
    padding: 0.1rem 0.55rem;
    border-radius: 999px;
    background: #e7f1fb;
    color: #0b5394;
    font-family: "Cascadia Code", Consolas, monospace;
    font-size: 0.75rem;
    font-weight: 600;
    white-space: nowrap;
}

.accounting-books-detail-value {
    font-size: 1rem;
    margin-top: 0.25rem;
}

.accounting-books-empty {
    opacity: 0.7;
    margin: 0;
    font-size: 0.85rem;
}

.accounting-books-hint {
    opacity: 0.7;
    font-size: 0.85rem;
    max-width: 560px;
}

.accounting-books-tabs {
    width: 100%;
}

/* Book columns grid: rows are draggable so their Order can be rearranged. */
.book-columns-drag-handle {
    display: inline-flex;
    align-items: center;
    color: var(--ae-primary);
    cursor: grab;
}

.book-columns-drop-target td {
    box-shadow: inset 0 2px 0 0 var(--ae-primary);
}



/* -----------------------------------------------------------------------------
   Book entries: the grid columns are generated from the selected book's
   BookColumns, so a new BIR journal renders here with no page-specific CSS.
   -------------------------------------------------------------------------- */
.book-entries-title {
    margin: 0;
    font-size: 1.35rem;
}

/* Neither .book-entries-header nor .book-entries-filters needs a rule of its own:
   the RadzenStacks that carry them lay them out, and the filters stopped being a
   bordered panel when the header took the row that panel used to occupy. */
.book-entries-grid {
    width: 100%;
}

/* The register groups by entry so that it can be read that way, not so that it can
   be regrouped: the group panel's row offered a chip naming a key, and the page
   header now carries the buttons that do the same job in words. */
.book-journal-lines .rz-group-header {
    display: none;
}

/* A book of journal lines groups into one group per entry, so the register reads
   the way it was written. The header carries what the whole posting was - its
   reference, the day it was posted, its description - and the rows beneath it are
   that entry's lines. The reference is the link to the posting, which is what
   gives it a link's weight while the rest of the header stays quiet. */
.gj-group {
    display: flex;
    align-items: baseline;
    gap: 0.75rem;
    flex-wrap: wrap;
}

.gj-group-date {
    color: var(--rz-text-secondary-color, #6c757d);
    font-size: 0.82rem;
    font-variant-numeric: tabular-nums;
}

.gj-group-description {
    max-width: 72ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The band lays its ends out with space between them, which puts the buttons at the
   right of the title's row. The auto margin keeps them at that edge when a narrower
   screen wraps them onto a row of their own. */
.gj-group-controls {
    display: flex;
    gap: 0.5rem;
    margin-left: auto;
}

/* Posting columns are the ones a source rule uses for journal lines. */
.book-entry-posting {
    font-weight: 600;
}

/* -----------------------------------------------------------------------------
   Book columns: the "calculation" block in the column dialog, and the
   read-only marker shown for a column the engine calculates.
   -------------------------------------------------------------------------- */
.book-column-calculation {
    padding: 0.6rem 0.75rem;
    border: 1px dashed var(--rz-base-300, #dee2e6);
    border-radius: 6px;
}

/* Engine-derived values (Reference, calculated totals) are not typed. */
.book-entry-derived {
    color: var(--rz-text-secondary-color, #6c757d);
    font-style: italic;
}

/* -----------------------------------------------------------------------------
   Book entry dialogs: one entry is viewed as a read-only list of its fields, and
   edited as a grid of the same fields. The form's own layout, density and markings
   live in BookEntryEditDialog.razor.css, beside the markup they belong to.
   -------------------------------------------------------------------------- */

/* The row the reader just wrote. Saving reads the list again, and the notification that says a
   record was saved is gone a few seconds later - so the row itself carries the news until the reader
   asks the list a different question (a filter, a reload). A tint plus an accent on the first cell,
   so it reads as a marker rather than as a differently-coloured row. Radzen's hover rule is more
   specific than this one, so hovering a marked row still behaves like hovering any other. */
.rz-data-row[data-just-changed="true"] > td {
    background-color: color-mix(in srgb, var(--ae-primary) 14%, var(--rz-grid-background-color, transparent));
}

.rz-data-row[data-just-changed="true"] > td:first-child {
    box-shadow: inset 3px 0 0 var(--ae-primary);
}

.book-entry-detail {
    max-height: 70vh;
    overflow-y: auto;
}

.book-entry-detail-values {
    width: 100%;
    margin-top: 0.25rem;
}

.book-entry-detail-value {
    font-size: 1rem;
    margin-top: 0.25rem;
    word-break: break-word;
}

/* Whether an entry reached the general ledger. "By hand" is not an error state:
   those sources are posted from the general journal instead. */
.book-entry-posted {
    color: #0f7b6c;
    font-weight: 600;
}

.book-entry-not-posted {
    color: var(--rz-text-secondary-color, #6c757d);
    font-style: italic;
}
/* -----------------------------------------------------------------------------
   Source rule header builder: each journal header field is composed from a list
   of pieces, with a live example so nothing has to be guessed.
   -------------------------------------------------------------------------- */
.source-rule-header-card {
    padding: 0.65rem 0.75rem;
    border: 1px solid var(--rz-base-300, #dee2e6);
    border-radius: 6px;
    margin-bottom: 0.5rem;
}

.source-rule-preview {
    padding: 0.35rem 0.5rem;
    background: var(--rz-base-100, #f6f6f6);
    border: 1px dashed var(--rz-base-300, #cfd4da);
    border-radius: 4px;
    font-family: var(--rz-font-family-monospace, ui-monospace, monospace);
    font-size: 0.85rem;
    word-break: break-word;
}
/* ---------------------------------------------------------------------------
   Sign-in
   Centerd card rather than the app shell: there is no tenant, no navigation and
   no data yet at this point, so showing the sidebar would be a lie.
   --------------------------------------------------------------------------- */
/* Shown while the session is read back from sessionStorage, before the Router
   renders. A slow storage read would otherwise flash text into a corner. */
.session-loading {
    padding: 2rem;
    color: #6c757d;
}


.login-shell {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    padding: 1.5rem;
}

.login-card {
    width: 100%;
    max-width: 24rem;
    padding: 2rem;
    border: 1px solid #dee2e6;
    border-radius: 0.5rem;
    background-color: #fff;
    box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.06);
}

.login-brand {
    margin: 0 auto 1rem;
    padding: 0.5rem 0.75rem;
    border-radius: 0.375rem;
    background: #fff;
}

.login-brand img {
    display: block;
    width: 100%;
    height: auto;
}

.login-sub {
    color: #6c757d;
    margin-bottom: 1.5rem;
}

.field {
    margin-bottom: 1rem;
}

.field label {
    display: block;
    margin-bottom: 0.25rem;
    font-weight: 500;
}

.login-card .ae-input {
    display: block;
    width: 100%;
}

.input {
    display: block;
    width: 100%;
    padding: 0.4rem 0.6rem;
    border: 1px solid #ced4da;
    border-radius: 0.25rem;
}

.login-card button[type=submit] {
    width: 100%;
    margin-top: 0.5rem;
    padding: 0.45rem 1rem;
    border-radius: 0.25rem;
    cursor: pointer;
}

.login-card button[type=submit]:disabled {
    opacity: 0.65;
    cursor: default;
}

/* Shown on a failed sign-in. role=alert in the markup is what announces it.
   Kept as .ae-alert (not Bootstrap's .alert): Radzen owns alerts elsewhere,
   and the login form stays dependency-light. */
.ae-alert {
    padding: 0.6rem 0.75rem;
    margin-bottom: 1rem;
    border-radius: 0.25rem;
    border: 1px solid transparent;
}

.ae-alert-error {
    color: #842029;
    background-color: #f8d7da;
    border-color: #f5c2c7;
}

/* Shown when the shell signs the user out because the API stopped accepting their token.
   Information rather than an error: nothing has gone wrong, the session simply ran out. */
.ae-alert-info {
    color: #0b4f6c;
    background-color: #d8ecf5;
    border-color: #b6d9e8;
}

/* Shown by the ErrorBoundary in App.razor. Kept plain and wrapping: the text is
   an exception message, so its length is not predictable. */
.error-detail {
    margin: 0;
    padding: 0.6rem 0.75rem;
    background-color: #f8f9fa;
    border: 1px solid #dee2e6;
    border-radius: 0.25rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.8125rem;
    white-space: pre-wrap;
    word-break: break-word;
    max-height: 12rem;
    overflow: auto;
}
/* --- Counterparties and aging -------------------------------------------------
   Two signals only. Neither is an error: money that is overdue is overdue
   because a date was missed, not because something is broken, and a party past
   its credit limit is over its limit, not invalid. */

.party-over-limit {
    color: #b3261e;
    font-weight: 600;
}

.aging-overdue {
    color: #b3261e;
    font-weight: 600;
}
/* --- Settlement dialog --------------------------------------------------------
   The payment's own figures sit above the documents it can be applied to, so the
   relationship between "received", "applied" and "outstanding" is one glance. */

.settlement-summary {
    padding-bottom: 0.35rem;
    border-bottom: 1px solid var(--rz-base-300, #e0e0e0);
}

.settlement-applied {
    margin-top: 0.35rem;
}

/* ----------------------------------------------------------------------------
   Dark-theme companions for custom chrome.
   Radzen's material-dark.css themes its own components; the rules below cover
   the app's hand-rolled surfaces (login, header menu, badges, chips, grids)
   whose light hex values would otherwise sit unreadably on the dark page.
   html[data-theme] is set by window.aeTheme before Blazor boots, so these
   apply on first paint with no flash. Scoped to [data-theme='dark'] so the
   light theme keeps its exact current look.
   ------------------------------------------------------------------------- */
/* A dialog sits on a page of the same color in dark mode, so its edge has to come from the
   surface and the border rather than from contrast with the background. The title bar needs no
   dark companion: the brand blue carries white text in either theme. */
html[data-theme='dark'] .rz-dialog {
    background-color: var(--rz-base-800);
    border: 1px solid var(--rz-base-600);
}

html[data-theme='dark'] .login-card {
    background: var(--rz-base-800);
    border-color: var(--rz-base-600);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
    color: var(--rz-text-color);
}

html[data-theme='dark'] .login-sub {
    color: var(--rz-text-secondary-color);
}

html[data-theme='dark'] .login-card label {
    color: var(--rz-text-secondary-color);
}

html[data-theme='dark'] .ae-alert-error {
    color: #f5c2c7;
    background-color: rgba(209, 52, 56, 0.16);
    border-color: rgba(209, 52, 56, 0.5);
}

html[data-theme='dark'] .ae-alert-info {
    color: #b6d9e8;
    background-color: rgba(43, 130, 170, 0.16);
    border-color: rgba(43, 130, 170, 0.5);
}

html[data-theme='dark'] .error-detail {
    background-color: var(--rz-base-900);
    border-color: var(--rz-base-600);
    color: var(--rz-text-color);
}

html[data-theme='dark'] .accounting-books-empty {
    background: var(--rz-base-800);
    border-color: var(--rz-base-600);
    color: var(--rz-text-secondary-color);
}

html[data-theme='dark'] .accounting-books-chip {
    background: var(--rz-base-700);
    border-color: var(--rz-base-500);
    color: var(--rz-text-color);
}

html[data-theme='dark'] .accounting-books-detail-label {
    color: var(--rz-text-secondary-color);
}

html[data-theme='dark'] .accounting-books-detail-value {
    background: var(--rz-base-800);
    border-color: var(--rz-base-600);
}

html[data-theme='dark'] .dialog-error {
    color: #f5c2c7;
}

html[data-theme='dark'] .fs-indent-1,
html[data-theme='dark'] .fs-indent-2,
html[data-theme='dark'] .fs-indent-3,
html[data-theme='dark'] .fs-indent-total,
html[data-theme='dark'] .fs-section-total td {
    border-top-color: var(--rz-base-600);
}

html[data-theme='dark'] .stk-link:hover {
    background: rgba(13, 166, 159, 0.22);
}

html[data-theme='dark'] .book-column-reorder-handle {
    color: var(--rz-text-secondary-color);
}

html[data-theme='dark'] .app-loading {
    color: var(--rz-text-color);
}

html[data-theme='dark'] .app-loading p {
    color: var(--rz-text-secondary-color);
}

/* --- Fixed asset register -----------------------------------------------------
   The register, its periods, and the setup scan. Colors come from the theme
   tokens so the whole thing follows the light/dark switch without a second set of
   rules. */

.discovery-note {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    padding: 0.5rem 0.6rem;
    border: 1px solid var(--rz-base-300, #d8dee4);
    border-left-width: 4px;
    border-radius: 4px;
    font-size: 0.875rem;
}

.discovery-note.is-warning {
    border-left-color: var(--rz-warning, #f0a000);
}

.discovery-note.is-blocking {
    border-left-color: var(--rz-danger, #d13438);
}

/* The tie-out. Green when the proposal agrees with the ledger, red when it does
   not - because a register that does not reconcile is the one thing that must not
   look ordinary. */
.recon {
    border-left: 4px solid var(--rz-success, #107c10);
}

.recon.is-unbalanced {
    border-left-color: var(--rz-danger, #d13438);
}

.recon-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 1.25rem;
    margin-top: 0.75rem;
}

.recon-grid > div {
    flex: 1 1 200px;
    min-width: 0;
}

.confidence-badge {
    display: inline-block;
    padding: 0.15rem 0.6rem;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    white-space: nowrap;
}

.confidence-exact {
    background: var(--rz-success-lighter, #e8f5e9);
    color: var(--rz-success-dark, #1b5e20);
}

.confidence-grouped {
    background: var(--rz-info-lighter, #e3f2fd);
    color: var(--rz-info-dark, #0d47a1);
}

.confidence-partial {
    background: var(--rz-warning-lighter, #fff3e0);
    color: var(--rz-warning-dark, #e65100);
}

.confidence-unmatched {
    background: var(--rz-base-200, #f1f1f1);
    color: var(--rz-text-secondary-color, #686868);
}

.discovery-chip {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--rz-base-300, #e0e0e0);
    border-radius: 6px;
    min-width: 200px;
}

.discovery-chip strong {
    font-family: Consolas, monospace;
    font-size: 0.85rem;
}

.discovery-chip small {
    font-size: 0.75rem;
}

.discovery-chip-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-top: 0.75rem;
}

/* A disposed asset is neither active nor merely inactive: it is gone from the
   books, so it reads differently from both. */
.account-status.is-disposed {
    color: var(--rz-text-secondary-color, #686868);
    text-decoration: line-through;
}

.disposal-preview {
    text-align: center;
}
