/* =========================================================
   Eight28 Design System
   ---------------------------------------------------------
   Single source of truth. All tokens are CSS custom
   properties on :root so a tenant <style> block injected
   at login can override anything without code changes.

   Layers (in cascade order):
     1. Primitive tokens   — raw values (color scales, ramps)
     2. Semantic tokens    — roles (--color-primary, --text-primary)
     3. Component tokens   — built on semantic tokens
     4. Dark theme override — [data-theme="dark"]
     5. Tenant override slot — last; wins via specificity/order

 
/* ---------------------------------------------------------
   1. PRIMITIVE TOKENS — unchanged
   --------------------------------------------------------- */
:root {
    /* ---- Teal scale (Eight28 brand) -------------------- */
    --teal-50: oklch(97.5% 0.018 215);
    --teal-100: oklch(94% 0.038 215);
    --teal-200: oklch(88% 0.065 213);
    --teal-300: oklch(80% 0.095 211);
    --teal-400: oklch(72% 0.115 209);
    --teal-500: oklch(64% 0.125 207);
    --teal-600: oklch(56% 0.118 206);
    --teal-700: oklch(48% 0.100 206);
    --teal-800: oklch(38% 0.078 207);
    --teal-900: oklch(28% 0.055 209);
    /* ---- Warm neutral scale, Ink to Film (UI-1 J1: the brief's Appendix A; was a cool blue-grey) ---- */
    --neutral-0: #ffffff;
    --neutral-25: #faf9f9;
    --neutral-50: #f3f2f2;      /* Film */
    --neutral-100: #e8e7e7;     /* sunken surfaces, subtle borders, secondary fills */
    --neutral-150: #dedddd;
    --neutral-200: #d3d2d2;     /* borders */
    --neutral-300: #b4b2b2;
    --neutral-400: #949392;     /* disabled text */
    --neutral-500: #7f7d7d;     /* strong borders: control edges, 3:1 */
    --neutral-600: #5f5e5d;     /* muted text */
    --neutral-700: #4a4848;     /* secondary text */
    --neutral-800: #353332;
    --neutral-850: #2d2b2a;
    --neutral-900: #201e1d;     /* Ink */
    --neutral-950: #1a1817;
    /* ---- Status scales --------------------------------- */
    --green-100: oklch(94% 0.045 155);
    --green-500: oklch(64% 0.135 155);
    --green-700: oklch(48% 0.110 155);
    --amber-100: oklch(94% 0.060 85);
    --amber-500: oklch(76% 0.150 82);
    --amber-700: oklch(58% 0.130 60);
    --red-100: oklch(94% 0.040 25);
    --red-500: oklch(64% 0.180 25);
    --red-700: oklch(50% 0.165 25);
    --blue-100: oklch(94% 0.045 250);
    --blue-500: oklch(64% 0.140 250);
    --blue-700: oklch(48% 0.130 250);
    --accent-coral: oklch(72% 0.135 30);
    /* UI-1 I1: colours the pages used that the palette lacked (phase J gives the brand's their final values). */
    --black: oklch(0% 0 0);                  /* shadows and scrims: color-mix(in srgb, var(--black) N%, transparent) */
    --violet-100: oklch(94% 0.045 300);
    --violet-600: oklch(55% 0.180 280);
    --violet-700: oklch(45% 0.140 300);
    --rose-100: oklch(94% 0.040 5);
    --rose-700: oklch(50% 0.160 5);
    /* ---- Eight28 brand (UI-1 J1: the brief's Appendix A, as approved in the phase C demo) ---- */
    --signal-50: #fff2ef;       /* tint: selected nav item, soft backgrounds */
    --signal-300: #ff7756;      /* pressed (lighter again, as in the demo) */
    --signal-400: #ff5a31;      /* hover */
    --signal-500: #ff3d0d;      /* Signal: the primary. Text on it is Ink, never white (white is 3.5:1) */
    --signal-700: #ae1800;      /* Signal deep: Signal as text (links, accents), 7:1 on white */
    --ink: var(--neutral-900);  /* text, and text on Signal (4.7:1) */
    --film: var(--neutral-50);  /* the page; light text on dark fills */
    --crimson-50: #fdebee;      /* error background */
    --crimson-600: #c8102e;     /* errors and danger (D3), 5.9:1 on white */
    --crimson-700: #a20d25;     /* danger hover */
    --forest-50: #e3f2e8;
    --forest-500: #3f9a62;
    --forest-700: #1d6b3a;      /* success */
    --ochre-50: #fbefd6;
    --ochre-500: #d99a1e;
    --ochre-700: #7a4b00;       /* warning, 6.5:1 on its background */
    --cobalt-50: #e4ecf8;
    --cobalt-400: #5b86cf;
    --cobalt-700: #1f4f9e;      /* info */
}

/* ---------------------------------------------------------
   2. SEMANTIC TOKENS — bolder type, generous spacing
   --------------------------------------------------------- */
:root {
    /* ---- Color: brand & action (unchanged) ------------- */
    --color-primary: var(--signal-500);
    --color-primary-hover: var(--signal-400);
    --color-primary-active: var(--signal-300);
    --color-primary-contrast: var(--ink);
    --color-primary-soft: var(--signal-50);
    --color-primary-soft-text: var(--signal-700);   /* the brand colour as text (tenant-theme.js derives it too) */
    --color-secondary: var(--neutral-100);
    --color-secondary-hover: var(--neutral-150);
    --color-secondary-active: var(--neutral-200);
    --color-secondary-contrast: var(--ink);
    --color-accent: var(--ink);
    /* ---- Color: surfaces (unchanged) ------------------- */
    --color-background-page: var(--film);
    --color-background-surface: var(--neutral-0);
    --color-background-elevated: var(--neutral-0);
    --color-background-sunken: var(--neutral-100);
    --color-background-inverse: var(--ink);
    --color-background-overlay: color-mix(in srgb, var(--ink) 55%, transparent);
    /* ---- Color: borders (unchanged) -------------------- */
    --color-border: var(--neutral-200);
    --color-border-strong: var(--neutral-500);
    --color-border-subtle: var(--neutral-100);
    --color-border-focus: var(--ink);
    /* ---- Color: text (unchanged) ----------------------- */
    --color-text-primary: var(--ink);
    --color-text-secondary: var(--neutral-700);
    --color-text-muted: var(--neutral-600);
    --color-text-disabled: var(--neutral-400);
    --color-text-inverse: var(--film);
    --color-text-link: var(--color-primary-soft-text);   /* follows a tenant's colour, darkened to read */
    --color-text-link-hover: var(--color-text-primary);
    /* ---- Color: status (unchanged) --------------------- */
    --color-success: var(--forest-700);
    --color-success-bg: var(--forest-50);
    --color-success-border: var(--forest-500);
    --color-warning: var(--ochre-700);
    --color-warning-bg: var(--ochre-50);
    --color-warning-border: var(--ochre-500);
    --color-error: var(--crimson-600);
    --color-error-bg: var(--crimson-50);
    --color-error-border: var(--crimson-600);
    --color-error-hover: var(--crimson-700);
    --color-error-contrast: var(--film);
    /* D3 — alias for the solid danger red. Was referenced by var(--color-danger)
       in 4 places (incl. the sidebar approvals badge) but never defined, so those
       backgrounds/colours silently fell back to transparent/inherited — the
       approvals count badge rendered with no red pill. Theme-aware via --color-error. */
    --color-danger: var(--color-error);
    --color-info: var(--cobalt-700);
    --color-info-bg: var(--cobalt-50);
    --color-info-border: var(--cobalt-400);
    /* ---- Typography (BOLDER scale) --------------------- */
    /* Archivo, self-hosted (UI-1 J2, @font-face in section 5): the same type on every machine. The fallbacks are
       the brief's, close in width to Archivo, for the moment before it loads. */
    --font-family-base: Archivo, Arial, Helvetica, sans-serif;
    --font-family-heading: Archivo, Arial, Helvetica, sans-serif;
    --font-family-display: Archivo, 'Arial Black', Arial, sans-serif;
    --font-family-mono: ui-monospace, 'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace;
    /* Type scale: body text at 13px (--font-size-base), hero at 52px+.
       Modular ratio ~1.20 from base upward.                  */
    --font-size-xs: 10px; /* captions / pills */
    --font-size-sm: 12px; /* meta, helper text */
    --font-size-base: 13px; /* DEFAULT body */
    --font-size-md: 16px; /* card titles, labels */
    --font-size-lg: 20px; /* subheads */
    --font-size-xl: 24px; /* was 18 — section heads */
    --font-size-2xl: 30px; /* was 22 — H3 */
    --font-size-3xl: 38px; /* was 28 — H2 */
    --font-size-4xl: 52px; /* was 36 — H1 */
    --font-size-5xl: 64px; /* NEW — hero display */
    --font-size-6xl: 80px; /* NEW — landing hero */

    --font-weight-regular: 400;
    --font-weight-medium: 500;
    --font-weight-semibold: 600;
    --font-weight-bold: 700;
    --font-weight-extrabold: 800; /* page titles (D5) */
    --font-stretch-display: 125%; /* page titles: Archivo's widest (D5) */

    --line-height-tight: 1.1; /* was 1.15 — tighter for big type */
    --line-height-normal: 1.5; /* was 1.45 — easier reading */
    --line-height-relaxed: 1.65;
    --letter-spacing-tight: -0.02em; /* was -0.01 — bolder hero */
    --letter-spacing-normal: 0;
    --letter-spacing-wide: 0.04em;
    /* ---- Spacing — same 4px base, more generous mid ---- */
    --space-0: 0;
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 14px; /* was 12 */
    --space-4: 20px; /* was 16 */
    --space-5: 24px; /* was 20 */
    --space-6: 32px; /* was 24 */
    --space-7: 40px; /* was 32 */
    --space-8: 48px; /* was 40 */
    --space-9: 64px; /* was 48 */
    --space-10: 80px; /* was 56 */
    --space-12: 96px; /* was 72 */
    --space-14: 128px; /* was 96 */
    --space-16: 160px; /* was 128 */
    /* ---- Shape — slightly softer ----------------------- */
    --radius-xs: 4px;
    --radius-sm: 8px; /* was 6 */
    --radius-md: 10px; /* was 8 */
    --radius-lg: 14px; /* was 12 */
    --radius-xl: 18px; /* was 16 */
    --radius-2xl: 24px; /* was 20 */
    --radius-full: 9999px;
    /* ---- Shadow — slightly more presence --------------- */
    --shadow-xs: 0 1px 2px 0 color-mix(in srgb, var(--ink) 5%, transparent);
    --shadow-sm: 0 2px 4px 0 color-mix(in srgb, var(--ink) 8%, transparent), 0 1px 2px 0 color-mix(in srgb, var(--ink) 5%, transparent);
    --shadow-md: 0 6px 16px -2px color-mix(in srgb, var(--ink) 10%, transparent), 0 2px 6px -1px color-mix(in srgb, var(--ink) 6%, transparent);
    --shadow-lg: 0 14px 32px -4px color-mix(in srgb, var(--ink) 12%, transparent), 0 6px 12px -2px color-mix(in srgb, var(--ink) 8%, transparent);
    --shadow-xl: 0 28px 56px -8px color-mix(in srgb, var(--ink) 18%, transparent), 0 12px 24px -4px color-mix(in srgb, var(--ink) 10%, transparent);
    --shadow-focus: 0 0 0 2px var(--color-border-focus);   /* the focus ring: 2px Ink */
    /* ---- Motion (unchanged) ---------------------------- */
    --motion-fast: 120ms;
    --motion-base: 180ms;
    --motion-slow: 280ms;
    --motion-ease: cubic-bezier(0.2, 0, 0, 1);
    --motion-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    /* ---- Layout — taller header + sidebar -------------- */
    --layout-z-modal: 300;
    --layout-z-toast: 400;
}

/* ---------------------------------------------------------
   3. COMPONENT TOKENS — chunkier buttons, inputs, cards
   --------------------------------------------------------- */
:root {
    /* ---- Button — taller, weightier -------------------- */
    --button-height-sm: 36px; /* was 26 */
    --button-height-md: 44px; /* was 32 — meets WCAG 44px target */
    --button-height-lg: 56px; /* was 40 — onboarding CTA size */
    --button-height-xl: 64px; /* NEW — hero CTA */
    --button-padding-x-sm: 16px; /* was 10 */
    --button-padding-x-md: 22px; /* was 14 */
    --button-padding-x-lg: 32px; /* was 20 */
    --button-padding-x-xl: 40px; /* NEW */
    --button-radius: var(--radius-md);
    --button-font-weight: var(--font-weight-semibold); /* was medium */
    --button-font-size: var(--font-size-base); /* 13px */
    --button-font-size-lg: var(--font-size-md); /* 17px on lg */
    --button-font-size-xl: var(--font-size-lg); /* 20px on xl */

    --button-primary-bg: var(--color-primary);
    --button-primary-text: var(--color-primary-contrast);
    --button-primary-hover-bg: var(--color-primary-hover);
    --button-primary-active-bg: var(--color-primary-active);
    --button-secondary-bg: var(--color-background-surface);
    --button-secondary-text: var(--color-text-primary);
    --button-secondary-border: var(--color-border-strong);
    --button-secondary-hover-bg: var(--color-secondary-hover);
    --button-ghost-text: var(--color-text-secondary);
    --button-ghost-hover-bg: var(--color-secondary);
    --button-danger-bg: var(--color-error);
    --button-danger-text: var(--color-error-contrast);
    --button-danger-hover-bg: var(--color-error-hover);
    /* ---- Input — taller, breathable -------------------- */
    --input-height-sm: 36px; /* was 26 */
    --input-height-md: 48px; /* was 32 — onboarding parity */
    --input-height-lg: 56px; /* was 40 */
    --input-padding-x: 16px; /* was 10 */
    --input-bg: var(--color-background-surface);
    --input-text: var(--color-text-primary);
    --input-placeholder: var(--color-text-muted);
    --input-border: var(--color-border-strong);
    --input-border-hover: var(--color-text-primary);
    --input-focus-border: var(--color-border-focus);
    --input-focus-ring: var(--shadow-focus);
    --input-radius: var(--radius-lg); /* was md — softer */
    --input-font-size: var(--font-size-base); /* 13px */
    --input-disabled-bg: var(--color-background-sunken);
    /* ---- Card — more generous padding ------------------ */
    --card-bg: var(--color-background-surface);
    --card-border: var(--color-border);
    --card-radius: var(--radius-xl); /* was lg */
    --card-shadow: var(--shadow-sm);
    --card-padding: var(--space-6); /* was space-5 → now 32px */
    /* ---- Nav / Sidebar (unchanged) --------------------- */
    /* ---- Modal / Popover ------------------------------- */
    --modal-bg: var(--color-background-elevated);
    --modal-overlay: var(--color-background-overlay);
    --popover-bg: var(--color-background-elevated);
    --popover-border: var(--color-border);
    --popover-radius: var(--radius-lg); /* was md */
    --popover-shadow: var(--shadow-lg);

/* ---- Table ---------------------------------------- */
--table-bg:            var(--color-background-surface);
--table-header-bg:     var(--color-background-sunken);
--table-header-text:   var(--color-text-secondary);
--table-row-hover-bg:  var(--color-background-sunken); /* UI-1 D14: neutral-50 was nearly white */
--table-border:        var(--color-border-subtle);
--table-cell-padding-y: 6px;
--table-cell-padding-x: 10px;

/* ---- Badge / Chip --------------------------------- */
--badge-radius:    var(--radius-sm);
--badge-font-size: var(--font-size-xs);
--badge-font-weight: var(--font-weight-medium);
--badge-padding-x: 6px;
--badge-padding-y: 2px;

/* ---- Tooltip -------------------------------------- */
--tooltip-bg:        var(--color-background-inverse);
--tooltip-text:      var(--color-text-inverse);
--tooltip-radius:    var(--radius-sm);
--tooltip-font-size: var(--font-size-xs);
--tooltip-padding:   4px 8px;

/* ---- Avatar --------------------------------------- */
--avatar-bg:     var(--color-primary);   /* UI-1 J1: the brand (the 8 avatar--color-N variants still vary it) */
--avatar-text:   var(--color-primary-contrast);
--avatar-border: var(--color-background-surface);
}

/* ---------------------------------------------------------
   4. DARK THEME — soft warm-navy, not pitch black
   --------------------------------------------------------- */
[data-theme="dark"] {
    /* Surfaces: stepped neutrals, with elevated surfaces
       BRIGHTER than the page (Linear/Notion convention).   */
    --color-background-page:     var(--neutral-950);
    --color-background-surface:  var(--neutral-900);
    --color-background-elevated: var(--neutral-850);
    --color-background-sunken:   oklch(10% 0.009 230);
    --color-background-inverse:  var(--neutral-50);
    --color-background-overlay:  oklch(8% 0.009 230 / 0.7);

    /* Borders: lifted, not pure white opacity */
    --color-border:        oklch(28% 0.012 230);
    --color-border-strong: oklch(36% 0.014 230);
    --color-border-subtle: oklch(22% 0.011 230);

    /* Text: never use full white — too sharp on dark */
    --color-text-primary:   oklch(96% 0.005 230);
    --color-text-secondary: oklch(78% 0.010 230);
    --color-text-muted:     oklch(60% 0.012 230);
    --color-text-disabled:  oklch(42% 0.012 230);
    --color-text-inverse:   var(--neutral-900);
    --color-text-link:      var(--teal-300);
    --color-text-link-hover:var(--teal-200);

    /* Brand: lift lightness so it pops on dark */
    --color-primary:           var(--teal-400);
    --color-primary-hover:     var(--teal-300);
    --color-primary-active:    var(--teal-200);
    --color-primary-contrast:  var(--neutral-950);
    --color-primary-soft:      oklch(30% 0.060 207);
    --color-primary-soft-text: var(--teal-200);

    --color-secondary:        oklch(24% 0.012 230);
    --color-secondary-hover:  oklch(28% 0.012 230);
    --color-secondary-active: oklch(32% 0.013 230);
    --color-secondary-contrast: var(--neutral-50);

    /* Status — soften for dark backgrounds */
    --color-success-bg:     oklch(28% 0.045 155);
    --color-warning-bg:     oklch(28% 0.060  82);
    --color-error-bg:       oklch(28% 0.060  25);
    --color-info-bg:        oklch(28% 0.050 250);

    /* Shadows lose contrast on dark — strengthen */
    --shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.30);
    --shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.36),
                 0 1px 2px 0 rgb(0 0 0 / 0.24);
    --shadow-md: 0 4px 12px -2px rgb(0 0 0 / 0.45),
                 0 2px 4px -1px rgb(0 0 0 / 0.30);
    --shadow-lg: 0 10px 24px -4px rgb(0 0 0 / 0.55),
                 0 4px 8px -2px rgb(0 0 0 / 0.35);
    --shadow-xl: 0 20px 40px -8px rgb(0 0 0 / 0.65),
                 0 8px 16px -4px rgb(0 0 0 / 0.40);
    --shadow-focus: 0 0 0 3px oklch(72% 0.115 209 / 0.35);

    /* Recompute dependent component tokens that reference
       semantics changed above.                              */
    --input-disabled-bg:        oklch(22% 0.011 230);
    --table-row-hover-bg:       oklch(22% 0.011 230);
    --button-secondary-bg:      var(--color-background-surface);
    --button-secondary-hover-bg: var(--color-secondary-hover);
    --tooltip-bg:               var(--neutral-50);
    --tooltip-text:             var(--neutral-900);
}

/* ---------------------------------------------------------
   Bootstrap table overrides — dark-mode safety
   ---------------------------------------------------------
   Bootstrap's
   .table class reaches for --bs-table-bg / --bs-table-color /
   --bs-table-border-color / --bs-table-accent-bg, and applies
   white-by-default to every cell via:
       .table > :not(caption) > * > * {
         background-color: var(--bs-table-bg);
         box-shadow: inset 0 0 0 9999px var(--bs-table-accent-bg);
       }
   Our design-system tokens don't reach those Bootstrap variables,
   so in dark mode every table row stays bright white on the dark
   page chrome — the loudest dark-mode-broken element on screen.

   Retarget the Bootstrap variables at our design-system tokens.
   Reuses the existing 3-tier surface convention:
     - canvas       (--color-background-page)     — sits behind cards
     - card / table (--color-background-surface)  — table body fill
     - raised       (--color-background-elevated) — table header band

   Also soften the search input border in the topbar — under dark
   mode the default --color-border reads as a hard light line
   against the chrome; --color-border-subtle is enough to delineate
   without competing visually.
*/
[data-theme="dark"] .table {
    --bs-table-bg:           var(--color-background-surface);
    --bs-table-color:        var(--color-text-primary);
    --bs-table-border-color: var(--color-border-subtle);
    --bs-table-accent-bg:    transparent;
    --bs-table-hover-bg:     var(--table-row-hover-bg);
    --bs-table-hover-color:  var(--color-text-primary);
    --bs-table-striped-bg:   var(--color-background-elevated);
    --bs-table-striped-color: var(--color-text-primary);
    background: var(--color-background-surface);
    color:      var(--color-text-primary);
}
[data-theme="dark"] .table th {
    /* In dark mode the header band reads better as a slightly-
       raised tier above the row body, not a sunken one. */
    background: var(--color-background-elevated);
    color:      var(--color-text-secondary);
    border-bottom-color: var(--color-border);
}
[data-theme="dark"] .table td {
    background: var(--color-background-surface);
    border-bottom-color: var(--color-border-subtle);
}

[data-theme="dark"] .topbar__search .input {
    border-color: var(--color-border-subtle);
}

/* ---------------------------------------------------------
   Defensive dark-mode backgrounds for the layout chain
   ---------------------------------------------------------
   The DOM chain is:

     .abp-application-layout            ← from ABP's global.css bundle
       #ApplicationContainer            ← from ABP's global.css bundle
         .app-shell                     ← ours; bg = page
           .app-shell__main             ← ours; no bg (inherits)
             .content (inside <main>)   ← ours; no bg (inherits)
             .topbar / .sidebar         ← ours; bg = surface

   In dark mode, ABP's outer wrappers have a hardcoded white
   background that we don't control. The Stage 9 UAT screenshot
   showed it bleeding through past .app-shell where layout
   measurements left ABP's wrapper visible. Forcing the chain
   to be dark all the way down ensures no white pixel can leak.
   Each rule scoped to [data-theme="dark"] so light mode is
   untouched. */
[data-theme="dark"] .abp-application-layout,
[data-theme="dark"] #ApplicationContainer,
[data-theme="dark"] .app-shell__main,
[data-theme="dark"] .app-shell .content {
    background: var(--color-background-page);
}

/* ---------------------------------------------------------
   5. BASE STYLES — minimal, tokenized
   --------------------------------------------------------- */
/* Archivo (SIL Open Font License, fonts/archivo/OFL.txt): one variable file per script, weight 100-900 and width
   62-125%. From @fontsource-variable/archivo 5.2.8; sha256 in docs/requirements/plan-ui-1-consistency-and-brand.md.
   The browser downloads only the file whose range a page uses. */
@font-face {
    font-family: Archivo;
    font-style: normal;
    font-display: swap;
    font-weight: 100 900;
    font-stretch: 62% 125%;
    src: url('../fonts/archivo/archivo-latin-ext-wdth-normal.woff2') format('woff2-variations');
    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: Archivo;
    font-style: normal;
    font-display: swap;
    font-weight: 100 900;
    font-stretch: 62% 125%;
    src: url('../fonts/archivo/archivo-latin-wdth-normal.woff2') format('woff2-variations');
    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;
}

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

html {
    -webkit-text-size-adjust: 100%;
    -webkit-tap-highlight-color: transparent;
}

body {
    margin: 0;
    font-family: var(--font-family-base);
    font-size:   var(--font-size-base);
    font-weight: var(--font-weight-regular);
    line-height: var(--line-height-normal);
    color:        var(--color-text-primary);
    background:   var(--color-background-page);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-family-heading);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-tight);
    letter-spacing: var(--letter-spacing-tight);
    color: var(--color-text-primary);
    margin: 0;
}
h1 { font-size: var(--font-size-3xl); }
h2 { font-size: var(--font-size-2xl); }
h3 { font-size: var(--font-size-xl);  }
h4 { font-size: var(--font-size-lg);  }
h5 { font-size: var(--font-size-md);  }
h6 { font-size: var(--font-size-base); }

p { margin: 0; }

a {
    color: var(--color-text-link);
    text-decoration: none;
    transition: color var(--motion-fast) var(--motion-ease);
}
a:hover { color: var(--color-text-link-hover); }

/* Form controls take the page's font and colour. Browsers give them their own (Arial at 13.33px),
   so without this, any control without a design-system class looked foreign (UI-1 phase B). */
button, input, select, textarea { font: inherit; color: inherit; }

/* A fieldset groups controls; it draws nothing unless a class says so. */
fieldset { border: 0; padding: 0; margin: 0; min-width: 0; }
legend { padding: 0; }

code, kbd, samp, pre {
    font-family: var(--font-family-mono);
    font-size: 0.92em;
}

/* Code inside a block is already the block's size; without this the two 0.92s compound. Bootstrap's reboot used to
   supply it in the end-user portal, until UI-1 phase G put Bootstrap in a layer below us. */
pre code {
    font-size: inherit;
}

::selection {
    background: var(--color-primary-soft);
    color: var(--color-primary-soft-text);
}

:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    border-radius: var(--radius-xs);
}

/* Reduced-motion + high-contrast media queries are defined further
   down in this file (lines ~1521 and ~1535). The duplicate that used
   to live here was the subset version of those — removed in Stage 9
   to keep one canonical block. */

/* ---------------------------------------------------------
   6. COMPONENT STYLES — pure token consumers
   --------------------------------------------------------- */

/* ---- Button --------------------------------------------- */
.btn {
    --_h:  var(--button-height-md);
    --_px: var(--button-padding-x-md);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    height: var(--_h);
    padding: 0 var(--_px);
    border: 1px solid transparent;
    border-radius: var(--button-radius);
    font-family: inherit;
    font-size:    var(--button-font-size);
    font-weight:  var(--button-font-weight);
    line-height: 1;
    white-space: nowrap;
    vertical-align: middle;
    cursor: pointer;
    user-select: none;
    transition: background-color var(--motion-fast) var(--motion-ease),
                border-color     var(--motion-fast) var(--motion-ease),
                color            var(--motion-fast) var(--motion-ease),
                box-shadow       var(--motion-fast) var(--motion-ease),
                transform        var(--motion-fast) var(--motion-ease);
}
.btn:active { transform: translateY(0.5px); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }

.btn--sm { --_h: var(--button-height-sm); --_px: var(--button-padding-x-sm); font-size: var(--font-size-sm); }
.btn--lg { --_h: var(--button-height-lg); --_px: var(--button-padding-x-lg); font-size: var(--font-size-md); }

.btn--primary {
    background: var(--button-primary-bg);
    color:      var(--button-primary-text);
}
.btn--primary:hover:not(:disabled)  { background: var(--button-primary-hover-bg); }
.btn--primary:active:not(:disabled) { background: var(--button-primary-active-bg); }

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

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

.btn--danger {
    background: var(--button-danger-bg);
    color:      var(--button-danger-text);
}
.btn--danger:hover:not(:disabled) { background: var(--button-danger-hover-bg); }

.btn--icon { padding: 0; width: var(--_h); }

/* ---- Input / Textarea / Select -------------------------- */
.input, .textarea, .select {
    width: 100%;
    height: var(--input-height-md);
    padding: 0 var(--input-padding-x);
    background: var(--input-bg);
    color:      var(--input-text);
    border: 1px solid var(--input-border);
    border-radius: var(--input-radius);
    font-family: inherit;
    font-size:   var(--input-font-size);
    line-height: 1;
    transition: border-color var(--motion-fast) var(--motion-ease),
                box-shadow   var(--motion-fast) var(--motion-ease);
}
.textarea { height: auto; padding: 8px var(--input-padding-x); line-height: var(--line-height-normal); resize: vertical; min-height: 72px; }

/* A dropdown draws its own chevron (UI-1 H2): the browser's arrow sat against the edge and differed between browsers.
   Two gradients in the muted text colour, so it follows the theme. */
.select {
    appearance: none;
    padding-right: calc(var(--input-padding-x) + 20px);
    background-image:
        linear-gradient(45deg, transparent 50%, var(--color-text-muted) 50%),
        linear-gradient(135deg, var(--color-text-muted) 50%, transparent 50%);
    background-position:
        calc(100% - var(--input-padding-x) - 5px) 50%,
        calc(100% - var(--input-padding-x)) 50%;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
}
.select[multiple] { background-image: none; padding-right: var(--input-padding-x); height: auto; }

/* The compact size, for filter bars (was Bootstrap's form-control-sm / form-select-sm). */
.input--sm, .select--sm {
    height: var(--input-height-sm);
    font-size: var(--font-size-sm);
}
.input::placeholder, .textarea::placeholder { color: var(--input-placeholder); }
.input:hover:not(:focus):not(:disabled),
.textarea:hover:not(:focus):not(:disabled),
.select:hover:not(:focus):not(:disabled) { border-color: var(--input-border-hover); }
.input:focus, .textarea:focus, .select:focus {
    outline: none;
    border-color: var(--input-focus-border);
    box-shadow: var(--input-focus-ring);
}
.input:disabled, .textarea:disabled, .select:disabled {
    background: var(--input-disabled-bg);
    cursor: not-allowed;
    color: var(--color-text-disabled);
}
.input--invalid,
.select--invalid {
    border-color: var(--color-error);
}
.input--invalid:focus { box-shadow: 0 0 0 3px color-mix(in srgb, var(--red-500) 20%, transparent); }

.input-group {
    display: flex; flex-direction: column; gap: 4px;
}
/* Bootstrap names its input groups the same and pulls every child after the first 1px left, a margin we never set,
   so it survived UI-1 phase G's layer. Zero specificity: any margin of our own still wins. */
:where(.input-group) > * {
    margin-left: 0;
}
/* The asterisk after a required field's label. */
.input-group__required { color: var(--color-error); }
.input-group__label {
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
    color: var(--color-text-secondary);
}
/* A field's hint and error are the size of its label (UI-1 H5): at 10px the one message a user must read was the
   smallest text on the page. --font-size-xs is for captions and pills. */
.input-group__hint  { font-size: var(--font-size-sm); color: var(--color-text-muted); }
.input-group__error { font-size: var(--font-size-sm); color: var(--color-error); }

/* Input + trailing suffix (e.g. "yourcompany" + ".eight28.biz"). Kept
   distinct from .input-group above (which composes label+input+hint
   vertically) so the two patterns can coexist. The suffix uses the
   same height, border, radius and font-size tokens as .input so the
   pair reads as a single field. font:inherit ensures the suffix font
   matches whatever cascade is in scope (sets the gap right where
   the old Bootstrap .input-group-text used a different font stack). */

/* ---- Input + leading select (e.g. dialling code + phone number) ----
   The mirror of .input-suffix-group: an ordinary .select and .input joined into one field. The select keeps its own
   chevron and sits on the sunken background; the shared edge is drawn once (the input overlaps it by 1px) and the
   focused part is raised so its ring is not clipped by its neighbour. Mark both parts --invalid for an error. */
.input-prefix-group {
    display: flex;
    align-items: stretch;
    width: 100%;
}
.input-prefix-group > .select {
    flex: 0 0 auto;
    width: auto;
    max-width: 50%;
    background-color: var(--color-background-sunken);
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
}
.input-prefix-group > .input {
    flex: 1 1 auto;
    min-width: 0;
    margin-left: -1px;
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
}
.input-prefix-group > :focus { position: relative; z-index: 1; }

/* ---- Drop zone (file upload with click + drag-and-drop) ----
   The native <InputFile> is positioned absolutely on top of the
   visual zone with opacity:0 — the browser handles BOTH clicks
   AND drops on a file input natively, so no JS bridge is needed
   beyond a small drag-over class toggle for visual feedback. */
.logo-drop-zone {
    position: relative;
    border: 2px dashed var(--color-border);
    border-radius: var(--radius-md);
    padding: 28px 16px;
    text-align: center;
    background: var(--color-background-sunken);
    color: var(--color-text-muted);
    margin-bottom: 12px;
    cursor: pointer;
    transition: border-color var(--motion-fast) var(--motion-ease),
                background    var(--motion-fast) var(--motion-ease);
}

.logo-drop-zone:hover {
    border-color: var(--color-primary);
    background: var(--color-background-surface);
}

.logo-drop-zone--active {
    border-color: var(--color-primary);
    border-style: solid;
    background: color-mix(in srgb,
        var(--color-primary) 8%,
        var(--color-background-surface));
}

/* The InputFile fills the whole zone but is invisible — clicks
   anywhere on the zone open the file picker, drops anywhere on
   the zone trigger OnChange. pointer-events:auto is the default
   for an <input> but we restate it for clarity. */
.logo-drop-zone__input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
    pointer-events: auto;
}

.logo-drop-zone__icon {
    font-size: 32px;
    margin-bottom: 6px;
    opacity: 0.5;
    line-height: 1;
}

.logo-drop-zone__primary {
    font-size: var(--font-size-base);
    color: var(--color-text-primary);
    font-weight: 500;
    margin-bottom: 2px;
}

.logo-drop-zone__secondary {
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}

/* ---- Checkbox / Radio / Switch ------------------------- */
.checkbox, .radio {
    appearance: none;
    width: 16px; height: 16px;
    border: 1px solid var(--color-border-strong);
    background: var(--input-bg);
    cursor: pointer;
    transition: background var(--motion-fast), border-color var(--motion-fast);
    flex: 0 0 auto;
    display: inline-grid;
    place-items: center;
}
.checkbox { border-radius: var(--radius-xs); }
.radio    { border-radius: var(--radius-full); }
.checkbox:hover:not(:disabled), .radio:hover:not(:disabled) { border-color: var(--color-primary); }

/* A consent checkbox (accepting terms, overriding a safeguard) is larger, so it reads as a deliberate choice
   (UI-1 H2; Register and the account-owner bypass each drew their own before). */
.checkbox--lg { width: 22px; height: 22px; border-width: 2px; border-radius: var(--radius-sm); }
.checkbox--lg:checked::after { width: 11px; height: 6px; }

/* A checkbox or switch with its label beside it; the text is clickable. */
.check-row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--font-size-sm);
    color: var(--color-text-primary);
    line-height: var(--line-height-normal);
    cursor: pointer;
}
.checkbox:checked, .radio:checked {
    background: var(--color-primary);
    border-color: var(--color-primary);
}
.checkbox:checked::after {
    content: '';
    width: 9px; height: 5px;
    border: 2px solid var(--color-primary-contrast);
    border-top: 0; border-right: 0;
    transform: rotate(-45deg) translate(1px, -1px);
}
.radio:checked::after {
    content: '';
    width: 6px; height: 6px;
    background: var(--color-primary-contrast);
    border-radius: var(--radius-full);
}
.checkbox:focus-visible, .radio:focus-visible { box-shadow: var(--shadow-focus); outline: none; }

.switch {
    appearance: none;
    width: 28px; height: 16px;
    border-radius: var(--radius-full);
    background: var(--color-border-strong);
    position: relative; cursor: pointer;
    transition: background var(--motion-fast);
}
.switch::after {
    content: '';
    position: absolute;
    top: 2px; left: 2px;
    width: 12px; height: 12px;
    background: var(--neutral-0);
    border-radius: var(--radius-full);
    transition: transform var(--motion-fast) var(--motion-ease);
    box-shadow: var(--shadow-xs);
}
.switch:checked { background: var(--color-primary); }
.switch:checked::after { transform: translateX(12px); }

/* ---- Card ---------------------------------------------- */
.card {
    /* A column, as the end-user portal's cards have been under Bootstrap: kept on purpose (UI-1 phase G) so both
       portals' cards lay out alike. Text colour and wrapping are set here rather than left to whichever
       stylesheet happens to load. */
    position: relative;
    display: flex;
    flex-direction: column;
    min-width: 0;
    color: var(--color-text-primary);
    overflow-wrap: break-word;
    background: var(--card-bg);
    border: 1px solid var(--card-border);
    border-radius: var(--card-radius);
    box-shadow: var(--card-shadow);
    overflow: hidden;
}
/* The header is a row: title (and subtitle, wrapped together) on the left, actions on the right; on a narrow card the
   actions wrap below. Header, body and footer share the card's horizontal padding, so their text lines up (UI-1 H5:
   a header's button sat under its title with no gap, and header text sat 12px left of the body's). */
.card__header  {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-3);
    padding: var(--space-4) var(--card-padding);
    border-bottom: 1px solid var(--color-border-subtle);
}
.card__body    { padding: var(--card-padding); }
/* A list of rows straight under the header (approval policies, permissions): the rows carry their own spacing. */
.card__body--list { padding-top: var(--space-2); padding-bottom: var(--space-2); }
.card__footer  { padding: var(--space-3) var(--card-padding); border-top: 1px solid var(--color-border-subtle); background: var(--color-background-sunken); }
.card__title   { font-size: var(--font-size-md); font-weight: var(--font-weight-semibold); }
.card__subtitle{ font-size: var(--font-size-sm); color: var(--color-text-muted); margin-top: 2px; }

/* ---- Badge --------------------------------------------- */
.badge {
    display: inline-flex; align-items: center; gap: 4px;
    padding: var(--badge-padding-y) var(--badge-padding-x);
    border-radius: var(--badge-radius);
    font-size:    var(--badge-font-size);
    font-weight:  var(--badge-font-weight);
    line-height: 1;
    text-align: center;
    white-space: nowrap;
    background: var(--neutral-100);
    color: var(--color-text-secondary);
    border: 1px solid transparent;
}
.badge--primary { background: var(--color-primary-soft); color: var(--color-primary-soft-text); }
.badge--success { background: var(--color-success-bg); color: var(--color-success); }
.badge--warning { background: var(--color-warning-bg); color: var(--color-warning); }
.badge--error   { background: var(--color-error-bg);   color: var(--color-error); }
.badge--info    { background: var(--color-info-bg);    color: var(--color-info); }
.badge--outline { background: transparent; border-color: var(--color-border); color: var(--color-text-secondary); }
.badge--pending { background: var(--color-warning-bg); color: var(--color-warning); border-color: var(--color-warning-bg); }
.badge--dot::before {
    content: ''; width: 6px; height: 6px;
    border-radius: var(--radius-full);
    background: currentColor; opacity: 0.7;
}

/* ---- Alert --------------------------------------------- */
.alert {
    position: relative;
    display: flex; gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border);
    background: var(--color-background-surface);
    font-size: var(--font-size-sm);
}
/* An alert keeps a gap below it in flowing content, as the end-user portal's did under Bootstrap; but not as the
   last thing in its box, nor where the layout spaces its children with a gap of its own (UI-1 H5). */
.alert { margin-bottom: var(--space-4); }
.alert:last-child,
:is(.auth__card, .auth__form, .drawer__body) > .alert { margin-bottom: 0; }
.alert__title{ font-weight: var(--font-weight-semibold); margin-bottom: 2px; }
.alert--info    { background: var(--color-info-bg);    border-color: var(--color-info-border);    color: var(--color-info); }
.alert--success { background: var(--color-success-bg); border-color: var(--color-success-border); color: var(--color-success); }
.alert--warning { background: var(--color-warning-bg); border-color: var(--color-warning-border); color: var(--color-warning); }
.alert--error   { background: var(--color-error-bg);   border-color: var(--color-error-border);   color: var(--color-error); }
/* An alert its page removes after a few seconds fades out first (bug 485: the sign-in account-settings banner). */
.alert--fades { transition: opacity 300ms ease-out; }
.alert--faded { opacity: 0; }
@media (prefers-reduced-motion: reduce) { .alert--fades { transition: none; } }

/* Pending-approval panel (UX1): the base .alert is a flex ROW (icon + text);
   this panel stacks its title / body / CTA vertically instead. */
.alert.pending-approval { flex-direction: column; align-items: flex-start; }

/* Pending-change banner (WS2): the alert may list several pending edits. Each
   is a self-contained block; a divider separates the second onward. */
.pending-change { width: 100%; padding-top: var(--space-2); }
.pending-change + .pending-change {
    margin-top: var(--space-2);
    border-top: 1px solid var(--color-border);
}
.pending-change__fields { margin: 0; display: flex; flex-direction: column; gap: 2px; }
.pending-change__field  { display: flex; gap: var(--space-2); font-size: var(--font-size-sm); }
.pending-change__label  { margin: 0; font-weight: var(--font-weight-semibold); min-width: 96px; }
.pending-change__value  { margin: 0; }
.pending-change__footer {
    display: flex; align-items: center; gap: var(--space-3);
    margin-top: var(--space-1);
}
.pending-change__meta   { font-size: var(--font-size-xs); color: var(--color-text-muted); }

/* ---- Avatar -------------------------------------------- */
.avatar {
    display: inline-flex; align-items: center; justify-content: center;
    width: 32px; height: 32px;
    border-radius: var(--radius-full);
    background: var(--avatar-bg);
    color: var(--avatar-text);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
    overflow: hidden;
    flex: 0 0 auto;
}
.avatar img { width: 100%; height: 100%; object-fit: cover; }
.avatar--sm { width: 24px; height: 24px; font-size: var(--font-size-xs); }
.avatar--lg { width: 40px; height: 40px; font-size: var(--font-size-md); }
.avatar--xl { width: 64px; height: 64px; font-size: var(--font-size-xl); }
.avatar-stack { display: inline-flex; align-items: center; }
.avatar-stack .avatar { border: 2px solid var(--avatar-border); }
.avatar-stack .avatar + .avatar { margin-left: -8px; }

/* ---- Filter chips -------------------------------------- */
.filter-chips { display: flex; gap: var(--space-2); flex-wrap: wrap; }
.filter-chip {
    display: inline-flex; align-items: center;
    padding: 4px 14px;
    border-radius: var(--radius-full);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
    border: 1.5px solid var(--color-border);
    background: var(--color-background-surface);
    color: var(--color-text-secondary);
    cursor: pointer;
    transition: background 120ms, color 120ms, border-color 120ms;
    white-space: nowrap;
    line-height: 1.4;
}
.filter-chip:hover {
    background: var(--color-background-sunken);
    color: var(--color-text-primary);
    border-color: var(--color-border-strong, var(--color-border));
}
.filter-chip--active {
    background: var(--color-primary);
    color: var(--color-primary-contrast);
    border-color: var(--color-primary);
}
.filter-chip--active:hover {
    background: var(--color-primary);
    color: var(--color-primary-contrast);
}

/* ---- Member cell (avatar stack + count) ---------------- */
.member-cell { display: flex; align-items: center; gap: var(--space-2); }
.member-count { font-size: var(--font-size-sm); color: var(--color-text-secondary); white-space: nowrap; }

/* ---- Table --------------------------------------------- */
.table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    background: var(--table-bg);
    font-size: var(--font-size-base);
}
.table th, .table td {
    padding: var(--table-cell-padding-y) var(--table-cell-padding-x);
    text-align: left;
    border-bottom: 1px solid var(--table-border);
    vertical-align: middle;
}
/* A data cell takes its row's colours. Bootstrap paints every cell white, black and with an inset shadow; those
   survived UI-1 phase G's layer because nothing of ours set them. */
.table td {
    background-color: transparent;
    color: inherit;
    box-shadow: none;
}
.table th {
    background: var(--table-header-bg);
    color: var(--table-header-text);
    font-weight: var(--font-weight-medium);
    font-size: var(--font-size-xs);
    text-transform: uppercase;
    letter-spacing: var(--letter-spacing-wide);
    position: sticky; top: 0;
}
/* A header row that stays in view while a long table scrolls inside its card (UI-1 I2; was inline on six tables). */
.table__head--sticky {
    position: sticky;
    top: 0;
    z-index: 1;
    background-color: var(--color-background-surface);
    box-shadow: 0 1px 2px color-mix(in srgb, var(--black) 8%, transparent);
}
/* The narrow column that holds a row's icon or actions. */
.table__col-icon { width: 48px; }
/* A column sized for a date or a short status, and one that shrinks to its content (UI-1 I2). */
.table__col-date { width: 180px; }
.table__col-status { width: 140px; }
.table__col-shrink { width: 1%; }

.table tbody tr {
    transition: background-color var(--motion-fast) var(--motion-ease);
}
.table tbody tr:hover { background: var(--table-row-hover-bg); }
/* On the cells too: the end-user portal's vendor table rules paint every cell, which hid the row's own hover. */
.table tbody tr:hover > td { background: var(--table-row-hover-bg); }
/* Rows that open a record (UI-1 D14): the hand cursor, and a visible focus for keyboard users, who reach the
   row with Tab (tabindex="0") and open it with Enter (Shared/js/clickable-rows.js). */
.table--clickable-rows tbody tr { cursor: pointer; }
.table--clickable-rows tbody tr:focus-visible { outline: 2px solid var(--color-border-focus); outline-offset: -2px; }
.table--clickable-rows tbody tr:focus-visible > td { background: var(--table-row-hover-bg); }

/* ---- Tabs ---------------------------------------------- */
.tabs {
    display: flex; gap: 2px;
    border-bottom: 1px solid var(--color-border);
    padding: 0 var(--space-1);
    position: relative;        /* anchor for .tabs__indicator */
}
.tab {
    display: inline-flex; align-items: center;
    padding: 8px var(--space-3);
    background: transparent;
    border: 0;
    border-bottom: 2px solid transparent;
    color: var(--color-text-muted);
    font-family: inherit;
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-medium);
    cursor: pointer;
    margin-bottom: -1px;
    transition: color var(--motion-base);
    white-space: nowrap;
}
.tab:hover { color: var(--color-text-primary); }
.tab-count {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 18px; height: 18px;
    padding: 0 5px;
    margin-left: 6px;
    border-radius: var(--radius-full);
    background: var(--color-background-sunken);
    color: var(--color-text-secondary);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    line-height: 18px;
    flex-shrink: 0;
}
.tab.active .tab-count, .tab[aria-selected="true"] .tab-count {
    background: var(--color-primary-soft);
    color: var(--color-primary-soft-text);
}
.tab[aria-selected="true"], .tab.active {
    color: var(--color-text-primary);
    border-bottom-color: var(--color-primary); /* CSS fallback; indicator overlaps when JS runs */
}
/* Sliding underline indicator — positioned by tab-indicator.js */
.tabs__indicator {
    position: absolute;
    bottom: -1px;              /* overlaps container border-bottom */
    left: 0;
    width: 0;
    height: 2px;
    background: var(--color-primary);
    border-radius: var(--radius-full);
    opacity: 0;
    pointer-events: none;
    z-index: 1;
    transition: left var(--motion-base) var(--motion-ease-out),
                width var(--motion-base) var(--motion-ease-out),
                opacity var(--motion-fast);
}

/* ---- Breadcrumb / Pagination --------------------------- */
.breadcrumb {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}
.breadcrumb__sep { color: var(--color-text-disabled); }
.breadcrumb a { color: var(--color-text-secondary); }
.breadcrumb a:hover { color: var(--color-text-primary); }
.breadcrumb__current { color: var(--color-text-primary); font-weight: var(--font-weight-medium); }

.pagination { display: inline-flex; gap: 2px; }
.pagination .page {
    min-width: 28px; height: 28px;
    padding: 0 8px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: var(--radius-sm);
    background: transparent;
    border: 1px solid transparent;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    cursor: pointer;
}
.pagination .page:hover { background: var(--color-secondary); }
.pagination .page.active {
    background: var(--color-primary-soft);
    color: var(--color-primary-soft-text);
}

/* ---- Tooltip / Popover --------------------------------- */
.tooltip {
    background: var(--tooltip-bg); color: var(--tooltip-text);
    padding: var(--tooltip-padding);
    border-radius: var(--tooltip-radius);
    font-size: var(--tooltip-font-size);
    font-weight: var(--font-weight-medium);
    box-shadow: var(--shadow-md);
    pointer-events: none;
}
.popover {
    background: var(--popover-bg);
    border: 1px solid var(--popover-border);
    border-radius: var(--popover-radius);
    box-shadow: var(--popover-shadow);
    padding: var(--space-2);
    min-width: 180px;
}

/* A popover dropped below the control that opened it, inside a positioned parent (a filter's checklist). */
.popover--dropdown {
    position: absolute;
    z-index: 30;
    margin-top: var(--space-1);
    max-height: 320px;
    overflow-y: auto;
}

/* ---- Modal: see E28Dialog (Shared/Components), the one dialog in both portals (UI-1 H6b). ---- */

/* ---- Drawer (right-anchored side panel) --------------- */
.drawer-overlay {
    position: fixed;
    inset: 0;
    background: var(--modal-overlay);
    z-index: var(--layout-z-modal);
    /* click-through cursor so users know the backdrop is interactive */
    cursor: default;
}
.drawer {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    width: 480px;
    max-width: 100vw;
    background: var(--modal-bg);
    border-left: 1px solid var(--color-border);
    box-shadow: -8px 0 32px color-mix(in srgb, var(--black) 14%, transparent);
    display: flex;
    flex-direction: column;
    z-index: calc(var(--layout-z-modal) + 1);
    outline: none; /* suppress visible focus ring on the container */
}
.drawer__header {
    flex-shrink: 0;
    padding: var(--space-5);
    border-bottom: 1px solid var(--color-border-subtle);
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
}
.drawer__header-icon {
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    border-radius: var(--radius-md);
    background: var(--color-primary-soft);
    color: var(--color-primary-soft-text);
    display: flex;
    align-items: center;
    justify-content: center;
}
.drawer__header-text { flex: 1; min-width: 0; }
.drawer__title {
    font-size: var(--font-size-md);
    font-weight: 600;
    color: var(--color-text-primary);
    margin: 0 0 3px;
}
.drawer__subtitle {
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    margin: 0;
}
.drawer__body {
    flex: 1;
    overflow-y: auto;
    padding: var(--space-5);
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
}
.drawer__footer {
    flex-shrink: 0;
    padding: var(--space-4) var(--space-5);
    border-top: 1px solid var(--color-border-subtle);
    background: var(--color-background-sunken);
    display: flex;
    align-items: center;
    gap: var(--space-2);
}
.drawer__esc-hint {
    flex: 1;
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    display: flex;
    align-items: center;
    gap: var(--space-1);
}
/* textarea reuses the same .input token as <input> but needs height reset.
   The base .input rule sets `padding: 0 var(--input-padding-x)` (zero vertical
   padding) which is correct for a fixed-height single-line input but leaves a
   multi-line textarea's text flush against the top border — so re-apply
   vertical padding here. */
textarea.input {
    height: auto;
    resize: vertical;
    line-height: var(--line-height-normal, 1.5);
    padding: 8px var(--input-padding-x);
}

/* ---- Drawer content blocks ----------------------------- */
/* Sections inside a .drawer__body. The body is already a flex column with a
   --space-5 gap, so sections only own their internal rhythm and divider. */
.drawer-section + .drawer-section {
    border-top: 1px solid var(--color-border-subtle);
    padding-top: var(--space-5);
}
.drawer-section__title {
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    margin: 0 0 var(--space-3);
}

/* Label/value pairs — the readable rendering of a request payload. */
.detail-list { margin: 0; }
.detail-list__row {
    display: grid;
    grid-template-columns: 96px 1fr;
    gap: var(--space-3);
    align-items: baseline;
    padding: var(--space-2) 0;
}
.detail-list__row + .detail-list__row {
    border-top: 1px solid var(--color-border-subtle);
}
.detail-list__label {
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    margin: 0;
}
.detail-list__value {
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium, 500);
    color: var(--color-text-primary);
    margin: 0;
    word-break: break-word;
}

/* Raw-JSON escape hatch for operations that have no payload describer yet. */

/* ---- Approval chain (vertical timeline) ---------------- */
.approval-chain {
    list-style: none;
    margin: 0;
    padding: 0;
}
.approval-chain__stage {
    position: relative;
    display: flex;
    gap: var(--space-3);
    padding-bottom: var(--space-4);
}
.approval-chain__stage:last-child { padding-bottom: 0; }

/* The rail connecting one marker to the next. Drawn from each stage except the
   last, behind the markers (which carry their own background). */
.approval-chain__stage:not(:last-child)::before {
    content: "";
    position: absolute;
    left: 11px;              /* marker centre: 24px / 2 - 1px */
    top: 24px;
    bottom: 0;
    width: 2px;
    background: var(--color-border);
}
/* A completed stage's rail is filled — progress reads at a glance. */
.approval-chain__stage.is-complete:not(:last-child)::before {
    background: var(--color-success, var(--green-500));
}

.approval-chain__marker {
    position: relative;
    z-index: 1;
    flex: 0 0 auto;
    width: 24px;
    height: 24px;
    border-radius: var(--radius-full);
    display: flex;
    align-items: center;
    justify-content: center;
    border: 2px solid var(--color-border);
    background: var(--color-background-surface);
    color: var(--color-text-muted);
}
.approval-chain__stage.is-complete .approval-chain__marker {
    background: var(--color-success, var(--green-500));
    border-color: var(--color-success, var(--green-500));
    color: var(--neutral-0);
}
.approval-chain__stage.is-current .approval-chain__marker {
    background: var(--color-primary-soft);
    border-color: var(--color-primary);
    color: var(--color-primary-soft-text);
}

.approval-chain__body { flex: 1; min-width: 0; padding-top: 1px; }
.approval-chain__label {
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
    color: var(--color-text-primary);
}
.approval-chain__stage.is-pending .approval-chain__label {
    color: var(--color-text-secondary);
}
.approval-chain__approvers {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    margin-top: 3px;
}
.approval-chain__approver {
    font-size: var(--font-size-xs);
    color: var(--color-text-secondary);
    background: var(--color-background-sunken);
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-full);
    padding: 1px 8px;
}
.approval-chain__status {
    display: inline-block;
    margin-top: var(--space-2);
    font-size: var(--font-size-xs);
}
.approval-chain__status--complete { color: var(--color-success, var(--green-500)); }
.approval-chain__status--current  { color: var(--color-primary-soft-text); font-weight: var(--font-weight-semibold); }
.approval-chain__status--pending  { color: var(--color-text-muted); }

/* ---- Decision history ---------------------------------- */
.decision-history {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
.decision-history__item {
    padding: var(--space-3);
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-md);
    background: var(--color-background-sunken);
}
.decision-history__line {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    font-size: var(--font-size-sm);
}
.decision-history__meta {
    font-size: var(--font-size-xs);
    margin-top: 2px;
}
.decision-history__comment {
    margin-top: var(--space-2);
    padding-left: var(--space-3);
    border-left: 2px solid var(--color-border);
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
    font-style: italic;
}

/* ---- Progress / Skeleton ------------------------------- */
.progress {
    width: 100%; height: 6px;
    background: var(--color-secondary);
    border-radius: var(--radius-full);
    overflow: hidden;
}
.skeleton {
    background: linear-gradient(90deg,
        var(--color-secondary) 0%,
        var(--color-secondary-hover) 50%,
        var(--color-secondary) 100%);
    background-size: 200% 100%;
    border-radius: var(--radius-sm);
    animation: skeleton-shimmer 1.4s linear infinite;
}
@keyframes skeleton-shimmer {
    0%   { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}

/* A heading-sized placeholder line (UI-1 phase D: used on seven screens, defined nowhere). */
.skeleton--heading { height: 1.25rem; width: 30%; }
.skeleton--field { height: var(--input-height-md); }

/* ---- Spinner -------------------------------------------
   A button's loading state (E28Button and four Admin pages; used, never defined, until UI-1 phase D).
   Drawn in the text colour, so it reads on any button. */
.spinner {
    display: inline-block;
    flex: 0 0 auto;
    width: 1em;
    height: 1em;
    border: 2px solid color-mix(in srgb, currentColor 30%, transparent);
    border-top-color: currentColor;
    border-radius: 50%;
    animation: spinner-turn 0.7s linear infinite;
}
@keyframes spinner-turn { to { transform: rotate(360deg); } }

/* ---- Divider ------------------------------------------- */
.divider { height: 1px; background: var(--color-border); border: 0; }

/* ---- Kbd ----------------------------------------------- */
kbd, .kbd {
    display: inline-flex; align-items: center;
    padding: 1px 5px;
    background: var(--color-background-sunken);
    border: 1px solid var(--color-border);
    border-bottom-width: 2px;
    border-radius: var(--radius-xs);
    font-family: var(--font-family-mono);
    font-size: var(--font-size-xs);
    color: var(--color-text-secondary);
    line-height: 1.2;
}

/* ---- Utilities ----------------------------------------- */
.u-stack-4 { display: flex; flex-direction: column; gap: var(--space-4); }
.u-text-muted { color: var(--color-text-muted); }

/* Layout and spacing utilities (UI-1 H6, replacing Bootstrap's). Spacing is the design system's scale: -1 4px,
   -2 8px, -3 14px, -5 24px. They are !important, as Bootstrap's were: a utility on an element says "this, here",
   and must beat the component's own rule whatever order the stylesheets load in. */
.u-flex          { display: flex !important; }
.u-wrap          { flex-wrap: wrap !important; }
.u-items-start   { align-items: flex-start !important; }
.u-items-center  { align-items: center !important; }
.u-items-end     { align-items: flex-end !important; }
.u-justify-between { justify-content: space-between !important; }
.u-gap-1 { gap: var(--space-1) !important; }
.u-gap-2 { gap: var(--space-2) !important; }
.u-gap-3 { gap: var(--space-3) !important; }
/* The shorthand first: a later u-mb-N / u-mt-N on the same element must win (all are !important). */
.u-m-0  { margin: 0 !important; }
.u-mb-0 { margin-bottom: 0 !important; }
.u-mb-1 { margin-bottom: var(--space-1) !important; }
.u-mb-2 { margin-bottom: var(--space-2) !important; }
.u-mb-3 { margin-bottom: var(--space-3) !important; }
.u-mb-5 { margin-bottom: var(--space-5) !important; }
.u-mt-1 { margin-top: var(--space-1) !important; }
.u-mt-2 { margin-top: var(--space-2) !important; }
.u-mt-3 { margin-top: var(--space-3) !important; }
.u-mt-5 { margin-top: var(--space-5) !important; }
.u-ms-0 { margin-inline-start: 0 !important; }
.u-ms-1 { margin-inline-start: var(--space-1) !important; }
.u-ms-2 { margin-inline-start: var(--space-2) !important; }
.u-ms-auto { margin-inline-start: auto !important; }   /* push to the far end of a row */
.u-p-0 { padding: 0 !important; }
.u-p-3 { padding: var(--space-3) !important; }
.u-text-start { text-align: start !important; }
.u-text-end   { text-align: end !important; }
.u-w-full     { width: 100% !important; }
.u-relative   { position: relative !important; }
/* UI-1 I2: the rest of the layout glue that pages wrote as inline styles. !important like the others, because the
   inline style they replace always won. */
.u-block       { display: block !important; }
.u-col         { flex-direction: column !important; }
.u-flex-1      { flex: 1 !important; }
.u-min-w-0     { min-width: 0 !important; }
.u-items-baseline { align-items: baseline !important; }
.u-justify-end { justify-content: flex-end !important; }
.u-gap-4 { gap: var(--space-4) !important; }
.u-mt-0 { margin-top: 0 !important; }
.u-mt-4 { margin-top: var(--space-4) !important; }
.u-mb-4 { margin-bottom: var(--space-4) !important; }
.u-p-4  { padding: var(--space-4) !important; }
.u-border-0 { border: 0 !important; }
.u-text-xs   { font-size: var(--font-size-xs) !important; }
.u-text-sm   { font-size: var(--font-size-sm) !important; }
.u-text-base { font-size: var(--font-size-base) !important; }
.u-text-md   { font-size: var(--font-size-md) !important; }
.u-text-lg   { font-size: var(--font-size-lg) !important; }
.u-weight-medium   { font-weight: var(--font-weight-medium) !important; }
.u-weight-semibold { font-weight: var(--font-weight-semibold) !important; }
.u-nowrap { white-space: nowrap !important; }
.u-italic { font-style: italic !important; }
.u-list-none { list-style: none !important; }
.u-hidden { display: none !important; }
.u-inline-block { display: inline-block !important; }
.u-shrink-0 { flex-shrink: 0 !important; }
/* A field or block's width cap: a short select (xs), a narrow field (sm), a dialog-sized block (md), and the
   readable measure for single-line inputs (lg, DESIGN_STANDARDS §13). */
.u-maxw-xs { max-width: 220px !important; }
.u-maxw-sm { max-width: 280px !important; }
.u-maxw-md { max-width: 420px !important; }
.u-maxw-lg { max-width: 600px !important; }
/* Read by screen readers, not drawn. */
.u-sr-only {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip: rect(0, 0, 0, 0) !important;
    white-space: nowrap !important;
    border: 0 !important;
}

/* A box of filters above a list or log (Security & Auditing). */
.filter-panel {
    background: var(--color-background-sunken);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--space-3);
    margin-bottom: var(--space-5);
}

/* A button that reads as a link: an inline action in a sentence or under a form ("Clear", "Show history"). */
.link-button {
    background: none;
    border: none;
    padding: 0;
    color: var(--color-primary-soft-text);
    text-decoration: none;
    cursor: pointer;
    font: inherit;
    position: relative;
    display: inline-block;
}

    .link-button::after {
        content: "";
        position: absolute;
        left: 0;
        bottom: -4px;
        width: 100%;
        height: 1px;
        background: var(--color-primary);
        opacity: 0;
        transform: scaleX(0.8);
        transition: all var(--motion-base) ease-out;
    }

    .link-button:hover::after,
    .link-button:focus::after {
        opacity: 1;
        transform: scaleX(1);
    }

    /* Focus states for accessibility */
    .link-button:focus-visible {
        outline: 2px solid var(--color-primary);
        outline-offset: 4px;
        border-radius: 2px;
    }
.u-text-mono { font-family: var(--font-family-mono); }
.u-truncate { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* A Company Settings tab (contact details, tax numbers, an office location): a capped column of sections, the sections
   in a grid of cards, each with a title row (UI-1 I2; three editors had it inline, two at 980px and one at 880px). */
.settings-stack {
    max-width: 980px;
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
}
.settings-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: var(--space-5);
}
.settings-section__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    min-height: 1.5rem;
}
.settings-section__title {
    margin: 0;
    font-size: var(--font-size-md);
    font-weight: var(--font-weight-semibold);
    min-height: 1.5rem;
}
/* Company Settings' own tabs (company details, branding): one column, narrower. */
.settings-stack--narrow { max-width: 640px; gap: var(--space-4); }

/* A card header that is a button (expands its card): no button chrome. */
.card__header--toggle {
    background: none;
    border: none;
    cursor: pointer;
}

/* An alert that stays in view at the top of a long form. */
.alert--sticky { position: sticky; top: 0; z-index: 5; }

/* The count after a filter chip's label. */
.filter-chip__count { margin-left: var(--space-1); opacity: 0.6; }

/* A round avatar-sized placeholder. */
.skeleton--avatar { display: block; width: 32px; height: 32px; border-radius: 50%; flex-shrink: 0; }

/* ---------------------------------------------------------
   Base rules for both portals: page scrolling, the Blazor error bar, the page transition, read-only
   inputs. They sat in the public-site block that was pasted in here; UI-1 phase B moved that block to
   the end-user portal and kept these, which every page relies on.
--------------------------------------------------------- */

html {
    scroll-behavior: smooth;
    overflow-y: scroll; /* Prevent layout shift when scrollbar appears */
}

/* ---------------------------------------------------------
   3. Blazor Error UI
--------------------------------------------------------- */

#blazor-error-ui {
    background: var(--color-warning-bg);
    border-top: 2px solid var(--color-warning-border);
    bottom: 0;
    box-shadow: 0 -2px 8px color-mix(in srgb, var(--black) 10%, transparent);
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 10000;
    font-size: 0.9rem;
    color: var(--color-warning);
}

    #blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 50%;
        transform: translateY(-50%);
        font-size: var(--font-size-lg);
        font-weight: 700;
        line-height: 1;
        color: var(--color-warning);
        opacity: 0.7;
        transition: opacity var(--motion-base) ease-out;
    }

        #blazor-error-ui .dismiss:hover {
            opacity: 1;
        }

/* ---------------------------------------------------------
   7. Page Transitions
--------------------------------------------------------- */

.page-transition {
    animation: pageFadeIn 180ms ease-out;
}

@keyframes pageFadeIn {
    from {
        opacity: 0;
        transform: translateY(4px);
    }

    to {
        opacity: 1;
        transform: translateY(0);
    }
}

input[readonly] {
    background-color: var(--neutral-50);
    cursor: not-allowed;
}

/* ---------------------------------------------------------
   . Accessibility & Focus States
--------------------------------------------------------- */

/* Ensure all interactive elements have visible focus states */
a:focus-visible,
button:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
    border-radius: 2px;
}

/* Reduce motion for users who prefer it */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* High contrast mode support */
@media (prefers-contrast: high) {
    :root {
        --color-border: rgba(0, 0, 0, 0.2);
    }
}

/* =========================================================================
   Eight28 D4 App Shell layout
   -------------------------------------------------------------------------
   Page-level layout consumed by Layouts/AppShell.razor + Sidebar.razor +
   Topbar.razor. Tokens only.

   --app-shell-header-height is the single source of truth for the chrome
   row height — the sidebar brand block and the topbar both pin to it so
   their bottom dividers line up at the same Y.
   ========================================================================= */

:root {
    --app-shell-header-height: 52px;
}

.app-shell {
    display: flex;
    min-height: 100vh;
    background: var(--color-background-page);
}

.app-shell__main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

/* ---------- Sidebar ---------- */
.sidebar {
    width: 232px;
    flex: 0 0 232px;
    background: var(--color-background-surface);
    border-right: 1px solid var(--color-border);
    display: flex;
    flex-direction: column;
    height: 100vh;
    position: sticky;
    top: 0;
    transition: flex-basis var(--motion-base) var(--motion-ease),
                width var(--motion-base) var(--motion-ease);
}

.sidebar--collapsed {
    width: 64px;
    flex: 0 0 64px;
}

/* Focusable (tabindex -1) only so the phone drawer can take focus as a last resort (SHELL.01). */
.sidebar:focus {
    outline: none;
}

.sidebar--collapsed .sidebar__brand-name,
.sidebar--collapsed .nav-item__label,
.sidebar--collapsed .nav-group__title,
.sidebar--collapsed .sidebar__user-meta { display: none; }

.sidebar__brand {
    height: var(--app-shell-header-height);
    flex: 0 0 var(--app-shell-header-height);
    padding: 0 var(--space-4);
    border-bottom: 1px solid var(--color-border-subtle);
    display: flex;
    align-items: center;
    gap: 10px;
    font-family: var(--font-family-heading);
    font-weight: 700;
    letter-spacing: -0.01em;
}

.sidebar__brand-mark {
    width: 24px; height: 24px;
    border-radius: 6px;
    background: var(--color-primary); color: var(--color-primary-contrast);
    display: grid; place-items: center;
    font-weight: 800; font-size: var(--font-size-sm);
    flex: 0 0 auto;
}

.sidebar__brand-logo {
    max-height: 32px;
    max-width: 120px;
    width: auto;
    height: auto;
    object-fit: contain;
    flex: 0 0 auto;
}

.sidebar__brand-name {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sidebar__tenant {
    padding: 10px var(--space-3);
    margin: 8px;
    border-radius: var(--radius-md);
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: var(--font-size-sm);
    cursor: pointer;
    transition: background var(--motion-fast);
}

.sidebar__tenant:hover { background: var(--color-background-sunken); }

.sidebar__nav {
    flex: 1;
    overflow-y: auto;
    padding: 8px;
}

.nav-group { margin-bottom: var(--space-3); }

.nav-group__title {
    font-size: var(--font-size-xs);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--color-text-muted);
    font-weight: 600;
    padding: 8px 10px 6px;
}

.nav-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 10px;
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
    color: var(--color-text-secondary);
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: all var(--motion-fast);
    text-decoration: none;
}

/* A nav item's icon is a LucideIcon in both portals (UI-1 H6; the end-user sidebar drew Font Awesome's). */
.nav-item .lucide {
    flex: 0 0 auto;
    color: var(--color-text-muted);
}

/* Pending-count pill on a nav item (e.g. My Approvals). Mirrors
   .notification-bell__badge — small circular danger badge — but sits
   inline at the right end of the row via margin-left:auto. Stays visible
   in the collapsed sidebar since only the text label is hidden there. */
.nav-item__badge {
    margin-left: auto;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    background: var(--color-danger);
    color: var(--neutral-0);
    border-radius: 999px;
    font-size: var(--font-size-xs);
    font-weight: 600;
    line-height: 18px;
    text-align: center;
    pointer-events: none;
}

.nav-item:hover {
    background: var(--color-background-sunken);
    color: var(--color-text-primary);
}

.nav-item:hover .lucide { color: var(--color-text-primary); }

.nav-item.active {
    background: var(--color-primary-soft);
    color: var(--color-primary-soft-text);
    font-weight: 500;
}

.nav-item.active .lucide { color: var(--color-primary-soft-text); }

.sidebar__user {
    padding: 10px var(--space-3);
    border-top: 1px solid var(--color-border-subtle);
    display: flex;
    align-items: center;
    gap: 10px;
}

.sidebar__user-meta { flex: 1; min-width: 0; }

.sidebar__user-name {
    font-size: var(--font-size-sm);
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sidebar__user-email {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Collapse / expand toggle.
   Expanded, it is a small icon button beside the user block. Collapsed, the
   user meta is hidden and the sidebar narrows to 64px, which left only a bare
   chevron to click — too small to find, and the only way back out. Collapsed,
   the footer stacks and the toggle claims the full width at a 40px row height
   so the whole strip is the target. */
.sidebar__collapse-toggle {
    flex: 0 0 auto;
}

.sidebar--collapsed .sidebar__user {
    flex-direction: column;
    gap: var(--space-2);
    padding: 10px var(--space-2);
}

.sidebar--collapsed .sidebar__collapse-toggle--expand {
    width: 100%;
    min-height: 40px;
    font-size: var(--font-size-lg);
    line-height: 1;
    border-radius: var(--radius-md);
}

/* ---------- Topbar ---------- */
.topbar {
    height: var(--app-shell-header-height);
    background: var(--color-background-surface);
    border-bottom: 1px solid var(--color-border);
    display: flex;
    align-items: center;
    padding: 0 var(--space-5);
    gap: var(--space-4);
    position: sticky;
    top: 0;
    z-index: 10;
}

/* Stretch the breadcrumb to fill the topbar's full height and
   center its content there. Without this, the breadcrumb only
   takes its intrinsic line-height and visually drifts toward
   the top of the row even though the flex parent has
   align-items:center — small font + tight line-height makes
   the eye perceive it as top-aligned. */
.topbar .breadcrumb {
    align-self: stretch;
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
}

.topbar .breadcrumb a {
    color: var(--color-text-secondary);
    text-decoration: none;
}

.topbar .breadcrumb a:hover { color: var(--color-text-primary); }

.topbar .breadcrumb__sep { color: var(--color-text-disabled); padding: 0 2px; }

.topbar .breadcrumb__current {
    color: var(--color-text-primary);
    font-weight: 500;
}

.topbar__search {
    flex: 1;
    max-width: 480px;
    position: relative;
}

.topbar__search .input {
    width: 100%;
    height: 32px;
    padding: 0 36px 0 32px;
    background: var(--color-background-sunken);
    font-size: var(--font-size-sm);
}

.topbar__search .search-icon {
    position: absolute;
    left: 10px;
    top: 50%;
    transform: translateY(-50%);
    font-size: var(--font-size-base);
    color: var(--color-text-muted);
    pointer-events: none;
}

.topbar__search-kbd {
    position: absolute;
    right: 8px;
    top: 50%;
    transform: translateY(-50%);
    font-size: var(--font-size-xs);
    padding: 2px 6px;
    background: var(--color-background-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-xs);
    color: var(--color-text-muted);
    font-family: var(--font-family-mono);
}

.topbar__actions {
    display: flex;
    gap: 6px;
    align-items: center;
    margin-left: auto;
    position: relative;
}

.topbar__user-menu {
    position: absolute;
    top: 100%;
    right: 0;
    margin-top: 8px;
    min-width: 220px;
    background: var(--color-background-elevated);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    padding: 6px;
    z-index: 20;
}

.topbar__user-menu-header {
    padding: 8px 10px;
    border-bottom: 1px solid var(--color-border-subtle);
    margin-bottom: 4px;
}

.topbar__user-menu-name { font-weight: 600; font-size: var(--font-size-sm); }
.topbar__user-menu-email { font-size: var(--font-size-xs); color: var(--color-text-muted); }

.topbar__user-menu-item {
    display: block;
    width: 100%;
    text-align: left;
    padding: 8px 10px;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--color-text-primary);
    border: 0;
    font-family: inherit;
    font-size: var(--font-size-sm);
    cursor: pointer;
}

.topbar__user-menu-item:hover { background: var(--color-background-sunken); }

/* ---------- Notification bell ----------
   Bell button styling matches the other ghost icon buttons in the topbar
   via E28Button — no border reset needed here. Below is the dropdown and
   badge styling. Dropdown items use consistent horizontal padding (10px)
   so nothing sits flush against the panel edge. */
.notification-bell {
    position: relative;
}

.notification-bell__button {
    /* The button itself is rendered via E28Button (btn btn--ghost btn--sm
       btn--icon). The wrapper here gives the badge an anchor — see below. */
    position: relative;
}

.notification-bell__badge {
    position: absolute;
    top: -2px;
    right: -2px;
    min-width: 18px;
    height: 18px;
    padding: 0 4px;
    background: var(--color-danger);
    color: var(--neutral-0);
    border-radius: 999px;
    font-size: var(--font-size-xs);
    font-weight: 600;
    line-height: 18px;
    text-align: center;
    pointer-events: none;
}

.notification-bell__dropdown {
    position: absolute;
    top: 100%;
    right: 0;
    margin-top: 8px;
    width: 360px;
    max-height: 480px;
    overflow-y: auto;
    z-index: 20;
}

.notification-bell__section {
    padding: 8px 0;
    border-bottom: 1px solid var(--color-border-subtle);
}

.notification-bell__section:last-of-type {
    border-bottom: 0;
}

.notification-bell__item {
    display: block;
    width: 100%;
    text-align: left;
    padding: 8px 12px;
    background: transparent;
    border: 0;
    font-family: inherit;
    font-size: var(--font-size-sm);
    color: var(--color-text-primary);
    cursor: pointer;
}

.notification-bell__item:hover {
    background: var(--color-background-sunken);
}

.notification-bell__item-title {
    font-weight: 500;
}

.notification-bell__item-meta {
    margin-top: 2px;
    font-size: var(--font-size-xs);
}

/* Batch 4 story 10: Snooze and Mark as done under a reminder. */
.notification-bell__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    padding: 0 12px 8px;
}

.notification-bell__action {
    padding: 2px 8px;
    border: 1px solid var(--color-border-subtle);
    border-radius: 999px;
    background: transparent;
    font-family: inherit;
    font-size: var(--font-size-xs);
    color: var(--color-text-primary);
    cursor: pointer;
    transition: background-color 150ms ease-out, border-color 150ms ease-out;
}

.notification-bell__action:hover:not(:disabled) {
    background: var(--color-background-sunken);
    border-color: var(--color-primary);
}

.notification-bell__action:disabled {
    opacity: 0.6;
    cursor: progress;
}

.notification-bell__empty {
    padding: 8px 12px;
    font-size: var(--font-size-sm);
}

.notification-bell__footer {
    padding: 8px 12px;
    border-top: 1px solid var(--color-border-subtle);
    font-size: var(--font-size-sm);
}

.notification-bell__footer a {
    color: var(--color-text-link);
}

/* ---------- Content area ---------- */
.app-shell .content {
    flex: 1;
    padding: var(--space-5) var(--space-6);
    overflow-x: hidden;
}

/* ---------- Phone widths (SHELL.01) ----------
   Below the app's 768 px breakpoint the sidebar becomes an off-canvas drawer opened from the
   topbar's menu button, over a backdrop; the page takes the full width. Layout is CSS-driven
   (it is right from the first paint); AppShell.razor owns open/closed and app-shell.js the
   focus trap, Esc and scroll lock. At 768 px and above none of this applies. */
.topbar__menu-button,
.sidebar__close,
.shell-backdrop,
.breadcrumb__compact {
    display: none;
}

@media (max-width: 768px) {
    .sidebar,
    .sidebar--collapsed {
        position: fixed;
        top: 0;
        left: 0;
        z-index: calc(var(--layout-z-modal) + 1);
        width: min(300px, 85vw);
        flex: none;
        height: 100vh;
        height: 100dvh;
        box-shadow: var(--shadow-lg);
        transform: translateX(-100%);
        /* Hidden (so its links can't be tabbed to or read out) once the slide-out finishes. */
        visibility: hidden;
        transition: transform var(--motion-base) var(--motion-ease-out),
                    visibility 0s linear var(--motion-base);
    }

    .sidebar.is-open {
        transform: translateX(0);
        visibility: visible;
        transition: transform var(--motion-base) var(--motion-ease-out), visibility 0s;
    }

    /* The drawer always shows full labels; the desktop collapse toggle gives way to Close. */
    .sidebar__collapse-toggle {
        display: none;
    }

    .sidebar__close {
        display: inline-flex;
        margin-left: auto;
        flex: 0 0 auto;
    }

    .shell-backdrop {
        display: block;
        position: fixed;
        inset: 0;
        z-index: var(--layout-z-modal);
        background: var(--modal-overlay);
        animation: shell-backdrop-in var(--motion-base) var(--motion-ease-out);
    }

    .topbar {
        height: auto;
        min-height: var(--app-shell-header-height);
        flex-wrap: wrap;
        padding: 0 var(--space-3);
        gap: var(--space-2);
    }

    .topbar__menu-button {
        display: inline-flex;
    }

    /* The breadcrumb shrinks to the current page's name. */
    .topbar .breadcrumb {
        flex: 1;
        min-width: 0;
        overflow: hidden;
    }

    .topbar .breadcrumb > * {
        display: none;
    }

    .topbar .breadcrumb > .breadcrumb__compact {
        display: block;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        color: var(--color-text-primary);
        font-weight: 500;
    }

    /* The trial banner, when shown, takes its own line under the topbar row. */
    .topbar .trial-banner {
        order: 10;
        flex-basis: 100%;
        margin-bottom: var(--space-2);
    }

    /* Menus from the topbar open within the screen. */
    .topbar__user-menu,
    .notification-bell__dropdown {
        position: fixed;
        top: calc(var(--app-shell-header-height) + 4px);
        left: var(--space-2);
        right: var(--space-2);
        width: auto;
        min-width: 0;
        margin-top: 0;
    }

    .app-shell .content {
        padding: var(--space-4) var(--space-3);
    }
}

@keyframes shell-backdrop-in {
    from { opacity: 0; }
    to { opacity: 1; }
}

/* While the drawer is open the page behind it stays put. */
html.shell-drawer-open,
html.shell-drawer-open body {
    overflow: hidden;
}

/* Page-level structural helpers — used by app pages */
.page-pad {
    /* Alias used by pages that want to opt in to standard content spacing.
       The .content wrapper already provides padding; .page-pad is a
       semantic grouping wrapper, not a spacing addition. */
}

/* The page header (PageHeader.razor, UI-1 D4): one per page, both portals. Title 30px in Ink; the icon sits
   in a box of the primary colour and is drawn in its contrast colour, so a tenant's own colour stays legible;
   the page's primary action sits top-right. */
.page-header {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    margin-bottom: var(--space-5);
}

.page-header__icon {
    width: 40px;
    height: 40px;
    border-radius: var(--radius-lg);
    background: var(--color-primary);
    color: var(--color-primary-contrast);
    display: grid;
    place-items: center;
    flex: 0 0 auto;
}

.page-header__text {
    flex: 1 1 auto;
    min-width: 0;
}

/* A record's secondary facts under its subtitle (a group's member count). */
.page-header__meta {
    margin-top: var(--space-1);
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
}

/* The title, with a record's badges beside it (outside the h1). */
.page-header__title-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
}

/* A monogram in the icon box (a record's first letter). */
.page-header__icon {
    font-family: var(--font-family-heading);
    font-size: var(--font-size-md);
    font-weight: var(--font-weight-bold);
}

.page-header__title {
    margin: 0;
    font-family: var(--font-family-heading);
    font-size: var(--font-size-2xl);
    font-weight: var(--font-weight-extrabold);
    font-stretch: var(--font-stretch-display);
    color: var(--color-text-primary);
    letter-spacing: var(--letter-spacing-tight);
    line-height: var(--line-height-tight);
    outline: none;
}

.page-header__subtitle {
    margin: var(--space-1) 0 0;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
}

.page-header__actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex: 0 0 auto;
}

@media (max-width: 640px) {
    .page-header {
        flex-wrap: wrap;
    }

    .page-header__actions {
        width: 100%;
    }
}

/* ---------------------------------------------------------
   Empty State
   Used by EmptyState.razor to fill tables/lists with
   an illustration, explanation, and optional CTA so no
   surface is ever left blank.
   --------------------------------------------------------- */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
    padding: var(--space-10) var(--space-6);
    text-align: center;
}
.empty-state__icon {
    color: var(--color-text-disabled);
    line-height: 1;
}
.empty-state__title {
    font-size: var(--font-size-md);
    font-weight: var(--font-weight-semibold);
    color: var(--color-text-primary);
    margin: 0;
}
.empty-state__subtitle {
    font-size: var(--font-size-base);
    color: var(--color-text-muted);
    margin: 0;
    max-width: 340px;
    line-height: var(--line-height-relaxed);
}

/* ---------------------------------------------------------
   Dashboard Grid
   12-column CSS grid for the dashboard layout.
   --------------------------------------------------------- */

/* 12-column, auto-row CSS grid for the dashboard */
.dashboard-grid {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    grid-auto-rows: minmax(120px, auto);   /* rows grow with content */
    gap: var(--space-4);
    padding: var(--space-4) 0;
}

/* Widget cell — placed by grid-column / grid-row inline styles */
.dashboard-widget-cell {
    min-width: 0;   /* prevent overflow in narrow grid cells */
    min-height: 0;
}

/* Dashboard selector bar above the grid */
.dashboard-selector {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}
.dashboard-selector__label {
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    white-space: nowrap;
}

/* ---------------------------------------------------------
   Avatar — deterministic per-user colour palette
   8 hues; colour-N is chosen by hashing the display name.
   Each class overrides the --avatar-bg / --avatar-text
   variables declared on .avatar so all sizes inherit.
   --------------------------------------------------------- */
/* Solid, vibrant colours — white text on all. Same hue always maps to the
   same user via a display-name char-sum hash in UserAvatar.razor.          */
/* 0 Teal */
.avatar.avatar--color-0 { --avatar-bg: oklch(58% 0.155 185); --avatar-text: #fff; }
/* 1 Indigo */
.avatar.avatar--color-1 { --avatar-bg: oklch(52% 0.200 265); --avatar-text: #fff; }
/* 2 Rose */
.avatar.avatar--color-2 { --avatar-bg: oklch(56% 0.220 18);  --avatar-text: #fff; }
/* 3 Amber  (lighter so white still contrasts) */
.avatar.avatar--color-3 { --avatar-bg: oklch(66% 0.160 55);  --avatar-text: #fff; }
/* 4 Emerald */
.avatar.avatar--color-4 { --avatar-bg: oklch(60% 0.170 155); --avatar-text: #fff; }
/* 5 Violet */
.avatar.avatar--color-5 { --avatar-bg: oklch(52% 0.200 295); --avatar-text: #fff; }
/* 6 Sky */
.avatar.avatar--color-6 { --avatar-bg: oklch(56% 0.180 240); --avatar-text: #fff; }
/* 7 Fuchsia */
.avatar.avatar--color-7 { --avatar-bg: oklch(52% 0.210 330); --avatar-text: #fff; }

/* Dark mode — same hue, slightly lighter for brightness in dark UI */
[data-theme="dark"] .avatar.avatar--color-0 { --avatar-bg: oklch(62% 0.155 185); }
[data-theme="dark"] .avatar.avatar--color-1 { --avatar-bg: oklch(56% 0.200 265); }
[data-theme="dark"] .avatar.avatar--color-2 { --avatar-bg: oklch(60% 0.220 18);  }
[data-theme="dark"] .avatar.avatar--color-3 { --avatar-bg: oklch(70% 0.160 55);  }
[data-theme="dark"] .avatar.avatar--color-4 { --avatar-bg: oklch(64% 0.170 155); }
[data-theme="dark"] .avatar.avatar--color-5 { --avatar-bg: oklch(56% 0.200 295); }
[data-theme="dark"] .avatar.avatar--color-6 { --avatar-bg: oklch(60% 0.180 240); }
[data-theme="dark"] .avatar.avatar--color-7 { --avatar-bg: oklch(56% 0.210 330); }

/* ---------------------------------------------------------
   Breadcrumb — non-URL ancestor node
   --------------------------------------------------------- */
.breadcrumb__node {
    color: var(--color-text-secondary);
}

/* ---------------------------------------------------------
   Status dot — inline coloured circle for Active / Inactive
   --------------------------------------------------------- */

/* ---------------------------------------------------------
   Row actions — "..." overflow menu per table row
   --------------------------------------------------------- */
.row-actions {
    position: relative;
    display: inline-flex;
}

.row-actions__trigger {
    background: transparent;
    border: 0;
    padding: 2px 6px;
    border-radius: var(--radius-sm);
    color: var(--color-text-muted);
    font-size: var(--font-size-md);
    cursor: pointer;
    line-height: 1;
    transition: background var(--motion-fast) var(--motion-ease), color var(--motion-fast) var(--motion-ease);
}

.row-actions__trigger:hover {
    background: var(--color-background-sunken);
    color: var(--color-text-primary);
}

.row-actions__menu {
    position: absolute;
    right: 0;
    top: calc(100% + 4px);
    min-width: 160px;
    background: var(--color-background-elevated);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
    padding: 4px;
    z-index: 30;
}

.row-actions__item {
    display: flex;
    align-items: center;
    gap: var(--space-2);   /* an item may lead with an icon (the tax type card's menu) */
    width: 100%;
    text-align: left;
    padding: 7px 10px;
    border-radius: var(--radius-sm);
    background: transparent;
    border: 0;
    font-family: inherit;
    font-size: var(--font-size-sm);
    color: var(--color-text-primary);
    cursor: pointer;
    transition: background var(--motion-fast) var(--motion-ease), color var(--motion-fast) var(--motion-ease);
}

.row-actions__item:hover {
    background: var(--color-background-sunken);
}

.row-actions__item--danger {
    color: var(--color-danger);
}

.row-actions__item--danger:hover {
    background: var(--color-error-bg);
}

/* The menu is an absolutely-positioned child of the row, so any ancestor with
   a non-visible overflow clips it — which is why the last row's menu was cut
   off at the bottom of the card. Two ancestors do this:

     .card             — overflow: hidden, to clip header/footer fills to the
                         rounded corners.
     .table-responsive — Bootstrap sets overflow-x: auto, and CSS forces the
                         other axis to compute to auto when one axis is not
                         visible, so this clips vertically too.

   :has() scopes the opt-out to exactly the moment a menu is open: the
   .row-actions__menu element is only rendered while its row menu is expanded.
   Corner clipping and horizontal table scrolling are therefore unchanged in
   the normal (closed) state. Order matters — this must stay after the .card
   rule to win on equal specificity if the selectors ever converge. */
.card:has(.row-actions__menu),
.table-responsive:has(.row-actions__menu),
.card:has(.row-actions__confirm),
.table-responsive:has(.row-actions__confirm) {
    overflow: visible;
}

/* RowActions.razor (UI-1 D15/D16): Edit and Delete as icons. In a table row or list item they appear on hover or
   keyboard focus; on a touch screen (no hover) and anywhere else they are always shown. */
.row-actions {
    align-items: center;
    gap: var(--space-1);
}

.row-actions__icon {
    display: inline-grid;
    place-items: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--color-text-muted);
    text-decoration: none;
    cursor: pointer;
    transition: opacity var(--motion-base) ease-out, background var(--motion-base) ease-out, color var(--motion-base) ease-out;
}

.row-actions__icon:hover {
    background: var(--color-background-sunken);
    color: var(--color-text-primary);
}

/* The Delete icon's wrapper: it carries the tooltip, which a disabled button can't show. */
.row-actions__slot {
    display: inline-flex;
}

.row-actions__icon:disabled {
    opacity: 0.4;
    cursor: not-allowed;
    background: transparent;
    color: var(--color-text-muted);
}

/* D16: grey until hovered; red only as a warning that it deletes, and it still asks first. */
.row-actions__icon--delete:hover,
.row-actions__icon--delete[aria-expanded="true"] {
    background: var(--color-error-bg);
    color: var(--color-error);
}

@media (hover: hover) {
    :is(tr, li) .row-actions__icon:not(:disabled) {
        opacity: 0;
    }

    :is(tr, li):hover .row-actions__icon:not(:disabled),
    :is(tr, li):focus-within .row-actions__icon:not(:disabled),
    :is(tr, li) .row-actions--open .row-actions__icon:not(:disabled) {
        opacity: 1;
    }

    :is(tr, li) .row-actions__icon:disabled {
        opacity: 0;
    }

    :is(tr, li):hover .row-actions__icon:disabled,
    :is(tr, li):focus-within .row-actions__icon:disabled {
        opacity: 0.4;
    }
}

.row-actions__backdrop {
    position: fixed;
    inset: 0;
    z-index: 29;
    cursor: default;
}

.row-actions__confirm {
    position: absolute;
    right: 0;
    top: calc(100% + 4px);
    z-index: 30;
    width: max-content;
    max-width: 280px;
    padding: var(--space-3);
    background: var(--color-background-elevated);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
    text-align: left;
    white-space: normal;
    cursor: default;
}

.row-actions__confirm-text {
    margin: 0 0 var(--space-3);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
    color: var(--color-text-primary);
}

.row-actions__confirm-actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-2);
}

/* ---------------------------------------------------------
   Group Detail — Permissions tab
   3-state segmented control (None / View / Full) + banner
   --------------------------------------------------------- */

/* Segmented control container */
.permission-segmented {
    display: inline-flex;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    overflow: hidden;
    flex-shrink: 0;
}

/* Each button in the segmented control */
.permission-segmented__btn {
    padding: 5px 14px;
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
    background: var(--color-background-surface);
    color: var(--color-text-secondary);
    border: none;
    cursor: pointer;
    line-height: 1.4;
    white-space: nowrap;
    transition: background 0.1s, color 0.1s;
}
.permission-segmented__btn + .permission-segmented__btn {
    border-left: 1px solid var(--color-border);
}
.permission-segmented__btn--active {
    background: var(--color-primary);
    color: var(--color-primary-contrast);
    font-weight: var(--font-weight-semibold);
}
.permission-segmented__btn:hover:not(.permission-segmented__btn--active):not(:disabled) {
    background: var(--color-background-sunken);
    color: var(--color-text-primary);
}
.permission-segmented__btn:disabled {
    cursor: not-allowed;
    opacity: 0.45;
}

/* Read-only variant — used to *display* an inherited level (e.g. a user's
   effective permissions, which come from their groups and aren't edited
   here). The active segment stays full-strength; the rest are quietly
   muted; nothing dims or shows a not-allowed cursor. */
.permission-segmented--readonly .permission-segmented__btn:disabled {
    cursor: default;
    opacity: 1;
}
.permission-segmented--readonly .permission-segmented__btn:disabled:not(.permission-segmented__btn--active) {
    color: var(--color-text-muted);
}

/* ---------------------------------------------------------
   Approval-workflow editor — stage card chrome
   --------------------------------------------------------- */

/* "Stage N" pill in the stage card header */
.stage-badge {
    display: inline-block;
    background: var(--color-primary);
    color: var(--color-primary-contrast);
    font-weight: var(--font-weight-bold);
    font-size: var(--font-size-sm);
    padding: 3px 10px;
    border-radius: var(--radius-sm);
}

/* Stage header control buttons — distinct affordances by colour:
   reorder (neutral grey), collapse (soft blue), remove (soft red). */
.stage-ctrl {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-size: var(--font-size-sm);
    line-height: 1;
    transition: filter var(--motion-fast, 120ms) var(--motion-ease, ease);
}
.stage-ctrl:disabled { opacity: 0.4; cursor: not-allowed; }
.stage-ctrl:not(:disabled):hover { filter: brightness(0.94); }
.stage-ctrl--move   { background: var(--color-background-sunken); color: var(--color-text-secondary); }
.stage-ctrl--toggle { background: var(--blue-100);          color: var(--color-text-secondary); }
.stage-ctrl--danger { background: var(--red-100);           color: var(--color-danger); }

/* Permission row — one per subcategory */
.permission-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-3) 0;
    border-bottom: 1px solid var(--color-border);
}
.permission-row:last-child {
    border-bottom: none;
}
.permission-row__info {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}
.permission-row__name {
    font-weight: var(--font-weight-semibold);
    color: var(--color-text-primary);
}

/* "Changed" amber badge */
.badge--changed {
    background: var(--color-warning-bg);
    color: var(--color-warning);
    border-color: var(--color-warning-bg);
    font-size: var(--font-size-xs);
}

/* Unsaved-changes banner */
.permissions-banner {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: var(--color-warning-bg);
    border: 1px solid var(--color-warning-border);
    border-radius: var(--radius-md);
    margin-bottom: var(--space-4);
}
.permissions-banner__icon {
    flex-shrink: 0;
    width: 22px;
    height: 22px;
    border-radius: var(--radius-full);
    background: var(--color-warning);
    color: var(--neutral-0);
    display: grid;
    place-items: center;
    font-size: var(--font-size-sm);
    font-weight: 700;
    line-height: 1;
}
.permissions-banner__body {
    flex: 1;
    min-width: 0;
}
.permissions-banner__title {
    font-weight: var(--font-weight-semibold);
    font-size: var(--font-size-sm);
    color: var(--color-warning);
    line-height: 1.3;
}
.permissions-banner__changes {
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    margin-top: 2px;
}
.permissions-banner__actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-shrink: 0;
}

/* ---------------------------------------------------------
   Accessibility — Reduced Motion
   Disables all animations/transitions for users who have
   requested reduced motion at the OS level.
   --------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* =========================================================================
   Auth pages — login, register, password recovery, reset password,
   email confirmation.

   All classes in this block are used exclusively by Pages/Public/Accounts/**
   and share a consistent left-aligned card layout. All values use
   design-system tokens so tenant theming applies automatically.
   ========================================================================= */

/* ---- Outer section: centres the card on the page ---- */
.auth {
    display: flex;
    justify-content: center;
    padding: var(--space-8) var(--space-5);
}

/* ---- A page that is only an auth card: Admin's anonymous pages and the auth server's own pages
   (UI-1 phase F). Centred both ways on an otherwise empty page; the end-user portal's auth pages sit
   inside its public layout instead. */
.auth-page {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-5);
    padding: var(--space-6) var(--space-4);
}

.auth-page > .auth {
    width: 100%;
    padding: 0;
}

/* ---- Rules listed under a field (the password policy) ---- */
.auth__rules {
    margin: var(--space-1) 0 0;
    padding-left: var(--space-5);
}

/* ---- Card ------------------------------------------- */
.auth__card {
    background: var(--color-background-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    padding: var(--space-7);
    width: 100%;
    max-width: 440px;
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
}

/* ---- Card header: centred on every auth card, both portals and the auth server (UI-1 D17) ---- */
.auth__header {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-1);
    text-align: center;
}

.auth__title {
    font-family: var(--font-family-heading);
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-extrabold);
    font-stretch: var(--font-stretch-display);
    color: var(--color-text-primary);
    margin: 0;
    line-height: var(--line-height-tight);
    letter-spacing: var(--letter-spacing-tight);
}

.auth__subtitle {
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    margin: 0;
}

.auth__description {
    font-size: var(--font-size-base);
    color: var(--color-text-secondary);
    margin: 0;
    line-height: var(--line-height-relaxed);
}

/* ---- Status banners (loading / success / error) ----- */
.auth__banner {
    border-radius: var(--radius-md);
    padding: var(--space-3) var(--space-4);
    font-size: var(--font-size-sm);
    line-height: var(--line-height-relaxed);
    background: var(--color-background-sunken);
    border: 1px solid var(--color-border);
    color: var(--color-text-secondary);
}

.auth__banner--success {
    background: var(--color-success-bg);
    border-color: var(--color-success-border);
    color: var(--color-success);
}

.auth__banner--error {
    background: var(--color-error-bg);
    border-color: var(--color-error-border);
    color: var(--color-error);
}

/* ---- Recovery success message (multiple paragraphs) - */
.auth__success {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.auth__success p {
    font-size: var(--font-size-base);
    color: var(--color-text-secondary);
    margin: 0;
    line-height: var(--line-height-relaxed);
}

/* ---- Status icons (check / clock / warning circles) - */
.auth__status-icon {
    width: 56px;
    height: 56px;
    border-radius: var(--radius-full);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--font-size-xl);
    flex-shrink: 0;
}

.auth__status-icon--success {
    background: var(--color-success-bg);
    color: var(--color-success);
}

.auth__status-icon--warning {
    background: var(--color-warning-bg);
    color: var(--color-warning);
}

.auth__status-icon--error {
    background: var(--color-error-bg);
    color: var(--color-error);
}

/* ---- Spinner row (validating state) ----------------- */
.auth__spinner {
    display: flex;
    justify-content: center;
    font-size: 1.75rem;
    color: var(--color-primary-soft-text);
}

/* ---- Back link row ---------------------------------- */
.auth__back {
    display: flex;
    align-items: center;
}

/* ---- The card's form: fields, error and button, evenly spaced -- */
.auth__form {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

/* ---- Footer links ("Forgot password · Register") ---- */
.auth__links {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    flex-wrap: wrap;
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}

/* ---- Several errors in one alert (Register, the reset page) ---- */
.auth__errors {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

/* ---- Small print under a form (Register's POPIA notice) ---- */
.auth__note {
    margin: 0;
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}

/* Blazor's <ValidationMessage> always renders class="validation-message" and can't take ours, so inside a field it
   is styled as the field's error (.input-group__error). */
.input-group .validation-message {
    font-size: var(--font-size-sm);
    color: var(--color-error);
}

/* ---- Form actions: primary button row --------------- */
.form-actions {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

/* Primary action spans the full card width */
.form-actions > * {
    width: 100%;
}

/* ---- Password input with eye-toggle ----------------- */
/*
   The wrapper makes the input + toggle look like one unified
   field. The inner .input surrenders its own border/shadow to
   the wrapper; the wrapper drives focus styling instead.
*/
.password-wrapper {
    position: relative;
    display: flex;
    align-items: center;
}

/* Input fills the row; right padding leaves room for the toggle */
.password-wrapper > .input {
    width: 100%;
    padding-right: 2.75rem;
}

/* Suppress the input's own focus ring — the wrapper handles it */
.password-wrapper > .input:focus {
    box-shadow: none;
    border-color: var(--color-border-focus);
}

/* Plain <button class="eye-button"> (Login, Register) */
.eye-button {
    position: absolute;
    right: 0;
    top: 0;
    bottom: 0;
    width: 2.75rem;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    cursor: pointer;
    color: var(--color-text-muted);
    font-size: var(--font-size-md);
    padding: 0;
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
    transition: color var(--motion-fast) var(--motion-ease);
}

.eye-button:hover { color: var(--color-text-primary); }

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

/* ---- Password rules list (PasswordRules.razor: Register, the reset page, Profile, Admin) - */
.password-rules {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    font-size: var(--font-size-sm);
}

.password-rules__heading {
    font-weight: var(--font-weight-semibold);
    color: var(--color-text-secondary);
    list-style: none;
}

.password-rule {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    transition: color var(--motion-fast) var(--motion-ease);
}

.password-rule--met {
    color: var(--color-success);
}

.password-rule--unmet {
    color: var(--color-text-muted);
}

/* ---- Mobile adjustments ----------------------------- */
@media (max-width: 480px) {
    .auth {
        padding: var(--space-5) var(--space-4);
    }

    .auth__card {
        padding: var(--space-6) var(--space-5);
        border-radius: var(--radius-md);
        box-shadow: none;
        border-color: transparent;
        max-width: 100%;
    }
}

/* ---- Toasts (app-owned; replaces Blazorise notifications) ---- */
/*
    Rendered by Components/Notifications/Eight28ToastHost.razor, fed by
    Eight28ToastService via IUiNotifier. Deliberately NOT Blazorise — see the
    banner neutraliser below for why. Sits on the --layout-z-toast layer so a
    success/error toast floats above open drawers and modals.
*/
.toast-host {
    position: fixed;
    right: var(--space-5);
    bottom: var(--space-5);
    z-index: var(--layout-z-toast);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    width: min(400px, calc(100vw - var(--space-6)));
    /* The container itself must never block clicks in the gaps between
       toasts — only the toasts re-enable pointer events. */
    pointer-events: none;
}

.toast {
    pointer-events: auto;
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border);
    background: var(--color-background-elevated);
    box-shadow: var(--shadow-lg);
    color: var(--color-text-primary);
    animation: toastIn 180ms ease-out;
}

/* Bootstrap, in the ABP global.css bundle, shares the .toast class name: it hides every
   .toast without .show (".toast:not(.show) { display: none }") and fixes its width at
   350px, so without this every app toast rendered invisibly. Ours are app-owned and always
   shown at the host's width. Same specificity as Bootstrap's rule and loaded after it (see
   App.razor's stylesheet order), so this wins. */
.toast-host .toast {
    display: flex;
    width: auto;
    max-width: none;
}

.toast--success { border-left: 3px solid var(--color-success-border); }
.toast--error   { border-left: 3px solid var(--color-error-border); }
.toast--warning { border-left: 3px solid var(--color-warning-border); }

.toast__icon {
    flex-shrink: 0;
    display: flex;
    margin-top: 1px;
}

.toast--success .toast__icon { color: var(--color-success); }
.toast--error   .toast__icon { color: var(--color-error); }
.toast--warning .toast__icon { color: var(--color-warning); }

.toast__message {
    flex: 1;
    font-size: var(--font-size-sm);
    line-height: 1.4;
}

.toast__dismiss {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2px;
    border: none;
    background: transparent;
    color: var(--color-text-muted);
    cursor: pointer;
    border-radius: var(--radius-sm);
    transition: color 150ms ease-out, background 150ms ease-out;
}

.toast__dismiss:hover {
    color: var(--color-text-primary);
    background: var(--color-background-sunken);
}

/* The one action a toast may carry (e.g. "Undo" after an organogram move). */
.toast__action {
    flex-shrink: 0;
    padding: 2px var(--space-2);
    border: none;
    background: transparent;
    color: var(--color-text-link);
    font: inherit;
    font-weight: var(--font-weight-semibold);
    cursor: pointer;
    border-radius: var(--radius-sm);
    transition: color 150ms ease-out, background 150ms ease-out;
}

.toast__action:hover {
    color: var(--color-text-link-hover);
    background: var(--color-background-sunken);
}

@keyframes toastIn {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* ---- Blazorise license banner (defence-in-depth) ---- */
/*
    The app-owned toast above means the custom shell renders no Blazorise
    component, so the license banner is no longer injected on the pages our
    E2E suite exercises. But Blazorise is still a hard dependency (ABP's
    BasicTheme, Identity, Tenant/Setting/Feature-management modules are all
    Blazorise-based), and a few surfaces still render Blazorise components
    directly — the public Terms/Privacy modals and ABP's own admin pages.

    When any of those mount, Blazorise (2.0, unlicensed — no ProductToken, see
    Eight28BlazorClientModule.ConfigureBlazorise) injects
    #blazorise-license-banner-host into <body> as a fixed, full-viewport layer
    that swallows pointer events. `!important` is required because Blazorise
    sets pointer-events inline on the host, which a plain rule can't override.
    The banner stays visible (the licence notice is not hidden); it simply
    stops blocking clicks. The proper long-term fix is a Blazorise ProductToken.
*/
#blazorise-license-banner-host {
    pointer-events: none !important;
}

/* ---- Contextual help bubbles (UI-HELP-01) --------------- */
/* A help icon after a label, heading or page title that opens a bubble with a definition, a list or
   a rule set. One sentence about a field stays a hint (.input-group__hint); anything longer is a
   bubble. HelpBubble.razor positions the panel fixed (so a scrolling side panel never clips it);
   without its script the panel falls back to sitting below the icon. */
.help-bubble {
    position: relative;
    display: inline-flex;
    align-items: center;
    vertical-align: middle;
    margin-left: var(--space-1);
}
.help-bubble__trigger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-full);
    background: transparent;
    color: var(--color-text-muted);
    cursor: pointer;
    transition: color var(--motion-fast) var(--motion-ease-out), background var(--motion-fast) var(--motion-ease-out);
}
.help-bubble__trigger:hover,
.help-bubble__trigger--open {
    color: var(--color-primary-soft-text);
    background: var(--color-primary-soft);
}
.help-bubble__trigger:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}
.help-bubble__panel {
    position: absolute;
    top: calc(100% + 8px);
    left: 0;
    z-index: calc(var(--layout-z-modal) + 5);
    display: block;
    width: max-content;
    max-width: min(360px, calc(100vw - 16px));
    padding: var(--space-3) var(--space-4);
    background: var(--popover-bg);
    border: 1px solid var(--popover-border);
    border-radius: var(--popover-radius);
    box-shadow: var(--popover-shadow);
    color: var(--color-text-primary);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-regular, 400);
    line-height: var(--line-height-normal, 1.5);
    text-align: left;
    text-transform: none;
    letter-spacing: normal;
    white-space: normal;
    animation: help-bubble-in var(--motion-fast) var(--motion-ease-out);
}
.help-bubble__panel--placed {
    position: fixed;
}
.help-bubble__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-2);
}
.help-bubble__title {
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
    color: var(--color-text-primary);
}
.help-bubble__close {
    display: inline-flex;
    margin-left: auto;
    padding: 2px;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--color-text-muted);
    cursor: pointer;
    transition: color var(--motion-fast) var(--motion-ease-out), background var(--motion-fast) var(--motion-ease-out);
}
.help-bubble__close:hover {
    color: var(--color-text-primary);
    background: var(--color-background-sunken);
}
.help-bubble__body {
    display: block;
    color: var(--color-text-secondary);
}
.help-bubble__body p { margin: 0 0 var(--space-2); }
.help-bubble__body p:last-child { margin-bottom: 0; }
.help-bubble__body ul { margin: 0; padding-left: var(--space-4); }
.help-bubble__body li + li { margin-top: var(--space-1); }
/* Term + explanation rows: lead statuses, retention rules. */
.help-bubble__terms {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: var(--space-2) var(--space-3);
    margin: 0;
}
.help-bubble__terms dt {
    margin: 0;
    font-weight: var(--font-weight-semibold);
    color: var(--color-text-primary);
}
.help-bubble__terms dd { margin: 0; }
@keyframes help-bubble-in {
    from { opacity: 0; transform: translateY(2px); }
    to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
    .help-bubble__panel { animation: none; }
}

/* ---- Build version (OPS-VER-1) ------------------------- */
/* One muted line: on both sign-in pages and at the foot of each portal's account menu. */
.app-version {
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}
.auth__version {
    display: block;
    margin-top: var(--space-4);
    text-align: center;
}
.topbar__user-menu-version {
    display: block;
    margin-top: var(--space-1);
    padding: var(--space-2) 12px var(--space-1);
    border-top: 1px solid var(--color-border-subtle);
}
