/* Import Nimbus Design System Theme */
/**
 * Nimbus Design System - CSS Theme
 * Auto-generated from Figma Design Tokens
 *
 * This file contains all design tokens as CSS custom properties.
 * The theme automatically adapts to light/dark mode using prefers-color-scheme.
 *
 * NOTE: the @import below is hand-added and must survive regeneration from the
 * token export. Everything after it is generated.
 */

/* Global scrollbar chrome. Hand-written, kept in its own file so a token
   regeneration of this one cannot clobber it. Must stay above all rules —
   @import is only valid at the top of a stylesheet. */
/**
 * Nimbus Design System - Scrollbars
 *
 * A single floating-pill scrollbar for every scroll container: no track chrome,
 * a narrow rounded thumb inset from the container edge.
 *
 * Hand-written, and deliberately NOT part of theme.css — that file is generated
 * from the Figma token export and would lose these rules on the next sync. It is
 * imported by theme.css so consumers still get it from the one entry point.
 *
 * Two engines, two mechanisms — each ignores the other's properties, so the
 * rules coexist and Firefox degrades to the closest thing it can express:
 *   - Firefox: `scrollbar-width` / `scrollbar-color` only. Thin and recoloured,
 *     but the thumb still spans the full track — no inset pill is possible.
 *   - WebKit/Blink (Chrome, Edge, Safari, Electron): the ::-webkit-scrollbar
 *     pseudo-elements give full control, which is what produces the design.
 *
 * The inset is a transparent border on the thumb rather than a narrower track:
 * a thumb always fills its track's width, so shrinking the track would shrink
 * the hit area too. `background-clip: padding-box` keeps the border transparent
 * to the (transparent) track, leaving a centred pill with a comfortable grab
 * target either side of it.
 */

:root {
    /* Thumb colours are deliberately borders, not text: the scrollbar is chrome
       that sits beside content, and the border ramp is the token scale tuned for
       that weight. Both resolve per-theme, so the bar follows light/dark with no
       extra rules here. */
    --scrollbar-size: 10px;
    --scrollbar-inset: 3px;
    --scrollbar-thumb: var(--border-60);
    --scrollbar-thumb-hover: var(--text-paragraph);
}

/* Firefox. Set on the root and inherited, so nested scroll containers pick it
   up without each needing its own rule. */
html {
    scrollbar-width: thin;
    scrollbar-color: var(--scrollbar-thumb) transparent;
}

/* WebKit does NOT inherit scrollbar pseudo-elements, so this has to match every
   scrollable element rather than just the root. `:where()` keeps specificity at
   zero — any component rule that wants a different scrollbar overrides this
   without needing !important or a specificity fight. */
:where(*)::-webkit-scrollbar {
    width: var(--scrollbar-size);
    height: var(--scrollbar-size);
}

:where(*)::-webkit-scrollbar-track {
    background: transparent;
}

:where(*)::-webkit-scrollbar-thumb {
    background-color: var(--scrollbar-thumb);
    border: var(--scrollbar-inset) solid transparent;
    background-clip: padding-box;
    border-radius: 999px;
}

:where(*)::-webkit-scrollbar-thumb:hover {
    background-color: var(--scrollbar-thumb-hover);
}

/* The square where the vertical and horizontal bars meet: left at its default
   it paints an opaque grey patch in the corner of dual-axis scrollers. */
:where(*)::-webkit-scrollbar-corner {
    background: transparent;
}

:root {
    color-scheme: light dark;
}

/* Light Theme (Default) */
:root {
    /* Backgrounds - Surface */
    --bg-surface-primary: #ffffff;
    --bg-surface-secondary: #f5f7f9;
    --bg-page: #f6f7f9;
    --bg-surface-invert: #ffffff;
    --bg-surface-invert-2: #edeff2;
    --bg-surface-brand: #403456;

    /* Backgrounds - Buttons */
    --bg-button-primary: #303640;
    --text-button-primary: #ffffff;
    --bg-button-secondary: #edeff2;
    --bg-button-ghost: #ffffff;
    --bg-button-border: #d7dae0;
    --bg-button-disable: #edeff2;

    /* Backgrounds - Chips */
    --bg-chip-filled: #edeff2;
    --bg-chip-border: #edeff2;

    /* Backgrounds - Content Switcher */
    --bg-cs-bg: #edeff2;
    --bg-cs-highlight: #ffffff;

    /* Backgrounds - Footer */
    --bg-footer-surface-primary: #f6f7f9;
    --bg-footer-border-selected: #232933;

    /* Borders */
    --border-20: #d7dae0;
    --border-40: #d7dae0;
    --border-60: #bdc4d1;
    --border-100: #232933;
    --border-brand: #2d1b3f;

    /* Text Colors */
    --text-title: #232933;
    --text-paragraph: #5c6575;
    --text-disable: #bdc4d1;
    --text-invert: #ffffff;
    --text-brand: #2d1b3f;

    /* Icon Colors */
    --icon-hero: #171b27;
    --icon-secondary: #5c6575;
    --icon-disable: #828b99;
    --icon-brand: #675d78;

    /* Status Colors */
    --color-cleared: #589a23;
    --color-fire: #e6251e;
    --color-mode-service: #7b3fbe;
    --color-mode-weekly-test: #285cc3;
}

/* Dark Theme */
@media (prefers-color-scheme: dark) {
    :root {
        /* Backgrounds - Surface */
        --bg-surface-primary: #303640;
        --bg-surface-secondary: #464e5c;
        --bg-page: #232933;
        --bg-surface-invert: #464e5c;
        --bg-surface-invert-2: #5c6575;
        --bg-surface-brand: #d8d6dd;

        /* Backgrounds - Buttons */
        --bg-button-primary: #5c6575;
        --text-button-primary: #ffffff;
        --bg-button-secondary: #303640;
        --bg-button-ghost: #232933;
        --bg-button-border: #464e5c;
        --bg-button-disable: #303640;

        /* Backgrounds - Chips */
        --bg-chip-filled: #303640;
        --bg-chip-border: #303640;

        /* Backgrounds - Content Switcher */
        --bg-cs-bg: #464e5c;
        --bg-cs-highlight: #303640;

        /* Backgrounds - Footer */
        --bg-footer-surface-primary: #303640;
        --bg-footer-border-selected: #bdc4d1;

        /* Borders */
        --border-20: #5c6575;
        --border-40: #464e5c;
        --border-60: #5c6575;
        --border-100: #f6f7f9;
        --border-brand: #675d78;

        /* Text Colors */
        --text-title: #ffffff;
        --text-paragraph: #d7dae0;
        --text-disable: #5c6575;
        --text-invert: #232933;
        --text-brand: #2d1b3f;

        /* Icon Colors */
        --icon-hero: #ffffff;
        --icon-secondary: #d7dae0;
        --icon-disable: #bdc4d1;
        --icon-brand: #675d78;

        /* Status Colors */
        --color-cleared: #589a23;
        --color-fire: #e6251e;
        --color-mode-service: #7b3fbe;
        --color-mode-weekly-test: #285cc3;
    }
}

/* Force Light Theme */
[data-theme="light"] {
    color-scheme: light;

    /* Backgrounds - Surface */
    --bg-surface-primary: #ffffff;
    --bg-surface-secondary: #f5f7f9;
    --bg-page: #f6f7f9;
    --bg-surface-invert: #ffffff;
    --bg-surface-invert-2: #edeff2;
    --bg-surface-brand: #403456;

    /* Backgrounds - Buttons */
    --bg-button-primary: #303640;
    --text-button-primary: #ffffff;
    --bg-button-secondary: #edeff2;
    --bg-button-ghost: #ffffff;
    --bg-button-border: #d7dae0;
    --bg-button-disable: #edeff2;

    /* Backgrounds - Chips */
    --bg-chip-filled: #edeff2;
    --bg-chip-border: #edeff2;

    /* Backgrounds - Content Switcher */
    --bg-cs-bg: #edeff2;
    --bg-cs-highlight: #ffffff;

    /* Backgrounds - Footer */
    --bg-footer-surface-primary: #f6f7f9;
    --bg-footer-border-selected: #232933;

    /* Borders */
    --border-20: #d7dae0;
    --border-40: #d7dae0;
    --border-60: #bdc4d1;
    --border-100: #232933;
    --border-brand: #2d1b3f;

    /* Text Colors */
    --text-title: #232933;
    --text-paragraph: #5c6575;
    --text-disable: #bdc4d1;
    --text-invert: #ffffff;
    --text-brand: #2d1b3f;

    /* Icon Colors */
    --icon-hero: #171b27;
    --icon-secondary: #5c6575;
    --icon-disable: #828b99;
    --icon-brand: #675d78;

    /* Status Colors */
    --color-cleared: #589a23;
    --color-fire: #e6251e;
    --color-mode-service: #7b3fbe;
    --color-mode-weekly-test: #285cc3;
}

/* Force Dark Theme */
[data-theme="dark"] {
    color-scheme: dark;

    /* Backgrounds - Surface */
    --bg-surface-primary: #303640;
    --bg-surface-secondary: #464e5c;
    --bg-page: #232933;
    --bg-surface-invert: #464e5c;
    --bg-surface-invert-2: #5c6575;
    --bg-surface-brand: #d8d6dd;

    /* Backgrounds - Buttons */
    --bg-button-primary: #5c6575;
    --text-button-primary: #ffffff;
    --bg-button-secondary: #303640;
    --bg-button-ghost: #232933;
    --bg-button-border: #464e5c;
    --bg-button-disable: #303640;

    /* Backgrounds - Chips */
    --bg-chip-filled: #303640;
    --bg-chip-border: #303640;

    /* Backgrounds - Content Switcher */
    --bg-cs-bg: #464e5c;
    --bg-cs-highlight: #303640;

    /* Backgrounds - Footer */
    --bg-footer-surface-primary: #303640;
    --bg-footer-border-selected: #bdc4d1;

    /* Borders */
    --border-20: #5c6575;
    --border-40: #464e5c;
    --border-60: #5c6575;
    --border-100: #f6f7f9;
    --border-brand: #675d78;

    /* Text Colors */
    --text-title: #ffffff;
    --text-paragraph: #d7dae0;
    --text-disable: #5c6575;
    --text-invert: #232933;
    --text-brand: #2d1b3f;

    /* Icon Colors */
    --icon-hero: #ffffff;
    --icon-secondary: #d7dae0;
    --icon-disable: #bdc4d1;
    --icon-brand: #675d78;

    /* Status Colors */
    --color-cleared: #589a23;
    --color-fire: #e6251e;
    --color-mode-service: #7b3fbe;
    --color-mode-weekly-test: #285cc3;
}

/* Import Nimbus Design System Components */
/**
 * Nimbus Design System - Components Package
 * @lancontrolsystems/nimbus-web-components
 *
 * This package provides structural CSS components and layout tokens.
 * Use alongside @lancontrolsystems/nimbus-web-theme for colors.
 *
 * Usage:
 *   @import '@lancontrolsystems/nimbus-web-components/src/index.css';
 *
 * Or import individual files:
 *   @import '@lancontrolsystems/nimbus-web-components/src/tokens/typography.css';
 *   @import '@lancontrolsystems/nimbus-web-components/src/components/buttons.css';
 */

/* Tokens - CSS Custom Properties */
/**
 * Nimbus Design System - Spacing & Layout Tokens
 * Based on 4px base unit grid system
 */

:root {
    /* Spacing Scale (4px base) */
    --spacing-0: 0;
    --spacing-1: 0.25rem; /* 4px */
    --spacing-2: 0.5rem; /* 8px */
    --spacing-3: 0.75rem; /* 12px */
    --spacing-4: 1rem; /* 16px */
    --spacing-5: 1.25rem; /* 20px */
    --spacing-6: 1.5rem; /* 24px */
    --spacing-8: 2rem; /* 32px */
    --spacing-10: 2.5rem; /* 40px */
    --spacing-12: 3rem; /* 48px */
    --spacing-16: 4rem; /* 64px */

    /* Border Radius */
    --radius-none: 0;
    --radius-sm: 0.25rem; /* 4px - subtle rounding */
    --radius-md: 0.5rem; /* 8px - cards, containers */
    --radius-lg: 0.75rem; /* 12px - larger cards */
    --radius-xl: 1rem; /* 16px - buttons, modals */
    --radius-full: 9999px; /* Pill shape - chips, badges */

    /* Shadows */
    --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
    --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
    --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
    --shadow-card: 0 2px 8px rgba(0, 0, 0, 0.08);
    /* Every floating list of choices: a Select's options, a Menu, a dropdown. One value, so
       they all lift off the page by the same amount. */
    --shadow-menu: 0 8px 24px rgba(0, 0, 0, 0.2);

    /* Transitions */
    --transition-fast: 150ms ease;
    --transition-base: 200ms ease;
    --transition-slow: 300ms ease;

    /* Z-Index Scale */
    --z-dropdown: 100;
    --z-sticky: 200;
    --z-modal: 300;
    --z-tooltip: 400;
    /* A floating list of choices is portalled to the body and opened from anywhere, a modal
       or a drawer included, so it has to clear every layer above. */
    --z-menu: 1100;
}
/**
 * Nimbus Design System - Typography Tokens
 * Based on Figma Style Guide (20 Jan 2026)
 *
 * Font: Montserrat
 * Line Height: 140% (1.4)
 * Letter Spacing: 0
 * Paragraph Spacing: 10px
 */

:root {
    /* Font Family */
    --font-family: "Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

    /* Font Weights */
    --font-weight-regular: 400;
    --font-weight-medium: 500;
    --font-weight-semibold: 600;
    --font-weight-bold: 700;

    /* Font Sizes */
    --font-size-xs: 0.625rem; /* 10px */
    --font-size-sm: 0.75rem; /* 12px */
    --font-size-m: 0.9375rem; /* 15px */
    --font-size-l: 1.25rem; /* 20px */
    --font-size-xl: 1.375rem; /* 22px */

    /* The label on a pill in the pill bar (a name, "System status", "Full screen"): small
       and bold, so a row of them reads as controls rather than as text. */
    --pill-label-size: 0.6875rem; /* 11px */

    /* Line Heights */
    --line-height-default: 1.4; /* 140% */

    /* Paragraph Spacing */
    --paragraph-spacing: 0.625rem; /* 10px */
}

/* Typography Classes */

/* Extra Small */
.text-xs {
    font-family: var(--font-family);
    font-size: var(--font-size-xs);
    line-height: var(--line-height-default);
    letter-spacing: 0;
}

.text-xs-bold {
    font-family: var(--font-family);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-default);
    letter-spacing: 0;
}

/* Small */
.text-sm {
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    line-height: var(--line-height-default);
    letter-spacing: 0;
}

.text-sm-bold {
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-default);
    letter-spacing: 0;
}

/* Medium */
.text-m {
    font-family: var(--font-family);
    font-size: var(--font-size-m);
    line-height: var(--line-height-default);
    letter-spacing: 0;
}

.text-m-bold {
    font-family: var(--font-family);
    font-size: var(--font-size-m);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-default);
    letter-spacing: 0;
}

/* Large */
.text-l {
    font-family: var(--font-family);
    font-size: var(--font-size-l);
    line-height: var(--line-height-default);
    letter-spacing: 0;
}

.text-l-bold {
    font-family: var(--font-family);
    font-size: var(--font-size-l);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-default);
    letter-spacing: 0;
}

/* Extra Large */
.text-xl {
    font-family: var(--font-family);
    font-size: var(--font-size-xl);
    line-height: var(--line-height-default);
    letter-spacing: 0;
}

.text-xl-bold {
    font-family: var(--font-family);
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-default);
    letter-spacing: 0;
}
/**
 * Nimbus Design System - Page Layout Tokens
 *
 * The page the shell (app-container) lays out, and every federated module's page sits in:
 * a fixed pill bar over the top of the view, the gutters either side of the content, and
 * the space the content keeps below the bar. Published here rather than by the shell so a
 * module reads the same values whether or not the shell's stylesheet has loaded.
 */

:root {
    /* Shared because layouts below the fixed bar have to reserve its height. */
    --pill-bar-height: 44px;
    /* The space either side of the page's content, which the pill bar's right edge lines up
       with. Modules leave it to the shell rather than adding their own, and read it where
       they need to reach into it. Narrows with the window, from 48px to 28px. */
    --page-gutter: clamp(1.75rem, 3.5vw, var(--spacing-12));
    /* The space below the page's content: a little under the side gutter, so a page that
       just fits the window doesn't scroll for the sake of padding. FLARE's panels end here. */
    --page-bottom: var(--spacing-8);
    /* The widest the page's content gets, inside the gutters. A wider window centres it in the
       room beside the menus, so a table's columns don't drift hundreds of pixels apart. A
       module with fullWidth set (FLARE's monitoring screen) keeps the whole window. */
    --page-max-width: 100rem;
    /* The space above a page's content: the pill bar's top offset, the bar itself, and a gap
       under it. Every page starts here, so a title holds its place as you move between them.
       The shell pads the sides and the bottom; a page pads only its top (see .page). */
    --page-top: calc(var(--spacing-5) + var(--pill-bar-height) + var(--spacing-4));

    /* Every list's search field is the same width: it holds its width, and what shares its
       row wraps, rather than squeezing it (see .list-toolbar__search). */
    --search-width: 20rem;

    /* The height every single-line control shares — a button, a text input, a select — so
       a field and the button beside it line up without per-page overrides. */
    --control-height: 36px;
}

/* Components */
/**
 * Nimbus Design System - Button Components
 * Based on Figma Style Guide (20 Jan 2026)
 *
 * Variants: Primary, Secondary, Ghost
 * States: Default, Hover, Focus, Pressed, Disabled
 * Shape: Rounded rectangle (--radius-md / 8px)
 * Anatomy: Label + Optional Icons (leading/trailing)
 */

/* Base Button */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--spacing-2);
    /* Shared with the text input and the select, so a field and its button line up. */
    min-height: var(--control-height);
    padding: var(--spacing-2) var(--spacing-4);
    border-radius: var(--radius-md);
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
    line-height: var(--line-height-default);
    text-decoration: none;
    cursor: pointer;
    border: 1px solid transparent;
    transition:
        background-color var(--transition-fast),
        border-color var(--transition-fast),
        color var(--transition-fast),
        box-shadow var(--transition-fast);
}

/* :focus-visible rather than :focus, here and for each variant below: a button keeps focus
   after it is clicked, and a drawer or modal hands focus back to the button that opened it when
   it closes, so with :focus a mouse user's trigger stayed filled as if pressed until they clicked
   elsewhere. Keyboard focus still shows both the fill and the ring. */
.btn:focus-visible {
    outline: 2px solid var(--border-brand);
    outline-offset: 2px;
}

/* Button with icon only (square/circle) */
.btn--icon-only {
    padding: var(--spacing-2);
    aspect-ratio: 1;
}

/* ==========================================
   PRIMARY BUTTON
   High emphasis - main actions
   ========================================== */

.btn--primary {
    background-color: var(--bg-button-primary);
    border-color: var(--bg-button-primary);
    /* Not --text-invert: that tracks light-on-dark surfaces and flips to dark text in
       dark mode, where this button stays mid-grey and still needs white. */
    color: var(--text-button-primary);
}

.btn--primary:hover {
    background-color: color-mix(in srgb, var(--bg-button-primary) 85%, black);
    border-color: color-mix(in srgb, var(--bg-button-primary) 85%, black);
}

.btn--primary:focus-visible {
    background-color: color-mix(in srgb, var(--bg-button-primary) 80%, black);
    border-color: color-mix(in srgb, var(--bg-button-primary) 80%, black);
}

.btn--primary:active {
    background-color: color-mix(in srgb, var(--bg-button-primary) 70%, black);
    border-color: color-mix(in srgb, var(--bg-button-primary) 70%, black);
}

.btn--primary:disabled,
.btn--primary.btn--disabled {
    background-color: var(--bg-button-disable);
    border-color: var(--bg-button-disable);
    color: var(--text-disable);
    cursor: not-allowed;
}

/* ==========================================
   SECONDARY BUTTON
   Medium emphasis - supporting actions
   ========================================== */

.btn--secondary {
    background-color: transparent;
    border-color: var(--border-20);
    color: var(--text-title);
}

.btn--secondary:hover {
    background-color: var(--bg-button-primary);
    border-color: var(--bg-button-primary);
    color: var(--text-button-primary);
}

.btn--secondary:focus-visible {
    background-color: color-mix(in srgb, var(--bg-button-primary) 90%, black);
    border-color: color-mix(in srgb, var(--bg-button-primary) 90%, black);
    color: var(--text-button-primary);
}

.btn--secondary:active {
    background-color: color-mix(in srgb, var(--bg-button-primary) 80%, black);
    border-color: color-mix(in srgb, var(--bg-button-primary) 80%, black);
    color: var(--text-button-primary);
}

.btn--secondary:disabled,
.btn--secondary.btn--disabled {
    background-color: transparent;
    border-color: var(--border-20);
    color: var(--text-disable);
    cursor: not-allowed;
}

/* ==========================================
   GHOST BUTTON
   Low emphasis - tertiary actions
   ========================================== */

.btn--ghost {
    background-color: transparent;
    border-color: transparent;
    color: var(--text-paragraph);
}

.btn--ghost:hover {
    background-color: var(--bg-button-primary);
    border-color: var(--bg-button-primary);
    color: var(--text-button-primary);
}

.btn--ghost:focus-visible {
    background-color: color-mix(in srgb, var(--bg-button-primary) 90%, black);
    border-color: color-mix(in srgb, var(--bg-button-primary) 90%, black);
    color: var(--text-button-primary);
}

.btn--ghost:active {
    background-color: color-mix(in srgb, var(--bg-button-primary) 80%, black);
    border-color: color-mix(in srgb, var(--bg-button-primary) 80%, black);
    color: var(--text-button-primary);
}

.btn--ghost:disabled,
.btn--ghost.btn--disabled {
    background-color: transparent;
    border-color: transparent;
    color: var(--text-disable);
    cursor: not-allowed;
}

/* ==========================================
   BUTTON SIZES
   ========================================== */

.btn--sm {
    padding: var(--spacing-1) var(--spacing-3);
    font-size: var(--font-size-xs);
}

.btn--lg {
    padding: var(--spacing-3) var(--spacing-6);
    font-size: var(--font-size-m);
}

/* ==========================================
   BUTTON ICON ELEMENTS
   ========================================== */

.btn__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1em;
    height: 1em;
    flex-shrink: 0;
}

.btn__icon--leading {
    margin-right: calc(var(--spacing-1) * -1);
}

.btn__icon--trailing {
    margin-left: calc(var(--spacing-1) * -1);
}

/* ==========================================
   BUTTON GROUP
   ========================================== */

.btn-group {
    display: inline-flex;
    gap: var(--spacing-2);
}

.btn-group--vertical {
    flex-direction: column;
}
/**
 * Nimbus Design System - Breadcrumb
 *
 * Trail of ancestor links ending in the page being looked at.
 */

/* ==========================================
   TRAIL
   ========================================== */

.breadcrumb {
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    /* A trail is usually a flex item beside a page's actions. Without this it keeps its
       content's width there, so a long crumb runs it off the page instead of clipping. */
    min-width: 0;
}

.breadcrumb__list {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    gap: var(--spacing-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

/* A long ancestor is capped, and clips at the cap. In a trail too long for its room an
   ancestor gives way too, down to the current crumb's minimum, so the trail fits rather
   than running past its container. A short one like "Users" goes no narrower than its own
   width (--crumb-natural, measured by the component), so it is never clipped at all. */
.breadcrumb__item {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-2);
    flex-shrink: 1;
    min-width: min(4rem, var(--crumb-natural, 4rem));
    max-width: 16rem;
}

/* The page being looked at gives way first, down to a few characters, so a long one clips
   before any ancestor does. Its shrink weight is so much larger that an ancestor's share is
   far below a pixel until this one is at its minimum, and only then do the ancestors give
   way. */
.breadcrumb__item:last-child {
    flex-shrink: 100000;
    min-width: 4rem;
    max-width: none;
}

/* A clipped crumb that is not a link takes focus, so its tooltip can be opened from the
   keyboard; the ring matches a link crumb's. */
.breadcrumb__item:focus-visible {
    outline: 2px solid var(--border-brand);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

.breadcrumb__separator {
    color: var(--text-disable);
    flex: 0 0 auto;
    user-select: none;
}

/* ==========================================
   CRUMBS
   ========================================== */

/* A consumer's own anchor is styled alongside the component's, so a trail whose crumbs
   navigate through a router looks the same as one built from plain links. */
.breadcrumb__link,
.breadcrumb__item a {
    display: block;
    min-width: 0;
    color: var(--text-paragraph);
    text-decoration: none;
    border-radius: var(--radius-sm);
    transition: color var(--transition-fast);
    /* Clipped rather than wrapped: a trail is a single line of ancestry, and a wrapped
       crumb reads as two. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.breadcrumb__link:hover,
.breadcrumb__item a:hover {
    color: var(--text-title);
    text-decoration: underline;
}

/* Focus. The ring matches .btn, and is removed again for pointer focus so that a host
   which rings every anchor on :focus does not box a crumb that was merely clicked.

   Both :focus and :focus-visible are styled deliberately: where :focus-visible is
   unknown the browser drops both rules below, including the one inside :not(), and the
   component would fall back to whatever focus styling the host happens to apply. */
.breadcrumb__link:focus,
.breadcrumb__link:focus-visible,
.breadcrumb__item a:focus,
.breadcrumb__item a:focus-visible {
    outline: 2px solid var(--border-brand);
    outline-offset: 2px;
}

.breadcrumb__link:focus:not(:focus-visible),
.breadcrumb__item a:focus:not(:focus-visible) {
    outline: none;
}

/* A crumb with nowhere to lead: shaped like a link, without the affordances of one. */
.breadcrumb__text {
    display: block;
    min-width: 0;
    color: var(--text-paragraph);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.breadcrumb__current {
    display: block;
    min-width: 0;
    color: var(--text-title);
    font-weight: var(--font-weight-medium);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/**
 * Nimbus Design System - Chip Components
 * Based on Figma Style Guide (20 Jan 2026)
 *
 * Sizes: Small, Medium, Large
 * States: Alarm (red), Warning (amber), Online (green), Offline (gray)
 * Shape: Pill (fully rounded)
 * Anatomy: Icon + Label + Optional Time
 *
 * Hierarchy (Traffic Light System):
 * - High emphasis: Alarm (red) - most important
 * - Medium emphasis: Warning/Fault (amber)
 * - Low emphasis: Online (green)
 * - Inactive: Offline (gray)
 */

/* ==========================================
   BASE CHIP
   ========================================== */

.chip {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-1);
    border-radius: var(--radius-full);
    font-family: var(--font-family);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-default);
    white-space: nowrap;
}

/* ==========================================
   CHIP SIZES
   ========================================== */

/* Small - icon only or minimal text */
.chip--sm {
    padding: var(--spacing-1);
    font-size: var(--font-size-xs);
}

.chip--sm.chip--has-text {
    padding: var(--spacing-1) var(--spacing-2);
}

/* Medium (default) */
.chip--md {
    padding: var(--spacing-1) var(--spacing-3);
    font-size: var(--font-size-xs);
}

/* Large - with time display */
.chip--lg {
    padding: var(--spacing-2) var(--spacing-4);
    font-size: var(--font-size-sm);
}

/* ==========================================
   CHIP STATES / VARIANTS
   Traffic light system: Red > Amber > Green > Gray
   ========================================== */

/* Alarm - High emphasis (Red) */
.chip--alarm {
    background-color: #c62828;
    color: #ffffff;
}

.chip--alarm .chip__icon {
    color: #ffffff;
}

/* Warning/Fault - Medium emphasis (Amber) */
.chip--warning {
    background-color: transparent;
    color: #e65100;
    border: 1px solid currentColor;
}

.chip--warning .chip__icon {
    color: #e65100;
}

/* Online - Low emphasis (Green) */
.chip--online {
    background-color: #2e7d32;
    color: #ffffff;
}

.chip--online .chip__icon {
    color: #ffffff;
}

/* Offline - Inactive (Gray) */
.chip--offline {
    background-color: var(--bg-chip-filled);
    color: var(--text-paragraph);
}

.chip--offline .chip__icon {
    color: var(--icon-secondary);
}

/* Offline variant with red text (for emphasis when needed) */
.chip--offline-alert {
    background-color: #c62828;
    color: #ffffff;
}

/* ==========================================
   CHIP ELEMENTS
   ========================================== */

.chip__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1em;
    height: 1em;
    flex-shrink: 0;
}

.chip__label {
    flex-shrink: 0;
}

.chip__time {
    opacity: 0.9;
}

.chip__separator {
    opacity: 0.6;
}

/* ==========================================
   CHIP DISPLAY VARIANTS
   ========================================== */

/* Icon only */
.chip--icon-only {
    padding: var(--spacing-1);
    aspect-ratio: 1;
    justify-content: center;
}

/* Text only (no icon) */
.chip--text-only .chip__icon {
    display: none;
}

/* ==========================================
   CHIP GROUP / LIST
   ========================================== */

.chip-group {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-2);
}

.chip-group--vertical {
    flex-direction: column;
    align-items: flex-start;
}

/* Chip stack for hierarchical display */
.chip-stack {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2);
    align-items: flex-start;
}
/**
 * Nimbus Design System - Card Components
 * Based on Figma Style Guide (20 Jan 2026)
 *
 * Card Anatomy:
 * 1. Status chip (header)
 * 2. Information widget (data grid)
 * 3. Information expansion (tags)
 * 4. Actions (buttons)
 * 5. Timeline (status icons)
 */

/* ==========================================
   BASE CARD
   ========================================== */

.card {
    display: flex;
    flex-direction: column;
    background-color: var(--bg-surface-primary);
    border: 1px solid var(--border-20);
    border-radius: var(--radius-lg);
    overflow: hidden;
}

.card--elevated {
    box-shadow: var(--shadow-card);
    border: none;
}

/* ==========================================
   CARD SECTIONS
   ========================================== */

.card__header {
    padding: var(--spacing-4);
    padding-bottom: var(--spacing-2);
}

.card__body {
    padding: var(--spacing-4);
    padding-top: var(--spacing-2);
    padding-bottom: var(--spacing-2);
}

.card__footer {
    padding: var(--spacing-4);
    padding-top: var(--spacing-2);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-4);
    flex-wrap: wrap;
}

/* ==========================================
   ALERT CARD
   Specific layout for alert/event cards
   ========================================== */

.card--alert {
    gap: var(--spacing-2);
}

.card--alert .card__header {
    padding-bottom: var(--spacing-3);
}

/* ==========================================
   INFORMATION WIDGET
   Grid of labeled data fields
   ========================================== */

.card__info-grid {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-1);
}

.card__info-item {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-1);
    padding: var(--spacing-2) var(--spacing-3);
    background-color: var(--bg-surface-secondary);
    border-radius: var(--radius-sm);
    min-width: 80px;
}

.card__info-label {
    font-family: var(--font-family);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-regular);
    color: var(--text-paragraph);
    text-transform: capitalize;
}

.card__info-value {
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
    color: var(--text-title);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ==========================================
   INFORMATION EXPANSION
   Row of tags/labels
   ========================================== */

.card__tags {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-2);
}

.card__tag {
    display: inline-flex;
    align-items: center;
    padding: var(--spacing-1) var(--spacing-3);
    background-color: transparent;
    border: 1px solid var(--border-40);
    border-radius: var(--radius-full);
    font-family: var(--font-family);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-regular);
    color: var(--text-paragraph);
}

/* ==========================================
   CARD ACTIONS
   Button row at bottom
   ========================================== */

.card__actions {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
}

.card__actions--start {
    justify-content: flex-start;
}

.card__actions--end {
    justify-content: flex-end;
    margin-left: auto;
}

.card__actions--between {
    justify-content: space-between;
    width: 100%;
}

/* ==========================================
   TIMELINE / STATUS ICONS
   Row of status indicator icons
   ========================================== */

.card__timeline {
    display: flex;
    align-items: center;
    gap: var(--spacing-1);
}

.card__timeline-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: var(--radius-full);
    font-size: var(--font-size-xs);
}

.card__timeline-icon--active {
    background-color: var(--bg-button-primary);
    color: var(--text-button-primary);
}

.card__timeline-icon--inactive {
    background-color: var(--bg-surface-secondary);
    color: var(--icon-disable);
}

/* ==========================================
   CARD VARIANTS
   ========================================== */

/* Compact card - less padding */
.card--compact .card__header,
.card--compact .card__body,
.card--compact .card__footer {
    padding: var(--spacing-3);
}

.card--compact .card__header {
    padding-bottom: var(--spacing-1);
}

.card--compact .card__body {
    padding-top: var(--spacing-1);
    padding-bottom: var(--spacing-1);
}

.card--compact .card__footer {
    padding-top: var(--spacing-1);
}

/* Clickable card */
.card--clickable {
    cursor: pointer;
    transition:
        box-shadow var(--transition-fast),
        border-color var(--transition-fast);
}

.card--clickable:hover {
    box-shadow: var(--shadow-md);
    border-color: var(--border-60);
}

/* Selected card */
.card--selected {
    border-color: var(--border-brand);
    border-width: 2px;
}

/* ==========================================
   SECTION CARD
   One section of a page — a settings card, a module's settings — headed at 15px
   semibold, with no bands above or below and no rule under the heading.
   ========================================== */

.card--section {
    gap: var(--spacing-2);
    padding: var(--spacing-6);
    font-family: var(--font-family);
}

/* The heading and its description on one side, the section's action across from them. */
.card__section-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-4);
}

/* A step below the page title and a step above the text it heads. */
.card__section-title {
    margin: 0;
    font-family: var(--font-family);
    font-size: var(--font-size-m);
    font-weight: var(--font-weight-semibold);
    line-height: var(--line-height-default);
    color: var(--text-title);
}

.card__section-description {
    margin: 0;
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    line-height: var(--line-height-default);
    color: var(--text-paragraph);
}
/**
 * Nimbus Design System - Form Controls
 * Based on Figma Style Guide (20 Jan 2026)
 *
 * Components: Checkbox, Radio, Switch/Toggle
 */

/* ==========================================
   CHECKBOX
   States: unchecked, checked, indeterminate
   ========================================== */

.checkbox {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-2);
    cursor: pointer;
    user-select: none;
}

.checkbox__input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.checkbox__box {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    border: 2px solid var(--border-60);
    border-radius: var(--radius-sm);
    background-color: var(--bg-surface-primary);
    transition: all var(--transition-fast);
    flex-shrink: 0;
}

.checkbox__box svg,
.checkbox__box::after {
    opacity: 0;
    transition: opacity var(--transition-fast);
}

/* Checked state */
.checkbox__input:checked + .checkbox__box {
    background-color: var(--bg-button-primary);
    border-color: var(--bg-button-primary);
}

.checkbox__input:checked + .checkbox__box svg,
.checkbox__input:checked + .checkbox__box::after {
    opacity: 1;
    color: var(--text-invert);
}

/* Checkmark icon fallback */
.checkbox__box::after {
    content: "✓";
    font-size: 0.75rem;
    font-weight: bold;
    color: var(--text-invert);
}

.checkbox__input:checked + .checkbox__box::after {
    opacity: 1;
}

/* Indeterminate state */
.checkbox__input:indeterminate + .checkbox__box {
    background-color: var(--bg-button-primary);
    border-color: var(--bg-button-primary);
}

.checkbox__input:indeterminate + .checkbox__box::after {
    content: "−";
    opacity: 1;
}

/* Focus state */
.checkbox__input:focus-visible + .checkbox__box {
    outline: 2px solid var(--border-brand);
    outline-offset: 2px;
}

/* Disabled state */
.checkbox__input:disabled + .checkbox__box {
    background-color: var(--bg-button-disable);
    border-color: var(--border-20);
    cursor: not-allowed;
}

.checkbox__input:disabled ~ .checkbox__label {
    color: var(--text-disable);
    cursor: not-allowed;
}

.checkbox__label {
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    color: var(--text-title);
}

/* An indicator rather than a control: a disabled checkbox reporting a state that is changed
   elsewhere (what an organisation pays for, say). A disabled label is greyed almost out of
   sight, and the name is the part that has to be read, so it keeps a live label's colour; and
   a disabled box is greyed even when checked, leaving a white tick on near-white, so checked
   keeps its live fill and on and off are told apart by it rather than by a faint mark. */
.checkbox--indicator,
.checkbox--indicator .checkbox__input:disabled + .checkbox__box {
    cursor: default;
}

.checkbox--indicator .checkbox__input:disabled ~ .checkbox__label {
    color: var(--text-title);
    cursor: default;
}

.checkbox--indicator .checkbox__input:checked:disabled + .checkbox__box {
    background-color: var(--bg-button-primary);
    border-color: var(--bg-button-primary);
}

/* Checkbox Group */
.checkbox-group {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2);
}

.checkbox-group--horizontal {
    flex-direction: row;
    flex-wrap: wrap;
    gap: var(--spacing-4);
}

.checkbox-group__label {
    font-family: var(--font-family);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-regular);
    color: var(--text-paragraph);
    margin-bottom: var(--spacing-1);
}

/* ==========================================
   RADIO
   States: unselected, selected
   ========================================== */

.radio {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-2);
    cursor: pointer;
    user-select: none;
}

.radio__input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.radio__circle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    border: 2px solid var(--border-60);
    border-radius: var(--radius-full);
    background-color: var(--bg-surface-primary);
    transition: all var(--transition-fast);
    flex-shrink: 0;
}

.radio__circle::after {
    content: "";
    width: 0.5rem;
    height: 0.5rem;
    border-radius: var(--radius-full);
    background-color: var(--bg-button-primary);
    opacity: 0;
    transform: scale(0);
    transition: all var(--transition-fast);
}

/* Selected state */
.radio__input:checked + .radio__circle {
    border-color: var(--bg-button-primary);
}

.radio__input:checked + .radio__circle::after {
    opacity: 1;
    transform: scale(1);
}

/* Focus state */
.radio__input:focus-visible + .radio__circle {
    outline: 2px solid var(--border-brand);
    outline-offset: 2px;
}

/* Disabled state */
.radio__input:disabled + .radio__circle {
    background-color: var(--bg-button-disable);
    border-color: var(--border-20);
    cursor: not-allowed;
}

.radio__input:disabled ~ .radio__label {
    color: var(--text-disable);
    cursor: not-allowed;
}

.radio__label {
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    color: var(--text-title);
}

/* Radio Group */
.radio-group {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2);
}

.radio-group--horizontal {
    flex-direction: row;
    flex-wrap: wrap;
    gap: var(--spacing-4);
}

.radio-group__label {
    font-family: var(--font-family);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-regular);
    color: var(--text-paragraph);
    margin-bottom: var(--spacing-1);
}

/* ==========================================
   SWITCH / TOGGLE
   States: on (green), off (gray)
   Sizes: l (large), sm (small)
   ========================================== */

.switch {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-2);
    cursor: pointer;
    user-select: none;
}

.switch__input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.switch__track {
    position: relative;
    display: inline-flex;
    align-items: center;
    border-radius: var(--radius-full);
    background-color: var(--bg-chip-filled);
    transition: background-color var(--transition-fast);
    flex-shrink: 0;
}

.switch__handle {
    position: absolute;
    border-radius: var(--radius-full);
    background-color: #ffffff;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
    transition: transform var(--transition-fast);
}

/* Large size (default) */
.switch__track {
    width: 2.75rem;
    height: 1.5rem;
}

.switch__handle {
    width: 1.25rem;
    height: 1.25rem;
    left: 0.125rem;
}

/* Small size */
.switch--sm .switch__track {
    width: 2rem;
    height: 1.125rem;
}

.switch--sm .switch__handle {
    width: 0.875rem;
    height: 0.875rem;
    left: 0.125rem;
}

/* On state */
.switch__input:checked + .switch__track {
    background-color: #4caf50;
}

.switch__input:checked + .switch__track .switch__handle {
    transform: translateX(1.25rem);
}

.switch--sm .switch__input:checked + .switch__track .switch__handle {
    transform: translateX(0.875rem);
}

/* Focus state */
.switch__input:focus-visible + .switch__track {
    outline: 2px solid var(--border-brand);
    outline-offset: 2px;
}

/* Disabled state */
.switch__input:disabled + .switch__track {
    opacity: 0.5;
    cursor: not-allowed;
}

.switch__input:disabled ~ .switch__label {
    color: var(--text-disable);
    cursor: not-allowed;
}

.switch__label {
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    color: var(--text-title);
}
/**
 * Nimbus Design System - Text Inputs
 * Based on Figma Style Guide (20 Jan 2026)
 *
 * Anatomy: Label, Input Field, Helper Text, Trailing Icon
 * Variants: Default, Search
 */

/* ==========================================
   INPUT FIELD WRAPPER
   ========================================== */

.input-field {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-1);
}

.input-field__label {
    font-family: var(--font-family);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-regular);
    color: var(--text-paragraph);
}

.input-field__helper {
    font-family: var(--font-family);
    font-size: var(--font-size-xs);
    color: var(--text-paragraph);
}

.input-field__helper--error {
    color: #c62828;
}

/* ==========================================
   INPUT CONTAINER
   ========================================== */

.input {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    /* The height of the button beside it. Sized by its content alone, a field falls short of
       a button's height by a few pixels — less with an icon, more without — and every toolbar
       that put the two side by side had to pad it out itself. */
    box-sizing: border-box;
    min-height: var(--control-height);
    padding: var(--spacing-2) var(--spacing-3);
    background-color: var(--bg-surface-primary);
    border: 1px solid var(--border-40);
    border-radius: var(--radius-md);
    transition: border-color var(--transition-fast);
}

.input:hover {
    border-color: var(--border-60);
}

/* Focus is a border recolour, deliberately without an outer ring. A ring drawn outside
   the border box is clipped wherever a field sits in a scroll container (a modal body,
   a drawer), and it reads as a double-weight edge beside any plainly-bordered control. */
.input:focus-within {
    border-color: var(--border-100);
}

/* Error state */
.input--error {
    border-color: #c62828;
}

.input--error:focus-within {
    border-color: #c62828;
}

/* Disabled state */
.input--disabled {
    background-color: var(--bg-button-disable);
    border-color: var(--border-20);
    cursor: not-allowed;
}

/* ==========================================
   INPUT ELEMENT
   ========================================== */

.input__field {
    flex: 1;
    border: none;
    outline: none;
    background: transparent;
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    color: var(--text-title);
    padding: 0;
    min-width: 0;
}

.input__field::placeholder {
    color: var(--text-disable);
}

.input__field:disabled {
    cursor: not-allowed;
    color: var(--text-disable);
}

/* ==========================================
   INPUT ICONS / TRAILING
   ========================================== */

.input__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--icon-secondary);
    flex-shrink: 0;
}

.input__trailing {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-1);
    color: var(--text-paragraph);
    font-family: var(--font-family);
    font-size: var(--font-size-xs);
}

.input__clear {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    border: none;
    background: transparent;
    color: var(--icon-secondary);
    cursor: pointer;
    padding: 0;
    border-radius: var(--radius-full);
    transition: background-color var(--transition-fast);
}

.input__clear:hover {
    background-color: var(--bg-surface-secondary);
    color: var(--text-title);
}

/* ==========================================
   SEARCH INPUT
   ========================================== */

.input--search {
    padding-left: var(--spacing-3);
}

.input--search .input__icon {
    order: -1;
}

/* ==========================================
   INPUT SIZES
   ========================================== */

.input--sm {
    padding: var(--spacing-1) var(--spacing-2);
}

.input--sm .input__field {
    font-size: var(--font-size-xs);
}

.input--lg {
    padding: var(--spacing-3) var(--spacing-4);
}

.input--lg .input__field {
    font-size: var(--font-size-m);
}

/* ==========================================
   TEXTAREA
   ========================================== */

.textarea {
    display: flex;
    flex-direction: column;
    padding: var(--spacing-2) var(--spacing-3);
    background-color: var(--bg-surface-primary);
    border: 1px solid var(--border-40);
    border-radius: var(--radius-md);
    transition: border-color var(--transition-fast);
}

.textarea:hover {
    border-color: var(--border-60);
}

.textarea:focus-within {
    border-color: var(--border-100);
}

.textarea__field {
    border: none;
    outline: none;
    background: transparent;
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    color: var(--text-title);
    resize: vertical;
    min-height: 80px;
    padding: 0;
}

.textarea__field::placeholder {
    color: var(--text-disable);
}

/* ==========================================
   SELECT
   ========================================== */

.select {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    /* The height of a button and a text input, as .input explains. */
    box-sizing: border-box;
    min-height: var(--control-height);
    padding: var(--spacing-2) var(--spacing-3);
    background-color: var(--bg-surface-primary);
    border: 1px solid var(--border-40);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: border-color var(--transition-fast);
}

.select:hover {
    border-color: var(--border-60);
}

.select:focus-within {
    border-color: var(--border-100);
}

.select__field {
    flex: 1;
    border: none;
    outline: none;
    background: transparent;
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    color: var(--text-title);
    cursor: pointer;
    appearance: none;
    padding: 0;
    min-width: 0;
}

.select__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--icon-secondary);
    flex-shrink: 0;
    pointer-events: none;
}

.select--error {
    border-color: #c62828;
}

.select--error:focus-within {
    border-color: #c62828;
}

/* ==========================================
   SELECT — STYLED LISTBOX
   The variant that draws its own option menu, for designs where the OS-rendered
   native list is not acceptable.
   ========================================== */

.select--listbox {
    /* The trigger owns the padding so its hit area covers the whole control. */
    padding: 0;
}

.select--open {
    border-color: var(--border-100);
}

.select--disabled {
    background-color: var(--bg-button-disable);
    border-color: var(--border-20);
    cursor: not-allowed;
}

.select__trigger {
    flex: 1;
    /* The trigger is the whole control's hit area, so it fills the box's height rather than
       centring inside it. */
    align-self: stretch;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-2);
    padding: var(--spacing-2) var(--spacing-3);
    border: none;
    background: transparent;
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    color: var(--text-title);
    text-align: left;
    cursor: inherit;
    min-width: 0;
}

/* The wrapper renders the focus ring via :focus-within, so the button must not
   draw its own — including against a global button:focus-visible outline. */
.select__trigger:focus,
.select__trigger:focus-visible {
    outline: none;
}

.select__trigger:disabled {
    cursor: not-allowed;
}

.select__value {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.select__value--placeholder {
    color: var(--text-disable);
}

.select__icon--open {
    transform: rotate(180deg);
}

.select__menu {
    /* Fixed, and positioned from the trigger's rect, so the menu escapes any
       ancestor that clips or scrolls — a modal body, for instance. */
    position: fixed;
    z-index: var(--z-menu);
    max-width: calc(100vw - 32px);
    max-height: 318px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 2px;
    /* The menu recipe every list of choices follows: the items sit inset in a rounded
       card, so a highlighted one is a rounded row rather than a full-width band. */
    padding: var(--spacing-2);
    background-color: var(--bg-surface-primary);
    border: 1px solid var(--border-40);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-menu);
    box-sizing: border-box;
}

.select__option {
    padding: var(--spacing-2) var(--spacing-3);
    border-radius: var(--radius-md);
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    color: var(--text-title);
    cursor: pointer;
    transition: background-color var(--transition-fast);
}

/* Hovered or reached by the keyboard: a soft grey row. */
.select__option--active {
    background-color: var(--bg-cs-bg);
}

/* The current choice reads as the same row, in the heavier weight, rather than a dark
   filled chip. */
.select__option--selected {
    background-color: var(--bg-cs-bg);
    font-weight: var(--font-weight-semibold);
}

/* Disabled is pale text and nothing else: no fill, no fade, and no hover. */
.select__option--disabled,
.select__option--disabled.select__option--active {
    color: var(--text-disable);
    background-color: transparent;
    cursor: not-allowed;
}
/**
 * Nimbus Design System - Content Switcher
 * Based on Figma Style Guide (20 Jan 2026)
 *
 * Segmented control with pill highlight
 * Variants: Text labels, Icon labels
 */

/* ==========================================
   CONTENT SWITCHER CONTAINER
   ========================================== */

.switcher {
    display: inline-flex;
    align-items: center;
    padding: var(--spacing-1);
    background-color: var(--bg-cs-bg);
    border-radius: var(--radius-full);
    gap: var(--spacing-1);
}

/* ==========================================
   SWITCHER ITEM
   ========================================== */

.switcher__item {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--spacing-1);
    padding: var(--spacing-1) var(--spacing-4);
    border-radius: var(--radius-full);
    border: none;
    background: transparent;
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-regular);
    color: var(--text-paragraph);
    cursor: pointer;
    transition: all var(--transition-fast);
    white-space: nowrap;
}

.switcher__item:hover {
    color: var(--text-title);
}

/* Selected state */
.switcher__item--selected {
    background-color: var(--bg-cs-highlight);
    color: var(--text-title);
    font-weight: var(--font-weight-bold);
    box-shadow: var(--shadow-sm);
}

/* Disabled state */
.switcher__item:disabled,
.switcher__item--disabled {
    color: var(--text-disable);
    cursor: not-allowed;
}

/* ==========================================
   SWITCHER ICON
   ========================================== */

.switcher__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1rem;
    height: 1rem;
}

/* Icon-only variant */
.switcher__item--icon-only {
    padding: var(--spacing-2);
}

/* ==========================================
   SWITCHER SIZES
   ========================================== */

.switcher--sm {
    padding: 2px;
}

.switcher--sm .switcher__item {
    padding: var(--spacing-1) var(--spacing-3);
    font-size: var(--font-size-xs);
}

.switcher--lg .switcher__item {
    padding: var(--spacing-2) var(--spacing-5);
    font-size: var(--font-size-m);
}
/**
 * Nimbus Design System - Tabs
 * Based on Figma Style Guide (20 Jan 2026)
 *
 * Underline style tabs
 * States: selected (bold + underline), unselected, inactive
 * Can have icon + text labels
 */

/* ==========================================
   TABS CONTAINER
   ========================================== */

.tabs {
    display: flex;
    align-items: center;
    gap: var(--spacing-1);
    border-bottom: 1px solid var(--border-20);
}

.tabs--no-border {
    border-bottom: none;
}

/* ==========================================
   TAB ITEM
   ========================================== */

.tab {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-2);
    padding: var(--spacing-2) var(--spacing-3);
    padding-bottom: calc(var(--spacing-2) - 2px);
    border: none;
    border-radius: 0;
    background: transparent;
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-regular);
    color: var(--text-paragraph);
    cursor: pointer;
    position: relative;
    transition: color var(--transition-fast);
    white-space: nowrap;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
}

.tab:hover {
    color: var(--text-title);
}

/* Focus. The ring matches .btn, inset rather than offset so it does not collide with
   the strip's own bottom border, and is removed again for pointer focus — the selected
   underline already answers which tab is chosen, and a host that rings every button on
   :focus would otherwise box it.

   Both :focus and :focus-visible are styled deliberately: where :focus-visible is
   unknown the browser drops both rules below, including the one inside :not(), and the
   component would fall back to whatever focus styling the host happens to apply. */
.tab:focus,
.tab:focus-visible {
    outline: 2px solid var(--border-brand);
    outline-offset: -2px;
    border-radius: var(--radius-sm);
}

.tab:focus:not(:focus-visible) {
    outline: none;
    /* Square again with the ring gone. The corners are only rounded to shape the ring, and
       the selected underline is this element's own bottom border, so a radius left behind
       after a click curves its ends. */
    border-radius: 0;
}

/* Selected state */
.tab--selected {
    color: var(--text-title);
    font-weight: var(--font-weight-bold);
    border-bottom-color: var(--border-100);
}

/* Inactive/disabled state */
.tab--inactive,
.tab:disabled {
    color: var(--text-disable);
    cursor: not-allowed;
}

.tab--inactive:hover,
.tab:disabled:hover {
    color: var(--text-disable);
}

/* ==========================================
   TAB ICON
   ========================================== */

.tab__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1rem;
    height: 1rem;
    flex-shrink: 0;
}

/* ==========================================
   TAB MORE / OVERFLOW
   ========================================== */

.tab--more {
    color: var(--text-paragraph);
}

.tab--more .tab__icon {
    margin-left: var(--spacing-1);
}

/* ==========================================
   TABS VARIANTS
   ========================================== */

/* Compact tabs */
.tabs--compact .tab {
    padding: var(--spacing-1) var(--spacing-2);
    padding-bottom: calc(var(--spacing-1) - 2px);
    font-size: var(--font-size-xs);
}

/* Pill tabs (no underline, background highlight) */
.tabs--pill {
    border-bottom: none;
    background-color: var(--bg-surface-secondary);
    padding: var(--spacing-1);
    border-radius: var(--radius-md);
    gap: var(--spacing-1);
}

.tabs--pill .tab {
    border-bottom: none;
    margin-bottom: 0;
    border-radius: var(--radius-sm);
    padding: var(--spacing-1) var(--spacing-3);
}

.tabs--pill .tab--selected {
    background-color: var(--bg-surface-primary);
    box-shadow: var(--shadow-sm);
}

/* ==========================================
   TAB PANEL (content area)
   ========================================== */

.tab-panel {
    padding: var(--spacing-4) 0;
}

.tab-panel[hidden] {
    display: none;
}
/**
 * Nimbus Design System - Notifications / Toasts
 * Based on Figma Style Guide (20 Jan 2026)
 *
 * Anatomy: Icon, Title, Description, Action Button, Close Button
 * Style: Dark background, pill-shaped
 */

/* ==========================================
   NOTIFICATION / TOAST
   ========================================== */

.notification {
    display: flex;
    align-items: center;
    gap: var(--spacing-3);
    padding: var(--spacing-3) var(--spacing-4);
    background-color: #232933;
    border-radius: var(--radius-full);
    color: #ffffff;
    max-width: 480px;
    box-shadow: var(--shadow-lg);
}

/* ==========================================
   NOTIFICATION ICON
   ========================================== */

.notification__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border-radius: var(--radius-full);
    flex-shrink: 0;
}

/* Icon variants */
.notification__icon--error {
    background-color: #c62828;
    color: #ffffff;
}

.notification__icon--warning {
    background-color: #e65100;
    color: #ffffff;
}

.notification__icon--success {
    background-color: #2e7d32;
    color: #ffffff;
}

.notification__icon--info {
    background-color: #1565c0;
    color: #ffffff;
}

/* ==========================================
   NOTIFICATION CONTENT
   ========================================== */

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

.notification__title {
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
    color: #ffffff;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.notification__description {
    font-family: var(--font-family);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-regular);
    color: rgba(255, 255, 255, 0.7);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ==========================================
   NOTIFICATION ACTIONS
   ========================================== */

.notification__actions {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    flex-shrink: 0;
}

.notification__action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: var(--spacing-1) var(--spacing-3);
    border: 1px solid rgba(255, 255, 255, 0.3);
    border-radius: var(--radius-full);
    background: transparent;
    font-family: var(--font-family);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-regular);
    color: #ffffff;
    cursor: pointer;
    transition: all var(--transition-fast);
    white-space: nowrap;
}

.notification__action:hover {
    background-color: rgba(255, 255, 255, 0.1);
    border-color: rgba(255, 255, 255, 0.5);
}

.notification__close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5rem;
    height: 1.5rem;
    border: none;
    background: transparent;
    color: rgba(255, 255, 255, 0.7);
    cursor: pointer;
    padding: 0;
    border-radius: var(--radius-full);
    transition: all var(--transition-fast);
    flex-shrink: 0;
}

.notification__close:hover {
    color: #ffffff;
    background-color: rgba(255, 255, 255, 0.1);
}

/* ==========================================
   NOTIFICATION VARIANTS
   ========================================== */

/* Compact - no description */
.notification--compact {
    padding: var(--spacing-2) var(--spacing-3);
}

.notification--compact .notification__icon {
    width: 1.5rem;
    height: 1.5rem;
}

/* Light theme notification */
.notification--light {
    background-color: var(--bg-surface-primary);
    color: var(--text-title);
    border: 1px solid var(--border-20);
}

.notification--light .notification__title {
    color: var(--text-title);
}

.notification--light .notification__description {
    color: var(--text-paragraph);
}

.notification--light .notification__action {
    color: var(--text-title);
    border-color: var(--border-40);
}

.notification--light .notification__action:hover {
    background-color: var(--bg-surface-secondary);
}

.notification--light .notification__close {
    color: var(--icon-secondary);
}

.notification--light .notification__close:hover {
    color: var(--text-title);
    background-color: var(--bg-surface-secondary);
}

/* ==========================================
   NOTIFICATION CONTAINER (for stacking)
   ========================================== */

.notification-container {
    position: fixed;
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2);
    z-index: var(--z-tooltip);
    pointer-events: none;
}

.notification-container > * {
    pointer-events: auto;
}

/* Position variants */
.notification-container--top-right {
    top: var(--spacing-4);
    right: var(--spacing-4);
}

.notification-container--top-center {
    top: var(--spacing-4);
    left: 50%;
    transform: translateX(-50%);
}

.notification-container--bottom-right {
    bottom: var(--spacing-4);
    right: var(--spacing-4);
}

.notification-container--bottom-center {
    bottom: var(--spacing-4);
    left: 50%;
    transform: translateX(-50%);
}

/* Top right, just under the shell's pill bar, which is fixed over that corner: the place every
   module's notices appear, so none sits behind the bar. */
.notification-container--below-pill-bar {
    top: calc(var(--spacing-5) + var(--pill-bar-height) + var(--spacing-2));
    right: var(--spacing-5);
}
/**
 * Nimbus Design System - Inline Messages
 *
 * In-flow feedback attached to a specific piece of UI: a failed save, a validation
 * summary, a retryable load. Unlike a notification it takes up layout space beside
 * whatever it describes and stays until the state that caused it clears.
 */

/* ==========================================
   INLINE MESSAGE
   ========================================== */

.inline-message {
    /* Every tint below is mixed from this one accent, so a variant only has to
       restate the colour. */
    --inline-message-accent: #c62828;

    display: flex;
    align-items: flex-start;
    gap: var(--spacing-3);
    padding: var(--spacing-4);
    /* The palette has no error or warning surfaces, so the accent is tinted into the
       card background and softened for the border, which holds up in either theme. */
    background-color: color-mix(
        in srgb,
        var(--inline-message-accent) 10%,
        var(--bg-surface-primary)
    );
    border: 1px solid color-mix(in srgb, var(--inline-message-accent) 45%, transparent);
    border-radius: var(--radius-md);
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    color: var(--text-title);
}

/* ==========================================
   INLINE MESSAGE VARIANTS
   ========================================== */

.inline-message--error {
    --inline-message-accent: #c62828;
}

.inline-message--warning {
    --inline-message-accent: #e65100;
}

.inline-message--success {
    --inline-message-accent: #2e7d32;
}

.inline-message--info {
    --inline-message-accent: #1565c0;
}

/* ==========================================
   INLINE MESSAGE ICON
   ========================================== */

.inline-message__icon {
    display: inline-flex;
    flex-shrink: 0;
    color: var(--inline-message-accent);
    /* Sized against the message and nudged onto its first line, rather than centred on
       a block whose height changes when the text wraps. */
    font-size: 1.125rem;
    margin-top: 0.0625rem;
}

/* ==========================================
   INLINE MESSAGE CONTENT
   ========================================== */

.inline-message__content {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: var(--spacing-1);
}

.inline-message__title {
    font-weight: var(--font-weight-bold);
}

.inline-message__text {
    margin: 0;
}

/* ==========================================
   INLINE MESSAGE ACTION
   ========================================== */

.inline-message__action {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: var(--spacing-1) var(--spacing-3);
    border: 1px solid var(--inline-message-accent);
    border-radius: var(--radius-full);
    background: transparent;
    font-family: var(--font-family);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-regular);
    color: var(--text-title);
    cursor: pointer;
    transition: background-color var(--transition-fast);
    white-space: nowrap;
}

.inline-message__action:hover {
    background-color: color-mix(in srgb, var(--inline-message-accent) 15%, transparent);
}

.inline-message__action:focus-visible {
    outline: 2px solid var(--border-brand);
    outline-offset: 2px;
}

/* ==========================================
   INLINE MESSAGE VARIANTS - SIZE
   ========================================== */

/* Compact - for dense surfaces such as drawers and modals */
.inline-message--compact {
    gap: var(--spacing-2);
    padding: var(--spacing-2) var(--spacing-3);
}

.inline-message--compact .inline-message__icon {
    font-size: 1rem;
}
/**
 * Nimbus Design System - Table
 *
 * Listings of records: sites, users, groups. The default variant is a plain grid; the
 * "rows" variant gives each record its own surface separated by a gap, which is how the
 * organisation management listings read — a row is an object you act on, not a line in
 * a spreadsheet.
 */

/* ==========================================
   TABLE
   ========================================== */

.table {
    width: 100%;
    border-collapse: collapse;
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    color: var(--text-title);
}

.table__header-cell {
    padding: var(--spacing-3) var(--spacing-4);
    text-align: left;
    font-weight: var(--font-weight-semibold);
    color: var(--text-paragraph);
    background-color: var(--bg-cs-bg);
    /* A header is a word or two, and a wrapped one doubles the height of the whole row. */
    white-space: nowrap;
}

.table__row-header,
.table__cell {
    padding: var(--spacing-4);
    text-align: left;
    /* A row header identifies its row; it should not also shout. */
    font-weight: var(--font-weight-regular);
    vertical-align: middle;
}

/* A count badge never breaks. */
.table .badge {
    white-space: nowrap;
}

/* A tag stays on one line where it fits, and a column is sized for the English label. A
   longer translation ("Administrador de la organización") wraps between its words inside the
   tag rather than running out of the column. */
.table .info-tag {
    max-width: 100%;
    white-space: normal;
}

/* A value that is not there, muted so a column of them does not read as content. */
.table__empty {
    color: var(--text-disable);
}

/* ==========================================
   TABLE — FIXED LAYOUT
   ========================================== */

/* The columns share out the table's width rather than each taking what its longest value
   asks for, so one long value cannot push every column after it off the side. Values clip
   instead (Table.Text / .truncated-text). The consumer sizes the columns that hold short
   values, and gives the table a min-width to scroll below rather than squeeze past
   reading, inside a .table-scroll wrapper. */
.table--fixed {
    table-layout: fixed;
}

/* Wraps a table that may be wider than the room it gets. */
.table-scroll {
    overflow-x: auto;
}

/* ==========================================
   TABLE — INTERACTIVE ROWS
   ========================================== */

/* A row that opens what it lists (Table.Row onActivate) has to look like it does. */
.table__row--interactive {
    cursor: pointer;
}

/* Painted on the cells, not the row: the rows variant sets each row's own background at a
   specificity a hover rule on the row cannot reach, but nothing paints the cells, so they
   win on top of it. The end cells also carry the row's rounded corners. */
.table__row--interactive > * {
    transition: background-color var(--transition-fast);
}

.table__body .table__row--interactive:hover > *,
.table__body .table__row--interactive:focus-visible > * {
    background-color: var(--bg-surface-secondary);
}

/* Inset, because the rows variant leaves a gap between rows and an offset ring would sit
   in it. */
.table__row--interactive:focus-visible {
    outline: 2px solid var(--border-brand);
    outline-offset: -2px;
}

/* ==========================================
   TABLE — ROWS VARIANT
   ========================================== */

/* Each record sits on its own surface, so the rows need to be separated rather than
   ruled. border-spacing only applies to a separated border model. */
.table--rows {
    border-collapse: separate;
    border-spacing: 0 var(--spacing-2);
}

.table--rows .table__body .table__row {
    background-color: var(--bg-surface-primary);
}

/* Radii go on the end cells: a <tr> cannot be rounded in a separated border model. */
.table--rows .table__header-cell:first-child,
.table--rows .table__body .table__row > *:first-child {
    border-top-left-radius: var(--radius-md);
    border-bottom-left-radius: var(--radius-md);
}

.table--rows .table__header-cell:last-child,
.table--rows .table__body .table__row > *:last-child {
    border-top-right-radius: var(--radius-md);
    border-bottom-right-radius: var(--radius-md);
}
/**
 * Nimbus Design System - Tooltip
 *
 * A short label shown on hover or focus, and the whole of a value that has been clipped
 * for room. One look and one behaviour everywhere: React consumers get both from
 * <Tooltip>, <TruncatedText> and Table.Text, which place the tooltip in the body so no
 * clipping container can cut it off.
 */

/* ==========================================
   TOOLTIP
   ========================================== */

/* The theme's inverse pair: dark on a light page, light on a dark one. Compact and quiet:
   a short label, or a sentence of explanation at most, and never an action. */
.tooltip {
    position: fixed;
    z-index: var(--z-tooltip);
    /* The width the component sets, when it narrows a wrapped tooltip to its longest line,
       includes the padding. */
    box-sizing: border-box;
    max-width: min(17.5rem, calc(100vw - 2 * var(--spacing-2)));
    padding: var(--spacing-2) var(--spacing-3);
    border-radius: var(--radius-sm);
    background-color: var(--text-title);
    color: var(--text-invert);
    box-shadow: var(--shadow-md);
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
    line-height: var(--line-height-default);
    text-align: left;
    /* A clipped value can be one unbroken string, an email address or a pasted token, and
       it has to wrap somewhere to fit the tooltip's width. */
    overflow-wrap: anywhere;
    white-space: normal;
    pointer-events: auto;
}

/* The pointer, in the gap between the tooltip and what it labels. The component sets
   --tooltip-pointer to keep it on the trigger's centre when the tooltip has been moved
   along to stay on screen. */
.tooltip::after {
    content: "";
    position: absolute;
    border: 5px solid transparent;
}

.tooltip--top::after,
.tooltip--bottom::after {
    left: var(--tooltip-pointer, 50%);
    transform: translateX(-50%);
}

.tooltip--left::after,
.tooltip--right::after {
    top: var(--tooltip-pointer, 50%);
    transform: translateY(-50%);
}

.tooltip--top::after {
    top: 100%;
    border-top-color: var(--text-title);
}

.tooltip--bottom::after {
    bottom: 100%;
    border-bottom-color: var(--text-title);
}

.tooltip--left::after {
    left: 100%;
    border-left-color: var(--text-title);
}

.tooltip--right::after {
    right: 100%;
    border-right-color: var(--text-title);
}

/* A value too long for the window scrolls inside the tooltip, which itself stays on
   screen; the scroll is on the content so the pointer outside the box is not clipped.
   The height left is the window less the 8px gap and the padding, top and bottom. */
.tooltip__content {
    max-height: calc(100vh - 4 * var(--spacing-2));
    overflow-y: auto;
}

/* ==========================================
   TRUNCATED TEXT
   ========================================== */

/* One line, clipped with an ellipsis. Only clips when its container gives it a width to
   clip to: a fixed-layout table column, a flex item with min-width: 0, a set width. */
.truncated-text {
    display: block;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* A clipped value takes keyboard focus so its tooltip can be opened without a pointer; the
   ring matches the other controls'. */
.truncated-text:focus-visible {
    outline: 2px solid var(--border-brand);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}
/**
 * Nimbus Design System - Info Tags / Badges
 * Based on Figma Style Guide (20 Jan 2026)
 *
 * Small inline status text indicators
 * Variants: Success (green), Error (red), Warning (amber), Neutral
 */

/* ==========================================
   INFO TAG
   ========================================== */

.info-tag {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-1);
    padding: var(--spacing-1) var(--spacing-2);
    border-radius: var(--radius-full);
    font-family: var(--font-family);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-regular);
    white-space: nowrap;
}

/* Separator between parts */
.info-tag__separator {
    opacity: 0.6;
}

/* ==========================================
   INFO TAG VARIANTS
   ========================================== */

/* Success / Passed (green) */
.info-tag--success {
    background-color: rgba(46, 125, 50, 0.1);
    color: #2e7d32;
}

/* Error / Failed (red) */
.info-tag--error {
    background-color: rgba(198, 40, 40, 0.1);
    color: #c62828;
}

/* Warning (amber) */
.info-tag--warning {
    background-color: rgba(230, 81, 0, 0.1);
    color: #e65100;
}

/* Neutral / Default */
.info-tag--neutral {
    background-color: var(--bg-surface-secondary);
    color: var(--text-paragraph);
}

/* ==========================================
   BADGE
   Small pill-shaped indicator
   ========================================== */

.badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0 var(--spacing-2);
    min-width: 1.25rem;
    height: 1.25rem;
    border-radius: var(--radius-full);
    font-family: var(--font-family);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-bold);
    line-height: 1;
}

/* Badge variants */
.badge--primary {
    background-color: var(--bg-button-primary);
    color: var(--text-button-primary);
}

.badge--secondary {
    background-color: var(--bg-surface-secondary);
    color: var(--text-paragraph);
}

.badge--success {
    background-color: #2e7d32;
    color: #ffffff;
}

.badge--error {
    background-color: #c62828;
    color: #ffffff;
}

.badge--warning {
    background-color: #e65100;
    color: #ffffff;
}

/* Dot badge (no text, just indicator) */
.badge--dot {
    width: 0.5rem;
    height: 0.5rem;
    min-width: 0.5rem;
    padding: 0;
}

/* Outline badge */
.badge--outline {
    background-color: transparent;
    border: 1px solid currentColor;
}

.badge--outline.badge--primary {
    color: var(--bg-button-primary);
}

.badge--outline.badge--success {
    color: #2e7d32;
}

.badge--outline.badge--error {
    color: #c62828;
}

.badge--outline.badge--warning {
    color: #e65100;
}
/**
 * Nimbus Design System - Card Repeater Component
 *
 * A panel/list container that wraps repeated Card entries.
 * Shows either a list of cards or a centered empty state.
 *
 * Usage:
 *   <div class="card-repeater">
 *     <div class="card-repeater__header">
 *       <span class="card-repeater__title">Events <span class="card-repeater__title-count">· 2</span></span>
 *       <div class="card-repeater__actions">...</div>
 *     </div>
 *     <div class="card-repeater__body">
 *       <div class="card-repeater__list">...</div>
 *       \3c !-- or when empty: -->
 *       <div class="card-repeater__empty">
 *         <span class="card-repeater__empty-icon">...</span>
 *         <span class="card-repeater__empty-label">Events cleared</span>
 *       </div>
 *     </div>
 *   </div>
 */

/* ==========================================
   CARD REPEATER CONTAINER
   ========================================== */

.card-repeater {
    display: flex;
    flex-direction: column;
    background-color: var(--bg-surface-primary);
    border: 1px solid var(--border-20);
    border-radius: var(--radius-lg);
    overflow: hidden;
    min-height: 0;
}

/* ==========================================
   HEADER
   Title row with optional action buttons
   ========================================== */

.card-repeater__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--spacing-4);
    flex-shrink: 0;
}

.card-repeater__title {
    font-family: var(--font-family);
    font-size: var(--font-size-m);
    font-weight: var(--font-weight-bold);
    color: var(--text-title);
}

.card-repeater__title-count {
    font-weight: var(--font-weight-bold);
    color: var(--text-paragraph);
}

.card-repeater__actions {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
}

/* ==========================================
   BODY
   ========================================== */

.card-repeater__body {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

/* ==========================================
   CARD LIST
   Populated state — stacked cards
   ========================================== */

.card-repeater__list {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-6);
    padding: var(--spacing-6);
    padding-top: 0;
    padding-right: var(--spacing-2);
    margin-right: var(--spacing-2);
    overflow-y: auto;
    min-height: 0;
}

/* ==========================================
   EMPTY STATE
   Centred icon + label when no cards present
   ========================================== */

.card-repeater__empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--spacing-3);
    padding: var(--spacing-8);
    flex: 1;
    min-height: 200px;
}

.card-repeater__empty-icon {
    color: var(--icon-disable);
    font-size: 1.5rem;
    display: flex;
    align-items: center;
    justify-content: center;
}

.card-repeater__empty-label {
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-regular);
    color: var(--text-paragraph);
}
/**
 * Nimbus Design System - Drawer Component
 * A slide-in panel from the right side of the screen
 */

/* ==========================================
   OVERLAY / BACKDROP
   ========================================== */

.drawer-overlay {
    position: fixed;
    inset: 0;
    background-color: rgba(0, 0, 0, 0.4);
    z-index: var(--z-modal);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--transition-slow);
}

.drawer-overlay--open {
    opacity: 1;
    pointer-events: all;
}

/* ==========================================
   DRAWER PANEL
   ========================================== */

.drawer {
    position: fixed;
    top: var(--spacing-4);
    bottom: var(--spacing-4);
    right: var(--spacing-4);
    height: auto;
    width: 575px;
    max-width: calc(100vw - var(--spacing-4) * 2);
    background-color: var(--bg-surface-primary);
    border: 1px solid var(--border-20);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    z-index: var(--z-modal);
    display: flex;
    flex-direction: column;
    transform: translateX(calc(100% + var(--spacing-4)));
    transition:
        transform var(--transition-slow),
        top var(--transition-slow),
        bottom var(--transition-slow),
        right var(--transition-slow),
        width var(--transition-slow),
        max-width var(--transition-slow),
        border-radius var(--transition-slow);
}

.drawer--open {
    transform: translateX(0);
}

.drawer--expanded {
    top: 0;
    bottom: 0;
    right: 0;
    width: 86vw;
    max-width: 86vw;
    border-radius: 0;
}

/* ==========================================
   DRAWER HEADER
   ========================================== */

.drawer__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-3);
    padding: var(--spacing-3) var(--spacing-4);
    border-bottom: 1px solid var(--border-20);
    flex-shrink: 0;
}

.drawer__header-left {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    flex-shrink: 0;
}


.drawer__header-actions {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    flex-shrink: 0;
}

/* Declared rather than inherited: the buttons beside it set their own line-height, so a
   title taking the page's instead gives the header two differently-measured boxes, and
   centring them looks wrong however faithfully it is done. */
.drawer__title {
    font-family: var(--font-family);
    font-size: var(--font-size-l);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-default);
    color: var(--text-title);
    margin: 0;
    flex: 1;
}

/* ==========================================
   DRAWER BODY
   ========================================== */

.drawer__body {
    flex: 1;
    overflow-y: auto;
    padding: var(--spacing-6);
}
/**
 * Nimbus Design System - Modal Component
 */

/* ==========================================
   BACKDROP
   ========================================== */

.modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: var(--z-modal);
    padding: var(--spacing-4);
}

/* ==========================================
   MODAL CONTAINER
   ========================================== */

.modal {
    background: var(--bg-surface-primary);
    border: 1px solid var(--border-20);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    padding: var(--spacing-6);
    width: 480px;
    max-width: 100%;
    max-height: calc(100vh - var(--spacing-4) * 2);
    display: flex;
    flex-direction: column;
    gap: var(--spacing-4);
    /* Portalled to the body, so it can't count on inheriting a font from the app root. */
    font-family: var(--font-family);
}

.modal--sm {
    width: 360px;
}

.modal--lg {
    width: 640px;
}

/* ==========================================
   MODAL SECTIONS
   ========================================== */

.modal__header {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-1);
}

.modal__title {
    margin: 0;
    font-family: var(--font-family);
    font-size: var(--font-size-l);
    font-weight: var(--font-weight-bold);
    color: var(--text-title);
}

.modal__subtitle {
    margin: 0;
    font-family: var(--font-family);
    font-size: var(--font-size-m);
    font-weight: var(--font-weight-regular);
    color: var(--text-paragraph);
}

.modal__body {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-3);
    overflow-y: auto;
}

.modal__footer {
    display: flex;
    justify-content: flex-end;
    gap: var(--spacing-2);
    margin-top: var(--spacing-2);
}
/**
 * Nimbus Design System - Status Pill
 * Based on Figma Style Guide
 *
 * Outlined pill indicator showing a current status or mode.
 * Renders as a <span> by default; use the interactive variant for clickable pills.
 */

.status-pill {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-2);
    padding: var(--spacing-2) var(--spacing-4);
    border-radius: var(--radius-md);
    background-color: var(--bg-surface-primary);
    border: 1px solid var(--border-20);
    border-bottom-width: 2px;
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-regular);
    color: var(--text-title);
    white-space: nowrap;
}

.status-pill--interactive {
    cursor: pointer;
}

.status-pill--interactive:hover:not(:disabled) {
    background-color: var(--bg-surface-secondary);
    border-color: var(--border-40);
}

.status-pill--interactive:focus-visible {
    outline: 2px solid var(--border-brand);
    outline-offset: 2px;
}

.status-pill--interactive:disabled {
    cursor: not-allowed;
    opacity: 0.5;
}
/**
 * Nimbus Design System - Page
 *
 * The frame of a module's page inside the shell: where it starts below the pill bar, and its
 * title. The shell pads a page's sides and bottom (--page-gutter, --page-bottom); a page pads
 * only its top, so every page's title holds the same place as you move between them.
 */

/* ==========================================
   PAGE
   ========================================== */

.page {
    padding-top: var(--page-top);
}

/* ==========================================
   PAGE TITLE
   ========================================== */

/* The page title's style everywhere: the top of the type scale, as .text-xl-bold. */
.page-title {
    margin: 0 0 var(--spacing-6);
    font-family: var(--font-family);
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-default);
    color: var(--text-title);
}

/* A line under the title; the gap under the page's heading moves below it. */
.page-title:has(+ .page-subtitle) {
    margin-bottom: var(--spacing-2);
}

.page-subtitle {
    margin: 0 0 var(--spacing-6);
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    line-height: var(--line-height-default);
    color: var(--text-paragraph);
}
/**
 * Nimbus Design System - List Toolbar
 *
 * The row above a listing (sites, users, groups, organisations): its search, any filters
 * beside it, and the page's action at the far end.
 *
 * Anatomy: search, filters, actions
 */

/* ==========================================
   LIST TOOLBAR
   ========================================== */

.list-toolbar {
    display: flex;
    align-items: center;
    /* Wraps rather than squeezing the search field to nothing on a narrow window. */
    flex-wrap: wrap;
    gap: var(--spacing-3);
    margin-bottom: var(--spacing-5);
}

/* Every list's search field is the same width: it holds its width, and what shares its row
   wraps, rather than squeezing it. */
.list-toolbar__search {
    box-sizing: border-box;
    flex: 0 1 var(--search-width);
    max-width: 100%;
}

/* The page's actions, as a group: a primary button, or a few side by side. */
.list-toolbar__actions {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--spacing-2);
}

/* The last item, the page's action, at the far end of the row, and still there when the row
   wraps. Not when it is the only item: a lone search stays at the start. */
.list-toolbar > *:last-child:not(:first-child) {
    margin-left: auto;
}

@media (max-width: 640px) {
    /* Full width once wrapped, so the action is not stranded mid-row. */
    .list-toolbar > *:last-child:not(:first-child) {
        margin-left: 0;
    }
}
/**
 * Nimbus Design System - Empty State
 *
 * What a listing or a page shows where its content would be: nothing created yet, nothing
 * matching a search, nothing to show until one is made. A surface of its own, centred, with
 * what to do about it underneath.
 *
 * Anatomy: icon, title, description, actions
 */

/* ==========================================
   EMPTY STATE
   ========================================== */

.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--spacing-2);
    box-sizing: border-box;
    width: 100%;
    min-height: 12.5rem;
    padding: var(--spacing-8) var(--spacing-6);
    text-align: center;
    font-family: var(--font-family);
    background: var(--bg-surface-primary);
    border: 1px solid var(--border-20);
    border-radius: var(--radius-lg);
}

.empty-state__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin-bottom: var(--spacing-2);
    font-size: 2rem;
    color: var(--icon-secondary);
}

.empty-state__title {
    margin: 0;
    font-size: var(--font-size-m);
    font-weight: var(--font-weight-regular);
    line-height: var(--line-height-default);
    color: var(--text-title);
}

.empty-state__description {
    margin: 0;
    font-size: var(--font-size-sm);
    line-height: var(--line-height-default);
    color: var(--text-paragraph);
}

/* What to do about it, set apart from the words: the gap under the description is the
   one empty listings have always had before their button. */
.empty-state__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--spacing-2);
    margin-top: var(--spacing-4);
}

/* Inside a surface that is already there (a panel, a pane): the same layout and words,
   without a card of its own, and filling what is left of a flex column. */
.empty-state--plain {
    flex: 1;
    background: none;
    border: none;
    border-radius: 0;
}

/* The words held to a readable measure, for a card that spans a wide listing. */
.empty-state--narrow .empty-state__title,
.empty-state--narrow .empty-state__description {
    max-width: 32rem;
}

@media (max-width: 640px) {
    .empty-state {
        min-height: 0;
        padding: var(--spacing-6) var(--spacing-4);
    }
}
/**
 * Nimbus Design System - Menu
 *
 * The one design for a floating list of choices: a dropdown of actions, a page's navigation
 * menu, a filter's options. It is the Select's own menu (inputs.css, .select__menu and
 * .select__option) with room for icons, group headings and dividers, so a Select and a Menu
 * opened side by side are the same thing to look at.
 *
 * Anatomy: surface, items (icon, label), group labels, dividers
 *
 * One shadow (--shadow-menu) and one layer (--z-menu) for every menu: it is portalled to the
 * body and may open from inside a modal or a drawer, so it clears them all.
 */

/* ==========================================
   MENU SURFACE
   ========================================== */

.menu {
    z-index: var(--z-menu);
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    gap: 2px;
    /* At least as wide as what it opens under, which the React Menu publishes. */
    min-width: max(12rem, var(--menu-anchor-width, 0px));
    max-width: calc(100vw - 32px);
    overflow-y: auto;
    /* The items sit inset in a rounded card, so a highlighted one is a rounded row rather than
       a full-width band. */
    padding: var(--spacing-2);
    background-color: var(--bg-surface-primary);
    border: 1px solid var(--border-40);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-menu);
    font-family: var(--font-family);
}

/* Focus sits on the list itself until an arrow key reaches an item; the item shows it. */
.menu:focus {
    outline: none;
}

/* ==========================================
   MENU ITEM
   The pill bar's dropdowns (pills.css) list their items with the same rules.
   ========================================== */

.menu__item,
.pill-dropdown__item {
    display: flex;
    align-items: center;
    gap: var(--spacing-3);
    box-sizing: border-box;
    width: 100%;
    margin: 0;
    padding: var(--spacing-2) var(--spacing-3);
    background: none;
    border: none;
    border-radius: var(--radius-md);
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-regular);
    line-height: var(--line-height-default);
    color: var(--text-title);
    text-align: left;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color var(--transition-fast);
}

/* Hovered or reached by the keyboard: a soft grey row, as a Select's option. */
.menu__item:hover,
.menu__item--active,
.pill-dropdown__item:hover {
    background-color: var(--bg-cs-bg);
    /* Against a global link hover that fades it. */
    opacity: 1;
}

.menu__item:focus,
.pill-dropdown__item:focus {
    outline: none;
}

.menu__item:focus-visible,
.pill-dropdown__item:focus-visible {
    background-color: var(--bg-cs-bg);
    /* Inset, so the ring is not clipped by the menu's own edge. */
    outline: 2px solid var(--border-brand);
    outline-offset: -2px;
}

/* The current choice, or the page showing: the same row, in the heavier weight, rather than a
   dark filled chip. */
.menu__item--selected,
.menu__item[aria-checked="true"],
.menu__item[aria-current="page"] {
    background-color: var(--bg-cs-bg);
    font-weight: var(--font-weight-semibold);
}

/* Disabled is pale text and nothing else: no fill, no fade, and no hover — against the
   global button:disabled a host may set too. */
.menu__item:disabled,
.menu__item[aria-disabled="true"],
.menu__item--disabled,
.pill-dropdown__item:disabled {
    color: var(--text-disable);
    background: transparent;
    opacity: 1;
    cursor: not-allowed;
}

.menu__item-icon,
.pill-dropdown__item-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    min-width: 1rem;
    font-size: 1rem;
    color: var(--icon-secondary);
}

.menu__item:disabled .menu__item-icon,
.menu__item[aria-disabled="true"] .menu__item-icon,
.menu__item--disabled .menu__item-icon {
    color: var(--icon-disable);
}

/* Cut with an ellipsis rather than widening the menu past its trigger's reach. */
.menu__item-label {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ==========================================
   GROUPS & DIVIDERS
   ========================================== */

.menu__group {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

/* A group's heading: small capitals in the paragraph colour, a step back from its items. */
.menu__group-label {
    margin: var(--spacing-2) 0 var(--spacing-1);
    padding: 0 var(--spacing-3);
    font-family: var(--font-family);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-default);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text-paragraph);
}

/* The first group's heading starts the menu: the menu's own padding is room enough. */
.menu > .menu__group:first-child .menu__group-label {
    margin-top: var(--spacing-1);
}

.menu__divider,
.pill-dropdown__divider {
    flex-shrink: 0;
    height: 1px;
    margin: var(--spacing-2) 0;
    background-color: var(--border-20);
    border: none;
}
/**
 * Nimbus Design System - Pills
 *
 * The round triggers in the shell's pill bar (the account, full screen, a module's own, such
 * as FLARE's system status) and the dropdown each one opens. The bar itself — where it sits
 * and how its pills are spaced — is the shell's; these are the pills, so a module that draws
 * one looks like the shell's own.
 *
 * Anatomy: pill (avatar, label, chevron), dropdown (header, menu items, divider)
 */

/* ==========================================
   PILL TRIGGER
   ========================================== */

.pill {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-2);
    height: var(--pill-bar-height);
    padding: 0 var(--spacing-3);
    border-radius: var(--radius-full);
    background-color: var(--bg-surface-primary);
    border: 1px solid var(--border-40);
    cursor: pointer;
    transition:
        background-color var(--transition-fast),
        border-color var(--transition-fast),
        box-shadow var(--transition-fast);
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    color: var(--text-title);
    box-shadow: var(--shadow-sm);
}

.pill:hover {
    background-color: var(--bg-surface-secondary);
    border-color: var(--border-60);
}

.pill:focus {
    outline: none;
}

.pill:focus-visible {
    outline: 2px solid var(--bg-button-primary);
    outline-offset: 2px;
}

.pill--active {
    background-color: var(--bg-surface-secondary);
    border-color: var(--border-60);
}

/* ==========================================
   PILL CONTENTS
   ========================================== */

.pill__avatar {
    width: 28px;
    height: 28px;
    border-radius: var(--radius-full);
    object-fit: cover;
    flex-shrink: 0;
}

.pill__avatar-placeholder {
    width: 28px;
    height: 28px;
    border-radius: var(--radius-full);
    background-color: var(--bg-button-primary);
    color: var(--text-button-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    flex-shrink: 0;
}

/* What a pill says ("Full screen", "System status"): .pill's own size and weight are for its
   contents, which set their own, so every pill's words are set by this. */
.pill__label {
    font-size: var(--pill-label-size);
    font-weight: var(--font-weight-bold);
    white-space: nowrap;
}

/* A pill's label that is somebody's name, which can be any length. */
.pill__name {
    font-size: var(--pill-label-size);
    font-weight: var(--font-weight-bold);
    white-space: nowrap;
    /* The pill bar is a flex row with no overflow handling, so an unbounded name
       pushes the other pills around. Cap it and ellipsise; the full value stays
       available via the title attribute and the dropdown header. */
    max-width: 24ch;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pill__chevron {
    font-size: 0.75rem;
    color: var(--icon-secondary);
    transition: transform var(--transition-fast);
}

.pill--active .pill__chevron {
    transform: rotate(180deg);
}

/* ==========================================
   PILL DROPDOWN
   Opens under its pill, which the bar wraps in a positioned element.
   ========================================== */

.pill-dropdown {
    position: absolute;
    top: calc(100% + var(--spacing-2));
    right: 0;
    min-width: 260px;
    background-color: var(--bg-surface-primary);
    border-radius: var(--radius-lg);
    /* The shadow alone lifts the panel off the page; an outline on top of it reads as
       a double edge against the bordered cards inside. */
    box-shadow: var(--shadow-lg);
    z-index: var(--z-dropdown);
    overflow: hidden;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px);
    transition:
        opacity var(--transition-fast),
        visibility var(--transition-fast),
        transform var(--transition-fast);
}

.pill-dropdown--open {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

.pill-dropdown__header {
    margin: var(--spacing-4);
    padding: var(--spacing-4);
    background-color: var(--bg-surface-secondary);
    border-radius: var(--radius-md);
}

.pill-dropdown__user-info {
    display: flex;
    align-items: center;
    gap: var(--spacing-3);
}

.pill-dropdown__avatar {
    width: 48px;
    height: 48px;
    border-radius: var(--radius-full);
    object-fit: cover;
    flex-shrink: 0;
}

.pill-dropdown__avatar-placeholder {
    width: 48px;
    height: 48px;
    border-radius: var(--radius-full);
    background-color: var(--bg-button-primary);
    color: var(--text-button-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--font-size-l);
    font-weight: var(--font-weight-semibold);
    flex-shrink: 0;
}

.pill-dropdown__user-details {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-1);
    min-width: 0;
}

.pill-dropdown__badge {
    display: inline-flex;
    align-items: center;
    padding: var(--spacing-1) var(--spacing-2);
    background-color: var(--bg-chip-filled);
    border: 1px solid var(--border-40);
    border-radius: var(--radius-sm);
    font-size: var(--font-size-xs);
    color: var(--text-paragraph);
    width: fit-content;
}

.pill-dropdown__name {
    font-weight: var(--font-weight-semibold);
    color: var(--text-title);
    font-size: var(--font-size-m);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pill-dropdown__email {
    font-size: var(--font-size-sm);
    color: var(--text-paragraph);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Items inset on every side, so a highlighted one is a rounded row rather than a full-width
   band. The items themselves (.pill-dropdown__item, __item-icon, __divider) are the menu
   design's, and are styled with .menu__item in menu.css. */
.pill-dropdown__menu {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: var(--spacing-2);
}
/**
 * Nimbus Design System - Pagination
 *
 * The row under a paged listing: how much of it is showing, and the pages to move between.
 * Its own file rather than part of table.css: a paged list need not be a table.
 *
 * Anatomy: summary ("Showing 1–25 of 300"), pages (Previous, page buttons, gaps, Next)
 */

/* ==========================================
   PAGINATION
   ========================================== */

.pagination {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--spacing-3);
    margin-top: var(--spacing-5);
}

.pagination__summary {
    margin: 0;
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    color: var(--text-paragraph);
}

/* The page buttons: .btn, the current one primary and the rest secondary. */
.pagination__pages {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--spacing-2);
}

/* The elided run. Sized to match a page button's text so the row of controls keeps an even
   rhythm rather than collapsing around the gap. */
.pagination__gap {
    padding: 0 var(--spacing-1);
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    color: var(--text-paragraph);
    user-select: none;
}
/**
 * Nimbus Design System - Filter chips
 *
 * A single-choice row of count chips over a list ("All 12", "Fire 3"). Each chip is a toggle
 * button; the chosen one is filled rather than outlined, so the choice reads without relying
 * on colour. Not the status .chip (chips.css), which only shows.
 *
 * Anatomy: chip (dot?, label, count)
 */

/* ==========================================
   FILTER CHIPS
   ========================================== */

.filter-chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-2);
}

.filter-chips__chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 28px;
    padding: 0 var(--spacing-3);
    border: 1px solid var(--border-20);
    border-radius: var(--radius-full);
    background-color: var(--bg-surface-primary);
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    color: var(--text-title);
    white-space: nowrap;
    cursor: pointer;
    transition:
        background-color var(--transition-fast),
        border-color var(--transition-fast);
}

.filter-chips__chip:hover {
    background-color: var(--bg-surface-secondary);
}

.filter-chips__chip:focus {
    outline: none;
}

.filter-chips__chip:focus-visible {
    outline: 2px solid var(--border-brand);
    outline-offset: 2px;
}

.filter-chips__chip--selected {
    background-color: var(--bg-surface-secondary);
    border-color: transparent;
}

/* Coloured by the caller, to match how the matching rows are drawn. */
.filter-chips__dot {
    width: 8px;
    height: 8px;
    border-radius: var(--radius-full);
    flex-shrink: 0;
}

.filter-chips__label {
    font-weight: var(--font-weight-semibold);
}

.filter-chips__count {
    font-weight: var(--font-weight-bold);
}
/**
 * Nimbus Design System - Searchable select
 *
 * The listbox select's trigger and options (inputs.css), with the pieces it has no counterpart
 * for: the list opening under the trigger, with a search box at its top.
 *
 * Anatomy: label (required?), trigger, popover (search, list of options with hints, status)
 */

/* ==========================================
   SEARCHABLE SELECT
   ========================================== */

.searchable-select {
    position: relative;
    min-width: 0;
}

.searchable-select__required {
    margin-left: 2px;
    color: var(--text-title);
}

/* Absolute under the trigger rather than portalled, so the list stays with the field as the
   page scrolls. The field must not sit inside something that clips. */
.searchable-select__popover {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    z-index: var(--z-menu);
    width: max(100%, 260px);
    max-width: calc(100vw - 32px);
    display: flex;
    flex-direction: column;
    gap: var(--spacing-1);
    padding: var(--spacing-2);
    background-color: var(--bg-surface-primary);
    border: 1px solid var(--border-40);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-menu);
    box-sizing: border-box;
}

.searchable-select__list {
    display: flex;
    flex-direction: column;
    gap: 2px;
    max-height: 260px;
    overflow-y: auto;
}

.searchable-select__list:empty {
    display: none;
}

.searchable-select__hint {
    margin-left: var(--spacing-2);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-regular);
    opacity: 0.75;
}

.searchable-select__status {
    margin: 0;
    padding: var(--spacing-2) var(--spacing-3);
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    color: var(--text-paragraph);
}
/**
 * Nimbus Design System - Settings
 *
 * The shell's settings cards (System Preferences, and the module settings shown beside it,
 * such as the developer portal's): one card per group, a row per setting with what it does on
 * one side and its control on the other.
 *
 * Anatomy: group (heading), item (info: label, description; control)
 */

/* ==========================================
   SETTINGS GROUP
   ========================================== */

/* One settings card, whoever's settings it holds: headed at 15px semibold, with no rule
   under the heading. The same card as .card--section, for markup that cannot use .card. */
.settings-group {
    background: var(--bg-surface-primary);
    border: 1px solid var(--border-20);
    border-radius: var(--radius-lg);
    padding: var(--spacing-6);
}

.settings-group h2 {
    margin: 0 0 var(--spacing-2) 0;
    font-size: var(--font-size-m);
    font-weight: var(--font-weight-semibold);
    color: var(--text-title);
}

/* ==========================================
   SETTINGS ITEM
   ========================================== */

.settings-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    /* The control drops under its label when both don't fit, rather than squeezing the label
       to a word a line or running past the card. */
    flex-wrap: wrap;
    gap: var(--spacing-3) var(--spacing-5);
    padding: var(--spacing-3) 0;
}

.settings-item + .settings-item {
    border-top: 1px solid var(--border-20);
}

.settings-item-info {
    flex: 1 1 14rem;
    min-width: 0;
}

.settings-item-info label {
    display: block;
    margin-bottom: var(--spacing-1);
}

.settings-item-info p {
    margin: 0;
}

/* ==========================================
   SETTINGS SELECT
   A native select, for a setting's control.
   ========================================== */

.settings-select {
    padding: var(--spacing-2) var(--spacing-4);
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    border: 1px solid var(--border-20);
    border-radius: var(--radius-md);
    background: var(--bg-surface-secondary);
    color: var(--text-title);
    cursor: pointer;
    min-width: 120px;
    transition: border-color var(--transition-fast);
}

.settings-select:focus {
    outline: none;
    border-color: var(--bg-button-primary);
}

.settings-select:hover {
    border-color: var(--border-40);
}
/**
 * Nimbus Design System - Status & Loading Panels
 *
 * What a page's place says when it has no content to show yet: that it is loading (the
 * loading panel), or why it cannot show it — it could not be loaded, it is not yours to see
 * (the status panel). Both are the same frame: a title in the page title's style, centred in
 * the content area, with a running bar under a loading panel and a description and what to
 * do under a status panel. The shell shows them while a module loads or fails to; a module
 * shows the same for its own page, so the two read as one.
 *
 * Anatomy: area; panel (icon, title, description, actions | track, fill)
 */

/* ==========================================
   AREA
   ========================================== */

/* The content area's own centre, inside the shell's sidebar and pill bar. The height is the
   content area's, which the shell publishes; the fallback is the same sum, for a page shown
   without it. */
.loading-area,
.status-area {
    min-height: var(--content-height, calc(100vh - var(--spacing-5) - var(--page-bottom)));
    display: flex;
    align-items: center;
    justify-content: center;
}

/* ==========================================
   PANEL
   ========================================== */

.loading-panel,
.status-panel {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-4);
}

.loading-panel__title,
.status-panel__title {
    margin: 0;
    font-family: var(--font-family);
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-bold);
    color: var(--text-title);
}

/* ==========================================
   STATUS PANEL
   ========================================== */

/* Each tone sets the accent its icon is drawn in. */
.status-panel {
    --status-panel-accent: var(--icon-secondary);
}

.status-panel--error {
    --status-panel-accent: #c62828;
}

.status-panel--warning {
    --status-panel-accent: #e65100;
}

.status-panel--success {
    --status-panel-accent: #2e7d32;
}

.status-panel--info {
    --status-panel-accent: #1565c0;
}

.status-panel__icon {
    display: inline-flex;
    font-size: 2rem;
    color: var(--status-panel-accent);
}

.status-panel__description {
    margin: 0;
    font-family: var(--font-family);
    font-size: var(--font-size-m);
    color: var(--text-paragraph);
}

/* What to do about it (try again, go elsewhere): buttons, at the start of the line. */
.status-panel__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--spacing-2);
}

/* ==========================================
   LOADING PANEL
   ========================================== */

.loading-panel__track {
    width: 100%;
    max-width: 470px;
    height: 6px;
    border-radius: var(--radius-full);
    background-color: var(--bg-surface-secondary);
    overflow: hidden;
}

.loading-panel__fill {
    width: 25%;
    height: 100%;
    border-radius: var(--radius-full);
    background-color: var(--color-fire);
    animation: loadingPanelBar 1.2s ease-in-out infinite;
}

/* Still, and across the whole track at half strength: a quarter of it standing still would
   read as a quarter done. The title still says what is loading. */
@media (prefers-reduced-motion: reduce) {
    .loading-panel__fill {
        width: 100%;
        opacity: 0.5;
        animation: none;
    }
}

@keyframes loadingPanelBar {
    0% {
        transform: translateX(-100%);
    }
    100% {
        transform: translateX(400%);
    }
}
/**
 * Nimbus Design System - Tiles
 *
 * The overview layout: an entity's header (its mark beside its name), and its people and
 * what it pays for, each a grid of small tiles — as many to a row as the width holds, so a
 * wide window shows more of them side by side rather than stretching any one across it.
 *
 * Anatomy: entity header (mark, title, subtitle, actions), logo mark (image or initial),
 * tile section (title, groups), tile grid, tile, person tile (avatar, name, detail, status)
 */

/* ==========================================
   ENTITY HEADER
   ========================================== */

.entity-header {
    display: flex;
    align-items: center;
    gap: var(--spacing-4);
    min-width: 0;
}

/* The name, and under it a line about it (an organisation's type, say). */
.entity-header__identity {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-1);
    min-width: 0;
}

/* The page title's style everywhere (.page-title), without its margin: the header spaces it. */
.entity-header__title {
    margin: 0;
    font-family: var(--font-family);
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-default);
    color: var(--text-title);
    overflow-wrap: anywhere;
}

.entity-header__subtitle {
    margin: 0;
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    color: var(--text-paragraph);
}

/* Pushed to the far end of the header, across from the name it edits. */
.entity-header__actions {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    margin-left: auto;
    flex-shrink: 0;
}

/* ==========================================
   LOGO MARK
   ========================================== */

/* An organisation's mark: its logo on white, framed as a tile, or its initial. Held to the
   header's height, so a tall or square logo shrinks to fit rather than pushing it taller. */
.logo-mark {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    box-sizing: border-box;
    height: 3.5rem;
    min-width: 3.5rem;
    max-width: 10rem;
    padding: var(--spacing-2) var(--spacing-3);
    background-color: var(--bg-surface-primary);
    border: 1px solid var(--border-20);
    border-radius: var(--radius-md);
}

.logo-mark__image {
    display: block;
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

.logo-mark__initial {
    font-family: var(--font-family);
    font-size: var(--font-size-l);
    font-weight: var(--font-weight-bold);
    color: var(--text-title);
}

/* ==========================================
   TILE SECTION
   A heading over one or more grids of tiles.
   ========================================== */

.tile-section {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-3);
}

/* As the settings cards and dashboard widgets head theirs: a step below the page title and a
   step above the names in the tiles it heads. */
.tile-section__title {
    margin: 0;
    font-family: var(--font-family);
    font-size: var(--font-size-m);
    font-weight: var(--font-weight-semibold);
    color: var(--text-title);
}

/* One level within a section (the primary user, then the admins): its heading, then its row. */
.tile-group {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2);
}

/* More room above a group than inside one, so each heading reads as starting its own row
   rather than ending the row above. */
.tile-group + .tile-group {
    margin-top: var(--spacing-2);
}

/* A step below the section's heading: smaller, and in the paragraph colour. */
.tile-group__title {
    margin: 0;
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
    color: var(--text-paragraph);
}

/* ==========================================
   TILE GRID
   ========================================== */

/* As many tiles to a row as the width holds, each between --tile-min-width and two columns'
   worth. Set --tile-min-width on the grid for a different floor, and --tile-gap for a wider
   gap (a grid of larger cards takes --spacing-4). Works as a <ul> too. */
.tile-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(var(--tile-min-width, 18rem), 100%), 1fr));
    gap: var(--tile-gap, var(--spacing-3));
    margin: 0;
    padding: 0;
    list-style: none;
}

/* A grid that is a list: each tile in an <li>, which may shrink with its column. */
.tile-grid__item {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

/* Whatever the item holds fills it, so a row's tiles are one height. */
.tile-grid__item > * {
    flex: 1;
}

/* ==========================================
   TILE
   ========================================== */

/* A card's surface at a tile's size: the medium radius, as the large one reads as a panel at
   these heights. Its contents sit in a row. */
.tile {
    display: flex;
    align-items: center;
    gap: var(--spacing-3);
    box-sizing: border-box;
    min-width: 0;
    padding: var(--spacing-4);
    font-family: var(--font-family);
    background-color: var(--bg-surface-primary);
    border: 1px solid var(--border-20);
    border-radius: var(--radius-md);
}

/* ==========================================
   PERSON TILE
   ========================================== */

/* Their initials, standing in for a picture. Also on its own, wherever a person is listed. */
.avatar {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 2.25rem;
    height: 2.25rem;
    overflow: hidden;
    border-radius: var(--radius-full);
    background-color: var(--bg-surface-secondary);
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
    color: var(--text-title);
}

.avatar__image {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.person-tile__lines {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-1);
    flex: 1;
    min-width: 0;
    overflow-wrap: anywhere;
}

.person-tile__name {
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
    color: var(--text-title);
}

.person-tile__detail {
    font-size: var(--font-size-xs);
    color: var(--text-paragraph);
}

/* Where they stand (an invitation still waiting, say), at the far end of the row. */
.person-tile__status {
    flex-shrink: 0;
    white-space: nowrap;
}
/**
 * Nimbus Design System - Image Upload
 *
 * A field for one picture, such as an organisation's logo: an Upload button that becomes a
 * preview with Remove and Replace once there is a picture to show.
 *
 * Anatomy: label, hidden file input, preview (image, actions), error
 */

/* ==========================================
   IMAGE UPLOAD
   ========================================== */

.image-upload {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--spacing-2);
}

/* Matches a drawer's field labels: the picker is a field, so it reads as one even though it
   is a button rather than an input. */
.image-upload__label {
    font-family: var(--font-family);
    font-size: var(--font-size-xs);
    line-height: 1.5;
    font-weight: var(--font-weight-semibold);
    color: var(--text-title);
}

/* The native control is driven by the Upload and Replace buttons. */
.image-upload__input {
    display: none;
}

.image-upload__preview {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-3);
    width: 100%;
}

.image-upload__image {
    /* Contain so a wide or tall picture is shown whole rather than cropped by the frame. A
       photo of a place is shown taller than a logo: set --image-upload-preview-height. The
       border is inside the width, so the frame does not overflow the field. */
    box-sizing: border-box;
    width: 100%;
    max-height: var(--image-upload-preview-height, 8rem);
    object-fit: contain;
    background-color: var(--bg-cs-bg);
    border: 1px solid var(--border-20);
    border-radius: var(--radius-md);
}

.image-upload__actions {
    display: flex;
    gap: var(--spacing-2);
}

/* ==========================================
   DROPZONE
   In place of the Upload button: a target to drop a file on, or to press to pick one.
   ========================================== */

.image-upload__dropzone {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--spacing-2);
    box-sizing: border-box;
    width: 100%;
    padding: var(--spacing-8) var(--spacing-6);
    background: none;
    /* Dashed, as the design draws it: it reads as a target rather than a filled field. */
    border: 1px dashed var(--bg-button-border);
    border-radius: var(--radius-md);
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    color: var(--text-paragraph);
    cursor: pointer;
    transition:
        border-color var(--transition-fast),
        background-color var(--transition-fast);
}

.image-upload__dropzone:hover {
    border-color: var(--border-40);
}

.image-upload__dropzone:focus-visible {
    outline: 2px solid var(--border-brand);
    outline-offset: 2px;
}

/* A file is being dragged over it: it will take it. */
.image-upload__dropzone--active {
    border-color: var(--border-100);
    background-color: var(--bg-surface-secondary);
}

.image-upload__dropzone:disabled {
    border-color: var(--border-20);
    cursor: not-allowed;
}

.image-upload__dropzone-icon {
    display: inline-flex;
    font-size: 1rem;
    color: var(--icon-secondary);
}

.image-upload__prompt {
    font-size: var(--font-size-sm);
    line-height: 1.5;
    font-weight: var(--font-weight-semibold);
    color: var(--text-title);
}

.image-upload__hint {
    font-size: var(--font-size-xs);
    line-height: 1.5;
    color: var(--icon-disable);
}

/* ==========================================
   PREPARING
   Shown while a picked file is being prepared (a photo shrunk), in place of the dropzone or
   the preview.
   ========================================== */

.image-upload__busy {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    box-sizing: border-box;
    width: 100%;
    margin: 0;
    padding: var(--spacing-4);
    font-family: var(--font-family);
    font-size: var(--font-size-sm);
    color: var(--text-paragraph);
    background-color: var(--bg-cs-bg);
    border: 1px solid var(--border-20);
    border-radius: var(--radius-md);
}

.image-upload__spinner {
    flex-shrink: 0;
    animation: image-upload-spin 1s linear infinite;
}

/* The words still say what is happening. */
@media (prefers-reduced-motion: reduce) {
    .image-upload__spinner {
        animation: none;
    }
}

@keyframes image-upload-spin {
    to {
        transform: rotate(360deg);
    }
}

:root {
    font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
    line-height: 1.5;
    font-weight: 400;

    color: var(--text-paragraph);
    background-color: var(--bg-surface-primary);

    font-synthesis: none;
    text-rendering: optimizeLegibility;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

body {
    margin: 0;
    display: flex;
    place-items: center;
    min-width: 320px;
    min-height: 100vh;
}

h1 {
    font-size: 3.2em;
    line-height: 1.1;
    color: var(--text-title);
}
