/* ==========================================================================
   BazarSoft — Unified Product 2026
   The design system ported from the Figma file "BazarSoft Accounting System
   UI Design".

   Ordered the way the design is: tokens first, then the shell (top bar, rail,
   book strip, page head), then the controls screens are built from (button,
   field, badge, tab, table, pager, state block), then the screens themselves.
   Nothing below the token block hard-codes a colour.
   ========================================================================== */

/* ------------------------------------------------------------------ tokens */

:root {
    /* Brand. A filled red always means "the main action"; it never means
       danger. Danger is an outline — see the button section. */
    --brand: #c8202a;
    --brand-hover: #b21c25;
    --brand-pressed: #8f171e;
    --on-brand: #ffffff;
    --nav-indicator: #c8202a;

    /* The design's brand-secondary. Only the sign-in hero rule wears it. */
    --brand-secondary: #ff4d2e;

    /* Surfaces. The paper ground is warm; cards sit white on top of it. */
    --surface-brand: #1f2733;
    --bg-paper: #faf7f2;
    --bg-card: #ffffff;
    --bg-sunken: #f0ece4;
    --bg-input: #fbf9f5;

    /* Text */
    --text-primary: #181820;
    --text-secondary: #52525e;
    --text-tertiary: #6f6f7a;

    /* Lines. The hairline rules inside a card; the edge separates shell
       regions and is deliberately softer. */
    --hairline: #d5d0c7;
    --edge: rgba(24, 24, 32, 0.08);
    --border-control: #8f8f97;
    --border-ghost: rgba(24, 24, 32, 0.16);

    /* Focus is blue on purpose: red carries error and danger everywhere else
       in this product, so it cannot also mean "you are here". */
    --focus-ring: #2563eb;

    /* Interaction */
    --row-hover: #f0ece4;
    --surface-pressed: #e2ded8;

    /* Meaning. One meaning each, never reused for decoration. */
    --error: #a8151c;
    --danger-pressed: #700d12;
    --mark-success: #0f6b38;
    --mark-warning: #96430a;
    --mark-error: #a8151c;
    --mark-neutral: #6f6f7a;

    --success-container: #e7f6ec;
    --on-success-container: #0f6b38;
    --warning-container: #fcf0d6;
    --on-warning-container: #96430a;
    --error-container: #fdecec;
    --on-error-container: #a8151c;
    --primary-container: #ffe5e2;
    --on-primary-container: #c8202a;
    --neutral-container: #f0ece4;
    --on-neutral-container: #45454f;

    /* Book avatars. A book keeps its colour on every screen that names it. */
    --avatar-1: #1d4ed8;
    --avatar-2: #15803d;
    --avatar-3: #b45309;
    --avatar-4: #7c3aed;
    --avatar-5: #0f766e;

    /* Radius and space */
    --radius-control: 8px;
    --radius-surface: 8px;
    --radius-pill: 999px;
    --space-4: 4px;
    --space-8: 8px;
    --space-12: 12px;
    --space-16: 16px;
    --space-24: 24px;

    --shadow-card: 0 2px 8px rgba(0, 0, 0, 0.08);
    --shadow-modal: 0 12px 40px rgba(0, 0, 0, 0.18);

    /* Type. Cairo carries the words; IBM Plex Sans carries the figures,
       because tabular numerals are what make a column of money readable. */
    --font-ui: "Cairo", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    --font-num: "IBM Plex Sans", "Cairo", -apple-system, "Segoe UI", sans-serif;

    --rail-width: 240px;
    --topbar-height: 60px;
}

/* ------------------------------------------------------------------- reset */

*,
*::before,
*::after {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

[hidden] {
    display: none !important;
}

html,
body {
    height: 100%;
}

body {
    font-family: var(--font-ui);
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-primary);
    background: var(--bg-paper);
    overflow: hidden;
    -webkit-font-smoothing: antialiased;
}

button,
input,
select,
textarea {
    font: inherit;
    color: inherit;
}

a {
    color: inherit;
    text-decoration: none;
}

:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

/* Every figure in the product is tabular, so a column of money lines up on
   the decimal point without any per-cell effort. */
.num,
.data-table td.num,
.data-table th.num,
.amount-debit,
.amount-credit,
.amount-balance,
.count-number,
.pager-info {
    font-family: var(--font-num);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

/* =============================================================== app shell */

.app {
    display: flex;
    flex-direction: column;
    height: 100vh;
    background: var(--bg-paper);
}

.app[hidden] {
    display: none;
}

/* ---------------------------------------------------------------- top bar */

.topbar {
    display: flex;
    align-items: center;
    gap: var(--space-12);
    height: var(--topbar-height);
    flex: 0 0 var(--topbar-height);
    padding: 0 20px;
    background: var(--surface-brand);
    color: var(--on-brand);
    overflow: hidden;
}

.topbar-mark {
    width: 34px;
    height: 34px;
    flex-shrink: 0;
    display: block;
}

.topbar-name {
    font: 600 16px/1.4 var(--font-ui);
    white-space: nowrap;
}

.topbar-divider {
    width: 1px;
    height: 24px;
    flex-shrink: 0;
    background: rgba(255, 255, 255, 0.18);
}

.topbar-gap {
    flex: 1 0 0;
    min-width: var(--space-8);
}

/* The scope pill names the book you are inside. It is the only control in
   the bar that changes what the whole screen is about. */
.scope-pill {
    display: flex;
    align-items: center;
    gap: var(--space-8);
    max-width: 340px;
    padding: 5px 12px 5px 5px;
    border: 0;
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.12);
    color: var(--on-brand);
    cursor: pointer;
}

.scope-pill:hover {
    background: rgba(255, 255, 255, 0.2);
}

.scope-pill .avatar {
    width: 26px;
    height: 26px;
    font: 600 11px/1.4 var(--font-ui);
}

.scope-pill-name {
    font: 600 14px/1.5 var(--font-ui);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.fy-chip {
    flex-shrink: 0;
    padding: 2px 8px;
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.2);
    font: 600 11px/1.4 var(--font-ui);
    white-space: nowrap;
}

.scope-pill .caret {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    stroke: currentColor;
    stroke-width: 1.5;
    fill: none;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* The round controls on the right of the bar. */
.topbar-icon-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    flex-shrink: 0;
    border: 0;
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.12);
    color: var(--on-brand);
    cursor: pointer;
}

.topbar-icon-btn:hover {
    background: rgba(255, 255, 255, 0.22);
}

.topbar-icon-btn svg {
    width: 16px;
    height: 16px;
    stroke: currentColor;
    stroke-width: 1.5;
    fill: none;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.topbar-icon-btn .count {
    position: absolute;
    top: -3px;
    left: 20px;
    min-width: 15px;
    height: 15px;
    padding: 0 3px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-pill);
    background: var(--brand);
    color: var(--on-brand);
    font: 700 11px/1.4 var(--font-num);
}

/* A book's avatar. The letter and the colour together are its identity, and
   they are the same on every screen that names it. */
.avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    border-radius: var(--radius-pill);
    background: var(--avatar-2);
    color: var(--on-brand);
    overflow: hidden;
}

.avatar-1 { background: var(--avatar-1); }
.avatar-2 { background: var(--avatar-2); }
.avatar-3 { background: var(--avatar-3); }
.avatar-4 { background: var(--avatar-4); }
.avatar-5 { background: var(--avatar-5); }

/* -------------------------------------------------------------------- body */

.shell-body {
    display: flex;
    flex: 1 0 0;
    min-height: 0;
    align-items: stretch;
    overflow: hidden;
}

/* -------------------------------------------------------------------- rail */

.rail {
    width: var(--rail-width);
    flex: 0 0 var(--rail-width);
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    padding: var(--space-16) 0;
    background: var(--bg-card);
    border-right: 1px solid var(--edge);
    overflow-x: hidden;
    overflow-y: auto;
}

.rail-group-label {
    padding: 12px 20px 4px;
    font: 700 11px/1.4 var(--font-ui);
    letter-spacing: 1.1px;
    text-transform: uppercase;
    color: var(--text-tertiary);
    white-space: nowrap;
}

.rail-spacer {
    height: 12px;
    flex-shrink: 0;
}

.rail-spacer-sm {
    height: 8px;
}

.rail-gap {
    flex: 1 0 0;
    min-height: var(--space-16);
}

.rail-rule {
    height: 1px;
    flex-shrink: 0;
    background: var(--edge);
}

/* U/NavItem. Active is deliberately the loudest thing on the rail — a solid
   dark pill with a red indicator — because "where am I" has to read from
   across the room. Hover is deliberately much quieter, so hovered can never
   be mistaken for current. */
.nav-item {
    display: flex;
    align-items: center;
    gap: var(--space-12);
    height: 36px;
    padding: 8px 12px;
    border-left: 3px solid transparent;
    border-radius: var(--radius-control);
    color: var(--text-secondary);
    font: 400 13px/1.5 var(--font-ui);
    white-space: nowrap;
    cursor: pointer;
}

.nav-item .nav-icon {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    display: block;
    stroke: currentColor;
    stroke-width: 1.5;
    fill: none;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.nav-item:hover {
    background: rgba(240, 236, 228, 0.6);
}

.nav-item.active {
    background: var(--surface-brand);
    border-left-color: var(--nav-indicator);
    color: var(--on-brand);
    font-weight: 600;
}

.nav-item.active:hover {
    background: var(--surface-brand);
}

/* -------------------------------------------------------------------- main */

.main {
    flex: 1 0 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* U/BookStrip — the book identity band. Every field here is the one source
   for how this book is described, so it cannot be described two different
   ways on two different screens. */
.bookstrip {
    display: flex;
    align-items: center;
    gap: var(--space-16);
    flex-shrink: 0;
    padding: 22px var(--space-24);
    background: var(--bg-paper);
}

.bookstrip .avatar {
    width: 40px;
    height: 40px;
    font: 600 14px/1.5 var(--font-ui);
}

.bookstrip-names {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    flex: 1 0 0;
    min-width: 0;
    overflow: hidden;
}

.bookstrip-title {
    display: flex;
    align-items: center;
    gap: var(--space-12);
}

.bookstrip-title h1 {
    font: 700 20px/1.25 var(--font-ui);
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.bookstrip-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    font: 400 12px/1.4 var(--font-ui);
    color: var(--text-secondary);
}

.bookstrip-meta .sep {
    color: var(--text-tertiary);
}

.bookstrip-actions {
    display: flex;
    align-items: center;
    gap: var(--space-8);
    flex-shrink: 0;
}

.shell-rule {
    height: 1px;
    flex-shrink: 0;
    background: var(--edge);
}

/* Content is the only scrolling region: 32 horizontal / 24 vertical, and a
   16px gap between the blocks a screen is made of. */
.content {
    flex: 1 0 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-16);
    padding: var(--space-24) 32px;
    overflow-y: auto;
    background: var(--bg-paper);
}

.pagehead {
    display: flex;
    align-items: flex-end;
    gap: var(--space-16);
    flex-shrink: 0;
}

.pagehead-text {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    min-width: 0;
}

.breadcrumb {
    display: flex;
    align-items: center;
    gap: var(--space-12);
    font-size: 13px;
    line-height: 1.5;
}

.breadcrumb a,
.breadcrumb .crumb {
    font-weight: 500;
    color: var(--brand);
    cursor: pointer;
}

.breadcrumb a:hover {
    text-decoration: underline;
}

.breadcrumb .breadcrumb-separator,
.breadcrumb .sep {
    font-weight: 400;
    color: var(--text-tertiary);
}

.breadcrumb .leaf,
.breadcrumb strong {
    font-weight: 400;
    color: var(--text-primary);
}

.pagehead h1 {
    font: 600 20px/1.25 var(--font-ui);
    color: var(--text-primary);
}

.pagehead-actions {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--space-8);
    flex-shrink: 0;
}

/* A screen pane. Only one shows at a time; the shell around them stays put. */
.page {
    display: none;
    flex-direction: column;
    gap: var(--space-16);
}

.page.active {
    display: flex;
}

/* ================================================================ controls */

/* ------------------------------------------------------------------ button */

/* U/Button. The kinds are separated by treatment, not by hue: a FILLED red
   button always means "the main action" and never means "dangerous".
   Danger is an outline. Focus is blue, not red, for the same reason. */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-8);
    padding: 10px 18px;
    border: 1px solid transparent;
    border-radius: var(--radius-control);
    background: var(--brand);
    color: var(--on-brand);
    font: 600 14px/1.5 var(--font-ui);
    white-space: nowrap;
    cursor: pointer;
    transition: background-color 0.12s ease, border-color 0.12s ease;
}

.btn:hover:not(:disabled) {
    background: var(--brand-hover);
}

/* The export control: one segmented control whose two halves are the two
   answers. It borrows .segmented's shape - a bordered strip divided by a
   hairline - but neither half is ever "current", because these are actions
   rather than a choice of view. Tighter than the tab strips it borrows from,
   since it sits in a toolbar beside a count and a date field. */
.segmented-split button {
    gap: 6px;
    padding: 7px 12px;
    font: 600 12px/1.5 var(--font-ui);
    color: var(--text-secondary);
}

.segmented-split button:disabled {
    opacity: 0.55;
    cursor: default;
}

.segmented-split .btn-icon {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    display: block;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.5;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* .btn is already a flex row with a gap, so an icon needs only its size and
   the stroke every icon in this interface is drawn with. */
.btn .btn-icon {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    display: block;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.5;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.btn:active:not(:disabled) {
    background: var(--brand-pressed);
}

/* Ghost: white ground, neutral hairline. The workhorse secondary. */
.btn-ghost {
    background: var(--bg-card);
    border-color: var(--border-ghost);
    color: var(--text-primary);
}

.btn-ghost:hover:not(:disabled) {
    background: var(--row-hover);
    border-color: var(--border-ghost);
}

.btn-ghost:active:not(:disabled) {
    background: var(--surface-pressed);
}

/* Danger is outlined, never filled. */
.btn-danger {
    background: var(--bg-card);
    border: 1.5px solid var(--error);
    color: var(--error);
}

.btn-danger:hover:not(:disabled) {
    background: var(--error-container);
}

.btn-danger:active:not(:disabled) {
    border-color: var(--danger-pressed);
    color: var(--danger-pressed);
}

/* Quiet: no fill at all. */
.btn-quiet {
    background: transparent;
    border-color: transparent;
    color: var(--text-secondary);
}

.btn-quiet:hover:not(:disabled) {
    background: var(--row-hover);
}

/* Disabled carries the reason the user cannot act, so its label must stay
   readable: text-secondary on bg-sunken is 6.1:1. */
.btn:disabled {
    background: var(--bg-sunken);
    border-color: transparent;
    color: var(--text-secondary);
    cursor: default;
    pointer-events: none;
}

.btn svg {
    width: 16px;
    height: 16px;
    stroke: currentColor;
    stroke-width: 1.5;
    fill: none;
    stroke-linecap: round;
    stroke-linejoin: round;
    flex-shrink: 0;
}

/* A row action: the small square icon button that sits at the end of a row. */
.action-cell {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 6px;
}

.action-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 1px solid var(--border-ghost);
    border-radius: var(--radius-control);
    background: var(--bg-card);
    color: var(--text-secondary);
    cursor: pointer;
}

.action-btn svg {
    width: 16px;
    height: 16px;
    stroke: currentColor;
    stroke-width: 1.5;
    fill: none;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.action-btn:hover {
    background: var(--row-hover);
    color: var(--text-primary);
}

.action-btn.danger {
    color: var(--error);
    border-color: var(--error);
}

.action-btn.danger:hover {
    background: var(--error-container);
}

/* ------------------------------------------------------------------- field */

/* U/Field. A 40px control on the warm input ground. */
.field {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}

.field-label {
    font: 600 12px/1.4 var(--font-ui);
    color: var(--text-secondary);
}

.field-input,
.currency-select,
.field select,
.field textarea {
    width: 100%;
    height: 40px;
    /* 9px, not 10: 40 less the two borders and this padding has to hold a
       19.5px line, and 10 leaves 18 - which clips every descender. It shows on
       selects, which do not centre their text the way an input does. */
    padding: 9px 12px;
    border: 1px solid var(--border-control);
    border-radius: var(--radius-control);
    background: var(--bg-input);
    color: var(--text-primary);
    font: 400 13px/1.5 var(--font-ui);
}

.field textarea {
    height: auto;
    min-height: 88px;
    resize: vertical;
}

.field-input::placeholder {
    color: var(--text-tertiary);
}

.field-input:focus,
.currency-select:focus {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
    border-color: var(--border-control);
}

.field-input.error {
    border-color: var(--error);
    background: var(--error-container);
}

/* A search field carries its magnifier inside the control. */
.search-field {
    position: relative;
    width: 280px;
    flex-shrink: 0;
}

.search-field input {
    width: 100%;
    height: 40px;
    padding: 9px 12px 9px 36px;
    border: 1px solid var(--border-control);
    border-radius: var(--radius-control);
    background: var(--bg-input);
    color: var(--text-primary);
    font: 400 13px/1.5 var(--font-ui);
}

.search-field .search-icon {
    position: absolute;
    inset-inline-start: 12px;
    top: 50%;
    transform: translateY(-50%);
    width: 16px;
    height: 16px;
    pointer-events: none;
    stroke: var(--text-tertiary);
    stroke-width: 1.5;
    fill: none;
    stroke-linecap: round;
}

[dir="rtl"] .search-field input {
    padding: 9px 36px 9px 12px;
}

/* Two fields on a line. */
.field-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-12);
}

.modal-form {
    display: flex;
    flex-direction: column;
    gap: var(--space-12);
}

/* ---------------------------------------------------------- notification */

/* What the bell opens: the same findings the dashboard shows, reachable from
   whichever screen you happen to be on. */
.notify-list {
    display: flex;
    flex-direction: column;
}

.notify-row {
    display: flex;
    align-items: center;
    gap: var(--space-16);
    padding: 12px 0;
    border-bottom: 1px solid var(--hairline);
}

.notify-row:last-child {
    border-bottom: 0;
}

.notify-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.notify-title {
    font: 600 13px/1.5 var(--font-ui);
    color: var(--text-primary);
}

.notify-detail {
    font: 400 12px/1.4 var(--font-ui);
    color: var(--text-secondary);
}

.notify-row .btn {
    margin-inline-start: auto;
    flex-shrink: 0;
}

/* ------------------------------------------------------------- notice bar */

/* Something is wrong with the screen you are already on, said in one line with
   the thing that fixes it beside it.
   
   Deliberately not .state-block: that one fills a region where content would
   otherwise be, so it is centred and 48px tall top and bottom. A notice sits
   above content that is already there and every pixel it takes is a pixel of
   that content pushed down, so it is as short as it can be while still being
   read first. */
.notice {
    display: flex;
    align-items: center;
    gap: var(--space-16);
    padding: 12px 16px;
    margin-bottom: var(--space-16);
    background: var(--bg-card);
    border: 1px solid var(--hairline);
    border-inline-start: 3px solid var(--text-tertiary);
    border-radius: var(--radius-surface);
}

.notice-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.notice-title {
    font: 600 13px/1.5 var(--font-ui);
    color: var(--text-primary);
}

.notice-body {
    font: 400 12px/1.4 var(--font-ui);
    color: var(--text-secondary);
}

.notice .btn {
    margin-inline-start: auto;
    flex-shrink: 0;
}

/* Tone by the edge and the ground, never by the button - a filled red button
   means "the main action" here and not "danger". */
.notice.error {
    background: var(--error-container);
    border-color: var(--error-container);
    border-inline-start-color: var(--mark-error);
}

.notice.error .notice-title { color: var(--on-error-container); }

/* ------------------------------------------------------- month-end strip */

/* The strip the dashboard opens with: which month, how far from closeable,
   and the one control that takes you to what is left. 1136 wide, 88 tall,
   with the bar spanning the card's own padding - the design's Period frame. */
.monthend {
    margin-bottom: var(--space-16);
    background: var(--bg-card);
    border: 1px solid var(--hairline);
    border-radius: var(--radius-surface);
    box-shadow: var(--shadow-card);
    overflow: hidden;
}

.monthend .monthend-row {
    display: flex;
    align-items: center;
    gap: var(--space-16);
    padding: 8px 20px;
    min-height: 64px;
}

.monthend .monthend-text {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    min-width: 0;
}

.monthend .monthend-title {
    display: flex;
    align-items: center;
    gap: 10px;
}

.monthend .monthend-title h2 {
    font: 600 16px/1.4 var(--font-ui);
    color: var(--text-primary);
}

.monthend .monthend-sub {
    font: 400 13px/1.5 var(--font-ui);
    color: var(--text-secondary);
}

.monthend .monthend-row .btn {
    margin-inline-start: auto;
    flex-shrink: 0;
}

.monthend .monthend-progress {
    padding: 0 20px 18px;
}

/* 6px, full width, and the filled part is the fraction that is clear. */
.monthend-bar {
    height: 6px;
    border-radius: var(--radius-pill);
    background: var(--bg-sunken);
    overflow: hidden;
}

.monthend-bar span {
    display: block;
    height: 100%;
    border-radius: var(--radius-pill);
    background: var(--mark-success);
    transition: width 0.2s ease;
}

/* ------------------------------------------------------------- freshness */

/* Where the figures came from. A head that stacks its note under the title
   rather than beside it, then a row per source with a hairline between. */
.card-head.stacked {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-4);
    height: auto;
    padding-top: 16px;
    padding-bottom: 16px;
}

.source-list {
    display: flex;
    flex-direction: column;
}

.source-row {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 40px;
    padding: 10px 20px;
    border-bottom: 1px solid var(--hairline);
    font: 400 13px/1.5 var(--font-ui);
    color: var(--text-primary);
}

.source-row:last-child {
    border-bottom: 0;
}

.source-row .dot {
    width: 7px;
    height: 7px;
    border-radius: var(--radius-pill);
    background: var(--mark-success);
    flex-shrink: 0;
}

/* Tone carries the state, and the words beside it say the same thing - the
   dot is a glance, not the only telling. */
.source-row.stale .dot { background: var(--mark-warning); }
.source-row.never .dot { background: var(--mark-error); }

.source-row .source-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.source-row .when {
    flex-shrink: 0;
    font: 400 12px/1.4 var(--font-num);
    color: var(--text-secondary);
}

.source-row.stale .when { color: var(--mark-warning); }
.source-row.never .when { color: var(--mark-error); }

/* --------------------------------------------------------- cleared checks */

.attention-cleared {
    display: flex;
    flex-direction: column;
    gap: var(--space-8);
    padding: 16px 20px 18px;
}

.clear-head {
    display: flex;
    align-items: center;
    font: 600 12px/1.4 var(--font-ui);
    color: var(--mark-success);
}

.clear-head .gap {
    flex: 1;
}

.clear-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4) var(--space-16);
}

.clear-item {
    display: inline-flex;
    align-items: center;
    gap: var(--space-8);
    font: 400 12px/1.4 var(--font-ui);
    color: var(--text-secondary);
}

.clear-item svg {
    width: 10px;
    height: 8px;
    flex-shrink: 0;
    stroke: var(--mark-success);
    stroke-width: 1.6;
    fill: none;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* ------------------------------------------------------------ badge & chip */

/* U/Badge. Tone carries the meaning; the dot is optional and only ever
   restates the tone. */
.badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border-radius: var(--radius-pill);
    background: var(--neutral-container);
    color: var(--on-neutral-container);
    font: 600 12px/1.4 var(--font-ui);
    white-space: nowrap;
}

.badge::before {
    content: none;
}

.badge.dot::before {
    content: "";
    display: block;
    width: 6px;
    height: 6px;
    border-radius: var(--radius-pill);
    background: currentColor;
    flex-shrink: 0;
}

.badge-success { background: var(--success-container); color: var(--on-success-container); }
.badge-warning { background: var(--warning-container); color: var(--on-warning-container); }
.badge-error   { background: var(--error-container);   color: var(--on-error-container); }

.badge-neutral { background: var(--neutral-container); color: var(--on-neutral-container); }

/* The read-only pill on a scope the user cannot write to. */
.pill-readonly {
    display: inline-flex;
    align-items: center;
    padding: 8px 12px;
    border-radius: var(--radius-pill);
    background: var(--bg-sunken);
    color: var(--on-neutral-container);
    font: 600 12px/1.4 var(--font-ui);
    white-space: nowrap;
    flex-shrink: 0;
}

/* A pinned shortcut. Outlined pill, brand label — it is a link, not a state. */
.chip {
    display: inline-flex;
    align-items: center;
    padding: 5px 12px;
    border: 1px solid var(--border-control);
    border-radius: var(--radius-pill);
    background: var(--bg-card);
    color: var(--brand);
    font: 500 12px/1.4 var(--font-ui);
    white-space: nowrap;
    cursor: pointer;
}

.chip:hover {
    background: var(--primary-container);
}

/* A severity mark: a filled disc blocks, a ring only asks you to look. */
.severity {
    display: flex;
    align-items: center;
    gap: var(--space-8);
    width: 112px;
    flex-shrink: 0;
    font: 600 12px/1.4 var(--font-ui);
}

.severity::before {
    content: "";
    width: 10px;
    height: 10px;
    border-radius: var(--radius-pill);
    flex-shrink: 0;
}

/* -------------------------------------------------------------------- tabs */
/* The indicator space is reserved on every tab, so switching tabs never
   moves the strip by 2px. */
.tabs {
    display: flex;
    align-items: flex-start;
    gap: var(--space-4);
    width: 100%;
    border-bottom: 1px solid var(--hairline);
    overflow-x: auto;
    flex-shrink: 0;
}

.tab {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    flex-shrink: 0;
    border: 0;
    background: transparent;
    cursor: pointer;
}

.tab-label {
    display: flex;
    align-items: center;
    padding: 12px 14px;
    font: 400 13px/1.5 var(--font-ui);
    color: var(--text-secondary);
    white-space: nowrap;
}

.tab::after {
    content: "";
    display: block;
    height: 2px;
    background: transparent;
}

.tab:hover .tab-label {
    background: var(--row-hover);
    border-radius: var(--radius-control) var(--radius-control) 0 0;
}

.tab.active .tab-label {
    font-weight: 600;
    color: var(--text-primary);
}

.tab.active::after {
    background: var(--nav-indicator);
}

.tab.active:hover .tab-label {
    background: transparent;
}

/* --------------------------------------------------------------- toolbar */

.toolbar {
    display: flex;
    align-items: center;
    gap: var(--space-16);
    width: 100%;
    flex-shrink: 0;
    flex-wrap: wrap;
}

.toolbar-count {
    font: 400 13px/1.5 var(--font-ui);
    color: var(--text-secondary);
    white-space: nowrap;
}

.toolbar-gap {
    flex: 1 0 0;
    min-width: 0;
}

.pinned {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
}

/* ================================================== cards, tables, pagers */
/* -------------------------------------------------------------------- card */
.card {
    display: flex;
    flex-direction: column;
    width: 100%;
    background: var(--bg-card);
    border-radius: var(--radius-control);
    box-shadow: var(--shadow-card);
    overflow: hidden;
    flex-shrink: 0;
}

.card-head {
    display: flex;
    align-items: center;
    gap: var(--space-12);
    padding: 16px 20px 12px;
    width: 100%;
}

.card-head h2,
.card-head h3 {
    font: 700 16px/1.4 var(--font-ui);
    color: var(--text-primary);
}

.card-head .gap {
    flex: 1 0 0;
    min-width: 0;
}

.card-note {
    font: 400 12px/1.4 var(--font-ui);
    color: var(--text-tertiary);
}

.card-rule,
.rule {
    height: 1px;
    flex-shrink: 0;
    background: var(--hairline);
}

.card-body {
    padding: 16px 20px;
}

.card-sunken {
    background: var(--bg-input);
    padding: 16px 20px;
}

/* A note card: a short paragraph on its own white ground. */
.note-card {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 14px 20px 16px;
    background: var(--bg-card);
    border-radius: var(--radius-surface);
    box-shadow: var(--shadow-card);
}

.note-card strong,
.note-card .note-title {
    font: 600 13px/1.5 var(--font-ui);
    color: var(--text-primary);
}

.note-card p {
    font: 400 12px/1.4 var(--font-ui);
    color: var(--text-secondary);
}

/* Layout helpers the screens are assembled from. */
.two-col {
    display: flex;
    align-items: flex-start;
    gap: var(--space-16);
    width: 100%;
}

.two-col > .col-main {
    flex: 1 0 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-16);
}

.two-col > .col-side {
    width: 340px;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-16);
}

.footnote {
    font: 400 12px/1.4 var(--font-ui);
    color: var(--text-tertiary);
}

/* ------------------------------------------------------------------- table */

/* The table lives inside a card and never draws its own outer border: the
   card's radius and shadow are the frame. Row rules span the full card width.
   Cell padding reproduces the design's 16px row padding + 16px cell padding
   + 16px inter-cell gap: 32px at the card edge, 48px between two columns. */
.table-wrap {
    width: 100%;
    overflow-x: auto;
}

.data-table,
.report-table {
    width: 100%;
    border-collapse: collapse;
    background: var(--bg-card);
}

.data-table th,
.report-table th {
    height: 44px;
    padding: 0 24px;
    background: var(--bg-sunken);
    border-bottom: 1px solid var(--border-control);
    font: 700 11px/1.4 var(--font-ui);
    letter-spacing: 1.1px;
    text-transform: uppercase;
    color: var(--text-primary);
    text-align: start;
    white-space: nowrap;
    vertical-align: middle;
}

.data-table th:first-child,
.report-table th:first-child { padding-inline-start: 32px; }

.data-table th:last-child,
.report-table th:last-child { padding-inline-end: 32px; }

.data-table td,
.report-table td {
    height: 44px;
    padding: 0 24px;
    border-bottom: 1px solid var(--hairline);
    font: 400 13px/1.5 var(--font-ui);
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    vertical-align: middle;
}

.data-table td:first-child,
.report-table td:first-child { padding-inline-start: 32px; }

.data-table td:last-child,
.report-table td:last-child { padding-inline-end: 32px; }

/* The card's own edge closes the table; a last-row rule would double up
   against the pager's top rule. */
.data-table tbody tr:last-child td {
    border-bottom: 0;
}

.data-table tbody tr:hover {
    background: var(--row-hover);
}

.data-table tbody tr.clickable,
.data-table tbody tr[onclick] {
    cursor: pointer;
}

.data-table tbody tr.clickable:active,
.data-table tbody tr[onclick]:active {
    background: var(--surface-pressed);
}

/* A row has exactly two states, Default and Hover. There is deliberately no
   selected row: the pink family is reserved for trouble, and a selection tint
   would compete with a status colour inside the same row. */

.data-table td.wrap {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    max-width: none;
}

/* Money and identifiers. Codes are numerals but read left, because they are
   names; balances read right, because they are quantities. */
.data-table th.num,
.data-table td.num,
.data-table th.amount,
.data-table td.amount,
.amount-debit,
.amount-credit,
.amount-balance {
    text-align: end;
}

.data-table td.code,
.data-table th.code {
    text-align: start;
}

/* The design gives every column a fixed width that sums to the card. A web
   table cannot do that across a dozen screens, so the rule is the same idea
   stated the other way round: the columns whose width is set by their content
   - codes, dates, figures, row actions - shrink to it, and the slack all goes
   to the columns carrying names. Without this the browser shares the slack in
   proportion to content, which fattens a "Type" column and squeezes the name. */
.data-table th.num,
.data-table td.num,
.data-table th.code,
.data-table td.code,
.data-table td:has(.action-cell) {
    width: 1%;
    white-space: nowrap;
}

.data-table:has(.action-cell) th:last-child {
    width: 1%;
}

.amount-debit,
.amount-credit,
.amount-balance {
    color: var(--text-primary);
    font-weight: 400;
}

.amount-balance {
    font-weight: 600;
}

.amount-negative,
.amount-debit.negative,
.amount-balance.negative {
    color: var(--mark-error);
}

.amount-mask {
    color: var(--text-tertiary);
    letter-spacing: 0.12em;
}

/* A sortable header shows which way the sort runs. */
.data-table th.sortable {
    cursor: pointer;
    user-select: none;
}

.data-table th.sortable .caret {
    display: inline-block;
    width: 8px;
    height: 5px;
    margin-inline-start: 6px;
    vertical-align: middle;
    background: currentColor;
    clip-path: polygon(0 100%, 50% 0, 100% 100%);
}

.data-table th.sortable.desc .caret {
    clip-path: polygon(0 0, 50% 100%, 100% 0);
}

.data-table th.sortable:not(.asc):not(.desc) .caret {
    display: none;
}

/* A subtotal or section head inside a statement. */
.report-section-head th,
.data-table tr.section-head td {
    height: 36px;
    background: var(--bg-input);
    border-bottom: 1px solid var(--hairline);
    font: 700 12px/1.4 var(--font-ui);
    letter-spacing: 0.3px;
    text-transform: none;
    color: var(--text-secondary);
}

.report-total td,
.data-table tr.total td {
    font-weight: 600;
    background: var(--bg-input);
    border-top: 1px solid var(--border-control);
}

/* ------------------------------------------------------------------- pager */
/* The count always states both the window and the sort, so a reader never
   has to guess what they are looking at nine rows of. */
.pager {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-16);
    width: 100%;
    padding: 12px 16px;
    border-top: 1px solid var(--hairline);
    background: var(--bg-card);
}

.pager-info {
    flex: 1 1 0;
    min-width: 0;
    font: 400 12px/1.4 var(--font-ui);
    color: var(--text-tertiary);
}

.pager-controls {
    display: flex;
    align-items: center;
    gap: var(--space-8);
    flex-shrink: 0;
}

/* ------------------------------------------------------- collection states */

/* U/StateBlock. Every collection has to be able to say it is empty, that it
   is loading, or that it failed — in words, not with a spinner alone. */
.state-block,
.loading:not(:has(*)) {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-8);
    padding: 48px 24px;
    text-align: center;
    background: var(--bg-card);
    border-radius: var(--radius-control);
    box-shadow: var(--shadow-card);
}

.state-block .state-title {
    font: 600 14px/1.5 var(--font-ui);
    color: var(--text-primary);
}

/* A content pane starts life holding only its loading sentence. Once a screen
   has painted into it the pane holds elements, so the block styling drops away
   and the screen's own layout takes over - no class juggling in every loader. */
.loading:not(:has(*)) {
    font: 400 14px/1.5 var(--font-ui);
    color: var(--text-secondary);
}

.loading:has(*) {
    display: flex;
    flex-direction: column;
    gap: var(--space-16);
}

.state-block .state-body {
    max-width: 420px;
    font: 400 13px/1.5 var(--font-ui);
    color: var(--text-secondary);
}

.state-block .state-actions {
    display: flex;
    gap: var(--space-8);
    margin-top: var(--space-4);
}

.state-block.error .state-title {
    color: var(--mark-error);
}

.error-message {
    display: none;
    padding: 10px 12px;
    border-radius: var(--radius-control);
    background: var(--error-container);
    color: var(--on-error-container);
    font: 400 13px/1.5 var(--font-ui);
}

.error-message.show {
    display: block;
}

/* ============================================================ auth screens */

/* Signing in has no shell — no top bar, no rail, no book, because you are
   not inside a book yet. The brand panel carries the identity instead. */
.auth-page {
    display: none;
    height: 100vh;
    background: var(--bg-paper);
}

/* Wins over the generic .page.active, which stacks a screen's blocks into a
   column: signing in is two side-by-side panels, not a stack. */
.auth-page.active {
    display: flex;
    flex-direction: row;
    align-items: stretch;
    gap: 0;
}

.brand-panel {
    width: 620px;
    flex: 0 0 620px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: space-between;
    padding: 40px 48px;
    background: var(--surface-brand);
    color: var(--on-brand);
    overflow: hidden;
}

.brand-logo {
    display: flex;
    align-items: center;
    gap: var(--space-12);
}

.brand-logo svg {
    width: 36px;
    height: 36px;
    display: block;
}

.brand-logo span {
    font: 600 16px/1.4 var(--font-ui);
    white-space: nowrap;
}

.brand-hero {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 20px;
    width: 430px;
    max-width: 100%;
}

.brand-hero .hero-rule {
    width: 56px;
    height: 3px;
    border-radius: var(--radius-control);
    background: var(--brand-secondary);
}

.brand-hero h2 {
    font: 700 26px/1.15 var(--font-ui);
    color: var(--on-brand);
}

.brand-hero p {
    font: 400 13px/1.5 var(--font-ui);
    color: rgba(255, 255, 255, 0.65);
}

.brand-footer {
    font: 400 11px/1.4 var(--font-ui);
    color: rgba(255, 255, 255, 0.4);
    white-space: nowrap;
}

.auth-form-area {
    position: relative;
    flex: 1 0 0;
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: auto;
    padding: 24px 16px;
}

/* The language pill sits clear of the card, 24 from the top and 38 from the
   right edge of the form column. */
.auth-lang {
    position: absolute;
    top: 24px;
    right: 38px;
    padding: 8px 16px;
    border: 1px solid rgba(24, 24, 32, 0.12);
    border-radius: var(--radius-pill);
    background: var(--bg-card);
    color: var(--text-primary);
    font: 500 12px/1.4 var(--font-ui);
    white-space: nowrap;
    cursor: pointer;
}

.auth-lang:hover {
    background: var(--row-hover);
}

/* The auth card's inputs are deliberately not U/Field: 38px on a white
   ground, because this card is the only place in the product where a form
   sits on paper rather than inside a working surface. */
.auth-card {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 20px;
    width: 100%;
    max-width: 420px;
    padding: 36px;
    background: var(--bg-card);
    border: 1px solid rgba(24, 24, 32, 0.08);
    border-radius: var(--radius-control);
    box-shadow: 0 8px 24px -4px rgba(24, 24, 32, 0.06);
}

.auth-title {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.auth-title h1 {
    font: 700 26px/1.15 var(--font-ui);
    color: var(--text-primary);
}

.auth-title p {
    font: 400 13px/1.5 var(--font-ui);
    color: var(--text-secondary);
}

.auth-field {
    display: flex;
    flex-direction: column;
    gap: var(--space-8);
}

.auth-field label {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    font: 500 12px/1.4 var(--font-ui);
    color: var(--text-primary);
}

.auth-field input {
    height: 38px;
    width: 100%;
    padding: 0 12px 0 16px;
    border: 1px solid rgba(24, 24, 32, 0.16);
    border-radius: var(--radius-control);
    background: var(--bg-card);
    color: var(--text-primary);
    font: 400 13px/1.5 var(--font-ui);
}

.auth-field input::placeholder {
    color: var(--text-tertiary);
}

.auth-field input.error {
    border: 2px solid var(--error);
}

/* Collapsed until there is something to say. The design's field is exactly
   label + 8 + input and reserves nothing, which is what makes the card 397
   tall; a permanently reserved row put 25px under every field and pushed the
   whole card out of shape. */
.auth-field .msg {
    font: 400 12px/1.4 var(--font-ui);
    color: var(--error);
}

.auth-field .msg:empty {
    display: none;
}

.auth-submit {
    width: 100%;
    height: 45px;
    padding: 12px 0;
    border: 0;
    border-radius: var(--radius-control);
    background: var(--brand);
    color: var(--on-brand);
    font: 600 14px/1.5 var(--font-ui);
    cursor: pointer;
}

.auth-submit:hover:not(:disabled) { background: var(--brand-hover); }
.auth-submit:active:not(:disabled) { background: var(--brand-pressed); }

.auth-submit:disabled {
    background: var(--bg-sunken);
    color: var(--text-secondary);
    cursor: default;
}

.auth-link {
    align-self: flex-start;
    border: 0;
    background: transparent;
    padding: 0;
    font: 400 13px/1.5 var(--font-ui);
    color: var(--text-secondary);
    cursor: pointer;
}

.auth-link:hover {
    color: var(--text-primary);
    text-decoration: underline;
}

@media (max-width: 1000px) {
    .brand-panel {
        display: none;
    }
}

@media (max-width: 480px) {
    .auth-card {
        padding: 24px 20px;
    }

    .auth-lang {
        right: 16px;
    }
}

/* ================================================== dialogs and messages */

/* A dialog is pinned 150px from the top rather than centred: a dialog that
   grows should grow downwards, so its head never moves. */
.modal-overlay {
    position: fixed;
    inset: 0;
    z-index: 100;
    display: none;
    align-items: flex-start;
    justify-content: center;
    padding: 150px 24px 24px;
    background: rgba(31, 39, 51, 0.45);
    overflow-y: auto;
}

.modal-overlay.show {
    display: flex;
}

.modal {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    width: 540px;
    max-width: 100%;
    background: var(--bg-card);
    border-radius: var(--radius-surface);
    box-shadow: 0 14px 44px rgba(0, 0, 0, 0.24);
    overflow: hidden;
}

.modal-header {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-12);
    padding: 24px 24px 16px;
}

/* The consequence badge says what pressing the main button will actually do
   before the user reads the title. */
.modal-consequence {
    padding: 4px 12px;
    border-radius: var(--radius-pill);
    background: var(--error-container);
    color: var(--on-error-container);
    font: 600 11px/1.4 var(--font-ui);
    white-space: nowrap;
}

.modal-header h2 {
    font: 700 20px/1.25 var(--font-ui);
    color: var(--text-primary);
}

.modal-header p,
.modal-lede {
    font: 400 13px/1.5 var(--font-ui);
    color: var(--text-secondary);
}

.modal-close {
    position: absolute;
    top: 20px;
    inset-inline-end: 20px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: 0;
    border-radius: var(--radius-control);
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
}

.modal-close:hover {
    background: var(--row-hover);
    color: var(--text-primary);
}

.modal-close svg {
    width: 16px;
    height: 16px;
    stroke: currentColor;
    stroke-width: 1.5;
    fill: none;
    stroke-linecap: round;
}

.modal-body {
    display: flex;
    flex-direction: column;
    gap: var(--space-12);
    padding: 0 24px 20px;
}

.modal-body:empty {
    display: none;
}

/* The quiet panel that explains a consequence the form itself cannot. */
.modal-slot {
    padding: 12px 16px;
    border-radius: var(--radius-control);
    background: var(--bg-sunken);
    font: 400 12px/1.4 var(--font-ui);
    color: var(--text-secondary);
}

.modal-footer {
    display: flex;
    align-items: center;
    gap: var(--space-12);
    padding: 16px 24px 20px;
    border-top: 1px solid rgba(24, 24, 32, 0.1);
    background: var(--bg-paper);
}

.modal-footer:empty {
    display: none;
}

.modal-footer .gap {
    flex: 1 0 0;
}

.modal-footer > .btn:first-child:last-child {
    margin-inline-start: auto;
}

/* ------------------------------------------------------------------ toasts */

.toast-container {
    position: fixed;
    bottom: 24px;
    inset-inline-end: 24px;
    z-index: 200;
    display: flex;
    flex-direction: column;
    gap: var(--space-8);
    max-width: 380px;
}

.toast {
    display: flex;
    align-items: flex-start;
    gap: var(--space-12);
    padding: 12px 16px;
    border-radius: var(--radius-control);
    background: var(--bg-card);
    box-shadow: var(--shadow-modal);
    border-inline-start: 3px solid var(--mark-neutral);
    font: 400 13px/1.5 var(--font-ui);
    color: var(--text-primary);
}

.toast.success { border-inline-start-color: var(--mark-success); }
.toast.error   { border-inline-start-color: var(--mark-error); }

.toast.info    { border-inline-start-color: var(--focus-ring); }

.toast-close {
    margin-inline-start: auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    flex-shrink: 0;
    border: 0;
    background: transparent;
    color: var(--text-tertiary);
    cursor: pointer;
}

.toast-close svg {
    width: 14px;
    height: 14px;
    stroke: currentColor;
    stroke-width: 1.5;
    fill: none;
    stroke-linecap: round;
}

/* ================================================================= screens */

/* ---------------------------------------------------------------- dashboard */

/* The dashboard answers one question — is the month finished, and can you
   trust it — so it carries no totals. Balances live on the ledger. */
.dash-context {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    font: 400 12px/1.4 var(--font-ui);
    color: var(--text-secondary);
}

.dash-context strong {
    font-weight: 600;
    color: var(--text-primary);
}

.dash-context .sep {
    color: var(--text-tertiary);
}

.progress-track {
    height: 6px;
    width: 100%;
    border-radius: var(--radius-pill);
    background: var(--bg-sunken);
    overflow: hidden;
}

.progress-fill {
    height: 6px;
    background: var(--mark-success);
}

/* What is not settled yet. A blocking item stops the month closing; an
   advisory one only asks you to look. */
.attention-list {
    display: flex;
    flex-direction: column;
}

.attention-row {
    display: flex;
    align-items: center;
    gap: var(--space-12);
    padding: 12px 20px;
    border-top: 1px solid var(--hairline);
}

.attention-row:first-child {
    border-top: 0;
}

.attention-mark {
    display: flex;
    align-items: center;
    gap: var(--space-8);
    width: 112px;
    flex-shrink: 0;
    font: 600 12px/1.4 var(--font-ui);
    color: var(--mark-neutral);
}

.attention-mark::before {
    content: "";
    width: 10px;
    height: 10px;
    border-radius: var(--radius-pill);
    background: var(--mark-neutral);
    flex-shrink: 0;
}

.attention-row.level-attention .attention-mark {
    color: var(--mark-error);
}

.attention-row.level-attention .attention-mark::before {
    background: var(--mark-error);
}

.attention-row.level-action .attention-mark {
    color: var(--mark-warning);
}

.attention-row.level-action .attention-mark::before {
    background: transparent;
    box-shadow: inset 0 0 0 2px var(--mark-warning);
}

.attention-row.level-note .attention-mark {
    color: var(--mark-neutral);
}

.attention-row.level-note .attention-mark::before {
    background: var(--mark-neutral);
}

.attention-text {
    display: flex;
    flex-direction: column;
    gap: 3px;
    flex: 1 0 0;
    min-width: 0;
}

.attention-title {
    font: 600 14px/1.5 var(--font-ui);
    color: var(--text-primary);
}

.attention-detail {
    font: 400 12px/1.4 var(--font-ui);
    color: var(--text-secondary);
}

.attention-row .btn {
    flex-shrink: 0;
}

/* The cleared band closes the card: what has already passed, in one line. */
.attention-clear {
    display: flex;
    flex-direction: column;
    gap: var(--space-8);
    padding: 16px 20px;
    background: var(--bg-input);
    border-top: 1px solid var(--hairline);
}

.attention-clear p {
    display: flex;
    align-items: center;
    gap: 6px;
    font: 400 12px/1.4 var(--font-ui);
    color: var(--text-secondary);
}

/* Counts. How much there is of each thing, and a way into each — a question
   you can answer out loud with somebody watching. */
.count-row {
    display: flex;
    flex-direction: column;
}

.count-tile {
    display: flex;
    align-items: center;
    gap: var(--space-8);
    width: 100%;
    padding: 10px 20px;
    border: 0;
    border-top: 1px solid var(--hairline);
    background: var(--bg-card);
    cursor: pointer;
    text-align: start;
}

.count-tile:first-child {
    border-top: 0;
}

/* Inside a sunken panel the rows take the panel's ground, not the card's. */
.card-sunken .count-tile {
    background: transparent;
}

.count-tile:hover {
    background: var(--row-hover);
}

.count-tile .gap {
    flex: 1 0 0;
}

.count-number {
    font: 600 13px/1.5 var(--font-num);
    color: var(--text-primary);
}

.count-label {
    font: 400 13px/1.5 var(--font-ui);
    color: var(--text-primary);
}

/* The position stays folded: it is the one thing an owner does not want on
   screen while a customer is at the desk. */
.dash-position {
    background: var(--bg-card);
    border-radius: var(--radius-control);
    box-shadow: var(--shadow-card);
    overflow: hidden;
}

.dash-position > summary {
    display: flex;
    align-items: center;
    gap: var(--space-8);
    padding: 14px 20px;
    font: 700 16px/1.4 var(--font-ui);
    color: var(--text-primary);
    cursor: pointer;
    list-style: none;
}

.dash-position > summary::-webkit-details-marker {
    display: none;
}

.dash-position > summary::before {
    content: "";
    width: 8px;
    height: 8px;
    border-inline-end: 1.5px solid var(--text-tertiary);
    border-bottom: 1.5px solid var(--text-tertiary);
    transform: rotate(-45deg);
    transition: transform 0.15s ease;
}

[dir="rtl"] .dash-position > summary::before {
    transform: rotate(135deg);
}

.dash-position[open] > summary::before {
    transform: rotate(45deg);
}

.dash-position > summary:hover {
    background: var(--row-hover);
}

/* The type mix bars under the position. */
.bar-row {
    display: flex;
    align-items: center;
    gap: var(--space-12);
    padding: 10px 20px;
    border-top: 1px solid var(--hairline);
}

.bar-name {
    width: 160px;
    flex-shrink: 0;
    font: 400 13px/1.5 var(--font-ui);
    color: var(--text-primary);
}

.bar-name small {
    display: block;
    font: 400 12px/1.4 var(--font-ui);
    color: var(--text-tertiary);
}

.bar-track {
    flex: 1 0 0;
    height: 6px;
    border-radius: var(--radius-pill);
    background: var(--bg-sunken);
    overflow: hidden;
}

.bar-fill {
    height: 6px;
    background: var(--brand);
}

.bar-value {
    width: 140px;
    flex-shrink: 0;
    text-align: end;
    font: 600 13px/1.5 var(--font-num);
    color: var(--text-primary);
}

/* ----------------------------------------------------------------- settings */

.settings {
    display: flex;
    flex-direction: column;
    gap: var(--space-16);
}

.settings-panel {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-16);
}

@media (min-width: 900px) {
    .settings-panel {
        grid-template-columns: 1fr 1fr;
    }
}

.settings-col {
    display: flex;
    flex-direction: column;
    gap: var(--space-16);
}

.settings-section {
    background: var(--bg-card);
    border-radius: var(--radius-control);
    box-shadow: var(--shadow-card);
    overflow: hidden;
}

.settings-section > h3 {
    padding: 16px 20px 12px;
    font: 700 16px/1.4 var(--font-ui);
    color: var(--text-primary);
}

.settings-note {
    padding: 0 20px 12px;
    font: 400 12px/1.4 var(--font-ui);
    color: var(--text-secondary);
}

.settings-rows {
    display: flex;
    flex-direction: column;
}

.settings-row {
    display: flex;
    align-items: center;
    gap: var(--space-12);
    padding: 12px 20px;
    border-top: 1px solid var(--hairline);
}

.settings-label {
    flex: 1 0 0;
    min-width: 0;
    font: 400 13px/1.5 var(--font-ui);
    color: var(--text-primary);
}

.settings-sub {
    display: block;
    font: 400 12px/1.4 var(--font-ui);
    color: var(--text-tertiary);
}

.settings-value {
    font: 600 13px/1.5 var(--font-num);
    color: var(--text-primary);
    white-space: nowrap;
}

/* U/Segmented. One choice out of a few, where tabs would overstate it: the
   options are readings of the same thing rather than places to be. Used for
   the interface language and for which statement is on screen. */
.segmented {
    display: inline-flex;

    /* A content pane is a column flex container, which stretches its children
       across it. Without this the control spans the whole screen with its
       options huddled at one end. */
    align-self: flex-start;
    border: 1px solid var(--border-control);
    border-radius: var(--radius-control);
    overflow: hidden;
}

.segmented button,
.segmented a {
    display: inline-flex;
    align-items: center;
    padding: 8px 14px;
    border: 0;
    text-decoration: none;
    white-space: nowrap;
    background: var(--bg-card);
    color: var(--text-secondary);
    font: 600 13px/1.5 var(--font-ui);
    cursor: pointer;
}

.segmented button + button,
.segmented a + a {
    border-inline-start: 1px solid var(--border-control);
}

.segmented button:hover:not(.active),
.segmented a:hover:not(.active) {
    background: var(--row-hover);
}

.segmented button.active,
.segmented a.active {
    background: var(--surface-brand);
    color: var(--on-brand);
}

.settings-row .currency-select {
    width: auto;
    min-width: 120px;
}

/* A text field in a settings row.
 *
 * .field-input is written for a form, where a control has the width of the
 * column it is in. A settings row is not that: it is a label on one side and
 * whatever acts on it on the other, so a field claiming 100% pushes the label
 * out from under itself and the two print over each other. This gives it a
 * width to want and lets it shrink, the same arrangement the currency select
 * beside it already had. */
.settings-row .settings-input {
    width: auto;
    flex: 0 1 320px;
    min-width: 180px;
}

/* ----------------------------------------------------------------- reports */

.report {
    background: var(--bg-card);
    border-radius: var(--radius-control);
    box-shadow: var(--shadow-card);
    overflow: hidden;
}

/* The letterhead a printed statement needs and a screen does not.
   
   On screen it repeats three things that are already on the page: the tab says
   which statement, the book strip says whose books, and the toolbar says what
   it covers. On paper none of those survive - the rail, the tabs and the
   toolbar are all dropped - and a sheet that does not say what it is, whose it
   is and as at when is not a statement anybody can file. So it prints and does
   not show. */
.report-heading {
    display: none;
    flex-direction: column;
    gap: var(--space-4);
    padding: 20px 24px 16px;
    text-align: center;
}

.report-heading h2 {
    font: 700 20px/1.25 var(--font-ui);
    color: var(--text-primary);
}

.report-company {
    font: 600 13px/1.5 var(--font-ui);
    color: var(--text-secondary);
}

.report-date {
    font: 400 12px/1.4 var(--font-num);
    color: var(--text-tertiary);
}

.report-note {
    padding: 12px 24px 16px;
    font: 400 12px/1.4 var(--font-ui);
    color: var(--text-tertiary);
}

.report-table td {
    height: 28px;
}

/* ------------------------------------------------------ shared small parts */

.currency-select {
    width: auto;
    min-width: 110px;
    height: 34px;
    padding: 6px 10px;
    cursor: pointer;
}

.currency-select:disabled {
    background: var(--bg-sunken);
    color: var(--text-secondary);
    cursor: default;
}

/* Hiding the figures is discretion, not access control: the numbers are
   still fetched and anyone can turn them back on. */
.amount-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    height: 34px;
    padding: 0 12px;
    border: 1px solid var(--border-ghost);
    border-radius: var(--radius-control);
    background: var(--bg-card);
    color: var(--text-secondary);
    font: 600 13px/1.5 var(--font-ui);
    cursor: pointer;
}

.amount-toggle:hover {
    background: var(--row-hover);
}

.amount-toggle[aria-pressed="true"] {
    background: var(--bg-sunken);
    color: var(--text-primary);
}

.amount-toggle .ui-icon {
    width: 16px;
    height: 16px;
    stroke: currentColor;
    stroke-width: 1.5;
    fill: none;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.ui-icon {
    width: 16px;
    height: 16px;
    stroke: currentColor;
    stroke-width: 1.5;
    fill: none;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    flex-shrink: 0;
}

.icon svg {
    width: 16px;
    height: 16px;
    stroke: currentColor;
    stroke-width: 1.5;
    fill: none;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* =================================================================== RTL */

/* The whole product mirrors, including the rail's indicator edge, which has
   to stay on the side the rail is anchored to. */
[dir="rtl"] .rail {
    border-right: 0;
    border-left: 1px solid var(--edge);
}

[dir="rtl"] .nav-item {
    border-left: 3px solid transparent;
    border-right: 3px solid transparent;
}

[dir="rtl"] .nav-item.active {
    border-left-color: transparent;
    border-right-color: var(--nav-indicator);
}

[dir="rtl"] .topbar-icon-btn .count {
    left: auto;
    right: 20px;
}

[dir="rtl"] .scope-pill {
    padding: 5px 5px 5px 12px;
}

[dir="rtl"] .auth-lang {
    right: auto;
    left: 38px;
}

/* Money stays right-aligned relative to reading order, which `end` already
   does; codes stay at the start. Nothing here needs to flip by hand. */

/* ============================================================= responsive */

/* Below 1200 the rail collapses to a drawer: the shell keeps its shape, but
   the rail slides over the content instead of holding a column open. */
@media (max-width: 1200px) {
    :root {
        --rail-width: 220px;
    }

    .content {
        padding: var(--space-24);
    }

    .two-col {
        flex-direction: column;
    }

    .two-col > .col-side {
        width: 100%;
    }
}

/* The drawer's head only exists once the rail is an overlay: at that width the
   book strip is off screen, so the drawer has to name the book itself. */
.rail-head {
    display: none;
    align-items: center;
    gap: var(--space-8);
    width: 100%;
    height: 48px;
    padding: 2px 8px 2px 20px;
    flex-shrink: 0;
}

.rail-head-name {
    flex: 1 0 0;
    min-width: 0;
    font: 700 16px/1.4 var(--font-ui);
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.rail-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    flex-shrink: 0;
    border: 0;
    background: transparent;
    color: var(--text-primary);
    cursor: pointer;
}

.rail-close svg {
    width: 16px;
    height: 16px;
    stroke: currentColor;
    stroke-width: 1.75;
    fill: none;
    stroke-linecap: round;
}

/* Below 900 the rail becomes a 300px overlay drawer, full bleed from the top
   edge, and the top bar sheds everything but the menu, the wordmark and the
   avatar. The scrim covers the bar too; because it is the bar's own colour at
   45%, the bar reads unchanged and only the paper below it dims. */
@media (max-width: 900px) {
    :root {
        --topbar-height: 56px;
    }

    .topbar {
        padding: 6px 8px;
        gap: 6px;
    }

    .topbar-mark,
    .topbar-divider,
    .scope-pill,
    .topbar-icon-btn {
        display: none;
    }

    .rail-toggle {
        display: inline-flex;
        width: 44px;
        height: 44px;
        background: transparent;
    }

    .rail-toggle svg {
        width: 18px;
        height: 12px;
        stroke-width: 2;
    }

    .rail {
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        z-index: 70;
        width: 300px;
        padding: var(--space-16) 0;
        border: 0;
        transform: translateX(-100%);
        transition: transform 0.2s ease;
        box-shadow: 8px 0 32px rgba(0, 0, 0, 0.24);
    }

    [dir="rtl"] .rail {
        left: auto;
        right: 0;
        transform: translateX(100%);
        box-shadow: -8px 0 32px rgba(0, 0, 0, 0.24);
    }

    .rail.open {
        transform: translateX(0);
    }

    .rail-head {
        display: flex;
    }

    /* A drawer item is a tap target, so it is taller and roomier than the
       desktop rail item it mirrors. */
    .nav-item {
        height: 44px;
        padding: 11px 16px 12px;
        gap: 14px;
        font-size: 14px;
    }

    .rail-scrim {
        display: none;
        position: fixed;
        inset: 0;
        z-index: 65;
        background: rgba(31, 39, 51, 0.45);
    }

    .rail-scrim.show {
        display: block;
    }

    /* The book strip compacts; the page title goes, because the breadcrumb
       already names where you are and 390px has no room to say it twice. */
    .bookstrip {
        padding: 14px 16px 12px;
        gap: var(--space-12);
    }

    .bookstrip .avatar {
        width: 34px;
        height: 34px;
    }

    .bookstrip-names {
        gap: 2px;
    }

    .bookstrip-title h1 {
        font-size: 16px;
    }

    .pagehead h1 {
        display: none;
    }

    .content {
        padding: var(--space-16);
    }

    .search-field {
        width: 100%;
    }

    .toolbar {
        gap: var(--space-8);
    }
}

/* The rail toggle only exists once the rail is a drawer. */
.rail-toggle {
    display: none;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    flex-shrink: 0;
    border: 0;
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.12);
    color: var(--on-brand);
    cursor: pointer;
}

.rail-toggle svg {
    width: 18px;
    height: 18px;
    stroke: currentColor;
    stroke-width: 1.5;
    fill: none;
    stroke-linecap: round;
}

@media (max-width: 640px) {
    .bookstrip-meta {
        display: none;
    }

    .data-table th,
    .data-table td {
        padding: 0 12px;
    }

    .data-table th:first-child,
    .data-table td:first-child { padding-inline-start: 16px; }

    .data-table th:last-child,
    .data-table td:last-child { padding-inline-end: 16px; }

    .pager {
        flex-direction: column;
        align-items: stretch;
        gap: var(--space-8);
    }

    .attention-row {
        flex-wrap: wrap;
    }

    .modal-overlay {
        padding: 24px 12px;
        align-items: center;
    }

    .field-row {
        grid-template-columns: 1fr;
    }
}

/* Print: the statements are meant to leave the building on paper. */
@media print {
    .topbar,
    .rail,
    .bookstrip,
    .pagehead-actions,
    .toolbar,
    .pager,
    .tabs,
    .breadcrumb {
        display: none !important;
    }

    body,
    .content {
        overflow: visible;
        background: #fff;
    }

    .card,
    .report {
        box-shadow: none;
        border: 1px solid var(--hairline);
    }

    /* The one thing that appears only on paper - see .report-heading. */
    .report-heading {
        display: flex;
    }
}

/* ------------------------------------------------------- statement period */

/* The date fields live in the toolbar beside the count they qualify - the
   period is the context the figures are read in, which is why the design
   prints "9 accounts · 01/01/2026 - 31/01/2026" as one line. A strip of its
   own put the reset at the opposite edge of the screen from the field it
   resets, and cost a row of the table below it.

   The label sits beside the field rather than above it. This is a filter, not
   a form: it wants to read as one short line above the table it narrows, and
   stacked labels made it as tall as the toolbar it sits under. */
.period-field {
    display: flex;
    align-items: center;
    gap: 6px;
}

.period-field span {
    font: 500 12px/1 var(--font-ui);
    color: var(--text-tertiary);
    white-space: nowrap;
}

.period-field input {
    height: 30px;
    padding: 0 8px;
    font: 400 13px/1 var(--font-num);
    color: var(--text-primary);
    background: var(--bg-input);
    border: 1px solid var(--border-control);
    border-radius: var(--radius-control);
}

.period-field input:focus {
    outline: 2px solid var(--focus-ring);
    outline-offset: 1px;
}

/* The reset is a quiet control beside the fields, not a third thing to read. */
.toolbar .btn-quiet {
    height: 30px;
    padding: 0 10px;
    font-size: 12px;
}

@media (max-width: 640px) {
    .period-field { flex: 1 1 150px; }
    .period-field input { flex: 1; min-width: 0; }
}

/* A row's link. The row is still the pointer target - this is what gives the
   same navigation a focus ring, a place in the tab order and an address on the
   middle-click menu. It inherits its colour because the row already reads as
   one thing; underlining every first cell would turn a table into a list of
   links. */
.data-table .row-link {
    color: inherit;
    text-decoration: none;
}

.data-table .row-link:hover {
    text-decoration: underline;
}

.data-table .row-link:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
    border-radius: 2px;
}
