html, body {
    font-family: var(--rz-text-font-family);
    /* Tabular figures, so amounts line up in every column (parity N7; DESIGN.md, Typography). */
    font-variant-numeric: tabular-nums;
}

h1:focus {
    outline: none;
}

/*
 * The Developer menu is a system-role menu, so it gets its own colour: the accent, which holds 4.5:1 on the shell the menu
 * sits on (DESIGN.md, Contrast). The item inherits color; icons and sub-items take their own variables because Material
 * sets both explicitly.
 */
.system-role-menu {
    --rz-panel-menu-icon-color: var(--sb-accent);
    --rz-panel-menu-item-2nd-level-color: var(--sb-accent);
    color: var(--sb-accent);
}

.rz-dialog-content {
    flex-basis: 100% !important;
}

/* The company's mark and name in the footer, as one link to its site. */
.company-link {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    color: inherit;
    text-decoration: none;
}

.company-link:hover {
    text-decoration: underline;
}

/* SpartaBok's mark at the top left, before the breadcrumbs; it leads to the start page. */
.product-logo {
    display: inline-flex;
    align-items: center;
    margin: 0 0.5rem 0 0.25rem;
}

.product-logo img {
    display: block;
}

/* The annual report as the page shows it (Årsredovisning): plain tables, amounts right-aligned, sums set off. */
.annual-report h3 { margin-top: 2rem; }
.annual-report h4, .annual-report h5 { margin-top: 1.25rem; }
.annual-report-text { white-space: pre-line; }
.annual-report-muted { color: var(--sb-helper-text); }
/* A struck Grundbok line is muted, as on the desktop; Radzen colours the cell content itself, so the row's colour alone
   would not reach it (JournalGrid.razor). */
tr[data-journal-struck] td .rz-cell-data { color: var(--sb-helper-text); }
.annual-report-table { border-collapse: collapse; width: 100%; max-width: 48rem; margin: 0.5rem 0 1rem; }
.annual-report-table th, .annual-report-table td { padding: 0.2rem 0.5rem; vertical-align: top; text-align: left; }
.annual-report-table th { font-weight: 600; border-bottom: 1px solid var(--sb-grid-border); }
.annual-report-table .amount { text-align: right; white-space: nowrap; }
.annual-report-table tr.section td { font-weight: 600; padding-top: 0.75rem; }
.annual-report-table tr.summary td { font-weight: 600; border-top: 1px solid var(--sb-grid-border); }
.annual-report-table tr.grand-total td { font-weight: 700; border-top: 2px solid var(--sb-control-border); }

/* The context bar (UX contract U2): the header's second row across the full width, set off by a 1 px seam, in the
   desktop toolbar's order, with the Årsremsan (parity 1.7) on a row of its own. Below 600 px the company name goes. */
.context-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 1rem;
    padding: 0.375rem 1rem;
    border-top: 1px solid var(--sb-grid-border);
}
.context-bar-company { max-width: 20rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.context-bar-year { min-width: 16rem; }
/* "Året är låst" in the warning text token, which holds 4.5:1 on the shell (DESIGN.md, Contrast). */
.context-bar-locked { font-weight: 600; color: var(--sb-warning-text); }
/* The page failure's sentence is body text, as the status line's; the alert's icon and tint keep the tone (SbErrorBoundary). */
.page-failure-text { color: var(--sb-body-text); }
/* The page's status line (SbStatusLine; DESIGN.md, Status line): sticky at the bottom of the body, and after the page's
   last row once scrolled to the end, so it never covers the last button. It reaches through the body's padding to the
   window's edge, so nothing shows below it, and has no shadow: it is part of the page, not a toast (U5). Its tint is the
   severity's opaque *-panel token and its icon the severity's *-text, so the pairs TokenContrastTests checks are the ones
   drawn. A control the keyboard reaches scrolls clear of it. */
.sb-status-line { position: sticky; bottom: 0; z-index: 2; }
/* Only while it shows something: an empty line must leave the body's padding below the page alone. */
.sb-status-line:has(.sb-status) { bottom: calc(-1 * var(--rz-layout-body-padding)); margin-bottom: calc(-1 * var(--rz-layout-body-padding)); }
.sb-status-line > div:not(:empty) { padding: 1rem 0 var(--rz-layout-body-padding); background-color: var(--sb-window); }
.rz-dialog .sb-status-line:has(.sb-status) { bottom: 0; margin-bottom: 0; }
.rz-dialog .sb-status-line > div:not(:empty) { padding-bottom: 0; background-color: var(--sb-panel); }
.sb-status { display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem 0.75rem; border-radius: var(--rz-border-radius); color: var(--sb-body-text); }
.sb-status-info { background-color: var(--sb-info-panel); }
.sb-status-info .sb-status-icon { color: var(--sb-info-text); }
.sb-status-success { background-color: var(--sb-success-panel); }
.sb-status-success .sb-status-icon { color: var(--sb-success-text); }
.sb-status-warning { background-color: var(--sb-warning-panel); }
.sb-status-warning .sb-status-icon { color: var(--sb-warning-text); }
.sb-status-danger { background-color: var(--sb-danger-panel); }
.sb-status-danger .sb-status-icon { color: var(--sb-danger-text); }
.rz-body:has(.sb-status-line .sb-status) { scroll-padding-bottom: 7rem; }
/* A page of records (SbMasterDetail; DESIGN.md U3, Page anatomy; parity 1.3d): list 2 : detail 3 with a splitter, each
   scrolling on its own in a frame as tall as the window leaves below the header and the page's heading; stacked below
   1050 px of the frame's own width, as the desktop's ResponsiveSplitGrid (A9; CloudPageAnatomyGuardTests holds the two
   numbers equal). The detail's title is DESIGN.md's 20 px, and its action row comes last (U4). */
.sb-master-detail { container-type: inline-size; --sb-master-detail-chrome: 13rem; }
.sb-master-detail > .rz-splitter { height: max(24rem, calc(100dvh - var(--sb-master-detail-chrome))); }
.sb-master-detail .rz-splitter-pane { overflow: auto; }
.sb-master-detail-list { display: flex; flex-direction: column; gap: 0.75rem; padding-right: 0.75rem; }
.sb-master-detail-toolbar:not(:empty) { display: flex; flex-wrap: wrap; align-items: end; gap: 0.5rem; }
.sb-master-detail-list > .sb-record-list { flex: 1 1 0; min-height: 12rem; }
.sb-master-detail-detail { padding-left: 1rem; }
.sb-detail-title { font-size: 20px; font-weight: 600; margin: 0 0 0.75rem; color: var(--sb-heading-text); }
.sb-detail-placeholder { color: var(--sb-helper-text); }
.sb-action-row { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1rem; }
/* A disabled button: no fill, no edge, muted text, as on the desktop (DESIGN.md, Fields and buttons; parity 1.4, F14).
   Radzen fades the whole button to 20 %, about 2:1, and its style and shade rules (.rz-button.rz-primary.rz-shade-default,
   up to four classes for an outlined danger) would keep a disabled button's fill and colour, so the state wins with
   !important: a disabled state is never a style. */
.rz-button.rz-state-disabled, .rz-button:disabled {
    opacity: 1 !important;
    background-color: transparent !important;
    box-shadow: none !important;
    color: var(--sb-muted-text) !important;
}
/* The chosen row: Radzen's selection fill (the selection token) and a 3 px accent bar at its start, as the left menu and
   the desktop's lists mark a choice, since the fill alone is 1.2:1 against the panel (DESIGN.md, Lists; parity 1.4, F8). */
.rz-data-row.rz-state-highlight > td:first-child { box-shadow: inset 3px 0 0 var(--sb-accent); }

/* A file shown in the page (SbFilePreview, DESIGN.md Files and PDFs): a PDF fills the width, an image keeps its shape. */
iframe.sb-file-preview { width: 100%; height: 75vh; border: 1px solid var(--sb-grid-border); }
img.sb-file-preview { max-width: 100%; max-height: 75vh; object-fit: contain; align-self: flex-start; }
/* Radzen draws no ring on the splitter's grip when the keyboard reaches it (U9, WCAG 2.4.7). */
.sb-master-detail .rz-splitter-bar .rz-resize:focus-visible { outline: 2px solid var(--sb-accent); outline-offset: 2px; }
@container (max-width: 1049.98px) {
    .sb-master-detail > .rz-splitter { flex-direction: column; height: auto; --sb-stacked: 1; }
    .sb-master-detail .rz-splitter-pane { flex-basis: auto !important; }
    .sb-master-detail > .rz-splitter > .rz-splitter-bar { display: none; } /* Radzen's own rule loads later */
    .sb-master-detail-list { max-height: 40vh; padding-right: 0; }
    .sb-master-detail-detail { padding: 1rem 0 0; }
}
.context-bar-separator { list-style: none; margin: 0.25rem 0; border-top: 1px solid var(--sb-grid-border); }

/* The Årsremsan (DESIGN.md, Context bar; parity 1.7): a cell per month after Hela året, at least 2rem each, and the Nästa
   line beside them while it fits, else under them (decision F3). The state is a bar: Bokfört filled, Ej bokförd hollow in
   warning, Pågår framed, Kommande a thin line; the chosen period has the accent bar and an accent, semibold word (F8). */
.year-strip-row { flex: 1 1 100%; display: flex; flex-wrap: wrap; align-items: center; gap: 0.25rem 1rem; }
.year-strip { flex: 1 1 36rem; display: flex; gap: 2px; min-width: 0; overflow-x: auto; user-select: none; outline: none; }
.year-strip-cell { flex: 1 0 2rem; min-width: 2rem; display: flex; flex-direction: column; align-items: center; padding: 1px 0.25rem; border: 1px solid transparent; border-radius: 4px; cursor: pointer; }
.year-strip-cell.whole { flex: 0 0 auto; margin-right: 0.375rem; }
.year-strip:focus-visible .year-strip-cell.cursor { border-color: var(--sb-accent); }
.year-strip-year { align-self: flex-start; min-height: 1.1em; font-size: 11px; color: var(--sb-helper-text); }
.year-strip-label { white-space: nowrap; }
.year-strip-cell.future .year-strip-label { color: var(--sb-muted-text); }
.year-strip-cell.chosen .year-strip-label { color: var(--sb-accent); font-weight: 600; }
.year-strip-tick { margin-left: 2px; color: var(--sb-helper-text); }
.year-strip-draft { display: inline-block; width: 5px; height: 5px; margin-left: 2px; border-radius: 50%; vertical-align: middle; background-color: var(--sb-warning-text); }
.year-strip-state { align-self: stretch; box-sizing: border-box; height: 4px; margin-top: 2px; border-radius: 2px; }
.year-strip-cell.booked .year-strip-state { background-color: var(--sb-helper-text); }
.year-strip-cell.not-booked .year-strip-state { border: 1px solid var(--sb-warning-text); }
.year-strip-cell.current .year-strip-state { border: 1px solid var(--sb-control-border); }
.year-strip-cell.future .year-strip-state { border-bottom: 1px solid var(--sb-muted-text); }
.year-strip-markers { position: relative; align-self: stretch; height: 6px; margin-top: 1px; }
.year-strip-marker { position: absolute; top: 0; width: 6px; height: 5px; transform: translateX(-50%); clip-path: polygon(50% 0, 100% 100%, 0 100%); background-color: var(--sb-helper-text); }
.year-strip-marker.next { background-color: var(--sb-accent); }
.year-strip-chosen { align-self: stretch; height: 2px; margin-top: 2px; }
.year-strip-cell.chosen .year-strip-chosen { background-color: var(--sb-accent); }
.year-strip-next { white-space: nowrap; color: var(--sb-helper-text); }

@media (max-width: 600px) {
    .context-bar-company, .context-bar-label { display: none; }
    .context-bar-year { flex: 1 1 12rem; min-width: 10rem; }
    /* The cells keep their month names and the strip scrolls sideways; the Nästa line breaks under it (F3). */
    .year-strip { flex-basis: 100%; }
    .year-strip-cell { flex: 0 0 2.5rem; }
    .year-strip-next { white-space: normal; }
}

/* The header's first row stays one line: the breadcrumbs give way with an ellipsis, and below 600 px only the page's
   own crumb shows. On a narrow screen the footer (tagline and Husiki link; About names the service) gives its height
   to the page (U12). */
.header-start { min-width: 0; flex: 1 1 auto; overflow: hidden; }
.header-start > span { display: flex; min-width: 0; overflow: hidden; } /* Tharga's BreadCrumbs: a span of items. */
.header-start .rz-breadcrumb-item { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

@media (max-width: 600px) {
    .header-start .product-logo, .header-start .rz-breadcrumb-item:not(:last-child) { display: none; }
    .header-start .rz-breadcrumb-item + .rz-breadcrumb-item::before { display: none; }
}

@media (max-width: 768px) {
    .rz-footer { display: none; }
}

/* The left menu's bands (DESIGN.md, Navigation map): a gap before the first shown entry of the menu bar's groups and
   before the first of the cloud's own groups, whichever entries the person's scopes leave. */
.main-menu li:not(.menu-band-lower) + li.menu-band-lower,
.main-menu li:not(.menu-band-cloud) + li.menu-band-cloud { margin-top: 0.75rem; }

/* The left menu: above 768 px the toggle folds it to a rail of icons; below, it is Radzen's drawer (U12). Open, it is
   12rem, which holds its longest entry (Bokföringsinställningar) and leaves a page of records 1056 px at 1280, so the
   list and the detail stay side by side there as on the desktop (parity 1.3d, D5; DESIGN.md Narrow screens). */
@media (min-width: 769px) {
    .main-menu.rz-sidebar-expanded { width: 12rem; }
    .rz-layout > .main-menu.rz-sidebar-collapsed { width: max-content !important; opacity: 1; }
}

/* The open drawer lies over the page, in the body's cell of Radzen's layout grid, instead of pushing it aside. */
@media (max-width: 768px) {
    .rz-layout > .main-menu.rz-sidebar-expanded { grid-area: rz-body; justify-self: start; position: relative; z-index: 3; height: 100%; }
}

/* The lost connection's dialog (Components/Layout/ReconnectModal.razor, from the .NET 10 template): centred over the
   dimmed page like a Radzen dialog, in Radzen's own variables, and within a 320 px screen. Blazor sets one state class
   on it; each line and button shows only in its state. */
.components-reconnect-first-attempt-visible,
.components-reconnect-repeated-attempt-visible,
.components-reconnect-failed-visible,
.components-pause-visible,
.components-resume-failed-visible {
    display: none;
}

#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible,
#components-reconnect-modal.components-reconnect-paused .components-pause-visible,
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible,
#components-reconnect-modal.components-reconnect-retrying,
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible,
#components-reconnect-modal.components-reconnect-failed,
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible {
    display: block;
}

/* Blazor keeps the first attempt's class while it retries; one line per state. */
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-first-attempt-visible {
    display: none;
}

#components-reconnect-modal {
    box-sizing: border-box;
    width: min(20rem, calc(100vw - 2rem));
    margin: 20vh auto;
    padding: var(--rz-dialog-content-padding);
    border: 0;
    border-radius: var(--rz-dialog-border-radius);
    background-color: var(--sb-panel);
    color: var(--sb-body-text);
    box-shadow: var(--rz-dialog-shadow);
}

/* The dialog takes focus when it opens; its buttons show the focus, not its frame. */
#components-reconnect-modal:focus {
    outline: none;
}

#components-reconnect-modal::backdrop {
    background-color: var(--rz-dialog-mask-background-color);
    opacity: 0.5;
}

.components-reconnect-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

#components-reconnect-modal p {
    margin: 0;
    text-align: center;
}

#components-reconnect-modal button {
    padding: 0.5rem 1.5rem;
    border: 0;
    border-radius: var(--rz-button-border-radius);
    background-color: var(--sb-accent);
    color: var(--sb-on-accent);
    font: inherit;
    cursor: pointer;
}

#components-reconnect-modal button:hover {
    background-color: var(--sb-accent-hover);
}

#components-reconnect-modal button:focus-visible {
    outline: var(--rz-outline-focus);
    outline-offset: var(--rz-outline-offset);
}
