/* PublonCore UI — hyper-param design system. KEEP MINIMAL (≤1,000 LOC).
 * See PublonCore.md → "Keeping css / ui / bindings / services lean".
 * Layers: 1 hp roots · 2 derived tokens · 3 dark · 4 reset · 5 utilities
 *         · 6 component skins · 7 themes · 8 responsive + animations */

/* ---- 1. Hyper-parameters — font stacks + every dial. */
:root {
    /* Sans-serif stacks */
    --hp-font-stack-system:    ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --hp-font-stack-inter:     "Inter", "Inter var", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --hp-font-stack-manrope:   "Manrope", "Inter", ui-sans-serif, system-ui, sans-serif;
    --hp-font-stack-dmsans:    "DM Sans", "Inter", ui-sans-serif, system-ui, sans-serif;
    --hp-font-stack-grotesk:   "Space Grotesk", "Söhne", "HK Grotesk", "Inter", ui-sans-serif, sans-serif;
    --hp-font-stack-ibmplex:   "IBM Plex Sans", "Helvetica Neue", system-ui, sans-serif;
    --hp-font-stack-jakarta:   "Plus Jakarta Sans", "Inter", system-ui, sans-serif;
    --hp-font-stack-public:    "Public Sans", "Inter", system-ui, sans-serif;
    --hp-font-stack-albert:    "Albert Sans", "Inter", system-ui, sans-serif;
    --hp-font-stack-outfit:    "Outfit", "Inter", system-ui, sans-serif;
    --hp-font-stack-work:      "Work Sans", "Inter", system-ui, sans-serif;
    --hp-font-stack-roboto:    "Roboto", "Helvetica Neue", system-ui, sans-serif;
    --hp-font-stack-helvetica: "Helvetica Neue", "Helvetica", "Arial", sans-serif;
    --hp-font-stack-humanist:  "Optima", "Lucida Sans", "Trebuchet MS", "Verdana", "Tahoma", system-ui, sans-serif;
    --hp-font-stack-geometric: "Avenir Next", "Avenir", "Futura", "Century Gothic", "URW Gothic", system-ui, sans-serif;
    --hp-font-stack-rounded:   "SF Pro Rounded", "Hiragino Maru Gothic ProN", -apple-system, ui-rounded, system-ui, sans-serif;
    --hp-font-stack-nunito:    "Nunito", "Quicksand", "Comfortaa", system-ui, sans-serif;
    --hp-font-stack-comfortaa: "Comfortaa", "Quicksand", "Nunito", system-ui, sans-serif;
    --hp-font-stack-quicksand: "Quicksand", "Nunito", system-ui, sans-serif;
    --hp-font-stack-condensed: "Roboto Condensed", "Archivo Narrow", "Helvetica Neue Condensed", "Arial Narrow", sans-serif;
    --hp-font-stack-narrow:    "Archivo Narrow", "Roboto Condensed", "Arial Narrow", sans-serif;
    --hp-font-stack-oswald:    "Oswald", "Bebas Neue", "Archivo Narrow", "Impact", sans-serif;
    --hp-font-stack-bebas:     "Bebas Neue", "Oswald", "Impact", sans-serif;
    --hp-font-stack-display:   "SF Pro Display", "Inter", "Helvetica Neue", system-ui, sans-serif;

    /* Serif stacks */
    --hp-font-stack-serif:     ui-serif, "New York", "Iowan Old Style", "Charter", Georgia, "Times New Roman", serif;
    --hp-font-stack-ibmplexs:  "IBM Plex Serif", "Source Serif Pro", Georgia, serif;
    --hp-font-stack-source:    "Source Serif 4", "Source Serif Pro", Georgia, serif;
    --hp-font-stack-georgia:   Georgia, "Iowan Old Style", "Times New Roman", Times, serif;
    --hp-font-stack-times:     "Times New Roman", Times, "Liberation Serif", serif;
    --hp-font-stack-garamond:  "EB Garamond", "Garamond", "Hoefler Text", "Palatino", serif;
    --hp-font-stack-cormorant: "Cormorant Garamond", "EB Garamond", "Hoefler Text", serif;
    --hp-font-stack-caslon:    "Libre Caslon Text", "Big Caslon", "Hoefler Text", serif;
    --hp-font-stack-palatino:  "Palatino", "Palatino Linotype", "Book Antiqua", "URW Palladio L", serif;
    --hp-font-stack-merri:     "Merriweather", "Source Serif Pro", Georgia, serif;
    --hp-font-stack-lora:      "Lora", "Merriweather", Georgia, serif;
    --hp-font-stack-playfair:  "Playfair Display", "Source Serif Pro", "Times New Roman", serif;
    --hp-font-stack-slab:      "Roboto Slab", "Rockwell", Georgia, serif;

    /* Handwritten / display */
    --hp-font-stack-caveat:    "Caveat", "Brush Script MT", cursive;
    --hp-font-stack-kalam:     "Kalam", "Caveat", "Brush Script MT", cursive;

    /* Monospace stacks */
    --hp-font-stack-mono:      ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    --hp-font-stack-jetbrains: "JetBrains Mono", "Fira Code", ui-monospace, "SF Mono", Menlo, monospace;
    --hp-font-stack-fira:      "Fira Code", "Source Code Pro", ui-monospace, Menlo, monospace;
    --hp-font-stack-ibmmono:   "IBM Plex Mono", "JetBrains Mono", ui-monospace, Menlo, monospace;
    --hp-font-stack-source-code: "Source Code Pro", "Fira Code", ui-monospace, Menlo, monospace;
    --hp-font-stack-roboto-mono: "Roboto Mono", "JetBrains Mono", ui-monospace, Menlo, monospace;
    --hp-font-stack-courier:   "Courier New", Courier, "Liberation Mono", monospace;

    /* Defaults */
    --hp-font-body:    var(--hp-font-stack-dmsans);
    --hp-font-heading: var(--hp-font-stack-outfit);
    --hp-font-mono:    var(--hp-font-stack-mono);
    --hp-weight-body:    300;
    --hp-weight-heading: 600;
    --hp-text-scale: 0.82;        /* multiplies every text size */
    --hp-text-ratio: 1.18;        /* type scale (modular) */
    --hp-line-height: 1.5;
    --hp-density: 1;              /* spacing multiplier */
    --hp-pad-base: 0.5rem;        /* base padding unit */
    --hp-margin-base: 0.5rem;     /* base margin unit */
    --hp-search-input-max-w: 14rem; /* sensible cap for short queries (~12 chars) */
    --hp-modal-max-w: 600px;        /* modal max width (clamped by 90vw at runtime) */
    --hp-drawer-w: 420px;           /* drawer width (clamped by 90vw at runtime) */
    --hp-avatar-size: 2.4rem;       /* default avatar circle */
    --hp-active-marker-w: 3px;      /* left/top stripe on selected list/card rows */
    --hp-tab-underline-w: 2px;      /* tab bottom border (active + transparent reserve) */
    --hp-on-primary-muted: rgba(255,255,255,0.78);   /* subtitle / inactive text on dark surface */
    --hp-on-primary-bg-soft: rgba(255,255,255,0.10); /* hover overlay on dark surface */
    --hp-on-primary-bg-strong: rgba(255,255,255,0.18); /* active overlay / brand-mark on dark */
    --hp-on-primary-divider: rgba(255,255,255,0.25); /* subtle 1px line on dark surface */
    --hp-corner-scale: 0;
    --hp-border-scale: 0.4;
    --hp-shadow-intensity: 0.12;
    --hp-transition-speed: 1;
    --hp-hue-1: 205; --hp-sat-1: 88%; --hp-l-shift-1: 0%;
    --hp-hue-2: 35;  --hp-sat-2: 78%; --hp-l-shift-2: 0%;
    --hp-hue-accent: 350; --hp-sat-accent: 78%; --hp-l-shift-accent: 0%;
    --hp-hue-danger:  4;   --hp-sat-danger:  82%;
    --hp-hue-warn:    32;  --hp-sat-warn:    94%;
    --hp-hue-success: 142; --hp-sat-success: 72%;
    --hp-hue-info:    200; --hp-sat-info:    82%;
    --hp-l-bg: 100%; --hp-l-fg: 12%; --hp-l-muted: 45%; --hp-l-border: 88%;
    --hp-l-elev: 99%; --hp-l-sunken: 96%;
}

/* ---- 2. Derived tokens — redeclared on every theme anchor so child
 * overrides of --hp-* re-derive --ui-* tokens (substitution freezes at
 * the declaration site). See ./README.md §Hyper-parameter system. */
:root, [class*="ui-theme-"], [data-theme] {
    --ui-font-body:    var(--hp-font-body);
    --ui-font-heading: var(--hp-font-heading);
    --ui-font-mono:    var(--hp-font-mono);

    --ui-text-2xs: calc(0.65rem  * var(--hp-text-scale));
    --ui-text-xs:  calc(0.75rem  * var(--hp-text-scale));
    --ui-text-sm:  calc(0.875rem * var(--hp-text-scale));
    --ui-text-base:calc(1rem     * var(--hp-text-scale));
    --ui-text-lg:  calc(1rem     * var(--hp-text-scale) * var(--hp-text-ratio));
    --ui-text-xl:  calc(var(--ui-text-lg)  * var(--hp-text-ratio));
    --ui-text-2xl: calc(var(--ui-text-xl)  * var(--hp-text-ratio));
    --ui-text-3xl: calc(var(--ui-text-2xl) * var(--hp-text-ratio));
    --ui-text-4xl: calc(var(--ui-text-3xl) * var(--hp-text-ratio));

    --ui-font-thin:       100;
    --ui-font-extralight: 200;
    --ui-font-light:      300;
    --ui-font-normal:     400;
    --ui-font-medium:     500;
    --ui-font-semibold:   600;
    --ui-font-bold:       700;
    --ui-font-extrabold:  800;
    --ui-font-black:      900;
    --ui-weight-body:    var(--hp-weight-body);
    --ui-weight-heading: var(--hp-weight-heading);

    --ui-line-height: var(--hp-line-height);

    /* Spacing scale — multiples of pad-base × density */
    --ui-space-0: 0;
    --ui-space-1: calc(var(--hp-pad-base) * 0.5  * var(--hp-density));
    --ui-space-2: calc(var(--hp-pad-base) * 1    * var(--hp-density));
    --ui-space-3: calc(var(--hp-pad-base) * 1.5  * var(--hp-density));
    --ui-space-4: calc(var(--hp-pad-base) * 2    * var(--hp-density));
    --ui-space-5: calc(var(--hp-pad-base) * 2.5  * var(--hp-density));
    --ui-space-6: calc(var(--hp-pad-base) * 3    * var(--hp-density));
    --ui-space-7: calc(var(--hp-pad-base) * 4    * var(--hp-density));
    --ui-space-8: calc(var(--hp-pad-base) * 5    * var(--hp-density));
    --ui-space-10:calc(var(--hp-pad-base) * 6    * var(--hp-density));
    --ui-search-input-max-w: var(--hp-search-input-max-w);
    --ui-modal-max-w: var(--hp-modal-max-w);
    --ui-drawer-w: var(--hp-drawer-w);
    --ui-avatar-size: var(--hp-avatar-size);
    --ui-active-marker-w: var(--hp-active-marker-w);
    --ui-tab-underline-w: var(--hp-tab-underline-w);
    --ui-on-primary-muted: var(--hp-on-primary-muted);
    --ui-on-primary-bg-soft: var(--hp-on-primary-bg-soft);
    --ui-on-primary-bg-strong: var(--hp-on-primary-bg-strong);
    --ui-on-primary-divider: var(--hp-on-primary-divider);

    --ui-radius-none: 0;
    --ui-radius-sm:  calc(0.25rem  * var(--hp-corner-scale));
    --ui-radius-md:  calc(0.375rem * var(--hp-corner-scale));
    --ui-radius-lg:  calc(0.5rem   * var(--hp-corner-scale));
    --ui-radius-xl:  calc(0.75rem  * var(--hp-corner-scale));
    --ui-radius-2xl: calc(1rem     * var(--hp-corner-scale));
    --ui-radius-full: 9999px;

    --ui-border-width: calc(1px * var(--hp-border-scale));

    --ui-shadow-none: none;
    --ui-shadow-sm:  0 1px 2px rgba(15,23,42, calc(var(--hp-shadow-intensity) * 1.5));
    --ui-shadow-md:  0 4px 8px rgba(15,23,42, calc(var(--hp-shadow-intensity) * 2));
    --ui-shadow-lg:  0 8px 22px rgba(15,23,42, calc(var(--hp-shadow-intensity) * 2.5));
    --ui-shadow-xl:  0 18px 40px rgba(15,23,42, calc(var(--hp-shadow-intensity) * 3));
    --ui-shadow-inner: inset 0 1px 2px rgba(15,23,42, calc(var(--hp-shadow-intensity) * 2));

    --ui-transition-fast:  calc(120ms * var(--hp-transition-speed));
    --ui-transition-base:  calc(200ms * var(--hp-transition-speed));
    --ui-transition-slow:  calc(380ms * var(--hp-transition-speed));
    --ui-ease: cubic-bezier(0.4, 0, 0.2, 1);

    /* Colour scales — derived from HSL hyper-params + per-color lightness shift */
    --ui-primary-50:  hsl(var(--hp-hue-1), var(--hp-sat-1), calc(97% + var(--hp-l-shift-1)));
    --ui-primary-100: hsl(var(--hp-hue-1), var(--hp-sat-1), calc(92% + var(--hp-l-shift-1)));
    --ui-primary-200: hsl(var(--hp-hue-1), var(--hp-sat-1), calc(83% + var(--hp-l-shift-1)));
    --ui-primary-300: hsl(var(--hp-hue-1), var(--hp-sat-1), calc(70% + var(--hp-l-shift-1)));
    --ui-primary-400: hsl(var(--hp-hue-1), var(--hp-sat-1), calc(60% + var(--hp-l-shift-1)));
    --ui-primary-500: hsl(var(--hp-hue-1), var(--hp-sat-1), calc(52% + var(--hp-l-shift-1)));
    --ui-primary-600: hsl(var(--hp-hue-1), var(--hp-sat-1), calc(45% + var(--hp-l-shift-1)));
    --ui-primary-700: hsl(var(--hp-hue-1), var(--hp-sat-1), calc(38% + var(--hp-l-shift-1)));
    --ui-primary-800: hsl(var(--hp-hue-1), var(--hp-sat-1), calc(28% + var(--hp-l-shift-1)));
    --ui-primary-900: hsl(var(--hp-hue-1), var(--hp-sat-1), calc(18% + var(--hp-l-shift-1)));
    --ui-primary: var(--ui-primary-600);
    --ui-on-primary: #fff;

    --ui-secondary-100: hsl(var(--hp-hue-2), var(--hp-sat-2), calc(92% + var(--hp-l-shift-2)));
    --ui-secondary-500: hsl(var(--hp-hue-2), var(--hp-sat-2), calc(52% + var(--hp-l-shift-2)));
    --ui-secondary-600: hsl(var(--hp-hue-2), var(--hp-sat-2), calc(45% + var(--hp-l-shift-2)));
    --ui-secondary-700: hsl(var(--hp-hue-2), var(--hp-sat-2), calc(38% + var(--hp-l-shift-2)));
    --ui-secondary: var(--ui-secondary-600);
    --ui-on-secondary: #fff;

    --ui-accent-500: hsl(var(--hp-hue-accent), var(--hp-sat-accent), calc(50% + var(--hp-l-shift-accent)));
    --ui-accent-600: hsl(var(--hp-hue-accent), var(--hp-sat-accent), calc(42% + var(--hp-l-shift-accent)));
    --ui-accent: var(--ui-accent-600);

    --ui-danger-100: hsl(var(--hp-hue-danger), var(--hp-sat-danger), 95%);
    --ui-danger-500: hsl(var(--hp-hue-danger), var(--hp-sat-danger), 50%);
    --ui-danger-600: hsl(var(--hp-hue-danger), var(--hp-sat-danger), 45%);
    --ui-danger: var(--ui-danger-600);
    --ui-warn-100:    hsl(var(--hp-hue-warn), var(--hp-sat-warn), 95%);
    --ui-warn-500:    hsl(var(--hp-hue-warn), var(--hp-sat-warn), 50%);
    --ui-warn:        hsl(var(--hp-hue-warn), var(--hp-sat-warn), 45%);
    --ui-success-100: hsl(var(--hp-hue-success), var(--hp-sat-success), 94%);
    --ui-success-500: hsl(var(--hp-hue-success), var(--hp-sat-success), 42%);
    --ui-success:     hsl(var(--hp-hue-success), var(--hp-sat-success), 38%);
    --ui-info-100:    hsl(var(--hp-hue-info), var(--hp-sat-info), 94%);
    --ui-info-500:    hsl(var(--hp-hue-info), var(--hp-sat-info), 50%);
    --ui-info:        hsl(var(--hp-hue-info), var(--hp-sat-info), 42%);

    /* Greys derived from primary hue (low sat) */
    --ui-gray-50:  hsl(var(--hp-hue-1), 12%, 98%);
    --ui-gray-100: hsl(var(--hp-hue-1), 12%, 96%);
    --ui-gray-200: hsl(var(--hp-hue-1), 10%, 90%);
    --ui-gray-300: hsl(var(--hp-hue-1), 10%, 82%);
    --ui-gray-400: hsl(var(--hp-hue-1), 8%,  64%);
    --ui-gray-500: hsl(var(--hp-hue-1), 8%,  48%);
    --ui-gray-600: hsl(var(--hp-hue-1), 8%,  36%);
    --ui-gray-700: hsl(var(--hp-hue-1), 8%,  26%);
    --ui-gray-800: hsl(var(--hp-hue-1), 8%,  18%);
    --ui-gray-900: hsl(var(--hp-hue-1), 8%,  10%);

    --ui-bg:       hsl(var(--hp-hue-1), 12%, var(--hp-l-bg));
    --ui-bg-elev:  hsl(var(--hp-hue-1), 12%, var(--hp-l-elev));
    --ui-bg-sunken:hsl(var(--hp-hue-1), 12%, var(--hp-l-sunken));
    --ui-bg-muted: var(--ui-gray-100);
    --ui-fg:       hsl(var(--hp-hue-1), 18%, var(--hp-l-fg));
    --ui-fg-muted: hsl(var(--hp-hue-1), 10%, var(--hp-l-muted));
    --ui-border:   hsl(var(--hp-hue-1), 12%, var(--hp-l-border));
    --ui-border-strong: hsl(var(--hp-hue-1), 12%, 78%);
}

/* ---- 3. Dark theme — declarations duplicated in @media so users get
 * either explicit `data-theme="dark"` or system preference. */
[data-theme="dark"], .ui-theme-dark {
    --hp-l-bg: 8%; --hp-l-elev: 12%; --hp-l-sunken: 5%;
    --hp-l-fg: 95%; --hp-l-muted: 65%; --hp-l-border: 22%;
    --hp-shadow-intensity: 0.45;
    --ui-gray-50:  hsl(var(--hp-hue-1), 12%, 12%);
    --ui-gray-100: hsl(var(--hp-hue-1), 12%, 16%);
    --ui-gray-200: hsl(var(--hp-hue-1), 10%, 22%);
    --ui-gray-300: hsl(var(--hp-hue-1), 10%, 32%);
    --ui-bg-muted: var(--ui-gray-100);
    --ui-border-strong: hsl(var(--hp-hue-1), 12%, 32%);
    /* Semantic 100-level (alert/callout/badge) backgrounds need to darken
     * too, otherwise we get pale-on-light text. */
    --ui-primary-100: hsl(var(--hp-hue-1), 35%, 18%);
    --ui-secondary-100: hsl(var(--hp-hue-2), 35%, 18%);
    --ui-info-100:    hsl(var(--hp-hue-info), 35%, 18%);
    --ui-danger-100:  hsl(var(--hp-hue-danger), 35%, 18%);
    --ui-warn-100:    hsl(var(--hp-hue-warn), 35%, 18%);
    --ui-success-100: hsl(var(--hp-hue-success), 35%, 18%);
}
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --hp-l-bg: 8%; --hp-l-elev: 12%; --hp-l-sunken: 5%;
        --hp-l-fg: 95%; --hp-l-muted: 65%; --hp-l-border: 22%;
        --hp-shadow-intensity: 0.45;
        --ui-gray-50:  hsl(var(--hp-hue-1), 12%, 12%);
        --ui-gray-100: hsl(var(--hp-hue-1), 12%, 16%);
        --ui-gray-200: hsl(var(--hp-hue-1), 10%, 22%);
        --ui-gray-300: hsl(var(--hp-hue-1), 10%, 32%);
        --ui-bg-muted: var(--ui-gray-100);
        --ui-border-strong: hsl(var(--hp-hue-1), 12%, 32%);
        --ui-primary-100: hsl(var(--hp-hue-1), 35%, 18%);
        --ui-secondary-100: hsl(var(--hp-hue-2), 35%, 18%);
        --ui-info-100:    hsl(var(--hp-hue-info), 35%, 18%);
        --ui-danger-100:  hsl(var(--hp-hue-danger), 35%, 18%);
        --ui-warn-100:    hsl(var(--hp-hue-warn), 35%, 18%);
        --ui-success-100: hsl(var(--hp-hue-success), 35%, 18%);
    }
}

/* ---- 4. Reset + base ---- */
*, *::before, *::after { box-sizing: border-box; }
body {
    margin: 0; font-family: var(--ui-font-body); font-size: var(--ui-text-base);
    font-weight: var(--ui-weight-body);
    line-height: var(--ui-line-height); color: var(--ui-fg); background: var(--ui-bg);
    -webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4, h5, h6 { font-family: var(--ui-font-heading); margin: 0 0 var(--ui-space-3); font-weight: var(--ui-weight-heading); line-height: 1.2; letter-spacing: -0.01em; }
h1 { font-size: var(--ui-text-3xl); }
h2 { font-size: var(--ui-text-2xl); }
h3 { font-size: var(--ui-text-xl); }
h4 { font-size: var(--ui-text-lg); }
h5, h6 { font-size: var(--ui-text-base); }
p { margin: 0 0 var(--ui-space-3); }
a { color: var(--ui-primary); text-decoration: none; }
a:hover { text-decoration: underline; }
code, kbd, pre, samp { font-family: var(--ui-font-mono); font-size: 0.92em; }

/* ---- 5. Utilities ---- */
.ui-hidden { display: none !important; }
.ui-flex, .ui-d-flex { display: flex; }
.ui-flex-col { flex-direction: column; }
.ui-flex-wrap { flex-wrap: wrap; }
.ui-flex-1 { flex: 1 1 auto; min-width: 0; min-height: 0; }
.ui-flex-2 { flex: 2 1 0; min-width: 0; min-height: 0; }
.ui-flex-3 { flex: 3 1 0; min-width: 0; min-height: 0; }
.ui-grid { display: grid; }
.ui-grid-auto { grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); }
.ui-grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.ui-grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ui-grid-cols-1-2 { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); }
.ui-grid-cols-2-1 { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
.ui-readable { max-width: 64rem; width: 100%; }   /* constrain long-form prose to a readable column */
.ui-h-tall { height: clamp(20rem, 50vh, 36rem); }
.ui-h-medium { height: clamp(14rem, 35vh, 24rem); }
.ui-items-center { align-items: center; }
.ui-items-start { align-items: flex-start; }
.ui-items-end { align-items: flex-end; }
.ui-justify-between { justify-content: space-between; }
.ui-justify-center { justify-content: center; }
.ui-justify-end { justify-content: flex-end; }
.ui-min-h-0 { min-height: 0; }
.ui-min-w-0 { min-width: 0; }
.ui-overflow-auto { overflow: auto; }
.ui-overflow-hidden { overflow: hidden; }
.ui-h-full { height: 100%; }
.ui-w-full { width: 100%; }
.ui-col { display: flex; flex-direction: column; }
.ui-relative { position: relative; }

.ui-gap-1 { gap: var(--ui-space-1); } .ui-gap-2 { gap: var(--ui-space-2); }
.ui-gap-3 { gap: var(--ui-space-3); } .ui-gap-4 { gap: var(--ui-space-4); }
.ui-gap-5 { gap: var(--ui-space-5); } .ui-gap-6 { gap: var(--ui-space-6); }

.ui-p-0 { padding: 0; } .ui-p-1 { padding: var(--ui-space-1); }
.ui-p-2 { padding: var(--ui-space-2); } .ui-p-3 { padding: var(--ui-space-3); }
.ui-p-4 { padding: var(--ui-space-4); } .ui-p-5 { padding: var(--ui-space-5); }
.ui-p-6 { padding: var(--ui-space-6); }
.ui-px-2 { padding-inline: var(--ui-space-2); } .ui-px-3 { padding-inline: var(--ui-space-3); }
.ui-px-4 { padding-inline: var(--ui-space-4); } .ui-px-5 { padding-inline: var(--ui-space-5); }
.ui-py-1 { padding-block: var(--ui-space-1); } .ui-py-2 { padding-block: var(--ui-space-2); }
.ui-py-3 { padding-block: var(--ui-space-3); } .ui-py-4 { padding-block: var(--ui-space-4); }
.ui-m-0 { margin: 0; } .ui-mt-1 { margin-top: var(--ui-space-1); }
.ui-mt-2 { margin-top: var(--ui-space-2); } .ui-mt-3 { margin-top: var(--ui-space-3); }
.ui-mt-4 { margin-top: var(--ui-space-4); } .ui-mb-2 { margin-bottom: var(--ui-space-2); }
.ui-mb-3 { margin-bottom: var(--ui-space-3); } .ui-mb-4 { margin-bottom: var(--ui-space-4); }

.ui-text-xs { font-size: var(--ui-text-xs); } .ui-text-sm { font-size: var(--ui-text-sm); }
.ui-text-base { font-size: var(--ui-text-base); } .ui-text-lg { font-size: var(--ui-text-lg); }
.ui-text-xl { font-size: var(--ui-text-xl); } .ui-text-2xl { font-size: var(--ui-text-2xl); }
.ui-text-3xl { font-size: var(--ui-text-3xl); }
.ui-font-thin       { font-weight: var(--ui-font-thin); }
.ui-font-extralight { font-weight: var(--ui-font-extralight); }
.ui-font-light      { font-weight: var(--ui-font-light); }
.ui-font-normal     { font-weight: var(--ui-font-normal); }
.ui-font-medium     { font-weight: var(--ui-font-medium); }
.ui-font-semibold   { font-weight: var(--ui-font-semibold); }
.ui-font-bold       { font-weight: var(--ui-font-bold); }
.ui-font-extrabold  { font-weight: var(--ui-font-extrabold); }
.ui-font-black      { font-weight: var(--ui-font-black); }
.ui-font-mono { font-family: var(--ui-font-mono); }
.ui-font-heading { font-family: var(--ui-font-heading); }
.ui-font-body { font-family: var(--ui-font-body); }
.ui-text-muted { color: var(--ui-fg-muted); }
.ui-text-success { color: var(--ui-success); }
.ui-text-danger  { color: var(--ui-danger); }
.ui-text-warn    { color: var(--ui-warn); }
.ui-text-center { text-align: center; }
.ui-text-right  { text-align: right; }
.ui-list-plain  { list-style: none; padding-left: 0; }
.ui-truncate { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ui-clickable { cursor: pointer; }

.ui-bg-muted { background: var(--ui-bg-muted); }
.ui-bg-elev  { background: var(--ui-bg-elev); }
.ui-bg-primary { background: var(--ui-primary); color: var(--ui-on-primary); }
.ui-color-primary { color: var(--ui-primary); }
.ui-color-primary-fade { color: var(--ui-primary-700); opacity: 0.85; }
.ui-color-danger  { color: var(--ui-danger); }
.ui-color-success { color: var(--ui-success); }
.ui-color-warn    { color: var(--ui-warn); }

.ui-radius-sm { border-radius: var(--ui-radius-sm); }
.ui-radius-md { border-radius: var(--ui-radius-md); }
.ui-radius-lg { border-radius: var(--ui-radius-lg); }
.ui-shadow-sm { box-shadow: var(--ui-shadow-sm); }
.ui-shadow-md { box-shadow: var(--ui-shadow-md); }
.ui-shadow-lg { box-shadow: var(--ui-shadow-lg); }
.ui-border { border: var(--ui-border-width) solid var(--ui-border); }

/* Status colour helpers used by chips/badges */
.ui-gray-50 { background: var(--ui-gray-50); } .ui-gray-100 { background: var(--ui-gray-100); }
.ui-gray-200 { background: var(--ui-gray-200); } .ui-gray-300 { background: var(--ui-gray-300); }

/* ---- 6. Component skins ---- */

/* Buttons */
.ui-btn {
    display: inline-flex; align-items: center; gap: var(--ui-space-2);
    padding: var(--ui-space-1) var(--ui-space-3);
    border: var(--ui-border-width) solid var(--ui-border);
    border-radius: var(--ui-radius-md); background: var(--ui-bg-elev);
    color: var(--ui-fg); font: inherit; font-weight: var(--ui-font-medium);
    cursor: pointer; transition: background var(--ui-transition-fast) var(--ui-ease),
        border-color var(--ui-transition-fast) var(--ui-ease),
        transform var(--ui-transition-fast) var(--ui-ease),
        box-shadow var(--ui-transition-fast) var(--ui-ease);
    line-height: 1.2; text-decoration: none; user-select: none;
}
.ui-btn:hover { background: var(--ui-gray-100); border-color: var(--ui-border-strong); }
.ui-btn:active { transform: translateY(1px); }
.ui-btn:disabled, .ui-btn[disabled] { opacity: 0.55; cursor: not-allowed; }
.ui-btn-primary {
    background: var(--ui-primary);
    color: var(--ui-on-primary); border-color: var(--ui-primary);
}
.ui-btn-primary:hover {
    background: var(--ui-primary-700); border-color: var(--ui-primary-700);
}
.ui-btn-danger  { background: var(--ui-danger);  color: #fff; border-color: var(--ui-danger); }
.ui-btn-danger:hover  { background: var(--ui-danger-600); }
.ui-btn-ghost { background: transparent; border-color: transparent; color: var(--ui-fg-muted); }
.ui-btn-ghost:hover { background: var(--ui-bg-muted); color: var(--ui-fg); }
.ui-btn-sm { padding: var(--ui-space-1) var(--ui-space-3); font-size: var(--ui-text-sm); }
.ui-btn-lg { padding: var(--ui-space-3) var(--ui-space-5); font-size: var(--ui-text-lg); }
.ui-ml-auto { margin-left: auto; }
.ui-btn-icon, .ui-icon-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 2rem; height: 2rem; border: var(--ui-border-width) solid transparent;
    border-radius: var(--ui-radius-md); background: transparent; color: inherit; cursor: pointer;
    transition: background var(--ui-transition-fast) var(--ui-ease);
}
.ui-btn-icon:hover, .ui-icon-btn:hover { background: var(--ui-bg-muted); }

/* Inputs */
.ui-input, .ui-select, .ui-textarea {
    display: block; width: 100%;
    padding: var(--ui-space-2) var(--ui-space-3);
    font: inherit; color: var(--ui-fg); background: var(--ui-bg-elev);
    border: var(--ui-border-width) solid var(--ui-border);
    border-radius: var(--ui-radius-md);
    transition: border-color var(--ui-transition-fast), box-shadow var(--ui-transition-fast);
}
.ui-input:focus, .ui-select:focus, .ui-textarea:focus {
    outline: none; border-color: var(--ui-primary);
    box-shadow: 0 0 0 3px hsl(var(--hp-hue-1) var(--hp-sat-1) 60% / 0.20);
}
.ui-textarea { resize: vertical; min-height: calc(var(--ui-space-4) * 4); }
.ui-tablesearch { display: flex; gap: var(--ui-space-1); align-items: center; }
.ui-tablesearch-btn { flex: 1; text-align: left; cursor: pointer; }
.ui-tablesearch-btn.ui-tablesearch-empty { color: var(--ui-fg-muted); }
.ui-tablesearch-clear { background: none; border: 0; cursor: pointer; color: var(--ui-fg-muted); padding: 0 var(--ui-space-1); }
.ui-tablesearch-btn.ui-tablesearch-invalid { border-color: var(--ui-danger); }
.ui-input-search { padding-left: var(--ui-space-7); background-position: var(--ui-space-2) center; background-repeat: no-repeat; }

.ui-checkbox { display: inline-flex; align-items: center; gap: var(--ui-space-2); cursor: pointer; user-select: none; }
.ui-checkbox input { position: absolute; opacity: 0; pointer-events: none; }
.ui-checkbox-mark {
    display: inline-flex; align-items: center; justify-content: center;
    width: 1.1rem; height: 1.1rem; border-radius: var(--ui-radius-sm);
    border: var(--ui-border-width) solid var(--ui-border-strong); background: var(--ui-bg-elev);
    transition: background var(--ui-transition-fast), border-color var(--ui-transition-fast);
}
.ui-checkbox input:checked + .ui-checkbox-mark { background: var(--ui-primary); border-color: var(--ui-primary); color: #fff; }
.ui-checkbox input:checked + .ui-checkbox-mark::after { content: "✓"; font-size: 0.85rem; line-height: 1; color: #fff; }

.ui-switch { display: inline-flex; align-items: center; gap: var(--ui-space-2); cursor: pointer; }
.ui-switch input { position: absolute; opacity: 0; }
.ui-switch-knob {
    position: relative; width: 2.4rem; height: 1.3rem; border-radius: var(--ui-radius-full);
    background: var(--ui-gray-300); transition: background var(--ui-transition-base);
}
.ui-switch-knob::after {
    content: ""; position: absolute; top: 0.15rem; left: 0.15rem;
    width: 1rem; height: 1rem; border-radius: var(--ui-radius-full);
    background: #fff; box-shadow: var(--ui-shadow-sm);
    transition: left var(--ui-transition-base) var(--ui-ease);
}
.ui-switch input:checked + .ui-switch-knob { background: var(--ui-primary); }
.ui-switch input:checked + .ui-switch-knob::after { left: 1.25rem; }

/* Containers */
.ui-card {
    background: var(--ui-bg-elev); border: var(--ui-border-width) solid var(--ui-border);
    border-radius: var(--ui-radius-lg); padding: var(--ui-space-4);
    box-shadow: var(--ui-shadow-md);
    transition: box-shadow var(--ui-transition-base) var(--ui-ease),
                transform var(--ui-transition-base) var(--ui-ease);
    position: relative; overflow: hidden;
}
.ui-card:hover { box-shadow: var(--ui-shadow-lg); transform: translateY(-1px); }
/* Nested cards — suppress shadow + border + heavy padding so a card-within-a-card
   looks like a section, not a separate floating element. The outer card already
   carries the visual weight. */
.ui-card .ui-card {
    box-shadow: none; border-color: var(--ui-border-faint, var(--ui-gray-100));
    padding: var(--ui-space-3);
}
.ui-card .ui-card:hover { box-shadow: none; transform: none; }
.ui-card .ui-card .ui-card { border: none; padding: var(--ui-space-2); background: transparent; }

.ui-bind-entity-card:hover { border-left-color: var(--ui-primary-300); }
.ui-bind-entity-card.ui-active {
    border-left-color: var(--ui-primary);
    background: var(--ui-primary-50);
    box-shadow: var(--ui-shadow-lg);
}
.ui-bind-entity-card.ui-deselected { border-left-color: var(--ui-border); }
/* Vivid header variants — use behind .ui-card for emphasis. */
.ui-card-primary   { background: var(--ui-primary-100);   border-color: var(--ui-primary-200); border-left: 4px solid var(--ui-primary); }
.ui-card-secondary { background: var(--ui-secondary-100); border-color: var(--ui-secondary-100); border-left: 4px solid var(--ui-secondary); }
.ui-card-success   { background: var(--ui-success-100);   border-color: var(--ui-success-100);   border-left: 4px solid var(--ui-success); }
.ui-card-warn      { background: var(--ui-warn-100);      border-color: var(--ui-warn-100);      border-left: 4px solid var(--ui-warn); }
.ui-card-danger    { background: var(--ui-danger-100);    border-color: var(--ui-danger-100);    border-left: 4px solid var(--ui-danger); }
.ui-card-flat::before { display: none; }
.ui-card-header { display: flex; flex-direction: column; gap: var(--ui-space-1); margin-bottom: var(--ui-space-2); }
.ui-card-icon { font-size: var(--ui-text-xl); line-height: 1; }
.ui-card-title { display: block; font-size: var(--ui-text-lg); font-weight: var(--ui-font-semibold); color: var(--ui-fg); }
.ui-card-subtitle { display: block; color: var(--ui-fg-muted); font-size: var(--ui-text-sm); }
.ui-card-body { color: var(--ui-fg); }
.ui-card-footer { margin-top: var(--ui-space-3); padding-top: var(--ui-space-2); border-top: var(--ui-border-width) solid var(--ui-border); }
.ui-container { display: block; }
/* Centered readable-width column — for standalone forms / single-record views
   that should not sprawl across a wide viewport. Token-overridable max-width. */
.ui-readable { max-width: var(--ui-readable-max-w, 44rem); margin-inline: auto; width: 100%; }
.ui-grid { gap: var(--ui-space-4); }
.ui-divider { height: 1px; background: var(--ui-border); margin: var(--ui-space-3) 0; border: 0; }

/* Modal + drawer share overlay */
.ui-overlay {
    position: fixed; inset: 0; background: rgba(15,23,42,0.45);
    display: flex; align-items: center; justify-content: center;
    opacity: 0; pointer-events: none; transition: opacity var(--ui-transition-base);
    z-index: 100;
}
.ui-overlay.ui-overlay-visible, .ui-overlay.ui-active { opacity: 1; pointer-events: auto; }
.ui-modal {
    background: var(--ui-bg-elev); border-radius: var(--ui-radius-xl);
    box-shadow: var(--ui-shadow-xl); padding: var(--ui-space-5);
    max-width: min(90vw, var(--ui-modal-max-w)); max-height: 90vh; overflow: auto;
    transform: scale(0.96); transition: transform var(--ui-transition-base) var(--ui-ease);
}
.ui-overlay.ui-active .ui-modal, .ui-overlay.ui-overlay-visible .ui-modal { transform: scale(1); }
.ui-drawer {
    position: fixed; top: 0; right: 0; height: 100vh; width: min(90vw, var(--ui-drawer-w));
    background: var(--ui-bg-elev); box-shadow: var(--ui-shadow-xl); padding: var(--ui-space-5);
    transform: translateX(100%); transition: transform var(--ui-transition-base) var(--ui-ease);
    z-index: 110; overflow: auto;
}
.ui-drawer.ui-active { transform: translateX(0); }

/* Badges + chips */
.ui-badge {
    display: inline-flex; align-items: center; gap: var(--ui-space-1);
    padding: 2px var(--ui-space-2); font-size: var(--ui-text-xs); font-weight: var(--ui-font-semibold);
    background: var(--ui-primary); color: var(--ui-on-primary);
    border-radius: var(--ui-radius-full); line-height: 1.4;
    text-transform: uppercase; letter-spacing: 0.04em;
    box-shadow: var(--ui-shadow-sm);
}
.ui-badge-muted   { background: var(--ui-bg-muted); color: var(--ui-fg-muted); text-transform: none; letter-spacing: 0; box-shadow: none; }
.ui-badge-info    { background: var(--ui-info);    color: #fff; }
.ui-badge-success { background: var(--ui-success); color: #fff; }
.ui-badge-warn    { background: var(--ui-warn);    color: #fff; }
.ui-badge-danger  { background: var(--ui-danger);  color: #fff; }
.ui-chipset { display: flex; flex-wrap: wrap; gap: var(--ui-space-2); }
.ui-chip {
    display: inline-flex; align-items: center; gap: var(--ui-space-1);
    padding: var(--ui-space-1) var(--ui-space-3); font-size: var(--ui-text-sm);
    background: var(--ui-bg-muted); border-radius: var(--ui-radius-full);
    cursor: pointer; transition: background var(--ui-transition-fast), color var(--ui-transition-fast);
    user-select: none;
}
.ui-chip-on { background: var(--ui-primary); color: var(--ui-on-primary); }
.ui-chip-off { background: var(--ui-bg-muted); color: var(--ui-fg-muted); }
.ui-chip:hover { filter: brightness(0.96); }
.ui-chip-sm { padding: 0 var(--ui-space-2); font-size: var(--ui-text-xs); }

/* Alerts + callouts */
.ui-alert, .ui-callout {
    display: flex; gap: var(--ui-space-3); padding: var(--ui-space-3) var(--ui-space-4);
    border-left: 4px solid var(--ui-info); background: var(--ui-info-100); color: var(--ui-fg);
    border-radius: var(--ui-radius-md); margin-bottom: var(--ui-space-3);
}
.ui-callout-danger, .ui-alert-danger, .ui-alert-error { border-color: var(--ui-danger); background: var(--ui-danger-100); }
.ui-callout-warning, .ui-alert-warning { border-color: var(--ui-warn); background: var(--ui-warn-100); }
.ui-callout-success, .ui-alert-success { border-color: var(--ui-success); background: var(--ui-success-100); }
.ui-alert-icon, .ui-callout-icon { flex-shrink: 0; font-size: var(--ui-text-lg); }
.ui-alert-title, .ui-callout-title { font-weight: var(--ui-font-semibold); margin: 0 0 var(--ui-space-1); }
.ui-alert-body, .ui-callout-body { flex: 1 1 auto; min-width: 0; line-height: var(--ui-leading-normal); }
.ui-alert-body > p:first-child, .ui-callout-body > p:first-child { margin-top: 0; }
.ui-alert-body > p:last-child, .ui-callout-body > p:last-child { margin-bottom: 0; }
.ui-alert-close { margin-left: auto; cursor: pointer; opacity: 0.6; }
.ui-alert-close:hover { opacity: 1; }

/* Spinner + progress */
.ui-spinner {
    display: inline-block; width: 1.25rem; height: 1.25rem;
    border: 2px solid var(--ui-border); border-top-color: var(--ui-primary);
    border-radius: 50%; animation: ui-spin 0.8s linear infinite;
}
@keyframes ui-spin { to { transform: rotate(360deg); } }
.ui-progress {
    height: 6px; background: var(--ui-bg-muted); border-radius: var(--ui-radius-full); overflow: hidden;
}
.ui-progress-bar {
    height: 100%; background: var(--ui-primary); border-radius: inherit;
    transition: width var(--ui-transition-base) var(--ui-ease);
}
.ui-progress-bar.ui-bar-good { background: var(--ui-success); }
.ui-progress-bar.ui-bar-warn { background: var(--ui-warn); }
.ui-progress-bar.ui-bar-bad  { background: var(--ui-danger); }

/* Circular progress ring (progress shape:'ring' + report cards) */
.ui-progress-ring { position: relative; width: 64px; height: 64px; flex: 0 0 64px; }
.ui-ring-svg   { width: 100%; height: 100%; transform: rotate(-90deg); }
.ui-ring-track { fill: none; stroke: var(--ui-bg-muted); stroke-width: 6; }
.ui-ring-fill  { fill: none; stroke-width: 6; stroke-linecap: round; transition: stroke-dashoffset var(--ui-transition-base) var(--ui-ease); }
.ui-ring-good  { stroke: var(--ui-success); }
.ui-ring-warn  { stroke: var(--ui-warn); }
.ui-ring-bad   { stroke: var(--ui-danger); }
.ui-ring-label { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: var(--ui-text-sm); font-weight: var(--ui-font-bold); }

/* Status pill */
.ui-pill         { display: inline-block; padding: 0 var(--ui-space-2); border-radius: var(--ui-radius-full); font-size: var(--ui-text-xs); font-weight: var(--ui-font-semibold); background: var(--ui-bg-muted); color: var(--ui-fg-muted); white-space: nowrap; }
.ui-pill-success { background: var(--ui-success); color: #fff; }
.ui-pill-warn    { background: var(--ui-warn);    color: #fff; }
.ui-pill-danger  { background: var(--ui-danger);  color: #fff; }

/* Report card — header (title + pill), optional ring, metric chips + value bars */
.ui-reportcard        { display: flex; flex-direction: column; gap: var(--ui-space-2); padding: var(--ui-space-3); background: var(--ui-bg); border: 1px solid var(--ui-border); border-radius: var(--ui-radius-lg); box-shadow: var(--ui-shadow-sm); }
.ui-reportcard-head   { display: flex; align-items: flex-start; gap: var(--ui-space-2); }
.ui-reportcard-titles { flex: 1; min-width: 0; }
.ui-reportcard-title  { font-weight: var(--ui-font-bold); }
.ui-reportcard-sub    { font-size: var(--ui-text-sm); color: var(--ui-fg-muted); }
.ui-reportcard-body   { display: flex; gap: var(--ui-space-3); align-items: center; }
.ui-reportcard-detail { flex: 1; min-width: 0; max-width: 40rem; display: flex; flex-direction: column; gap: var(--ui-space-1); }
.ui-reportcard-metrics { display: flex; flex-wrap: wrap; gap: var(--ui-space-2); }
.ui-reportcard-metrics .ui-metric-chip { flex: 0 0 auto; }
.ui-reportcard-bar    { display: flex; align-items: center; gap: var(--ui-space-2); }
.ui-reportcard-bar-label { flex: 0 0 9rem; font-size: var(--ui-text-sm); color: var(--ui-fg-muted); }
.ui-reportcard-bar .ui-progress { flex: 1; }
.ui-reportcard-bar-val   { flex: 0 0 3rem; text-align: right; font-size: var(--ui-text-sm); font-weight: var(--ui-font-semibold); }
.ui-reportcard-foot   { font-size: var(--ui-text-xs); color: var(--ui-fg-muted); }

/* Avatar + metric chip + empty state */
/* Avatar — fixed-size circle. Image fills via object-fit; initials centred. */
.ui-avatar {
    display: inline-flex; align-items: center; justify-content: center;
    width: var(--ui-avatar-size); height: var(--ui-avatar-size); flex: 0 0 auto;
    padding: 0; border-radius: var(--ui-radius-full); overflow: hidden;
    background: var(--ui-primary-600); color: #fff;
    font-weight: var(--ui-font-bold); font-size: var(--ui-text-sm); line-height: 1;
    box-shadow: var(--ui-shadow-sm);
    border: 2px solid var(--ui-bg-elev);
    user-select: none;
}
.ui-avatar-sm { width: 2rem; height: 2rem; font-size: var(--ui-text-xs); }
.ui-avatar-lg { width: 3.2rem; height: 3.2rem; font-size: var(--ui-text-lg); }
.ui-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* 8-shade hash cycle, 60-30-10 across primary/secondary/accent. */
.ui-avatar-c0 { background: hsl(calc(var(--hp-hue-1) - 30)      calc(var(--hp-sat-1) * 0.7) 45%); }
.ui-avatar-c1 { background: hsl(var(--hp-hue-1)                  calc(var(--hp-sat-1) * 0.8) 42%); }
.ui-avatar-c2 { background: hsl(calc(var(--hp-hue-1) + 25)      calc(var(--hp-sat-1) * 0.7) 40%); }
.ui-avatar-c3 { background: hsl(calc(var(--hp-hue-1) + 50)      calc(var(--hp-sat-1) * 0.6) 42%); }
.ui-avatar-c4 { background: hsl(calc(var(--hp-hue-2) - 20)      calc(var(--hp-sat-2) * 0.7) 45%); }
.ui-avatar-c5 { background: hsl(var(--hp-hue-2)                  calc(var(--hp-sat-2) * 0.8) 42%); }
.ui-avatar-c6 { background: hsl(calc(var(--hp-hue-2) + 30)      calc(var(--hp-sat-2) * 0.7) 40%); }
.ui-avatar-c7 { background: hsl(var(--hp-hue-accent)             calc(var(--hp-sat-accent) * 0.85) 38%); }
.ui-avatar-success { background: var(--ui-success); }
.ui-avatar-warn    { background: var(--ui-warn); }
.ui-avatar-danger  { background: var(--ui-danger); }
.ui-avatar-info    { background: var(--ui-info); }
.ui-metric-chip {
    display: inline-flex; align-items: baseline; gap: var(--ui-space-2);
    padding: var(--ui-space-2) var(--ui-space-3); border-radius: var(--ui-radius-md);
    background: var(--ui-primary-100);
    border-left: 3px solid var(--ui-primary);
    font-size: var(--ui-text-sm);
}
.ui-metric-chip strong { color: var(--ui-primary-700); font-weight: var(--ui-font-bold); font-size: var(--ui-text-base); }
.ui-metric-chip-secondary { background: var(--ui-secondary-100); border-left-color: var(--ui-secondary); }
.ui-metric-chip-secondary strong { color: var(--ui-secondary-700); }
.ui-metric-chip-accent    { background: hsl(var(--hp-hue-accent) calc(var(--hp-sat-accent) * 0.4) 92%); border-left-color: var(--ui-accent); }
.ui-metric-chip-accent strong    { color: var(--ui-accent); }
/* Empty-state chip: data hasn't loaded yet. Muted so it reads as "slot
 * waiting" rather than "loaded with em-dash" — see UIBind.renderMetricChip
 * which applies this modifier when the value is '—'. */
.ui-metric-chip-empty           { background: var(--ui-gray-50); border-left-color: var(--ui-gray-300); }
.ui-metric-chip-empty strong    { color: var(--ui-gray-400); font-weight: var(--ui-font-normal); }
.ui-metric-chip-empty .ui-metric-chip-icon { opacity: 0.4; }
.ui-empty {
    text-align: center; padding: var(--ui-space-7) var(--ui-space-4);
    color: var(--ui-fg-muted); font-size: var(--ui-text-sm);
}
.ui-empty-icon { font-size: var(--ui-text-3xl); margin-bottom: var(--ui-space-3); opacity: 0.45; }

/* Tooltip */
.ui-tooltip {
    position: absolute; z-index: 200; padding: var(--ui-space-1) var(--ui-space-2);
    background: var(--ui-gray-800); color: #fff; border-radius: var(--ui-radius-sm);
    font-size: var(--ui-text-xs); pointer-events: none; box-shadow: var(--ui-shadow-md);
    opacity: 0; transition: opacity var(--ui-transition-fast);
}
.ui-tooltip.ui-active { opacity: 1; }

/* Tabs / accordion / ribbon / nav / stepper / segmented / sidebar */
.ui-tabs { display: flex; flex-direction: column; min-height: 0; }
.ui-tabs-bar {
    display: flex; gap: var(--ui-space-1); border-bottom: var(--ui-border-width) solid var(--ui-border);
    padding: 0 var(--ui-space-2); overflow-x: auto;
}
.ui-tabs-head, .ui-ribbon-item, .ui-segmented-item, .ui-navbar-item, .ui-sidebar-item, .ui-stepper-item {
    display: inline-flex; align-items: center; gap: var(--ui-space-2);
    padding: var(--ui-space-2) var(--ui-space-3); cursor: pointer;
    color: var(--ui-fg-muted); font-weight: var(--ui-font-medium);
    border-radius: var(--ui-radius-md); transition: background var(--ui-transition-fast), color var(--ui-transition-fast);
    user-select: none; white-space: nowrap; border: none; background: transparent;
}
.ui-tabs-head:hover, .ui-ribbon-item:hover, .ui-navbar-item:hover, .ui-sidebar-item:hover, .ui-segmented-item:hover { background: var(--ui-bg-muted); color: var(--ui-fg); }
.ui-tabs-head { padding-bottom: var(--ui-space-3); border-radius: 0; border-bottom: var(--ui-tab-underline-w) solid transparent; margin-bottom: -1px; }
.ui-tabs-head.ui-active { color: var(--ui-primary); border-bottom-color: var(--ui-primary); background: transparent; }
.ui-ribbon { display: flex; gap: var(--ui-space-2); padding: var(--ui-space-2); background: var(--ui-bg-muted); border-radius: var(--ui-radius-md); }
.ui-ribbon-item.ui-active, .ui-segmented-item.ui-active, .ui-navbar-item.ui-active { background: var(--ui-primary); color: var(--ui-on-primary); }
.ui-segmented { display: inline-flex; padding: 2px; background: var(--ui-bg-muted); border-radius: var(--ui-radius-md); }
.ui-navbar { display: flex; gap: var(--ui-space-1); padding: var(--ui-space-2); background: var(--ui-bg-elev); border-bottom: var(--ui-border-width) solid var(--ui-border); }
.ui-stepper { display: flex; gap: var(--ui-space-2); padding: var(--ui-space-2); }
.ui-stepper-step { display: flex; align-items: center; gap: var(--ui-space-2); flex: 1; }
.ui-stepper-step::after { content: ""; flex: 1; height: 2px; background: var(--ui-border); }
.ui-stepper-step:last-child::after { display: none; }
.ui-stepper-item.ui-active { color: var(--ui-primary); }

.ui-sidebar { display: flex; flex-direction: column; padding: var(--ui-space-3); gap: var(--ui-space-1); background: var(--ui-bg-elev); border-right: var(--ui-border-width) solid var(--ui-border); }
.ui-sidebar-item { padding: var(--ui-space-2) var(--ui-space-3); justify-content: flex-start; }
.ui-sidebar-item.ui-active { background: var(--ui-primary-100); color: var(--ui-primary-700); border-left: 3px solid var(--ui-primary); padding-left: calc(var(--ui-space-3) - 3px); font-weight: var(--ui-font-semibold); }
.ui-sidebar-section { margin-top: var(--ui-space-3); }
.ui-sidebar-section-title { font-size: var(--ui-text-xs); text-transform: uppercase; letter-spacing: 0.06em; color: var(--ui-fg-muted); padding: var(--ui-space-2) var(--ui-space-3); }

.ui-accordion { display: flex; flex-direction: column; border: var(--ui-border-width) solid var(--ui-border); border-radius: var(--ui-radius-md); overflow: hidden; background: var(--ui-bg-elev); }
.ui-accordion-item + .ui-accordion-item, .ui-accordion-entry + .ui-accordion-entry { border-top: var(--ui-border-width) solid var(--ui-border); }
.ui-accordion-head { display: flex; align-items: center; gap: var(--ui-space-2); padding: var(--ui-space-2) var(--ui-space-3); cursor: pointer; font-size: var(--ui-text-xs); font-weight: var(--ui-font-semibold); text-transform: uppercase; letter-spacing: 0.04em; background: var(--ui-bg-muted); color: var(--ui-fg-muted); transition: background var(--ui-transition-fast), color var(--ui-transition-fast); }
.ui-accordion-head:hover { background: var(--ui-bg-sunken); }
.ui-accordion-head::after { content: "›"; margin-left: auto; font-size: 1.2em; line-height: 1; transition: transform var(--ui-transition-fast); }
.ui-accordion-item.ui-active > .ui-accordion-head::after, .ui-accordion-entry.ui-active > .ui-accordion-head::after { transform: rotate(90deg); }
.ui-accordion-item.ui-active > .ui-accordion-head, .ui-accordion-entry.ui-active > .ui-accordion-head { background: var(--ui-primary); color: var(--ui-on-primary); }
.ui-accordion-body, .ui-accordion-content { padding: var(--ui-space-3); }
.ui-accordion-item:not(.ui-active) > .ui-accordion-body { display: none; }

.ui-breadcrumbs { display: flex; gap: var(--ui-space-2); font-size: var(--ui-text-sm); color: var(--ui-fg-muted); }
.ui-breadcrumbs > * + *::before { content: "›"; margin-right: var(--ui-space-2); color: var(--ui-fg-muted); }

/* ───────────────────────────────────────────────────────────────────────────
   PAGE-FRAME LAYOUT — DOCUMENT-FLOW STICKY FOOTER (read before changing this).

   Want: the footer sits at the bottom of the VIEWPORT when the page is short,
   and is PUSHED DOWN by the content (the whole PAGE scrolls) when the content is
   tall. This is the classic CSS sticky footer — NOT an app-shell with an
   internally-scrolling body. The footer comes after the body in normal flow.

   Three load-bearing rules:
     1. Frame = flex COLUMN, MIN-height of one viewport:
          display:flex; flex-direction:column; min-height:100dvh;
        `min-height` (NOT `height`) is the whole point — the frame must be free to
        grow taller than the screen so the footer travels down with the content.
     2. Header + footer size to content, never grow/shrink:  flex:0 0 auto;
     3. Body grows to fill the gap (pinning the footer to the viewport bottom when
        the page is short) but is NEVER capped and does NOT scroll internally:
          flex:1 0 auto;
        No overflow/min-height:0 on the body — that would trap scrolling inside it
        and pin the footer (the app-shell behaviour we explicitly do NOT want).

   The PAGE is the scroll container. Do NOT reintroduce height:100dvh on the frame
   or overflow:auto on the body — that pins the footer and reads as "fixed", the
   recurring regression. If ONE pane genuinely needs its own scroll, cap THAT pane
   (max-height + overflow) — never the frame.
   ─────────────────────────────────────────────────────────────────────────── */
.ui-pageframe { display: flex; flex-direction: column; min-height: 100dvh; background: var(--ui-bg); }
.ui-pageframe-header, .ui-pageframe-footer { flex: 0 0 auto; }
/* The content region between header and footer: grow to push the footer down; the page scrolls. */
.ui-pageframe > :not(.ui-pageframe-header):not(.ui-pageframe-footer) { flex: 1 0 auto; }
.ui-pageframe .ui-pageframe { min-height: 0; }   /* a nested frame flows; it does not start a 2nd viewport */
/* `.ui-pageframe-app` was an opt-in "fixed shell" modifier; harmless alias now. */
.ui-pageframe-header {
    display: flex; align-items: center; gap: var(--ui-space-5);
    padding: var(--ui-space-3) var(--ui-space-5);
    background: var(--ui-primary);
    color: var(--ui-on-primary);
    border-bottom: 0;
    box-shadow: var(--ui-shadow-md);
    /* Sticky so the nav stays visible while the PAGE scrolls (document-flow
       sticky-footer model — see the PAGE-FRAME LAYOUT block above). */
    flex-shrink: 0; position: sticky; top: 0; z-index: 5;
}
.ui-pageframe-header .ui-pageframe-title    { color: var(--ui-on-primary); }
.ui-pageframe-header .ui-pageframe-subtitle { color: var(--ui-on-primary-muted); }
.ui-pageframe-header .ui-pageframe-brand-mark {
    background: var(--ui-on-primary-bg-strong); color: var(--ui-on-primary);
    box-shadow: inset 0 0 0 1px var(--ui-on-primary-divider);
}
.ui-pageframe-action {
    color: var(--ui-on-primary); border-radius: var(--ui-radius-md);
    width: 2rem; height: 2rem;
}
.ui-pageframe-action:hover { background: var(--ui-on-primary-bg-strong); color: var(--ui-on-primary); }
.ui-pageframe-action > i.fa { font-size: 1rem; line-height: 1; }
.ui-sidebar-item .fa, .ui-tabs-head .fa { font-size: 0.95em; opacity: 0.85; margin-right: 0.25rem; }
.ui-pageframe-brand { display: flex; align-items: center; gap: var(--ui-space-3); line-height: 1.2; min-width: 0; }
.ui-pageframe-brand-mark {
    display: inline-flex; align-items: center; justify-content: center;
    aspect-ratio: 1; padding: var(--ui-space-2);
    border-radius: var(--ui-radius-md);
    background: var(--ui-primary);
    color: #fff; font-weight: var(--ui-font-bold);
    font-size: var(--ui-text-lg); line-height: 1;
    box-shadow: var(--ui-shadow-sm);
    flex-shrink: 0;
}
.ui-pageframe-brand-stack { display: flex; flex-direction: column; min-width: 0; gap: 2px; }
.ui-pageframe-title { font-size: var(--ui-text-lg); font-weight: var(--ui-font-semibold); color: var(--ui-fg); white-space: nowrap; }
.ui-pageframe-subtitle { color: var(--ui-fg-muted); font-size: var(--ui-text-xs); }
.ui-pageframe-actions { margin-left: auto; display: flex; gap: var(--ui-space-2); align-items: center; }
/* In-header tabs — translucent white on primary background. */
.ui-pageframe-tabs { flex: 0 1 auto; background: transparent; display: flex; min-width: 0; }
.ui-pageframe-tabs > * { min-width: 0; }
.ui-pageframe-tabs .ui-tabs-bar { border-bottom: 0; padding: 0; gap: var(--ui-space-2); }
.ui-pageframe-tabs .ui-tabs-head {
    color: var(--ui-on-primary-muted); border-bottom: var(--ui-tab-underline-w) solid transparent;
    margin-bottom: 0;
}
.ui-pageframe-tabs .ui-tabs-head:hover { color: var(--ui-on-primary); background: var(--ui-on-primary-bg-soft); }
.ui-pageframe-tabs .ui-tabs-head.ui-active {
    color: var(--ui-on-primary); background: var(--ui-on-primary-bg-strong);
    border-bottom-color: var(--ui-on-primary);
}
/* Padding only — fill/scroll comes from the catch-all rule above (the single
   content child gets flex:1 1 auto; min-height:0; overflow:auto). Do NOT add a
   flex value with `0` shrink here; it re-breaks the sticky footer. */
/* ONE padding level only. The frame nests body > stage and content mounts into
   the stage (or the hub-page-host inside it), so padding BOTH stacked 32px of
   dead space at the top/bottom. Pad the stage; the body is a bare flex wrapper. */
.ui-pageframe-stage { padding: var(--ui-space-4); }

/* Login shield host (mounted between header and footer by System._mountShield).
   Layout + visuals only. The card's WIDTH is set inline by System._mountShield
   from `config.shield.width` so a designer can override per-system without
   fighting CSS specificity. */
.ui-system-shield-host {
    display: flex;
    align-items: flex-start;
    justify-content: center;
    flex: 1 0 auto;
    padding: var(--ui-space-7) var(--ui-space-4);
    min-height: 60vh;
    background: var(--ui-bg-sunken, transparent);
}
.ui-system-shield-host > .ui {
    width: 100%;
    background: var(--ui-bg-elev);
    border: 1px solid var(--ui-border);
    border-radius: var(--ui-radius-lg);
    padding: var(--ui-space-6) var(--ui-space-5);
    box-shadow: var(--ui-shadow-md);
}
.ui-pageframe-footer {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--ui-space-5);
    padding: var(--ui-space-5) var(--ui-space-5);
    background: var(--ui-gray-900);
    color: var(--ui-on-primary-muted);
    border-top: 3px solid var(--ui-accent);
    font-size: var(--ui-text-sm); flex-shrink: 0;
}
.ui-pageframe-footer-column { display: flex; flex-direction: column; gap: var(--ui-space-1); min-width: 0; }
.ui-pageframe-footer-title { font-weight: var(--ui-font-semibold); color: var(--ui-on-primary); margin-bottom: var(--ui-space-2); font-size: var(--ui-text-sm); text-transform: uppercase; letter-spacing: 0.06em; }
.ui-pageframe-footer-link { color: rgba(255,255,255,0.7); transition: color var(--ui-transition-fast); }
.ui-pageframe-footer-link:hover { color: #fff; }
.ui-pageframe-footer-text { color: rgba(255,255,255,0.72); font-size: var(--ui-text-sm); }
.ui-pageframe-footer-copyright { grid-column: 1 / -1; padding-top: var(--ui-space-3); border-top: 1px solid rgba(255,255,255,0.12); margin-top: var(--ui-space-3); text-align: center; font-size: var(--ui-text-xs); color: rgba(255,255,255,0.55); }
.ui-footer { display: flex; align-items: center; gap: var(--ui-space-3); padding: var(--ui-space-3); background: var(--ui-bg-muted); }

/* Control-stage — fluid grid, content sizes the control column. */
.ui-control-stage {
    display: grid;
    grid-template-columns: minmax(min-content, 1fr) 3fr;
    gap: var(--ui-space-4);
}
.ui-control-stage-control { display: flex; flex-direction: column; gap: var(--ui-space-3); min-height: 0; overflow: auto; }
.ui-control-stage-stage   { display: flex; flex-direction: column; min-width: 0; min-height: 0; overflow: auto; }
@media (max-width: 800px) { .ui-control-stage { grid-template-columns: 1fr; } }

/* Forms */
.ui-form { display: flex; flex-direction: column; gap: var(--ui-space-3); }
.ui-form-field { display: flex; flex-direction: column; gap: var(--ui-space-1); }
.ui-form-label { font-size: var(--ui-text-sm); font-weight: var(--ui-font-medium); color: var(--ui-fg); }
.ui-form-buttons { display: flex; gap: var(--ui-space-2); margin-top: var(--ui-space-3); }

/* Data list / cards / tree / pager */
.ui-data { display: flex; flex-direction: column; min-height: 0; gap: var(--ui-space-2); }
.ui-data-list-content { display: flex; flex-direction: column; min-height: 0; overflow: auto; }
.ui-data-list-row, .ui-bind-list-row {
    display: flex; align-items: center; gap: var(--ui-space-3); padding: var(--ui-space-2) var(--ui-space-3);
    border-bottom: var(--ui-border-width) solid var(--ui-border); cursor: pointer;
    transition: background var(--ui-transition-fast), border-left-color var(--ui-transition-fast);
    border-left: var(--ui-active-marker-w) solid transparent;
}
.ui-data-list-row:hover, .ui-bind-list-row:hover { background: var(--ui-bg-muted); border-left-color: var(--ui-primary-300); }
.ui-data-list-row.ui-active, .ui-bind-list-row.ui-active { background: var(--ui-primary-100); color: var(--ui-primary-700); border-left-color: var(--ui-primary); }
/* Cards grid — items live in a sub-host (.ui-bind-cards-items) so toolbar
   + pager can sit above/below as flex siblings of the grid, not as grid
   items. auto-fill keeps every column the same width on the last row. */
.ui-bind-cards { display: flex; flex-direction: column; gap: var(--ui-space-2); padding: var(--ui-space-2); }
.ui-data-cards-grid, .ui-bind-cards-items { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: var(--ui-space-3); align-items: stretch; align-content: start; }
.ui-data-cards-grid > .ui-card, .ui-bind-cards-items > .ui-card { min-width: 0; display: flex; flex-direction: column; }
.ui-data-card, .ui-bind-entity-card {
    background: var(--ui-bg-elev); border: var(--ui-border-width) solid var(--ui-border);
    border-left: var(--ui-active-marker-w) solid transparent;
    border-radius: var(--ui-radius-lg); padding: var(--ui-space-3);
    cursor: pointer; transition: box-shadow var(--ui-transition-fast), transform var(--ui-transition-fast);
}
.ui-data-card:hover, .ui-bind-entity-card:hover { box-shadow: var(--ui-shadow-md); transform: translateY(-1px); }
.ui-bind-entity-card-header, .ui-bind-entity-card-title { font-weight: var(--ui-font-semibold); margin-bottom: var(--ui-space-1); }
.ui-bind-entity-card-body { color: var(--ui-fg-muted); font-size: var(--ui-text-sm); }
.ui-bind-entity-card-actions, .ui-bind-list-actions { display: flex; gap: var(--ui-space-2); margin-top: var(--ui-space-2); }
/* Layout root — minimal. Each template adds its own display rules.
   Charts size themselves from CONTENT (Plotly height = N_bars × bar_height).
   Kanban lanes size themselves from card count. Don't force container
   heights — that squashes bars when N is large or wastes space when N
   is small. */
.ui-bind-layout { min-height: 0; }
/* A chart layout (calendar/kanban/graph…) needs a resolved height to draw into;
   without this the block-level bind-layout collapses to content height and the
   chart's height:100% resolves to ~0. Scoped to chart hosts so list/table/form
   layouts (content-height by design) are untouched. */
.ui-bind-layout:has(> .ui-chart) { height: 100%; }
.ui-paginator { display: flex; align-items: center; gap: var(--ui-space-3); padding: var(--ui-space-2) var(--ui-space-3); border-top: var(--ui-border-width) solid var(--ui-border); font-size: var(--ui-text-sm); }
.ui-paginator-controls { display: flex; gap: var(--ui-space-1); margin-left: auto; }
.ui-paginator-btn { padding: var(--ui-space-1) var(--ui-space-2); border: var(--ui-border-width) solid var(--ui-border); border-radius: var(--ui-radius-sm); background: var(--ui-bg-elev); cursor: pointer; }
.ui-paginator-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.ui-paginator-btn:hover:not(:disabled) { background: var(--ui-bg-muted); }
.ui-paginator-info { color: var(--ui-fg-muted); }

.ui-tree { display: flex; flex-direction: column; gap: var(--ui-space-1); padding: var(--ui-space-2); }
.ui-tree-node, .ui-bind-tree-node {
    position: relative;
    display: flex; align-items: center; gap: var(--ui-space-2);
    padding: var(--ui-space-1) var(--ui-space-2); border-radius: var(--ui-radius-sm);
    cursor: pointer; transition: background var(--ui-transition-fast),
                                  border-color var(--ui-transition-fast);
    padding-left: calc(var(--ui-space-2) + var(--ui-tree-depth, 0) * var(--ui-space-5));
    border-left: var(--ui-active-marker-w) solid transparent;
}
.ui-tree-node:hover, .ui-bind-tree-node:hover {
    background: var(--ui-bg-muted);
    border-left-color: var(--ui-primary-300);
}
.ui-tree-node.ui-active, .ui-bind-tree-node.ui-active {
    background: var(--ui-primary-100); color: var(--ui-primary-700);
    border-left-color: var(--ui-primary); font-weight: var(--ui-font-semibold);
}
.ui-bind-tree-node.ui-deselected { border-left-color: var(--ui-border); }
.ui-tree-bullet { color: var(--ui-fg-muted); font-size: var(--ui-text-xs); }
/* L5.6 — per-table colour for chain renderers (tree nodes + chips). Hash 0-7 reuses the avatar palette HSL spec. */
[data-table-hash="0"] { --ui-table-color: hsl(calc(var(--hp-hue-1) - 30) calc(var(--hp-sat-1) * 0.7) 45%); }
[data-table-hash="1"] { --ui-table-color: hsl(var(--hp-hue-1) calc(var(--hp-sat-1) * 0.8) 42%); }
[data-table-hash="2"] { --ui-table-color: hsl(calc(var(--hp-hue-1) + 25) calc(var(--hp-sat-1) * 0.7) 40%); }
[data-table-hash="3"] { --ui-table-color: hsl(calc(var(--hp-hue-1) + 50) calc(var(--hp-sat-1) * 0.6) 42%); }
[data-table-hash="4"] { --ui-table-color: hsl(calc(var(--hp-hue-2) - 20) calc(var(--hp-sat-2) * 0.7) 45%); }
[data-table-hash="5"] { --ui-table-color: hsl(var(--hp-hue-2) calc(var(--hp-sat-2) * 0.8) 42%); }
[data-table-hash="6"] { --ui-table-color: hsl(calc(var(--hp-hue-2) + 30) calc(var(--hp-sat-2) * 0.7) 40%); }
[data-table-hash="7"] { --ui-table-color: hsl(var(--hp-hue-accent) calc(var(--hp-sat-accent) * 0.85) 38%); }
.ui-bind-tree-node[data-table-hash] { border-left-color: var(--ui-table-color); border-left-width: 3px; }
.ui-bind-tree-node[draggable="true"] { cursor: move; }
.ui-bind-tree-node[draggable="true"]:hover { outline: 2px dashed var(--ui-primary-300); outline-offset: -2px; }
.ui-chip[data-table-hash] { color: var(--ui-table-color); border: 1px solid var(--ui-table-color); }

/* Tree — twisty + folder/leaf icon in front of the label. */
.ui-bind-tree { padding: var(--ui-space-2); }
.ui-bind-tree-rows { display: flex; flex-direction: column; gap: 2px; }
.ui-bind-tree-twisty { display: inline-flex; align-items: center; justify-content: center; width: 0.9rem; height: 0.9rem; flex-shrink: 0; color: var(--ui-fg-muted); font-size: 0.65rem; line-height: 1; }
.ui-bind-tree-twisty-active { cursor: pointer; }
.ui-bind-tree-twisty-active:hover { color: var(--ui-primary); }
.ui-bind-tree-icon { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; width: 1.1rem; height: 1.1rem; line-height: 1; font-size: var(--ui-text-base); }
.ui-bind-tree-icon-leaf { opacity: 0.55; }
.ui-bind-tree-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Charts */
.ui-chart, .ui-chart-frame { display: flex; flex-direction: column; min-height: 0; height: 100%; background: var(--ui-bg-elev); border-radius: var(--ui-radius-lg); border: var(--ui-border-width) solid var(--ui-border); padding: var(--ui-space-3); position: relative; }
.ui-chart-frame.ui-chart-fixed-h { height: var(--ui-chart-h); }
.ui-chart-frame.ui-chart-flex { flex: 0 0 auto; min-height: 0; height: var(--ui-chart-min-h, clamp(200px, 26vh, 300px)); overflow: hidden; }
.ui-chart-panel { background: var(--ui-bg-elev); border: var(--ui-border-width) solid var(--ui-border); border-radius: var(--ui-radius-lg); }
.ui-chart-panel .ui-chart-panel-header { padding: var(--ui-space-2) var(--ui-space-3); border-bottom: var(--ui-border-width) solid var(--ui-border); font-weight: var(--ui-font-semibold); }
.ui-chart-panel .ui-chart-panel-body { padding: var(--ui-space-3); height: var(--ui-chart-panel-h, 300px); }
.ui-chart-panel-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--ui-space-2); }
.ui-chart-panel-body { flex: 1 1 auto; min-height: 0; }
.ui-chart-title { font-weight: var(--ui-font-semibold); }
.ui-chart-empty { display: flex; align-items: center; justify-content: center; min-height: 12rem; color: var(--ui-fg-muted); font-size: var(--ui-text-sm); }

/* Kanban + timeline */
.ui-kanban { display: flex; gap: var(--ui-space-3); padding: var(--ui-space-2); align-items: stretch; overflow-x: auto; min-height: 14rem; }
/* Lanes grow when few; shrink to a still-readable floor (8.5rem) so a fixed
   board (6-stage pipeline) fits without hidden scroll, then scroll past that. */
.ui-kanban-lane { flex: 1 1 11rem; min-width: 8.5rem; display: flex; flex-direction: column; background: var(--ui-bg-muted); border-radius: var(--ui-radius-lg); padding: var(--ui-space-2); }
.ui-kanban-lane-header { font-weight: var(--ui-font-semibold); padding: var(--ui-space-2); display: flex; justify-content: space-between; gap: var(--ui-space-2); }
.ui-kanban-lane-body { display: flex; flex-direction: column; gap: var(--ui-space-2); flex: 1 1 auto; }
.ui-kanban-card { background: var(--ui-bg-elev); border-radius: var(--ui-radius-md); padding: var(--ui-space-3); box-shadow: var(--ui-shadow-sm); cursor: pointer; transition: transform var(--ui-transition-fast); border-left: 3px solid var(--ui-kanban-card-accent, var(--ui-primary)); }
.ui-kanban-card:hover { transform: translateY(-1px); box-shadow: var(--ui-shadow-md); }
.ui-kanban-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--ui-kanban-dot-color, var(--ui-primary)); }
.ui-timeline { display: flex; flex-direction: column; gap: var(--ui-space-3); padding-left: var(--ui-space-4); border-left: 2px solid var(--ui-border); }
.ui-timeline-item { display: flex; flex-direction: column; gap: var(--ui-space-1); position: relative; }
.ui-timeline-item::before { content: ""; position: absolute; left: calc(-1 * var(--ui-space-4) - 5px); top: 0.4rem; width: 8px; height: 8px; border-radius: 50%; background: var(--ui-primary); }
.ui-timeline-time { font-size: var(--ui-text-xs); color: var(--ui-fg-muted); }
.ui-timeline-body { font-size: var(--ui-text-sm); }

/* Datatables.net integration */
.ui-data-table { width: 100%; border-collapse: collapse; font-size: var(--ui-text-sm); }
.ui-data-table th, .ui-data-table td { padding: var(--ui-space-2) var(--ui-space-3); border-bottom: var(--ui-border-width) solid var(--ui-border); text-align: left; }
.ui-data-table thead th { background: var(--ui-bg-muted); font-weight: var(--ui-font-semibold); color: var(--ui-fg); }
.ui-data-table tbody tr:hover { background: var(--ui-bg-muted); }
.ui-dt-toolbar, .ui-dt-foot { display: flex; align-items: center; gap: var(--ui-space-3); padding: var(--ui-space-2) 0; }
.ui-dt-search input { padding: var(--ui-space-1) var(--ui-space-3); border: var(--ui-border-width) solid var(--ui-border); border-radius: var(--ui-radius-sm); background: var(--ui-bg-elev); }
.ui-dt-buttons { display: flex; gap: var(--ui-space-2); }
.ui-dt-paging { margin-left: auto; display: flex; gap: var(--ui-space-1); }
.ui-dt-info { color: var(--ui-fg-muted); font-size: var(--ui-text-xs); }
.ui-dt-length, .ui-dt-body { display: flex; align-items: center; gap: var(--ui-space-2); }

/* Misc */
.ui-print-label-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: var(--ui-space-3); padding: var(--ui-space-2); }
.ui-print-label-sheet { page-break-after: always; break-after: page; }
.ui-print-label-sheet + .ui-print-label-sheet { margin-top: var(--ui-space-4); padding-top: var(--ui-space-3); border-top: 1px dashed var(--ui-border); }
@media print { .ui-print-label-sheet + .ui-print-label-sheet { margin-top: 0; padding-top: 0; border-top: none; } }
.ui-print-label { display: flex; align-items: center; gap: var(--ui-space-3); padding: var(--ui-space-3); border: 1px solid var(--ui-border-strong); border-radius: var(--ui-radius-sm); background: var(--ui-bg-elev); font-size: var(--ui-text-sm); }
.ui-print-label-qr { width: 5rem; height: 5rem; flex-shrink: 0; background: var(--ui-bg-muted); display: flex; align-items: center; justify-content: center; font-family: var(--ui-font-mono); font-size: var(--ui-text-2xs); border-radius: var(--ui-radius-sm); }
.ui-map-marker { width: 1.1rem; height: 1.1rem; border-radius: 50%; background: var(--ui-marker-color, var(--ui-primary)); border: 2px solid var(--ui-bg-elev); box-shadow: var(--ui-shadow-md); cursor: pointer; transition: transform 120ms ease, box-shadow 120ms ease; }
.ui-map-marker:hover { transform: scale(1.2); }
.ui-map-marker.ui-map-marker-highlight { transform: scale(1.4); box-shadow: 0 0 0 3px var(--ui-primary-bg-soft), var(--ui-shadow-lg); z-index: 2; }
.ui-chart.ui-chart-map { height: clamp(22rem, 65vh, 44rem); }
.ui-chart.ui-chart-map .ui-chart-frame { flex: 1 1 auto; min-height: 0; }
.ui-chart.ui-chart-graph { height: clamp(20rem, 55vh, 36rem); }
.ui-chart.ui-chart-graph .ui-chart-frame { flex: 1 1 auto; min-height: 0; }
.ui-chart-host { display: flex; flex-direction: column; flex: 1 1 auto; min-height: clamp(18rem, 50vh, 32rem); }
.ui-toggle-grid-table { border-collapse: collapse; }
.ui-toggle-grid-table th, .ui-toggle-grid-table td { padding: var(--ui-space-1) var(--ui-space-2); }
.ui-toggle-grid-rowlabel { font-weight: var(--ui-font-semibold); }
.ui-toggle-grid-cell { text-align: center; cursor: pointer; min-width: 2rem; border-radius: var(--ui-radius-sm); transition: background var(--ui-transition-fast); }
.ui-toggle-grid-cell:hover { background: var(--ui-bg-muted); }
.ui-toggle-grid-cell.ui-active { background: var(--ui-primary); color: var(--ui-on-primary); }
.ui-aggregate-metrics { display: flex; flex-wrap: wrap; gap: var(--ui-space-2); padding: var(--ui-space-2); }
.ui-bind-list-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ui-space-2); margin-bottom: var(--ui-space-2); }
.ui-bind-list-bar input[type=search] { max-width: var(--ui-search-input-max-w); }
.ui-bind-collection { display: flex; flex-wrap: wrap; gap: var(--ui-space-3); padding: var(--ui-space-2); align-items: flex-start; }

/* ── Labeller-surface decorators + selector templates ─────────────── */
.ui-pill { display: inline-flex; align-items: center; padding: 1px var(--ui-space-2); border-radius: var(--ui-radius-full); font-size: var(--ui-text-2xs); font-weight: var(--ui-font-semibold); text-transform: uppercase; letter-spacing: 0.04em; color: #fff; background: var(--ui-pill-color, var(--ui-fg-muted)); }
/* Tone classes need to win over the variable-based .ui-pill above (which is
   declared later than the tone rules near .ui-pill-success); use compound
   selectors for higher specificity so the tone colour applies. */
.ui-pill.ui-pill-success { background: var(--ui-success); color: #fff; }
.ui-pill.ui-pill-warn    { background: var(--ui-warn);    color: #fff; }
.ui-pill.ui-pill-danger  { background: var(--ui-danger);  color: #fff; }
.ui-bind-list { padding: var(--ui-space-2); }
.ui-bind-list-rows { display: flex; flex-direction: column; }
.ui-bind-list-row { position: relative; min-width: 0; display: flex; align-items: center; gap: var(--ui-space-2); }
.ui-bind-list-head { display: flex; flex-direction: column; gap: 2px; min-width: 0; line-height: 1.25; }
.ui-bind-list-pills, .ui-bind-card-pills, .ui-bind-tree-pills { display: flex; gap: var(--ui-space-1); margin-left: auto; align-items: flex-start; }
.ui-bind-list-progress { position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--ui-bg-muted); }
.ui-bind-list-progress::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: var(--ui-progress-pct, 0%); background: var(--ui-progress-color, var(--ui-primary)); transition: width var(--ui-transition-base) var(--ui-ease); }
.ui-bind-entity-card-header { display: flex; align-items: center; gap: var(--ui-space-3); margin-bottom: var(--ui-space-2); }
.ui-bind-card-progress { margin-top: var(--ui-space-3); }
.ui-bind-entity-card-actions { position: absolute; top: var(--ui-space-2); right: var(--ui-space-2); display: flex; gap: var(--ui-space-1); opacity: 0; transition: opacity var(--ui-transition-fast); }
.ui-bind-entity-card:hover .ui-bind-entity-card-actions { opacity: 1; }
.ui-bind-dropdown { width: 100%; }
.ui-bind-chips     { display: flex; flex-wrap: wrap; gap: var(--ui-space-1); padding: var(--ui-space-2); }
.ui-bind-chips .ui-chip { cursor: pointer; }
.ui-bind-gallery   { display: flex; flex-direction: column; gap: var(--ui-space-2); padding: var(--ui-space-2); }
.ui-bind-gallery-items { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: var(--ui-space-3); align-content: start; }
.ui-bind-gallery-tile { display: flex; flex-direction: column; cursor: pointer; border-radius: var(--ui-radius-lg); overflow: hidden; background: var(--ui-bg-elev); border: var(--ui-border-width) solid var(--ui-border); box-shadow: var(--ui-shadow-sm); transition: box-shadow var(--ui-transition-base), transform var(--ui-transition-base); }
.ui-bind-gallery-tile:hover { transform: translateY(-2px); box-shadow: var(--ui-shadow-md); }
.ui-bind-gallery-tile.ui-active { outline: 3px solid var(--ui-primary); outline-offset: -3px; }
.ui-bind-gallery-image { aspect-ratio: 1; background-size: cover; background-position: center; background-color: var(--ui-bg-muted); display: flex; align-items: center; justify-content: center; }
.ui-bind-gallery-image-initials .ui-avatar { width: 50%; height: 50%; }
.ui-bind-gallery-caption { padding: var(--ui-space-2) var(--ui-space-3) var(--ui-space-3); }
.ui-bind-compact   { padding: var(--ui-space-1); }
.ui-bind-compact-row { display: flex; align-items: center; gap: var(--ui-space-2); padding: var(--ui-space-1) var(--ui-space-2); cursor: pointer; border-radius: var(--ui-radius-sm); transition: background var(--ui-transition-fast); }
.ui-bind-compact-row:hover { background: var(--ui-bg-muted); }
.ui-bind-compact-row.ui-active { background: var(--ui-primary-100); color: var(--ui-primary-700); font-weight: var(--ui-font-semibold); }
.ui-bind-segmented { display: inline-flex; padding: 2px; gap: 2px; background: var(--ui-bg-muted); border-radius: var(--ui-radius-md); margin: var(--ui-space-2); }
.ui-bind-segmented .ui-segmented-item { cursor: pointer; white-space: nowrap; }
.ui-bind-segmented .ui-segmented-item.ui-active { background: var(--ui-bg-elev); box-shadow: var(--ui-shadow-sm); color: var(--ui-fg); }
.ui-metric-chip-icon { display: inline-flex; align-items: center; }
.ui-bind-list-actions { position: absolute; right: var(--ui-space-3); top: 50%; transform: translateY(-50%); display: flex; gap: var(--ui-space-1); padding: var(--ui-space-1); background: var(--ui-bg-elev); border-radius: var(--ui-radius-md); box-shadow: var(--ui-shadow-sm); opacity: 0; pointer-events: none; transition: opacity var(--ui-transition-fast); }
.ui-bind-list-row:hover .ui-bind-list-actions, .ui-bind-tree-node:hover > .ui-bind-list-actions { opacity: 1; pointer-events: auto; }
.ui-mgr-pane { flex: 1 1 0; min-width: clamp(220px, 20vw, 320px); }
.ui-drilldown-list { display: flex; flex-direction: column; }
.ui-drilldown-row { display: flex; justify-content: space-between; padding: var(--ui-space-2) var(--ui-space-3); cursor: pointer; border-bottom: var(--ui-border-width) solid var(--ui-border); transition: background var(--ui-transition-fast); }
.ui-drilldown-row:hover { background: var(--ui-bg-muted); }
.ui-stepper-done { color: var(--ui-success); }
.ui-wizard-body { padding: var(--ui-space-4); min-height: 8rem; }
.ui-wizard-footer { display: flex; justify-content: space-between; padding: var(--ui-space-3); border-top: var(--ui-border-width) solid var(--ui-border); }
.ui-action { display: inline-flex; gap: var(--ui-space-1); }
/* Hyper-parameter live-edit panel (gallery) */
.ui-hp-controls { display: flex; flex-direction: column; gap: var(--ui-space-3); padding: var(--ui-space-3) var(--ui-space-4); margin-bottom: var(--ui-space-3); background: var(--ui-bg-elev); border: var(--ui-border-width) solid var(--ui-border); border-radius: var(--ui-radius-lg); }
.ui-hp-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ui-space-3); }
.ui-hp-row-label { font-size: var(--ui-text-xs); font-weight: var(--ui-font-semibold); color: var(--ui-fg-muted); text-transform: uppercase; letter-spacing: 0.06em; }
.ui-hp-chips { display: flex; flex-wrap: wrap; gap: var(--ui-space-1); }
.ui-hp-chips .ui-chip { font-size: var(--ui-text-xs); padding: var(--ui-space-1) var(--ui-space-2); }
.ui-hp-font   { width: auto; min-width: 9rem; padding: var(--ui-space-1) var(--ui-space-2); font-size: var(--ui-text-sm); }
.ui-hp-weight { width: auto; min-width: 7rem; padding: var(--ui-space-1) var(--ui-space-2); font-size: var(--ui-text-sm); }
.ui-hp-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: var(--ui-space-3); padding-top: var(--ui-space-2); border-top: var(--ui-border-width) solid var(--ui-border); }
.ui-hp-cell { display: flex; flex-direction: column; gap: var(--ui-space-1); font-size: var(--ui-text-xs); color: var(--ui-fg-muted); }
.ui-hp-cell label { display: flex; align-items: center; justify-content: space-between; gap: var(--ui-space-2); font-weight: var(--ui-font-medium); color: var(--ui-fg); text-transform: uppercase; letter-spacing: 0.04em; font-size: var(--ui-text-2xs); }
.ui-hp-readout { font-family: var(--ui-font-mono); font-size: var(--ui-text-xs); color: var(--ui-fg-muted); padding: 0 var(--ui-space-1); background: var(--ui-bg-muted); border-radius: var(--ui-radius-sm); }
.ui-hp-slider { width: 100%; appearance: none; height: 4px; background: var(--ui-bg-muted); border-radius: var(--ui-radius-full); outline: none; }
.ui-hp-slider::-webkit-slider-thumb { appearance: none; width: 14px; height: 14px; border-radius: 50%; background: var(--ui-primary); cursor: pointer; box-shadow: var(--ui-shadow-sm); transition: transform var(--ui-transition-fast); }
.ui-hp-slider::-webkit-slider-thumb:hover { transform: scale(1.15); }
.ui-hp-slider::-moz-range-thumb { width: 14px; height: 14px; border: 0; border-radius: 50%; background: var(--ui-primary); cursor: pointer; box-shadow: var(--ui-shadow-sm); }
.ui-hp-cell-color { gap: 4px; }
.ui-hp-color-row { display: flex; align-items: center; gap: var(--ui-space-2); }
.ui-hp-color-row > span { font-family: var(--ui-font-mono); font-size: var(--ui-text-2xs); color: var(--ui-fg-muted); width: 0.9rem; flex-shrink: 0; }
.ui-hp-color-row .ui-hp-slider { flex: 1; }
.ui-hp-swatch { display: inline-block; width: 1.1rem; height: 1.1rem; border-radius: var(--ui-radius-sm); border: var(--ui-border-width) solid var(--ui-border); }
.ui-hp-snippet { display: flex; flex-direction: column; gap: var(--ui-space-2); padding-top: var(--ui-space-2); border-top: var(--ui-border-width) solid var(--ui-border); }
.ui-hp-snippet-bar { display: flex; align-items: center; gap: var(--ui-space-2); }
.ui-hp-snippet-name { flex: 0 1 12rem; font-family: var(--ui-font-mono); font-size: var(--ui-text-sm); }
.ui-hp-snippet-text { width: 100%; font-family: var(--ui-font-mono); font-size: var(--ui-text-xs); line-height: 1.5; resize: vertical; background: var(--ui-bg-sunken); }

/* ---- 7a. Bundled theme variants ---- comprehensive (font/weight/spacing/
 * corner/border/shadow/motion/hue) at the top, scoped tweaks at the bottom. */
.ui-theme-apple {
    --hp-font-heading: var(--hp-font-stack-display); --hp-font-body: var(--hp-font-stack-system); --hp-font-mono: var(--hp-font-stack-mono);
    --hp-weight-heading: 700; --hp-weight-body: 400; --hp-density: 1.15; --hp-pad-base: 0.55rem;
    --hp-text-ratio: 1.22; --hp-line-height: 1.5; --hp-corner-scale: 1.5; --hp-border-scale: 0.5;
    --hp-shadow-intensity: 0.08; --hp-transition-speed: 0.9;
    --hp-hue-1: 211; --hp-sat-1: 100%; --hp-hue-2: 268; --hp-sat-2: 70%; --hp-hue-accent: 32; --hp-sat-accent: 95%;
}
.ui-theme-metro {
    --hp-font-heading: var(--hp-font-stack-system); --hp-font-body: var(--hp-font-stack-system); --hp-font-mono: var(--hp-font-stack-mono);
    --hp-weight-heading: 300; --hp-weight-body: 400; --hp-density: 0.95; --hp-pad-base: 0.45rem;
    --hp-line-height: 1.4; --hp-corner-scale: 0; --hp-border-scale: 0; --hp-shadow-intensity: 0; --hp-transition-speed: 1.2;
    --hp-hue-1: 200; --hp-sat-1: 100%; --hp-hue-2: 14; --hp-sat-2: 92%; --hp-hue-accent: 130; --hp-sat-accent: 90%;
}
.ui-theme-material {
    --hp-font-heading: var(--hp-font-stack-roboto); --hp-font-body: var(--hp-font-stack-roboto); --hp-font-mono: var(--hp-font-stack-roboto-mono);
    --hp-weight-heading: 500; --hp-weight-body: 400; --hp-corner-scale: 0.5; --hp-border-scale: 0.7;
    --hp-shadow-intensity: 0.22;
    --hp-hue-1: 207; --hp-sat-1: 90%; --hp-hue-2: 174; --hp-sat-2: 70%; --hp-hue-accent: 36; --hp-sat-accent: 100%;
}
.ui-theme-brutalist {
    --hp-font-heading: var(--hp-font-stack-bebas); --hp-font-body: var(--hp-font-stack-mono); --hp-font-mono: var(--hp-font-stack-mono);
    --hp-weight-heading: 400; --hp-weight-body: 500; --hp-density: 1.05; --hp-text-scale: 1.05; --hp-text-ratio: 1.4;
    --hp-line-height: 1.4; --hp-corner-scale: 0; --hp-border-scale: 2.5; --hp-shadow-intensity: 0; --hp-transition-speed: 0.5;
    --hp-hue-1: 0; --hp-sat-1: 0%; --hp-hue-2: 0; --hp-sat-2: 0%; --hp-hue-accent: 50; --hp-sat-accent: 100%;
}
.ui-theme-newspaper {
    --hp-font-heading: var(--hp-font-stack-playfair); --hp-font-body: var(--hp-font-stack-source); --hp-font-mono: var(--hp-font-stack-source-code);
    --hp-weight-heading: 700; --hp-density: 0.95; --hp-text-ratio: 1.3; --hp-line-height: 1.65;
    --hp-corner-scale: 0.2; --hp-border-scale: 0.5; --hp-shadow-intensity: 0.04;
    --hp-hue-1: 24; --hp-sat-1: 60%; --hp-hue-2: 15; --hp-sat-2: 35%; --hp-hue-accent: 0; --hp-sat-accent: 70%;
}
.ui-theme-mono {
    --hp-font-heading: var(--hp-font-stack-jetbrains); --hp-font-body: var(--hp-font-stack-jetbrains); --hp-font-mono: var(--hp-font-stack-jetbrains);
    --hp-weight-heading: 600; --hp-text-scale: 0.94; --hp-line-height: 1.55;
    --hp-corner-scale: 0.4; --hp-border-scale: 0.8; --hp-shadow-intensity: 0.06;
    --hp-hue-1: 152; --hp-sat-1: 55%; --hp-hue-2: 25; --hp-sat-2: 70%; --hp-hue-accent: 268; --hp-sat-accent: 70%;
}
.ui-theme-serif {
    --hp-font-heading: var(--hp-font-stack-garamond); --hp-font-body: var(--hp-font-stack-garamond); --hp-font-mono: var(--hp-font-stack-mono);
    --hp-weight-heading: 600; --hp-density: 1.05; --hp-text-scale: 1.05; --hp-text-ratio: 1.28; --hp-line-height: 1.6;
    --hp-corner-scale: 0.4; --hp-border-scale: 0.5; --hp-shadow-intensity: 0.06;
    --hp-hue-1: 212; --hp-sat-1: 45%; --hp-hue-2: 14; --hp-sat-2: 50%; --hp-hue-accent: 33; --hp-sat-accent: 70%;
}
/* Scoped tweaks — colour-only or density-only. */
.ui-theme-emerald  { --hp-hue-1: 158; --hp-sat-1: 70%; --hp-hue-2: 195; }
.ui-theme-amber    { --hp-hue-1: 32;  --hp-sat-1: 92%; --hp-hue-2: 14;  --hp-sat-2: 80%; }
.ui-theme-violet   { --hp-hue-1: 268; --hp-sat-1: 70%; --hp-hue-2: 320; --hp-sat-2: 65%; }
.ui-theme-slate    { --hp-hue-1: 215; --hp-sat-1: 18%; --hp-hue-2: 215; --hp-sat-2: 18%; --hp-shadow-intensity: 0.05; }
.ui-theme-compact  { --hp-density: 0.8; --hp-text-scale: 0.92; --hp-corner-scale: 0.8; }
.ui-theme-spacious { --hp-density: 1.2; --hp-text-scale: 1.06; --hp-corner-scale: 1.2; }
.ui-theme-rounded  { --hp-corner-scale: 1.6; }
.ui-theme-sharp    { --hp-corner-scale: 0; --hp-border-scale: 1.2; }

/* ---- 7b. Animations ---- */
@keyframes ui-fade-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
@keyframes ui-fade-up { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
.ui-pageframe-stage > *, .ui-pageframe-body > * { animation: ui-fade-in var(--ui-transition-base) var(--ui-ease) both; }
.ui-modal { animation: ui-fade-up var(--ui-transition-base) var(--ui-ease) both; }

/* ---- 8. Responsive ---- */
@media (max-width: 640px) {
    :root { --hp-density: 0.9; --hp-text-scale: 0.94; }
    .ui-pageframe-header { flex-wrap: wrap; }
    .ui-pageframe-actions { margin-left: 0; }
    .ui-data-cards-grid > *, .ui-bind-cards > * { flex-basis: 100%; max-width: 100%; }
    .ui-modal { padding: var(--ui-space-4); border-radius: var(--ui-radius-lg); }
}
@media (min-width: 1600px) { :root { --hp-text-scale: 1.05; } }

/* Heatmap — service-agnostic band-coloured grid (used by Accreditation matrix). */
.ui-heatmap { border-collapse: collapse; width: 100%; font-size: var(--ui-text-sm); }
.ui-heatmap th, .ui-heatmap td { border: 1px solid var(--ui-gray-200); padding: var(--ui-space-2); text-align: center; min-width: 64px; }
.ui-heatmap td:first-child, .ui-heatmap th:first-child { text-align: left; font-weight: var(--ui-font-semibold); }
.ui-band { cursor: pointer; transition: opacity var(--ui-transition-fast); }
.ui-band:hover { opacity: 0.85; outline: 2px solid var(--ui-primary); outline-offset: -2px; }
.ui-band-emerging   { background: var(--ui-danger-100);  color: var(--ui-danger); }
.ui-band-developed  { background: var(--ui-warn-100);    color: var(--ui-warn); }
.ui-band-exit-level { background: var(--ui-success-100); color: var(--ui-success); }
.ui-band-exceeds    { background: var(--ui-primary-100); color: var(--ui-primary); }
.ui-band-not-met    { background: var(--ui-gray-100);    color: var(--ui-text-muted); }
.ui-band-empty      { color: var(--ui-text-muted); }

/* Trend bar — cross-scan metric strip (PerformanceScanner.renderMetricTrend). */
.ui-trend-bar { flex: 1; height: 12px; background: var(--ui-gray-100); border-radius: var(--ui-radius-sm); position: relative; overflow: hidden; }
.ui-trend-bar::after { content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: var(--w, 0%); background: var(--ui-primary); }

/* uiMcq — multiple-choice question primitive (class.ui.js). One ruleset
   per concept; lean. Hyper-tokens used directly so themes can re-skin. */
.ui-mcq { background: var(--ui-bg-elevated); border: 1px solid var(--ui-border); border-radius: var(--ui-radius-lg); padding: var(--ui-space-4) var(--ui-space-5); }
.ui-mcq-tag { text-transform: uppercase; letter-spacing: 0.06em; font-size: var(--ui-text-xs); font-weight: 600; color: var(--ui-text-muted); margin-bottom: var(--ui-space-2); }
.ui-mcq-statement { font-size: var(--ui-text-base); margin-bottom: var(--ui-space-3); }
.ui-mcq-options { display: flex; flex-direction: column; gap: var(--ui-space-2); margin-bottom: var(--ui-space-2); }
.ui-mcq-option { display: flex; align-items: flex-start; gap: var(--ui-space-3); padding: var(--ui-space-2) var(--ui-space-3); background: var(--ui-bg); border: 1px solid var(--ui-border); border-radius: var(--ui-radius-md); cursor: pointer; text-align: left; font-size: var(--ui-text-sm); transition: border-color 100ms, background 100ms; }
.ui-mcq-option:hover:not(:disabled) { border-color: var(--ui-primary); }
.ui-mcq-option:disabled { cursor: default; }
.ui-mcq-letter { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: var(--ui-radius-full, 999px); background: var(--ui-bg-muted); color: var(--ui-text-muted); font-weight: 700; font-size: var(--ui-text-xs); flex-shrink: 0; }
.ui-mcq-label { flex: 1; }
.ui-mcq-label > p:first-child { margin-top: 0; }
.ui-mcq-correct { background: var(--ui-success-100); border-color: var(--ui-success); }
.ui-mcq-correct .ui-mcq-letter { background: var(--ui-success); color: white; }
.ui-mcq-wrong { background: var(--ui-danger-100); border-color: var(--ui-danger); }
.ui-mcq-wrong .ui-mcq-letter { background: var(--ui-danger); color: white; }
.ui-mcq-result { font-weight: 600; margin-top: var(--ui-space-2); }
.ui-mcq-result-correct { color: var(--ui-success); }
.ui-mcq-result-wrong { color: var(--ui-danger); }
.ui-mcq-solution { background: var(--ui-bg); padding: var(--ui-space-3); border-radius: var(--ui-radius-md); border-left: 3px solid var(--ui-primary); margin-top: var(--ui-space-2); }

/* Casework Workbench — two-region layout. A fixed-width side panel (selected-
   case detail stacked above the category rail) and a wide kanban board that
   takes all remaining width so lanes aren't forced thin. Wraps on narrow. */
.ui-cw-workbench { flex-wrap: wrap; }
.ui-cw-pane { display: flex; flex-direction: column; min-width: 0; gap: var(--ui-space-3); }
.ui-cw-pane-side  { flex: 0 0 22rem; }
.ui-cw-pane-board { flex: 1 1 0; min-width: 0; }
.ui-cw-detail { display: flex; flex-direction: column; gap: var(--ui-space-3); }
@media (max-width: 60rem) {
    .ui-cw-pane-side, .ui-cw-pane-board { flex: 1 1 100%; }
}

/* Chart canvas — responsive container for embedded Plotly plots
   (used by Runbook, Ordering, Specimen, etc.). clamp() scales with viewport
   while keeping a usable minimum + maximum so Plotly always has size. */
.ui-rb-chart { width: 100%; height: clamp(16rem, 40vh, 28rem); }

/* Workload utilization bars — width driven by --util-pct CSS variable set
   inline (data-bound, not layout). Colour band via modifier class. */
.ui-wl-util-row   { display: flex; align-items: center; gap: var(--ui-space-2); margin: var(--ui-space-1) 0; }
.ui-wl-util-label { flex: 0 0 9rem; font-size: var(--ui-text-sm); color: var(--ui-fg-muted); }
.ui-wl-util-bar   { flex: 1 1 auto; height: 10px; background: var(--ui-bg-muted); border-radius: var(--ui-radius-sm); overflow: hidden; min-width: 4rem; }
.ui-wl-util-fill  { display: block; height: 100%; background: var(--ui-success); transition: width 0.3s; width: var(--util-pct, 0%); }
.ui-wl-util-fill.ui-wl-util-amber { background: var(--ui-warning); }
.ui-wl-util-fill.ui-wl-util-red   { background: var(--ui-danger); }
.ui-wl-util-fill.ui-wl-util-dark  { background: var(--ui-danger-700); }
.ui-wl-util-pct   { flex: 0 0 3.5rem; text-align: right; font-variant-numeric: tabular-nums; font-size: var(--ui-text-sm); }

/* Analytics KPI cards — flex grid of selectable cards, each with a large
   value number, target context, status badge, and trend arrow. Card colour
   accent and trend glyph are data-driven via the AN_STATUS_* maps in code. */
.ui-an-kpi-grid   { display: flex; flex-wrap: wrap; gap: var(--ui-space-3); }
.ui-an-kpi-card   { flex: 1 1 14rem; min-width: 12rem; padding: var(--ui-space-3); border-radius: var(--ui-radius-lg); background: var(--ui-bg-elev); border: 1px solid var(--ui-border); cursor: pointer; transition: box-shadow var(--ui-transition-fast); display: flex; flex-direction: column; gap: var(--ui-space-1); }
.ui-an-kpi-card:hover { box-shadow: var(--ui-shadow-md); }
.ui-an-kpi-card.ui-active { border-color: var(--ui-primary); box-shadow: 0 0 0 2px var(--ui-primary-100); }
.ui-an-kpi-name   { font-size: var(--ui-text-sm); color: var(--ui-fg-muted); font-weight: var(--ui-font-semibold); }
.ui-an-kpi-value  { font-size: 2rem; font-weight: var(--ui-font-bold); font-variant-numeric: tabular-nums; line-height: 1.1; }
.ui-an-kpi-unit   { font-size: var(--ui-text-sm); color: var(--ui-fg-muted); margin-left: var(--ui-space-1); }
.ui-an-kpi-meta   { display: flex; align-items: center; justify-content: space-between; gap: var(--ui-space-2); font-size: var(--ui-text-xs); color: var(--ui-fg-muted); }
.ui-an-kpi-trend  { font-variant-numeric: tabular-nums; }
.ui-an-kpi-trend.ui-an-up    { color: var(--ui-success); }
.ui-an-kpi-trend.ui-an-down  { color: var(--ui-danger); }
.ui-an-kpi-trend.ui-an-flat  { color: var(--ui-fg-muted); }

/* Specimen / Chain-of-Custody — bespoke visuals for the LIMS service. */
.ui-spc-tree { display: flex; flex-direction: column; gap: var(--ui-space-1); }
.ui-spc-tree-node { padding: var(--ui-space-2) var(--ui-space-3); border-left: 3px solid var(--ui-border); border-radius: var(--ui-radius-md); background: var(--ui-bg); margin-left: calc(var(--tree-depth, 0) * var(--ui-space-4)); }
.ui-spc-tree-selected { border-left-color: var(--ui-primary); background: var(--ui-primary-50); }
.ui-spc-tree-head { display: flex; align-items: center; gap: var(--ui-space-2); flex-wrap: wrap; }
.ui-spc-tree-bullet { color: var(--ui-fg-muted); }

.ui-spc-timeline { display: flex; flex-direction: column; gap: var(--ui-space-2); }
.ui-spc-timeline-row { display: flex; gap: var(--ui-space-3); padding: var(--ui-space-2) var(--ui-space-3); border-left: 3px solid var(--ui-primary); background: var(--ui-bg); border-radius: var(--ui-radius-md); }
.ui-spc-timeline-icon { font-size: 1.25rem; flex: 0 0 1.5rem; }
.ui-spc-timeline-body { flex: 1 1 auto; min-width: 0; }

.ui-spc-fill { background: var(--ui-bg-muted); border-radius: var(--ui-radius-full); overflow: hidden; height: 0.5rem; margin-top: var(--ui-space-2); }
.ui-spc-fill-bar { height: 100%; transition: width 200ms ease; width: var(--fill-pct, 0%); }
.ui-spc-fill-success { background: var(--ui-success); }
.ui-spc-fill-warn    { background: var(--ui-warn); }
.ui-spc-fill-danger  { background: var(--ui-danger); }

.ui-spc-chips { display: flex; flex-wrap: wrap; gap: var(--ui-space-1); margin-top: var(--ui-space-2); }
.ui-spc-chip { display: inline-flex; align-items: center; padding: 1px var(--ui-space-2); border-radius: var(--ui-radius-sm); font-size: var(--ui-text-xs); background: var(--ui-bg-muted); color: var(--ui-fg); border: 1px solid var(--ui-border); }
.ui-spc-chip-more { background: transparent; font-style: italic; color: var(--ui-fg-muted); }

.ui-spc-due { padding: var(--ui-space-2) var(--ui-space-3); border-radius: var(--ui-radius-md); border-left: 3px solid var(--ui-warn); background: var(--ui-bg); font-size: var(--ui-text-sm); }
.ui-spc-due-past { border-left-color: var(--ui-danger); background: var(--ui-danger-50); }

.ui-btn-tiny { padding: 0 var(--ui-space-2); font-size: var(--ui-text-xs); height: auto; line-height: 1.4; }
.ui-btn-success { background: var(--ui-success); color: #fff; border-color: var(--ui-success); }
.ui-btn-success:hover { filter: brightness(0.95); }

/* Procedure — scope-of-accreditation matrix (analytes × matrices). */
.ui-proc-scope { display: flex; flex-direction: column; gap: 2px; }
.ui-proc-scope-row { display: flex; gap: 2px; }
.ui-proc-scope-cell { flex: 1 1 0; min-width: 6rem; padding: var(--ui-space-2); border-radius: var(--ui-radius-sm); background: var(--ui-bg); border: 1px solid var(--ui-border); font-size: var(--ui-text-sm); display: flex; flex-wrap: wrap; gap: var(--ui-space-1); align-items: center; }
.ui-proc-scope-corner { background: var(--ui-bg-muted); font-style: italic; color: var(--ui-fg-muted); justify-content: center; }
.ui-proc-scope-mhead { background: var(--ui-bg-muted); font-weight: var(--ui-font-semibold); justify-content: center; }
.ui-proc-scope-ahead { background: var(--ui-bg-muted); font-weight: var(--ui-font-semibold); }
.ui-proc-scope-success { background: var(--ui-success-50); border-color: var(--ui-success); }
.ui-proc-scope-warn    { background: var(--ui-warn-50); border-color: var(--ui-warn); }
.ui-proc-scope-danger  { background: var(--ui-danger-50); border-color: var(--ui-danger); }
.ui-proc-scope-muted   { background: var(--ui-bg-muted); }
.ui-proc-scope-pill { display: inline-flex; padding: 1px var(--ui-space-2); border-radius: var(--ui-radius-sm); font-size: var(--ui-text-xs); background: var(--ui-bg); border: 1px solid var(--ui-border); cursor: help; }
.ui-proc-scope-pill.ui-proc-scope-success { background: var(--ui-success); color: #fff; border-color: var(--ui-success); }
.ui-proc-scope-pill.ui-proc-scope-warn    { background: var(--ui-warn); color: #fff; border-color: var(--ui-warn); }
.ui-proc-scope-pill.ui-proc-scope-danger  { background: var(--ui-danger); color: #fff; border-color: var(--ui-danger); }

.ui-proc-req-list { display: flex; flex-direction: column; gap: var(--ui-space-1); }
.ui-proc-req-item { padding: var(--ui-space-1) var(--ui-space-2); border-left: 3px solid var(--ui-primary); background: var(--ui-bg-muted); border-radius: var(--ui-radius-sm); font-size: var(--ui-text-sm); }
.ui-proc-rev-current { border-left-color: var(--ui-success); background: var(--ui-success-50); }

/* Risk — 5×5 likelihood × impact heatmap. */
.ui-rsk-heatmap { display: flex; flex-direction: column; gap: 2px; }
.ui-rsk-heat-row { display: flex; gap: 2px; }
.ui-rsk-heat-cell { flex: 1 1 0; min-width: 6rem; min-height: 5rem; padding: var(--ui-space-2); border-radius: var(--ui-radius-sm); border: 1px solid var(--ui-border); font-size: var(--ui-text-xs); display: flex; flex-direction: column; gap: var(--ui-space-1); }
.ui-rsk-heat-head    { background: var(--ui-bg-muted); font-weight: var(--ui-font-semibold); justify-content: center; align-items: center; min-height: 2rem; flex-direction: row; }
.ui-rsk-heat-corner  { background: var(--ui-bg-muted); font-style: italic; color: var(--ui-fg-muted); justify-content: center; align-items: center; min-height: 2rem; flex-direction: row; }
.ui-rsk-heat-low        { background: #d1fae5; border-color: #10b981; }
.ui-rsk-heat-mediumLow  { background: #d9f99d; border-color: #84cc16; }
.ui-rsk-heat-mediumHigh { background: #fef3c7; border-color: #f59e0b; }
.ui-rsk-heat-high       { background: #fecaca; border-color: #ef4444; }
.ui-rsk-heat-score { font-weight: var(--ui-font-semibold); font-size: var(--ui-text-sm); }
.ui-rsk-heat-chips { display: flex; flex-wrap: wrap; gap: 2px; }

.ui-rsk-card-success { border-left-color: var(--ui-success) !important; }
.ui-rsk-card-warn    { border-left-color: var(--ui-warn) !important; }
.ui-rsk-card-danger  { border-left-color: var(--ui-danger) !important; }

/* QR — printable label preview (mimics a real sticker, responsive). */
.ui-qr-label { display: flex; flex-direction: column; border: 2px dashed var(--ui-border); padding: var(--ui-space-3); border-radius: var(--ui-radius-md); background: var(--ui-bg-elev); width: 100%; max-width: 28rem; box-shadow: var(--ui-shadow-sm); }
.ui-qr-label-head { font-size: var(--ui-text-xs); font-weight: var(--ui-font-semibold); color: var(--ui-fg-muted); border-bottom: 1px solid var(--ui-border); padding-bottom: var(--ui-space-1); margin-bottom: var(--ui-space-2); text-transform: uppercase; letter-spacing: 0.06em; }
.ui-qr-label-body { display: flex; flex-direction: row; flex-wrap: wrap; gap: var(--ui-space-3); align-items: center; }
.ui-qr-canvas { flex: 0 0 auto; aspect-ratio: 1; width: clamp(8rem, 28vw, 12rem); display: flex; align-items: center; justify-content: center; background: var(--ui-bg-sunken); border: 1px solid var(--ui-border); }
.ui-qr-canvas canvas, .ui-qr-canvas img { display: block; max-width: 100%; max-height: 100%; }
.ui-qr-label-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: var(--ui-space-1); }
.ui-qr-label-code { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: var(--ui-text-base); font-weight: var(--ui-font-semibold); word-break: break-all; }
.ui-qr-label-url  { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: var(--ui-text-xs); color: var(--ui-fg-muted); word-break: break-all; }
.ui-qr-fallback   { font-family: ui-monospace, monospace; text-align: center; color: var(--ui-fg-muted); font-size: var(--ui-text-xs); line-height: 1.4; }

/* Chat bubbles — used by MessagesService.renderConversation. Bubbles are
   left-aligned by default; .ui-msg-mine rows align right + use the primary
   colour so the user can tell their own messages apart at a glance. */
.ui-msg-list { display: flex; flex-direction: column; gap: var(--ui-space-2); padding: var(--ui-space-2); background: var(--ui-bg-sunken, var(--ui-gray-50)); border: 1px solid var(--ui-border); border-radius: var(--ui-radius-md); }
.ui-msg-row { display: flex; flex-direction: column; align-items: flex-start; max-width: 78%; }
.ui-msg-row.ui-msg-mine { align-self: flex-end; align-items: flex-end; }
.ui-msg-meta { font-size: var(--ui-text-xs); color: var(--ui-fg-muted); margin-bottom: 2px; }
.ui-msg-bubble { background: var(--ui-bg-elev); border: 1px solid var(--ui-border); border-radius: var(--ui-radius-lg); padding: var(--ui-space-2) var(--ui-space-3); white-space: pre-wrap; word-wrap: break-word; line-height: 1.4; }
.ui-msg-bubble.ui-msg-bubble-mine { background: var(--ui-primary-100); border-color: var(--ui-primary-200); }
.ui-msg-compose { align-items: stretch; }
.ui-msg-input { flex: 1 1 auto; resize: vertical; min-height: 2.4rem; }

/* NotificationService — bell chip + inbox card states. The unread card uses
   a primary-tinted left border so it reads as "needs attention" without
   shouting; read cards drop to the muted border colour. */
.ui-ntf-bell { font-weight: var(--ui-font-semibold); padding: var(--ui-space-1) var(--ui-space-2); }
.ui-ntf-unread { border-left: 3px solid var(--ui-primary) !important; }
.ui-ntf-read   { opacity: 0.85; }
