/* Base styles on the design tokens (css/tokens.css), following the apple-design skill. Hand-built components;
   Syncfusion only where master plan 6.2 says. Shared patterns (form controls, tabs, cards, tables) are styled once
   here, so the scoped .razor.css files only keep layout. */
*, *::before, *::after {
    box-sizing: border-box;
}

/* The root keeps the browser's size (16px by default, or the user's own), so every rem token means what tokens.css says
   (0.875rem body = 14px, 2.5rem row = 40px). Only the body text is set to the base size; setting it on html too made the
   root 14px and every rem-based size, body text included, 12.5% smaller (phase 12, UX-03). */
html {
    font-size: 100%;
}

html, body {
    margin: 0;
    font-family: var(--font-sans);
    line-height: var(--leading-body);
    letter-spacing: var(--tracking-body);
    color: var(--color-text);
    background: var(--canvas);
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
}

body {
    font-size: var(--font-size-base);
}

h1, h2, h3 {
    letter-spacing: var(--tracking-title);
    line-height: var(--leading-title);
    font-weight: var(--weight-title);
}

h1 {
    margin: 0 0 var(--space-4);
    font-size: var(--font-size-title);
    font-weight: var(--weight-display);
    letter-spacing: var(--tracking-display);
    line-height: var(--leading-display);
}

h1:focus {
    outline: none;
}

a {
    color: var(--color-primary);
    text-underline-offset: 0.15em;
}

a:hover {
    color: var(--color-primary-hover);
}

:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
}

.muted {
    color: var(--color-text-muted);
}

.spacer {
    flex: 1;
}

/* The hidden attribute wins over the display of the page templates (.fill is a flex box). */
[hidden] {
    display: none !important;
}

.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

/* Buttons: they answer the press at once (skill section 1), on transform only. */
.btn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-height: var(--control-height);
    padding: var(--space-1) var(--space-4);
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-sm);
    background: var(--surface);
    box-shadow: var(--shadow-1);
    color: var(--color-text);
    font: inherit;
    font-weight: 550;
    letter-spacing: var(--tracking-small);
    text-decoration: none;
    cursor: pointer;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    transition: transform var(--press-duration) ease-out;
}

.btn:hover {
    background: var(--surface-sunken);
    border-color: var(--line-control);
    color: var(--color-text);
}

.btn:active:not(:disabled) {
    transform: scale(var(--press-scale));
}

.btn:disabled {
    opacity: 0.55;
    cursor: default;
}

/* A leading icon (New +, Print, Export, Upload, Download) sits a little into the button's padding. */
.btn > .icon:first-child {
    flex: none;
    margin-left: calc(var(--space-1) * -1);
}

.btn-primary {
    background: var(--color-primary);
    border-color: var(--color-primary-hover);
    box-shadow: inset 0 1px 0 var(--edge-light), 0 1px 2px var(--primary-shadow);
    color: var(--color-on-primary);
}

.btn-primary:hover {
    background: var(--color-primary-hover);
    border-color: var(--color-primary-hover);
    color: var(--color-on-primary);
}

/* A primary that cannot act yet is neutral, never a pale orange that reads like a pressed state. */
.btn-primary:disabled, .btn-primary:disabled:hover {
    opacity: 1;
    background: var(--surface-sunken);
    border-color: var(--line);
    box-shadow: none;
    color: var(--color-text-muted);
}

/* Destructive actions are outlined red at rest and fill only on hover (DESIGN-SYSTEM.md section 4.2); solid red is kept for
   the confirm step (.btn-danger-solid). */
.btn-danger {
    background: var(--surface);
    border-color: color-mix(in srgb, var(--color-danger) 45%, var(--surface));
    color: var(--color-danger);
}

.btn-danger:hover, .btn-danger-solid {
    background: var(--color-danger);
    border-color: var(--color-danger);
    color: var(--color-on-primary);
}

.btn-danger-solid:hover {
    background: color-mix(in srgb, var(--color-danger) 85%, black);
    border-color: color-mix(in srgb, var(--color-danger) 85%, black);
    color: var(--color-on-primary);
}

.btn-danger:disabled:hover {
    background: var(--surface);
    color: var(--color-danger);
}

.btn-link {
    border-color: transparent;
    background: transparent;
    box-shadow: none;
    color: var(--color-primary);
    padding-inline: var(--space-2);
}

.btn-link:hover {
    background: transparent;
    color: var(--color-primary-hover);
    text-decoration: underline;
    text-underline-offset: 0.15em;
}

/* Forms. Plain controls are styled by element so every page gets the same edge, radius and focus ring; the
   :where() keeps the specificity at zero for the few layout tweaks in scoped CSS. Syncfusion's own inputs (e-control,
   e-input, anything inside one) follow the Syncfusion theme instead. */
.field {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    margin-bottom: var(--space-4);
}

.field > label,
.field > span:first-child,
.price-machines > label {
    font-size: var(--font-size-sm);
    font-weight: var(--weight-emph);
    letter-spacing: var(--tracking-small);
}

/* The native file chooser button follows the button style. */
::file-selector-button {
    margin-right: var(--space-3);
    padding: var(--space-1) var(--space-3);
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--color-text);
    font: inherit;
    cursor: pointer;
}

:where(:is(input, select, textarea):not([type="checkbox"], [type="radio"], [type="range"], [type="file"], [type="hidden"], [type="submit"], [type="button"], [type="color"], .e-control, .e-input, .e-control *)) {
    min-height: var(--control-height);
    padding: var(--space-1) var(--space-3);
    border: 1px solid var(--line-control);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--color-text);
    font: inherit;
    letter-spacing: var(--tracking-body);
}

:where(textarea:not(.e-control, .e-input)) {
    padding-block: var(--space-2);
}

/* One select look on every system: no OS chevron, the app's own in the muted text colour (the value of --color-text-muted;
   a data URI cannot read a variable). */
:where(select:not([multiple], [size], .e-control, .e-input, .e-control *)) {
    appearance: none;
    padding-right: 2.25rem;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235f5b55' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
    background-position: right var(--space-3) center;
    background-repeat: no-repeat;
    background-size: 1rem;
    text-overflow: ellipsis;
    cursor: pointer;
}

/* A native input or select inside a grid cell: the base rules skip everything inside a Syncfusion control, so a cell asks for the
   same look with this class, at the small control height to fit a row (UX-16). */
.e-grid :is(input, select).cell-control:not([type="checkbox"], [type="radio"]) {
    min-height: var(--control-height-sm);
    padding: var(--space-1) var(--space-3);
    border: 1px solid var(--line-control);
    border-radius: var(--radius-sm);
    background-color: var(--surface);
    color: var(--color-text);
    font: inherit;
}

/* As specific as the rule above and after it, so the chevron and its room win (UX-20: the pager's page size showed no chevron). */
.e-grid select.cell-control:not([multiple], [size]) {
    appearance: none;
    padding-right: 2.25rem;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235f5b55' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
    background-position: right var(--space-3) center;
    background-repeat: no-repeat;
    background-size: 1rem;
    text-overflow: ellipsis;
    cursor: pointer;
}

.e-grid :is(input, select).cell-control:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 1px;
}

/* The search field's own clear button replaces the browser's. */
input[type="search"]::-webkit-search-cancel-button {
    appearance: none;
}

:where(:is(input, select, textarea):not([type="checkbox"], [type="radio"], [type="range"], [type="file"], [type="hidden"], [type="submit"], [type="button"], [type="color"], .e-control, .e-input, .e-control *):focus-visible) {
    outline: none;
    border-color: var(--color-focus);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-focus) 28%, transparent);
}

:where(:is(input, select, textarea):not([type="checkbox"], [type="radio"], [type="range"], [type="file"], [type="hidden"], [type="submit"], [type="button"], [type="color"], .e-control, .e-input, .e-control *)[readonly]) {
    background: var(--surface-sunken);
}

:where(input, select, textarea):disabled {
    opacity: 0.6;
    cursor: default;
}

/* Checkboxes and radios drawn by the app, the same on every system: a white box with the control edge, filled orange when on
   with a white check (the white in the data URI is --color-on-primary). Syncfusion's own checkboxes are left alone. */
:where(input:is([type="checkbox"], [type="radio"]):not(.e-control, .e-checkbox)) {
    appearance: none;
    display: inline-grid;
    flex: none;
    place-content: center;
    width: 1.125rem;
    height: 1.125rem;
    margin: 0;
    border: 1px solid var(--line-control);
    border-radius: 5px;
    background: var(--surface) center / 0.875rem no-repeat;
    vertical-align: middle;
    cursor: pointer;
    transition: transform var(--press-duration) ease-out;
}

:where(input[type="radio"]:not(.e-control)) {
    border-radius: 50%;
}

:where(input[type="checkbox"]:not(.e-control, .e-checkbox):checked) {
    border-color: var(--color-primary);
    background-color: var(--color-primary);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12.5 4.5 4.5L19 7.5'/%3E%3C/svg%3E");
}

:where(input[type="checkbox"]:not(.e-control, .e-checkbox):indeterminate) {
    border-color: var(--color-primary);
    background-color: var(--color-primary);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round'%3E%3Cpath d='M6 12h12'/%3E%3C/svg%3E");
}

:where(input[type="radio"]:not(.e-control):checked) {
    border: 0.3125rem solid var(--color-primary);
}

:where(input:is([type="checkbox"], [type="radio"]):not(.e-control, .e-checkbox)):active:not(:disabled) {
    transform: scale(0.92);
}

:where(input:is([type="checkbox"], [type="radio"]):not(.e-control, .e-checkbox)):focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
}

/* A switch (class="switch" on a checkbox) for settings that take effect at once: a pill track, a white knob that slides. */
input[type="checkbox"].switch {
    justify-content: start;
    width: 2rem;
    height: 1.125rem;
    padding: 0.125rem;
    border: 0;
    border-radius: var(--radius-pill);
    background: var(--line-strong);
}

input[type="checkbox"].switch::before {
    content: "";
    width: 0.875rem;
    height: 0.875rem;
    border-radius: 50%;
    background: var(--surface);
    box-shadow: var(--shadow-1);
    transition: transform var(--press-duration) ease-out;
}

input[type="checkbox"].switch:checked {
    background: var(--color-primary);
}

input[type="checkbox"].switch:checked::before {
    transform: translateX(0.875rem);
}

.check {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-4);
}

.form-error, .validation-message {
    color: var(--color-danger);
}

.form-error {
    background: var(--color-danger-bg);
    border-radius: var(--radius-sm);
    padding: var(--space-2) var(--space-3);
}

.invalid {
    outline: 1px solid var(--color-danger);
}

.logout-form {
    display: inline;
    margin: 0;
}

/* Sign-in pages (AuthLayout) */
.auth-layout {
    background: radial-gradient(ellipse 60rem 28rem at 50% -8%, var(--accent-soft), transparent), var(--canvas);
    min-height: 100vh;
    display: grid;
    place-items: center;
    padding: var(--space-4);
}

.auth-card {
    width: min(100%, 24rem);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-2);
    padding: var(--space-6);
    animation: var(--anim-enter);
}

.auth-brand {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-5);
}

.auth-brand h1 {
    margin: 0;
}

.auth-brand-name {
    font-weight: var(--weight-title);
    letter-spacing: var(--tracking-title);
}

/* The sign-in card: the brand as a quiet line, then what the page is for. */
.auth-title {
    margin: 0;
    font-size: var(--font-size-title);
    letter-spacing: var(--tracking-display);
}

.auth-sub {
    margin: var(--space-1) 0 var(--space-5);
    color: var(--color-text-muted);
}

.auth-brand .brand-mark {
    width: 2.5rem;
    height: 2.5rem;
}

.login-form .btn-primary {
    width: 100%;
    justify-content: center;
}

/* Stand-alone messages (StatusCard, UX-19): a glyph, a title, one line, one action, centered. */
.status-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-3);
    width: min(100%, 26rem);
    text-align: center;
}

.status-card h1 {
    margin: 0;
    font-size: var(--font-size-lg);
    font-weight: var(--weight-title);
    letter-spacing: var(--tracking-title);
}

.status-card p {
    margin: 0;
    color: var(--color-text-muted);
}

.status-card-icon {
    display: inline-grid;
    place-items: center;
    width: 3rem;
    height: 3rem;
    border-radius: 50%;
    background: var(--surface-sunken);
    color: var(--color-text-muted);
}

.status-card-icon.status-card-error {
    background: var(--color-danger-bg);
    color: var(--color-danger);
}

.status-card-icon.status-card-warning {
    background: var(--color-warning-bg);
    color: var(--color-warning);
}

.status-card-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--space-2) var(--space-3);
    margin-top: var(--space-2);
}

/* The same card inside the shell (not found, an error in a page): centered in the room the page has. */
.state-page {
    display: grid;
    flex: 1 1 auto;
    place-items: center;
    min-height: 60vh;
}

/* Shell (P1-03, redesigned): a dark ink sidebar for structure and wayfinding, a light canvas for work. The sidebar
   is the heaviest layer (skill section 12), content sits on white cards with a hairline and a soft shadow. */
.app-main {
    padding: var(--space-5);
}

.shell {
    display: grid;
    grid-template-columns: var(--sidebar-width) minmax(0, 1fr);
    grid-template-rows: var(--header-height) 1fr;
    grid-template-areas: "nav header" "nav main";
    min-height: 100dvh;
}

.shell-header {
    grid-area: header;
    position: sticky;
    top: 0;
    z-index: var(--z-sticky);
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 0 clamp(1rem, 3vw, 2.5rem);
    background: var(--canvas);
    border-bottom: 1px solid var(--line);
}

/* Desktop only, one surface per screen (skill rule 0.2): the header lets the page show through a little. */
@media (pointer: fine) {
    .shell-header {
        background: color-mix(in srgb, var(--canvas) 80%, transparent);
        backdrop-filter: blur(16px) saturate(160%);
    }
}

.shell-nav {
    grid-area: nav;
    position: sticky;
    top: 0;
    align-self: start;
    height: 100vh;
    display: flex;
    flex-direction: column;
    padding: 0 var(--space-3) var(--space-4);
    background: var(--sidebar);
    color: var(--nav-text);
    overflow-y: auto;
    overscroll-behavior: contain;
}

/* Phase 12 frame (UX-02): main is a column that fills the viewport under the header, so a page template can take the
   remaining height (lists scroll inside their card) or push its action bar to the bottom edge. The paddings are variables
   because the list height and the action bar's full-bleed margins are worked out from them. */
.shell-main {
    --main-pad-x: clamp(1rem, 3vw, 2.5rem);
    --main-pad-top: var(--space-6);
    --main-pad-bottom: var(--space-6);
    grid-area: main;
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: calc(100dvh - var(--header-height));
    padding: var(--main-pad-top) var(--main-pad-x) var(--main-pad-bottom);
}

.brand, .header-brand {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    color: var(--nav-text-strong);
    font-size: 1.0625rem;
    font-weight: 650;
    letter-spacing: var(--tracking-title);
    text-decoration: none;
}

.brand {
    flex: none;
    height: var(--header-height);
    margin-bottom: var(--space-2);
    padding: 0 var(--space-2);
}

.brand:hover, .brand:focus-visible {
    color: var(--nav-text-strong);
}

.header-brand {
    display: none;
    color: var(--color-text);
}

.header-brand:hover {
    color: var(--color-text);
}

.brand-mark {
    flex: none;
    border-radius: 9px;
    box-shadow: 0 2px 8px var(--brand-glow);
}

.btn-icon {
    padding: var(--space-2);
    line-height: 0;
}

/* Small buttons, inside tables, toolbars and pagers. */
.btn-sm {
    min-height: var(--control-height-sm);
    padding: var(--space-1) var(--space-3);
    font-size: var(--font-size-sm);
}

.btn-icon.btn-sm {
    justify-content: center;
    min-width: var(--control-height-sm);
    padding: var(--space-1);
}

.nav-toggle {
    display: none;
}

.nav-scrim {
    display: none;
}

.nav-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.nav-list > li + li {
    margin-top: 2px;
}

.nav-link {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.5rem var(--space-3);
    border-radius: var(--radius-sm);
    color: var(--nav-text);
    font-weight: 500;
    text-decoration: none;
    transition: transform var(--press-duration) ease-out;
    -webkit-tap-highlight-color: transparent;
}

.nav-link:hover {
    background: var(--nav-hover);
    color: var(--nav-text-strong);
}

.nav-link:active:not(.disabled) {
    transform: scale(0.985);
}

.nav-link.active {
    background: var(--nav-active);
    color: var(--nav-text-strong);
    font-weight: 600;
}

/* The current page is marked by a tab on the sidebar's edge as well as by tone and weight (not colour alone). */
.nav-link.active::before {
    content: "";
    position: absolute;
    left: calc(var(--space-3) * -1);
    top: 50%;
    width: 3px;
    height: 1.25rem;
    margin-top: -0.625rem;
    border-radius: 0 3px 3px 0;
    background: var(--accent);
}

.nav-icon {
    flex: none;
    opacity: 0.85;
}

.nav-link.active .nav-icon {
    color: var(--accent);
    opacity: 1;
}

.nav-label {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.nav-link.disabled {
    color: var(--nav-text-dim);
    cursor: default;
}

.nav-link.disabled:hover {
    background: none;
    color: var(--nav-text-dim);
}

.nav-badge {
    min-width: 1.5rem;
    padding: 0 var(--space-2);
    border-radius: var(--radius-pill);
    background: var(--accent);
    color: var(--ink);
    font-size: 0.75rem;
    font-weight: 700;
    line-height: 1.5;
    text-align: center;
}

/* The former "More" menu: labelled groups that fold away (phase 12, UX-05). The tiny uppercase label is the one place it is
   used: a group's name, not a control's text. */
.nav-group {
    margin-top: var(--space-2);
}

.nav-group:first-of-type {
    margin-top: var(--space-4);
    padding-top: var(--space-3);
    border-top: 1px solid var(--nav-line);
}

.nav-group-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: var(--space-1) var(--space-3);
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--nav-text-label);
    font: inherit;
    font-size: 0.6875rem;
    font-weight: var(--weight-title);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    cursor: pointer;
}

.nav-group-toggle:hover {
    color: var(--nav-text-strong);
}

.nav-group-chevron {
    transition: transform var(--press-duration) ease-out;
}

.nav-group-toggle[aria-expanded="true"] .nav-group-chevron {
    transform: rotate(90deg);
}

.nav-group .nav-list {
    margin-top: var(--space-1);
}

/* The sector pill (SectorSwitcher): the sector's name and a chevron in a white pill; the list opens under it. */
.sector-pill {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    min-height: var(--control-height-sm);
    max-width: 14rem;
    padding: 0 var(--space-2) 0 var(--space-3);
    border: 1px solid var(--line);
    border-radius: var(--radius-pill);
    background: var(--surface);
    box-shadow: var(--shadow-1);
    color: var(--color-text);
    font: inherit;
    font-weight: var(--weight-emph);
    cursor: pointer;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    transition: transform var(--press-duration) ease-out;
}

.sector-pill:hover, .sector-pill[aria-expanded="true"] {
    border-color: var(--line-strong);
}

.sector-pill:active {
    transform: scale(var(--press-scale));
}

.sector-pill .menu-trigger-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.btn-ghost {
    border-color: transparent;
    background: transparent;
    color: var(--color-text-muted);
    box-shadow: none;
}

.btn-ghost:hover {
    background: var(--surface);
    border-color: var(--line);
    color: var(--color-text);
}

/* The user menu's trigger (UserMenu): the avatar, the name and a chevron as one pill; the menu itself is the shared one. */
.user-menu-trigger {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: 0.1875rem var(--space-2) 0.1875rem 0.1875rem;
    border: 1px solid transparent;
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--color-text);
    font: inherit;
    cursor: pointer;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    transition: transform var(--press-duration) ease-out;
}

.user-menu-trigger:hover, .user-menu-trigger[aria-expanded="true"] {
    background: var(--surface);
    border-color: var(--line);
    box-shadow: var(--shadow-1);
}

.user-menu-trigger:active {
    transform: scale(var(--press-scale));
}

.user-menu .chevron {
    color: var(--color-text-muted);
}

.avatar {
    display: grid;
    place-items: center;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    background: var(--color-primary);
    color: var(--color-on-primary);
    font-size: 0.75rem;
    font-weight: 650;
    letter-spacing: var(--tracking-small);
    box-shadow: inset 0 0 0 1px var(--edge-light);
}

.user-name {
    max-width: 12rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 500;
}

.language-form {
    display: contents;
}

.user-menu-name {
    color: var(--color-text);
    font-size: var(--font-size-sm);
}

/* Only on a phone (the header moves Refresh into the user menu there). */
.phone-only {
    display: none;
}

/* Narrow screens: the navigation becomes a drawer behind the menu button. It comes in from the left and a scrim
   dims the page behind it; tapping the scrim closes it. */
@media (max-width: 900px) {
    .shell {
        grid-template-columns: minmax(0, 1fr);
        grid-template-areas: "header" "main";
    }

    .nav-toggle {
        display: inline-flex;
    }

    .header-brand {
        display: flex;
    }

    .shell-nav {
        display: none;
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        height: auto;
        width: min(84vw, var(--sidebar-width));
        z-index: calc(var(--z-sticky) + 5);
        box-shadow: var(--shadow-3);
    }

    .shell.nav-open .shell-nav {
        display: flex;
        animation: var(--anim-enter-left);
    }

    .nav-scrim {
        display: block;
        position: fixed;
        inset: 0;
        z-index: calc(var(--z-sticky) + 4);
        background: var(--color-overlay);
        animation: var(--anim-enter-fade);
    }

    .user-name, .user-menu .chevron {
        display: none;
    }
}

/* Phone: the header keeps the menu button, the brand mark, the sector pill and the avatar; Refresh moves into the user menu. */
@media (max-width: 599px) {
    .header-wordmark, .shell-header .refresh {
        display: none;
    }

    .menu-item.phone-only {
        display: flex;
    }

    .shell-header {
        gap: var(--space-2);
    }

    .sector-pill {
        max-width: 9.5rem;
    }
}

/* A styled scrollbar only for a mouse (skill rule 0.6). */
@media (pointer: fine) {
    .shell-nav {
        scrollbar-width: thin;
        scrollbar-color: var(--nav-scrollbar) transparent;
    }
}

/* Touch screens: every control reaches the minimum hit size (skill section 10). */
@media (pointer: coarse) {
    .btn, .nav-link, .nav-group-toggle, .user-menu-trigger, .sector-pill, .menu-item,
    .client-tab, .pm-tab, .settings-tab, .vesuvio-tab {
        min-height: var(--hit-min);
    }

    :where(:is(input, select):not([type="checkbox"], [type="radio"], [type="range"], [type="file"], [type="hidden"], .e-control, .e-input, .e-control *)) {
        min-height: var(--hit-min);
    }
}

/* Shared components (P1-04): modal, toasts, progress overlay, error panel. A modal task gets a scrim; the dialog
   arrives with opacity and scale in 200 ms and is replaced at once on close (a closing animation would have to hold
   the component in the tree). Reduced motion turns the arrival into a cross-fade (tokens.css). */
.modal-backdrop, .progress-overlay {
    position: fixed;
    inset: 0;
    z-index: var(--z-overlay);
    display: grid;
    place-items: center;
    padding: var(--space-4);
    background: var(--color-overlay);
    animation: var(--anim-enter-fade);
}

.modal {
    display: flex;
    flex-direction: column;
    width: min(100%, 34rem);
    max-height: calc(100dvh - 2 * var(--space-4));
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-3);
    padding: var(--space-5);
    animation: var(--anim-enter);
}

/* A dialog (or the help panel) without fields takes the focus itself when it opens, so Escape works; the frame shows no ring, its
   controls do. */
.modal:focus,
.help-panel:focus {
    outline: none;
}

/* Sizes (Modal Size, phase 12): sm for confirmations, md (default) for small forms, lg for forms with a list, xl for two grids. */
.modal-sm {
    width: min(100%, 26rem);
}

.modal-lg {
    width: min(100%, 48rem);
}

.modal-xl {
    width: min(100%, 72rem);
}

/* The title row: the title, and the close button at the right edge. */
.modal-head {
    display: flex;
    flex: none;
    align-items: flex-start;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}

.modal-title {
    flex: 1;
    min-width: 0;
    margin: 0;
    font-size: var(--font-size-lg);
}

.modal-close {
    flex: none;
    margin: calc(var(--space-2) * -1) calc(var(--space-2) * -1) 0 0;
}

/* A dialog taller than the window scrolls inside, so its buttons stay reachable. The negative margin and equal
   padding keep focus rings at the edge from being clipped. */
.modal-body {
    flex: 1 1 auto;
    min-height: 0;
    margin: -0.25rem;
    padding: 0.25rem;
    overflow-y: auto;
}

/* Dialogs that host Syncfusion controls keep the old behaviour: their popups may open inside the dialog and must not be clipped. */
.modal-body:has(.e-control) {
    margin: 0;
    padding: 0;
    overflow-y: visible;
}

.modal-message {
    margin: 0 0 var(--space-4);
    white-space: pre-line;
}

.modal-buttons {
    display: flex;
    flex: none;
    justify-content: flex-end;
    gap: var(--space-2);
    margin-top: var(--space-4);
}

.modal-body > .modal-message {
    margin-bottom: 0;
}

.toast-host {
    position: fixed;
    right: var(--space-4);
    bottom: var(--space-4);
    z-index: var(--z-toast);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    width: min(calc(100vw - 2 * var(--space-4)), 24rem);
}

.toast {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--line);
    border-left: 4px solid var(--color-primary);
    border-radius: var(--radius-md);
    background: var(--surface);
    box-shadow: var(--shadow-2);
    animation: var(--anim-enter-right);
}

.toast-success {
    border-left-color: var(--color-success);
    background: var(--color-success-bg);
}

.toast-error {
    border-left-color: var(--color-danger);
    background: var(--color-danger-bg);
}

.toast-text {
    flex: 1;
}

.btn-close {
    border: none;
    border-radius: var(--radius-sm);
    background: transparent;
    font-size: var(--font-size-lg);
    line-height: 1;
    cursor: pointer;
    color: var(--color-text-muted);
    transition: transform var(--press-duration) ease-out;
}

.btn-close:hover {
    color: var(--color-text);
    background: var(--surface-sunken);
}

.btn-close:active {
    transform: scale(var(--press-scale));
}

.progress-panel {
    min-width: 16rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-5);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-3);
    animation: var(--anim-enter);
}

.progress-panel p {
    margin: 0;
}

.progress-panel progress {
    width: 100%;
    accent-color: var(--color-primary);
}

/* The only endless animation, allowed because it is a loading indicator: ProgressOverlay removes it from the DOM
   as soon as the work ends (skill section 0.3). */
.spinner {
    width: 2rem;
    height: 2rem;
    border: 3px solid var(--line);
    border-top-color: var(--color-primary);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
}

@keyframes spin {
    to {
        transform: rotate(360deg);
    }
}

.error-reference {
    font-family: var(--font-mono);
    color: var(--color-text-muted);
}

/* Word editor workspace (quotation document, OLO, product template): editing takes the whole window over the shell, a slim
   bar with the way out, the document's name and its actions on top, the editor (toolbar, page, properties pane) below.
   It sits on the overlay layer, so confirm dialogs and toasts, rendered after the page, still come in front of it. */
.doc-workspace {
    position: fixed;
    inset: 0;
    z-index: var(--z-overlay);
    display: flex;
    flex-direction: column;
    background: var(--canvas);
    animation: var(--anim-enter-fade);
}

.doc-workspace-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
    padding: var(--space-2) var(--space-4);
    background: var(--surface);
    border-bottom: 1px solid var(--line);
    box-shadow: var(--shadow-1);
}

.doc-workspace-title {
    flex: 1 1 16rem;
    min-width: 0;
}

.doc-workspace-title h2 {
    margin: 0;
    font-size: var(--font-size-lg);
    letter-spacing: var(--tracking-title);
    line-height: var(--leading-title);
    overflow-wrap: anywhere;
}

.doc-workspace-title p {
    margin: 0;
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    overflow-wrap: anywhere;
}

.doc-workspace-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.doc-workspace-actions .chip {
    white-space: nowrap;
}

/* The editor fills what the bar leaves; it scrolls inside, the window never does. */
.doc-workspace-body {
    flex: 1;
    min-height: 0;
    overflow: hidden;
}

.doc-workspace-body > .muted,
.doc-workspace-body > .skeleton {
    margin: var(--space-4);
}

/* Phones: the bar stays short so the document keeps most of the screen; the hint shows its first line. */
@media (max-width: 599px) {
    .doc-workspace-bar {
        padding: var(--space-2) var(--space-3);
    }

    .doc-workspace-title p {
        display: -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 1;
        line-clamp: 1;
        overflow: hidden;
    }
}

.doc-workspace-upload {
    cursor: pointer;
}

.doc-workspace-upload input[type="file"] {
    display: none;
}

/* Help panel (P1-06): a side sheet that comes in from the right, over a scrim. */
.help-backdrop {
    position: fixed;
    inset: 0;
    z-index: var(--z-overlay);
    background: var(--color-overlay);
    animation: var(--anim-enter-fade);
}

.help-panel {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: var(--z-overlay);
    width: min(100vw, 44rem);
    display: flex;
    flex-direction: column;
    background: var(--surface);
    border-left: 1px solid var(--line);
    box-shadow: var(--shadow-3);
    animation: var(--anim-enter-right);
}

.help-panel-header {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--line);
}

.help-panel-header h2 {
    margin: 0;
    font-size: var(--font-size-lg);
}

.help-panel-body {
    flex: 1;
    min-height: 0;
    padding: var(--space-3);
}

.help-content {
    width: 100%;
    height: 100%;
    border: none;
}

/* Shared patterns used by several pages. Tabs are one underlined control; cards one hairline surface; plain data
   tables one header style. Pages add only their own layout. */
.client-tabs, .pm-tabs, .settings-tabs, .vesuvio-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-bottom: var(--gap-tabs);
    border-bottom: 1px solid var(--line);
}

.client-tab, .pm-tab, .settings-tab, .vesuvio-tab {
    margin-bottom: -1px;
    padding: var(--space-2) var(--space-4);
    border: 0;
    border-bottom: 2px solid transparent;
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
    font-weight: 500;
    background: none;
    color: var(--color-text-muted);
    font: inherit;
    text-decoration: none;
    cursor: pointer;
    touch-action: manipulation;
    transition: transform var(--press-duration) ease-out;
}

.client-tab:hover, .pm-tab:hover, .settings-tab:hover, .vesuvio-tab:hover {
    background: var(--surface-sunken);
    color: var(--color-text);
}

.client-tab:active, .pm-tab:active, .settings-tab:active, .vesuvio-tab:active {
    transform: scale(var(--press-scale));
}

.client-tab-active, .pm-tab.active, .settings-tab.active, .vesuvio-tab.active {
    border-bottom-color: var(--color-primary);
    color: var(--color-primary);
    font-weight: 600;
}

.card, .costs, .history, .hierarchy section {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-1);
}

.card {
    padding: var(--space-5);
}

/* A card whose only content is the one line that says what is missing or what to pick (EmptyState), filling the room it is given. */
.card-empty {
    display: grid;
    flex: 1 1 0;
    place-items: center;
    min-height: 12rem;
}

/* Every page opens with this header: the title (and one line saying what the page is for) on the left, the primary
   action and secondary tools on the right. Wayfinding: where am I, what can I do here. */
.page-header {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--space-3) var(--space-5);
    margin-bottom: var(--gap-header);
}

.page-header h1 {
    margin: 0;
}

.page-sub {
    margin: var(--space-1) 0 0;
    color: var(--color-text-muted);
}

.page-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

/* A toolbar above a list: search first, filters next, actions at the end. */
.toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--gap-toolbar);
}

.toolbar .check, .toolbar .field {
    margin: 0;
}

/* A toolbar that holds labelled fields (a date range): the buttons line up with the inputs, not with the labels. */
.toolbar-form {
    align-items: flex-end;
}

.toolbar-date {
    flex: 0 1 11rem;
}

/* A multi-select or other combo that sits in a toolbar beside the search; the row count at the toolbar's end; a Notice between
   the toolbar and the list. */
.toolbar-combo {
    flex: 0 1 13rem;
    min-width: min(10rem, 100%);
}

@media (max-width: 599px) {
    .toolbar-combo {
        flex: 1 1 100%;
    }
}

/* A muted count at the end of a toolbar ("38,104 clients"); on phones it may wrap, so the toolbar's own `...` stays beside it. */
.toolbar-count {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

@media (max-width: 599px) {
    .toolbar-count {
        flex: 1 1 8rem;
        min-width: 0;
        white-space: normal;
        text-align: right;
    }
}

.page-notice {
    margin-bottom: var(--gap-toolbar);
}

/* A row of label + value pairs (DESIGN-SYSTEM.md section 5.1): totals beside a list or a form. Small muted labels in sentence
   case above the values; numbers tabular. <dl class="figures"><div><dt>Total</dt><dd>1,200.00</dd></div> ... */
.figures {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3) var(--space-6);
    margin: 0;
}

.figures > div {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

.figures dt {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.figures dd {
    margin: 0;
    font-size: var(--font-size-lg);
    font-weight: var(--weight-title);
    font-variant-numeric: tabular-nums;
}

/* Figures at the top of a form or dialog: room before the first field. */
.figures + .field {
    margin-top: var(--space-4);
}

/* Search field (SearchField): the magnifier inside on the left, the clear button inside on the right, 20 to 24rem wide in a
   toolbar. */
.search-field {
    position: relative;
    display: flex;
    align-items: center;
    flex: 0 1 22rem;
    min-width: min(14rem, 100%);
}

.search-field input {
    width: 100%;
    padding-left: 2.25rem;
    padding-right: 2.25rem;
}

.search-field-icon {
    position: absolute;
    left: var(--space-3);
    color: var(--color-text-muted);
    pointer-events: none;
}

.search-field-clear {
    position: absolute;
    right: var(--space-1);
    display: grid;
    place-items: center;
    width: 1.75rem;
    height: 1.75rem;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--color-text-muted);
    cursor: pointer;
    transition: transform var(--press-duration) ease-out;
}

.search-field-clear:hover {
    background: var(--hover-tint);
    color: var(--color-text);
}

.search-field-clear:active {
    transform: scale(var(--press-scale));
}

/* Segmented control (Segmented): a sunken track, the chosen segment raised in white with a soft shadow; no orange fill. */
.segmented {
    display: inline-flex;
    gap: 2px;
    min-width: 0;
    margin: 0;
    padding: 2px;
    border: 0;
    border-radius: var(--radius-sm);
    background: var(--surface-sunken);
}

.segmented-option {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: calc(var(--control-height) - 4px);
    padding: 0 var(--space-3);
    border-radius: calc(var(--radius-sm) - 2px);
    color: var(--color-text-muted);
    font-weight: var(--weight-emph);
    white-space: nowrap;
    cursor: pointer;
    transition: transform var(--press-duration) ease-out;
}

.segmented-option:hover {
    color: var(--color-text);
}

.segmented-option:active {
    transform: scale(var(--press-scale));
}

.segmented-option.is-on {
    background: var(--surface);
    box-shadow: var(--shadow-1);
    color: var(--color-text);
}

.segmented-option input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
}

.segmented-option:has(input:focus-visible) {
    outline: 2px solid var(--color-focus);
    outline-offset: 1px;
}

/* Phones: the track takes the row and the segments share it, so five languages fit 390px instead of running off the edge. */
@media (max-width: 599px) {
    .segmented {
        display: flex;
        width: 100%;
    }

    .segmented-option {
        flex: 1 1 0;
        min-width: 0;
        padding: 0 var(--space-1);
    }

    .segmented-option > span {
        overflow: hidden;
        text-overflow: ellipsis;
    }
}

/* Menus (MenuButton, MenuItem; phase 12, UX-05): a card that grows out of its trigger with opacity and scale (reduced motion: a
   cross-fade), lined up with the trigger's right edge (or left, .align-start). Rows are 36px, a neutral tint on hover and focus;
   a check column for the current choice; Delete in red text. */
.menu-button {
    position: relative;
    display: inline-flex;
}

.menu-caret {
    flex: none;
    color: currentColor;
    opacity: 0.7;
}

.menu-popover {
    position: absolute;
    top: calc(100% + var(--space-1));
    right: 0;
    z-index: var(--z-menu);
    display: flex;
    flex-direction: column;
    min-width: 13rem;
    max-width: min(22rem, calc(100vw - 2 * var(--space-4)));
    max-height: min(26rem, calc(100dvh - var(--header-height) - var(--space-6)));
    padding: var(--space-1);
    overflow-y: auto;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-2);
    transform-origin: top right;
    animation: var(--anim-enter);
}

.menu-popover.align-start {
    right: auto;
    left: 0;
    transform-origin: top left;
}

.menu-item {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    width: 100%;
    min-height: var(--control-height);
    padding: 0 var(--space-3);
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--color-text);
    font: inherit;
    text-align: left;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.menu-item:hover, .menu-item:focus-visible {
    background: var(--hover-tint);
    color: var(--color-text);
}

.menu-item:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: -2px;
}

.menu-item > .icon {
    flex: none;
    color: var(--color-text-muted);
}

.menu-item.is-danger, .menu-item.is-danger > .icon {
    color: var(--color-danger);
}

.menu-item:disabled {
    opacity: 0.5;
    cursor: default;
}

.menu-check {
    display: inline-grid;
    flex: none;
    place-items: center;
    width: 1rem;
    color: var(--color-primary);
}

.menu-item-text {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.menu-separator {
    height: 1px;
    margin: var(--space-1) calc(var(--space-1) * -1);
    background: var(--line);
}

.menu-label {
    padding: var(--space-2) var(--space-3) var(--space-1);
    color: var(--color-text-muted);
    font-size: var(--font-size-caption);
    font-weight: var(--weight-emph);
}

/* Split button: the main action and the chevron as one control with a hairline between them. */
.menu-button.is-split > .menu-split-main {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
}

.menu-button.is-split > .menu-split-toggle {
    min-width: 0;
    margin-left: -1px;
    padding-inline: var(--space-2);
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
}

.menu-button.is-split > .btn-primary.menu-split-toggle {
    border-left-color: color-mix(in srgb, var(--color-on-primary) 35%, var(--color-primary));
}

/* States (phase 12, UX-06; DESIGN-SYSTEM.md section 4.3). Empty: one centered line and the action. Notice: a page-level
   message with an icon, a title, a line and the next step, tinted by level. Skeleton: static grey rows in the grid's rhythm while
   a list loads (no shimmer, skill rule 0.3). */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-6) var(--space-4);
    text-align: center;
}

.empty-state-text {
    margin: 0;
    color: var(--color-text-muted);
}

.notice {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    max-width: 48rem;
    margin-bottom: var(--gap-cards);
    padding: var(--space-4) var(--space-5);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    background: var(--surface);
    box-shadow: var(--shadow-1);
}

.notice-icon {
    flex: none;
    margin-top: 0.0625rem;
    color: var(--color-text-muted);
}

.notice-error {
    border-color: color-mix(in srgb, var(--color-danger) 30%, var(--surface));
    background: var(--color-danger-bg);
}

.notice-error .notice-icon {
    color: var(--color-danger);
}

.notice-warning {
    border-color: color-mix(in srgb, var(--color-warning) 30%, var(--surface));
    background: var(--color-warning-bg);
}

.notice-warning .notice-icon {
    color: var(--color-warning);
}

.notice-body {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

.notice-title {
    margin: 0;
    font-weight: var(--weight-title);
}

.notice-text p {
    margin: 0;
}

.notice-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-2);
}

.skeleton {
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    background: var(--surface);
    box-shadow: var(--shadow-1);
}

.skeleton-row {
    display: flex;
    align-items: center;
    gap: var(--space-6);
    height: var(--row-height);
    padding: 0 var(--space-3);
}

.skeleton-row + .skeleton-row {
    border-top: 1px solid var(--line);
}

.skeleton-bar {
    width: 40%;
    height: 0.625rem;
    border-radius: var(--radius-pill);
    background: var(--surface-sunken);
}

.skeleton-row:nth-child(3n+2) .skeleton-bar:first-child {
    width: 28%;
}

.skeleton-row:nth-child(3n) .skeleton-bar:first-child {
    width: 50%;
}

.skeleton-muted {
    width: 18%;
    opacity: 0.6;
}

/* A toast's status as an icon (no text characters as glyphs). */
.toast-icon {
    flex: none;
    margin-top: 0.125rem;
    color: var(--color-primary);
}

.toast-success .toast-icon {
    color: var(--color-success);
}

.toast-error .toast-icon {
    color: var(--color-danger);
}

/* Page templates (phase 12, UX-02; DESIGN-SYSTEM.md section 4.1). One per page; the shell's main is the flex column they
   live in. .page-list takes exactly the viewport's remaining height, so its .fill (the grid's card) scrolls inside and the
   page does not; the others grow with their content and keep their actions in a sticky bar or column. */
.page-list, .page-detail, .page-form, .page-wizard {
    display: flex;
    flex: 1 0 auto;
    flex-direction: column;
    min-width: 0;
}

.page-list {
    flex: 0 0 auto;
    height: calc(100dvh - var(--header-height) - var(--main-pad-top) - var(--main-pad-bottom));
    min-height: 30rem;
}

.fill {
    display: flex;
    flex: 1 1 0;
    flex-direction: column;
    min-height: 0;
}

/* A grid with Height="100%" fills its .fill: the header stays, the rows scroll inside, the pager stays at the foot. */
.fill > .e-grid, .fill > .e-treegrid {
    flex: 1 1 0;
    min-height: 0;
}

/* The one way back (BackLink): a quiet ghost button on its own line above the header, aligned with the title. */
.back-link {
    display: inline-flex;
    align-items: center;
    align-self: flex-start;
    gap: var(--space-1);
    margin: calc(var(--space-2) * -1) 0 var(--space-2) calc(var(--space-2) * -1);
    padding: var(--space-1) var(--space-2) var(--space-1) var(--space-1);
    border-radius: var(--radius-sm);
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    font-weight: var(--weight-emph);
    text-decoration: none;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    transition: transform var(--press-duration) ease-out;
}

.back-link:hover {
    background: var(--hover-tint);
    color: var(--color-text);
}

.back-link:active {
    transform: scale(var(--press-scale));
}

/* Action bar and wizard footer (ActionBar): solid surface on the bottom edge of the viewport, full bleed across the main
   area, a top hairline and an upward shadow; never blurred (skill rule 0.2). The spacer before it keeps a gap above the bar
   and pushes it to the bottom when the content is short. */
.action-bar-spacer {
    flex: 1 0 var(--space-5);
}

/* On a list page that has a bar (the review batch) the grid's .fill takes the room, the bar only keeps a gap above it. */
.page-list > .action-bar-spacer {
    flex: 0 0 var(--space-4);
}

.action-bar {
    position: sticky;
    bottom: 0;
    z-index: var(--z-sticky);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
    min-height: var(--action-bar-height);
    margin: 0 calc(var(--main-pad-x) * -1) calc(var(--main-pad-bottom) * -1);
    padding: var(--space-3) var(--main-pad-x);
    background: var(--surface);
    border-top: 1px solid var(--line);
    box-shadow: var(--shadow-up);
}

.action-bar-start, .action-bar-end {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.action-bar-status {
    flex: 1 1 8rem;
    min-width: 0;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.action-bar-status:empty {
    visibility: hidden;
}

.action-bar-end .btn {
    min-width: 6.5rem;
    justify-content: center;
}

/* A field scrolled into view (Tab, a script) must not end up under the sticky header or the action bar on the bottom edge. */
html {
    scroll-padding-top: calc(var(--header-height) + var(--space-3));
    scroll-padding-bottom: calc(var(--action-bar-height) + var(--space-4));
}

/* Long forms (.page-form): the fields in section cards, at most 64rem wide, labels above inputs, two columns from 900px. */
.form-stack {
    display: flex;
    flex-direction: column;
    gap: var(--gap-cards);
    max-width: 64rem;
}

.form-card {
    padding: var(--space-5);
}

.form-card > h2, .form-card-title {
    margin: 0 0 var(--space-4);
    font-size: var(--font-size-card-title);
    font-weight: var(--weight-title);
    letter-spacing: var(--tracking-title);
}

.form-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    column-gap: var(--space-4);
}

.form-grid > .wide {
    grid-column: 1 / -1;
}

/* A value in a form that is never editable: text, not a tinted disabled input (DESIGN-SYSTEM.md section 5.2). */
.field-static {
    display: flex;
    align-items: center;
    min-height: var(--control-height);
    margin: 0;
    font-weight: var(--weight-emph);
}

@media (min-width: 900px) {
    .form-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* Detail pages (.page-detail): the side column with the record's actions stays in view while the main column scrolls; when it
   is taller than the window it scrolls itself (the padding keeps focus rings and card shadows from being cut). Under 1200px
   the page is one column with the side column first. */
.page-detail .details-grid {
    flex: 1 0 auto;
}

@media (min-width: 1200px) {
    .page-detail .details-side {
        position: sticky;
        top: calc(var(--header-height) + var(--space-5));
        max-height: calc(100dvh - var(--header-height) - var(--space-5) * 2);
        margin: calc(var(--space-1) * -1);
        padding: var(--space-1);
        overflow-y: auto;
        overscroll-behavior: contain;
    }
}

@media (max-width: 1199px) {
    .page-detail .details-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    .page-detail .details-side {
        order: -1;
    }
}

/* Card titles never compete with the page title (DESIGN-SYSTEM.md section 6). */
.card h2, .card-head h2, .details-grid h2 {
    font-size: var(--font-size-card-title);
    font-weight: var(--weight-title);
    letter-spacing: var(--tracking-title);
}

.costs-table, .language-table, .pick, .wizard-table, .finance-banks {
    width: 100%;
    border-collapse: collapse;
    font-variant-numeric: tabular-nums;
    line-height: var(--leading-dense);
}

/* Plain tables follow the grid's rules (DESIGN-SYSTEM.md section 5.3): a white header in sentence case, 40px rows, hairlines
   between rows and none after the last, a neutral hover. */
.costs-table th, .language-table th, .pick th, .wizard-table th, .finance-banks thead th {
    height: var(--row-height);
    padding: 0 var(--space-3);
    color: var(--color-text-muted);
    font-size: var(--font-size-caption);
    font-weight: 600;
    letter-spacing: var(--tracking-small);
}

.costs-table td, .language-table td, .pick td, .wizard-table td, .finance-banks td, .finance-banks tbody th, .finance-banks tfoot th {
    height: var(--row-height);
    padding: var(--space-1) var(--space-3);
}

.costs-table tbody tr:last-child > *, .language-table tbody tr:last-child > *,
.pick tbody tr:last-child > *, .wizard-table tbody tr:last-child > *, .finance-banks tbody tr:last-child > * {
    border-bottom-color: transparent;
}

.costs-table tbody tr:hover, .language-table tbody tr:hover, .pick tbody tr:hover, .wizard-table tbody tr:hover, .finance-banks tbody tr:hover {
    background: var(--hover-tint);
}

/* Table cells (phase 12, UX-03): a yes/no as a check glyph, a date short with its time muted, a row's actions as icons that
   show on hover or focus with a mouse and always on touch. */
.cell-check {
    color: var(--color-text);
    vertical-align: middle;
}

/* The record's name in a row: text, a step heavier, never orange (DESIGN-SYSTEM.md section 5.3). */
.cell-primary {
    color: var(--color-text);
    font-weight: var(--weight-emph);
}

.cell-time {
    margin-left: var(--space-2);
    color: var(--color-text-muted);
}

.row-actions {
    display: inline-flex;
    gap: var(--space-1);
}

.row-action {
    display: inline-grid;
    place-items: center;
    width: var(--control-height-sm);
    height: var(--control-height-sm);
    padding: 0;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--color-text-muted);
    cursor: pointer;
    touch-action: manipulation;
    transition: transform var(--press-duration) ease-out;
}

.row-action:hover {
    background: var(--hover-tint);
    color: var(--color-text);
}

.row-action-danger:hover {
    color: var(--color-danger);
}

.row-action:active:not(:disabled) {
    transform: scale(var(--press-scale));
}

.row-action:disabled {
    opacity: 0.4;
    cursor: default;
}

@media (pointer: fine) {
    .row-actions {
        opacity: 0;
    }

    .e-row:hover .row-actions, .e-row:focus-within .row-actions, .e-row[aria-selected="true"] .row-actions, td.e-focused .row-actions,
    tr:hover > td > .row-actions, tr:focus-within > td > .row-actions {
        opacity: 1;
    }
}

/* The phone form of a grid (RowList): under 600px the grid in the same .fill hides and the stacked list shows in a card. */
.row-list {
    display: none;
}

@media (max-width: 599px) {
    .fill:has(> .row-list) > .e-grid {
        display: none;
    }

    .row-list {
        display: block;
        flex: 1 1 0;
        min-height: 0;
        margin: 0;
        padding: 0;
        position: relative; /* the screen-reader text of CheckCell is absolute: it must not stretch the page */
        overflow-y: auto;
        overscroll-behavior: contain;
        list-style: none;
        background: var(--surface);
        border: 1px solid var(--line);
        border-radius: var(--radius-lg);
        box-shadow: var(--shadow-1);
    }
}

.row-list li + li {
    border-top: 1px solid var(--line);
}

.row-list-item {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    min-height: 4rem;
    padding: var(--space-2) var(--space-4);
    color: var(--color-text);
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
}

button.row-list-item {
    width: 100%;
    border: 0;
    background: transparent;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

a.row-list-item:hover, a.row-list-item:active, button.row-list-item:hover, button.row-list-item:active {
    background: var(--hover-tint);
    color: var(--color-text);
}

.row-list-text {
    display: flex;
    flex: 1;
    flex-direction: column;
    min-width: 0;
}

.row-list-primary, .row-list-secondary {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.row-list-primary {
    font-weight: var(--weight-emph);
}

.row-list-secondary {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.row-list-trailing {
    flex: none;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    text-align: right;
}

.costs-table th, .costs-table td,
.language-table th, .language-table td,
.pick th, .pick td,
.wizard-table th, .wizard-table td,
.finance-banks th, .finance-banks td {
    text-align: left;
    border-bottom: 1px solid var(--line);
}

.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: var(--text-error-boundary, "")
    }

/* To-do list (P2-09) */
.todo-new {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: var(--space-3);
    margin-bottom: var(--gap-tabs);
}

/* The composer is one line that grows with what is typed (up to a few lines). */
.todo-new .field {
    flex: 1 1 24rem;
    margin-bottom: 0;
}

.todo-new textarea {
    width: 100%;
    min-height: var(--control-height);
    max-height: 9rem;
    field-sizing: content;
    resize: none;
}

.todo-text {
    white-space: pre-wrap;
}

.todo-finished {
    width: 1.1rem;
    height: 1.1rem;
}

.todo-item-dialog textarea {
    display: block;
    width: 100%;
    resize: vertical;
}

.todo-item-head {
    display: flex;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-2);
}

/* Settings (phase 12, UX-16): the tab's content takes the room under the tabs and scrolls inside itself, never the page. Several
   lists (ListCard) sit side by side in .list-editor-grid, filling the height when they fit and scrolling the panel when they do
   not. Any .page-list tab whose content is cards rather than one grid does the same with .fill-scroll (Finances' bank balances). */
.settings-panel, .fill-scroll {
    overflow-y: auto;
    padding: var(--space-1);
    margin: calc(var(--space-1) * -1);
}

.settings-section {
    display: flex;
    flex: 1 1 0;
    flex-direction: column;
    min-height: 0;
}

.list-editor-grid {
    display: grid;
    flex: 1 1 0;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 30rem), 1fr));
    grid-auto-rows: minmax(17rem, 1fr);
    gap: var(--gap-cards);
    min-height: 0;
}

/* One column on a phone: each list gets a card tall enough to show its rows. */
@media (max-width: 899px) {
    .list-editor-grid {
        flex: none;
        grid-auto-rows: 26rem;
    }
}

.list-card {
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
}

.list-card > .card-head {
    flex: none;
}

.list-card > .fill > .e-grid {
    border-width: 1px 0 0;
    border-radius: 0;
}

.list-card-toolbar {
    flex: none;
    margin: 0 var(--space-5) var(--space-3);
}

.form-hint {
    margin: 0;
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-sm);
    background: var(--color-warning-bg);
    color: var(--color-warning);
}

/* Users (P2-07) */
.user-flags {
    grid-column: 1 / -1;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-5);
}

.user-flags .check {
    margin-bottom: 0;
}

.user-hint {
    margin: var(--space-3) 0 0;
}

.user-add {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}

.user-add select {
    flex: 1 1 12rem;
    min-width: 0;
}

.chip-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

.chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-1) var(--space-2);
    border: 1px solid var(--line);
    border-radius: var(--radius-pill);
    background: var(--surface-sunken);
}

.chip-remove {
    border: 0;
    background: transparent;
    color: var(--color-text-muted);
    padding: var(--space-1);
    font: inherit;
    line-height: 1;
    cursor: pointer;
    transition: transform var(--press-duration) ease-out;
}

.chip-remove:active {
    transform: scale(var(--press-scale));
}

.chip-remove:hover {
    color: var(--color-danger);
}

/* User activity (P2-08) */
.activity-range {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-2) var(--space-3);
    margin-bottom: var(--space-4);
    padding: 0 var(--space-5);
}

.activity-date {
    width: 11rem;
    margin-bottom: 0;
}

.log-changes {
    white-space: pre-wrap;
}

/* Clients (UX-12): the detail page's sections are form cards; the last activity is text; the records (contacts, activity,
   cases, quotations, files) sit in one card with their tabs. */
.client-last-activity {
    margin: 0;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.client-records .client-tabs {
    margin-top: 0;
}

/* The records' grids sit in the card: no second frame around them. */
.client-records .e-grid {
    border: 0;
    border-radius: 0;
    box-shadow: none;
}

.client-tabs {
    margin-top: var(--space-5);
}

/* Directly under the page header the tabs follow the page rhythm (--gap-header above, --gap-tabs below). */
.page-header + .client-tabs {
    margin-top: 0;
}

.client-tabpanel {
    padding-top: 0;
}

.client-merge {
    min-width: 0;
    max-width: 100%;
    overflow: hidden;
}

.client-merge-destination {
    margin-bottom: var(--space-4);
    padding: var(--space-3);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--surface-sunken);
}

.client-merge-destination h3 {
    margin: 0 0 var(--space-2);
    font-size: var(--font-size-base);
}

.client-merge-destination dl {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: var(--space-1) var(--space-3);
    margin: 0;
}

.client-merge-destination dt {
    color: var(--color-text-muted);
}

.client-merge-destination dd {
    margin: 0;
}

.client-check-import {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin-bottom: var(--gap-cards);
}

.client-check-status {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    min-height: 1.5rem;
}

.modal-help {
    margin-right: auto;
}

/* Part management (phase 12, UX-17): a master list on the left, the chosen record on the right, both scrolling inside their cards.
   From 1200px the page is exactly the window and the two panes share it; below that the panes stack and the area scrolls. */
.pm-tabs {
    margin-bottom: var(--gap-tabs);
}

.pm-split {
    display: grid;
    flex: 1 1 0;
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: var(--gap-cards);
    min-height: 0;
}

.pm-pane {
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
}

.pm-pane > .list-card {
    flex: 1 1 0;
}

/* The record side of Machines: details, units, parts. */
.pm-stack {
    display: grid;
    grid-template-rows: auto minmax(12rem, 1fr) minmax(14rem, 2fr);
    gap: var(--gap-cards);
    min-width: 0;
    min-height: 0;
}

.pm-form {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    column-gap: var(--space-4);
}

@media (min-width: 640px) {
    .pm-form {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

.pm-head-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
}

.pm-form-actions {
    grid-column: 1 / -1;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
}

@media (max-width: 1199px) {
    .pm-split {
        grid-template-columns: minmax(0, 1fr);
        align-content: start;
        overflow-y: auto;
        padding: var(--space-1);
        margin: calc(var(--space-1) * -1);
    }

    .pm-pane > .list-card {
        flex: none;
        height: 26rem;
    }

    .pm-pane > .card-empty {
        flex: none;
    }

    .pm-stack {
        grid-template-rows: auto 18rem 22rem;
    }
}

.parts-assign {
    min-width: 0;
    max-width: 100%;
    overflow: hidden;
}

.parts-assign-grids {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    gap: var(--space-3);
    align-items: start;
    margin-top: var(--space-3);
}

.parts-assign-grids h3 {
    margin: 0 0 var(--space-2);
    font-size: var(--font-size-base);
}

.parts-assign-add {
    align-self: center;
}

/* The title row of a detail page: the name of what is open and its status chips, which wrap as whole items on a phone. */
.page-title {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    min-width: 0;
}

.page-title h1 {
    margin: 0;
}

/* Wizards (quotation, case; phase 12 UX-10, DESIGN-SYSTEM.md section 4.1): the way back, the header, the steps as a quiet stepper
   (where am I), one panel, and the footer (ActionBar with wizard-footer) on the bottom edge. From 900px the wizard is exactly the
   window's remaining height: a list step's grid scrolls inside its card, a form step's panel scrolls itself, and the footer never
   moves. Under 900px the page grows, the footer sticks to the bottom edge and the lists keep a fixed height. */
@media (min-width: 900px) {
    .page-wizard {
        flex: 0 0 auto;
        height: calc(100dvh - var(--header-height) - var(--main-pad-top) - var(--main-pad-bottom));
        min-height: 32rem;
    }

    .page-wizard > .action-bar-spacer {
        flex: 0 0 var(--space-4);
    }

    /* The panel scrolls itself when a form step is taller than the window; a little room keeps the cards' edges and focus rings. */
    .wizard-panel {
        flex: 1 1 0;
        min-height: 0;
        overflow-y: auto;
        margin: 0 calc(var(--space-1) * -1);
        padding: 0 var(--space-1) var(--space-1);
    }
}

@media (max-width: 899px) {
    .wizard-panel .fill {
        flex: none;
        height: min(36rem, 62dvh);
    }
}

.wizard-steps ol {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
    margin: 0 0 var(--gap-tabs);
    padding: 0;
    list-style: none;
}

.wizard-step {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    font-weight: var(--weight-emph);
}

/* A hairline between two steps: the way through, not a box per step. */
.wizard-step + .wizard-step::before {
    content: "";
    width: 2rem;
    height: 1px;
    margin-right: var(--space-1);
    background: var(--line-strong);
}

.wizard-step-number {
    display: inline-grid;
    flex: none;
    place-items: center;
    width: 1.5rem;
    height: 1.5rem;
    border: 1px solid var(--line-strong);
    border-radius: 50%;
    background: var(--surface);
    font-size: var(--font-size-caption);
    font-weight: var(--weight-title);
    font-variant-numeric: tabular-nums;
}

.wizard-step.is-current, .wizard-step.is-done {
    color: var(--color-text);
}

.wizard-step.is-current .wizard-step-number {
    border-color: var(--color-primary);
    background: var(--color-primary);
    color: var(--color-on-primary);
}

/* Done: an ink disc with a check; orange stays for the step the user is on. */
.wizard-step.is-done .wizard-step-number {
    border-color: var(--color-text);
    background: var(--color-text);
    color: var(--surface);
}

.wizard-step.is-skipped {
    color: var(--color-text-muted);
}

.wizard-step.is-skipped .wizard-step-number {
    border-style: dashed;
}

.wizard-step-skipped {
    margin-left: var(--space-1);
    font-weight: var(--weight-body);
}

/* Phones: the numbers and the current step's name. */
@media (max-width: 599px) {
    .wizard-step:not(.is-current) .wizard-step-label {
        display: none;
    }

    .wizard-step + .wizard-step::before {
        width: 1rem;
    }
}

.wizard-panel {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.wizard-hint {
    margin: 0 0 var(--gap-toolbar);
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.card .wizard-hint {
    margin: var(--space-3) 0 0;
}

/* The footer's middle: what has been chosen so far ("Mabilmac, S.L. · 2 contacts · 3 products"), on one line. */
.wizard-summary {
    display: block;
    overflow: hidden;
    color: var(--color-text);
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Phones: the summary takes its own line above the buttons, so Back stays left and the primary right. */
@media (max-width: 599px) {
    .wizard-footer .action-bar-status {
        flex-basis: 100%;
        order: -1;
    }

    .wizard-footer .action-bar-status:empty {
        display: none;
    }

    .wizard-footer .action-bar-end {
        margin-left: auto;
    }
}

.wizard-footer-error {
    color: var(--color-danger);
    font-weight: var(--weight-emph);
}

/* A count beside a card's title ("Selected 3"). */
.wizard-count {
    min-width: 1.5rem;
    margin-right: auto;
    padding: 0 var(--space-2);
    border-radius: var(--radius-pill);
    background: var(--surface-sunken);
    color: var(--color-text-muted);
    font-size: var(--font-size-caption);
    font-weight: var(--weight-emph);
    line-height: 1.5rem;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

/* A plain table to pick from (contacts): a card as tall as its rows, scrolling inside under a fixed header when longer. */
.wizard-table-card {
    flex: 0 1 auto;
    min-height: 0;
    overflow: auto;
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    background: var(--surface);
    box-shadow: var(--shadow-1);
}

.wizard-table-card .wizard-table {
    width: 100%;
}

.wizard-table-card thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--surface);
}

.wizard-table .cell-select {
    width: 2.75rem;
    text-align: center;
}

.wizard-table .cell-center {
    text-align: center;
}

.wizard-table-card tbody tr {
    cursor: pointer;
    -webkit-user-select: none;
    user-select: none;
}

.wizard-table-card tbody tr.is-selected {
    background: var(--color-selected);
}

.wizard-table-card tbody tr.is-selected > td:first-child {
    box-shadow: inset 3px 0 0 var(--color-primary);
}

/* Products: the list to choose from, and beside it the chosen ones in a card as tall as its items. */
.wizard-products {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(18rem, 24rem);
    grid-template-rows: minmax(0, 1fr);
    gap: var(--gap-cards);
    flex: 1 1 0;
    min-height: 0;
}

.wizard-pane {
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
}

.wizard-selected-card {
    display: flex;
    flex-direction: column;
    align-self: start;
    max-height: 100%;
    min-height: 0;
    padding: var(--space-4) var(--space-4) var(--space-2);
}

.wizard-selected-card .empty-state {
    padding: var(--space-5) var(--space-2);
}

.wizard-selected {
    min-height: 0;
    margin: 0;
    padding: 0;
    overflow-y: auto;
    list-style: none;
}

.wizard-selected li {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-height: var(--row-height);
    border-top: 1px solid var(--line);
}

.wizard-selected li:first-child {
    border-top: 0;
}

/* A product just added shows itself with a short fade (opacity only, skill rule 0.4). */
.wizard-selected-card .wizard-selected li {
    animation: var(--anim-enter-fade);
}

.wizard-selected-index {
    flex: none;
    width: 1.25rem;
    color: var(--color-text-muted);
    font-size: var(--font-size-caption);
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.wizard-selected-name {
    flex: 1;
    min-width: 0;
    overflow-wrap: anywhere;
}

@media (max-width: 899px) {
    .wizard-products {
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: auto;
        flex: none;
    }

    .wizard-selected-card {
        align-self: stretch;
        max-height: none;
    }
}

/* Review and details steps: what was chosen on the left, the fields to fill in on the right. */
.wizard-review {
    display: grid;
    grid-template-columns: minmax(0, 3fr) minmax(20rem, 2fr);
    gap: var(--gap-cards);
    align-items: start;
}

.wizard-review-main {
    display: flex;
    flex-direction: column;
    gap: var(--gap-cards);
    min-width: 0;
}

@media (max-width: 1199px) {
    .wizard-review {
        grid-template-columns: minmax(0, 1fr);
    }
}

.wizard-client {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    gap: var(--space-2) var(--space-4);
    margin: 0;
}

.wizard-client dt {
    color: var(--color-text-muted);
}

.wizard-client dd {
    margin: 0;
    overflow-wrap: anywhere;
}

/* A card whose table runs to its edges (no box in a box): the title keeps the card's padding, the grid loses its own frame. */
.card.card-flush {
    padding: var(--space-5) 0 0;
    overflow: hidden;
}

.card-flush > .card-head {
    padding: 0 var(--space-5);
}

.card-flush > .e-grid {
    border-width: 1px 0 0;
    border-radius: 0;
}

/* A field's own message under it (inline validation), and the field marked. */
.field-message {
    margin: 0;
    font-size: var(--font-size-sm);
}

.field :is(input, select, textarea)[aria-invalid="true"] {
    border-color: var(--color-danger);
}

/* A trailing icon (Next, Edit client) sits a little into the button's padding, like a leading one. */
.btn > .btn-icon-end {
    flex: none;
    margin-right: calc(var(--space-1) * -1);
}

/* A chip that toggles a filter (aria-pressed): its on state is outlined in the primary colour and heavier, not colour alone. */
.chip[aria-pressed="true"] {
    border-color: var(--color-primary);
    color: var(--color-primary);
    font-weight: 600;
}

/* Cases (UX-13): an overdue reminder is the date in red beside an "Overdue" chip, never a tinted row. */
.cell-overdue .cell-date {
    color: var(--color-danger);
}

/* Detail pages (quotation P5-07, case P6-04): what the record is on the left, what to do with it on the right; one column
   under 1000px. Moved from the quotation page's scoped CSS so every detail page has the same rhythm. */
.details-grid {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    gap: var(--space-4);
    align-items: start;
}

.details-main,
.details-side {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    min-width: 0;
}

@media (max-width: 1000px) {
    .details-grid {
        grid-template-columns: minmax(0, 1fr);
    }
}

.details-grid h2 {
    margin: 0 0 var(--space-3);
}

.details-list {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    gap: var(--space-2) var(--space-4);
    margin: 0;
}

.details-list dt {
    color: var(--color-text-muted);
}

.details-list dt,
.details-list dd {
    margin: 0;
}

@media (max-width: 480px) {
    .details-list {
        grid-template-columns: minmax(0, 1fr);
        gap: 0;
    }

    .details-list dd {
        margin-bottom: var(--space-2);
    }
}

.details-file {
    overflow-wrap: anywhere;
}

/* A table inside a card scrolls inside it on a phone, never the page. */
.details-table-wrap {
    overflow-x: auto;
    margin-bottom: var(--space-3);
}

/* A list that can grow long inside a detail or form card (activity feed, payments, installments, costs, allowed countries; UX-20): it scrolls inside
   its card from about ten rows, with the column header kept in view, so the page stays as long as its cards and not its data. */
.card-scroll {
    max-height: 26rem;
    overflow-y: auto;
    overscroll-behavior: contain;
}

.card-scroll thead th,
.card-scroll .e-gridheader {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--surface);
}

.details-nowrap {
    white-space: nowrap;
}

.details-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-3);
}

.details-hint {
    flex: 1 1 14rem;
    margin: 0;
}

.details-list + .details-row {
    margin-top: var(--space-3);
}

.page-title h1,
.page-title .chip {
    white-space: nowrap;
}

/* A card's heading with its one action on the right (Add activity, New quotation). */
.card-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}

.card-head h2 {
    margin: 0;
}

/* Status reads by a dot, a tint and its word, never colour alone (DESIGN-SYSTEM.md section 5.3); quiet enough to sit in a
   table row without looking like a button. */
.chip.status-ok, .chip.status-pending, .chip.status-closed, .chip.status-error {
    gap: 0.375rem;
    padding: 0.0625rem var(--space-2);
    border-color: transparent;
    font-size: var(--font-size-sm);
    line-height: var(--leading-dense);
    white-space: nowrap;
}

.chip.status-ok::before, .chip.status-pending::before, .chip.status-closed::before, .chip.status-error::before {
    content: "";
    flex: none;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
}

.chip.status-ok {
    background: var(--color-success-bg);
}

.chip.status-ok::before {
    background: var(--color-success);
}

.chip.status-pending {
    background: var(--color-warning-bg);
}

.chip.status-pending::before {
    background: var(--color-warning);
}

.chip.status-closed {
    background: var(--surface-sunken);
    color: var(--color-text-muted);
}

/* An activity feed (case activity, P6-04): who and when on one quiet line, the text under it, a hairline between entries. */
.feed {
    list-style: none;
    margin: 0;
    padding: 0;
}

.feed-item {
    padding: var(--space-3) 0;
    border-top: 1px solid var(--line);
}

.feed-item:first-child {
    border-top: 0;
    padding-top: 0;
}

.feed-meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}

.feed-meta strong {
    color: var(--color-text);
    font-weight: 600;
}

.feed-text {
    margin: var(--space-1) 0 0;
    white-space: pre-line;
    overflow-wrap: anywhere;
}

/* Case payments (UX-13): the missing amount turns red when the payments do not cover the case amount; a paid payment shows a
   "Paid" chip, not a tinted row. */
.payment-short {
    color: var(--color-danger);
}

.chip.status-error {
    border-color: transparent;
    background: var(--color-danger-bg);
    color: var(--color-danger);
}

/* Finance (phase 12, UX-15): the VAT and date fields sit in a row under the bank ledger, set off by a hairline. */
.finance-extra {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
    gap: 0 var(--space-4);
    margin-top: var(--space-4);
    padding-top: var(--space-4);
    border-top: 1px solid var(--line);
}

/* The bank table reads like a ledger across its card: bank names in the emphasis weight, amounts right-aligned in tabular
   figures, the all-banks row set off by a stronger rule. A negative final balance and a case payment without quotation read as
   errors by colour and by their text. */
.finance-banks {
    min-width: 30rem;
}

.finance-banks tbody th {
    font-weight: var(--weight-emph);
}

.finance-banks .finance-num {
    text-align: right;
    white-space: nowrap;
}

.finance-banks tfoot th, .finance-banks tfoot td {
    border-top: 1px solid var(--line-strong);
    border-bottom: 0;
    font-weight: var(--weight-title);
}

.finance-amount {
    width: 100%;
    max-width: 11rem;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.finance-banks .finance-amount {
    height: var(--control-height-sm);
}

.finance-negative {
    color: var(--color-danger);
}

.finance-missing {
    color: var(--color-danger);
    font-weight: 600;
}

/* Finance (P7-03): the invoice line of the payment dialog; the invoice totals read as right-aligned figures. */
.finance-pay-line {
    margin: 0 0 var(--space-4);
    font-variant-numeric: tabular-nums;
}

.finance-invoice-totals dd {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* File check (P10-06, UX-19): one card per folder with its figures, the path in mono, wrapped so its end stays readable. */
.file-area h3 {
    margin: 0;
    font-size: var(--font-size-card-title);
    font-weight: var(--weight-title);
    letter-spacing: var(--tracking-title);
}

.file-area-root {
    margin: 0;
    font-family: var(--font-mono);
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    overflow-wrap: anywhere;
}

/* A quiet line under a field or inside a card: context, not a warning. */
.file-check-note {
    margin: 0;
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}

.file-area-facts dt {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.file-area-facts dd {
    margin: var(--space-1) 0 0;
    font-size: var(--font-size-lg);
    font-weight: var(--weight-title);
    font-variant-numeric: tabular-nums;
}

.file-area-newest {
    font-size: var(--font-size-sm);
}

.file-area-newest-name {
    overflow: hidden;
    max-width: 100%;
    font-weight: 600;
    white-space: nowrap;
    text-overflow: ellipsis;
}
