/*
 * Migration Portal — Design System
 * =================================================================
 * A single, token-driven theme layered over Bootstrap 5.3.
 *
 * WHY IT IS BUILT THIS WAY. Every screen in this product is rendered by vanilla JS
 * components that emit Bootstrap classes (`card`, `btn`, `badge`, `progress`,
 * `list-group`, `alert`) with `emp-*` ids for behaviour. Restyling those primitives here
 * therefore re-skins the entire application — connection, report tree, date configuration,
 * review, execution dashboard, logs and downloads — without editing a single line of
 * component logic or touching an id an event handler depends on.
 *
 * STRUCTURE
 *   1. Tokens            colour, type, space, radius, shadow, motion
 *   2. Theming           light / dark, system-aware, user-overridable
 *   3. Base              document, typography, focus, scrollbars
 *   4. Chrome            navbar, footer, status indicators
 *   5. Primitives        buttons, cards, badges, forms, tables, alerts, list groups
 *   6. Wizard            stepper, report tree, date config, review
 *   7. Execution         progress dashboard, stage timeline, log console, artifacts
 *   8. Feedback          toasts, skeletons, empty states, overlays
 *   9. Legacy            the analytics screen's existing classes, preserved
 *  10. Responsive & a11y
 *
 * Every legacy class name is retained. The JS references them directly, so removing one
 * would break a screen rather than restyle it.
 */

/* ============================================================ AUTH GATE */
body.app-auth-locked .navbar-nbh,
body.app-auth-locked .mp-hero,
body.app-auth-locked .container-fluid,
body.app-auth-locked .footer-nbh {
    opacity: 0.12;
    filter: blur(6px);
    pointer-events: none;
    user-select: none;
}

#google-auth-overlay {
    position: fixed;
    inset: 0;
    z-index: 99999;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--sp-5);
    background: rgba(15, 23, 42, 0.88);
}

#google-auth-overlay.auth-hidden {
    display: none;
}

.auth-panel {
    width: min(100%, 430px);
    border-radius: var(--r-lg);
    background: var(--bg-surface);
    box-shadow: var(--shadow-lg);
    border: 1px solid var(--border);
    padding: var(--sp-8);
    text-align: center;
}

.auth-brand-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 52px;
    height: 52px;
    border-radius: var(--r-md);
    background: var(--brand-600);
    color: #fff;
    font-weight: 800;
    font-size: var(--text-xl);
    margin-bottom: var(--sp-4);
}

.auth-profile-avatar {
    width: 28px;
    height: 28px;
    object-fit: cover;
}

/* ============================================================ MYGATE VIEWER */
.mygate-viewer-page {
    min-height: 100vh;
    margin: 0;
    background: #111827;
    color: #f8fafc;
}

.mygate-viewer-shell {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

.mygate-viewer-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 16px 20px;
    background: #1f2937;
    border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}

.mygate-viewer-header h1 {
    margin: 0;
    font-size: 1.25rem;
    font-weight: 700;
    letter-spacing: 0;
}

.mygate-viewer-kicker {
    color: #fca5a5;
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0;
}

.mygate-viewer-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.mygate-viewer-status {
    padding: 10px 20px;
    font-size: 0.95rem;
    font-weight: 600;
    background: #334155;
    color: #e2e8f0;
}

.mygate-viewer-status.is-success {
    background: #166534;
    color: #dcfce7;
}

.mygate-viewer-status.is-warning {
    background: #854d0e;
    color: #fef3c7;
}

.mygate-viewer-status.is-danger {
    background: #991b1b;
    color: #fee2e2;
}

.mygate-screen {
    position: relative;
    flex: 1;
    height: calc(100vh - 156px);
    min-height: 480px;
    background: #020617;
    overflow: hidden;
}

.mygate-rfb-target {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}

.mygate-rfb-target > div {
    width: 100%;
    height: 100%;
}

.mygate-rfb-target canvas {
    display: block;
    position: relative;
    z-index: 0;
    max-width: 100%;
    max-height: 100%;
    outline: none;
}

.mygate-screen.is-stream-connected .mygate-rfb-target canvas {
    visibility: visible;
}

.mygate-screen-empty {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    color: #cbd5e1;
    text-align: center;
    z-index: 1;
    pointer-events: none;
}

.mygate-stream-diagnostics {
    padding: 6px 20px;
    background: #0f172a;
    color: #94a3b8;
    font-size: 0.78rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
}

@media (max-width: 768px) {
    .mygate-viewer-header {
        align-items: flex-start;
        flex-direction: column;
    }

    .mygate-viewer-actions {
        width: 100%;
    }
}

/* ============================================================ 1. TOKENS */

:root {
    /* Brand. The red is kept — it is the product's identity — but deepened so it reads as
       a considered accent rather than a warning colour, and paired with a slate neutral
       ramp that carries the actual information hierarchy. */
    --brand-500: #D92D3C;
    --brand-600: #C0212F;
    --brand-700: #9E1926;
    --brand-050: #FEF2F3;
    --brand-100: #FCE4E6;

    /* Neutral ramp */
    --slate-000: #FFFFFF;
    --slate-025: #FBFCFD;
    --slate-050: #F6F8FA;
    --slate-100: #EEF1F5;
    --slate-200: #E2E7ED;
    --slate-300: #CBD3DD;
    --slate-400: #9AA5B4;
    --slate-500: #6B7787;
    --slate-600: #4B5563;
    --slate-700: #343C48;
    --slate-800: #232A34;
    --slate-900: #161B22;
    --slate-950: #0E1218;

    /* Semantic */
    --ok-500: #12805C;
    --ok-050: #E7F6F0;
    --warn-500: #A76400;
    --warn-050: #FDF3E2;
    --err-500: #C0212F;
    --err-050: #FDECEE;
    --info-500: #1F6FEB;
    --info-050: #EAF2FE;

    /* Type — one scale, used everywhere. */
    --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
    --text-2xs: 0.6875rem;
    --text-xs:  0.75rem;
    --text-sm:  0.8125rem;
    --text-md:  0.875rem;
    --text-base:0.9375rem;
    --text-lg:  1.0625rem;
    --text-xl:  1.25rem;
    --text-2xl: 1.5rem;
    --text-3xl: 1.875rem;

    /* Space — 4px base */
    --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px;
    --sp-5: 20px; --sp-6: 24px; --sp-8: 32px; --sp-10: 40px; --sp-12: 48px;

    /* Radius — restrained. Pills are reserved for status, not for everything. */
    --r-sm: 6px;
    --r-md: 10px;
    --r-lg: 14px;
    --r-pill: 999px;

    /* Elevation — light, layered, never muddy */
    --shadow-xs: 0 1px 2px rgba(16, 24, 40, 0.04);
    --shadow-sm: 0 1px 3px rgba(16, 24, 40, 0.06), 0 1px 2px rgba(16, 24, 40, 0.04);
    --shadow-md: 0 4px 12px rgba(16, 24, 40, 0.07), 0 2px 4px rgba(16, 24, 40, 0.04);
    --shadow-lg: 0 12px 28px rgba(16, 24, 40, 0.10), 0 4px 8px rgba(16, 24, 40, 0.04);

    /* Motion — short and purposeful */
    --ease: cubic-bezier(0.32, 0.72, 0, 1);
    --t-fast: 120ms;
    --t-med: 200ms;

    /* Semantic surface aliases (themed below) */
    --bg-app:      var(--slate-050);
    --bg-surface:  var(--slate-000);
    --bg-raised:   var(--slate-000);
    --bg-sunken:   var(--slate-100);
    --bg-hover:    var(--slate-050);
    --border:      var(--slate-200);
    --border-strong: var(--slate-300);
    --text-1: var(--slate-900);
    --text-2: var(--slate-600);
    --text-3: var(--slate-500);
    --accent: var(--brand-500);
    --accent-contrast: #FFFFFF;
    /* The accent used for TEXT on a page background. --accent is tuned for filled surfaces;
       as small text it measures 4.49:1 against white, just under the 4.5 AA threshold, so
       links, active tabs and inline emphasis use this darker variant instead. */
    --accent-text: #B01B28;
    /* Same reasoning as --accent-text: the info blue is tuned for filled surfaces and
       measures 4.11:1 as small bold text on the info tint. */
    --info-text: #1657BE;
    --console-bg: var(--slate-950);
    --console-fg: #D7DEE8;

    /* Legacy aliases — older markup still references these names. */
    --nbh-red: var(--brand-500);
    --nbh-red-dark: var(--brand-600);
    --nbh-red-light: var(--brand-050);
    --nbh-white: var(--bg-surface);
    --nbh-gray-bg: var(--bg-app);
    --nbh-gray-card: var(--bg-surface);
    --nbh-gray-border: var(--border);
    --nbh-text-dark: var(--text-1);
    --nbh-text-muted: var(--text-2);
    --nbh-shadow: var(--shadow-sm);
    --nbh-shadow-lg: var(--shadow-md);
    --nbh-radius: var(--r-md);
}

/* ============================================================ 2. THEMING
   Three states: explicit light, explicit dark, and "follow the system" (no attribute).
   Colours are defined once on :root and only the surface aliases are remapped, so a new
   component inherits both themes for free. */

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --bg-app:     var(--slate-950);
        --bg-surface: var(--slate-900);
        --bg-raised:  var(--slate-800);
        --bg-sunken:  #11161D;
        --bg-hover:   rgba(255, 255, 255, 0.04);
        --border:     #2A323D;
        --border-strong: #3A4450;
        --text-1: #E8EDF3;
        --text-2: #A7B2C0;
        --text-3: #8592A3;
        --brand-050: rgba(217, 45, 60, 0.12);
        --brand-100: rgba(217, 45, 60, 0.20);
        --ok-050:   rgba(18, 128, 92, 0.16);
        --warn-050: rgba(167, 100, 0, 0.18);
        --err-050:  rgba(192, 33, 47, 0.16);
        --info-050: rgba(31, 111, 235, 0.16);
        --ok-500:   #3DD9A0;
        --warn-500: #E0A030;
        --err-500:  #FF6B78;
        --info-500: #6BA5FF;
        --accent-text: #FF8A94;
        --info-text: #8CBAFF;
        --console-bg: #090C11;
        --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
        --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.45);
        --shadow-md: 0 4px 14px rgba(0, 0, 0, 0.5);
        --shadow-lg: 0 14px 32px rgba(0, 0, 0, 0.6);
    }
}

:root[data-theme="dark"] {
    --bg-app:     var(--slate-950);
    --bg-surface: var(--slate-900);
    --bg-raised:  var(--slate-800);
    --bg-sunken:  #11161D;
    --bg-hover:   rgba(255, 255, 255, 0.04);
    --border:     #2A323D;
    --border-strong: #3A4450;
    --text-1: #E8EDF3;
    --text-2: #A7B2C0;
    --text-3: #8592A3;
    --brand-050: rgba(217, 45, 60, 0.12);
    --brand-100: rgba(217, 45, 60, 0.20);
    --ok-050:   rgba(18, 128, 92, 0.16);
    --warn-050: rgba(167, 100, 0, 0.18);
    --err-050:  rgba(192, 33, 47, 0.16);
    --info-050: rgba(31, 111, 235, 0.16);
    --ok-500:   #3DD9A0;
    --warn-500: #E0A030;
    --err-500:  #FF6B78;
    --info-500: #6BA5FF;
    --accent-text: #FF8A94;
    --info-text: #8CBAFF;
    --console-bg: #090C11;
    --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.45);
    --shadow-md: 0 4px 14px rgba(0, 0, 0, 0.5);
    --shadow-lg: 0 14px 32px rgba(0, 0, 0, 0.6);
}

/* Bootstrap reads its own variables for a handful of components; remap them once so
   dropdowns, modals and popovers follow the theme instead of staying white in dark mode. */
:root {
    --bs-body-bg: var(--bg-app);
    --bs-body-color: var(--text-1);
    --bs-border-color: var(--border);
    --bs-primary: var(--accent);
    --bs-link-color: var(--accent);
    --bs-link-hover-color: var(--brand-600);
    --bs-emphasis-color: var(--text-1);
    --bs-secondary-color: var(--text-2);
    --bs-tertiary-bg: var(--bg-sunken);
}

/* ============================================================ 3. BASE */

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

html { -webkit-text-size-adjust: 100%; }

body {
    background-color: var(--bg-app);
    color: var(--text-1);
    font-family: var(--font-sans);
    font-size: var(--text-base);
    line-height: 1.55;
    margin: 0;
    padding: 0;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    font-feature-settings: "cv02", "cv03", "cv04", "tnum";
    transition: background-color var(--t-med) var(--ease), color var(--t-med) var(--ease);
}

h1, h2, h3, h4, h5, h6 {
    color: var(--text-1);
    font-weight: 650;
    letter-spacing: -0.014em;
}

.text-muted { color: var(--text-2) !important; }
.small, small { font-size: var(--text-md); }
.font-monospace { font-family: var(--font-mono) !important; font-variant-ligatures: none; }

/* Numeric alignment: figures in tables and metrics must not jitter as they update. */
.kpi-value, .summary-value, .font-monospace, .badge, td, th { font-variant-numeric: tabular-nums; }

a { color: var(--accent-text); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--brand-600); }

/* One visible, consistent focus ring for keyboard users on every interactive element. */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: var(--r-sm);
}
:where(a, button, input, select, textarea):focus:not(:focus-visible) { outline: none; }

::selection { background: var(--brand-100); color: var(--text-1); }

/* Scrollbars — themed, unobtrusive */
* { scrollbar-width: thin; scrollbar-color: var(--slate-300) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
    background: var(--border-strong);
    border-radius: var(--r-pill);
    border: 2px solid transparent;
    background-clip: content-box;
}
*::-webkit-scrollbar-thumb:hover { background-clip: content-box; background-color: var(--slate-400); }

/* ============================================================ 4. CHROME */

.navbar-nbh {
    background-color: var(--bg-surface);
    border-bottom: 1px solid var(--border);
    box-shadow: none;
    position: sticky;
    top: 0;
    z-index: 1030;
    backdrop-filter: saturate(140%) blur(8px);
}

.logo-container { display: flex; align-items: center; gap: var(--sp-3); }
.logo-nbh { height: 36px; width: auto; }

.dashboard-title {
    font-weight: 650;
    color: var(--text-1);
    font-size: var(--text-lg);
    letter-spacing: -0.018em;
}

/* A quiet product descriptor under the title: says what this tool is, once. */
.dashboard-subtitle {
    display: block;
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--text-3);
    letter-spacing: 0.01em;
    margin-top: -2px;
}

.status-indicator {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    font-size: var(--text-md);
    font-weight: 550;
    color: var(--text-2);
    padding: 5px var(--sp-3);
    border-radius: var(--r-pill);
    background-color: var(--bg-sunken);
    border: 1px solid var(--border);
}

.status-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.status-dot.online  { background-color: var(--ok-500);  box-shadow: 0 0 0 3px var(--ok-050); }
.status-dot.offline { background-color: var(--err-500); box-shadow: 0 0 0 3px var(--err-050); }

/* The online dot breathes only while the backend is reachable — motion that means
   something, and that stops when there is nothing to report. */
.status-dot.online { animation: pulse-ok 2.4s var(--ease) infinite; }
@keyframes pulse-ok {
    0%, 100% { box-shadow: 0 0 0 3px var(--ok-050); }
    50%      { box-shadow: 0 0 0 6px transparent; }
}

/* Theme toggle */
.theme-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: var(--r-sm);
    border: 1px solid var(--border);
    background: var(--bg-sunken);
    color: var(--text-2);
    cursor: pointer;
    transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease),
                border-color var(--t-fast) var(--ease);
}
.theme-toggle:hover { background: var(--bg-hover); color: var(--text-1); border-color: var(--border-strong); }
.theme-toggle svg { width: 17px; height: 17px; }
.theme-toggle .icon-sun { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-sun { display: block; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: none; }
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .theme-toggle .icon-sun { display: block; }
    :root:not([data-theme="light"]) .theme-toggle .icon-moon { display: none; }
}

.footer-nbh {
    padding: var(--sp-6) 0;
    color: var(--text-3);
    font-size: var(--text-md);
    border-top: 1px solid var(--border);
    background: var(--bg-surface);
    margin-top: var(--sp-10);
}

/* ============================================================ 5. PRIMITIVES */

/* --- Cards. Bootstrap's `.card` is the backbone of every wizard screen. */
.card,
.card-nbh {
    background-color: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-xs);
    color: var(--text-1);
}
.card-nbh { padding: var(--sp-6); margin-bottom: var(--sp-6); }

.card-header {
    background-color: transparent;
    border-bottom: 1px solid var(--border);
    padding: var(--sp-4) var(--sp-5);
    font-weight: 600;
    color: var(--text-1);
    border-radius: var(--r-lg) var(--r-lg) 0 0 !important;
}
.card-body { padding: var(--sp-5); }
.card-footer { background: var(--bg-sunken); border-top: 1px solid var(--border); }

/* Bootstrap utility overrides so `.shadow-sm` / `.border-0` read correctly in both themes. */
.shadow-sm { box-shadow: var(--shadow-sm) !important; }
.shadow, .shadow-lg { box-shadow: var(--shadow-md) !important; }
.card.border-0 { border: 1px solid var(--border) !important; }
.bg-white, .bg-body, .bg-light { background-color: var(--bg-surface) !important; color: var(--text-1); }
.bg-body-tertiary, .bg-light-subtle { background-color: var(--bg-sunken) !important; }
.border, .border-top, .border-bottom, .border-start, .border-end { border-color: var(--border) !important; }

.card-title-nbh {
    font-size: var(--text-lg);
    font-weight: 650;
    color: var(--text-1);
    margin-bottom: var(--sp-5);
    padding-bottom: var(--sp-3);
    border-bottom: 1px solid var(--border);
    letter-spacing: -0.012em;
}
.card-title-nbh-red { color: var(--accent); }

/* --- Buttons */
.btn {
    --bs-btn-focus-box-shadow: none;
    font-weight: 570;
    font-size: var(--text-md);
    border-radius: var(--r-sm);
    padding: 9px var(--sp-4);
    letter-spacing: -0.005em;
    transition: background-color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
                color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease),
                box-shadow var(--t-fast) var(--ease);
}
.btn:active { transform: translateY(0.5px); }
.btn-lg { padding: 11px var(--sp-5); font-size: var(--text-base); border-radius: var(--r-md); }
.btn-sm { padding: 5px var(--sp-3); font-size: var(--text-sm); }

.btn-primary,
.btn-primary-nbh {
    background-color: var(--accent);
    border: 1px solid var(--accent);
    color: var(--accent-contrast);
    box-shadow: var(--shadow-xs);
}
.btn-primary:hover, .btn-primary-nbh:hover,
.btn-primary:focus-visible, .btn-primary-nbh:focus-visible {
    background-color: var(--brand-600);
    border-color: var(--brand-600);
    color: #fff;
    box-shadow: var(--shadow-sm);
}
.btn-primary:disabled, .btn-primary.disabled { background-color: var(--slate-400); border-color: var(--slate-400); opacity: 0.7; }

.btn-outline-nbh, .btn-outline-secondary, .btn-outline-primary {
    background-color: var(--bg-surface);
    border: 1px solid var(--border-strong);
    color: var(--text-1);
}
.btn-outline-nbh:hover, .btn-outline-secondary:hover, .btn-outline-primary:hover {
    background-color: var(--bg-hover);
    border-color: var(--slate-400);
    color: var(--text-1);
}
.btn-outline-primary { color: var(--accent); border-color: var(--accent); }
.btn-outline-primary:hover { background-color: var(--brand-050); color: var(--brand-600); border-color: var(--accent); }

.btn-success { background-color: var(--ok-500); border-color: var(--ok-500); }
.btn-danger  { background-color: var(--err-500); border-color: var(--err-500); }
.btn-secondary { background-color: var(--slate-500); border-color: var(--slate-500); }
.btn-link { color: var(--accent); font-weight: 550; }

/* --- Badges. Used everywhere for status; make each state legible at a glance. */
.badge {
    font-weight: 600;
    font-size: var(--text-xs);
    letter-spacing: 0.01em;
    padding: 4px 9px;
    border-radius: var(--r-sm);
    border: 1px solid transparent;
}
.badge.rounded-pill, .badge.rounded-circle { border-radius: var(--r-pill); }

.badge.bg-primary   { background-color: var(--brand-050) !important; color: var(--accent-text) !important;  border-color: var(--brand-100); }
.badge.bg-success   { background-color: var(--ok-050) !important;   color: var(--ok-500) !important;   border-color: color-mix(in srgb, var(--ok-500) 24%, transparent); }
.badge.bg-danger    { background-color: var(--err-050) !important;  color: var(--err-500) !important;  border-color: color-mix(in srgb, var(--err-500) 24%, transparent); }
.badge.bg-warning   { background-color: var(--warn-050) !important; color: var(--warn-500) !important; border-color: color-mix(in srgb, var(--warn-500) 24%, transparent); }
.badge.bg-info      { background-color: var(--info-050) !important; color: var(--info-500) !important; border-color: color-mix(in srgb, var(--info-500) 24%, transparent); }
.badge.bg-secondary { background-color: var(--bg-sunken) !important; color: var(--text-2) !important;  border-color: var(--border); }
.badge.bg-light     { background-color: var(--bg-sunken) !important; color: var(--text-1) !important;  border-color: var(--border); }
.badge.bg-dark      { background-color: var(--slate-700) !important; color: #fff !important; }
.badge.bg-danger-subtle  { background-color: var(--err-050) !important; color: var(--err-500) !important; }
.badge.bg-success-subtle { background-color: var(--ok-050) !important;  color: var(--ok-500) !important; }
.text-danger  { color: var(--err-500) !important; }
.text-success { color: var(--ok-500) !important; }
.text-warning { color: var(--warn-500) !important; }
.text-primary { color: var(--accent-text) !important; }

/* --- Coloured surfaces.
   Several cards use Bootstrap's `bg-primary` / `bg-success` / `bg-warning` / `bg-dark` on
   their HEADER, together with `text-white` or `text-dark`. Those defaults are the loud
   primary palette this redesign exists to replace — a section header rendered in #0D6EFD
   blue is the single most template-looking element on the page.

   They are recoloured to the system's own semantics and kept SOLID rather than converted to
   tints: the markup hard-codes its own text colour, so a light tint would leave white text
   invisible. These four tokens therefore stay dark enough for white text in BOTH themes,
   which is why they are fixed values rather than the theme-flipping --ok-500 family. */
:root {
    --surface-accent: #C0212F;
    --surface-ok:     #12805C;
    --surface-info:   #1F6FEB;
    --surface-warn:   #F0B429;
}

.card-header.bg-primary, .bg-primary:not(.badge):not(.progress-bar) {
    background-color: var(--surface-accent) !important;
    color: #fff !important;
    border-bottom-color: transparent;
}
.card-header.bg-success, .bg-success:not(.badge):not(.progress-bar) {
    background-color: var(--surface-ok) !important;
    color: #fff !important;
    border-bottom-color: transparent;
}
.card-header.bg-info, .bg-info:not(.badge) {
    background-color: var(--surface-info) !important;
    color: #fff !important;
    border-bottom-color: transparent;
}
.card-header.bg-warning, .bg-warning:not(.badge) {
    background-color: var(--surface-warn) !important;
    color: var(--slate-900) !important;
    border-bottom-color: transparent;
}
.card-header.bg-secondary, .bg-secondary:not(.badge) {
    background-color: var(--bg-sunken) !important;
    color: var(--text-1) !important;
}

/* The audit screen builds dark cards explicitly (`card bg-dark text-white`). In dark mode
   those were nearly invisible against the page; in light mode they were an unexplained slab
   of black. Both become the theme's raised surface, keeping their intended "inset panel"
   role without fighting the palette. */
.card.bg-dark, .bg-dark:not(.badge):not(#emp-log-console) {
    background-color: var(--bg-raised) !important;
    color: var(--text-1) !important;
    border-color: var(--border) !important;
}
.card.bg-dark .form-control, .bg-dark .form-control {
    background-color: var(--bg-sunken) !important;
    color: var(--text-1) !important;
    border-color: var(--border) !important;
}
.card.bg-dark .table { --bs-table-color: var(--text-1); color: var(--text-1); }
.border-secondary { border-color: var(--border) !important; }

/* `text-dark` is scattered through the wizard markup on labels and headings. It resolves to
   near-black, which in dark mode renders those labels almost invisible against the surface —
   "Select ERP System" was legible only as a smudge. It is remapped to the theme's primary
   text colour, so it keeps meaning "the strongest text here" in BOTH themes rather than
   meaning one literal colour. The solid-surface exceptions below re-assert real black/white
   where the background is a fixed colour. */
.text-dark { color: var(--text-1) !important; }
.text-black { color: var(--text-1) !important; }
.text-white { color: var(--text-1) !important; }
/* Only surfaces that are a FIXED colour in both themes force a literal text colour. The
   amber warning header is fixed; `bg-light` is not — it follows the theme, so its text must
   follow the theme too. */
.card-header.bg-warning, .card-header.bg-warning .text-dark { color: var(--slate-900) !important; }
.badge.bg-warning { color: var(--warn-500) !important; }
.badge.bg-warning.text-dark { color: var(--slate-900) !important; background-color: var(--surface-warn) !important; }
.badge.bg-light.text-dark { color: var(--text-1) !important; }
/* …except where the surface is genuinely a solid colour, where white is the point. */
.bg-primary .text-white, .bg-success .text-white, .bg-info .text-white,
.card-header.bg-primary, .card-header.bg-success, .card-header.bg-info { color: #fff !important; }

/* --- Forms */
.form-control, .form-select, .form-control-nbh {
    background-color: var(--bg-surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--r-sm);
    color: var(--text-1);
    font-size: var(--text-md);
    padding: 9px var(--sp-3);
    transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.form-control:focus, .form-select:focus, .form-control-nbh:focus {
    background-color: var(--bg-surface);
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--brand-050);
    color: var(--text-1);
    outline: none;
}
.form-control::placeholder { color: var(--text-3); }
.form-control:disabled, .form-select:disabled { background-color: var(--bg-sunken); color: var(--text-3); }
.form-label, .control-label {
    font-size: var(--text-md);
    font-weight: 600;
    color: var(--text-1);
    margin-bottom: var(--sp-2);
}
.form-text { color: var(--text-3); font-size: var(--text-sm); }

.form-check-input {
    border: 1.5px solid var(--border-strong);
    background-color: var(--bg-surface);
    transition: background-color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.form-check-input:checked { background-color: var(--accent); border-color: var(--accent); }
.form-check-input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--brand-050); }
.form-check-label { color: var(--text-1); }

/* --- Tables */
.table {
    --bs-table-bg: transparent;
    --bs-table-color: var(--text-1);
    color: var(--text-1);
    font-size: var(--text-md);
    border-color: var(--border);
}
.table > thead th {
    background: var(--bg-sunken);
    color: var(--text-2);
    font-weight: 600;
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    border-bottom: 1px solid var(--border);
    padding: var(--sp-3) var(--sp-4);
    white-space: nowrap;
}
.table > tbody td { padding: var(--sp-3) var(--sp-4); border-color: var(--border); vertical-align: middle; }
.table-hover > tbody > tr:hover > * { background-color: var(--bg-hover); color: var(--text-1); }
.table-responsive { border-radius: var(--r-md); }

/* --- Alerts */
.alert {
    border-radius: var(--r-md);
    border: 1px solid var(--border);
    font-size: var(--text-md);
    padding: var(--sp-3) var(--sp-4);
    color: var(--text-1);
}
/* Bootstrap 5.3 pipes alert colours through its OWN custom properties
   (`.alert { color: var(--bs-alert-color) }`), so overriding `color` alone leaves nested
   text — the <ol>/<li> instructions in the connection panel — reading Bootstrap's dark
   emphasis colour. On the dark theme that measured 1.86:1, effectively unreadable. Setting
   the --bs-alert-* variables fixes the alert AND everything inside it. */
.alert-danger {
    --bs-alert-color: var(--err-500);  --bs-alert-bg: var(--err-050);
    --bs-alert-border-color: color-mix(in srgb, var(--err-500) 26%, transparent);
    background-color: var(--err-050); border-color: var(--bs-alert-border-color); color: var(--err-500);
}
.alert-success {
    --bs-alert-color: var(--ok-500);   --bs-alert-bg: var(--ok-050);
    --bs-alert-border-color: color-mix(in srgb, var(--ok-500) 26%, transparent);
    background-color: var(--ok-050); border-color: var(--bs-alert-border-color); color: var(--ok-500);
}
.alert-warning {
    --bs-alert-color: var(--warn-500); --bs-alert-bg: var(--warn-050);
    --bs-alert-border-color: color-mix(in srgb, var(--warn-500) 26%, transparent);
    background-color: var(--warn-050); border-color: var(--bs-alert-border-color); color: var(--warn-500);
}
.alert-info {
    --bs-alert-color: var(--info-500); --bs-alert-bg: var(--info-050);
    --bs-alert-border-color: color-mix(in srgb, var(--info-500) 26%, transparent);
    background-color: var(--info-050); border-color: var(--bs-alert-border-color); color: var(--info-500);
}
/* Body copy inside an alert stays the page's text colour; only headings and emphasis carry
   the semantic hue. Four lines of blue-on-blue instructions were harder to read than the
   same lines in normal text. */
.alert p, .alert li, .alert ol, .alert ul, .alert .small { color: var(--text-1); }
.alert strong, .alert b, .alert .alert-heading { color: inherit; }
.alert-info li strong, .alert-info li b { color: var(--info-text); }

/* --- List groups (report outcomes, artifact lists) */
.list-group { --bs-list-group-bg: transparent; border-radius: var(--r-md); }
.list-group-item {
    background-color: var(--bg-surface);
    border-color: var(--border);
    color: var(--text-1);
    padding: var(--sp-3) var(--sp-4);
    font-size: var(--text-md);
    transition: background-color var(--t-fast) var(--ease);
}
.list-group-item:hover { background-color: var(--bg-hover); }

/* --- Progress */
.progress {
    background-color: var(--bg-sunken);
    border-radius: var(--r-pill);
    overflow: hidden;
    height: 10px;
}
.progress-bar {
    background-color: var(--accent);
    transition: width 600ms var(--ease);
}
.progress-bar.bg-primary { background-color: var(--accent) !important; }
.progress-bar.bg-success { background-color: var(--ok-500) !important; }
.progress-bar.bg-danger  { background-color: var(--err-500) !important; }

/* A moving sheen while work is genuinely in flight. It is attached to Bootstrap's own
   `.progress-bar-animated`, which the component sets only while a job is running, so the
   animation cannot outlive the work it describes. */
.progress-bar-animated {
    background-image: linear-gradient(90deg,
        transparent 0%, rgba(255, 255, 255, 0.28) 50%, transparent 100%);
    background-size: 200% 100%;
    animation: sheen 1.4s linear infinite;
}
@keyframes sheen { from { background-position: 200% 0; } to { background-position: -200% 0; } }

/* --- Accordion, modal, tabs, dropdown */
.accordion-item { background-color: var(--bg-surface); border-color: var(--border); }
.accordion-button {
    background-color: var(--bg-surface);
    color: var(--text-1);
    font-weight: 570;
    font-size: var(--text-md);
}
.accordion-button:not(.collapsed) { background-color: var(--brand-050); color: var(--accent); box-shadow: none; }
.accordion-button:focus { box-shadow: 0 0 0 3px var(--brand-050); }
.accordion-body { background: var(--bg-surface); }

.modal-content { background-color: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--r-lg); box-shadow: var(--shadow-lg); }
.modal-header, .modal-footer { border-color: var(--border); }
.modal.fade .modal-dialog { transition: transform var(--t-med) var(--ease), opacity var(--t-med) var(--ease); }

.nav-tabs, .nav-tabs-nbh { border-bottom: 1px solid var(--border); gap: var(--sp-1); }
.nav-tabs .nav-link {
    border: none;
    border-bottom: 2px solid transparent;
    color: var(--text-2);
    font-weight: 570;
    font-size: var(--text-md);
    padding: var(--sp-3) var(--sp-4);
    border-radius: var(--r-sm) var(--r-sm) 0 0;
    transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.nav-tabs .nav-link:hover { color: var(--text-1); background: var(--bg-hover); }
.nav-tabs .nav-link.active { color: var(--accent-text); border-bottom-color: var(--accent); background: transparent; }

.dropdown-menu {
    background-color: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    box-shadow: var(--shadow-lg);
    padding: var(--sp-1);
}
.dropdown-item { color: var(--text-1); border-radius: var(--r-sm); font-size: var(--text-md); }
.dropdown-item:hover { background-color: var(--bg-hover); color: var(--text-1); }

/* ============================================================ 6. WIZARD */

/* --- Stepper. The single most important orientation device: which of the four steps am
   I on, what is done, what is left. Connectors fill in as steps complete. */
.emp-stepper {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    align-items: start;
    gap: 0;
}

.emp-step-item {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--sp-2);
    padding: 0 var(--sp-2);
    text-align: center;
}

/* The connector is drawn by the step itself, not by extra markup, so the row cannot fall
   out of alignment when a label wraps. */
.emp-step-item::before {
    content: "";
    position: absolute;
    top: 17px;
    right: calc(50% + 22px);
    left: calc(-50% + 22px);
    height: 2px;
    background: var(--border);
    border-radius: var(--r-pill);
    transition: background-color var(--t-med) var(--ease);
}
.emp-step-item:first-child::before { display: none; }
.emp-step-item.is-complete::before,
.emp-step-item.is-active::before { background: var(--ok-500); }

.emp-step-dot {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: var(--text-md);
    font-weight: 650;
    background: var(--bg-sunken);
    color: var(--text-2);
    border: 2px solid var(--border);
    position: relative;
    z-index: 1;
    transition: background-color var(--t-med) var(--ease), color var(--t-med) var(--ease),
                border-color var(--t-med) var(--ease), box-shadow var(--t-med) var(--ease);
}
.emp-step-label {
    font-size: var(--text-md);
    font-weight: 570;
    color: var(--text-3);
    transition: color var(--t-med) var(--ease);
}
.emp-step-hint { font-size: var(--text-xs); color: var(--text-3); }

.emp-step-item.is-active .emp-step-dot {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
    box-shadow: 0 0 0 4px var(--brand-050);
}
.emp-step-item.is-active .emp-step-label { color: var(--text-1); font-weight: 650; }

.emp-step-item.is-complete .emp-step-dot {
    background: var(--ok-050);
    border-color: var(--ok-500);
    color: var(--ok-500);
}
.emp-step-item.is-complete .emp-step-label { color: var(--text-2); }

/* Panels fade in so moving between steps reads as a transition, not a flash. */
.emp-step-panel { animation: panel-in var(--t-med) var(--ease) both; }
@keyframes panel-in {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: none; }
}

/* --- Report tree. Selection state must be obvious at a glance. */
.emp-parent-check, .emp-subgroup-check, .emp-leaf-check { cursor: pointer; }

.list-group-item:has(.emp-leaf-check:checked),
.list-group-item:has(.emp-subgroup-check:checked) {
    background-color: var(--brand-050);
    border-left: 3px solid var(--accent);
}

/* Row hover affordance across the tree */
.form-check:hover .form-check-label { color: var(--text-1); }

/* --- Date configuration */
.emp-individual-row {
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    padding: var(--sp-3);
    background: var(--bg-surface);
    transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.emp-individual-row:hover { border-color: var(--border-strong); background: var(--bg-hover); }
.emp-individual-badge { font-family: var(--font-mono); font-size: var(--text-xs); }

/* ============================================================ 7. EXECUTION */

/* Metric readouts on the progress dashboard */
.summary-item {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: var(--sp-3) var(--sp-4);
    background: var(--bg-sunken);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
}
.summary-label {
    font-size: var(--text-2xs);
    font-weight: 650;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-3);
}
.summary-value { font-size: var(--text-xl); font-weight: 680; color: var(--text-1); letter-spacing: -0.02em; }

/* Stage timeline — pending / running / done / failed */
.stage-step {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-2) var(--sp-3);
    border-radius: var(--r-sm);
    font-size: var(--text-md);
    color: var(--text-3);
    transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.stage-step .stage-icon {
    width: 18px; height: 18px; flex: none;
    border-radius: 50%;
    border: 2px solid var(--border-strong);
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 10px; font-weight: 700;
}
.stage-step.is-done { color: var(--text-2); }
.stage-step.is-done .stage-icon { background: var(--ok-050); border-color: var(--ok-500); color: var(--ok-500); }
.stage-step.is-running { color: var(--text-1); background: var(--brand-050); font-weight: 600; }
.stage-step.is-running .stage-icon {
    border-color: var(--accent);
    border-right-color: transparent;
    animation: spin 700ms linear infinite;
}
.stage-step.is-failed { color: var(--err-500); }
.stage-step.is-failed .stage-icon { background: var(--err-050); border-color: var(--err-500); color: var(--err-500); }
@keyframes spin { to { transform: rotate(360deg); } }

/* Log console — readable, severity-coded, monospaced */
#emp-log-console {
    background: var(--console-bg) !important;
    color: var(--console-fg) !important;
    border: 1px solid var(--border);
    border-radius: var(--r-md) !important;
    font-family: var(--font-mono) !important;
    font-size: var(--text-sm) !important;
    line-height: 1.65;
    scrollbar-color: var(--slate-600) transparent;
}
#emp-log-console .text-danger  { color: #FF8A94 !important; }
#emp-log-console .text-warning { color: #F0BE5A !important; }
#emp-log-console .text-success { color: #5FE3B0 !important; }
#emp-log-console .text-info    { color: #7FB4FF !important; }
#emp-log-console .text-muted   { color: #6F7C8D !important; }

/* Artifact / download rows read as objects you can act on. */
.file-meta-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--text-2);
    background: var(--bg-sunken);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    padding: 3px 8px;
    font-family: var(--font-mono);
}

/* ============================================================ 8. FEEDBACK */

#toast-container {
    position: fixed;
    top: var(--sp-5);
    right: var(--sp-5);
    z-index: 2000;
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    pointer-events: none;
}
.nbh-toast {
    pointer-events: auto;
    display: flex;
    align-items: flex-start;
    gap: var(--sp-3);
    min-width: 300px;
    max-width: 420px;
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-left: 3px solid var(--accent);
    border-radius: var(--r-md);
    box-shadow: var(--shadow-lg);
    padding: var(--sp-3) var(--sp-4);
    animation: toast-in var(--t-med) var(--ease) both;
}
@keyframes toast-in { from { opacity: 0; transform: translateX(12px); } to { opacity: 1; transform: none; } }
.nbh-toast.success { border-left-color: var(--ok-500); }
.nbh-toast.error   { border-left-color: var(--err-500); }
.nbh-toast.warning { border-left-color: var(--warn-500); }
.toast-icon { flex: none; font-size: var(--text-lg); line-height: 1.3; }
.toast-content { flex: 1; min-width: 0; }
.toast-title { font-weight: 650; font-size: var(--text-md); color: var(--text-1); }
.toast-message { font-size: var(--text-sm); color: var(--text-2); word-wrap: break-word; }
.toast-close {
    background: none; border: none; color: var(--text-3);
    cursor: pointer; font-size: var(--text-lg); line-height: 1; padding: 0 2px;
}
.toast-close:hover { color: var(--text-1); }

/* Skeletons */
.skeleton-card { padding: var(--sp-5); border: 1px solid var(--border); border-radius: var(--r-lg); background: var(--bg-surface); }
.skeleton-line {
    height: 12px;
    border-radius: var(--r-pill);
    margin-bottom: var(--sp-3);
    background: linear-gradient(90deg, var(--bg-sunken) 25%, var(--bg-hover) 37%, var(--bg-sunken) 63%);
    background-size: 400% 100%;
    animation: shimmer 1.3s ease-in-out infinite;
}
@keyframes shimmer { from { background-position: 100% 50%; } to { background-position: 0 50%; } }

/* Empty states */
.empty-state { text-align: center; padding: var(--sp-12) var(--sp-6); color: var(--text-2); }
.empty-state-icon { font-size: 2.5rem; opacity: 0.45; margin-bottom: var(--sp-3); }

/* Spinner + overlay */
.spinner-nbh {
    width: 40px; height: 40px;
    border: 3px solid var(--border);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: spin 800ms linear infinite;
}
.loading-overlay {
    position: fixed; inset: 0;
    background: color-mix(in srgb, var(--bg-app) 82%, transparent);
    backdrop-filter: blur(3px);
    display: none;
    align-items: center; justify-content: center;
    flex-direction: column; gap: var(--sp-3);
    z-index: 2500;
}
.loading-overlay.active { display: flex; }
.loading-text { font-weight: 650; color: var(--text-1); }
.loading-subtext { font-size: var(--text-md); color: var(--text-2); }

/* ============================================================ 9. LEGACY
   The analytics screen predates the wizard and its markup is unchanged; these rules keep
   it coherent with the new system instead of leaving it visually orphaned. */

.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--sp-4); }
.kpi-card {
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    padding: var(--sp-5);
    box-shadow: var(--shadow-xs);
    transition: box-shadow var(--t-med) var(--ease), transform var(--t-med) var(--ease), border-color var(--t-med) var(--ease);
}
.kpi-card:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); border-color: var(--border-strong); }
.kpi-header { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.kpi-icon { font-size: var(--text-xl); opacity: 0.85; }
.kpi-title { font-size: var(--text-2xs); font-weight: 650; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-3); }
.kpi-value { font-size: var(--text-3xl); font-weight: 700; color: var(--text-1); letter-spacing: -0.028em; line-height: 1.15; }
.kpi-desc, .kpi-metadata { font-size: var(--text-sm); color: var(--text-3); }

.upload-zone {
    border: 1.5px dashed var(--border-strong);
    border-radius: var(--r-lg);
    padding: var(--sp-10) var(--sp-5);
    text-align: center;
    background-color: var(--bg-sunken);
    cursor: pointer;
    transition: border-color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
.upload-zone:hover { border-color: var(--slate-400); }
.upload-zone.dragging { border-color: var(--accent); background-color: var(--brand-050); }
.upload-icon { font-size: 2rem; opacity: 0.6; }
.upload-btn-nbh { display: inline-block; }

.chart-container-nbh { position: relative; }
.highlight-nbh { color: var(--accent-text); font-weight: 650; }
.developer-mode-section { border-top: 1px solid var(--border); padding-top: var(--sp-4); }
.btn-check-nbh:checked + .btn { background-color: var(--accent); border-color: var(--accent); color: #fff; }

.matrix-table-container { overflow: auto; border: 1px solid var(--border); border-radius: var(--r-md); }
.matrix-table { font-size: var(--text-sm); margin: 0; }
.matrix-cell-active { background-color: var(--brand-050); font-weight: 650; color: var(--accent); }
.matrix-cell-zero { color: var(--text-3); }

/* ============================================================ 10. RESPONSIVE & A11Y */

@media (max-width: 992px) {
    .card-body { padding: var(--sp-4); }
    .kpi-value { font-size: var(--text-2xl); }
    .summary-value { font-size: var(--text-lg); }
}

@media (max-width: 768px) {
    /* The stepper becomes a compact row: dots stay, descriptive labels step aside so four
       steps still fit without wrapping into an unreadable stack. */
    .emp-step-label { font-size: var(--text-xs); }
    .emp-step-hint { display: none; }
    .emp-step-item::before { top: 15px; right: calc(50% + 18px); left: calc(-50% + 18px); }
    .emp-step-dot { width: 30px; height: 30px; font-size: var(--text-sm); }

    .navbar-nbh .container-fluid { padding-inline: var(--sp-3) !important; }
    .dashboard-subtitle { display: none; }
    .status-indicator span { display: none; }
    .status-indicator { padding: 6px; }

    #toast-container { left: var(--sp-3); right: var(--sp-3); top: var(--sp-3); }
    .nbh-toast { min-width: 0; max-width: none; }

    .card-nbh { padding: var(--sp-4); }
    .kpi-grid { grid-template-columns: 1fr; }
    .btn-lg { padding: 10px var(--sp-4); font-size: var(--text-md); }
}

@media (max-width: 576px) {
    body { font-size: var(--text-md); }
    .emp-step-label { display: none; }
    .table-responsive { font-size: var(--text-sm); }
}

/* Never let a wide table or console blow out the page width. */
.table-responsive, #emp-log-console { max-width: 100%; overflow-x: auto; }

/* Respect the platform's reduced-motion preference: decoration stops, state remains. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        scroll-behavior: auto !important;
    }
}

/* High-contrast users get stronger borders rather than a different layout. */
@media (prefers-contrast: more) {
    :root { --border: var(--slate-400); --border-strong: var(--slate-500); }
}

@media print {
    .navbar-nbh, .footer-nbh, #toast-container, .loading-overlay, .theme-toggle { display: none !important; }
    .card { box-shadow: none; border: 1px solid #ccc; }
}

/* Bootstrap's `.text-secondary` resolves to a fixed grey that measured 3.69:1 on the dark
   surface ("Connection Status:"). Remapped to the theme's secondary text, which is tuned
   per theme. */
.text-secondary { color: var(--text-2) !important; }

/* ============================================================ 11. REPORT SELECTION
   The report tree is the screen an operator spends the most time on, and it was the
   most template-looking: a grid of plain bordered `.form-check` rows that gave no sense
   of which reports were chosen without reading every checkbox.

   Everything below is presentation only. The markup is generated by tree.js and is left
   untouched - these rules hook the classes it already emits (`.emp-leaf-check`,
   `.emp-subgroup-check`, `.emp-parent-check`), so selection logic, ids and event handlers
   are unaffected. */

/* --- Toolbar (Expand / Collapse / Select All / Clear All) */
#emp-tree-container > .d-flex.bg-light {
    background: var(--bg-surface) !important;
    border: 1px solid var(--border) !important;
    border-radius: var(--r-lg) !important;
    padding: var(--sp-3) var(--sp-4) !important;
}

/* --- Group accordion: a quiet header, not a slab of colour */
#emp-tree-accordion .accordion-item {
    border: 1px solid var(--border) !important;
    border-radius: var(--r-lg) !important;
    overflow: hidden;
    margin-bottom: var(--sp-3) !important;
    background: var(--bg-surface);
    box-shadow: var(--shadow-xs);
}
#emp-tree-accordion .accordion-button {
    background: var(--bg-surface) !important;
    color: var(--text-1) !important;
    font-weight: 620;
    letter-spacing: -0.01em;
    border-bottom: 1px solid transparent;
    transition: background var(--t-fast) var(--ease);
}
#emp-tree-accordion .accordion-button:hover { background: var(--bg-hover) !important; }
#emp-tree-accordion .accordion-body { background: var(--bg-surface) !important; }

/* The group's own description badge reads as metadata, not as a status pill. */
#emp-tree-accordion .accordion-button .badge.bg-secondary {
    background: transparent !important;
    border: none;
    color: var(--text-3) !important;
    font-weight: 500;
    font-size: var(--text-xs);
    padding-left: 0;
}

/* --- Subgroup block: an inset panel, clearly a level below the group */
#emp-tree-accordion .border.rounded.p-3.bg-light {
    background: var(--bg-sunken) !important;
    border: 1px solid var(--border) !important;
    border-radius: var(--r-md) !important;
}

/* --- Report card. The unit of choice, so it is styled like one. */
#emp-tree-accordion .form-check.bg-white {
    position: relative;
    background: var(--bg-surface) !important;
    border: 1px solid var(--border) !important;
    border-radius: var(--r-md) !important;
    padding: var(--sp-3) var(--sp-3) var(--sp-3) var(--sp-4) !important;
    gap: var(--sp-2);
    cursor: pointer;
    overflow: hidden;
    transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease),
                box-shadow var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}

/* A left accent rail that fills in on selection: selected rows are identifiable from
   across the screen, without relying on the checkbox glyph alone. */
#emp-tree-accordion .form-check.bg-white::before {
    content: "";
    position: absolute;
    inset: 0 auto 0 0;
    width: 3px;
    background: transparent;
    transition: background var(--t-fast) var(--ease);
}

#emp-tree-accordion .form-check.bg-white:hover {
    border-color: var(--border-strong) !important;
    background: var(--bg-hover) !important;
    box-shadow: var(--shadow-sm);
    transform: translateY(-1px);
}

/* Selected state, driven by the real checkbox - no JS class bookkeeping to drift. */
#emp-tree-accordion .form-check.bg-white:has(.emp-leaf-check:checked) {
    background: var(--brand-050) !important;
    border-color: color-mix(in srgb, var(--accent) 38%, var(--border)) !important;
}
#emp-tree-accordion .form-check.bg-white:has(.emp-leaf-check:checked)::before { background: var(--accent); }
#emp-tree-accordion .form-check.bg-white:has(.emp-leaf-check:checked) .form-check-label {
    color: var(--text-1) !important;
    font-weight: 620;
}

/* Keyboard users get the same affordance as mouse users. */
#emp-tree-accordion .form-check.bg-white:focus-within {
    border-color: var(--accent) !important;
    box-shadow: 0 0 0 3px var(--brand-050);
}

#emp-tree-accordion .emp-leaf-check { width: 17px; height: 17px; margin-top: 0; flex: none; }
#emp-tree-accordion .form-check-label { font-size: var(--text-md); line-height: 1.35; }

/* The strategy tag is reference information, so it recedes until the row matters. */
#emp-tree-accordion .form-check .badge {
    background: var(--bg-sunken) !important;
    color: var(--text-3) !important;
    border: 1px solid var(--border) !important;
    font-family: var(--font-mono);
    font-size: var(--text-2xs);
    font-weight: 600;
    letter-spacing: 0.02em;
    white-space: nowrap;
}
#emp-tree-accordion .form-check.bg-white:has(.emp-leaf-check:checked) .badge {
    background: var(--bg-surface) !important;
    color: var(--accent-text) !important;
    border-color: color-mix(in srgb, var(--accent) 30%, transparent) !important;
}

/* Group/subgroup checkboxes are slightly larger: they act on many reports at once. */
.emp-parent-check, .emp-subgroup-check { width: 18px; height: 18px; }

/* Narrow viewports: one report per row, and the strategy tag drops rather than
   squeezing the title into two words per line. */
@media (max-width: 576px) {
    #emp-tree-accordion .form-check .badge { display: none; }
    #emp-tree-container > .d-flex.bg-light { gap: var(--sp-2); }
}

/* ============================================================ 12. EXECUTION SCREEN
   Progress, stage timeline, metrics, console and results. Presentation only: the ids and
   the real backend fields (progress_pct, current_stage, stage_durations, report_results)
   are untouched, and no state here is inferred in the browser. */

/* --- Stage timeline. progress.js now emits .stage-step + .is-done/.is-running, so the
   design-system rules in §7 are live rather than scaffolding. The row is a 3-column grid
   so the duration column aligns without the ASCII dot-leader it used to draw. */
#emp-stage-list {
    background: var(--bg-surface) !important;
    border: 1px solid var(--border) !important;
    border-radius: var(--r-md) !important;
    padding: var(--sp-2) !important;
}
#emp-stage-list .stage-step {
    display: grid;
    grid-template-columns: 20px 1fr auto;
    align-items: center;
    gap: var(--sp-3);
}
.stage-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stage-time {
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    color: var(--text-3);
    font-variant-numeric: tabular-nums;
}
/* A measured duration is fact; an estimate is a guess. They should not look identical. */
.stage-time.is-measured { color: var(--text-1); font-weight: 600; }
.stage-step.is-running .stage-time { color: var(--accent-text); }

/* --- Metric tiles (Total / Completed / Pending / Failed / Elapsed / Remaining) */
#emp-step-4 .row .p-3.bg-light.rounded.border {
    background: var(--bg-surface) !important;
    border: 1px solid var(--border) !important;
    border-radius: var(--r-md) !important;
    padding: var(--sp-4) var(--sp-3) !important;
    transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
#emp-step-4 .row .p-3.bg-light.rounded.border:hover {
    border-color: var(--border-strong) !important;
    box-shadow: var(--shadow-xs);
}
#emp-step-4 .row .text-secondary.small.fw-semibold {
    font-size: var(--text-2xs) !important;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-3) !important;
}
#emp-metric-total, #emp-metric-completed, #emp-metric-pending,
#emp-metric-failed, #emp-metric-elapsed, #emp-metric-time {
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
}

/* Overall progress reads as the headline number on this screen. */
#emp-prog-pct { font-variant-numeric: tabular-nums; letter-spacing: -0.02em; color: var(--accent-text) !important; }
#emp-step-4 .progress { height: 10px !important; }

/* --- Current task banner: the single most important line while a job runs. */
#emp-current-task-banner {
    background: var(--bg-surface) !important;
    border: 1px solid var(--border) !important;
    border-left: 3px solid var(--accent) !important;
    border-radius: var(--r-md) !important;
    color: var(--text-1) !important;
    box-shadow: var(--shadow-xs);
}
#emp-task-title { font-size: var(--text-base); letter-spacing: -0.01em; }
#emp-task-step { color: var(--text-2); }

/* --- Console header + log rows */
#emp-log-console { height: 280px !important; padding: var(--sp-3) var(--sp-4) !important; }
#emp-log-console > div { padding: 1px 0; }
#emp-log-count { font-family: var(--font-mono); }

/* --- Results & downloads: each report is an object you can act on. */
#emp-results-container .list-group-item {
    border-radius: var(--r-md);
    margin-bottom: var(--sp-2);
    border: 1px solid var(--border) !important;
    transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
#emp-results-container .list-group-item:hover {
    border-color: var(--border-strong) !important;
    box-shadow: var(--shadow-sm);
}
#emp-results-container .btn { white-space: nowrap; }

/* Narrow screens: metric tiles stay legible rather than shrinking their numbers away. */
@media (max-width: 576px) {
    #emp-step-4 .row .p-3.bg-light.rounded.border { padding: var(--sp-3) var(--sp-2) !important; }
    #emp-stage-list .stage-step { grid-template-columns: 18px 1fr auto; gap: var(--sp-2); }
}

/* ============================================================ 13. APPLICATION SHELL
   Navbar + module bar, treated as one docked header rather than two unrelated strips.

   Markup is untouched: registry.js resolves the module tabs by id (`nav-mod-*`), so every
   rule here hooks existing classes and ids. */

:root {
    /* Height of the sticky navbar. The module bar docks directly beneath it, which is what
       stops the tab strip sliding UNDER the navbar while scrolling - previously the tabs
       were cut in half mid-scroll. Measured against the rendered navbar. */
    --nav-h: 68px;   /* measured against the rendered navbar, not estimated */
}

.navbar-nbh {
    padding-block: var(--sp-3) !important;
    background: color-mix(in srgb, var(--bg-surface) 88%, transparent);
    backdrop-filter: saturate(180%) blur(12px);
    -webkit-backdrop-filter: saturate(180%) blur(12px);
}

/* The brand mark gets a soft accent halo - one deliberate flourish, not a gradient wash. */
.logo-container svg { border-radius: 9px; box-shadow: 0 2px 8px color-mix(in srgb, var(--accent) 30%, transparent); }

/* --- Module bar: the product's primary navigation. */
.nav-tabs-nbh {
    position: sticky;
    top: var(--nav-h);
    z-index: 1020;
    background: color-mix(in srgb, var(--bg-app) 92%, transparent);
    backdrop-filter: saturate(180%) blur(12px);
    -webkit-backdrop-filter: saturate(180%) blur(12px);
    border-bottom: 1px solid var(--border) !important;
    padding: var(--sp-2) var(--sp-1) 0;
    margin-bottom: var(--sp-5) !important;
    gap: var(--sp-1);
    overflow-x: auto;
    scrollbar-width: none;
}
.nav-tabs-nbh::-webkit-scrollbar { display: none; }

.nav-tabs-nbh .nav-link {
    position: relative;
    border: none !important;
    border-radius: var(--r-sm) var(--r-sm) 0 0;
    color: var(--text-2);
    font-weight: 560;
    font-size: var(--text-md);
    letter-spacing: -0.006em;
    padding: var(--sp-3) var(--sp-4) calc(var(--sp-3) + 2px);
    white-space: nowrap;
    transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.nav-tabs-nbh .nav-link:hover { color: var(--text-1); background: var(--bg-hover); }

/* The active indicator is drawn as a pseudo-element so it can animate its width instead of
   snapping a border on and off. */
.nav-tabs-nbh .nav-link::after {
    content: "";
    position: absolute;
    left: var(--sp-4); right: var(--sp-4); bottom: 0;
    height: 2px;
    background: var(--accent);
    border-radius: var(--r-pill) var(--r-pill) 0 0;
    transform: scaleX(0);
    transform-origin: center;
    transition: transform var(--t-med) var(--ease);
}
.nav-tabs-nbh .nav-link.active {
    color: var(--accent-text);
    font-weight: 640;
    background: transparent;
}
.nav-tabs-nbh .nav-link.active::after { transform: scaleX(1); }

/* The audit tab is separated from the reports group; make that divider deliberate. */
.nav-tabs-nbh .nav-item.border-start { border-color: var(--border) !important; }

/* Anchored jumps must clear BOTH sticky bars rather than landing under them. */
html { scroll-padding-top: calc(var(--nav-h) + 56px); scroll-behavior: smooth; }

@media (max-width: 768px) {
    /* Measured at 390px: the header wraps and grows rather than shrinking. */
    :root { --nav-h: 95px; }
    .nav-tabs-nbh .nav-link { padding: var(--sp-2) var(--sp-3) calc(var(--sp-2) + 2px); font-size: var(--text-sm); }
    .nav-tabs-nbh .nav-link::after { left: var(--sp-3); right: var(--sp-3); }
}

@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

/* ============================================================ 14. RESULTS & STATES */

/* --- Result rows: the payoff screen. Success should read as resolved, not merely listed. */
#emp-results-container .list-group-item {
    position: relative;
    padding-left: calc(var(--sp-4) + 3px);
    background: var(--bg-surface);
}
#emp-results-container .list-group-item::before {
    content: "";
    position: absolute;
    inset: 0 auto 0 0;
    width: 3px;
    border-radius: var(--r-pill) 0 0 var(--r-pill);
    background: var(--ok-500);
}
/* Failure is signalled by the same rail in the error colour - identical layout, so a failed
   report reads as "this one didn't work", not as a broken screen. */
#emp-results-container .list-group-item:has(.badge.bg-danger-subtle)::before,
#emp-results-container .list-group-item:has(.text-danger)::before { background: var(--err-500); }

/* File metadata (size, format, rows) is reference data: monospace, recessive, aligned. */
#emp-results-container .font-monospace { color: var(--text-2); font-size: var(--text-sm); }

/* The download control is the call to action on this screen. */
#emp-results-container .btn-primary, #emp-results-container .btn-success,
#emp-results-container a[href*="/artifacts/"] {
    font-weight: 600;
    box-shadow: var(--shadow-xs);
    transition: transform var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease),
                background-color var(--t-fast) var(--ease);
}
#emp-results-container a[href*="/artifacts/"]:hover { transform: translateY(-1px); box-shadow: var(--shadow-sm); }
#emp-results-container a[href*="/artifacts/"]:active { transform: translateY(0); }

/* --- Spinners inherit the brand instead of Bootstrap blue. */
.spinner-border { border-width: 2px; color: var(--accent); }
.spinner-border.text-primary { color: var(--accent) !important; }

/* --- Disabled controls read as unavailable, not as broken. */
.btn:disabled, .btn.disabled { opacity: 0.55; box-shadow: none; cursor: not-allowed; }
.form-check-input:disabled + .form-check-label { opacity: 0.55; }

/* --- Loading placeholder used while the report tree is fetched. */
#emp-tree-container .spinner-border + p, .text-center.py-5 p { color: var(--text-2); }

/* ============================================================ 15. AMBIENT ENVIRONMENT
   A layered environment behind the whole product, replacing the flat page colour.

   Built entirely from two pseudo-elements on <body>, so it costs no markup, no JS and no
   library - which matters because every screen here is rendered by vanilla JS that depends
   on the existing DOM. Nothing in this section can break a selector.

   PALETTE DECISION. Indigo/violet/cyan is used for the ENVIRONMENT - ambient light, glass
   tint, data-flow accents - while the brand red stays the action colour. Recolouring the
   primary actions would have traded the product identity for a trend. */

:root {
    --amb-indigo: 99 102 241;    /* ambient key light   */
    --amb-violet: 139 92 246;    /* ambient fill light  */
    --amb-cyan:    34 211 238;   /* data-flow highlight */

    /* Liquid glass, tuned per theme below: glass over a light room and glass over a dark
       room need different tint, border and highlight to read as the same material. */
    --glass-bg:        rgba(255, 255, 255, 0.62);
    --glass-border:    rgba(255, 255, 255, 0.75);
    --glass-highlight: rgba(255, 255, 255, 0.90);
    --glass-blur: 18px;
    --glass-shadow: 0 8px 32px rgba(16, 24, 40, 0.07), 0 2px 8px rgba(16, 24, 40, 0.04);
}

:root[data-theme="dark"] {
    --glass-bg:        rgba(30, 38, 50, 0.55);
    --glass-border:    rgba(255, 255, 255, 0.09);
    --glass-highlight: rgba(255, 255, 255, 0.14);
    --glass-shadow: 0 8px 32px rgba(0, 0, 0, 0.45), 0 2px 8px rgba(0, 0, 0, 0.30);
}
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --glass-bg:        rgba(30, 38, 50, 0.55);
        --glass-border:    rgba(255, 255, 255, 0.09);
        --glass-highlight: rgba(255, 255, 255, 0.14);
        --glass-shadow: 0 8px 32px rgba(0, 0, 0, 0.45), 0 2px 8px rgba(0, 0, 0, 0.30);
    }
}

body { position: relative; isolation: isolate; background-color: var(--bg-app); }

/* Ambient key/fill light. `fixed` so it behaves like room lighting the content moves
   through, rather than wallpaper that scrolls with it. */
body::before {
    content: "";
    position: fixed;
    inset: -20% -10% auto -10%;
    height: 130vh;
    z-index: -2;
    pointer-events: none;
    background:
        radial-gradient(50% 45% at 18% 8%,  rgb(var(--amb-indigo) / 0.16), transparent 70%),
        radial-gradient(45% 40% at 88% 4%,  rgb(var(--amb-violet) / 0.13), transparent 72%),
        radial-gradient(38% 34% at 62% 46%, rgb(var(--amb-cyan)   / 0.07), transparent 76%);
}

/* A faint structural grid - the data plane the migration runs on. Masked so it fades out
   before it can compete with content. */
body::after {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background-image:
        linear-gradient(to right, rgb(var(--amb-indigo) / 0.05) 1px, transparent 1px),
        linear-gradient(to bottom, rgb(var(--amb-indigo) / 0.05) 1px, transparent 1px);
    background-size: 56px 56px;
    mask-image: radial-gradient(75% 55% at 50% 0%, #000 0%, transparent 78%);
    -webkit-mask-image: radial-gradient(75% 55% at 50% 0%, #000 0%, transparent 78%);
}

:root[data-theme="dark"] body::before {
    background:
        radial-gradient(50% 45% at 18% 8%,  rgb(var(--amb-indigo) / 0.26), transparent 70%),
        radial-gradient(45% 40% at 88% 4%,  rgb(var(--amb-violet) / 0.20), transparent 72%),
        radial-gradient(38% 34% at 62% 46%, rgb(var(--amb-cyan)   / 0.11), transparent 76%);
}

/* ============================================================ 16. LIQUID GLASS
   Applied by WEIGHT, not everywhere: strong glass for the panels that frame the workflow,
   solid surfaces for dense content (console, tables) where translucency costs legibility. */

#emp-step-1-wrapper > .card,
#emp-tree-container > .card,
#emp-step-3-wrapper .card,
#emp-step-4 > .card,
#employee-report-area > .container-fluid > .card,
#emp-tree-accordion .accordion-item {
    background: var(--glass-bg) !important;
    backdrop-filter: blur(var(--glass-blur)) saturate(165%);
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(165%);
    border: 1px solid var(--glass-border) !important;
    /* The inset highlight is what stops this reading as "a blurred rectangle": it gives the
       panel a lit top edge and a grounded bottom, like real glass catching a light source. */
    box-shadow:
        inset 0 1px 0 var(--glass-highlight),
        inset 0 -1px 0 rgba(0, 0, 0, 0.03),
        var(--glass-shadow) !important;
}

/* A specular sheen across the top of the primary panels. Static - it is lighting, not
   animation, so it costs nothing to run. */
#emp-step-4 > .card, #employee-report-area > .container-fluid > .card { position: relative; }
#emp-step-4 > .card::before,
#employee-report-area > .container-fluid > .card::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 40%;
    pointer-events: none;
    border-radius: var(--r-lg) var(--r-lg) 0 0;
    background: linear-gradient(180deg, rgb(255 255 255 / 0.10), transparent);
}
:root[data-theme="dark"] #emp-step-4 > .card::before {
    background: linear-gradient(180deg, rgb(255 255 255 / 0.045), transparent);
}

/* Docked chrome reads as glass over the environment. */
.navbar-nbh, .nav-tabs-nbh {
    background: var(--glass-bg) !important;
    backdrop-filter: blur(20px) saturate(180%);
    -webkit-backdrop-filter: blur(20px) saturate(180%);
    border-bottom: 1px solid var(--glass-border) !important;
}

/* Report cards: depth on hover, and a selected state lit from the accent. */
#emp-tree-accordion .form-check.bg-white {
    background: var(--glass-bg) !important;
    backdrop-filter: blur(10px) saturate(140%);
    -webkit-backdrop-filter: blur(10px) saturate(140%);
    box-shadow: inset 0 1px 0 var(--glass-highlight);
}
#emp-tree-accordion .form-check.bg-white:hover {
    transform: translateY(-2px);
    box-shadow: inset 0 1px 0 var(--glass-highlight), var(--shadow-md);
}
#emp-tree-accordion .form-check.bg-white:has(.emp-leaf-check:checked) {
    box-shadow:
        inset 0 1px 0 var(--glass-highlight),
        0 0 0 1px color-mix(in srgb, var(--accent) 30%, transparent),
        0 6px 20px color-mix(in srgb, var(--accent) 16%, transparent);
}

/* Metric tiles float above the plane rather than sitting flat on it. */
#emp-step-4 .row .p-3.bg-light.rounded.border {
    background: var(--glass-bg) !important;
    backdrop-filter: blur(10px) saturate(140%);
    -webkit-backdrop-filter: blur(10px) saturate(140%);
    box-shadow: inset 0 1px 0 var(--glass-highlight);
}
#emp-step-4 .row .p-3.bg-light.rounded.border:hover {
    transform: translateY(-2px);
    box-shadow: inset 0 1px 0 var(--glass-highlight), var(--shadow-md);
}

/* The running stage carries the data-flow accent: a live migration should look alive. */
.stage-step.is-running {
    background: linear-gradient(90deg,
        rgb(var(--amb-indigo) / 0.10), rgb(var(--amb-cyan) / 0.05) 60%, transparent);
    border-radius: var(--r-sm);
}
.stage-step.is-running .stage-icon { box-shadow: 0 0 0 4px rgb(var(--amb-indigo) / 0.12); }

#emp-results-container .list-group-item:hover {
    box-shadow: inset 0 1px 0 var(--glass-highlight), var(--shadow-md);
    transform: translateY(-1px);
}

/* The console stays SOLID on purpose: log text must never fight a blurred backdrop. */
#emp-log-console {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.05), var(--shadow-md);
}

/* Primary action: lit, not flat. */
.btn-primary, .btn-primary-nbh {
    box-shadow: 0 1px 2px rgba(16, 24, 40, 0.10),
                0 4px 14px color-mix(in srgb, var(--accent) 26%, transparent);
}
.btn-primary:hover, .btn-primary-nbh:hover {
    transform: translateY(-1px);
    box-shadow: 0 2px 4px rgba(16, 24, 40, 0.12),
                0 8px 22px color-mix(in srgb, var(--accent) 34%, transparent);
}

/* Backdrop-filter is GPU work. On small screens the panels are nearly full-width and the
   effect is barely visible, so it is dropped rather than paid for. */
@media (max-width: 768px) {
    #emp-tree-accordion .form-check.bg-white,
    #emp-step-4 .row .p-3.bg-light.rounded.border {
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
    }
    body::after { display: none; }
}

@media (prefers-reduced-motion: reduce) {
    #emp-tree-accordion .form-check.bg-white:hover,
    #emp-step-4 .row .p-3.bg-light.rounded.border:hover,
    .btn-primary:hover,
    #emp-results-container .list-group-item:hover { transform: none; }
}

/* ============================================================ 17. HERO + BENTO + 3D
   The "AI Migration Command Center" landing composition.

   Implementation note: the 3D is CSS `transform-style: preserve-3d` on empty divs - no
   WebGL, no library, no images, no requests. It animates only `transform`/`opacity`, so it
   composites on the GPU and never triggers layout. All of it is decorative and aria-hidden;
   the metrics beside it are real values. */

.mp-hero {
    position: relative;
    padding: var(--sp-10) var(--sp-6) var(--sp-8);
    max-width: 1560px;
    margin-inline: auto;
}

.mp-hero-inner {
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
    gap: var(--sp-10);
    align-items: center;
}

/* --- Copy ------------------------------------------------------------------ */
.mp-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    font-size: var(--text-xs);
    font-weight: 650;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--text-2);
    margin: 0 0 var(--sp-4);
    padding: 6px var(--sp-3);
    border: 1px solid var(--glass-border);
    border-radius: var(--r-pill);
    background: var(--glass-bg);
    backdrop-filter: blur(10px) saturate(150%);
    -webkit-backdrop-filter: blur(10px) saturate(150%);
}
.mp-eyebrow-dot {
    width: 7px; height: 7px; border-radius: 50%;
    background: rgb(var(--amb-cyan));
    box-shadow: 0 0 0 3px rgb(var(--amb-cyan) / 0.22);
}

.mp-title {
    font-size: clamp(2rem, 3.6vw, 3.4rem);
    line-height: 1.06;
    letter-spacing: -0.032em;
    font-weight: 700;
    margin: 0 0 var(--sp-4);
    color: var(--text-1);
}
/* The second line carries the ambient palette; the brand red stays for actions. */
.mp-title-accent {
    background: linear-gradient(100deg, rgb(var(--amb-indigo)), rgb(var(--amb-violet)) 55%, rgb(var(--amb-cyan)));
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}
.mp-sub {
    font-size: var(--text-lg);
    line-height: 1.55;
    color: var(--text-2);
    max-width: 46ch;
    margin: 0 0 var(--sp-6);
}
.mp-cta-row { display: flex; flex-wrap: wrap; gap: var(--sp-3); }

/* --- 3D scene -------------------------------------------------------------- */
.mp-hero-visual { display: grid; place-items: center; min-height: 380px; }

.mp-scene {
    position: relative;
    width: min(420px, 100%);
    aspect-ratio: 1;
    perspective: 1100px;
    transform-style: preserve-3d;
}

/* Orbits: the data paths the migration travels. */
.mp-orbit {
    position: absolute;
    inset: 0;
    margin: auto;
    border-radius: 50%;
    border: 1px solid rgb(var(--amb-indigo) / 0.28);
    transform-style: preserve-3d;
}
.mp-orbit-1 {
    width: 82%; height: 82%;
    transform: rotateX(72deg) rotateZ(0deg);
    animation: mp-spin 26s linear infinite;
}
.mp-orbit-2 {
    width: 60%; height: 60%;
    border-color: rgb(var(--amb-cyan) / 0.30);
    transform: rotateX(66deg) rotateY(22deg);
    animation: mp-spin 18s linear infinite reverse;
}
@keyframes mp-spin { to { transform: rotateX(72deg) rotateZ(360deg); } }

/* The migration core: a translucent glass cube, slowly rotating. */
.mp-core {
    position: absolute;
    inset: 0; margin: auto;
    width: 132px; height: 132px;
    transform-style: preserve-3d;
    animation: mp-float 9s ease-in-out infinite, mp-tumble 30s linear infinite;
}
.mp-core-face {
    position: absolute;
    inset: 0;
    border: 1px solid rgb(var(--amb-indigo) / 0.5);
    border-radius: 14px;
    background:
        linear-gradient(140deg, rgb(var(--amb-indigo) / 0.30), rgb(var(--amb-violet) / 0.16) 60%, rgb(var(--amb-cyan) / 0.14));
    box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.35);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}
.mp-core-front  { transform: translateZ(66px); }
.mp-core-back   { transform: rotateY(180deg) translateZ(66px); }
.mp-core-right  { transform: rotateY(90deg)  translateZ(66px); }
.mp-core-left   { transform: rotateY(-90deg) translateZ(66px); }
.mp-core-top    { transform: rotateX(90deg)  translateZ(66px); }
.mp-core-bottom { transform: rotateX(-90deg) translateZ(66px); }

@keyframes mp-tumble { to { transform: rotateX(360deg) rotateY(360deg); } }
@keyframes mp-float {
    0%, 100% { margin-top: 0; }
    50%      { margin-top: -14px; }
}

/* Report documents drifting around the core - the artifacts the engine produces. */
.mp-doc {
    position: absolute;
    width: 74px; height: 94px;
    border-radius: 10px;
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    box-shadow: inset 0 1px 0 var(--glass-highlight), var(--glass-shadow);
    backdrop-filter: blur(8px) saturate(150%);
    -webkit-backdrop-filter: blur(8px) saturate(150%);
}
/* Ruled lines, so each object reads as a spreadsheet rather than a blank card. */
.mp-doc::after {
    content: "";
    position: absolute;
    inset: 12px 12px auto 12px;
    height: 46px;
    background: repeating-linear-gradient(
        to bottom,
        rgb(var(--amb-indigo) / 0.34) 0 2px,
        transparent 2px 9px);
    border-radius: 2px;
}
.mp-doc-1 { top: 6%;  left: 2%;   transform: rotate(-11deg); animation: mp-drift 11s ease-in-out infinite; }
.mp-doc-2 { top: 52%; right: 0%;  transform: rotate(9deg);   animation: mp-drift 13s ease-in-out infinite 1.5s; }
.mp-doc-3 { bottom: 2%; left: 22%; transform: rotate(4deg);  animation: mp-drift 15s ease-in-out infinite 3s; }
@keyframes mp-drift {
    0%, 100% { translate: 0 0; }
    50%      { translate: 0 -16px; }
}

/* Connection nodes pulsing along the data paths. */
.mp-node {
    position: absolute;
    width: 9px; height: 9px;
    border-radius: 50%;
    background: rgb(var(--amb-cyan));
    box-shadow: 0 0 14px rgb(var(--amb-cyan) / 0.8);
    animation: mp-pulse 3.4s ease-in-out infinite;
}
.mp-node-1 { top: 20%; right: 20%; }
.mp-node-2 { bottom: 26%; left: 12%; animation-delay: 1.1s; }
.mp-node-3 { top: 58%; right: 8%;  animation-delay: 2.2s; }
@keyframes mp-pulse {
    0%, 100% { opacity: 0.35; transform: scale(0.85); }
    50%      { opacity: 1;    transform: scale(1.15); }
}

/* --- Bento ----------------------------------------------------------------- */
.mp-bento {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--sp-4);
    margin-top: var(--sp-10);
}
/* One dominant tile, three supporting - deliberately unequal weight. */
.mp-tile-lg { grid-column: span 2; grid-row: span 1; }

.mp-tile {
    position: relative;
    overflow: hidden;
    padding: var(--sp-5);
    border-radius: var(--r-lg);
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    box-shadow: inset 0 1px 0 var(--glass-highlight), var(--glass-shadow);
    backdrop-filter: blur(var(--glass-blur)) saturate(165%);
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(165%);
    transition: transform var(--t-med) var(--ease), box-shadow var(--t-med) var(--ease);
}
.mp-tile:hover {
    transform: translateY(-3px);
    box-shadow: inset 0 1px 0 var(--glass-highlight), var(--shadow-lg);
}
.mp-tile-label {
    font-size: var(--text-2xs);
    font-weight: 650;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-3);
    margin: 0 0 var(--sp-2);
}
.mp-tile-value {
    font-size: clamp(1.5rem, 2.2vw, 2.1rem);
    font-weight: 700;
    letter-spacing: -0.026em;
    color: var(--text-1);
    margin: 0 0 var(--sp-1);
    font-variant-numeric: tabular-nums;
}
.mp-tile-note { font-size: var(--text-md); color: var(--text-2); margin: 0; }
.mp-tile-lg .mp-tile-value {
    background: linear-gradient(100deg, rgb(var(--amb-indigo)), rgb(var(--amb-cyan)));
    -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* A quiet data-flow marker on the dominant tile. */
.mp-flow { display: flex; gap: 6px; margin-top: var(--sp-4); }
.mp-flow i {
    width: 28px; height: 4px; border-radius: var(--r-pill);
    background: rgb(var(--amb-indigo) / 0.30);
    animation: mp-flow 2.6s ease-in-out infinite;
}
.mp-flow i:nth-child(2) { animation-delay: 0.3s; }
.mp-flow i:nth-child(3) { animation-delay: 0.6s; }
@keyframes mp-flow {
    0%, 100% { background: rgb(var(--amb-indigo) / 0.22); }
    50%      { background: rgb(var(--amb-cyan) / 0.85); }
}

/* --- Responsive ------------------------------------------------------------ */
@media (max-width: 1100px) {
    .mp-hero-inner { grid-template-columns: 1fr; gap: var(--sp-8); }
    .mp-hero-visual { order: -1; min-height: 300px; }
    .mp-scene { width: min(330px, 86vw); }
    .mp-bento { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .mp-tile-lg { grid-column: span 2; }
}
@media (max-width: 640px) {
    .mp-hero { padding: var(--sp-6) var(--sp-4); }
    .mp-bento { grid-template-columns: 1fr; }
    .mp-tile-lg { grid-column: span 1; }
    .mp-scene { width: min(260px, 78vw); }
    .mp-cta-row .btn { flex: 1 1 auto; }
    /* Backdrop-filter on six tiles is GPU work that buys little at this width. */
    .mp-tile, .mp-doc { backdrop-filter: none; -webkit-backdrop-filter: none; }
}

/* Motion is decoration here: under reduced-motion the scene holds a composed pose. */
@media (prefers-reduced-motion: reduce) {
    .mp-core, .mp-orbit-1, .mp-orbit-2, .mp-doc, .mp-node, .mp-flow i { animation: none !important; }
    .mp-tile:hover { transform: none; }
}

/* ============================================================ 18. REPORT IDENTITY
   Per-report visual markers on the selection cards.

   Implemented as a CSS custom property (`--ico`) resolved by `:has()` on the checkbox's
   own value, then painted through `::after`. That means:
     - no markup change, so tree.js keeps rendering exactly what it renders today;
     - no new dependency, no icon font, no SVG sprite, no requests;
     - the report id is the single source of truth for the glyph, so a report that is
       renamed in the catalogue keeps its marker.

   `::before` on this card is already the selection accent rail (section 11), so the icon
   uses `::after`. Glyphs are geometric Unicode present in the default UI stacks on Windows,
   macOS and Linux - deliberately not an emoji set, which would render as colour pictures on
   some platforms and flat outlines on others. */

#emp-tree-accordion .form-check.bg-white {
    /* Room for the marker, which is positioned in the padding rather than in the flow -
       the checkbox, label and strategy badge keep their existing order and behaviour. */
    padding-left: calc(var(--sp-4) + 30px) !important;
    --ico: "\25A6";            /* default: grid/document */
}

#emp-tree-accordion .form-check.bg-white::after {
    content: var(--ico);
    position: absolute;
    left: var(--sp-3);
    top: 50%;
    translate: 0 -50%;
    width: 24px;
    height: 24px;
    display: grid;
    place-items: center;
    font-size: 13px;
    line-height: 1;
    border-radius: 7px;
    color: var(--text-3);
    background: var(--bg-sunken);
    border: 1px solid var(--border);
    transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease),
                border-color var(--t-fast) var(--ease), transform var(--t-med) var(--ease),
                box-shadow var(--t-fast) var(--ease);
}

/* Hover: the marker lifts fractionally with the card. */
#emp-tree-accordion .form-check.bg-white:hover::after {
    color: var(--text-2);
    border-color: var(--border-strong);
    transform: translateY(-1px);
}

/* Selected: the marker becomes the most prominent thing on the row, lit by the accent. */
#emp-tree-accordion .form-check.bg-white:has(.emp-leaf-check:checked)::after {
    color: #fff;
    background: linear-gradient(135deg, rgb(var(--amb-indigo)), rgb(var(--amb-violet)));
    border-color: transparent;
    box-shadow: 0 3px 10px rgb(var(--amb-indigo) / 0.42);
    transform: scale(1.06);
}

/* --- Per-report glyphs, grouped by what the report actually is. ------------- */

/* Dues & collection - part-filled circle reads as "balance outstanding". */
#emp-tree-accordion .form-check:has([value="dues_report"]),
#emp-tree-accordion .form-check:has([value="dues_collection_by_account"]),
#emp-tree-accordion .form-check:has([value="advance_collection"]) { --ico: "\25D1"; }

/* Account balances - stacked bars. */
#emp-tree-accordion .form-check:has([value="dues_advance_account_balance"]),
#emp-tree-accordion .form-check:has([value="advance_account_balance"]),
#emp-tree-accordion .form-check:has([value="account_statement"]) { --ico: "\25A4"; }

/* Statements - two-panel layout, matching how these reports actually render. */
#emp-tree-accordion .form-check:has([value="receipt_payment_statement"]),
#emp-tree-accordion .form-check:has([value="cash_bank_statement"]) { --ico: "\25A5"; }

/* Income / expense - diamond, the analysis marker. */
#emp-tree-accordion .form-check:has([value="income_report"]),
#emp-tree-accordion .form-check:has([value="expense_report"]),
#emp-tree-accordion .form-check:has([value="income_expense_account"]) { --ico: "\25C8"; }

/* Final accounts - full grid, the most structured outputs. */
#emp-tree-accordion .form-check:has([value="trial_balance"]),
#emp-tree-accordion .form-check:has([value="balance_sheet"]),
#emp-tree-accordion .form-check:has([value="detailed_balance_sheet"]) { --ico: "\25A6"; }

/* Ledgers - horizontal rules, like a ledger page. */
#emp-tree-accordion .form-check:has([value="all_ledger"]),
#emp-tree-accordion .form-check:has([value="day_book"]) { --ico: "\2263"; }

/* Direct ERP downloads - downward arrow: the ERP hands us the file. */
#emp-tree-accordion .form-check:has([value="general_payment"]),
#emp-tree-accordion .form-check:has([value="general_receipt"]) { --ico: "\2913"; }

/* Vendor reports - hexagonal node, the supplier in the data graph. */
#emp-tree-accordion .form-check:has([value="paid_vendor"]),
#emp-tree-accordion .form-check:has([value="unpaid_vendor"]),
#emp-tree-accordion .form-check:has([value="vendor_report"]) { --ico: "\2B22"; }

/* Invoicing batch - grouped blocks. */
#emp-tree-accordion .form-check:has([value="group_batch_report"]) { --ico: "\25A9"; }

/* Credit note - an adjustment to an existing document. */
#emp-tree-accordion .form-check:has([value="credit_note_register"]) { --ico: "\229F"; }

/* MIS - the overview report. */
#emp-tree-accordion .form-check:has([value="mis_report"]) { --ico: "\25CE"; }

@media (max-width: 576px) {
    /* The marker survives; the strategy tag is what drops (section 11). */
    #emp-tree-accordion .form-check.bg-white { padding-left: calc(var(--sp-3) + 28px) !important; }
}

@media (prefers-reduced-motion: reduce) {
    #emp-tree-accordion .form-check.bg-white:hover::after,
    #emp-tree-accordion .form-check.bg-white:has(.emp-leaf-check:checked)::after { transform: none; }
}

/* ============================================================ 19. HERO SCOPE
   The hero is the landing composition. It stays for the default workspace and steps aside
   once the operator commits to a specific module, so the workflow - not the marketing -
   owns the screen. Driven by a class on <body>, set by a listener on the EXISTING module
   tabs; no routing is introduced and registry.js is untouched. */

.mp-hero {
    max-height: 2000px;
    opacity: 1;
    overflow: hidden;
    transition: max-height var(--t-med) var(--ease), opacity var(--t-med) var(--ease),
                padding var(--t-med) var(--ease);
}
body.mp-focus-module .mp-hero {
    max-height: 0;
    opacity: 0;
    padding-block: 0;
    pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
    .mp-hero { transition: none; }
}
