/*
    StockPilot Cloud admin panel.

    The decisions behind every value in this file are recorded in
    design-system/stockpilot-cloud/MASTER.md at the repository root. In one line: flat and
    minimal, data-dense, industrial slate with stock green, a mono face for headings and data and
    a sans face for labels, no shadows, no gradients, and nothing that needs a build step.

    Tokens come in three layers. Primitives are raw values and are never used by a component.
    Semantic tokens say what a value is for, and are the only layer the dark theme overrides.
    Component tokens let one component be retuned without touching the others. A deployment that
    wants its own brand colour overrides --color-accent and --color-on-accent and nothing else.

    Written mobile first: the base rules are the phone layout, and each min-width block adds to it.
*/

/* === PRIMITIVES ================================================================================ */
:root {
    --color-white: #FFFFFF;
    --color-black: #000000;

    --color-slate-50: #F8FAFC;
    --color-slate-100: #F1F5F9;
    --color-slate-200: #E2E8F0;
    --color-slate-300: #CBD5E1;
    --color-slate-400: #94A3B8;
    --color-slate-500: #64748B;
    --color-slate-600: #475569;
    --color-slate-700: #334155;
    --color-slate-800: #1E293B;
    --color-slate-900: #0F172A;
    --color-slate-950: #020617;

    --color-grey-50: #F2F3F4;
    --color-grey-100: #E6E8EA;
    /* The lightest slate that still reaches 3:1 against white, the page and the muted fill, which
       is what the boundary of a control needs when the boundary is all that identifies it. */
    --color-slate-450: #7D8CA1;

    --color-emerald-50: #ECFDF5;
    --color-emerald-300: #6EE7B7;
    --color-emerald-400: #34D399;
    --color-emerald-500: #10B981;
    --color-emerald-600: #059669;
    --color-emerald-700: #047857;
    --color-emerald-800: #065F46;
    --color-emerald-950: #022C22;

    --color-amber-50: #FFFBEB;
    --color-amber-300: #FCD34D;
    --color-amber-500: #F59E0B;
    --color-amber-600: #D97706;
    --color-amber-700: #B45309;
    --color-amber-800: #92400E;
    --color-amber-950: #451A03;

    --color-red-50: #FEF2F2;
    --color-red-300: #FCA5A5;
    --color-red-400: #F87171;
    --color-red-600: #DC2626;
    --color-red-700: #B91C1C;
    --color-red-800: #991B1B;
    --color-red-950: #450A0A;

    --color-sky-50: #F0F9FF;
    --color-sky-300: #7DD3FC;
    --color-sky-400: #38BDF8;
    --color-sky-600: #0284C7;
    --color-sky-800: #075985;
    --color-sky-950: #082F49;

    /* Density 8 of 10: a dashboard scale, not a marketing one. */
    --space-xs: 0.125rem;
    --space-sm: 0.25rem;
    --space-md: 0.5rem;
    --space-lg: 0.75rem;
    --space-xl: 1rem;
    --space-2xl: 1.5rem;
    --space-3xl: 2rem;

    --font-size-xs: 0.75rem;
    --font-size-sm: 0.875rem;
    --font-size-base: 1rem;
    --font-size-lg: 1.125rem;
    --font-size-xl: 1.5rem;
    --font-size-2xl: 2rem;

    --radius-sm: 2px;
    --radius-md: 4px;
    --radius-full: 999px;

    --duration-fast: 150ms;
    --duration-normal: 200ms;
    --ease-out: cubic-bezier(0.2, 0, 0, 1);

    --z-sticky: 10;
    --z-nav: 20;
    --z-overlay: 40;
    --z-modal: 100;
}

/* === SEMANTIC, LIGHT ========================================================================== */
:root {
    color-scheme: light dark;

    --font-sans: "Fira Sans", "Segoe UI Variable Text", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
    --font-mono: "Fira Code", "Cascadia Mono", "Cascadia Code", Consolas, ui-monospace, "SF Mono", Menlo, monospace;

    --color-background: var(--color-slate-50);
    --color-foreground: var(--color-slate-900);
    --color-card: var(--color-white);
    --color-card-foreground: var(--color-slate-900);
    --color-muted: var(--color-grey-50);
    --color-muted-foreground: var(--color-slate-600);
    --color-hover: var(--color-slate-100);
    --color-border: var(--color-grey-100);
    --color-border-control: var(--color-slate-450);

    --color-primary: var(--color-slate-700);
    --color-on-primary: var(--color-white);
    --color-secondary: var(--color-slate-600);
    --color-on-secondary: var(--color-white);

    --color-accent: var(--color-emerald-600);
    --color-accent-hover: var(--color-emerald-500);
    --color-on-accent: var(--color-black);
    --color-accent-text: var(--color-emerald-700);

    --color-destructive: var(--color-red-600);
    --color-destructive-hover: var(--color-red-700);
    --color-on-destructive: var(--color-white);
    --color-destructive-text: var(--color-red-700);

    --color-ring: var(--color-slate-700);
    --color-scrim: rgb(15 23 42 / 0.6);

    /* Status. Each has a solid for bars and marks, and a soft pair for tags and notices. */
    --color-success: var(--color-emerald-600);
    --color-success-soft: var(--color-emerald-50);
    --color-on-success-soft: var(--color-emerald-800);
    --color-warning: var(--color-amber-700);
    --color-warning-soft: var(--color-amber-50);
    --color-on-warning-soft: var(--color-amber-800);
    --color-danger: var(--color-red-600);
    --color-danger-soft: var(--color-red-50);
    --color-on-danger-soft: var(--color-red-800);
    --color-info: var(--color-sky-600);
    --color-info-soft: var(--color-sky-50);
    --color-on-info-soft: var(--color-sky-800);
    --color-neutral-soft: var(--color-slate-100);
    --color-on-neutral-soft: var(--color-slate-700);
    --color-track: var(--color-slate-200);

    /* The navigation rail is slate in both themes, so it carries its own set. */
    --color-rail: var(--color-slate-900);
    --color-rail-border: var(--color-slate-800);
    --color-rail-hover: var(--color-slate-800);
    --color-on-rail: var(--color-slate-300);
    --color-on-rail-strong: var(--color-white);
    --color-on-rail-muted: var(--color-slate-400);
    --color-rail-mark: var(--color-emerald-400);

    --font-size-body: var(--font-size-base);
    --page-gutter: var(--space-xl);
    --stack-gap: var(--space-lg);

    --sidebar-width: 15rem;
    --header-height: 3.5rem;
    --content-max: 80rem;
}

/* === SEMANTIC, DARK =========================================================================== */
@media (prefers-color-scheme: dark) {
    :root {
        --color-background: var(--color-slate-950);
        --color-foreground: var(--color-slate-100);
        --color-card: var(--color-slate-900);
        --color-card-foreground: var(--color-slate-100);
        --color-muted: var(--color-slate-800);
        --color-muted-foreground: var(--color-slate-400);
        --color-hover: var(--color-slate-800);
        --color-border: var(--color-slate-800);
        --color-border-control: var(--color-slate-500);

        --color-primary: var(--color-slate-200);
        --color-on-primary: var(--color-slate-900);
        --color-secondary: var(--color-slate-400);
        --color-on-secondary: var(--color-slate-900);

        --color-accent: var(--color-emerald-500);
        --color-accent-hover: var(--color-emerald-400);
        --color-on-accent: var(--color-black);
        --color-accent-text: var(--color-emerald-400);

        --color-destructive: var(--color-red-600);
        --color-destructive-hover: var(--color-red-700);
        --color-on-destructive: var(--color-white);
        --color-destructive-text: var(--color-red-400);

        --color-ring: var(--color-slate-200);
        --color-scrim: rgb(2 6 23 / 0.75);

        --color-success: var(--color-emerald-500);
        --color-success-soft: var(--color-emerald-950);
        --color-on-success-soft: var(--color-emerald-300);
        --color-warning: var(--color-amber-500);
        --color-warning-soft: var(--color-amber-950);
        --color-on-warning-soft: var(--color-amber-300);
        --color-danger: var(--color-red-400);
        --color-danger-soft: var(--color-red-950);
        --color-on-danger-soft: var(--color-red-300);
        --color-info: var(--color-sky-400);
        --color-info-soft: var(--color-sky-950);
        --color-on-info-soft: var(--color-sky-300);
        --color-neutral-soft: var(--color-slate-800);
        --color-on-neutral-soft: var(--color-slate-300);
        --color-track: var(--color-slate-700);
    }
}

/* === COMPONENT TOKENS ========================================================================= */
:root {
    /* Forty-four pixels, small buttons included, until the layout knows it has a mouse. A row
       action on a phone is hit with a thumb, however compact it looks. */
    --control-height: 2.75rem;
    --control-height-sm: 2.75rem;
    --control-padding-x: var(--space-lg);
    --control-radius: var(--radius-md);

    --card-radius: var(--radius-md);
    --card-padding-x: var(--space-xl);
    --card-padding-y: var(--space-lg);

    --table-cell-padding-x: var(--space-lg);
    --table-cell-padding-y: var(--space-md);
    --table-row-height: 2.25rem;

    --tag-radius: var(--radius-sm);
    --ring-width: 2px;
    --ring-offset: 2px;
    --icon-size: 1.25rem;
    --icon-size-sm: 1rem;
}

/* === BASE ===================================================================================== */
*, *::before, *::after { box-sizing: border-box; }

html {
    /* Left at the browser's own size, so somebody who has asked for larger text gets it. */
    font-size: 100%;
    -webkit-text-size-adjust: 100%;
    /* Keeps a control that takes keyboard focus clear of the bar fixed above it. */
    scroll-padding-top: calc(var(--header-height) + var(--space-md));
}

body {
    margin: 0;
    background: var(--color-background);
    color: var(--color-foreground);
    font: 400 var(--font-size-body)/1.5 var(--font-sans);
}

h1, h2, h3 {
    margin: 0;
    font-family: var(--font-mono);
    font-weight: 600;
    letter-spacing: -0.01em;
    text-wrap: balance;
}
h1 { font-size: var(--font-size-xl); line-height: 1.2; }
h2 { font-size: var(--font-size-base); line-height: 1.3; }
h3 { font-size: var(--font-size-sm); line-height: 1.3; }

/* The router moves focus to the page title after navigation, for screen readers. It is not a
   control, so it takes no ring. */
h1:focus { outline: none; }

p { margin: 0; }
a { color: var(--color-accent-text); text-underline-offset: 0.15em; }
a:hover { text-decoration-thickness: 2px; }
strong { font-weight: 600; }
img { max-width: 100%; }

:focus-visible {
    outline: var(--ring-width) solid var(--color-ring);
    outline-offset: var(--ring-offset);
}

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

.skip-link {
    position: absolute;
    left: var(--space-md);
    top: var(--space-md);
    z-index: var(--z-modal);
    padding: var(--space-md) var(--space-xl);
    background: var(--color-accent);
    color: var(--color-on-accent);
    font-weight: 600;
    border-radius: var(--radius-md);
    transform: translateY(-200%);
}
.skip-link:focus { transform: none; }

.icon {
    width: var(--icon-size);
    height: var(--icon-size);
    flex: none;
    vertical-align: -0.25em;
}
.icon-sm { width: var(--icon-size-sm); height: var(--icon-size-sm); vertical-align: -0.175em; }

/* === SHELL ==================================================================================== */
.app { min-height: 100vh; min-height: 100dvh; }

.topbar {
    position: sticky;
    top: 0;
    z-index: var(--z-sticky);
    height: var(--header-height);
    display: flex;
    align-items: center;
    gap: var(--space-md);
    padding: 0 var(--space-md);
    background: var(--color-rail);
    color: var(--color-on-rail-strong);
    border-bottom: 1px solid var(--color-rail-border);
    --color-ring: var(--color-white);
}
.topbar .btn { color: var(--color-on-rail-strong); }
.topbar .btn:hover { background: var(--color-rail-hover); }

.brand {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    min-height: 2.75rem;
    padding: 0 var(--space-md);
    color: var(--color-on-rail-strong);
    text-decoration: none;
    border-radius: var(--radius-md);
}
.brand img { width: 1.75rem; height: 1.75rem; flex: none; }
/* A client's own logo is whatever shape it is. Held to the height of the mark it replaces, and
   to a width that leaves room for the name beside it. */
.brand img.brand-logo, .brand-sample-rail img.brand-logo {
    width: auto; max-width: 6rem; object-fit: contain; object-position: left center;
    /* On a white plate, always. Most logos are drawn for white paper, and the dark lettering of
       one would otherwise vanish into the navigation, which is dark in both themes. */
    box-sizing: content-box; padding: 0.125rem 0.25rem; background: var(--color-white); border-radius: var(--radius-sm);
}
.brand-name { overflow-wrap: anywhere; }
.brand-name { display: block; font: 600 var(--font-size-base)/1.2 var(--font-mono); letter-spacing: -0.01em; }
.brand-sub { display: block; font-size: var(--font-size-xs); line-height: 1.3; color: var(--color-on-rail-muted); }

.sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    z-index: var(--z-overlay);
    width: min(17rem, 86vw);
    display: flex;
    flex-direction: column;
    padding: var(--space-lg) var(--space-md);
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--color-rail);
    color: var(--color-on-rail);
    border-right: 1px solid var(--color-rail-border);
    --color-ring: var(--color-white);

    /* Closed on a small screen: moved away with a transform, and hidden so its links leave the
       tab order instead of being reachable off screen. */
    visibility: hidden;
    transform: translateX(-100%);
    transition: transform var(--duration-normal) var(--ease-out), visibility 0s linear var(--duration-normal);
}
.sidebar.is-open {
    visibility: visible;
    transform: none;
    transition: transform var(--duration-normal) var(--ease-out), visibility 0s;
}

.scrim {
    position: fixed;
    inset: 0;
    z-index: calc(var(--z-overlay) - 1);
    width: 100%;
    padding: 0;
    border: 0;
    background: var(--color-scrim);
    cursor: pointer;
}

.sidebar .brand { margin-bottom: var(--space-lg); }

.nav-group { margin-bottom: var(--space-lg); }
.nav-heading {
    margin: 0;
    padding: var(--space-md) var(--space-lg) var(--space-sm);
    font: 600 var(--font-size-xs)/1.3 var(--font-sans);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-on-rail-muted);
}

.nav-link {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--space-lg);
    min-height: 2.75rem;
    padding: 0 var(--space-lg);
    color: var(--color-on-rail);
    text-decoration: none;
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: background-color var(--duration-fast) ease-in-out, color var(--duration-fast) ease-in-out;
}
.nav-link:hover { background: var(--color-rail-hover); color: var(--color-on-rail-strong); }
.nav-link.active {
    background: var(--color-rail-hover);
    color: var(--color-on-rail-strong);
    font-weight: 600;
}
/* Where you are is marked by position and weight as well as colour. */
.nav-link.active::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.5rem;
    bottom: 0.5rem;
    width: 3px;
    background: var(--color-rail-mark);
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}

.sidebar-foot {
    margin-top: auto;
    padding-top: var(--space-lg);
    border-top: 1px solid var(--color-rail-border);
}
.who {
    display: flex;
    align-items: center;
    gap: var(--space-lg);
    padding: var(--space-md) var(--space-lg);
    font-size: var(--font-size-sm);
    color: var(--color-on-rail-muted);
    overflow-wrap: anywhere;
}
.sidebar-foot form { margin: 0; }
.sidebar-foot .nav-link { width: 100%; border: 0; background: none; font: inherit; text-align: left; }
.sidebar-foot .nav-link:hover { background: var(--color-rail-hover); }

.main { min-width: 0; }
.main:focus { outline: none; }
.page {
    max-width: var(--content-max);
    margin: 0 auto;
    padding: var(--space-xl) var(--page-gutter) var(--space-3xl);
}

.centred {
    min-height: 100vh;
    min-height: 100dvh;
    display: grid;
    place-items: center;
    padding: var(--space-xl);
}

/* === PAGE FURNITURE =========================================================================== */
.page-header {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--space-lg) var(--space-2xl);
    margin-bottom: var(--space-xl);
}
.page-header-text { min-width: 0; flex: 1 1 24rem; }
.page-header-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-md); }
.lede {
    margin-top: var(--space-sm);
    max-width: 68ch;
    color: var(--color-muted-foreground);
}

.stack > * + * { margin-top: var(--stack-gap); }
.cluster { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-md); }
.cluster-end { justify-content: flex-end; }

/* Main column and a narrower one beside it. One column until there is room for two. */
.split { display: grid; gap: var(--stack-gap); align-items: start; }
.split > * { min-width: 0; }

.toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-lg);
    padding: var(--space-lg) var(--card-padding-x);
    background: var(--color-card);
    border: 1px solid var(--color-border);
    border-radius: var(--card-radius);
}
.toolbar .field { flex: 1 1 12rem; max-width: 22rem; }
/* A choice with the button that acts on it beside it, which needs the room of two. */
.toolbar .field-wide { flex: 2 1 22rem; max-width: 30rem; }
.cluster-tight { flex-wrap: nowrap; gap: var(--space-sm); }
.cluster-tight > .select { min-width: 0; flex: 1 1 auto; }
.toolbar .toolbar-note { flex: 1 1 100%; }

/* === CARD ===================================================================================== */
.card {
    background: var(--color-card);
    color: var(--color-card-foreground);
    border: 1px solid var(--color-border);
    border-radius: var(--card-radius);
    /* Keeps a table's header fill inside the corner radius. */
    overflow: clip;
}
.card-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-md) var(--space-lg);
    min-height: 3rem;
    padding: var(--space-md) var(--card-padding-x);
    border-bottom: 1px solid var(--color-border);
}
.card-header h2 { margin-right: auto; }
.card-header .count {
    font: 500 var(--font-size-sm)/1 var(--font-mono);
    color: var(--color-muted-foreground);
}
.card-body { padding: var(--card-padding-y) var(--card-padding-x); }
.card-body > * + * { margin-top: var(--space-lg); }
.card-footer {
    padding: var(--space-md) var(--card-padding-x);
    border-top: 1px solid var(--color-border);
    font-size: var(--font-size-sm);
    color: var(--color-muted-foreground);
}

/* === STAT TILES =============================================================================== */
.stats { display: grid; gap: var(--space-md); grid-template-columns: repeat(2, minmax(0, 1fr)); }
.stat {
    min-width: 0;
    padding: var(--space-lg) var(--card-padding-x);
    background: var(--color-card);
    border: 1px solid var(--color-border);
    border-radius: var(--card-radius);
}
.stat-label {
    font: 600 var(--font-size-xs)/1.3 var(--font-sans);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--color-muted-foreground);
}
.stat-value {
    margin-top: var(--space-sm);
    font: 600 var(--font-size-2xl)/1.1 var(--font-mono);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.02em;
    overflow-wrap: anywhere;
}
.stat-note { margin-top: var(--space-sm); font-size: var(--font-size-sm); color: var(--color-muted-foreground); }
.stat.is-alert { border-color: var(--color-danger); }
.stat.is-alert .stat-value { color: var(--color-destructive-text); }

/* === TABLE ==================================================================================== */
/* Scrolls sideways inside its own box on a narrow screen, so the page itself never does. */
.table-wrap {
    /* Positioned, so the visually hidden labels inside row buttons are measured against this
       box. Left unpositioned they are measured against the page, and one sitting in a column
       that has scrolled out of view makes the whole page scroll sideways to reach it. */
    position: relative;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

.table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--font-size-sm);
}
.table th, .table td {
    padding: var(--table-cell-padding-y) var(--table-cell-padding-x);
    text-align: left;
    vertical-align: middle;
}
.table-wide { min-width: 42rem; }

/* The outer columns line up with the card's own padding; the ones between sit closer together. */
.table th:first-child, .table td:first-child { padding-left: var(--card-padding-x); }
.table th:last-child, .table td:last-child { padding-right: var(--card-padding-x); }
.table th {
    height: var(--table-row-height);
    background: var(--color-muted);
    color: var(--color-muted-foreground);
    font: 600 var(--font-size-xs)/1.3 var(--font-sans);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    white-space: nowrap;
}
.table td {
    height: var(--table-row-height);
    border-top: 1px solid var(--color-border);
}
.table tbody tr { transition: background-color var(--duration-fast) ease-in-out; }
.table tbody tr:hover { background: var(--color-hover); }
.table tbody tr.is-selected { background: var(--color-hover); box-shadow: inset 3px 0 0 var(--color-primary); }
.table .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* A screen busy with something that must not be interrupted puts itself in one of these.
   Everything inside that can be pressed or typed in is switched off by the browser, all at once,
   and nothing about the layout changes. */
fieldset.held { min-width: 0; margin: 0; padding: 0; border: 0; }

/* What a long import is doing now: a bar and a line of words beside it. */
.import-progress {
    display: flex;
    align-items: center;
    gap: var(--space-lg);
    margin-top: var(--space-lg);
    font-size: var(--font-size-sm);
}
.import-progress progress { flex: none; width: 10rem; accent-color: var(--color-accent); }
.import-progress strong { display: block; font-weight: 600; }

/* A heading that sorts its table: a button that reads as the heading it is in. The mark is quiet
   until its column is the one sorted by, so a row of headings is still a row of words. */
.table th .sort {
    display: inline-flex;
    align-items: center;
    gap: var(--space-sm);
    min-height: 1.75rem;
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: var(--radius-sm, 0.25rem);
    background: none;
    color: inherit;
    font: inherit;
    letter-spacing: inherit;
    text-transform: inherit;
    cursor: pointer;
    transition: color var(--duration-fast) ease-in-out;
}
.table th .sort .icon { flex: none; opacity: 0.6; }
.table th .sort:hover, .table th .sort.is-sorted { color: var(--color-foreground); }
.table th .sort.is-sorted .icon { opacity: 1; }
.table .actions { text-align: right; white-space: nowrap; }
.table .actions > * + * { margin-left: var(--space-sm); }
.table .primary-cell { font-weight: 500; }
/* A leading column that says several things about its row, one under another: a handheld's name,
   its make and model, its identifier. Without a floor it is the column the browser squeezes,
   since the others will not wrap, and a forty character identifier ends up four lines deep. */
.table .col-roomy { min-width: 19rem; }

/* The particulars of a line of the audit log: several short lines of "was this, now that", kept
   as lines. */
.audit-details { white-space: pre-line; }
.table .sub { display: block; font-size: var(--font-size-xs); color: var(--color-muted-foreground); }

/* The row a comparison opens in, directly under the shelf it belongs to. */
.table tr.detail > td { padding: var(--space-xl); background: var(--color-muted); }
.table tr.detail:hover { background: none; }
.table tr.detail .table-wrap {
    background: var(--color-card);
    border: 1px solid var(--color-border);
    border-radius: var(--card-radius);
}

/* A label and its value, for facts that are not a list. */
.facts {
    display: grid;
    grid-template-columns: minmax(8rem, max-content) 1fr;
    gap: var(--space-md) var(--space-xl);
    margin: 0;
    font-size: var(--font-size-sm);
}
.facts dt { color: var(--color-muted-foreground); }
.facts dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }

.plain-list { margin-bottom: 0; padding-left: 1.25rem; }
.muted { color: var(--color-muted-foreground); }
.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.nowrap { white-space: nowrap; }
.small { font-size: var(--font-size-sm); }
.break { overflow-wrap: anywhere; }

/* === BUTTONS ================================================================================== */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-md);
    min-height: var(--control-height);
    padding: 0 var(--space-xl);
    border: 1px solid transparent;
    border-radius: var(--control-radius);
    background: transparent;
    color: var(--color-foreground);
    font: 600 var(--font-size-sm)/1 var(--font-sans);
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    touch-action: manipulation;
    transition: background-color var(--duration-fast) ease-in-out, border-color var(--duration-fast) ease-in-out, color var(--duration-fast) ease-in-out;
}
.btn-primary { background: var(--color-accent); color: var(--color-on-accent); }
.btn-primary:hover { background: var(--color-accent-hover); }
.btn-secondary { border-color: var(--color-border-control); }
.btn-secondary:hover { background: var(--color-hover); border-color: var(--color-primary); }
.btn-ghost { color: var(--color-muted-foreground); }
.btn-ghost:hover { background: var(--color-hover); color: var(--color-foreground); }
.btn-danger { border-color: var(--color-destructive-text); color: var(--color-destructive-text); }
.btn-danger:hover { background: var(--color-danger-soft); }
.btn-danger-solid { background: var(--color-destructive); color: var(--color-on-destructive); }
.btn-danger-solid:hover { background: var(--color-destructive-hover); }
.btn-sm { min-height: var(--control-height-sm); padding: 0 var(--space-lg); }
.btn-icon { width: var(--control-height); padding: 0; }
.btn-icon.btn-sm { width: var(--control-height-sm); }

.btn:disabled, .btn[aria-disabled="true"] {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
}

/* Busy: the button is already disabled by the page, and this says why. */
.btn[aria-busy="true"]::before {
    content: "";
    width: 0.875rem;
    height: 0.875rem;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: var(--radius-full);
    animation: spin 700ms linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.link-button {
    padding: 0;
    border: 0;
    background: none;
    color: var(--color-accent-text);
    font: inherit;
    text-decoration: underline;
    text-underline-offset: 0.15em;
    cursor: pointer;
}

/* === FORMS ==================================================================================== */
.field { display: flex; flex-direction: column; gap: var(--space-sm); min-width: 0; }
.field > label, .field-label {
    font: 500 var(--font-size-sm)/1.3 var(--font-sans);
    color: var(--color-foreground);
}
.hint { font-size: var(--font-size-xs); line-height: 1.4; color: var(--color-muted-foreground); }
.field-error { font-size: var(--font-size-xs); line-height: 1.4; color: var(--color-destructive-text); }

/* === BRANDING ================================================================================= */
/* The logo in use, beside what can be done with it. Shown on a muted ground so that a logo
   with a clear background, or a white one, can be told from the card it sits on. */
.brand-current { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-md); margin-bottom: var(--space-sm); }
.brand-current img {
    height: 3rem; width: auto; max-width: 12rem; object-fit: contain;
    padding: var(--space-xs); border: 1px solid var(--color-border); border-radius: var(--radius-sm);
    background: var(--color-muted);
}
/* The browser's own colour picker, sized to sit beside the box the number is typed in. */
.colour-text { max-width: 9rem; }
/* A choice with few, short answers, beside the button that acts on it. */
.select-short { width: auto; min-width: 11rem; }
.colour-pick { width: 2.75rem; height: 2.75rem; padding: 0.125rem; border: 1px solid var(--color-border-control); border-radius: var(--radius-sm); background: var(--color-card); cursor: pointer; }
/* Samples of the three surfaces a brand has to work on. Their colours are fixed and are not the
   theme's, because the point is to show both themes at once whichever one is being looked at. */
.brand-sample { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-md); padding: var(--space-md) var(--space-lg); border-radius: var(--radius-md); border: 1px solid var(--color-border); }
.brand-sample-rail { background: var(--color-rail); color: var(--color-on-rail-strong); border-color: var(--color-rail-border); }
.brand-sample-rail img { height: 1.75rem; width: 1.75rem; flex: none; }
.brand-sample-light { background: var(--color-slate-50); color: var(--color-slate-600); }
.brand-sample-dark { background: var(--color-slate-900); color: var(--color-slate-400); border-color: var(--color-slate-800); }
.brand-sample-button { display: inline-flex; align-items: center; min-height: 2.25rem; padding: 0 var(--space-lg); border-radius: var(--radius-sm); font-weight: 600; background: var(--color-accent); color: var(--color-on-accent); }
.brand-sample-link { text-decoration: underline; text-underline-offset: 0.15em; color: var(--color-accent-text); }
.brand-sample-light .brand-sample-link { color: var(--color-emerald-700); }
.brand-sample-dark .brand-sample-link { color: var(--color-emerald-400); }
.brand-sample-light .brand-sample-button, .brand-sample-dark .brand-sample-button { background: var(--color-emerald-600); color: var(--color-black); }
.brand-sample-dark .brand-sample-button { background: var(--color-emerald-500); }

.input, .select {
    width: 100%;
    min-height: var(--control-height);
    padding: 0 var(--control-padding-x);
    border: 1px solid var(--color-border-control);
    border-radius: var(--control-radius);
    background: var(--color-card);
    color: var(--color-foreground);
    /* Sixteen pixels on a phone, or iOS zooms the page every time a field takes focus. */
    font: 400 var(--font-size-base)/1.3 var(--font-sans);
    transition: border-color var(--duration-fast) ease-in-out;
}
.input::placeholder { color: var(--color-muted-foreground); opacity: 0.8; }
.input:hover, .select:hover { border-color: var(--color-primary); }
.input:focus-visible, .select:focus-visible { border-color: var(--color-primary); }
.input[aria-invalid="true"] { border-color: var(--color-destructive-text); }
.input:disabled, .select:disabled { opacity: 0.5; cursor: not-allowed; }
.select { padding-right: var(--space-md); cursor: pointer; }
.input-sm, .select-sm { min-height: var(--control-height-sm); font-size: var(--font-size-sm); }
.input-code { font-family: var(--font-mono); }

input[type="file"].input { height: auto; padding: var(--space-md) var(--control-padding-x); cursor: pointer; }

/* Fields that sit side by side while there is room and stack when there is not. */
.form-grid {
    display: grid;
    gap: var(--space-lg) var(--space-xl);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
    align-items: end;
}
.form-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-md); }

/* One field with its button beside it, the button dropping underneath when there is no room. */
.inline-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-lg) var(--space-xl); }
.inline-form .field { flex: 1 1 16rem; max-width: 40rem; }

/* A yes or no setting. A real checkbox underneath, so it is a switch to assistive technology
   and to the keyboard without a line of script. */
.switch {
    appearance: none;
    position: relative;
    flex: none;
    width: 2.75rem;
    height: 1.5rem;
    margin: 0;
    border: 1px solid var(--color-border-control);
    border-radius: var(--radius-full);
    background: var(--color-track);
    cursor: pointer;
    transition: background-color var(--duration-fast) ease-in-out, border-color var(--duration-fast) ease-in-out;
}
.switch::before {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: 1.125rem;
    height: 1.125rem;
    border: 1px solid var(--color-border-control);
    border-radius: var(--radius-full);
    background: var(--color-white);
    transition: transform var(--duration-fast) var(--ease-out);
}
.switch:checked { background: var(--color-accent); border-color: var(--color-accent); }
.switch:checked::before { transform: translateX(1.25rem); border-color: var(--color-accent); }
.switch-row { display: inline-flex; align-items: center; gap: var(--space-md); min-height: var(--control-height-sm); }
.switch-state { min-width: 2ch; font-size: var(--font-size-sm); }

/* One setting per row: what it is on the left, the control that changes it on the right. */
.setting {
    display: grid;
    gap: var(--space-md) var(--space-xl);
    align-items: center;
    padding: var(--space-lg) var(--card-padding-x);
    border-top: 1px solid var(--color-border);
}
.setting:first-child { border-top: 0; }
.setting-text { min-width: 0; }
.setting-text > * + * { margin-top: var(--space-xs); }

/* === TAGS ===================================================================================== */
/* Squared off like a shelf-edge label, and never colour alone: each carries a mark and a word. */
.tag {
    display: inline-flex;
    align-items: center;
    gap: var(--space-sm);
    padding: 0.125rem var(--space-md);
    border-radius: var(--tag-radius);
    background: var(--color-neutral-soft);
    color: var(--color-on-neutral-soft);
    font: 500 var(--font-size-xs)/1.5 var(--font-sans);
    white-space: nowrap;
}
.tag .icon { width: 0.875rem; height: 0.875rem; vertical-align: 0; }
.tag-success { background: var(--color-success-soft); color: var(--color-on-success-soft); }
.tag-warning { background: var(--color-warning-soft); color: var(--color-on-warning-soft); }
.tag-danger { background: var(--color-danger-soft); color: var(--color-on-danger-soft); }
.tag-info { background: var(--color-info-soft); color: var(--color-on-info-soft); }
.tag-muted { background: transparent; color: var(--color-muted-foreground); box-shadow: inset 0 0 0 1px var(--color-border-control); }

/* === NOTICES ================================================================================== */
.notice {
    display: flex;
    align-items: flex-start;
    gap: var(--space-lg);
    padding: var(--space-lg) var(--card-padding-x);
    border-left: 3px solid var(--color-info);
    border-radius: var(--radius-sm);
    background: var(--color-info-soft);
    color: var(--color-on-info-soft);
}
.notice .icon { margin-top: 0.125rem; }
.notice-body { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.notice-success { border-left-color: var(--color-success); background: var(--color-success-soft); color: var(--color-on-success-soft); }
.notice-error { border-left-color: var(--color-danger); background: var(--color-danger-soft); color: var(--color-on-danger-soft); }
.notice-warning { border-left-color: var(--color-warning); background: var(--color-warning-soft); color: var(--color-on-warning-soft); }
.notice-dismiss {
    flex: none;
    display: inline-grid;
    place-items: center;
    width: 1.75rem;
    height: 1.75rem;
    margin: -0.125rem -0.25rem 0 0;
    padding: 0;
    border: 0;
    border-radius: var(--radius-md);
    background: transparent;
    color: inherit;
    cursor: pointer;
    --color-ring: currentColor;
}
.notice-dismiss:hover { background: rgb(127 127 127 / 0.18); }

/* === EMPTY STATE ============================================================================== */
.empty {
    display: grid;
    justify-items: center;
    gap: var(--space-md);
    padding: var(--space-3xl) var(--card-padding-x);
    text-align: center;
}
.empty .icon { width: 2rem; height: 2rem; color: var(--color-muted-foreground); }
.empty p { max-width: 48ch; color: var(--color-muted-foreground); }
.empty .btn { margin-top: var(--space-md); }

/* === CODES ==================================================================================== */
/* A join code or an enrolment code: something read aloud across a shop floor and typed on a
   handheld, so it is set in mono with room between the characters. */
.code-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-md);
    min-height: var(--control-height-sm);
    padding: 0 var(--space-lg);
    border: 1px solid var(--color-border-control);
    border-radius: var(--radius-md);
    background: var(--color-muted);
    font: 600 var(--font-size-sm)/1 var(--font-mono);
    letter-spacing: 0.08em;
    white-space: nowrap;
}
.code-chip-lg { min-height: 3.5rem; padding: 0 var(--space-xl); font-size: var(--font-size-xl); letter-spacing: 0.12em; }

.qr {
    display: block;
    width: 12.5rem;
    height: 12.5rem;
    padding: var(--space-md);
    /* Always white, in both themes: a scanner needs the contrast the code was generated with. */
    background: var(--color-white);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
}

/* === SEGMENTED BAR ============================================================================ */
/* Parts of a whole. The legend beside it carries the numbers, and the hatching carries the two
   states that most need telling apart without colour. */
.segbar {
    display: flex;
    height: 0.75rem;
    overflow: hidden;
    background: var(--color-track);
    border-radius: var(--radius-sm);
}
.segbar-sm { height: 0.5rem; }
.seg { min-width: 2px; }
.seg-verified { background: var(--color-success); }
.seg-counted { background: var(--color-info); }
.seg-progress { background: var(--color-warning); }
.seg-disagreed {
    background-color: var(--color-danger);
    background-image: repeating-linear-gradient(135deg, transparent 0 3px, rgb(255 255 255 / 0.55) 3px 5px);
}
.seg-resolved {
    background-color: var(--color-secondary);
    background-image: repeating-linear-gradient(90deg, transparent 0 4px, rgb(255 255 255 / 0.5) 4px 5px);
}

.legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm) var(--space-xl);
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: var(--font-size-sm);
}
.legend li { display: inline-flex; align-items: center; gap: var(--space-md); }
.legend .swatch { flex: none; width: 0.75rem; height: 0.75rem; border-radius: var(--radius-sm); }
.legend .swatch-empty { background: var(--color-track); }
.legend strong { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* === STEPS ==================================================================================== */
.steps {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-md) var(--space-xl);
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: var(--font-size-sm);
}
.steps li { display: inline-flex; align-items: center; gap: var(--space-md); color: var(--color-muted-foreground); }
.steps .step-number {
    display: inline-grid;
    place-items: center;
    width: 1.5rem;
    height: 1.5rem;
    border: 1px solid var(--color-border-control);
    border-radius: var(--radius-full);
    font: 600 var(--font-size-xs)/1 var(--font-mono);
}
.steps li.is-current { color: var(--color-foreground); font-weight: 600; }
.steps li.is-current .step-number { background: var(--color-primary); border-color: var(--color-primary); color: var(--color-on-primary); }
.steps li.is-done .step-number { background: var(--color-success-soft); border-color: var(--color-success); color: var(--color-on-success-soft); }

/* === TREE ===================================================================================== */
.tree-cell { display: flex; align-items: center; gap: var(--space-md); padding-left: calc(var(--depth, 0) * 1.25rem); }
.tree-cell .branch {
    flex: none;
    width: 0.75rem;
    height: 0.75rem;
    margin-top: -0.5rem;
    border-left: 1px solid var(--color-border-control);
    border-bottom: 1px solid var(--color-border-control);
}

/* === LIVE ===================================================================================== */
.live { display: inline-flex; align-items: center; gap: var(--space-md); font-size: var(--font-size-sm); color: var(--color-muted-foreground); }
.live-dot { width: 0.5rem; height: 0.5rem; border-radius: var(--radius-full); background: var(--color-success); }
.live.is-on .live-dot { animation: pulse 2s ease-in-out infinite; }
.live.is-off .live-dot { background: var(--color-muted-foreground); }
@keyframes pulse { 50% { opacity: 0.35; } }

/* === DIALOG =================================================================================== */
.dialog {
    width: min(30rem, calc(100vw - 2rem));
    padding: 0;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-card);
    color: var(--color-card-foreground);
}
.dialog::backdrop { background: var(--color-scrim); }
.dialog-body { padding: var(--space-xl) var(--space-xl) var(--space-lg); }
.dialog-body > * + * { margin-top: var(--space-md); }
.dialog-body p { color: var(--color-muted-foreground); }
.dialog-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--space-md);
    padding: var(--space-lg) var(--space-xl);
    border-top: 1px solid var(--color-border);
}

/* The dialog Blazor shows when the connection to the server drops. The framework finds it by id
   and drives it through these class names, so the names are its, not ours. */
.components-reconnect-first-attempt-visible,
.components-reconnect-repeated-attempt-visible,
.components-reconnect-failed-visible,
.components-pause-visible,
.components-resume-failed-visible,
.components-rejoining-animation { display: none; }

#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible,
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation,
#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-repeated-attempt-visible,
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation,
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible { display: block; }

#components-reconnect-modal.components-reconnect-failed button.components-reconnect-failed-visible,
#components-reconnect-modal.components-reconnect-paused button.components-pause-visible,
#components-reconnect-modal.components-reconnect-resume-failed button.components-resume-failed-visible { display: inline-flex; }

#components-reconnect-modal .dialog-actions { display: none; }
#components-reconnect-modal.components-reconnect-failed .dialog-actions,
#components-reconnect-modal.components-reconnect-paused .dialog-actions,
#components-reconnect-modal.components-reconnect-resume-failed .dialog-actions { display: flex; }

.components-rejoining-animation {
    width: 1.5rem;
    height: 1.5rem;
    border: 2px solid var(--color-primary);
    border-right-color: transparent;
    border-radius: var(--radius-full);
    animation: spin 900ms linear infinite;
}

/* === SIGN IN ================================================================================== */
.login { width: min(24rem, 100%); }
.login .brand { margin-bottom: var(--space-xl); padding: 0; color: var(--color-foreground); }
.login .brand img { width: 2.5rem; height: 2.5rem; }
.login .brand img.brand-logo { width: auto; max-width: 9rem; }
.login .brand-name { font-size: var(--font-size-xl); }
.login .brand-sub { font-size: var(--font-size-sm); color: var(--color-muted-foreground); }
.login .card-body { padding: var(--space-2xl); }
.login .card-body > * + * { margin-top: var(--space-xl); }
.login .btn-primary { width: 100%; }
.password-row { display: flex; gap: var(--space-md); }
.password-row .input { flex: 1; min-width: 0; }

/* What to do about a forgotten password, under the sign-in form. Closed until it is asked for:
   most people at this page know their password, and a paragraph about servers is not for them. */
.login-help { margin-top: var(--space-xl); font-size: var(--font-size-sm); line-height: 1.5; color: var(--color-muted-foreground); }
.login-help > summary { width: fit-content; padding: var(--space-sm) 0; font-weight: 500; color: var(--color-foreground); cursor: pointer; }
.login-help p { margin: var(--space-md) 0 0; }
.login-help .command { margin-top: var(--space-md); }

/* === FIRST RUN AND LICENCE ==================================================================== */
/* The setup wizard and the licence page: the same frame as sign in, a little wider, because they
   carry a paragraph of explanation and a code to be read and copied. */
.login-wide { width: min(34rem, 100%); }
.login-wide h2 { margin: 0; font: 600 var(--font-size-base)/1.3 var(--font-sans); }
.login-wide .muted { margin-top: var(--space-md); }
.login-wide .btn-ghost { width: auto; }
.login-wide .stack > * + * { margin-top: var(--space-xl); }

/* Where the person is in the four steps: the same numbered steps the catalogue import uses,
   ruled off from the step itself because here they head the whole card. */
.login-wide .steps { padding-bottom: var(--space-xl); border-bottom: 1px solid var(--color-border); }

/* Host and port side by side, the port only as wide as a port is. */
.form-row { display: flex; flex-wrap: wrap; gap: var(--space-lg) var(--space-xl); align-items: flex-start; }
.form-row .field { flex: 1 1 14rem; }
.form-row .field-narrow { flex: 0 1 7rem; }

/* A pasted licence key, or anything else that is several lines of code. */
.textarea { min-height: 6rem; padding: var(--space-md) var(--control-padding-x); font-size: var(--font-size-sm); line-height: 1.5; resize: vertical; overflow-wrap: anywhere; }

/* Something to be copied exactly: the deployment ID, or the command that restarts the service. */
.command {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-md);
    padding: var(--space-md) var(--space-lg);
    border: 1px solid var(--color-border-control);
    border-radius: var(--radius-md);
    background: var(--color-muted);
}
.command code { flex: 1 1 12rem; min-width: 0; font: 600 var(--font-size-sm)/1.5 var(--font-mono); overflow-wrap: anywhere; user-select: all; }
.login-wide p + .command { margin-top: var(--space-md); }

/* The client's own logo, when the licence carries one, above the name it was issued to. What the
   licence says is laid out by .facts, like every other list of names and values in the panel. */
.licence-logo { display: block; max-width: 10rem; max-height: 3rem; margin-bottom: var(--space-md); }

.notice-list { margin: 0; padding-left: 1.1em; }
.notice-list li + li { margin-top: var(--space-sm); }

/* A heading that divides one long form into its subjects. */
.group-heading { margin: 0; font: 600 var(--font-size-sm)/1.3 var(--font-sans); }
.card-body > .group-heading { margin-top: var(--space-2xl); }

/* A notice that belongs to the whole panel rather than to one screen, above whatever is open. */
.page-notice { margin-bottom: var(--space-xl); }
.page-notice a { margin-left: var(--space-md); font-weight: 600; white-space: nowrap; }

/* === TABLET, 768 AND UP ======================================================================= */
@media (min-width: 48rem) {
    :root { --page-gutter: var(--space-2xl); }
    .page { padding-top: var(--space-2xl); }
    .stats { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* === DESKTOP, 1024 AND UP ===================================================================== */
@media (min-width: 64rem) {
    :root {
        /* Fourteen pixels with a mouse and a desk, for the density a counting screen wants. */
        --font-size-body: var(--font-size-sm);
        --control-height: 2.25rem;
        --control-height-sm: 1.75rem;
    }

    html { scroll-padding-top: var(--space-md); }

    .topbar, .scrim { display: none; }

    .sidebar, .sidebar.is-open {
        z-index: var(--z-nav);
        width: var(--sidebar-width);
        visibility: visible;
        transform: none;
        transition: none;
    }
    .nav-link { min-height: 2.25rem; }
    .main { margin-left: var(--sidebar-width); }

    .input, .select { font-size: var(--font-size-sm); }

    .split { grid-template-columns: minmax(0, 2fr) minmax(18rem, 1fr); }
    .setting { grid-template-columns: minmax(0, 1fr) minmax(12rem, 20rem); }
    .split-even { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}

/* === TOUCH ==================================================================================== */
/* A wide screen is not always a mouse: a tablet on its side, or a touchscreen laptop. Wherever
   the main pointer is a finger, controls keep their full height whatever the width. */
@media (pointer: coarse) {
    :root {
        --control-height: 2.75rem;
        --control-height-sm: 2.75rem;
    }
    .nav-link { min-height: 2.75rem; }
}

/* === WIDE, 1440 AND UP ======================================================================== */
@media (min-width: 90rem) {
    :root { --page-gutter: var(--space-3xl); }
}

/* === MOTION =================================================================================== */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* The unhandled-error bar. Blazor keeps it hidden and reveals it by setting display on the id when
   a page error cannot be recovered. A quiet strip along the foot, in the danger colours, with the
   one action that helps a dead circuit: reload. */
#blazor-error-ui {
    display: none;
    position: fixed;
    inset: auto 0 0 0;
    z-index: var(--z-modal);
    align-items: center;
    gap: var(--space-lg);
    padding: var(--space-lg) var(--space-xl);
    background: var(--color-danger-soft);
    color: var(--color-on-danger-soft);
    border-top: 2px solid var(--color-danger);
    font-size: var(--font-size-sm);
}

#blazor-error-ui .error-body { flex: 1 1 auto; }

#blazor-error-ui .reload,
#blazor-error-ui .dismiss {
    flex: 0 0 auto;
    font: inherit;
    font-weight: 600;
    color: var(--color-on-danger-soft);
    background: transparent;
    border: 1px solid var(--color-danger);
    border-radius: var(--control-radius);
    padding: var(--space-md) var(--space-lg);
    cursor: pointer;
    text-decoration: none;
}

#blazor-error-ui .reload:hover,
#blazor-error-ui .dismiss:hover { background: var(--color-danger); color: var(--color-card); }

/* Help page: screen summaries and collapsible setting topics. Namespaced so these rules
   touch nothing else. The collapsible rows are a native <details>, styled to lose the
   default marker in favour of a plus and minus that read in both themes. */
.help-screens { display: grid; gap: var(--space-lg); }
.help-screen h3 { margin: 0 0 var(--space-xs); font-size: var(--font-size-base); }
.help-screen p { margin: 0; color: var(--color-muted-foreground); }

.help-topic { border: 1px solid var(--color-border); border-radius: var(--radius-md); margin-bottom: var(--space-sm); }
.help-topic:last-child { margin-bottom: 0; }
.help-topic > summary {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-sm);
    padding: var(--space-md);
    cursor: pointer;
    list-style: none;
}
.help-topic > summary::-webkit-details-marker { display: none; }
.help-topic > summary::before {
    content: "+";
    width: 1em;
    flex: 0 0 auto;
    font-weight: 600;
    text-align: center;
    color: var(--color-muted-foreground);
}
.help-topic[open] > summary::before { content: "\2212"; }
.help-topic-title { font-weight: 600; }
.help-topic-body { padding: 0 var(--space-md) var(--space-md) calc(var(--space-md) + 1em + var(--space-sm)); }
.help-topic-body p { margin: 0 0 var(--space-sm); }
.help-topic-body h4 { margin: var(--space-md) 0 var(--space-xs); font-size: var(--font-size-sm); }
.help-topic-body ul { margin: 0; padding-left: var(--space-lg); }
.help-topic-body li { margin: var(--space-xs) 0; color: var(--color-muted-foreground); }

/* === ROLES, USER GROUPS AND LOCATIONS ========================================================= */
/* A tick box, for the places where there are many of them in a grid or a tree and a switch each
   would be a wall of switches. A real checkbox underneath, drawn to match the other controls. */
.check {
    appearance: none;
    position: relative;
    flex: none;
    width: 1.25rem;
    height: 1.25rem;
    margin: 0;
    border: 1px solid var(--color-border-control);
    border-radius: var(--radius-sm);
    background: var(--color-card);
    cursor: pointer;
    transition: background-color var(--duration-fast) ease-in-out, border-color var(--duration-fast) ease-in-out;
}
.check:hover { border-color: var(--color-primary); }
.check:checked { background: var(--color-accent); border-color: var(--color-accent); }
.check:checked::after {
    content: "";
    position: absolute;
    left: 0.375rem;
    top: 0.125rem;
    width: 0.375rem;
    height: 0.6875rem;
    border: solid var(--color-on-accent);
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}
.check:disabled { opacity: 0.5; cursor: not-allowed; }

/* A tick box with what it means beside it. The whole row is the label, so the target is the
   full width of the row rather than twenty pixels of box. */
.check-row {
    display: flex;
    align-items: flex-start;
    gap: var(--space-md);
    min-height: var(--control-height-sm);
    font-size: var(--font-size-sm);
    padding: var(--space-md) var(--space-md) var(--space-md) calc(var(--space-md) + var(--depth, 0) * 1.5rem);
    border-radius: var(--radius-sm);
    cursor: pointer;
}
.check-row:hover { background: var(--color-hover); }
.check-row .check { margin-top: 0.125rem; }
.check-row .icon { flex: none; margin-top: 0.1875rem; color: var(--color-muted-foreground); }
.check-row-text { min-width: 0; }
.check-row-text .sub { display: block; font-size: var(--font-size-xs); color: var(--color-muted-foreground); }
.check-row.is-covered { cursor: default; }

/* A list of them that scrolls inside its own box once it is long, so a deployment with two
   hundred sites does not push the Save button off the bottom of the page. */
.choice-list {
    max-height: 22rem;
    overflow-y: auto;
    border: 1px solid var(--color-border);
    border-radius: var(--control-radius);
    padding: var(--space-sm);
}

/* The role grid: screens down the side, View and Manage across.
   The name of each screen is a row header, which is right for a screen reader, and a table header
   to the stylesheet, which would set it in small capitals on a grey band and stop it wrapping.
   So it is put back to reading like the row it is. */
.permission-grid th[scope="row"] {
    height: var(--table-row-height);
    border-top: 1px solid var(--color-border);
    background: transparent;
    color: var(--color-foreground);
    font: 500 var(--font-size-sm)/1.4 var(--font-sans);
    letter-spacing: normal;
    text-transform: none;
    white-space: normal;
}
.permission-grid th[scope="row"] .sub { font-weight: 400; }
.permission-grid .check-col { width: 4.5rem; text-align: center; }
.permission-grid td.check-col { vertical-align: middle; }
.permission-grid .check { vertical-align: middle; }
.permission-grid .grid-section th { height: auto; white-space: normal; }

/* A name with a tag beside it, kept a little apart and together on one line while there is room. */
.name-with-tag { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--space-sm) var(--space-md); }

/* The two or three blocks of an editor that sit side by side while there is room. */
.editor-columns {
    display: grid;
    gap: var(--space-xl);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr));
    align-items: start;
}
.editor-columns > * { min-width: 0; }
.editor-block > * + * { margin-top: var(--space-md); }
.editor-block h3 { margin: 0; font: 600 var(--font-size-sm)/1.3 var(--font-sans); }

/* A heading part way down a block starts a new subject, so it stands clear of what is above it. */
.editor-block > * + h3 { margin-top: var(--space-xl); }

/* Fields whose labels line up along the top. The ordinary grid lines them up along the bottom,
   which suits a row of fields with a button at the end, and looks wrong once some of the fields
   have a line of help under them and others do not. */
.form-grid-top { align-items: start; }

/* A short list of names in a table cell, each with the mark that says what it is. */
.name-list { display: flex; flex-wrap: wrap; gap: var(--space-sm) var(--space-md); }
.name-list .icon { width: 0.875rem; height: 0.875rem; color: var(--color-muted-foreground); }
.name-list > span { display: inline-flex; align-items: center; gap: var(--space-xs); }

