/* The Sovrain look over Bootstrap 5.3, shared by every app that wears it: fonts, tokens, light and dark
   themes, Bootstrap's components in the Sovrain style, and the components Bootstrap has no equivalent
   for (segmented controls, save bars, setting rows, the admin shell and more). Pages use Bootstrap's
   markup and class names; this file is the only stylesheet they load. App-only rules go in the app's
   own stylesheet, loaded after this one. */
/* Bootstrap's base first, then Tom Select (the library behind searchable selects), so the rules below
   win ties with both. */
@import url("bootstrap.css");
@import url("tom-select/tom-select.css");

/* Geist (variable, 300–700) */
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("./fonts/geist-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("./fonts/geist-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("./fonts/geist-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

/* Geist Mono (variable, 400–500) */
@font-face {
  font-family: "Geist Mono";
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url("./fonts/geist-mono-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Geist Mono";
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url("./fonts/geist-mono-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Geist Mono";
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url("./fonts/geist-mono-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}


/* --- Tokens ------------------------------------------------- */
/* Colours follow the Sovrain design system (Figma "WD — Applications", DS 01–07). Figma draws the
   dark theme only; the light values mirror each token's role on a white page. Every colour is one
   light-dark() pair, resolved by the color-scheme the theme blocks below set. */

:root {
  --font-sans: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* surfaces get brighter as they come closer to the user: page, inset, card, raised control, hover */
  --color-surface: light-dark(#ffffff, #0a0b0d);
  --color-surface-sunken: light-dark(#f6f7f9, #0e0f12);
  --color-surface-subtle: light-dark(#fafafb, #111215);
  --color-surface-raised: light-dark(#ffffff, #17191d);
  --color-surface-hover: light-dark(#f1f2f4, #1f2227);
  --color-surface-pressed: light-dark(#e9ebee, #14161a);
  --color-surface-inverse: light-dark(#111215, #fafafb);
  /* a hover or quiet fill on a page or card: on dark the raised surface, on light a grey step */
  --color-fill-quiet: light-dark(#f1f2f4, #17191d);
  --color-btn-secondary-bg: var(--color-surface-raised);
  --color-badge-neutral: var(--color-fill-quiet);
  --color-notice-bg: var(--color-fill-quiet);
  --color-nav-active: var(--color-fill-quiet);
  --color-row-hover: var(--color-fill-quiet);

  /* borders: dividers and rows, cards, inputs and buttons, hover and dashed, unchecked controls */
  --color-divider: light-dark(#eaecef, #1e2126);
  --color-border: light-dark(#e3e5e9, #23262c);
  --color-control-border: light-dark(#d6d9de, #2b2f36);
  --color-border-strong: light-dark(#bcc1c8, #3a3f48);
  --color-border-off: light-dark(#a7adb6, #4a4f59);

  /* text: the current tab and nav entry (strong), titles and values, strong body, descriptions,
     labels and table heads, placeholders, disabled */
  --color-fg-strong: light-dark(#000000, #ffffff);
  --color-fg: light-dark(#111215, #ecedef);
  --color-fg-secondary: light-dark(#33373d, #c7cbd2);
  --color-fg-muted: light-dark(#5f6570, #9a9fa9);
  --color-fg-subtle: light-dark(#737985, #848994);
  --color-placeholder: light-dark(#8b919b, #7a808b);
  --color-fg-disabled: light-dark(#a1a6af, #6b707a);
  --color-fg-inverse: light-dark(#fafafb, #0a0b0d);

  /* Green marks the one thing to do, the current place and "on"; it is the only brand colour.
     On white the design's #3ECF8E is too faint for text and hairlines, so light uses a deeper green. */
  --color-accent: light-dark(#087f53, #3ecf8e);
  --color-accent-hover: light-dark(#066b46, #57db9f);
  --color-accent-pressed: light-dark(#055c3c, #2fb77a);
  --color-on-accent: light-dark(#ffffff, #04200f);
  --color-accent-soft: light-dark(rgb(8 127 83 / 0.1), rgb(62 207 142 / 0.12));
  --color-accent-line: light-dark(rgb(8 127 83 / 0.35), rgb(62 207 142 / 0.35));
  /* the focused field's glow */
  --color-accent-ring: light-dark(rgb(8 127 83 / 0.18), rgb(62 207 142 / 0.18));
  /* a chosen option, a selected row or radio card */
  --color-accent-wash: light-dark(rgb(8 127 83 / 0.06), rgb(62 207 142 / 0.06));
  --color-btn-primary-bg: var(--color-accent);
  --color-btn-primary-bg-hover: var(--color-accent-hover);
  --color-btn-primary-bg-pressed: var(--color-accent-pressed);
  --color-btn-primary-fg: var(--color-on-accent);

  /* Status: each tone has a text colour, an 8% fill and a 30% line. Never a colour alone: pair it
     with an icon or a word. */
  --color-success-fg: var(--color-accent);
  --color-success-bg: light-dark(rgb(8 127 83 / 0.08), rgb(62 207 142 / 0.08));
  --color-success-border: light-dark(rgb(8 127 83 / 0.3), rgb(62 207 142 / 0.3));
  --color-warn-fg: light-dark(#8f5400, #f2c979);
  --color-warn-strong: light-dark(#d99a1e, #f2b84b);
  --color-warn-bg: light-dark(rgb(242 184 75 / 0.14), rgb(242 184 75 / 0.08));
  --color-warn-border: light-dark(rgb(217 154 30 / 0.45), rgb(242 184 75 / 0.28));
  --color-info-fg: light-dark(#1d5fd1, #8fb8ff);
  --color-info-bg: light-dark(rgb(59 130 246 / 0.08), rgb(110 168 255 / 0.08));
  --color-info-border: light-dark(rgb(59 130 246 / 0.3), rgb(110 168 255 / 0.3));
  --color-danger-fg: light-dark(#c0283c, #f2a0a0);
  /* a failed field's border, the danger tab's underline, a full progress bar */
  --color-danger-strong: light-dark(#d93348, #f27a7a);
  --color-danger-bg: light-dark(rgb(217 51 72 / 0.08), rgb(242 109 109 / 0.08));
  --color-danger-border: light-dark(rgb(217 51 72 / 0.3), rgb(242 109 109 / 0.3));
  --color-danger-ring: light-dark(rgb(217 51 72 / 0.14), rgb(242 109 109 / 0.14));
  --color-btn-danger-bg: light-dark(#d93348, #f2a0a0);
  --color-btn-danger-bg-hover: light-dark(#c42a3e, #f5b3b3);
  --color-btn-danger-bg-pressed: light-dark(#ae2436, #e88a8a);
  --color-on-danger: light-dark(#ffffff, #2a0a0a);

  /* initials avatars (accent-tinted) and app tiles (neutral) */
  --color-avatar: light-dark(#d3f1e3, #1e5c4e);
  --color-on-avatar-default: light-dark(#0b5e40, #e8fff6);
  --avatar-neutral-bg: light-dark(#f1f2f4, #1a1d22);
  /* palette avatars set --avatar-bg inline to a saturated colour; their letter stays light */
  --color-on-avatar: #fafafa;

  /* Only menus float, so only menus cast a shadow. */
  --shadow-menu: 0 16px 40px rgb(15 20 30 / 0.12), 0 2px 6px rgb(15 20 30 / 0.08);
  --shadow-segment: 0 1px 2px rgb(15 20 30 / 0.12);
  /* the home page's top glow, softer over a light page */
  --home-glow-opacity: 0.35;
  /* native controls (scrollbars, date pickers) follow the theme */
  color-scheme: light;
  /* icons drawn as data URIs cannot take a custom property, so each theme spells its own colours:
     the select chevron in fg-muted, the checkbox marks in on-accent */
  --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%235f6570' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='m4 6 4 4 4-4'/%3E%3C/svg%3E");
  --select-chevron-up: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%235f6570' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='m4 10 4-4 4 4'/%3E%3C/svg%3E");
  --checkbox-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%23ffffff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round' d='M2.25 6.375 4.65 8.625 9.75 3.375'/%3E%3C/svg%3E");
  --checkbox-dash: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%23ffffff' stroke-width='1.8' stroke-linecap='round' d='M2.625 6h6.75'/%3E%3C/svg%3E");

  --radius-sm: 0.25rem;
  --radius-md: 0.375rem;
  --radius-lg: 0.5rem;
  --radius-xl: 0.75rem;
  --radius-full: 9999px;

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;

  --text-xs: 0.75rem;
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-lg: 1.125rem;
  --text-xl: 1.25rem;
  --text-2xl: 1.5rem;
  --text-3xl: 1.875rem;

  --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.04);
}

/* --- Themes ---------------------------------------------------- */
/* Bootstrap's switch: data-bs-theme="light" or "dark" on <html> (or on any element, for a dark navbar);
   no attribute follows the system. The colour tokens hold both values, so a theme only sets
   color-scheme, the *-rgb channels and the few values that are not colours. */

:root,
[data-bs-theme="light"] {
  color-scheme: light;
  /* the switch knob, off and on, drawn as a data URI like the checkbox marks */
  --switch-knob: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Crect width='14' height='14' rx='2' fill='%23bcc1c8'/%3E%3C/svg%3E");
  --switch-knob-on: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Crect width='14' height='14' rx='2' fill='%23087f53'/%3E%3C/svg%3E");
  --bs-body-color-rgb: 17, 18, 21;
  --bs-body-bg-rgb: 255, 255, 255;
  --bs-emphasis-color-rgb: 0, 0, 0;
  --bs-secondary-color-rgb: 95, 101, 112;
  --bs-tertiary-color-rgb: 115, 121, 133;
  --bs-secondary-bg-rgb: 246, 247, 249;
  --bs-tertiary-bg-rgb: 250, 250, 251;
  --bs-link-color-rgb: 17, 18, 21;
  --bs-link-hover-color-rgb: 0, 0, 0;
  --bs-primary: #087f53;
  --bs-primary-rgb: 8, 127, 83;
  --bs-secondary: #5f6570;
  --bs-secondary-rgb: 95, 101, 112;
  --bs-success: #087f53;
  --bs-success-rgb: 8, 127, 83;
  --bs-info: #1d5fd1;
  --bs-info-rgb: 29, 95, 209;
  --bs-warning: #8f5400;
  --bs-warning-rgb: 143, 84, 0;
  --bs-danger: #c0283c;
  --bs-danger-rgb: 192, 40, 60;
  /* light and dark are fixed colours in Bootstrap, the same in both themes (a bg-dark bar stays dark) */
  --bs-light: #f6f7f9;
  --bs-light-rgb: 246, 247, 249;
  --bs-dark: #111215;
  --bs-dark-rgb: 17, 18, 21;
}

[data-bs-theme="dark"] {
  color-scheme: dark;
  --home-glow-opacity: 1;
  --shadow-menu: 0 16px 40px rgb(0 0 0 / 0.5), 0 2px 6px rgb(0 0 0 / 0.4);
  --shadow-segment: 0 1px 1px rgb(0 0 0 / 0.4);
  --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%239a9fa9' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='m4 6 4 4 4-4'/%3E%3C/svg%3E");
  --select-chevron-up: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%239a9fa9' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='m4 10 4-4 4 4'/%3E%3C/svg%3E");
  --checkbox-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%2304200f' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round' d='M2.25 6.375 4.65 8.625 9.75 3.375'/%3E%3C/svg%3E");
  --checkbox-dash: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%2304200f' stroke-width='1.8' stroke-linecap='round' d='M2.625 6h6.75'/%3E%3C/svg%3E");
  --switch-knob: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Crect width='14' height='14' rx='2' fill='%233a3f48'/%3E%3C/svg%3E");
  --switch-knob-on: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Crect width='14' height='14' rx='2' fill='%233ecf8e'/%3E%3C/svg%3E");
  --bs-body-color-rgb: 236, 237, 239;
  --bs-body-bg-rgb: 10, 11, 13;
  --bs-emphasis-color-rgb: 255, 255, 255;
  --bs-secondary-color-rgb: 154, 159, 169;
  --bs-tertiary-color-rgb: 132, 137, 148;
  --bs-secondary-bg-rgb: 14, 15, 18;
  --bs-tertiary-bg-rgb: 17, 18, 21;
  --bs-link-color-rgb: 236, 237, 239;
  --bs-link-hover-color-rgb: 255, 255, 255;
  --bs-primary: #3ecf8e;
  --bs-primary-rgb: 62, 207, 142;
  --bs-secondary: #9a9fa9;
  --bs-secondary-rgb: 154, 159, 169;
  --bs-success: #3ecf8e;
  --bs-success-rgb: 62, 207, 142;
  --bs-info: #8fb8ff;
  --bs-info-rgb: 143, 184, 255;
  --bs-warning: #f2c979;
  --bs-warning-rgb: 242, 201, 121;
  --bs-danger: #f2a0a0;
  --bs-danger-rgb: 242, 160, 160;
}

/* Aurora blobs use multiply on light surfaces (darkens color over white).
   On dark surfaces multiply collapses to ~black, so switch to screen (lightens). */
[data-bs-theme="dark"] .bg-aurora-blob { mix-blend-mode: screen; }

@media (prefers-color-scheme: dark) {
  :root:not([data-bs-theme]) {
    color-scheme: dark;
    --home-glow-opacity: 1;
    --shadow-menu: 0 16px 40px rgb(0 0 0 / 0.5), 0 2px 6px rgb(0 0 0 / 0.4);
    --shadow-segment: 0 1px 1px rgb(0 0 0 / 0.4);
    --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%239a9fa9' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='m4 6 4 4 4-4'/%3E%3C/svg%3E");
    --select-chevron-up: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%239a9fa9' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='m4 10 4-4 4 4'/%3E%3C/svg%3E");
    --checkbox-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%2304200f' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round' d='M2.25 6.375 4.65 8.625 9.75 3.375'/%3E%3C/svg%3E");
    --checkbox-dash: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%2304200f' stroke-width='1.8' stroke-linecap='round' d='M2.625 6h6.75'/%3E%3C/svg%3E");
    --switch-knob: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Crect width='14' height='14' rx='2' fill='%233a3f48'/%3E%3C/svg%3E");
    --switch-knob-on: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Crect width='14' height='14' rx='2' fill='%233ecf8e'/%3E%3C/svg%3E");
    --bs-body-color-rgb: 236, 237, 239;
    --bs-body-bg-rgb: 10, 11, 13;
    --bs-emphasis-color-rgb: 255, 255, 255;
    --bs-secondary-color-rgb: 154, 159, 169;
    --bs-tertiary-color-rgb: 132, 137, 148;
    --bs-secondary-bg-rgb: 14, 15, 18;
    --bs-tertiary-bg-rgb: 17, 18, 21;
    --bs-link-color-rgb: 236, 237, 239;
    --bs-link-hover-color-rgb: 255, 255, 255;
    --bs-primary: #3ecf8e;
    --bs-primary-rgb: 62, 207, 142;
    --bs-secondary: #9a9fa9;
    --bs-secondary-rgb: 154, 159, 169;
    --bs-success: #3ecf8e;
    --bs-success-rgb: 62, 207, 142;
    --bs-info: #8fb8ff;
    --bs-info-rgb: 143, 184, 255;
    --bs-warning: #f2c979;
    --bs-warning-rgb: 242, 201, 121;
    --bs-danger: #f2a0a0;
    --bs-danger-rgb: 242, 160, 160;
  }
  :root:not([data-bs-theme]) .bg-aurora-blob { mix-blend-mode: screen; }
}

/* Bootstrap's variables, taken from the tokens. Set on every theme root, so an element with its own
   data-bs-theme gets them again and its light-dark() pairs resolve for that theme. */
:root,
[data-bs-theme] {
  --bs-font-sans-serif: var(--font-sans);
  --bs-font-monospace: var(--font-mono);
  --bs-body-font-family: var(--font-sans);
  --bs-body-font-size: var(--text-base);
  --bs-body-line-height: 1.5;
  --bs-body-color: var(--color-fg);
  --bs-body-bg: var(--color-surface);
  --bs-emphasis-color: var(--color-fg-strong);
  --bs-secondary-color: var(--color-fg-muted);
  --bs-secondary-bg: var(--color-surface-sunken);
  --bs-tertiary-color: var(--color-fg-subtle);
  --bs-tertiary-bg: var(--color-surface-subtle);
  --bs-heading-color: var(--color-fg);
  --bs-link-color: var(--color-fg);
  --bs-link-hover-color: var(--color-fg-strong);
  --bs-link-decoration: underline;
  --bs-code-color: var(--color-fg);
  --bs-highlight-color: var(--color-fg);
  --bs-highlight-bg: var(--color-accent-soft);
  --bs-border-color: var(--color-border);
  --bs-border-color-translucent: var(--color-border);
  --bs-border-radius: var(--radius-lg);
  --bs-border-radius-sm: var(--radius-md);
  --bs-border-radius-lg: var(--radius-xl);
  --bs-border-radius-xl: var(--radius-xl);
  --bs-border-radius-xxl: var(--radius-xl);
  --bs-border-radius-pill: var(--radius-full);
  --bs-box-shadow: var(--shadow-menu);
  --bs-box-shadow-sm: var(--shadow-sm);
  --bs-box-shadow-lg: var(--shadow-menu);
  --bs-focus-ring-color: var(--color-accent-ring);
  --bs-form-valid-color: var(--color-success-fg);
  --bs-form-valid-border-color: var(--color-accent);
  --bs-form-invalid-color: var(--color-danger-fg);
  --bs-form-invalid-border-color: var(--color-danger-strong);
  --bs-primary-text-emphasis: var(--color-accent);
  --bs-primary-bg-subtle: var(--color-accent-soft);
  --bs-primary-border-subtle: var(--color-accent-line);
  --bs-secondary-text-emphasis: var(--color-fg-secondary);
  --bs-secondary-bg-subtle: var(--color-fill-quiet);
  --bs-secondary-border-subtle: var(--color-border);
  --bs-success-text-emphasis: var(--color-success-fg);
  --bs-success-bg-subtle: var(--color-success-bg);
  --bs-success-border-subtle: var(--color-success-border);
  --bs-info-text-emphasis: var(--color-info-fg);
  --bs-info-bg-subtle: var(--color-info-bg);
  --bs-info-border-subtle: var(--color-info-border);
  --bs-warning-text-emphasis: var(--color-warn-fg);
  --bs-warning-bg-subtle: var(--color-warn-bg);
  --bs-warning-border-subtle: var(--color-warn-border);
  --bs-danger-text-emphasis: var(--color-danger-fg);
  --bs-danger-bg-subtle: var(--color-danger-bg);
  --bs-danger-border-subtle: var(--color-danger-border);
  --bs-light-text-emphasis: var(--color-fg);
  --bs-light-bg-subtle: var(--color-surface-subtle);
  --bs-light-border-subtle: var(--color-border);
  --bs-dark-text-emphasis: var(--color-fg);
  --bs-dark-bg-subtle: var(--color-surface-inverse);
  --bs-dark-border-subtle: var(--color-border-strong);
}

/* --- Base ------------------------------------------------------ */

body {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Links take the colour of the text around them; muted text keeps muted links. */
a { color: inherit; text-underline-offset: 0.2em; }
a:hover { color: inherit; }
/* Bootstrap bolds <dt>; the apps set their own label weight. */
dt { font-weight: inherit; }
/* .small is a fixed 0.875rem, not Bootstrap's 0.875em, which shrinks again inside tables and cards. */
small, .small { font-size: var(--text-sm); }
.text-xs { font-size: var(--text-xs); }
/* A paragraph keeps the browser's 1em above and below (Bootstrap drops the top one); the components that
   hold paragraphs set their own. */
p { margin-top: 1em; margin-bottom: 1em; }
/* Code is set at the size of the text around it, not Bootstrap's 0.875em, in the browser's monospace face;
   the components that show code (.font-monospace, .code-inline, terminals) set Geist Mono. */
code, pre { font-size: inherit; }
code, kbd, pre, samp { font-family: monospace; }
/* A label is inline text, as the browser sets it (Bootstrap makes it an inline block). */
label { display: inline; }
/* Images and icons sit on the text's baseline (Bootstrap centres them on the line). */
img, svg { vertical-align: baseline; }
/* Code takes the colour of the text around it; a bare <kbd> is plain monospace text (.kbd draws a key). */
code { color: inherit; }
kbd { padding: 0; font-size: inherit; color: inherit; background: none; border-radius: 0; }
/* A legend sits in the flow at the size of the text around it, as the browser sets it (Bootstrap floats it
   full width at heading size). */
legend { float: none; width: auto; padding: revert; margin-bottom: 0; font-size: inherit; }
/* Long words break where the text allows, as in plain text: Bootstrap breaks them anywhere inside cards
   and code, which wraps narrow table headers mid-word. */
.card, code { overflow-wrap: normal; }

/* A bare heading is bold at the line height of the text around it; the component that holds it sets
   its size and spacing. The .h1-.h6 classes are the type scale: semibold, tight and a little closer set. */
h1, h2, h3, h4, h5, h6 {
  margin: 0 0 var(--space-2);
  font-weight: 700;
  line-height: inherit;
}
.h1, .h2, .h3, .h4, .h5, .h6 {
  margin: 0 0 var(--space-2);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.3;
}
h1, .h1 { font-size: var(--text-3xl); }
h2, .h2 { font-size: var(--text-2xl); }
h3, .h3 { font-size: var(--text-xl); }
h4, .h4 { font-size: var(--text-lg); }
h5, .h5 { font-size: var(--text-base); }
h6, .h6 { font-size: var(--text-sm); color: var(--color-fg-muted); }

.lead { font-size: var(--text-lg); color: var(--color-fg-muted); }

.kbd {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  padding: 2px 6px;
  color: var(--color-fg);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-bottom-width: 2px;
  border-radius: var(--radius-sm);
}

.code-inline {
  font-family: var(--font-mono);
  font-size: 0.85em;
  padding: 2px 6px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
}

.blockquote {
  margin: 0;
  padding: var(--space-2) var(--space-4);
  border-left: 2px solid var(--color-fg);
  color: var(--color-fg-muted);
  font-size: var(--text-lg);
  line-height: 1.5;
}
.blockquote-footer {
  margin: var(--space-2) 0 0;
  font-size: var(--text-sm);
  font-family: var(--font-mono);
  color: var(--color-fg-subtle);
}
.blockquote-footer::before { content: none; }

.prose h1, .prose h2, .prose h3, .prose h4, .prose h5, .prose h6 { margin: 0 0 var(--space-2); }
.prose p { margin: 0 0 var(--space-3); color: var(--color-fg); }
.prose small { font-size: var(--text-sm); color: var(--color-fg-muted); }

/* The warning text is the amber of warning notices, not the bar's brighter amber. */
.text-warning { color: var(--color-warn-fg) !important; }
.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-fg-subtle);
}

/* A placeholder is an example, not a value. Bootstrap's .form-control::placeholder outranks a bare
   ::placeholder, so the controls are named too. */
::placeholder, .form-control::placeholder { color: var(--color-placeholder); opacity: 1; }

.cluster {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: center;
}

.cluster-tight {
  gap: var(--space-2);
}

/* A stack is as tall as its content: it neither grows to fill a flex parent nor stretches across a grid
   row, as Bootstrap's .vstack does. */
.vstack { flex: 0 1 auto; align-self: auto; }

/* Layout parents that space their children with a gap: the bottom margins Bootstrap gives bare elements
   (lists, headings) would add to it. Paragraphs keep theirs, and any class that sets a margin wins. */
:where(.vstack, .hstack, .card-body:not(.card), .form, .field, .cluster, .grid-2, .grid-3, .actions, .admin-main) > :not(p) { margin-bottom: 0; }

/* --- Buttons --------------------------------------------------- */
/* One primary action per view; secondary for everything else, ghost for low-priority actions.
   Destructive styles appear only inside danger flows. Disabled states spell their colours out
   instead of fading the button. Large 44, medium 40 (the default), small 32. */

.btn {
  --bs-btn-padding-x: var(--space-4);
  --bs-btn-padding-y: 0;
  --bs-btn-font-size: 0.8125rem;
  --bs-btn-font-weight: 500;
  --bs-btn-line-height: 1;
  --bs-btn-border-radius: var(--radius-lg);
  --bs-btn-box-shadow: none;
  --bs-btn-focus-box-shadow: none;
  --bs-btn-disabled-opacity: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  height: 2.5rem;
  /* the face of the text around it (a mono table cell gives a mono button) */
  font-family: inherit;
  /* on the text's baseline, as an inline-flex box sits by default (Bootstrap centres it) */
  vertical-align: baseline;
  white-space: nowrap;
  transition: background-color 120ms, color 120ms, border-color 120ms;
}
.btn svg { flex: none; width: 0.875rem; height: 0.875rem; }
/* Focus is the same green ring on every variant, danger included. */
.btn:focus-visible,
.btn-check:focus-visible + .btn {
  outline: 2px solid var(--color-accent);
  outline-offset: 1px;
  box-shadow: none;
}
.btn:disabled,
.btn.disabled,
.btn[aria-disabled="true"] { cursor: not-allowed; pointer-events: auto; }
/* aria-disabled (a link or span made to look like a button) takes the disabled colours too */
.btn[aria-disabled="true"] {
  color: var(--bs-btn-disabled-color);
  background-color: var(--bs-btn-disabled-bg);
  border-color: var(--bs-btn-disabled-border-color);
  opacity: var(--bs-btn-disabled-opacity);
}
/* A link is never disabled by its fieldset; only form controls are. */
fieldset:disabled a.btn:not(.disabled, [aria-disabled="true"]) {
  color: var(--bs-btn-color);
  background-color: var(--bs-btn-bg);
  border-color: var(--bs-btn-border-color);
  opacity: 1;
  pointer-events: auto;
  cursor: pointer;
}

.btn-sm {
  --bs-btn-padding-x: var(--space-3);
  --bs-btn-font-size: var(--text-xs);
  --bs-btn-border-radius: var(--radius-md);
  height: 2rem;
}
.btn-lg {
  --bs-btn-padding-x: var(--space-5);
  --bs-btn-font-size: 0.8125rem;
  height: 2.75rem;
}

.btn-primary,
.btn-success {
  --bs-btn-color: var(--color-btn-primary-fg);
  --bs-btn-bg: var(--color-btn-primary-bg);
  --bs-btn-border-color: var(--color-btn-primary-bg);
  --bs-btn-hover-color: var(--color-btn-primary-fg);
  --bs-btn-hover-bg: var(--color-btn-primary-bg-hover);
  --bs-btn-hover-border-color: var(--color-btn-primary-bg-hover);
  --bs-btn-active-color: var(--color-btn-primary-fg);
  --bs-btn-active-bg: var(--color-btn-primary-bg-pressed);
  --bs-btn-active-border-color: var(--color-btn-primary-bg-pressed);
  --bs-btn-disabled-color: var(--color-fg-disabled);
  --bs-btn-disabled-bg: var(--color-border);
  --bs-btn-disabled-border-color: var(--color-border);
  --bs-btn-font-weight: 600;
}

.btn-secondary,
.btn-outline-secondary,
.btn-light {
  --bs-btn-color: var(--color-fg);
  --bs-btn-bg: var(--color-btn-secondary-bg);
  --bs-btn-border-color: var(--color-control-border);
  --bs-btn-hover-color: var(--color-fg);
  --bs-btn-hover-bg: var(--color-surface-hover);
  --bs-btn-hover-border-color: var(--color-border-strong);
  --bs-btn-active-color: var(--color-fg);
  --bs-btn-active-bg: var(--color-surface-pressed);
  --bs-btn-active-border-color: var(--color-control-border);
  --bs-btn-disabled-color: var(--color-fg-disabled);
  --bs-btn-disabled-bg: var(--color-btn-secondary-bg);
  --bs-btn-disabled-border-color: var(--color-border);
}

/* A borderless button for low-priority actions (Cancel, Discard); it takes a fill only under the pointer. */
.btn-ghost {
  --bs-btn-color: var(--color-fg-secondary);
  --bs-btn-bg: transparent;
  --bs-btn-border-color: transparent;
  --bs-btn-hover-color: var(--color-fg);
  --bs-btn-hover-bg: var(--color-fill-quiet);
  --bs-btn-hover-border-color: transparent;
  --bs-btn-active-color: var(--color-fg);
  --bs-btn-active-bg: var(--color-surface-hover);
  --bs-btn-active-border-color: transparent;
  --bs-btn-disabled-color: var(--color-fg-disabled);
  --bs-btn-disabled-bg: transparent;
  --bs-btn-disabled-border-color: transparent;
}

.btn-outline-primary {
  --bs-btn-color: var(--color-accent);
  --bs-btn-bg: transparent;
  --bs-btn-border-color: var(--color-accent-line);
  --bs-btn-hover-color: var(--color-accent);
  --bs-btn-hover-bg: var(--color-accent-soft);
  --bs-btn-hover-border-color: var(--color-accent);
  --bs-btn-active-color: var(--color-accent);
  --bs-btn-active-bg: var(--color-accent-soft);
  --bs-btn-active-border-color: var(--color-accent);
  --bs-btn-disabled-color: var(--color-fg-disabled);
  --bs-btn-disabled-bg: transparent;
  --bs-btn-disabled-border-color: var(--color-border);
}

.btn-danger {
  --bs-btn-color: var(--color-on-danger);
  --bs-btn-bg: var(--color-btn-danger-bg);
  --bs-btn-border-color: var(--color-btn-danger-bg);
  --bs-btn-hover-color: var(--color-on-danger);
  --bs-btn-hover-bg: var(--color-btn-danger-bg-hover);
  --bs-btn-hover-border-color: var(--color-btn-danger-bg-hover);
  --bs-btn-active-color: var(--color-on-danger);
  --bs-btn-active-bg: var(--color-btn-danger-bg-pressed);
  --bs-btn-active-border-color: var(--color-btn-danger-bg-pressed);
  --bs-btn-disabled-color: color-mix(in srgb, var(--color-danger-fg) 70%, var(--color-surface));
  --bs-btn-disabled-bg: color-mix(in srgb, var(--color-danger-strong) 18%, var(--color-surface));
  --bs-btn-disabled-border-color: transparent;
  --bs-btn-font-weight: 600;
}

/* The quieter destructive action (Deactivate): a red outline that tints under the pointer. */
.btn-outline-danger {
  --bs-btn-color: var(--color-danger-fg);
  --bs-btn-bg: transparent;
  --bs-btn-border-color: color-mix(in srgb, var(--color-danger-strong) 40%, transparent);
  --bs-btn-hover-color: var(--color-danger-fg);
  --bs-btn-hover-bg: color-mix(in srgb, var(--color-danger-strong) 10%, transparent);
  --bs-btn-hover-border-color: color-mix(in srgb, var(--color-danger-strong) 60%, transparent);
  --bs-btn-active-color: var(--color-danger-fg);
  --bs-btn-active-bg: color-mix(in srgb, var(--color-danger-strong) 16%, transparent);
  --bs-btn-active-border-color: color-mix(in srgb, var(--color-danger-strong) 60%, transparent);
  --bs-btn-disabled-color: color-mix(in srgb, var(--color-danger-fg) 45%, var(--color-surface));
  --bs-btn-disabled-bg: transparent;
  --bs-btn-disabled-border-color: color-mix(in srgb, var(--color-danger-strong) 18%, var(--color-surface));
}

.btn-warning,
.btn-outline-warning {
  --bs-btn-color: var(--color-warn-fg);
  --bs-btn-bg: var(--color-warn-bg);
  --bs-btn-border-color: var(--color-warn-border);
  --bs-btn-hover-color: var(--color-warn-fg);
  --bs-btn-hover-bg: color-mix(in srgb, var(--color-warn-strong) 22%, transparent);
  --bs-btn-hover-border-color: var(--color-warn-strong);
  --bs-btn-active-color: var(--color-warn-fg);
  --bs-btn-active-bg: color-mix(in srgb, var(--color-warn-strong) 28%, transparent);
  --bs-btn-active-border-color: var(--color-warn-strong);
}

.btn-link {
  --bs-btn-color: var(--color-fg-muted);
  --bs-btn-hover-color: var(--color-fg);
  --bs-btn-active-color: var(--color-fg);
  --bs-btn-disabled-color: var(--color-fg-disabled);
  text-underline-offset: 0.2em;
}

/* A square button holding one 16px icon (14px when small). */
.btn-square { width: 2.5rem; padding: 0; }
.btn-square svg { width: 1rem; height: 1rem; }
.btn-square.btn-sm { width: 2rem; }
.btn-square.btn-sm svg { width: 0.875rem; height: 0.875rem; }

/* Same colours as the resting button, a 14px spinner before a label in -ing form ("Saving…"). */
.btn.is-loading,
.btn[aria-busy="true"] { cursor: progress; pointer-events: none; }
.btn.is-loading::before,
.btn[aria-busy="true"]::before {
  content: "";
  flex: none;
  width: 0.875rem;
  height: 0.875rem;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  opacity: 0.8;
  animation: spin 0.6s linear infinite;
}

/* A toggle group: plain buttons joined into one outlined bar, the pressed one inverse. */
.btn-group > .btn:not(:is(.btn-primary, .btn-secondary, .btn-outline-secondary, .btn-ghost, .btn-danger,
    .btn-outline-danger, .btn-outline-primary, .btn-success, .btn-warning, .btn-outline-warning, .btn-link, .btn-light)) {
  --bs-btn-color: var(--color-fg);
  --bs-btn-bg: var(--color-surface);
  --bs-btn-border-color: var(--color-border);
  --bs-btn-hover-color: var(--color-fg);
  --bs-btn-hover-bg: var(--color-surface);
  --bs-btn-hover-border-color: var(--color-border-strong);
  --bs-btn-active-color: var(--color-fg);
  --bs-btn-active-bg: var(--color-surface-hover);
  --bs-btn-active-border-color: var(--color-border-strong);
}
.btn-group > .btn:hover { z-index: 1; }
.btn-group > .btn-check:checked + .btn,
.btn-group > .btn.active,
.btn-group > .btn[aria-pressed="true"] {
  color: var(--color-fg-inverse);
  background: var(--color-fg);
  border-color: var(--color-fg);
}

/* A bare 40px button holding one icon; grouped ones sit 2px apart. */
.icon-actions { display: inline-flex; align-items: center; justify-content: flex-end; gap: 2px; }
.btn-icon {
  display: inline-grid; place-items: center;
  width: 2.5rem; height: 2.5rem; padding: 0;
  color: var(--color-fg-muted);
  background: transparent; border: 1px solid transparent; border-radius: var(--radius-lg);
  cursor: pointer; list-style: none;
  transition: color 120ms, background 120ms;
}
.btn-icon::-webkit-details-marker { display: none; }
.btn-icon:hover { color: var(--color-fg); background: var(--color-fill-quiet); }
.btn-icon:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 1px; }
.btn-icon-sm { width: 2rem; height: 2rem; border-radius: var(--radius-md); }
.btn-icon-danger:hover { color: var(--color-danger-fg); background: var(--color-danger-bg); }
.btn-icon.is-copied, .copy-field-btn.is-copied { color: var(--color-accent); }

/* The close button: a bare 24px square with the theme's x, in the text colour. */
.btn-close {
  --bs-btn-close-color: currentColor;
  --bs-btn-close-bg: none;
  --bs-btn-close-opacity: 1;
  --bs-btn-close-hover-opacity: 1;
  --bs-btn-close-focus-shadow: none;
  display: inline-grid;
  place-items: center;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  color: var(--color-fg-muted);
  background: none;
  border-radius: var(--radius-md);
  filter: none;
}
.btn-close:empty::before {
  content: "";
  width: 14px;
  height: 14px;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath fill='none' stroke='%23000' stroke-width='1.4' stroke-linecap='round' d='m3.5 3.5 7 7m0-7-7 7'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath fill='none' stroke='%23000' stroke-width='1.4' stroke-linecap='round' d='m3.5 3.5 7 7m0-7-7 7'/%3E%3C/svg%3E") center / contain no-repeat;
}
.btn-close .icon { width: 14px; height: 14px; }
.btn-close:hover { color: var(--color-fg); background: var(--color-fill-quiet); }
.btn-close:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 1px; box-shadow: none; }
.btn-close-white { filter: none; }

/* --- Forms ----------------------------------------------------- */
/* The label sits above and never moves; an error message replaces the helper line, so the field
   keeps its height. Focus is always the green edge and glow; an error swaps both for red. */

.form { display: flex; flex-direction: column; gap: var(--space-4); }
.field { display: flex; flex-direction: column; gap: var(--space-2); }
.field-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); }

/* A label, hint or error adds no margin of its own (a paragraph keeps the browser's): the field, or
   whatever holds it, spaces them. */
.form-label,
.col-form-label {
  margin-bottom: revert;
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.4;
  color: var(--color-fg);
}
.form-text {
  margin-top: revert;
  font-size: 0.8125rem;
  line-height: 1.55;
  color: var(--color-fg-muted);
}
/* a segmented bar of buttons keeps its own width in a field instead of stretching across it */
.field > .btn-group { align-self: flex-start; }

.invalid-feedback {
  margin-top: revert;
  font-size: 0.8125rem;
  line-height: 1.55;
  color: var(--color-danger-fg);
}
.valid-feedback { font-size: 0.8125rem; color: var(--color-success-fg); }

/* A fixed 44px, so an app can set a control shorter or taller with its own height. */
.form-control,
.form-select {
  height: 2.75rem;
  padding: var(--space-2) 0.875rem;
  font-family: inherit;
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--color-fg);
  background-color: var(--color-surface);
  border: 1px solid var(--color-control-border);
  border-radius: var(--radius-lg);
  transition: border-color 120ms, box-shadow 120ms;
}
/* A textarea is set in the text face at 14px, a .form-control-code one too. */
textarea.form-control { height: auto; min-height: 7rem; padding: var(--space-3) 0.875rem; font-family: inherit; font-size: var(--text-sm); resize: vertical; }
.form-control:hover,
.form-select:hover { border-color: var(--color-border-strong); }
.form-control:focus,
.form-select:focus {
  color: var(--color-fg);
  background-color: var(--color-surface);
  border-color: var(--color-accent);
  box-shadow: 0 0 0 3px var(--color-accent-ring);
  outline: 0;
}
:is(.form-control, .form-select):is([aria-invalid="true"], .is-invalid),
.was-validated :is(.form-control, .form-select):invalid,
.field-error :is(.form-control, .form-select) {
  border-color: var(--color-danger-strong);
  box-shadow: 0 0 0 3px var(--color-danger-ring);
  background-image: none;
  padding-right: 0.875rem;
}
.form-select:is([aria-invalid="true"], .is-invalid),
.field-error .form-select { background-image: var(--select-chevron); padding-right: calc(var(--space-3) * 2 + 16px); }
.form-control.is-valid,
.was-validated .form-control:valid { background-image: none; padding-right: 0.875rem; }
:is(.form-control, .form-select):disabled {
  color: var(--color-fg-disabled);
  background-color: var(--color-surface-sunken);
  border-color: var(--color-divider);
  cursor: not-allowed;
}
.form-control[readonly]:not(:disabled) {
  color: var(--color-fg-secondary);
  background-color: var(--color-surface-sunken);
  border-color: var(--color-border);
}
.form-control[readonly]:not(:disabled):focus { border-color: var(--color-border); box-shadow: none; }

.form-select:is([multiple], [size]:not([size="1"])) { height: auto; }
.form-control-sm,
.form-select-sm { height: 2rem; padding-top: var(--space-1); padding-bottom: var(--space-1); font-size: var(--text-xs); border-radius: var(--radius-md); }
.form-control-lg,
.form-select-lg { height: 3rem; font-size: var(--text-base); }

.form-control[type="file"] {
  /* as tall as its button and padding: 42px */
  height: auto;
  padding: var(--space-1);
  color: var(--color-fg-muted);
  cursor: pointer;
}
.form-control[type="file"]::file-selector-button {
  height: 2rem;
  margin: 0 var(--space-3) 0 0;
  padding: 0 var(--space-3);
  font: 500 var(--text-sm) var(--font-sans);
  color: var(--color-fg);
  background: var(--color-surface-subtle);
  border: 1px solid var(--color-control-border);
  border-radius: var(--radius-md);
  cursor: pointer;
}
.form-control[type="file"]:hover:not(:disabled):not([readonly])::file-selector-button { background: var(--color-surface-subtle); border-color: var(--color-fg-muted); }

.form-control-plaintext { font-size: var(--text-sm); color: var(--color-fg); }

/* mono values: URLs, ids, keys */
.form-control-code { font-family: var(--font-mono); font-size: 0.8125rem; }
.form-control-spaced { letter-spacing: 0.18em; }
.form-control-underline {
  min-height: 0;
  padding: var(--space-2) 0;
  background: transparent;
  border-width: 0 0 1px;
  border-color: var(--color-border);
  border-radius: 0;
}
.form-control-underline:focus { border-color: var(--color-accent); box-shadow: none; background: transparent; }

/* The chevron sits inset like the text padding and turns up while a list is open; the chosen value
   truncates, never wraps. */
.form-select {
  padding-right: calc(var(--space-3) * 2 + 16px);
  text-overflow: ellipsis;
  background-image: var(--select-chevron);
  background-position: right var(--space-3) center;
  background-size: 16px 16px;
  background-repeat: no-repeat;
}
.form-select[multiple],
.form-select[size]:not([size="1"]) { padding-right: 0.875rem; background-image: none; }

.input-group-text {
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
  background-color: var(--color-surface-subtle);
  border-color: var(--color-control-border);
  border-radius: var(--radius-lg);
}

.form-range { height: 1rem; }
.form-range::-webkit-slider-runnable-track { height: 2px; background: var(--color-border); border-radius: 0; }
.form-range::-moz-range-track { height: 2px; background: var(--color-border); border-radius: 0; }
.form-range::-webkit-slider-thumb { width: 14px; height: 14px; margin-top: -6px; background: var(--color-fg); border-radius: 0; }
.form-range::-moz-range-thumb { width: 14px; height: 14px; background: var(--color-fg); border: 0; border-radius: 0; }
.form-range:focus::-webkit-slider-thumb { box-shadow: 0 0 0 3px var(--color-accent-ring); }

/* A check or radio and its label, the label clickable; a disabled one greys out with its control.
   Works for Bootstrap's markup (div.form-check, input.form-check-input, label.form-check-label) and for
   a label wrapping its input. */
.form-check {
  display: flex;
  width: fit-content;
  align-items: center;
  gap: var(--space-3);
  min-height: 0;
  margin-bottom: 0;
  padding-left: 0;
  font-size: var(--text-sm);
  font-weight: 500;
  cursor: pointer;
}
.form-check .form-check-input { float: none; margin: 0; }
/* a label wrapping its control flows inline, like the text it sits in */
label.form-check { display: inline-flex; }
.form-check-label { cursor: pointer; }
.form-check:has(input:disabled),
.form-check-input:disabled ~ .form-check-label { color: var(--color-fg-disabled); cursor: not-allowed; opacity: 1; }
.form-check-inline { display: inline-flex; margin-right: var(--space-4); }
.form-check-reverse { flex-direction: row-reverse; padding-right: 0; }

/* Checkboxes everywhere: an 18px square, filled with the accent and a check (or a dash when mixed). */
input[type="checkbox"],
.form-check-input[type="checkbox"] {
  appearance: none;
  flex: none;
  width: 1.125rem;
  height: 1.125rem;
  margin: 0;
  border: 1px solid var(--color-border-off);
  border-radius: var(--radius-sm);
  background: var(--color-surface) center / 0.75rem no-repeat;
  vertical-align: -0.1875rem;
  cursor: pointer;
  transition: border-color 120ms, background-color 120ms;
}
input[type="checkbox"]:hover,
.form-check-input[type="checkbox"]:hover { border-color: var(--color-fg-muted); }
input[type="checkbox"]:is(:checked, :indeterminate),
.form-check-input[type="checkbox"]:is(:checked, :indeterminate) {
  border-color: var(--color-accent);
  background-color: var(--color-accent);
  background-image: var(--checkbox-check);
}
input[type="checkbox"]:indeterminate,
.form-check-input[type="checkbox"]:indeterminate { background-image: var(--checkbox-dash); }
input[type="checkbox"]:is(:checked, :indeterminate):hover,
.form-check-input[type="checkbox"]:is(:checked, :indeterminate):hover { border-color: var(--color-accent-hover); background-color: var(--color-accent-hover); }

/* Radios: an 18px circle, an 8px accent dot when selected. */
input[type="radio"],
.form-check-input[type="radio"] {
  appearance: none;
  flex: none;
  width: 1.125rem;
  height: 1.125rem;
  margin: 0;
  border: 1px solid var(--color-border-off);
  border-radius: 50%;
  background: var(--color-surface);
  vertical-align: -0.1875rem;
  cursor: pointer;
  transition: border-color 120ms, background 120ms;
}
input[type="radio"]:hover,
.form-check-input[type="radio"]:hover { border-color: var(--color-fg-muted); }
input[type="radio"]:checked,
.form-check-input[type="radio"]:checked {
  border-color: var(--color-accent);
  background: var(--color-accent);
  box-shadow: inset 0 0 0 4px var(--color-surface);
}

:is(input[type="checkbox"], input[type="radio"]):focus { box-shadow: none; }
:is(input[type="checkbox"], input[type="radio"]):focus-visible { outline: 2px solid var(--color-accent); outline-offset: 1px; }
:is(input[type="checkbox"], input[type="radio"]):disabled { cursor: not-allowed; opacity: 0.45; }
:is(input[type="checkbox"], input[type="radio"]):is([aria-invalid="true"], .is-invalid) {
  border-color: var(--color-danger-strong);
  box-shadow: 0 0 0 3px var(--color-danger-ring);
}

/* The switch: a 36x20 frame with a square knob that slides right and turns green. */
.form-switch { padding-left: 0; gap: var(--space-2); font-weight: 400; }
.form-switch input[type="checkbox"],
.form-switch .form-check-input[type="checkbox"] {
  width: 2.25rem;
  height: 1.25rem;
  margin: 0;
  border: 1px solid var(--color-border-strong);
  border-radius: 4px;
  background: var(--color-surface) var(--switch-knob) left 2px center / 14px no-repeat;
  transition: border-color 120ms, background-position 120ms;
}
.form-switch input[type="checkbox"]:hover { border-color: var(--color-border-strong); }
.form-switch input[type="checkbox"]:checked,
.form-switch input[type="checkbox"]:checked:hover {
  border-color: var(--color-accent);
  background: var(--color-surface) var(--switch-knob-on) right 2px center / 14px no-repeat;
}
.form-switch input[type="checkbox"]:focus-visible { outline-offset: 2px; }

/* Radio cards: for choices that need a sentence of explanation; the whole card is the target.
   Selected gets a green hairline and a faint fill. */
.radio-card {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: 0.875rem var(--space-4);
  border: 1px solid var(--color-control-border);
  border-radius: 0.625rem;
  background: var(--color-surface-sunken);
  cursor: pointer;
  transition: border-color 120ms, background 120ms;
}
.radio-card input { margin-top: 1px; }
.radio-card:hover { background: var(--color-surface-subtle); border-color: var(--color-border-strong); }
.radio-card:has(input:checked) { background: var(--color-accent-wash); border-color: var(--color-accent-line); }
.radio-card:has(input:focus-visible) { outline: 2px solid var(--color-accent); outline-offset: 1px; }
.radio-card:has(input:focus-visible) input { outline: 0; }
.radio-card:has(input:disabled) { opacity: 0.45; cursor: not-allowed; }
.radio-card-title { display: block; font-size: var(--text-sm); font-weight: 500; line-height: 1.4; color: var(--color-fg); }
.radio-card-desc { display: block; margin-top: 2px; font-size: 0.8125rem; line-height: 1.55; color: var(--color-fg-muted); }

/* --- Tables ---------------------------------------------------- */
/* Rows are 56px under a 40px head with no fill of its own; the head is mono caps. Values people may
   copy (URLs, ids) are mono. Only rows with something to act on highlight. */

.table {
  --bs-table-color: var(--color-fg);
  --bs-table-bg: transparent;
  --bs-table-border-color: var(--color-divider);
  --bs-table-striped-color: var(--color-fg);
  --bs-table-striped-bg: var(--color-surface-subtle);
  --bs-table-active-color: var(--color-fg);
  --bs-table-active-bg: var(--color-accent-wash);
  --bs-table-hover-color: var(--color-fg);
  --bs-table-hover-bg: var(--color-row-hover);
  margin-bottom: revert;
  font-size: var(--text-sm);
  border-collapse: separate;
  border-spacing: 0;
}
.table > :not(caption) > * > * {
  height: 3.5rem;
  padding: var(--space-3) var(--space-4);
  vertical-align: middle;
  text-align: left;
  border-bottom-width: 1px;
}
/* every heading cell, a row's heading in the body too, is set as the head */
.table > thead > * > *,
.table > * > * > th {
  height: 2.5rem;
  padding-block: 0;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-fg-subtle);
  border-top: 1px solid var(--color-divider);
  border-bottom-color: var(--color-border);
}
.table > :not(:first-child) { border-top: 0; }
.table tbody tr:has(a, button):hover > * { --bs-table-bg-state: var(--color-row-hover); }
.table tbody tr:is(.is-selected, [aria-selected="true"]) > * { --bs-table-bg-state: var(--color-accent-wash); }
/* an inactive row stays readable, its text dimmed rather than faded */
.table tbody tr.is-inactive > * { color: var(--color-fg-disabled); }

.table-sm > :not(caption) > * > * { height: 2.5rem; padding: var(--space-2) var(--space-3); }
/* rows as tall as their content (short activity lists), not the 56px row of a list table */
.table-compact > :not(caption, thead) > * > * { height: auto; }
.table-compact > thead > * > * { border-top: 0; }
/* many narrow columns: tighter side padding keeps them on screen */
.table-dense > :not(caption) > * > * { padding-inline: var(--space-2); }
.table-dense > :not(caption) > * > :first-child { padding-left: var(--space-3); }

.table-check { width: 1.5rem; padding-right: 0 !important; }
.table-row-link { color: var(--color-fg); text-decoration: none; font-weight: 500; }
.table-row-link:hover { text-decoration: underline; }
button.table-row-link { background: none; border: 0; padding: 0; font: inherit; cursor: pointer; text-align: left; }
/* the column that takes the spare width, so the status columns sit at the right edge */
.table td.table-fill { width: 100%; }
/* an optional note column folds away when a row has nothing to say */
.table td.table-note:empty { padding: 0; }
/* a secondary line under a cell's main value (a host under a node name, an age under a badge) */
.table-sub { display: block; margin-top: 2px; font-size: var(--text-xs); color: var(--color-fg-muted); }
/* tag chips wrap onto a second line instead of widening the table */
.table td.table-tags { white-space: normal; min-width: 8.5rem; max-width: 9rem; line-height: 1.9; }
/* a row's open link as a bare chevron */
.table-chevron { display: inline-block; padding: 0 var(--space-2); color: var(--color-fg-subtle); font-size: var(--text-xl); line-height: 1; text-decoration: none; }
.table tr:hover .table-chevron, .table-chevron:focus-visible { color: var(--color-fg); }
/* a value and the badge that qualifies it (a release and OUTDATED) */
.table td > code + .badge { margin-left: var(--space-2); }

/* A list page's table framed like a form card: the card's fill and corners. It scrolls sideways
   inside its frame. */
.table-card,
.table-frame {
  overflow-x: auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  background: var(--color-surface-subtle);
}
/* Element selectors, so the rules reach every table kind in the frame (.table and the apps' own tables)
   and outrank each kind's own th/td rules. */
:is(.table-card, .table-frame) table { margin: 0; }
:is(.table-card, .table-frame) table th { background: transparent; border-top: 0; }
.table-card table :is(th, td):first-child { padding-left: var(--space-5); }
.table-card table :is(th, td):last-child { padding-right: var(--space-5); }
/* The last row drops its rule against the frame: any table in a card frame, a compact table in a plain one. */
.table-card table > tbody > tr:last-child > *,
.table-frame .table-compact > tbody > tr:last-child > * { border-bottom: 0; }

.toolbar { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-3); margin-bottom: var(--space-4); }
.toolbar-search { flex: 1 1 280px; min-width: 220px; }
.toolbar-group { display: flex; flex-direction: column; gap: 4px; }
.toolbar-label { font-size: var(--text-xs); color: var(--color-fg-muted); font-family: var(--font-mono); letter-spacing: 0.02em; }
.daterange { display: inline-flex; align-items: center; gap: var(--space-2); }
.daterange .form-control { width: 11.5rem; }
.daterange-sep { color: var(--color-fg-subtle); font-family: var(--font-mono); }

.th-sort { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; user-select: none; color: inherit; text-decoration: none; }
.th-sort-arrow { font-family: var(--font-mono); font-size: 0.75rem; color: var(--color-fg-subtle); line-height: 1; }
.th-sort-active .th-sort-arrow { color: var(--color-fg); }

.table-footer { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-3) 0; flex-wrap: wrap; }
.table-footer-count { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--color-fg-muted); }
.table-footer .pagination { margin: 0; }
.table-empty { text-align: center; color: var(--color-fg-muted); padding: var(--space-5) var(--space-4); }
/* in a table cell too: td.table-empty outranks the colour Bootstrap gives every cell */
td.table-empty { color: var(--color-fg-muted); }

/* Mail log (Gmail-style) */
.table-mail-log thead { display: none; }
td.mail-log-main { width: 100%; max-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mail-log-snippet { color: var(--color-fg-muted); }
td.mail-log-meta { width: 1%; white-space: nowrap; text-align: right; }
.mail-log-meta-inner { display: flex; align-items: center; justify-content: flex-end; gap: 0.5rem; }
.mail-log-type { display: inline-flex; align-items: center; justify-content: center; width: 1.5rem; height: 1.5rem; border-radius: 50%; border: 1px solid var(--color-border); font-size: 0.8rem; }
.mail-log-time { color: var(--color-fg-muted); font-variant-numeric: tabular-nums; min-width: 4ch; }

/* --- Navigation ------------------------------------------------ */

.nav {
  --bs-nav-link-padding-x: var(--space-3);
  --bs-nav-link-padding-y: var(--space-2);
  --bs-nav-link-font-size: var(--text-sm);
  --bs-nav-link-color: var(--color-fg-muted);
  --bs-nav-link-hover-color: var(--color-fg);
  --bs-nav-link-disabled-color: var(--color-fg-disabled);
  gap: var(--space-1);
}
.nav-link:focus-visible { outline: 2px solid var(--color-accent); outline-offset: -2px; box-shadow: none; }

/* 44px tabs over a hairline; the current one is underlined in the accent. Same weight as the other
   tabs: a heavier one is wider and would shift its neighbours. */
.nav-tabs {
  --bs-nav-tabs-border-width: 1px;
  --bs-nav-tabs-border-color: var(--color-border);
  --bs-nav-tabs-border-radius: var(--radius-md);
  --bs-nav-tabs-link-hover-border-color: transparent;
  --bs-nav-tabs-link-active-color: var(--color-fg-strong);
  --bs-nav-tabs-link-active-bg: transparent;
  --bs-nav-tabs-link-active-border-color: transparent;
  /* one row, as the tabs always were: a wrapped tab would hang under the row's hairline */
  flex-wrap: nowrap;
  margin: 0;
  padding: 0;
  list-style: none;
}
.nav-tabs .nav-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  height: 2.75rem;
  padding: 0 0.875rem;
  font-family: inherit;
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: var(--radius-md) var(--radius-md) 0 0;
  margin-bottom: -1px;
}
.nav-tabs .nav-link:is(.active, [aria-selected="true"], [aria-current="page"]),
.nav-tabs .nav-item.show .nav-link {
  color: var(--color-fg-strong);
  background: none;
  border-bottom-color: var(--color-accent);
}
.nav-tabs .nav-link:is(:disabled, .disabled, [aria-disabled="true"]) { color: var(--color-fg-disabled); cursor: not-allowed; }
.nav-link-danger, .nav-tabs .nav-link-danger { color: var(--color-danger-fg); }
.nav-link-danger:hover { color: color-mix(in srgb, var(--color-danger-fg) 80%, var(--color-fg)); }
.nav-tabs .nav-link-danger:is(.active, [aria-selected="true"], [aria-current="page"]) {
  color: var(--color-danger-fg);
  border-bottom-color: var(--color-danger-strong);
}
/* A tab with something to fix carries an amber dot after its label. */
.nav-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--color-warn-strong); }

/* Pills and list tabs take the side nav's fills: a quiet hover, a green wash for the current one. */
.nav-pills {
  --bs-nav-pills-border-radius: var(--radius-lg);
  --bs-nav-pills-link-active-color: var(--color-fg-strong);
  --bs-nav-pills-link-active-bg: var(--color-accent-soft);
}
.nav-pills .nav-link { font-weight: 500; }
.nav-pills .nav-link:hover { background: var(--color-nav-active); }
.nav-pills .nav-link[aria-current="page"] { color: var(--color-fg-strong); background: var(--color-accent-soft); }

.nav-underline {
  --bs-nav-underline-gap: var(--space-1);
  --bs-nav-underline-link-active-color: var(--color-fg-strong);
}
.nav-underline .nav-link.active { border-bottom-color: var(--color-accent); font-weight: inherit; }

.tab-content > .tab-pane:focus { outline: 0; }

/* Links are muted and underline on hover; the current page is bright and not a link. */
.breadcrumb {
  --bs-breadcrumb-margin-bottom: 0;
  --bs-breadcrumb-font-size: 0.8125rem;
  --bs-breadcrumb-item-padding-x: var(--space-2);
  --bs-breadcrumb-item-active-color: var(--color-fg);
  align-items: center;
  color: var(--color-fg-muted);
  line-height: 1.5;
}
.breadcrumb-item { display: inline-flex; align-items: center; min-width: 0; }
.breadcrumb-item + .breadcrumb-item::before {
  content: "";
  flex: none;
  float: none;
  width: 12px;
  height: 12px;
  padding: 0;
  margin-right: var(--space-2);
  background: var(--color-border-off);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%23000' stroke-width='1.2' stroke-linecap='round' stroke-linejoin='round' d='m4.5 3 3 3-3 3'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%23000' stroke-width='1.2' stroke-linecap='round' stroke-linejoin='round' d='m4.5 3 3 3-3 3'/%3E%3C/svg%3E") center / contain no-repeat;
}
.breadcrumb a { color: var(--color-fg-muted); text-decoration: none; border-radius: var(--radius-sm); }
.breadcrumb a:hover { color: var(--color-fg); text-decoration: underline; }
.breadcrumb a:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.breadcrumb-item.active,
.breadcrumb-item[aria-current="page"] { color: var(--color-fg); font-weight: 500; }
.breadcrumb-ellipsis { color: var(--color-fg-muted); }

/* Square mono pages 4px apart; hover and the current page take the side nav's fills. */
.pagination {
  --bs-pagination-padding-x: var(--space-2);
  --bs-pagination-padding-y: 0;
  --bs-pagination-font-size: var(--text-sm);
  --bs-pagination-color: var(--color-fg-muted);
  --bs-pagination-bg: transparent;
  --bs-pagination-border-color: var(--color-border);
  --bs-pagination-border-radius: var(--radius-md);
  --bs-pagination-hover-color: var(--color-fg);
  --bs-pagination-hover-bg: var(--color-nav-active);
  --bs-pagination-hover-border-color: var(--color-border);
  --bs-pagination-focus-color: var(--color-fg);
  --bs-pagination-focus-bg: transparent;
  --bs-pagination-focus-box-shadow: none;
  --bs-pagination-active-color: var(--color-fg-strong);
  --bs-pagination-active-bg: var(--color-accent-soft);
  --bs-pagination-active-border-color: transparent;
  --bs-pagination-disabled-color: var(--color-fg-disabled);
  --bs-pagination-disabled-bg: transparent;
  --bs-pagination-disabled-border-color: var(--color-border);
  gap: var(--space-1);
  margin: 0;
}
.page-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.25rem;
  height: 2.25rem;
  font-family: var(--font-mono);
  text-decoration: none;
  border-radius: var(--bs-pagination-border-radius);
}
.page-item:not(:first-child) .page-link { margin-left: 0; }
.page-item .page-link { border-radius: var(--bs-pagination-border-radius); }
.page-link:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 1px; }
.page-link[aria-current="page"],
.active > .page-link {
  color: var(--color-fg-strong);
  background: var(--color-accent-soft);
  border-color: transparent;
  font-weight: 600;
}

/* The top bar: brand on the left, links and the account menu on the right. */
.navbar {
  --bs-navbar-padding-x: var(--space-6);
  --bs-navbar-padding-y: var(--space-2);
  --bs-navbar-color: var(--color-fg-muted);
  --bs-navbar-hover-color: var(--color-fg);
  --bs-navbar-active-color: var(--color-fg);
  --bs-navbar-brand-color: inherit;
  --bs-navbar-brand-hover-color: inherit;
  --bs-navbar-nav-link-padding-x: var(--space-3);
  min-height: 3.75rem;
  border-bottom: 1px solid var(--color-divider);
  background: var(--brand-header-bg, var(--color-surface));
  color: var(--brand-header-fg, var(--color-fg));
}
.navbar .wordmark { color: inherit; }
.navbar .nav { --bs-nav-link-color: var(--bs-navbar-color); --bs-nav-link-hover-color: var(--bs-navbar-hover-color); }
.navbar .nav-link { border-bottom: 1px solid transparent; }
.navbar .nav-link:is(.active, [aria-current="page"]) { color: var(--bs-navbar-active-color); border-bottom-color: currentColor; }
/* A dark bar stays dark in both themes (the inverse tokens flip in dark mode), so its text is fixed light. */
.navbar-dark {
  --bs-navbar-color: #fafafb;
  --bs-navbar-hover-color: #fafafb;
  --bs-navbar-active-color: #fafafb;
  background: #111215;
  border-color: #262626;
  color: #fafafb;
}

/* --- Alerts ---------------------------------------------------- */
/* Inline, tied to the section it belongs to: the tone's fill and line, an icon in the tone, the text
   itself in the regular colours. The icon is drawn by the alert, so the markup stays plain text. */

.alert {
  --bs-alert-padding-x: var(--space-4);
  --bs-alert-padding-y: var(--space-3);
  --bs-alert-border-radius: 0.625rem;
  --bs-alert-color: var(--color-fg);
  --bs-alert-bg: var(--color-notice-bg);
  --bs-alert-border-color: transparent;
  --bs-alert-link-color: var(--color-fg);
  font-size: var(--text-sm);
  /* the page spaces its notices: an alert adds no margin of its own (a paragraph keeps the browser's) */
  margin-bottom: revert;
}
.alert-info,
.alert-success,
.alert-warning,
.alert-danger,
.alert-primary {
  --alert-tone: var(--color-info-fg);
  --alert-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18' fill='none' stroke='%23000' stroke-width='1.575' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='9' r='7'/%3E%3Cpath d='M9 8.25v4M9 5.75v.01'/%3E%3C/svg%3E");
  --bs-alert-color: var(--color-fg);
  --bs-alert-bg: var(--color-info-bg);
  --bs-alert-border-color: var(--color-info-border);
  position: relative;
  padding: 0.875rem var(--space-4) 0.875rem 2.875rem;
  font-size: 0.8125rem;
  line-height: 1.55;
}
.alert-info::before,
.alert-success::before,
.alert-warning::before,
.alert-danger::before,
.alert-primary::before {
  content: "";
  position: absolute;
  top: calc(0.875rem + 1px);
  left: var(--space-4);
  width: 18px;
  height: 18px;
  background: var(--alert-tone);
  -webkit-mask: var(--alert-icon) center / contain no-repeat;
  mask: var(--alert-icon) center / contain no-repeat;
}
.alert-success,
.alert-primary {
  --alert-tone: var(--color-success-fg);
  --alert-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18' fill='none' stroke='%23000' stroke-width='1.575' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='9' r='7'/%3E%3Cpath d='m6.25 9.1 1.9 1.9 3.6-3.75'/%3E%3C/svg%3E");
  --bs-alert-bg: var(--color-success-bg);
  --bs-alert-border-color: var(--color-success-border);
}
.alert-warning {
  --alert-tone: var(--color-warn-fg);
  --alert-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18' fill='none' stroke='%23000' stroke-width='1.575' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7.7 3.05 1.9 13.1a1.5 1.5 0 0 0 1.3 2.25h11.6a1.5 1.5 0 0 0 1.3-2.25L10.3 3.05a1.5 1.5 0 0 0-2.6 0Z'/%3E%3Cpath d='M9 7.25v3M9 12.75v.01'/%3E%3C/svg%3E");
  --bs-alert-bg: var(--color-warn-bg);
  --bs-alert-border-color: var(--color-warn-border);
}
.alert-danger {
  --alert-tone: var(--color-danger-fg);
  --alert-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18' fill='none' stroke='%23000' stroke-width='1.575' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='9' r='7'/%3E%3Cpath d='M9 5.75v4M9 12.25v.01'/%3E%3C/svg%3E");
  --bs-alert-bg: var(--color-danger-bg);
  --bs-alert-border-color: var(--color-danger-border);
}
/* plain notices: the quiet fill, no icon */
.alert-secondary,
.alert-light,
.alert-dark {
  --bs-alert-color: var(--color-fg);
  --bs-alert-bg: var(--color-notice-bg);
  --bs-alert-border-color: transparent;
}
.alert-heading { display: block; margin: 0; font-size: var(--text-sm); font-weight: 500; line-height: 1.4; color: var(--color-fg); }
.alert-body { display: block; margin-top: 1px; color: var(--color-fg-secondary); }
.alert a:not(.btn) { color: var(--color-fg); font-weight: 500; text-decoration: underline; }
.alert-link { display: inline-block; margin-top: 6px; color: var(--color-fg); font-weight: 500; text-decoration: underline; }
/* a small button in the alert's text keeps the line its normal height, so the icon stays level with the text */
.alert > .btn-sm { margin-block: -0.375rem; }
.alert > p:last-child, .alert > ul:last-child { margin-bottom: 0; }
/* Dismiss only notices that will not return. */
.alert-dismissible { padding-right: 3rem; }
.alert .btn-close,
.alert-dismissible .btn-close { position: absolute; top: 0.75rem; right: 0.75rem; z-index: 2; padding: 0; }
.alert:has(> .btn-close) { padding-right: 3rem; }
/* one line: tighter, the icon centred on it */
.alert-compact { padding-top: 0.625rem; padding-bottom: 0.625rem; padding-left: 2.625rem; }
.alert-compact::before { top: 50%; left: 0.875rem; width: 16px; height: 16px; transform: translateY(-50%); }
.alert-compact:not(:is(.alert-info, .alert-success, .alert-warning, .alert-danger, .alert-primary)) { padding-left: var(--space-4); }

/* --- Badges and chips ------------------------------------------ */
/* A badge is the status of a thing (Active, Expires soon): a 24px pill in sentence case. A status
   tone leads with a dot, so the colour never stands alone; the plain badge is the inactive one.
   Bootstrap's text-bg-* tones are the status tones here. */

.badge {
  --bs-badge-padding-x: 10px;
  --bs-badge-padding-y: 0;
  --bs-badge-font-size: var(--text-xs);
  --bs-badge-font-weight: 500;
  --bs-badge-color: var(--color-fg-muted);
  --bs-badge-border-radius: var(--radius-full);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 1.5rem;
  font-family: var(--font-sans);
  line-height: 1;
  text-transform: capitalize;
  letter-spacing: 0;
  white-space: nowrap;
  border: 1px solid var(--color-border);
  background: var(--color-badge-neutral);
}
.badge.text-bg-success { color: var(--color-success-fg) !important; background: var(--color-accent-soft) !important; border-color: var(--color-accent-line); }
.badge.text-bg-danger { color: var(--color-danger-fg) !important; background: var(--color-danger-bg) !important; border-color: var(--color-danger-border); }
.badge.text-bg-warning { color: var(--color-warn-fg) !important; background: var(--color-warn-bg) !important; border-color: var(--color-warn-border); }
.badge.text-bg-info { color: var(--color-info-fg) !important; background: var(--color-info-bg) !important; border-color: var(--color-info-border); }
.badge:is(.text-bg-success, .text-bg-danger, .text-bg-warning, .text-bg-info)::before {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}
/* primary: the accent outline, no state */
.badge.text-bg-primary { color: var(--color-accent) !important; background: transparent !important; border-color: var(--color-accent-line); }
/* secondary and light: a plain label with no state, so no fill and no dot */
.badge:is(.text-bg-secondary, .text-bg-light) { color: var(--color-fg-secondary) !important; background: transparent !important; border-color: var(--color-control-border); }
.badge.text-bg-dark { color: var(--color-fg-inverse) !important; background: var(--color-fg) !important; border-color: var(--color-fg); }
.badge.rounded-pill { border-radius: var(--radius-full) !important; }

/* The small badge: 20px, 11px text. */
.badge-sm { height: 1.25rem; padding: 0 var(--space-2); font-size: 0.6875rem; }
/* badges stacked in a column (a role legend) share one width */
.badge-even { min-width: 6rem; justify-content: center; }
/* a badge holding a literal value (a release id) keeps its case */
.badge-code { text-transform: none; }
/* a long value broken into lines inside one badge (a release id after its date) */
.badge-stack { flex-direction: column; align-items: flex-start; gap: 0; height: auto; padding-block: 3px; line-height: 1.5; }
.badge-stack::before { display: none !important; }

/* In-heading badges sit on the baseline with the text */
:is(h1, h2, h3, h4, h5, h6) .badge { margin-left: var(--space-2); transform: translateY(-2px); }

/* Counters and pinned markers carry a number, not a state: no dot. A toned one is solid, so it
   reads on any surface, a primary button included; an empty pin is the dot alone. */
.badge-anchor { position: relative; display: inline-flex; }
.badge-pin { position: absolute; top: -8px; right: -10px; z-index: 1; }
.badge:is(.badge-counter, .badge-pin)::before { display: none; }
.badge-counter { height: 1.25rem; padding: 0 var(--space-1); min-width: 1.25rem; justify-content: center; }
.badge:is(.badge-counter, .badge-pin).text-bg-danger { color: var(--color-on-danger) !important; background: var(--color-btn-danger-bg) !important; border-color: transparent; }
.badge:is(.badge-counter, .badge-pin).text-bg-success { color: var(--color-on-accent) !important; background: var(--color-accent) !important; border-color: transparent; }
.badge-pin:empty { display: inline-flex; width: 10px; height: 10px; min-width: 0; padding: 0; top: -4px; right: -4px; background: currentColor !important; }

/* A tag is a fixed label (Required, Default, SAML): a small rectangle in mono caps, no fill. */
.chips { display: inline-flex; gap: var(--space-1); flex-wrap: wrap; }
.chip {
  display: inline-flex;
  align-items: center;
  padding: 2px 6px;
  font: 500 0.65625rem/1.5 var(--font-mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--color-fg-muted);
  background: transparent;
  border: 1px solid var(--color-control-border);
  border-radius: var(--radius-sm);
}
.chip-accent { color: var(--color-accent); border-color: var(--color-accent-line); }
.chip-warn { color: var(--color-warn-fg); border-color: var(--color-warn-border); }
.chip-danger { color: var(--color-danger-fg); border-color: var(--color-danger-border); }
.chip-more { color: var(--color-fg-subtle); border-style: dashed; }

/* A value someone added (an email, a domain): a raised mono chip with a remove button. */
.chip-removable {
  display: inline-flex; align-items: center; gap: 6px;
  height: 1.75rem; padding: 0 6px 0 10px;
  font: 400 var(--text-xs)/1 var(--font-mono); color: var(--color-fg);
  background: var(--color-surface-raised);
  border: 1px solid var(--color-control-border);
  border-radius: var(--radius-md);
}
.chip-removable:hover { border-color: var(--color-border-strong); }
.chip-removable-remove {
  display: grid; place-items: center;
  width: 18px; height: 18px; padding: 0;
  color: var(--color-fg-muted);
  background: none; border: 0; border-radius: var(--radius-sm);
  cursor: pointer;
}
.chip-removable-remove:hover { color: var(--color-fg); background: var(--color-surface-hover); }
.chip-removable-remove .icon { width: 12px; height: 12px; }

.status { display: inline-flex; align-items: center; gap: var(--space-2); }
.status-name { font-weight: 500; }
.status-label { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-fg-subtle); text-transform: lowercase; letter-spacing: 0.04em; }
.status-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--color-fg-subtle); flex-shrink: 0; }
.status-dot-ok { background: var(--color-accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 14%, transparent); }
.status-dot-warn { background: var(--color-warn-fg); box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-warn-fg) 14%, transparent); }
.status-dot-down { background: var(--color-danger-fg); box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-danger-fg) 14%, transparent); }
.status-dot-idle { background: var(--color-border-off); }

/* --- Cards ----------------------------------------------------- */
/* The base container for every section of a settings page: header, body and footer each pad
   themselves, and the body spaces its children 20px apart. */

.card {
  --bs-card-spacer-y: var(--space-5);
  --bs-card-spacer-x: var(--space-5);
  --bs-card-title-spacer-y: 0;
  --bs-card-border-color: var(--color-border);
  --bs-card-border-radius: var(--radius-xl);
  --bs-card-inner-border-radius: calc(var(--radius-xl) - 1px);
  --bs-card-cap-padding-y: var(--space-4);
  --bs-card-cap-padding-x: var(--space-5);
  --bs-card-cap-bg: transparent;
  --bs-card-bg: var(--color-surface-subtle);
  --bs-card-color: var(--color-fg);
}
.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding-top: 0.9375rem;
  border-bottom-color: var(--color-border);
}
.card-header .nav-tabs { margin-bottom: calc(-1 * var(--bs-card-cap-padding-y) - 1px); border-bottom: 0; }
.card-title { margin: 0; font-size: 0.9375rem; font-weight: 600; line-height: 1.5; color: var(--color-fg); }
.card-subtitle { margin: 0; font-size: 0.8125rem; color: var(--color-fg-muted); }
.card-text:last-child { margin-bottom: 0; }
.card-body { display: flex; flex-direction: column; gap: var(--space-5); }
.card-footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  padding-block: var(--space-3);
  border-top-color: var(--color-border);
}
/* A body that runs edge to edge (a table, an empty state): it drops its padding, and under another body it
   closes the card with a rule. A table inside keeps the card's padding in its first and last cells. */
.card-body-flush { padding: 0; gap: 0; overflow-x: auto; }
/* an open picker or menu inside reaches past the body instead of scrolling inside it */
.card-body-flush:has(.ts-wrapper.dropdown-active, details.dropdown[open]) { overflow-x: visible; }
.card-body-flush:last-child { border-radius: 0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius); }
.card-body + .card-body-flush { border-top: 1px solid var(--color-border); }
.card-body-flush .table :is(th, td):first-child { padding-left: var(--bs-card-spacer-x); }
.card-body-flush .table :is(th, td):last-child { padding-right: var(--bs-card-spacer-x); }
.card-body-flush .table th { border-top: 0; background: transparent; }
.card-body-flush .table > tbody > tr:last-child > * { border-bottom: 0; }
/* Bootstrap's one-piece card (card card-body): the card pads its content itself and lays it out as plain
   blocks; a header or footer inside reaches back out to the card's edges. */
.card.card-body { display: block; }
.card.card-body > .card-header {
  margin: calc(-1 * var(--bs-card-spacer-y)) calc(-1 * var(--bs-card-spacer-x)) var(--bs-card-spacer-y);
  border-radius: var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0;
}
.card.card-body > .card-footer {
  margin: var(--bs-card-spacer-y) calc(-1 * var(--bs-card-spacer-x)) calc(-1 * var(--bs-card-spacer-y));
  border-radius: 0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius);
}
/* The page's own surface, for a card inside a card. */
.card-plain { --bs-card-bg: var(--color-surface); }
/* A destructive card swaps the border for the danger line and the title for danger text. */
.card-danger { --bs-card-border-color: var(--color-danger-border); }
.card-danger > .card-header { border-bottom-color: color-mix(in srgb, var(--color-danger-strong) 20%, transparent); }
.card-danger .card-title { color: var(--color-danger-fg); }

/* A destructive panel on a detail page: rows of action and explanation. */
.danger {
  padding: var(--space-4) var(--space-5);
  border: 1px solid var(--color-danger-border);
  border-radius: var(--radius-xl);
  background: var(--color-surface-subtle);
}
.danger-title { font-weight: 600; color: var(--color-danger-fg); margin: 0 0 var(--space-2); }
.danger-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-2) 0; }
.danger-row + .danger-row { border-top: 1px solid color-mix(in srgb, var(--color-danger-strong) 20%, transparent); }
.danger-desc { font-size: var(--text-sm); color: var(--color-fg-muted); }

/* --- List group, progress, spinner ------------------------------- */

.list-group {
  --bs-list-group-color: var(--color-fg);
  --bs-list-group-bg: var(--color-surface);
  --bs-list-group-border-color: var(--color-border);
  --bs-list-group-border-radius: var(--radius-lg);
  --bs-list-group-item-padding-x: var(--space-4);
  --bs-list-group-item-padding-y: var(--space-3);
  --bs-list-group-action-color: var(--color-fg);
  --bs-list-group-action-hover-color: var(--color-fg);
  --bs-list-group-action-hover-bg: var(--color-row-hover);
  --bs-list-group-action-active-color: var(--color-fg);
  --bs-list-group-action-active-bg: var(--color-surface-hover);
  --bs-list-group-disabled-color: var(--color-fg-disabled);
  --bs-list-group-disabled-bg: var(--color-surface);
  --bs-list-group-active-color: var(--color-fg-strong);
  --bs-list-group-active-bg: var(--color-accent-soft);
  --bs-list-group-active-border-color: var(--color-border);
  font-size: var(--text-sm);
}
.list-group-item:not(.list-group-item-action) {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.list-group-item.active { z-index: auto; }

/* A 6px rounded track; the fill is green, amber near the limit, red when full. */
.progress,
.progress-stacked {
  --bs-progress-height: 6px;
  --bs-progress-font-size: var(--text-xs);
  --bs-progress-bg: var(--color-border);
  --bs-progress-border-radius: 3px;
  --bs-progress-bar-color: var(--color-on-accent);
  --bs-progress-bar-bg: var(--color-accent);
  --bs-progress-bar-transition: width 0.3s ease;
}
.progress-bar { border-radius: 3px; }
.progress-bar.bg-warning { background-color: var(--color-warn-strong) !important; }
.progress-bar.bg-danger { background-color: var(--color-danger-strong) !important; }
.progress-row { display: flex; flex-direction: column; gap: var(--space-2); }
.progress-row-head { display: flex; justify-content: space-between; gap: var(--space-3); font-size: 0.8125rem; line-height: 1.5; color: var(--color-fg); }
.progress-row-value { font: 400 var(--text-xs)/1.5 var(--font-mono); color: var(--color-fg-muted); }

/* A 14px ring with an accent arc. */
.spinner-border {
  --bs-spinner-width: 0.875rem;
  --bs-spinner-height: 0.875rem;
  --bs-spinner-border-width: 2px;
  --bs-spinner-animation-speed: 0.6s;
  color: var(--color-border);
  border-top-color: var(--color-accent);
  border-right-color: var(--color-border);
}
.spinner-border-sm { --bs-spinner-width: 0.875rem; --bs-spinner-height: 0.875rem; --bs-spinner-border-width: 2px; }
/* Tom Select's loading indicator carries .spinner */
.spinner {
  display: inline-block;
  width: 0.875rem;
  height: 0.875rem;
  border: 2px solid var(--color-border);
  border-top-color: var(--color-accent);
  border-radius: var(--radius-full);
  animation: spin 0.6s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* --- Dropdowns ------------------------------------------------- */
/* A raised panel of 36px items, 6px below its trigger. Destructive items sit last, after a divider,
   and tint red only under the pointer; an ellipsis means a confirmation follows. Opened by
   components.js (data-bs-toggle="dropdown"), or written as <details class="dropdown"> with a
   <summary> trigger, which opens without a script. */

.dropdown,
.dropup,
.dropstart,
.dropend { position: relative; }
details.dropdown { display: inline-block; }
details.dropdown > summary { list-style: none; }
details.dropdown > summary::-webkit-details-marker { display: none; }

.dropdown-menu {
  --bs-dropdown-zindex: 1000;
  --bs-dropdown-min-width: 13.75rem;
  --bs-dropdown-padding-x: 6px;
  --bs-dropdown-padding-y: 6px;
  --bs-dropdown-spacer: 6px;
  --bs-dropdown-font-size: 0.8125rem;
  --bs-dropdown-color: var(--color-fg);
  --bs-dropdown-bg: var(--color-surface-raised);
  --bs-dropdown-border-color: var(--color-control-border);
  --bs-dropdown-border-radius: 0.625rem;
  --bs-dropdown-inner-border-radius: var(--radius-md);
  --bs-dropdown-divider-bg: var(--color-border);
  --bs-dropdown-divider-margin-y: 4px;
  --bs-dropdown-box-shadow: var(--shadow-menu);
  --bs-dropdown-link-color: var(--color-fg);
  --bs-dropdown-link-hover-color: var(--color-fg);
  --bs-dropdown-link-hover-bg: var(--color-surface-hover);
  --bs-dropdown-link-active-color: var(--color-fg);
  --bs-dropdown-link-active-bg: color-mix(in srgb, var(--color-accent) 8%, transparent);
  --bs-dropdown-link-disabled-color: var(--color-fg-disabled);
  --bs-dropdown-item-padding-x: 10px;
  --bs-dropdown-item-padding-y: 0;
  --bs-dropdown-header-color: var(--color-fg-subtle);
  --bs-dropdown-header-padding-x: 10px;
  --bs-dropdown-header-padding-y: 7px;
  top: 100%;
  left: 0;
  margin-top: var(--bs-dropdown-spacer);
  flex-direction: column;
  gap: 2px;
  box-shadow: var(--bs-dropdown-box-shadow);
  text-align: left;
}
.dropdown-menu.show,
details.dropdown[open] > .dropdown-menu { display: flex; }
.dropdown-menu-end,
.dropdown-menu[data-bs-popper].dropdown-menu-end { right: 0; left: auto; }
.dropup .dropdown-menu { top: auto; bottom: 100%; margin: 0 0 var(--bs-dropdown-spacer); }
/* a menu shown in place, as in the catalogue */
.dropdown-menu.position-static { display: flex; margin: 0; }

.dropdown-item {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 2.25rem;
  font-family: var(--font-sans);
  text-decoration: none;
  border-radius: var(--radius-md);
  cursor: pointer;
}
.dropdown-item .icon { color: var(--color-fg-muted); }
.dropdown-item:focus-visible { outline: 2px solid var(--color-accent); outline-offset: -2px; }
.dropdown-item:is(:disabled, .disabled, [aria-disabled="true"]) { background: none; cursor: not-allowed; }
.dropdown-item:is(:disabled, .disabled, [aria-disabled="true"]) .icon { color: var(--color-fg-disabled); }
.dropdown-item-danger,
.dropdown-item-danger .icon { color: var(--color-danger-fg); }
.dropdown-item-danger:hover,
.dropdown-item-danger:focus { color: var(--color-danger-fg); background: var(--color-danger-bg); }
/* the current pick in a switcher: the chosen-option fill and a check */
.dropdown-item:is(.active, [aria-current="true"]) { color: var(--color-fg); background: color-mix(in srgb, var(--color-accent) 8%, transparent); }
.dropdown-item:is(.active, [aria-current="true"]) .icon { color: var(--color-accent); }
.dropdown-item-text { padding: var(--space-2) 10px; font-size: 0.8125rem; color: var(--color-fg-muted); }
.dropdown-header {
  font: 500 0.6875rem/1.4 var(--font-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding-bottom: 4px;
}
.dropdown-divider { margin: 4px 0; opacity: 1; }
.dropdown-shortcut { margin-left: auto; padding-left: var(--space-4); font: 400 0.6875rem/1 var(--font-mono); color: var(--color-fg-subtle); }
.dropdown-meta { margin-left: auto; }
.dropdown-toggle::after {
  width: 12px;
  height: 12px;
  margin-left: 0;
  vertical-align: middle;
  border: 0;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%23000' stroke-width='1.2' stroke-linecap='round' stroke-linejoin='round' d='m3 4.5 3 3 3-3'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%23000' stroke-width='1.2' stroke-linecap='round' stroke-linejoin='round' d='m3 4.5 3 3 3-3'/%3E%3C/svg%3E") center / contain no-repeat;
}
/* a square ⋯ or icon trigger has no caret */
.dropdown-toggle:is(.btn-square, .btn-icon)::after { display: none; }
.dropdown.show > .btn-square,
details.dropdown[open] > .btn-square { background: var(--color-surface-hover); border-color: var(--color-border-strong); }
.dropdown.show > .btn-icon,
details.dropdown[open] > .btn-icon { color: var(--color-fg); background: var(--color-fill-quiet); }

/* --- Modal ----------------------------------------------------- */
/* A raised, rounded sheet over a dimmed page. Bootstrap's markup (.modal > .modal-dialog >
   .modal-content) opens through components.js; a native <dialog class="modal"> opens with
   showModal() and carries its header, body and footer directly. */

.modal {
  --bs-modal-width: 28rem;
  --bs-modal-padding: var(--space-6);
  --bs-modal-margin: var(--space-6);
  --bs-modal-color: var(--color-fg);
  --bs-modal-bg: var(--color-surface);
  --bs-modal-border-color: var(--color-border);
  --bs-modal-border-radius: var(--radius-xl);
  --bs-modal-inner-border-radius: calc(var(--radius-xl) - 1px);
  --bs-modal-box-shadow: var(--shadow-menu);
  --bs-modal-header-padding: var(--space-6) var(--space-6) 0;
  --bs-modal-header-border-width: 0;
  --bs-modal-footer-border-width: 0;
  --bs-modal-footer-gap: var(--space-2);
  --bs-modal-title-line-height: 1.5;
}
.modal-content { box-shadow: var(--bs-modal-box-shadow); }
.modal-header { align-items: flex-start; gap: var(--space-3); }
.modal-header .btn-close { margin: 0 0 0 auto; padding: 0; }
/* A close button that holds a text × instead of the icon is as large as the glyph, in mono. */
.btn-close:not(:empty):not(:has(*)) {
  width: auto;
  height: auto;
  padding: 1px 6px;
  font-family: var(--font-mono);
  font-size: var(--text-lg);
  line-height: 1;
}
.modal-title { margin: 0; font-size: var(--text-lg); font-weight: 600; }
.modal-body { font-size: var(--text-sm); color: var(--color-fg-muted); line-height: 1.6; }
.modal-footer { padding-top: 0; justify-content: flex-end; gap: var(--space-2); }
.modal-footer > * { margin: 0; }
.modal-backdrop { --bs-backdrop-bg: rgb(10 11 13); --bs-backdrop-opacity: 0.55; }

/* A native <dialog class="modal">: as wide as its content up to 28rem. :where() keeps these at class weight,
   so an app's own dialog class (a wider sheet, a flex column) wins. */
.modal:where(dialog) {
  position: fixed;
  inset: 0;
  max-width: min(var(--bs-modal-width), calc(100% - 2 * var(--space-4)));
  height: fit-content;
  max-height: calc(100% - 2 * var(--space-4));
  margin: auto;
  padding: var(--bs-modal-padding);
  overflow: auto;
  color: var(--bs-modal-color);
  background: var(--bs-modal-bg);
  border: 1px solid var(--bs-modal-border-color);
  border-radius: var(--bs-modal-border-radius);
  box-shadow: var(--bs-modal-box-shadow);
}
.modal:where(dialog[open]) { display: block; }
.modal:where(dialog)::backdrop { background: rgb(10 11 13 / 0.55); }
.modal:where(dialog) > .modal-header { padding: 0; margin-bottom: var(--space-3); }
.modal:where(dialog) > .modal-body { padding: 0; margin-bottom: var(--space-4); }
.modal:where(dialog) > .modal-footer { display: flex; padding: 0; }
/* The catalogue shows a sheet in place, on a framed patch of page. */
.modal-showcase {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-10);
  background: var(--color-surface-subtle);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
}
.modal-showcase > dialog.modal { position: static; display: block; margin: 0; }

/* --- Toasts ---------------------------------------------------- */
/* A toast floats bottom right, so it is a raised sheet with the menu shadow. */

.toast {
  --bs-toast-max-width: 22rem;
  --bs-toast-padding-x: 0.875rem;
  --bs-toast-padding-y: var(--space-3);
  --bs-toast-font-size: 0.8125rem;
  --bs-toast-color: var(--color-fg);
  --bs-toast-bg: var(--color-surface-raised);
  --bs-toast-border-color: var(--color-control-border);
  --bs-toast-border-radius: 0.625rem;
  --bs-toast-box-shadow: var(--shadow-menu);
  --bs-toast-header-color: var(--color-fg);
  --bs-toast-header-bg: transparent;
  --bs-toast-header-border-color: var(--color-border);
  width: auto;
}
.toast.show { display: flex; align-items: flex-start; gap: var(--space-3); padding: var(--bs-toast-padding-y) var(--bs-toast-padding-x); }
.toast-container { --bs-toast-zindex: 1090; display: flex; flex-direction: column; gap: var(--space-2); pointer-events: none; }
.toast-container > .toast { pointer-events: auto; }
.toast-title { margin: 0 0 2px; font-size: 0.8125rem; font-weight: 500; line-height: 1.5; }
.toast-body { margin: 0; padding: 0; font-size: var(--text-xs); color: var(--color-fg-muted); }
.toast-icon { flex: none; width: 18px; height: 18px; color: var(--color-accent); }
/* a one-line toast with an action (Undo) centres its row */
.toast:has(> .toast-action) { align-items: center; }
.toast-action { margin-left: auto; padding-left: var(--space-3); font: 500 0.8125rem/1.5 var(--font-sans); color: var(--color-fg); text-decoration: underline; background: none; border: 0; cursor: pointer; }
/* The error alert's frame over the raised sheet. */
.toast-danger {
  border-color: var(--color-danger-border);
  background: linear-gradient(var(--color-danger-bg), var(--color-danger-bg)) var(--color-surface-raised);
}
.toast-danger .toast-title { color: var(--color-danger-fg); }
.toast-danger .toast-icon { color: var(--color-danger-fg); }

/* --- Accordion ------------------------------------------------- */
/* Bootstrap's markup with a button and a .collapse, or <details class="accordion-item"> with a
   <summary class="accordion-button">; either way a + turns into a − when open. */

.accordion {
  --bs-accordion-color: var(--color-fg);
  --bs-accordion-bg: var(--color-surface);
  --bs-accordion-border-color: var(--color-border);
  --bs-accordion-border-radius: var(--radius-lg);
  --bs-accordion-inner-border-radius: calc(var(--radius-lg) - 1px);
  --bs-accordion-btn-padding-x: var(--space-4);
  --bs-accordion-btn-padding-y: var(--space-3);
  --bs-accordion-btn-color: var(--color-fg);
  --bs-accordion-btn-bg: transparent;
  --bs-accordion-btn-focus-box-shadow: none;
  --bs-accordion-body-padding-x: var(--space-4);
  --bs-accordion-body-padding-y: var(--space-4);
  --bs-accordion-active-color: var(--color-fg);
  --bs-accordion-active-bg: transparent;
}
.accordion-button {
  font-size: var(--text-sm);
  font-weight: 500;
  font-family: inherit;
  list-style: none;
  cursor: pointer;
}
.accordion-button::-webkit-details-marker { display: none; }
.accordion-button:not(.collapsed) { box-shadow: none; }
.accordion-button:focus-visible { outline: 2px solid var(--color-accent); outline-offset: -2px; }
.accordion-button::after,
.accordion-button:not(.collapsed)::after {
  content: "−";
  width: auto;
  height: auto;
  margin-left: auto;
  font-family: var(--font-mono);
  color: var(--color-fg-muted);
  background: none;
  transform: none;
}
.accordion-button.collapsed::after,
details.accordion-item:not([open]) > .accordion-button::after { content: "+"; }
.accordion-body { padding-top: 0; font-size: var(--text-sm); color: var(--color-fg-muted); line-height: 1.6; }
details.accordion-item > .accordion-button { display: flex; }

/* --- Page, wordmark and login ------------------------------------ */

.page {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: var(--space-8) var(--space-6);
}

.page-subtle { background: var(--color-surface-subtle); }

.wordmark {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-weight: 600;
  font-size: var(--text-lg);
  letter-spacing: -0.01em;
  color: var(--color-fg);
  text-decoration: none;
}

.wordmark-dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: var(--radius-full);
  background: var(--color-accent);
}

.wordmark-lg { font-size: var(--text-2xl); }
.wordmark-lg .wordmark-dot {
  width: 0.625rem;
  height: 0.625rem;
}

.wordmark-icon,
.wordmark-initials {
  width: 1.5rem;
  height: 1.5rem;
  border-radius: var(--radius-md);
  object-fit: contain;
}

.wordmark-initials {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--color-accent);
  color: var(--color-on-accent);
  font-size: var(--text-xs);
  font-weight: 600;
}

.wordmark-lg .wordmark-icon,
.wordmark-lg .wordmark-initials { width: 2rem; height: 2rem; }

/* One icon per theme; only the active theme's shows. */
.brand-only-dark { display: none; }
[data-bs-theme="dark"] .brand-only-dark { display: inline-flex; }
[data-bs-theme="dark"] .brand-only-light { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-bs-theme]) .brand-only-dark { display: inline-flex; }
  :root:not([data-bs-theme]) .brand-only-light { display: none; }
}

.login {
  width: 100%;
  max-width: 22rem;
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

.login-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-6);
  text-align: center;
}

.login-title {
  font-size: var(--text-2xl);
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0;
}

.login-subtitle {
  margin: var(--space-1) 0 0;
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
}

/* --- Links under forms ------------------------------------------- */

.muted-link {
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
  text-decoration: none;
}

.muted-link:hover {
  color: var(--color-fg);
  text-decoration: underline;
}


.footer-links {
  display: flex;
  justify-content: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
}

.footer-links a {
  color: var(--color-fg-muted);
  text-decoration: none;
}

.footer-links a:hover {
  color: var(--color-fg);
  text-decoration: underline;
}

.login-minimal .form { gap: var(--space-5); }

/* --- Auth split -------------------------------------------------- */

.auth-split {
  min-height: 100vh;
  display: grid;
  grid-template-columns: 1fr;
}

.auth-split-brand {
  display: none;
  position: relative;
  overflow: hidden;
  isolation: isolate;
  border-right: 1px solid var(--color-border);
}

.auth-split-brand-inner {
  position: relative;
  z-index: 5;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-8);
  padding: var(--space-12);
  height: 100%;
  width: 100%;
}

.auth-split-quote {
  margin: 0;
  max-width: 32rem;
  font-size: var(--text-2xl);
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.3;
  color: var(--color-fg);
}

.auth-split-quote p { margin: 0 0 var(--space-4); }

.auth-split-quote-cite {
  display: block;
  margin-top: var(--space-4);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 400;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--color-fg-subtle);
}

.auth-split-meta {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--color-fg-subtle);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.auth-split-form {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-10) var(--space-6);
  background: var(--color-surface);
}

@media (min-width: 768px) {
  .auth-split { grid-template-columns: 1fr 1fr; }
  .auth-split-brand { display: block; }
}

/* --- Inspiring backgrounds (aurora / lattice / mix) -------------- */

.bg-aurora,
.bg-lattice,
.bg-mix { background: var(--color-surface); }

.bg-aurora-blob {
  position: absolute;
  width: 90%;
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  translate: -50% -50%;
  filter: blur(var(--a-blur, 38px));
  will-change: transform;
  mix-blend-mode: multiply;
  pointer-events: none;
}

.bg-aurora-blob-1 {
  background: radial-gradient(circle, var(--a-c1, transparent), transparent 60%);
  top: var(--a-y1, 30%); left: var(--a-x1, 30%);
  animation: var(--a-name1, bg-blob-a) var(--a-d1, 28s) ease-in-out infinite;
  animation-delay: var(--a-delay1, 0s);
}

.bg-aurora-blob-2 {
  background: radial-gradient(circle, var(--a-c2, transparent), transparent 60%);
  top: var(--a-y2, 50%); left: var(--a-x2, 70%);
  animation: var(--a-name2, bg-blob-b) var(--a-d2, 32s) ease-in-out infinite;
  animation-delay: var(--a-delay2, 0s);
}

.bg-aurora-blob-3 {
  background: radial-gradient(circle, var(--a-c3, transparent), transparent 60%);
  top: var(--a-y3, 70%); left: var(--a-x3, 50%);
  animation: var(--a-name3, bg-blob-c) var(--a-d3, 36s) ease-in-out infinite;
  animation-delay: var(--a-delay3, 0s);
}

@keyframes bg-blob-a {
  0%   { transform: translate(0%, 0%) scale(1); }
  25%  { transform: translate(28%, 14%) scale(1.08); }
  50%  { transform: translate(8%, 32%) scale(0.95); }
  75%  { transform: translate(-22%, 18%) scale(1.05); }
  100% { transform: translate(0%, 0%) scale(1); }
}
@keyframes bg-blob-b {
  0%   { transform: translate(0%, 0%) scale(1); }
  25%  { transform: translate(-20%, 22%) scale(0.92); }
  50%  { transform: translate(-32%, -14%) scale(1.1); }
  75%  { transform: translate(12%, -18%) scale(1); }
  100% { transform: translate(0%, 0%) scale(1); }
}
@keyframes bg-blob-c {
  0%   { transform: translate(0%, 0%) scale(1); }
  25%  { transform: translate(18%, -24%) scale(1.05); }
  50%  { transform: translate(34%, 4%) scale(0.92); }
  75%  { transform: translate(14%, 26%) scale(1.08); }
  100% { transform: translate(0%, 0%) scale(1); }
}
@keyframes bg-blob-d {
  0%   { transform: translate(0%, 0%) scale(1); }
  25%  { transform: translate(-26%, -8%) scale(1.1); }
  50%  { transform: translate(-12%, 28%) scale(0.95); }
  75%  { transform: translate(20%, 14%) scale(1.04); }
  100% { transform: translate(0%, 0%) scale(1); }
}

.bg-lattice::before, .bg-lattice::after {
  content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
}
.bg-lattice::before {
  background-image:
    radial-gradient(circle, var(--l-color1) var(--l-size1), transparent calc(var(--l-size1) + 0.6px));
  background-size: var(--l-gap1) var(--l-gap1);
  animation: bg-lattice-pan-far var(--l-speed1, 80s) linear infinite;
}
.bg-lattice::after {
  background-image:
    radial-gradient(circle, var(--l-color2) var(--l-size2), transparent calc(var(--l-size2) + 0.6px));
  background-size: var(--l-gap2) var(--l-gap2);
  animation: bg-lattice-pan-near var(--l-speed2, 40s) linear infinite;
}

@keyframes bg-lattice-pan-far {
  from { background-position: 0 0; }
  to   { background-position: calc(var(--l-gap1) * var(--l-dx)) calc(var(--l-gap1) * var(--l-dy)); }
}
@keyframes bg-lattice-pan-near {
  from { background-position: 0 0; }
  to   { background-position: calc(var(--l-gap2) * var(--l-dx)) calc(var(--l-gap2) * var(--l-dy)); }
}

/* Mix — aurora blobs underneath a parallax lattice */
.bg-mix .bg-aurora-blob { z-index: 0; }
.bg-mix::before, .bg-mix::after {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
}
.bg-mix::before {
  background-image:
    radial-gradient(circle, var(--l-color1) var(--l-size1), transparent calc(var(--l-size1) + 0.6px));
  background-size: var(--l-gap1) var(--l-gap1);
  animation: bg-lattice-pan-far var(--l-speed1, 80s) linear infinite;
}
.bg-mix::after {
  background-image:
    radial-gradient(circle, var(--l-color2) var(--l-size2), transparent calc(var(--l-size2) + 0.6px));
  background-size: var(--l-gap2) var(--l-gap2);
  animation: bg-lattice-pan-near var(--l-speed2, 40s) linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .bg-aurora-blob,
  .bg-lattice::before,
  .bg-lattice::after,
  .bg-mix::before,
  .bg-mix::after { animation: none; }
}

/* --- Layout ------------------------------------------------------ */

.shell {
  width: 100%;
  max-width: 64rem;
  margin: 0 auto;
  padding: var(--space-10) var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
}

.shell-hero {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding-bottom: var(--space-6);
  border-bottom: 1px solid var(--color-border);
}

.shell-eyebrow {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-fg-subtle);
}

.shell-title {
  font-size: var(--text-3xl);
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0;
}

.shell-lede {
  font-size: var(--text-lg);
  color: var(--color-fg-muted);
  margin: 0;
  max-width: 44rem;
}

.section {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

.section-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  padding-bottom: var(--space-2);
  border-bottom: 1px dashed var(--color-border);
}

.section-title {
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.3;
  margin: 0;
}

.section-meta {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  color: var(--color-fg-subtle);
}


.fingerprint {
  display: inline-block;
  max-width: 14ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.grid-2 {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-6);
}
/* Grid items may shrink below their content (long select options), so a column never widens the page. */
.grid-2 > *, .grid-3 > * { min-width: 0; }

@media (min-width: 720px) {
  .grid-2 { grid-template-columns: 1fr 1fr; }
}

.grid-3 {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-6);
}

@media (min-width: 720px) {
  .grid-3 { grid-template-columns: 1fr 1fr 1fr; }
}

/* --- Colour swatches --------------------------------------------- */

.swatches {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
  gap: var(--space-3);
}

.swatch {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--color-fg-muted);
}

.swatch-chip {
  height: 3.5rem;
  border: 1px solid var(--color-border);
}

.swatch-label { color: var(--color-fg); }

/* --- Profile shell (side-nav layout) ----------------------------- */

/* Laid out like the admin shell: edge to edge, the nav a rail with a divider, the same gutters. */
.shell:has(> .profile-shell) { max-width: none; padding: 0; gap: 0; }
.shell:has(> .profile-shell) > .shell-footer { padding: var(--space-4) var(--space-10); }

.profile-shell {
  display: grid;
  grid-template-columns: 1fr;
  width: 100%;
  min-height: 38rem;
}

.profile-shell-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-divider);
}

@media (min-width: 720px) {
  .profile-shell { grid-template-columns: 16.5rem 1fr; }
  .profile-shell-nav {
    flex-direction: column;
    flex-wrap: nowrap;
    padding: var(--space-6) var(--space-4);
    border-bottom: 0;
    border-right: 1px solid var(--color-divider);
  }
}

.profile-nav-link {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 2.5rem;
  padding: 0 var(--space-3);
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--color-fg-secondary);
  text-decoration: none;
  border-radius: var(--radius-lg);
}
.profile-nav-link:focus-visible { outline: 2px solid var(--color-accent); outline-offset: -2px; }

.profile-nav-link:hover {
  color: var(--color-fg);
  background: var(--color-nav-active);
}

.profile-nav-link[aria-current="page"] {
  color: var(--color-fg-strong);
  background: var(--color-accent-soft);
}

.profile-shell-content {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  min-width: 0;
  padding: var(--space-4);
}
@media (min-width: 720px) {
  .profile-shell-content { padding: 1.75rem var(--space-10) var(--space-12); }
}
/* A page of forms reads as one column of at most 60rem; a page with a table keeps the full width
   for it. The fields fill their card, and its submit button sits at the card's right edge. */
.profile-shell-content:not(:has(table)) > * { width: 100%; max-width: 60rem; }
/* The profile page's cards in two halves once the screen is wide enough: account on the left,
   preferences on the right. Narrower, they stack in the 60rem column above. */
.profile-columns { display: grid; gap: var(--space-6); align-items: start; }
.profile-columns > .vstack { gap: var(--space-6); align-self: start; }
@media (min-width: 1320px) {
  .profile-shell-content:has(> .profile-columns) > * { max-width: none; }
  .profile-columns { grid-template-columns: 1fr 1fr; }
}
.profile-shell-content .form > .w-100,
.profile-shell-content .vstack > .w-100 { width: auto !important; align-self: flex-end; }

.profile-shell-header {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-border);
}

.profile-shell-title {
  font-size: var(--text-2xl);
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0;
}

.profile-shell-subtitle {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
}

/* --- Footer -------------------------------------------------- */

.shell-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-divider);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--color-fg-subtle);
}

/* --- Avatars and app tiles --------------------------------------- */

/* Initials on the accent-tinted avatar colour; 24, 32 (default), 40 and 56. */
.avatar {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: var(--radius-full);
  background: var(--avatar-bg, var(--color-avatar));
  color: var(--color-on-avatar-default);
  font-weight: 600;
  font-size: var(--text-xs);
  line-height: 1;
}
/* Palette avatars set --avatar-bg inline to a saturated color; keep their letter light. */
.avatar[style*="--avatar-bg"] { color: var(--color-on-avatar); }
.avatar-sm { width: 1.5rem; height: 1.5rem; font-size: 0.625rem; }
.avatar-lg { width: 2.5rem; height: 2.5rem; font-size: var(--text-sm); }
.avatar-xl { width: 3.5rem; height: 3.5rem; font-size: var(--text-lg); }
/* Overlapping avatars, each ringed in the page colour. */
.avatar-stack { display: inline-flex; }
.avatar-stack > .avatar { box-shadow: 0 0 0 2px var(--color-surface); }
.avatar-stack > .avatar + .avatar { margin-left: -8px; }

/* An application's tile: its initial in the accent on a neutral square; 32 and 48. */
.app-icon {
  display: inline-grid;
  flex: none;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border: 1px solid var(--color-control-border);
  border-radius: 0.625rem;
  background: var(--avatar-neutral-bg);
  color: var(--color-accent);
  font-size: 0.8125rem;
  font-weight: 600;
}
.app-icon-lg { width: 3rem; height: 3rem; border-radius: var(--radius-xl); font-size: var(--text-xl); }

/* --- Account menu ------------------------------------------------ */

.account-menu { position: relative; }
.account-menu-trigger { list-style: none; cursor: pointer; }
.account-menu-trigger::-webkit-details-marker { display: none; }

/* The menu follows the dropdown look: a raised, rounded sheet with inset rows. */
.account-menu-panel {
  position: absolute;
  top: calc(100% + var(--space-2));
  right: 0;
  width: 18rem;
  padding: 6px;
  background: var(--color-surface-raised);
  border: 1px solid var(--color-control-border);
  border-radius: 10px;
  box-shadow: var(--shadow-menu);
  z-index: 50;
}

.account-menu-section { display: flex; flex-direction: column; gap: 2px; }
.account-menu-section + .account-menu-section { margin-top: 4px; padding-top: 4px; border-top: 1px solid var(--color-border); }

.account-menu-identity {
  flex-direction: row;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) 10px;
}
.account-menu-email { font-size: var(--text-sm); color: var(--color-fg); word-break: break-all; }

.account-menu-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 2.25rem;
  padding: var(--space-2) 10px;
  border-radius: var(--radius-md);
  font-size: 0.8125rem;
  color: var(--color-fg);
  text-decoration: none;
  background: transparent;
  border: 0;
  font-family: inherit;
  cursor: pointer;
  text-align: left;
  width: 100%;
}
.account-menu-item svg { flex: none; width: 1rem; height: 1rem; color: var(--color-fg-muted); }
.account-menu-item:hover { background: var(--color-surface-hover); }
.account-menu-item-muted { color: var(--color-fg-muted); }
/* Destructive items sit last; their red tint shows only under the pointer. */
.account-menu-item-danger,
.account-menu-item-danger svg { color: var(--color-danger-fg); }
.account-menu-item-danger:hover { background: var(--color-danger-bg); }
/* a bare gear in the header's own text colour, for headers without an avatar */
.account-menu-trigger-icon { box-sizing: border-box; display: inline-grid; place-items: center; width: 2rem; height: 2rem; color: inherit; opacity: 0.7; transition: opacity 120ms; }
.account-menu-trigger-icon svg { width: 1.125rem; height: 1.125rem; }
.account-menu-trigger-icon:hover, .account-menu[open] .account-menu-trigger-icon { opacity: 1; }
.account-menu-trigger-icon:focus-visible { opacity: 1; outline: 2px solid var(--color-accent); outline-offset: 1px; }
/* a line under the email (the role, or why there is no session) */
.account-menu-note { font-size: var(--text-xs); color: var(--color-fg-muted); }
.account-menu-theme { gap: var(--space-2); padding: var(--space-3) var(--space-4); }
.account-menu-label { font: 500 var(--text-xs)/1 var(--font-mono); color: var(--color-fg-subtle); letter-spacing: 0.06em; text-transform: uppercase; }

/* --- Admin shell ------------------------------------------------- */

/* Admin pages are app chrome: header, side nav and footer run edge to edge, no outer frame. */
.shell:has(> .admin) { max-width: none; padding: 0; gap: 0; }
.shell:has(> .admin) > .shell-footer { padding: var(--space-4) var(--space-10); }

.admin {
  display: grid;
  grid-template-columns: 16.5rem 1fr;
  gap: 0;
  background: var(--color-surface);
  min-height: 38rem;
}
.admin-nav {
  border-right: 1px solid var(--color-divider);
  padding: var(--space-6) var(--space-4);
  display: flex;
  flex-direction: column;
  gap: 0;
}
.admin-nav-section {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-fg-subtle);
  padding: 7px var(--space-3) 6px;
}
.admin-nav-section:not(:first-child) { margin-top: var(--space-6); }
/* 40px items with a 16px outline icon 12px from the label. The current page gets a green wash and a
   green icon; nothing else is coloured. */
.admin-nav-link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  min-height: 2.5rem;
  padding: 0 var(--space-3);
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--color-fg-secondary);
  text-decoration: none;
  border-radius: var(--radius-lg);
}
.admin-nav-link .icon { color: var(--color-fg-muted); }
.admin-nav-link:hover {
  color: var(--color-fg);
  background: var(--color-nav-active);
}
.admin-nav-link:hover .icon { color: var(--color-fg); }
.admin-nav-link:focus-visible { outline: 2px solid var(--color-accent); outline-offset: -2px; }
.admin-nav-link[aria-current="page"],
.admin-nav-link.is-active {
  color: var(--color-fg-strong);
  background: var(--color-accent-soft);
}
.admin-nav-link[aria-disabled="true"] { color: var(--color-fg-disabled); pointer-events: none; }
.admin-nav-link[aria-disabled="true"] .icon { color: inherit; }
.admin-nav-label { flex: 1 1 auto; min-width: 0; }
.admin-nav-link.is-active .icon,
.admin-nav-link[aria-current="page"] .icon { color: var(--color-accent); }
.admin-nav-count {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 500;
  color: var(--color-fg-subtle);
}
.admin-nav-sep {
  height: 1px;
  background: var(--color-border);
  margin: var(--space-2);
}
.admin-main {
  padding: 1.75rem var(--space-10) var(--space-12);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  min-width: 0;
}
.admin-main-detail { max-width: none; }
.admin-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.admin-header h1 { margin: 0; font-size: 1.375rem; line-height: 1.2; letter-spacing: -0.015em; }

/* --- Segmented control (one-of filter, radio-backed) ------------- */

/* Two to four short options that switch a view or a filter, not a stored setting; the radio drives a
   GET form. The chosen segment is a raised tile in the inset frame. */
.segmented {
  display: inline-flex;
  gap: 2px;
  height: 2.5rem;
  padding: 3px;
  border: 1px solid var(--color-border);
  border-radius: 0.625rem;
  background: var(--color-surface-sunken);
}
.segmented-item {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 var(--space-3);
  font: 500 0.8125rem/1 var(--font-sans);
  color: var(--color-fg-muted);
  background: none;
  border: 0;
  border-radius: 7px;
  cursor: pointer;
  transition: color 120ms, background 120ms;
}
.segmented-item input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.segmented-item:hover { color: var(--color-fg); background: var(--color-fill-quiet); }
.segmented-item:has(input:checked),
.segmented-item[aria-pressed="true"],
.segmented-item[aria-selected="true"] {
  color: var(--color-fg);
  background: light-dark(var(--color-surface-raised), var(--color-border));
  box-shadow: var(--shadow-segment);
}
.segmented-item:has(input:focus-visible),
.segmented-item:focus-visible { outline: 2px solid var(--color-accent); outline-offset: -1px; }
.segmented-item:has(input:disabled),
.segmented-item:disabled { color: var(--color-fg-disabled); background: none; cursor: not-allowed; }
/* Compact (menus) and stretched (segments share the full width) variants. */
.segmented-sm { height: 2rem; padding: 2px; border-radius: var(--radius-lg); }
.segmented-sm .segmented-item { padding: 0 var(--space-2); font-size: var(--text-xs); border-radius: var(--radius-md); }
.segmented-count { margin-left: var(--space-1); font-weight: 400; }
/* An optional leading icon, e.g. the theme switch. */
.segmented-item svg { flex-shrink: 0; width: 0.875rem; height: 0.875rem; margin-right: var(--space-1); }
.segmented-block { display: flex; }
.segmented-block .segmented-item { flex: 1; }

/* --- Actions row and chevron link -------------------------------- */

/* confirming buttons sit at the right edge of their form */
.actions { display: flex; justify-content: flex-end; gap: var(--space-2); }
/* Its display beats the user-agent [hidden] rule; scripts hide some action rows. */
.actions[hidden] { display: none; }
/* a long note beside the actions: it wraps, the buttons keep their size */
.actions-note { align-items: center; gap: var(--space-4); }
.actions-note > .btn { flex-shrink: 0; }
/* The primary action stays first in the markup, so Enter submits it, but is drawn last, at the right edge. */
.actions-reverse { flex-direction: row-reverse; justify-content: flex-start; }
/* a confirm field beside its button: the button lines up with the input, not the label */
.actions-field { align-items: flex-end; }
/* the field takes the row, so the button lands on the right edge */
.actions-field > :not(.btn):not(form) { flex: 1 1 auto; min-width: 0; }

/* --- Chevron link ("see all ›") ------------------------------ */
/* quiet text with a trailing chevron, brightening on hover - never underlined */
.link-chev { display: inline-flex; align-items: center; gap: var(--space-1); color: var(--color-fg-subtle); font-size: var(--text-xs); text-decoration: none; white-space: nowrap; }
.link-chev::after { content: "\203A"; font-size: var(--text-base); line-height: 1; }
.link-chev:hover, .link-chev:focus-visible { color: var(--color-fg); }

/* --- User cell, usage rings and bars ----------------------------- */

.user-cell {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}
.user-cell-meta {
  display: flex;
  flex-direction: column;
  line-height: 1.2;
}
.user-cell-email {
  font-weight: 500;
  color: var(--color-fg);
}
.user-cell-name {
  font-size: var(--text-xs);
  color: var(--color-fg-subtle);
}

/* --- Usage: rings and bars ------------------------------------ */
/* two small rings (a quota and the disk under it), the state as a quiet line underneath;
   --p on each ring is the percentage, the tone follows the state */
.usage-rings { --usage-tone: var(--color-accent); display: flex; flex-direction: column; gap: var(--space-1); }
.usage-rings-grow { --usage-tone: var(--color-warn-strong); }
.usage-rings-alert { --usage-tone: var(--color-danger-strong); }
.usage-rings-pair { display: flex; gap: var(--space-3); }
.usage-rings-item { display: inline-flex; align-items: center; gap: 6px; }
.usage-rings-ring { --ring: var(--usage-tone); flex: none; display: grid; place-items: center; width: 24px; height: 24px; border-radius: 50%; background: conic-gradient(var(--ring) calc(var(--p) * 1%), var(--color-border) 0); }
/* the second ring is context, not state: always grey */
.usage-rings-item-muted .usage-rings-ring { --ring: var(--color-fg-subtle); }
.usage-rings-ring::after { content: ""; width: 16px; height: 16px; border-radius: 50%; background: var(--color-surface); }
.usage-rings-text { display: flex; flex-direction: column; font: var(--text-xs)/1.15 var(--font-mono); color: var(--color-fg-muted); }
.usage-rings-text b { font-weight: 500; color: var(--color-fg); }
.usage-rings-state { color: var(--color-fg-muted); font-size: var(--text-xs); }
/* a labelled bar: label, track, figure */
.usage { display: grid; grid-template-columns: 7rem 1fr auto; align-items: center; gap: var(--space-2); font-size: var(--text-sm); }
.usage-track { --usage-tone: var(--color-fg-subtle); height: 6px; overflow: hidden; border-radius: 3px; background: var(--color-border); }
.usage-track i { display: block; height: 100%; border-radius: 3px; background: var(--usage-tone); }
.usage-track-ok { --usage-tone: var(--color-accent); }
.usage-track-grow { --usage-tone: var(--color-warn-strong); }
.usage-track-alert { --usage-tone: var(--color-danger-strong); }

/* --- Colour field and upload tile -------------------------------- */

/* swatch, hex and reset in one box, presets as dots beside it */
.color-field { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; min-width: 0; }
.color-field-box { display: inline-flex; align-items: stretch; height: 2.25rem; overflow: hidden; border: 1px solid var(--color-control-border); border-radius: var(--radius-lg); background: var(--color-surface); }
.color-field-box:focus-within { border-color: var(--color-accent); box-shadow: 0 0 0 3px var(--color-accent-ring); }
.color-field-box:has(.color-field-hex:invalid) { border-color: var(--color-danger-fg); }
.color-field-swatch { position: relative; width: 2.25rem; border-right: 1px solid var(--color-border); cursor: pointer; }
/* the native picker covers the swatch, invisible */
.color-field-swatch input { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; }
.color-field-hex { width: 6rem; border: 0; padding: 0 var(--space-2); background: none; color: var(--color-fg); font: var(--text-sm) var(--font-mono); }
.color-field-hex:focus { outline: none; }
.color-field-reset { width: 1.75rem; border: 0; padding: 0; background: none; color: var(--color-fg-muted); font-size: 1rem; cursor: pointer; }
.color-field-reset:hover { color: var(--color-fg); }
.color-field-presets { display: flex; flex-wrap: wrap; gap: 6px; }
.color-field-preset { width: 1.25rem; height: 1.25rem; padding: 0; border: 1px solid rgb(128 128 128 / 0.45); border-radius: 50%; cursor: pointer; }
.color-field-preset[aria-pressed="true"] { outline: 2px solid var(--color-accent); outline-offset: 2px; }

/* --- Upload tile ---------------------------------------------- */
/* a dashed square (the current image or +) plus Upload / Remove text; stands in for the native file control */
.upload-tile { display: flex; align-items: center; gap: var(--space-3); min-width: 0; }
.upload-tile-tile { position: relative; flex: none; width: 2.25rem; height: 2.25rem; display: grid; place-items: center; border: 1px dashed var(--color-border-strong); color: var(--color-fg-muted); font-size: 1.125rem; cursor: pointer; }
.upload-tile-tile:hover { border-color: var(--color-accent); color: var(--color-fg); }
.upload-tile-tile:focus-within { outline: 2px solid var(--color-accent); outline-offset: 1px; }
.upload-tile-tile img { width: 100%; height: 100%; object-fit: contain; }
.upload-tile-tile input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.upload-tile-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; font-size: var(--text-sm); }
.upload-tile-action { padding: 0; border: 0; background: none; color: var(--color-fg); font: inherit; font-weight: 500; cursor: pointer; }
.upload-tile-action:hover { color: var(--color-accent); }
.upload-tile-action-muted { color: var(--color-fg-muted); font-weight: 400; }

/* File variant: the whole dashed box is the label, so a click anywhere opens the picker.
   The input stays in the box (not display:none) so `required` still reports on it. */
.upload-file {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
  padding: var(--space-3) var(--space-4);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-lg);
  color: var(--color-fg-muted);
  font-size: var(--text-sm);
  cursor: pointer;
  transition: border-color 120ms;
}
.upload-file:hover { border-color: var(--color-accent); }
.upload-file:focus-within { outline: 2px solid var(--color-accent); outline-offset: 1px; }
.upload-file svg { flex: none; width: 1.25rem; height: 1.25rem; }
.upload-file input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.upload-file-action { color: var(--color-fg); font-weight: 500; }
.upload-file-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: var(--font-mono); font-size: var(--text-xs); }
.upload-file.is-picked { border-style: solid; }
.upload-file.is-picked .upload-file-name { color: var(--color-fg); }

/* --- Select with search (Tom Select) ----------------------------- */

/* searchable-select.js turns <select class="js-searchable"> into a pick list with a search box,
   like Select2, and every other single .form-select into the same panel without one. The library's
   stylesheet comes in through the @import at the top of this file; it is more specific in places
   and pads with !important itself, hence the importants below. */

/* a floor so the widget is usable */
select.js-searchable + .ts-wrapper { min-width: 18rem; }

/* Once the widget exists, the original select must go. Class-based hiding is not enough:
   a swap restores the markup's class attribute, wiping the ts-hidden-accessible class TomSelect
   added — so hide by structure, not by class. Visually hidden rather than display:none: the browser
   anchors a required field's validation message to the select, and skips one that is not rendered. */
select:has(+ .ts-wrapper) {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  margin: 0 !important;
  padding: 0 !important;
  border: 0 !important;
  opacity: 0 !important;
  pointer-events: none !important;
}
/* TomSelect copies the select's classes onto its wrapper. That is handy for the mono value
   classes, and a trap for .form-select, whose border, background, arrow and padding would paint a
   second box around the widget's own control. The bare select keeps .form-select for the pre-init render. */
.ts-wrapper.font-monospace .ts-control,
.ts-wrapper.font-monospace .ts-dropdown,
.ts-wrapper.form-control-code .ts-control,
.ts-wrapper.form-control-code .ts-dropdown {
  font-family: var(--font-mono) !important;
}
.ts-wrapper.form-control-code .ts-control { font-size: 0.8125rem; }
.ts-wrapper.form-select,
.ts-wrapper.form-control {
  min-height: 0;
  height: auto;
  padding: 0;
  border: 0;
  background: none;
  background-image: none;
  box-shadow: none;
}

/* The trigger: the text field's 44px box; focus and the open list draw the green edge and glow. */
.ts-wrapper .ts-control {
  min-height: 2.75rem;
  align-items: center;
  background: var(--color-surface) !important;
  color: var(--color-fg) !important;
  border: 1px solid var(--color-control-border) !important;
  border-radius: var(--radius-lg) !important;
  box-shadow: none !important;
  padding: var(--space-2) var(--space-3) var(--space-2) 0.875rem;
  font-size: var(--text-sm);
  transition: border-color 120ms, box-shadow 120ms;
}
.ts-wrapper:not(.disabled):not(.locked):hover .ts-control { border-color: var(--color-border-strong) !important; }
.ts-wrapper.focus .ts-control,
.ts-wrapper.dropdown-active .ts-control {
  border-color: var(--color-accent) !important;
  box-shadow: 0 0 0 3px var(--color-accent-ring) !important;
}
.ts-wrapper .ts-control input {
  color: var(--color-fg) !important;
  font-family: inherit;
  font-size: inherit;
}
.ts-wrapper .ts-control input::placeholder { color: var(--color-placeholder); }
/* Disabled (the select's own flag) or locked (inside a disabled fieldset) reads like .form-select:disabled. */
.ts-wrapper.disabled .ts-control,
.ts-wrapper.locked .ts-control {
  opacity: 1 !important;
  color: var(--color-fg-disabled) !important;
  background-color: var(--color-surface-sunken) !important;
  border-color: var(--color-divider) !important;
  cursor: not-allowed !important;
}
/* TomSelect marks the wrapper when the browser rejects the hidden select as invalid. */
.ts-wrapper.invalid .ts-control,
select:is([aria-invalid="true"], .is-invalid) + .ts-wrapper .ts-control,
.ts-wrapper:has(+ .invalid-feedback) .ts-control,
.field-error .ts-wrapper .ts-control {
  border-color: var(--color-danger-strong) !important;
  box-shadow: 0 0 0 3px var(--color-danger-ring) !important;
}

/* A plain pick list (no search box) reads as a select: pointer cursor and the same chevron.
   tom-select.css forces the control's right padding to max(--ts-pr-min, ...) !important,
   so the room for the chevron goes through that variable. */
.ts-wrapper.no-search { --ts-pr-min: 2.5rem; }
.ts-wrapper.no-search .ts-control {
  cursor: pointer;
  background-image: var(--select-chevron) !important;
  background-repeat: no-repeat !important;
  background-position: right var(--space-3) center !important;
}
.ts-wrapper.no-search .ts-control::after { display: none !important; }
/* the chevron turns up while the list is open */
.ts-wrapper.no-search.dropdown-active .ts-control { background-image: var(--select-chevron-up) !important; }
/* Size to the longest option: the control keeps its one line clear of the chevron,
   and the open list may grow past a narrow control instead of wrapping its rows. */
.ts-wrapper.no-search .ts-control { flex-wrap: nowrap; white-space: nowrap; }
.ts-wrapper.no-search .ts-dropdown { width: max-content; min-width: 100%; }
.ts-wrapper.no-search .ts-dropdown .option { white-space: nowrap; }
/* The control itself takes focus when there is no search box (TomSelect focuses it from script,
   so even a click counts as focus-visible); the accent edge from .focus marks it instead. */
.ts-wrapper.no-search .ts-control:focus { outline: none; }

/* The list: a raised panel 6px below the trigger, as wide as it; long lists scroll inside. */
.ts-dropdown {
  padding: 6px;
  background: var(--color-surface-raised) !important;
  color: var(--color-fg) !important;
  border: 1px solid var(--color-control-border) !important;
  border-radius: 0.625rem !important;
  box-shadow: var(--shadow-menu) !important;
  margin-top: 6px !important;
}
.ts-wrapper .ts-dropdown-content { display: flex; flex-direction: column; gap: 2px; max-height: min(20rem, 50vh); overflow-y: auto; }
/* Set by searchable-select.js when the list would open past the bottom of the window. */
.ts-wrapper.ts-drop-up .ts-dropdown {
  top: auto !important;
  bottom: 100%;
  margin-top: 0 !important;
  margin-bottom: 6px !important;
}

/* Rows are 36px with a 16px slot for the chosen one's check; tom-select.css pads options with a
   more specific selector, hence the doubled class. */
.ts-dropdown .option,
.ts-dropdown .create,
.ts-dropdown .no-results {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 2.25rem;
  border-radius: var(--radius-md);
  font-size: 0.8125rem;
}
.ts-dropdown .ts-dropdown-content .option[data-selectable],
.ts-dropdown .ts-dropdown-content .create { padding: 0 10px 0 2.25rem; }
.ts-dropdown .option.active,
.ts-dropdown .option:hover,
.ts-dropdown .create.active,
.ts-dropdown .create:hover {
  background-color: var(--color-surface-hover) !important;
  color: var(--color-fg) !important;
}
.ts-dropdown .option.selected { background-color: color-mix(in srgb, var(--color-accent) 8%, transparent) !important; }
.ts-dropdown .option.selected.active { background-color: color-mix(in srgb, var(--color-accent) 12%, transparent) !important; }
.ts-dropdown .option.selected::before {
  content: "";
  position: absolute;
  left: 11px;
  width: 14px;
  height: 14px;
  background: var(--color-accent);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round' d='M2.625 7.4375 5.425 10.0625 11.375 3.9375'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round' d='M2.625 7.4375 5.425 10.0625 11.375 3.9375'/%3E%3C/svg%3E") center / contain no-repeat;
}
.ts-dropdown .option[aria-disabled="true"],
.ts-dropdown .option.disabled { color: var(--color-fg-disabled) !important; background: none !important; }
/* the typed text, marked inside each match */
.ts-dropdown .highlight { color: inherit; background: var(--color-accent-soft); border-radius: 2px; }
/* "Create" offers what was typed; an empty result says so in muted text. */
.ts-dropdown .create { color: var(--color-fg); }
.ts-dropdown .no-results { padding: 14px 10px 10px; color: var(--color-fg-muted); }

/* Option groups: mono caps headers, not selectable, a hairline between groups. */
.ts-dropdown .optgroup + .optgroup { margin-top: 4px; padding-top: 4px; border-top: 1px solid var(--color-border); }
.ts-dropdown .ts-dropdown-content .optgroup-header {
  padding: 7px 10px 4px;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-fg-subtle) !important;
  background: transparent !important;
}

/* A remote search in flight: TomSelect draws its own dual ring in ::after; the element wears the
   .spinner ring instead. */
.ts-dropdown .spinner { width: 0.875rem !important; height: 0.875rem !important; margin: var(--space-2) !important; }
.ts-dropdown .spinner::after { content: none !important; }

/* --- Type styles, effects and icons ------------------------------ */

/* Ten styles cover every screen: weight 400, 500 and 600 only, and mono text is never bold. */
.type-title { font: 600 1.375rem/1.2 var(--font-sans); letter-spacing: -0.015em; color: var(--color-fg); }
.type-section { font: 600 1.125rem/1.3 var(--font-sans); color: var(--color-fg); }
.type-card { font: 600 0.9375rem/1.3 var(--font-sans); color: var(--color-fg); }
.type-body { font: 400 var(--text-sm)/1.5 var(--font-sans); color: var(--color-fg); }
.type-label { font: 500 0.8125rem/1.4 var(--font-sans); color: var(--color-fg); }
.type-helper { font: 400 0.8125rem/1.55 var(--font-sans); color: var(--color-fg-muted); }
.type-badge { font: 500 var(--text-xs)/1 var(--font-sans); }
.type-mono { font: 400 0.8125rem/1.4 var(--font-mono); color: var(--color-fg); }
.type-mono-label { font: 500 0.6875rem/1.4 var(--font-mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-fg-subtle); }
.type-mono-chip { font: 400 0.65625rem/1.5 var(--font-mono); letter-spacing: 0.04em; text-transform: uppercase; color: var(--color-fg-muted); }

/* --- Effects ------------------------------------------------ */
/* Only menus float, so only menus cast a shadow (--shadow-menu). Focus is always the green ring;
   error and disabled change border and opacity, never layout. */
.focus-outline { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.focus-field { border-color: var(--color-accent) !important; box-shadow: 0 0 0 3px var(--color-accent-ring) !important; }
.focus-error { border-color: var(--color-danger-strong) !important; box-shadow: 0 0 0 3px var(--color-danger-ring) !important; }
/* A disabled control dims what depends on it too: wrap the dependent section. */
.is-disabled,
[data-disabled-scope] { opacity: 0.45; pointer-events: none; user-select: none; }

/* --- Icons -------------------------------------------------- */
/* 16px outline icons from icons.svg, drawn in currentColor:
   <svg class="icon"><use href="/webjars/idp-theme/2.0.0/icons.svg#users"/></svg> */
.icon { flex: none; display: block; width: 1rem; height: 1rem; }
.icon-sm { width: 0.875rem; height: 0.875rem; }
.icon-lg { width: 1.125rem; height: 1.125rem; }

/* --- Copy field, setting rows, checkbox group -------------------- */

.copy-field { position: relative; flex: 1 1 auto; min-width: 0; }
.copy-field .form-control { padding-right: 3rem; text-overflow: ellipsis; }
.copy-field-btn {
  position: absolute; top: 1px; right: 1px;
  display: grid; place-items: center;
  width: 2.5rem; height: calc(100% - 2px);
  color: var(--color-fg-muted);
  background: transparent; border: 0; border-radius: var(--radius-lg);
  cursor: pointer;
}
.copy-field-btn:hover { color: var(--color-fg); background: var(--color-fill-quiet); }
.copy-field-btn:focus-visible { outline: 2px solid var(--color-accent); outline-offset: -2px; }

/* --- Setting rows ------------------------------------------- */
/* The usual way a switch appears: a title and one line of help on the left, the control on the
   right. A dependent option sits indented below, or stays visible but disabled with a reason. Rows
   do not highlight on hover; only the control reacts. */
.setting-rows { border: 1px solid var(--color-border); border-radius: var(--radius-xl); background: var(--color-surface-subtle); }
.setting-row {
  display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-6);
  padding: 0.9375rem var(--space-5);
}
.setting-row + .setting-row { border-top: 1px solid var(--color-divider); }
.setting-row-text { display: flex; flex-direction: column; gap: 1px; max-width: 32.5rem; min-width: 0; }
.setting-row-title { font-size: var(--text-sm); font-weight: 500; line-height: 1.4; color: var(--color-fg); }
.setting-row-help { font-size: 0.8125rem; line-height: 1.55; color: var(--color-fg-muted); }
.setting-row-control { flex: none; padding-top: 1px; }
.setting-row-dependent { padding-left: calc(var(--space-5) + var(--space-6)); }
.setting-row-disabled .setting-row-title,
.setting-row-disabled .setting-row-help { color: var(--color-fg-disabled); }
.setting-row-disabled .setting-row-control { opacity: 0.45; pointer-events: none; }
/* an option that cannot apply yet: dimmed, its reason kept readable, a tag instead of the control */
.setting-row-unavailable { opacity: 0.5; }
.setting-row-unavailable .setting-row-title { color: var(--color-fg-disabled); }
.setting-row-status { flex: none; padding-top: 3px; font: 400 var(--text-xs)/1.5 var(--font-mono); color: var(--color-fg-subtle); }

/* --- Checkbox group ----------------------------------------- */
/* A parent that is mixed while some children are picked; its children indented under it. */
.check-group { display: flex; flex-direction: column; gap: 0.875rem; padding: var(--space-5); border: 1px solid var(--color-border); border-radius: var(--radius-xl); background: var(--color-surface-subtle); }
.check-group-parent { display: flex; align-items: flex-start; gap: var(--space-3); cursor: pointer; }
.check-group-parent input { margin-top: 1px; }
.check-group-title { display: block; font-size: var(--text-sm); font-weight: 500; line-height: 1.4; }
.check-group-count { display: block; font-size: 0.8125rem; line-height: 1.55; color: var(--color-fg-muted); }
.check-group-children { display: flex; flex-direction: column; gap: var(--space-3); padding-left: 1.875rem; }
.check-group-children .form-check { font: 400 0.8125rem/1.4 var(--font-mono); }

/* --- Empty, loading and error states ----------------------------- */

.empty-state {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: var(--space-10) var(--space-6);
  text-align: center;
}
.empty-state-icon {
  display: grid; place-items: center;
  width: 2.5rem; height: 2.5rem; margin-bottom: 6px;
  color: var(--color-fg-muted);
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
  border-radius: 0.625rem;
}
.empty-state-icon .icon { width: 18px; height: 18px; }
.empty-state-title { font-size: 0.9375rem; font-weight: 600; line-height: 1.5; color: var(--color-fg); }
.empty-state-text { max-width: 16.25rem; font-size: 0.8125rem; line-height: 1.55; color: var(--color-fg-muted); }
.empty-state-actions { margin-top: var(--space-3); }
/* the error state: the same layout, the icon in the danger tone */
.empty-state-error .empty-state-icon { color: var(--color-danger-fg); background: var(--color-danger-bg); border-color: var(--color-danger-border); }
/* skeleton bars while something loads */
.skeleton { display: flex; flex-direction: column; gap: 0.875rem; padding: var(--space-5); }
.skeleton-bar { height: 2.5rem; border-radius: var(--radius-md); background: var(--color-fill-quiet); animation: skeleton-pulse 1.6s ease-in-out infinite; }
.skeleton-bar-title { width: 40%; height: 0.875rem; }
.skeleton-bar-short { width: 80%; }
@keyframes skeleton-pulse { 50% { opacity: 0.55; } }
@media (prefers-reduced-motion: reduce) { .skeleton-bar { animation: none; } }

/* --- Page header and save bar ------------------------------------ */

/* App tile, name, status and identifiers on one row with one secondary action on the right; the
   tabs run below, edge to edge inside the card. */
.page-header { background: var(--color-surface-subtle); border: 1px solid var(--color-border); border-radius: var(--radius-xl); }
.page-header-top { display: flex; align-items: center; gap: var(--space-4); padding: var(--space-6) var(--space-6) var(--space-5); }
.page-header-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: var(--space-1); }
.page-header-title { display: flex; align-items: center; gap: var(--space-3); margin: 0; font: 600 1.375rem/1.5 var(--font-sans); letter-spacing: -0.015em; color: var(--color-fg); }
/* a status beside the name is a pill, not a heading badge nudged onto the baseline */
.page-header-title .badge { margin-left: 0; transform: none; }
/* the second line: identifiers (mono chips and code) or one sentence of description */
.page-header-meta { display: flex; align-items: center; gap: var(--space-2) 10px; flex-wrap: wrap; font-size: 0.8125rem; line-height: 1.5; color: var(--color-fg-muted); }
.page-header-meta strong { font-weight: 400; color: var(--color-fg-muted); }
.page-header-meta .code-inline { padding: 2px 6px; border-radius: var(--radius-sm); font-size: var(--text-xs); color: var(--color-fg-muted); background: transparent; border-color: var(--color-control-border); }
.page-header-sep { color: var(--color-border-strong); }
.page-header-actions { flex: none; display: flex; gap: var(--space-2); }
.page-header > .nav-tabs { padding: 0 var(--space-6); }
/* without tabs the card closes as it opened */
.page-header:not(:has(> .nav-tabs)) > .page-header-top { padding-bottom: var(--space-6); }

/* --- Save bar ----------------------------------------------- */
/* At the bottom of the content column, not floating; Save stays disabled until something changes.
   A danger zone has no save bar. */
.save-bar {
  display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface-subtle);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
}
.save-bar-message { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: var(--space-2); font-size: 0.8125rem; line-height: 1.5; color: var(--color-fg-muted); }
.save-bar-actions { display: flex; align-items: center; gap: var(--space-2); margin-left: auto; }
.save-bar-dirty { border-color: var(--color-control-border); }
.save-bar-dirty .save-bar-message { color: var(--color-fg); }
.save-bar-dirty .save-bar-message::before { content: ""; flex: none; width: 6px; height: 6px; border-radius: 50%; background: var(--color-warn-strong); }

/* --- Narrow viewport --------------------------------------------- */

@media (max-width: 1024px) {
  .admin { grid-template-columns: 1fr; }
  .admin-nav {
    flex-direction: row;
    flex-wrap: wrap;
    border-right: none;
    border-bottom: 1px solid var(--color-border);
  }
  /* In a row, section labels and separators read as stray items. */
  .admin-nav-section,
  .admin-nav-sep { display: none; }
  /* A wide table scrolls inside its box instead of widening the page. */
  .table-responsive { overflow-x: auto; }
  /* An open pick list or row menu would be clipped by that box, so it lets go while one is open. */
  .table-responsive:has(.ts-wrapper.dropdown-active, details.dropdown[open]) { overflow-x: visible; }
}

@media (max-width: 720px) {
  .admin-main { padding: var(--space-4); }
  /* Headers and save bars stack: the text first, the actions on their own row at the right edge. */
  .page-header-top { flex-wrap: wrap; }
  .page-header-actions { flex-basis: 100%; justify-content: flex-end; }
  .save-bar { flex-wrap: wrap; }
  .save-bar-message { flex-basis: 100%; }
  /* Danger rows: text above, buttons below on the right. */
  .danger-row { flex-direction: column; align-items: stretch; }
  .danger-row > .btn,
  .danger-row > form { align-self: flex-end; }
}

/* The hidden attribute wins over display utilities (d-block on an error that a script shows and hides). */
[hidden] { display: none !important; }
