/* ============================================================================
   DTS Design System
   A unified light/dark theme mixing three references:
     - Industrial   -> Inter headings, JetBrains Mono for data/labels, LED
                       status dots, tactile "pressed" buttons, recessed inputs.
     - SaaS         -> clean rounded cards, soft layered shadows, calm layout.
     - Cyberpunk    -> dark HUD chassis sidebar, electric-blue glow accent, terminal
                       brand mark (Share Tech Mono), bracket/mono eyebrow labels.
   Theme switch = Bootstrap's own `data-bs-theme` attribute on <html>, so
   Bootstrap's built-in dark-mode component variables flip at the same time
   as everything below. See site.js for the toggle + persistence logic.
   ============================================================================ */

:root {
    /* ---- surfaces ---- */
    --bg: #eef1f6;
    --surface: #ffffff;
    --surface-2: #f4f6fb;
    --surface-3: #e9edf5;
    --border: #dfe3ec;
    --border-strong: #c7cedb;

    /* ---- text ---- */
    --text: #141a26;
    --text-muted: #667085;
    --text-faint: #98a2b3;

    /* ---- brand accent (monochrome - black in light mode, inverts to white in dark) ---- */
    --accent: #101828;
    --accent-hover: #1d2939;
    --accent-active: #000000;
    --accent-ink: #ffffff;
    --accent-soft: rgba(16, 24, 40, .06);
    --focus-ring: rgba(16, 24, 40, .25);

    /* ---- semantic status ---- */
    --success: #1a9c56;
    --success-soft: rgba(26, 156, 86, .12);
    --warning: #b5790f;
    --warning-soft: rgba(181, 121, 15, .14);
    --warning-soft-strong: rgba(181, 121, 15, .32);
    --danger: #dc3a54;
    --danger-soft: rgba(220, 58, 84, .12);
    --info: #0891b2;
    --info-soft: rgba(8, 145, 178, .12);

    /* ---- decorative-only accent (grid section-header labels) - a neutral gray, distinct from
       --warning, which carries a semantic "something needs attention" meaning elsewhere ---- */
    --section-label: #667085;

    /* ---- shape ---- */
    --radius-xs: 6px;
    --radius-sm: 8px;
    --radius-md: 12px;
    --radius-lg: 16px;
    --radius-pill: 999px;

    /* ---- shadow ---- */
    --shadow-sm: 0 1px 2px rgba(20, 30, 60, .06);
    --shadow-md: 0 1px 2px rgba(20, 30, 60, .04), 0 8px 24px -12px rgba(20, 30, 60, .14);
    --shadow-lg: 0 4px 10px rgba(20, 30, 60, .06), 0 20px 44px -18px rgba(20, 30, 60, .22);
    --press-shadow: 0 2px 0 rgba(15, 20, 35, .16);

    /* ---- fonts - one unified family everywhere. --font-mono/--font-display used to point at
       JetBrains Mono/Share Tech Mono for a "terminal" look; both now just alias --font-sans, so
       every existing selector that references them (tracking numbers, table headers, kpi values,
       the brand mark, ...) automatically becomes Inter with no per-selector hunting. Numeric
       alignment (the actual reason mono was used for prices/tracking numbers) comes from
       font-variant-numeric: tabular-nums instead, set independently of font-family - see
       .ind-mono/.sp-grid th,td below - and Inter supports tabular figures natively. ---- */
    --font-sans: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-mono: var(--font-sans);
    --font-display: var(--font-sans);

    /* ---- fixed chassis (sidebar stays dark in both themes - control-panel feel) ---- */
    --chassis-bg: #010409;
    --chassis-bg-2: #0d1117;
    --chassis-border: #21262d;
    --chassis-text: #8b949e;
    --chassis-text-active: #e6edf3;
    --chassis-heading: #6e7681;

    /* ---- sidebar "active item" contrast - theme-INDEPENDENT (the sidebar chassis is always dark
       in both light and dark mode), so this can't just reuse --accent: once --accent goes
       near-black for light mode, that would be dark-on-dark against the dark sidebar. ---- */
    --sidebar-active-bg: rgba(255, 255, 255, .08);
    --sidebar-active-text: #ffffff;
    --sidebar-active-border: #ffffff;
}

/* Dark theme = GitHub's "Dark default" palette (canvas #0d1117, subtle #161b22, border #30363d,
   fg #e6edf3 / muted #8b949e, semantic green/yellow/red/blue) - cool blue-gray rather than a
   purple-tinted navy. */
:root[data-bs-theme="dark"] {
    --bg: #0d1117;
    --surface: #161b22;
    --surface-2: #1c2128;
    --surface-3: #21262d;
    --border: #30363d;
    --border-strong: #484f58;

    --text: #e6edf3;
    --text-muted: #8b949e;
    --text-faint: #6e7681;

    --accent: #f5f5f5;
    --accent-hover: #ffffff;
    --accent-active: #d0d0d0;
    --accent-ink: #0a0a0a;
    --accent-soft: rgba(245, 245, 245, .10);
    --focus-ring: rgba(245, 245, 245, .35);

    --success: #3fb950;
    --success-soft: rgba(63, 185, 80, .16);
    --warning: #d29922;
    --warning-soft: rgba(210, 153, 34, .16);
    --warning-soft-strong: rgba(210, 153, 34, .38);
    --danger: #f85149;
    --danger-soft: rgba(248, 81, 73, .16);
    --info: #58a6ff;
    --info-soft: rgba(88, 166, 255, .16);

    --section-label: #8b949e;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .5);
    --shadow-md: 0 1px 2px rgba(0, 0, 0, .4), 0 10px 28px -14px rgba(0, 0, 0, .75);
    --shadow-lg: 0 4px 12px rgba(0, 0, 0, .5), 0 24px 56px -22px rgba(0, 0, 0, .85);
    --press-shadow: 0 2px 0 rgba(0, 0, 0, .5);
}

/* ============================================================================
   Base
   ============================================================================ */
* { scrollbar-color: var(--border-strong) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 99px; }
::-webkit-scrollbar-track { background: transparent; }
::selection { background: var(--accent-soft); color: var(--accent); }

/* Mouse-wheel scrolling jumps straight to the new position with no animation by default - only
   dragging the scrollbar thumb feels "smooth" because it's many tiny position updates. Chrome and
   Firefox both animate wheel-driven scrolling too (not just scrollIntoView/anchor-link scrolls)
   when the scrolled element has scroll-behavior:smooth, so this closes that gap everywhere the app
   scrolls: the page itself, the sidebar, and every wide/tall table's own scroll container. */
html, .sp-grid-wrapper, .table-responsive, .dts-content {
    scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
    html, .sp-grid-wrapper, .table-responsive, .dts-content {
        scroll-behavior: auto;
    }
}

html, body { background: var(--bg); }
body {
    font-family: var(--font-sans);
    color: var(--text);
    -webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4, h5, h6 { color: var(--text); font-weight: 700; letter-spacing: -.01em; }
a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-hover); }
.text-muted { color: var(--text-muted) !important; }
hr { border-color: var(--border); opacity: 1; }

:focus-visible { outline: none; }

/* ---- mono / eyebrow helpers (used ad hoc across views) ---- */
.ind-mono, .mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.ind-label, .eyebrow {
    font-family: var(--font-mono); font-size: .68rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: .08em; color: var(--text-muted);
}

/* ============================================================================
   Shell / Sidebar
   ============================================================================
   A persistent, collapsible left sidebar (icon+label "expanded" <-> icon-only "rail") replaces
   the old top navbar. Desktop-only concept: collapse state is ignored below 768px, where the
   sidebar instead becomes a full-width slide-in drawer (see the mobile block at the bottom). */
.dts-shell { display: flex; min-height: 100vh; }

.dts-sidebar {
    width: 248px; flex-shrink: 0; display: flex; flex-direction: column;
    background: var(--chassis-bg); border-right: 1px solid var(--chassis-border);
    position: sticky; top: 0; height: 100vh; z-index: 20;
    transition: width .15s ease;
}
html.dts-sidebar-collapsed .dts-sidebar { width: 72px; }

.dts-sidebar-header {
    display: flex; align-items: center; justify-content: space-between;
    padding: 1rem 1.1rem; border-bottom: 1px solid var(--chassis-border); flex-shrink: 0; gap: .5rem;
}
.dts-sidebar-brand {
    display: flex; align-items: center; gap: .6rem; font-weight: 800; font-size: 1.25rem;
    letter-spacing: -.01em; color: var(--chassis-text-active); overflow: hidden; white-space: nowrap; min-width: 0;
    position: relative;
}
.dts-sidebar-brand:hover { color: var(--chassis-text-active); }
.dts-sidebar-logo { height: 28px; width: 28px; object-fit: contain; flex-shrink: 0; border-radius: 6px; }
/* Small "click to expand" badge on the logo - only shown once the logo IS the expand button (see
   the collapsed-mode rules below); hidden the rest of the time so it doesn't clutter the normal,
   expanded-sidebar wordmark. */
.dts-sidebar-brand-hint { display: none; }
.dts-sidebar-toggle {
    display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px;
    border-radius: var(--radius-xs); border: 1px solid var(--chassis-border); background: transparent;
    color: var(--chassis-text); cursor: pointer; flex-shrink: 0; transition: background .12s ease, color .12s ease;
}
.dts-sidebar-toggle:hover { background: var(--chassis-bg-2); color: var(--chassis-text-active); }
.dts-sidebar-toggle i { transition: transform .15s ease; }
html.dts-sidebar-collapsed .dts-sidebar-toggle i { transform: rotate(180deg); }

.dts-sidebar-nav { flex: 1 1 auto; overflow-y: auto; overflow-x: hidden; padding: .6rem; }
.dts-nav { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .1rem; }
.dts-nav .nav-link, .dts-nav-section-toggle {
    display: flex; align-items: center; gap: .7rem; width: 100%;
    color: var(--chassis-text); padding: .55rem .65rem; border-radius: var(--radius-sm);
    font-size: .87rem; font-weight: 500; border: none; background: transparent; text-align: left;
    transition: background .12s ease, color .12s ease;
}
.dts-nav .nav-link:hover, .dts-nav-section-toggle:hover { background: var(--chassis-bg-2); color: var(--chassis-text-active); }
.dts-nav .nav-link.active, .dts-nav-section-toggle.active {
    background: var(--sidebar-active-bg); color: var(--sidebar-active-text);
}
.dts-nav .nav-link i:first-child, .dts-nav-section-toggle i:first-child {
    font-size: 1.05rem; width: 1.2rem; text-align: center; flex-shrink: 0;
}
.dts-nav .nav-link span, .dts-nav-section-toggle span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.dts-nav-section-toggle { cursor: pointer; }
.dts-nav-chevron { margin-left: auto; font-size: .75rem !important; width: auto !important; flex-shrink: 0; transition: transform .15s ease; }
.dts-nav-section.expanded .dts-nav-chevron { transform: rotate(180deg); }

.dts-nav-section-items {
    list-style: none; margin: .1rem 0 .3rem; padding: 0; display: flex; flex-direction: column; gap: .05rem;
    overflow: hidden; max-height: 0; transition: max-height .18s ease;
}
.dts-nav-section.expanded .dts-nav-section-items { max-height: 600px; }
.dts-nav-section-items .nav-link { padding-left: 2.35rem; font-size: .83rem; }

.dts-sidebar-footer {
    border-top: 1px solid var(--chassis-border); padding: .7rem; flex-shrink: 0;
    display: flex; flex-direction: column; gap: .4rem;
}
.dts-sidebar-footer .theme-toggle { align-self: flex-start; border-color: var(--chassis-border); background: var(--chassis-bg-2); color: var(--chassis-text); }
/* Overrides the global .theme-toggle:hover below, which uses --accent - in light mode that's
   near-black, so hovering this button (always on the sidebar's permanently-dark chassis
   background, in both themes) made the icon and border nearly invisible against it. Same
   chassis-scoped hover already used for every other sidebar control instead. */
.dts-sidebar-footer .theme-toggle:hover { color: var(--chassis-text-active); border-color: var(--chassis-border); background: var(--chassis-bg); }
.dts-sidebar-user { display: flex; align-items: center; gap: .6rem; padding: .35rem .3rem; color: var(--chassis-text-active); font-size: .85rem; overflow: hidden; }
.dts-sidebar-user i { font-size: 1.5rem; color: var(--chassis-text); flex-shrink: 0; }
.dts-sidebar-user-text { overflow: hidden; min-width: 0; }
.dts-sidebar-user-name { display: block; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dts-sidebar-logout {
    display: flex; align-items: center; gap: .6rem; width: 100%; padding: .5rem .55rem;
    border-radius: var(--radius-sm); border: none; background: transparent; color: var(--chassis-text);
    font-size: .85rem; font-weight: 500; cursor: pointer; transition: background .12s ease, color .12s ease;
}
.dts-sidebar-logout:hover { background: var(--chassis-bg-2); color: var(--chassis-text-active); }

/* ---- collapsed (icon-rail) mode: hide every label, center icons, and turn Setup's inline
   sub-list into a floating flyout anchored to the right of its icon instead of an indented
   list (there's no room to indent inside a 72px rail). ---- */
html.dts-sidebar-collapsed .dts-sidebar-brand span,
html.dts-sidebar-collapsed .dts-nav span,
html.dts-sidebar-collapsed .dts-sidebar-user-text,
html.dts-sidebar-collapsed .dts-sidebar-logout span {
    display: none;
}
/* The footer's three rows (theme toggle, user, logout) all stay full-width in the rail (nothing
   shrinks them), so hiding their labels above just leaves each icon sitting at the LEFT edge of
   that still-full-width row instead of in the middle of the rail - .theme-toggle even more so,
   since its own fixed 34px size means the column's default align-items:stretch can't center it by
   sizing alone. Centering each row's own content (and the fixed-size toggle itself) fixes both. */
html.dts-sidebar-collapsed .dts-sidebar-footer .theme-toggle { align-self: center; }
html.dts-sidebar-collapsed .dts-sidebar-user { justify-content: center; padding-left: 0; padding-right: 0; }
/* The separate collapse-toggle button and the brand icon both being icon-only, side by side, had
   nowhere near enough room in a 72px rail and visibly overlapped. Rather than shrink either one
   further, the logo itself becomes the expand button while collapsed (see site.js's brand click
   handler) - the dedicated toggle button is hidden and the logo takes over its job and its space,
   centered alone in the header. */
html.dts-sidebar-collapsed .dts-sidebar-header { justify-content: center; padding-left: .5rem; padding-right: .5rem; }
html.dts-sidebar-collapsed .dts-sidebar-toggle { display: none; }
html.dts-sidebar-collapsed .dts-sidebar-brand {
    width: 34px; height: 34px; justify-content: center; border-radius: var(--radius-xs);
    transition: background .12s ease;
}
html.dts-sidebar-collapsed .dts-sidebar-brand:hover { background: var(--chassis-bg-2); }
/* The "click to expand" badge itself - a small chevron pinned to the icon's corner, always
   visible (not just on hover) so the logo reads as clickable at a glance, not just discoverable
   by accident. */
html.dts-sidebar-collapsed .dts-sidebar-brand-hint {
    display: flex; align-items: center; justify-content: center;
    position: absolute; right: -3px; bottom: -3px; width: 14px; height: 14px;
    border-radius: 50%; background: var(--chassis-bg-2); border: 1px solid var(--chassis-border);
    color: var(--chassis-text-active); font-size: .5rem;
}
/* ...except inside the Setup flyout itself - it's a floating popout, not the rail, so its own
   sub-item labels should read normally once it's open. */
html.dts-sidebar-collapsed .dts-nav-section-items span { display: inline; }
html.dts-sidebar-collapsed .dts-nav .nav-link,
html.dts-sidebar-collapsed .dts-nav-section-toggle,
html.dts-sidebar-collapsed .dts-sidebar-logout { justify-content: center; }
html.dts-sidebar-collapsed .dts-nav-section-items .nav-link { justify-content: flex-start; }
html.dts-sidebar-collapsed .dts-nav-chevron { display: none; }
/* position:fixed (not absolute) + JS-computed top/left (see site.js's setupToggle handler) -
   .dts-sidebar-nav (its nearest ancestor) is a scroll container (overflow-y:auto), and a
   scroll-container clips ANY absolutely-positioned descendant that overflows it, including on
   the axis left `visible`/`auto` - not just the axis explicitly set to `hidden`. fixed positioning
   escapes that clipping entirely by leaving normal layout flow altogether. */
html.dts-sidebar-collapsed .dts-nav-section-items {
    position: fixed; z-index: 30;
    /* max-height is set inline in px by site.js's setupToggle handler, sized to whatever room is
       actually left below the icon in the current viewport - a long Setup list (11 items and
       growing) can otherwise run off the bottom of the screen with nothing to scroll it back into
       view, since this is position:fixed and out of the page's own normal scroll flow. */
    max-height: none; overflow-y: auto; width: 220px; background: var(--chassis-bg-2); border: 1px solid var(--chassis-border);
    border-radius: var(--radius-md); box-shadow: var(--shadow-lg); padding: .4rem; margin: 0;
    opacity: 0; visibility: hidden; transform: translateX(-4px);
    transition: opacity .12s ease, transform .12s ease, visibility .12s ease;
}
html.dts-sidebar-collapsed .dts-nav-section.expanded .dts-nav-section-items {
    opacity: 1; visibility: visible; transform: translateX(0);
}
html.dts-sidebar-collapsed .dts-nav-section-items .nav-link { padding-left: .65rem; }

/* ---- main column ---- */
.dts-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.dts-topbar {
    position: sticky; top: 0; z-index: 15; background: var(--bg);
    padding: .9rem 1.5rem; display: flex; align-items: center; gap: 1rem;
    border-bottom: 1px solid var(--border);
}
.dts-topbar-title { font-weight: 700; font-size: 1.05rem; color: var(--text); flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dts-mobile-toggle {
    display: none; align-items: center; justify-content: center; width: 34px; height: 34px;
    border-radius: var(--radius-sm); border: 1px solid var(--border-strong); background: var(--surface-2);
    color: var(--text); cursor: pointer; flex-shrink: 0;
}

.dts-content { padding: 1.5rem; }

/* ---- mobile (<768px): the sidebar becomes a full-width slide-in drawer behind a hamburger
   button, instead of the desktop rail/expanded toggle - so the desktop collapsed state is
   force-disabled here regardless of what's persisted in localStorage. ---- */
@media (max-width: 767.98px) {
    .dts-mobile-toggle { display: inline-flex; }
    .dts-sidebar {
        position: fixed; top: 0; left: 0; height: 100%; width: 268px; z-index: 1050;
        transform: translateX(-100%); transition: transform .2s ease; box-shadow: var(--shadow-lg);
    }
    .dts-shell.dts-mobile-nav-open .dts-sidebar { transform: translateX(0); }
    html.dts-sidebar-collapsed .dts-sidebar { width: 268px; }
    html.dts-sidebar-collapsed .dts-sidebar-header { justify-content: space-between; padding-left: 1.1rem; padding-right: 1.1rem; }
    html.dts-sidebar-collapsed .dts-sidebar-brand { width: auto; height: auto; justify-content: flex-start; background: none; }
    html.dts-sidebar-collapsed .dts-sidebar-brand-hint { display: none; }
    html.dts-sidebar-collapsed .dts-sidebar-brand span,
    html.dts-sidebar-collapsed .dts-nav span,
    html.dts-sidebar-collapsed .dts-sidebar-user-text,
    html.dts-sidebar-collapsed .dts-sidebar-logout span { display: inline; }
    html.dts-sidebar-collapsed .dts-nav .nav-link,
    html.dts-sidebar-collapsed .dts-nav-section-toggle,
    html.dts-sidebar-collapsed .dts-sidebar-logout { justify-content: flex-start; }
    html.dts-sidebar-collapsed .dts-nav-chevron { display: inline-block; }
    html.dts-sidebar-collapsed .dts-nav-section-items {
        position: static; opacity: 1; visibility: visible; transform: none; width: auto;
        background: transparent; border: none; box-shadow: none; padding: 0; max-height: 0;
    }
    html.dts-sidebar-collapsed .dts-nav-section.expanded .dts-nav-section-items { max-height: 600px; }
    .dts-sidebar-toggle { display: none; } /* desktop-only affordance */
}
.dts-mobile-backdrop {
    display: none; position: fixed; inset: 0; background: rgba(0,0,0,.5); z-index: 1040;
}
.dts-shell.dts-mobile-nav-open .dts-mobile-backdrop { display: block; }
@media (min-width: 768px) {
    .dts-mobile-backdrop { display: none !important; }
}

/* ---- theme toggle ---- */
.theme-toggle {
    display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px;
    border-radius: var(--radius-sm); border: 1px solid var(--border-strong); background: var(--surface-2);
    color: var(--text-muted); cursor: pointer; transition: background .12s ease, color .12s ease, box-shadow .12s ease;
}
.theme-toggle:hover { color: var(--accent); border-color: var(--accent); }
.theme-toggle:focus-visible { box-shadow: 0 0 0 3px var(--focus-ring); }
.theme-toggle .bi-sun-fill { display: none; }
[data-bs-theme="dark"] .theme-toggle .bi-moon-stars-fill { display: none; }
[data-bs-theme="dark"] .theme-toggle .bi-sun-fill { display: inline-block; }

/* ============================================================================
   Buttons (global override of every Bootstrap variant)
   ============================================================================ */
.btn {
    display: inline-flex; align-items: center; justify-content: center;
    font-family: var(--font-sans); font-weight: 600; font-size: .875rem; letter-spacing: .005em;
    line-height: 1.25; /* Bootstrap's default 1.5 body line-height was the real cause of "too tall"
                           buttons - padding alone looked reasonable, but a 1.5 line box under .875rem
                           text adds ~3-4px of dead vertical space on every button in the app. */
    border-radius: var(--radius-sm); padding: .44rem 1rem; border-width: 1px;
    transition: background-color .12s ease, border-color .12s ease, color .12s ease, box-shadow .12s ease, transform .08s ease;
}
.btn-sm { border-radius: var(--radius-xs); padding: .28rem .7rem; font-size: .8rem; line-height: 1.2; }
.btn-lg { border-radius: var(--radius-md); padding: .62rem 1.3rem; font-size: .95rem; }
.btn:focus-visible { box-shadow: 0 0 0 3px var(--focus-ring) !important; }
.btn:active { transform: translateY(1px); }

.btn-primary, .btn-success, .btn-danger, .btn-warning, .btn-info, .btn-secondary, .btn-dark {
    box-shadow: var(--press-shadow);
}
.btn-primary:active, .btn-success:active, .btn-danger:active, .btn-warning:active,
.btn-info:active, .btn-secondary:active, .btn-dark:active { box-shadow: 0 0 0 rgba(0,0,0,0); }

.btn-primary {
    background: var(--accent); border-color: var(--accent); color: var(--accent-ink);
}
.btn-primary:hover, .btn-primary:focus { background: var(--accent-hover); border-color: var(--accent-hover); color: var(--accent-ink); }
.btn-primary:active { background: var(--accent-active); border-color: var(--accent-active); }

.btn-outline-primary { color: var(--accent); border-color: var(--accent); background: transparent; }
.btn-outline-primary:hover { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }

/* Deliveries Table view's Container Actions column - "flag as dwelling" button (see
   _TableViewBody.cshtml). Explicit violet, independent of this app's monochrome --accent
   (.btn-primary above) - it needs to read as its own distinct action, not blend in with the
   ordinary black/white buttons around it. Same no-fill-until-hover shape as .btn-outline-info
   (Monitor Temps) above, just its own color. */
.btn-cer-flag { background: transparent; border-color: #7c3aed; color: #7c3aed; }
.btn-cer-flag:hover, .btn-cer-flag:focus { background: #7c3aed; border-color: #7c3aed; color: #fff; }

.btn-secondary { background: var(--surface-3); border-color: var(--border-strong); color: var(--text); }
.btn-secondary:hover { background: var(--border-strong); border-color: var(--border-strong); color: var(--text); }
.btn-outline-secondary { color: var(--text-muted); border-color: var(--border-strong); background: transparent; }
.btn-outline-secondary:hover { background: var(--surface-3); border-color: var(--border-strong); color: var(--text); }
.btn-outline-secondary.active, .btn-check:checked + .btn-outline-secondary {
    background: var(--accent); border-color: var(--accent); color: var(--accent-ink);
}

/* "Pop" treatment for the one primary call-to-action per screen (e.g. "New Delivery") - stays the
   same brand accent color rather than a one-off hue, so it reads as "the important button" without
   breaking the rest of the app's color consistency. Sits slightly raised even at rest, lifts
   further on hover. */
.btn-cta {
    font-weight: 700;
    box-shadow: var(--press-shadow);
    transition: transform .15s ease, box-shadow .15s ease, background-color .12s ease, border-color .12s ease;
}
.btn-cta:hover { transform: translateY(-1px); }
.btn-cta:active { transform: translateY(0); }

.btn-success { background: var(--success); border-color: var(--success); color: #fff; }
.btn-success:hover { filter: brightness(.92); }
.btn-outline-success { color: var(--success); border-color: var(--success); }
.btn-outline-success:hover { background: var(--success); border-color: var(--success); color: #fff; }

.btn-danger { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn-danger:hover { filter: brightness(.92); }
.btn-outline-danger { color: var(--danger); border-color: var(--danger); }
.btn-outline-danger:hover { background: var(--danger); border-color: var(--danger); color: #fff; }

.btn-warning { background: var(--warning); border-color: var(--warning); color: #fff; }
.btn-warning:hover { filter: brightness(.92); }
.btn-outline-warning { color: var(--warning); border-color: var(--warning); }
.btn-outline-warning:hover { background: var(--warning); border-color: var(--warning); color: #fff; }

.btn-info { background: var(--info); border-color: var(--info); color: #fff; }
.btn-outline-info { color: var(--info); border-color: var(--info); }
.btn-outline-info:hover { background: var(--info); border-color: var(--info); color: #fff; }

.btn-light { background: var(--surface-2); border-color: var(--border); color: var(--text); }
.btn-close { opacity: .6; }
[data-bs-theme="dark"] .btn-close { filter: invert(1) grayscale(100%) brightness(1.7); }

.icon-btn {
    display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px;
    border-radius: var(--radius-xs); color: var(--text-muted); border: none; background: transparent; text-decoration: none;
    transition: background .12s ease, color .12s ease;
}
.icon-btn:hover { background: var(--surface-3); color: var(--accent); }
.icon-btn.icon-btn-danger:hover { background: var(--danger-soft); color: var(--danger); }

/* ============================================================================
   Filter bar - compact toolbar of search/dropdowns/toggle-chips above a data grid
   ============================================================================ */
.filter-bar {
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-md);
    padding: .5rem .6rem; box-shadow: var(--shadow-sm);
}
.filter-bar .form-control, .filter-bar .form-select { font-size: .82rem; }

.filter-search { position: relative; }
.filter-search .bi { position: absolute; left: .65rem; top: 50%; transform: translateY(-50%); color: var(--text-faint); font-size: .8rem; pointer-events: none; }
.filter-search input { padding-left: 1.85rem; }

/* Checkbox filters rendered as compact toggle pills instead of checkbox+label, so they read as
   part of the same toolbar rather than a separate form section. */
.filter-chip {
    display: inline-flex; align-items: center; gap: .4rem; padding: .32rem .75rem;
    border-radius: var(--radius-pill); border: 1px solid var(--border-strong); background: var(--surface-2);
    font-size: .78rem; font-weight: 600; color: var(--text-muted); cursor: pointer; user-select: none;
    transition: background .12s ease, border-color .12s ease, color .12s ease;
}
.filter-chip input { position: absolute; opacity: 0; width: 0; height: 0; }
.filter-chip:hover { background: var(--surface-3); }
.filter-chip:has(input:checked) { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.filter-chip .bi { font-size: .75rem; }

/* A chip rendered outside a picker modal to show one already-selected item (e.g. Import Upload's
   match-key fields) - same look as .filter-chip but never toggles, so no :has(input:checked)
   state applies; the trailing icon is its own click target for removal. */
.selected-key-chip { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); cursor: default; }
.selected-key-chip .bi-x-lg:hover { color: var(--danger); }

/* Scoped scroll container for a picker modal's field list, which can run 50+ items long for a
   consignee with a large booking template - without this the modal grows past the viewport. */
.key-picker-body { max-height: 55vh; overflow-y: auto; }

/* ============================================================================
   Forms
   ============================================================================ */
.form-control, .form-select {
    background: var(--surface-2); border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
    color: var(--text); box-shadow: inset 0 1px 2px rgba(20, 30, 45, .05);
    font-size: .875rem;
}
.form-control:focus, .form-select:focus {
    background: var(--surface); border-color: var(--accent); color: var(--text);
    box-shadow: inset 0 1px 2px rgba(20, 30, 45, .04), 0 0 0 3px var(--focus-ring);
}
.form-control::placeholder { color: var(--text-faint); }
.form-control:disabled, .form-select:disabled { background: var(--surface-3); color: var(--text-muted); }
.form-label { font-weight: 600; font-size: .82rem; color: var(--text); margin-bottom: .3rem; }
.form-check-input { background-color: var(--surface-2); border-color: var(--border-strong); }
.form-check-input:checked { background-color: var(--accent); border-color: var(--accent); }
.form-check-input:focus { box-shadow: 0 0 0 3px var(--focus-ring); border-color: var(--accent); }
.form-switch .form-check-input:checked { background-color: var(--accent); }
.input-group-text { background: var(--surface-3); border-color: var(--border-strong); color: var(--text-muted); }

/* ============================================================================
   Cards / panels
   ============================================================================ */
.card {
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md); color: var(--text);
}
.card-header, .card-footer { background: var(--surface-2); border-color: var(--border); }
.kpi-card { transition: transform .16s cubic-bezier(.2,.8,.3,1.1), box-shadow .16s ease; }
.kpi-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-lg); }
.kpi-value { font-family: var(--font-mono); font-size: 1.9rem; font-weight: 700; color: var(--text); }
.kpi-label { font-family: var(--font-mono); color: var(--text-muted); font-size: .74rem; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; }

/* Rate Builder (Views/Rates/Details.cshtml) - numbered step badge before each of the 4 section
   headings, and the prominent Final Price callout closing section 4. */
.rb-step {
    display: inline-flex; align-items: center; justify-content: center; width: 1.5em; height: 1.5em;
    border-radius: 50%; background: var(--accent-soft); color: var(--accent); font-size: .75rem;
    font-weight: 800; margin-right: .4rem; vertical-align: middle;
}
.rb-final-price {
    background: color-mix(in srgb, var(--accent) 12%, var(--surface)); border: 1px solid var(--accent);
    border-radius: var(--radius-md); padding: .9rem 1rem; text-align: center; color: var(--accent);
}
.rb-final-price-value { font-family: var(--font-mono); font-size: 1.9rem; font-weight: 800; letter-spacing: -.01em; }

/* Fixed-height chart containers - Chart.js's own responsive sizing otherwise lets a doughnut
   (default aspect ratio 1:1) grow to fill its column's full width, dwarfing a bar chart in the
   next column. maintainAspectRatio:false (set in the chart options) + a capped-height wrapper
   keeps both charts in a row visually balanced regardless of column width. */
.chart-box { position: relative; height: 220px; }
.chart-box-donut { max-width: 360px; margin: 0 auto; }



/* ============================================================================
   Tables (global - no wrapper class required)
   ============================================================================ */
table.table { color: var(--text); font-size: .87rem; --bs-table-bg: transparent; }
table.table thead th, .table-light {
    --bs-table-bg: var(--surface-2); --bs-table-color: var(--text-muted);
    font-family: var(--font-mono); font-size: .69rem; text-transform: uppercase;
    letter-spacing: .05em; font-weight: 700; border-bottom: 1px solid var(--border-strong) !important;
    vertical-align: middle;
}
table.table td, table.table th { border-color: var(--border); vertical-align: middle; }
table.table > tbody > tr:hover > * { --bs-table-accent-bg: var(--surface-2); }
.table-danger { --bs-table-bg: var(--danger-soft); --bs-table-color: var(--text); }
.table-responsive { border-radius: var(--radius-md); }

/* ============================================================================
   Badges / status pills / LED
   ============================================================================ */
.badge { font-weight: 600; border-radius: var(--radius-xs); font-size: .72rem; letter-spacing: .01em; padding: .38em .6em; }
.badge.bg-light { --bs-bg-opacity: 1; background-color: var(--surface-3) !important; color: var(--text) !important; }
.badge.border { border-color: var(--border-strong) !important; }

.badge-status { padding: .35em .7em; border-radius: var(--radius-xs); font-weight: 700; color: #fff; font-family: var(--font-mono); letter-spacing: .02em; }

.pill {
    display: inline-flex; align-items: center; gap: .4rem; padding: .3rem .75rem;
    border-radius: var(--radius-pill); font-size: .78rem; font-weight: 600; white-space: nowrap;
    background: color-mix(in srgb, var(--c, #6c757d) 16%, var(--surface));
    color: color-mix(in srgb, var(--c, #6c757d) 60%, var(--text));
}
.pill .dot { width: .4rem; height: .4rem; border-radius: 50%; background: var(--c, #6c757d); flex: none; }

.pill-blue, .pill-blue .dot { background: var(--info-soft); color: var(--info); }
.pill-blue .dot { background: var(--info); }
.pill-gray { background: var(--surface-3); color: var(--text-muted); }
.pill-gray .dot { background: var(--text-muted); }
.pill-green { background: var(--success-soft); color: var(--success); }
.pill-green .dot { background: var(--success); }
.pill-amber { background: var(--warning-soft); color: var(--warning); }
.pill-amber .dot { background: var(--warning); }
.pill-red { background: var(--danger-soft); color: var(--danger); }
.pill-red .dot { background: var(--danger); }

/* Container Empty Return's Status badge (Views/ContainerEmptyReturn) - subtle per-status tint via
   --c (see ContainerEmptyReturn.StatusColorHex), same color-mix technique as .pill above. Display-
   only (a plain <span>, not a button) - editing status is a separate "Edit" icon-button beside it,
   see .js-cer-status-btn in Index.cshtml/Details.cshtml. */
.cer-status-btn {
    display: inline-flex; align-items: center; justify-content: center;
    padding: .3rem .7rem; border-radius: var(--radius-pill); font-size: .78rem;
    border: 1px solid color-mix(in srgb, var(--c, #6c757d) 45%, transparent);
    background: color-mix(in srgb, var(--c, #6c757d) 14%, var(--surface));
    color: color-mix(in srgb, var(--c, #6c757d) 70%, var(--text));
    font-weight: 700; white-space: nowrap;
}

.led-dot { display: inline-block; width: .55rem; height: .55rem; border-radius: 50%; margin-right: .45rem; vertical-align: 1px; }
.led-dot.led-green { background: var(--success); }
.led-dot.led-amber { background: var(--warning); }
.led-dot.led-red { background: var(--danger); }

.ball-row.overdue { background: var(--danger-soft) !important; }
.ball-row.on-hold { background: var(--warning-soft) !important; }

/* ============================================================================
   Timeline
   ============================================================================ */
.timeline { list-style: none; padding-left: 0; }
.timeline li { position: relative; padding-left: 2rem; padding-bottom: 1.25rem; border-left: 2px solid var(--border); margin-left: .6rem; }
.timeline li:last-child { border-left-color: transparent; }
.timeline li::before { content: ''; position: absolute; left: -7px; top: 2px; width: 12px; height: 12px; border-radius: 50%; background: var(--border-strong); }
.timeline li.completed::before { background: var(--success); }
.timeline li.overdue::before { background: var(--danger); }
.timeline li.in-progress::before { background: var(--accent); }

/* ============================================================================
   Nav tabs / pills / list-group / alerts / modal / dropdown
   (Bootstrap's own [data-bs-theme=dark] vars cover most of the base look;
   these add the brand accent + shape consistency on top.)
   ============================================================================ */
.nav-tabs { border-bottom-color: var(--border); }
.nav-tabs .nav-link { color: var(--text-muted); border: none; border-bottom: 2px solid transparent; font-weight: 600; font-size: .87rem; }
.nav-tabs .nav-link:hover { color: var(--text); border-color: var(--border-strong); }
.nav-tabs .nav-link.active { color: var(--accent); background: transparent; border-color: var(--accent); }

.nav-pills .nav-link { color: var(--text-muted); border-radius: var(--radius-sm); font-weight: 600; font-size: .87rem; }
.nav-pills .nav-link.active { background: var(--accent); color: var(--accent-ink); }

.list-group-item { background: var(--surface); border-color: var(--border); color: var(--text); }

.alert { border-radius: var(--radius-md); border-width: 1px; }
.alert-success { background: var(--success-soft); border-color: var(--success); color: var(--success); }
.alert-danger { background: var(--danger-soft); border-color: var(--danger); color: var(--danger); }
.alert-warning { background: var(--warning-soft); border-color: var(--warning); color: var(--warning); }
.alert-info { background: var(--info-soft); border-color: var(--info); color: var(--info); }

.modal-content { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); }
.modal-header, .modal-footer { border-color: var(--border); }

.dropdown-menu { background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow-md); border-radius: var(--radius-sm); }
.dropdown-item { color: var(--text); }
.dropdown-item:hover, .dropdown-item:focus { background: var(--surface-2); color: var(--text); }

/* A .kpi-card's hover-lift `transform` (see .kpi-card:hover below) creates a new stacking context
   the instant the pointer is over anything inside it - including an open dropdown-menu, since
   :hover matches every ancestor of whatever the pointer is actually over. That traps the dropdown
   (position:absolute, z-index:1000) inside the card's own stacking context, so a later-in-DOM
   sibling (e.g. the price grid below the Regions card on Fuel Price Management) paints on top of
   it despite the dropdown's much higher z-index. Suppressing the lift while a dropdown inside the
   card is open keeps the card from creating that trap in the first place.
   transition:none is required alongside transform:none - otherwise the card was still hover-lifted
   at the moment the dropdown opened (hovering the toggle button already counts as hovering the
   card), so this rule's transform:none would itself animate back to flat over kpi-card's own
   .16s transition. A "transform other than none" persists as the stacking-context trigger for the
   full duration of that animation, so the dropdown stayed trapped behind the table below for that
   whole .16s before popping in front - visible as a jarring flash-then-appear on open. */
.kpi-card:has(.dropdown-menu.show) { transform: none; transition: none; }

/* Regions picker (Fuel Price Management) - a checkbox list styled as a combobox, replacing a plain
   .dropdown-item-text row so each row gets real left/right breathing room instead of sitting flush
   against the menu's edge. */
.region-picker { overflow: hidden; }
.region-picker-header {
    padding: .55rem .9rem .4rem; font-family: var(--font-mono); font-size: .68rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: .05em; color: var(--text-muted);
}
.region-picker-item {
    display: flex; align-items: center; gap: .65rem; margin: 0; padding: .5rem .9rem;
    font-size: .86rem; color: var(--text); cursor: pointer;
}
.region-picker-item:hover { background: var(--surface-2); }
.region-picker-item .form-check-input { margin: 0; flex-shrink: 0; cursor: pointer; }
.region-picker-add { padding: .5rem .9rem .6rem; }

.progress { background: var(--surface-3); border-radius: var(--radius-pill); overflow: hidden; }
.progress-bar { background: var(--accent); transition: width .3s ease; }

/* ============================================================================
   Login
   ============================================================================ */
.login-wrapper {
    /* flex-direction:column so the brand block (.text-center.mb-3) stacks above the card, per the
       markup order in Login.cshtml, instead of the flex default of row placing them side by side. */
    min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center;
    background: var(--chassis-bg);
    position: relative;
}
.login-brand {
    display: inline-flex; align-items: center; font-weight: 800; color: #fff; letter-spacing: -.01em;
    font-size: 1.6rem; margin-bottom: .25rem;
}
.login-logo { height: 40px; width: 40px; object-fit: contain; margin-right: .5rem; border-radius: 8px; }
.login-eyebrow { font-size: .78rem; letter-spacing: .02em; color: var(--chassis-text); text-transform: uppercase; }
.login-card {
    width: 400px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
    padding: 2rem; box-shadow: var(--shadow-lg);
    position: relative; z-index: 1;
}
.login-footnote { font-size: .78rem; color: var(--text-faint); }

/* ============================================================================
   Import preview grid + list-table (retokenized, no wrapper class required)
   ============================================================================ */
.sp-toolbar {
    display: flex; align-items: center; gap: 1.1rem; flex-wrap: wrap;
    padding: .8rem 1.1rem; background: var(--surface); border: 1px solid var(--border); border-bottom: none;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}
.sp-toolbar .form-control, .sp-toolbar .form-select { font-size: .82rem; }

.sp-pill { display: inline-flex; align-items: center; gap: .35rem; padding: .3rem .7rem; border-radius: var(--radius-pill); font-size: .78rem; font-weight: 600; line-height: 1; }
.sp-pill-new { background: var(--success-soft); color: var(--success); }
.sp-pill-update { background: var(--info-soft); color: var(--info); }
.sp-pill-warn { background: var(--warning-soft); color: var(--warning); }
.sp-pill-muted { background: var(--surface-3); color: var(--text-muted); }

.sp-table-frame {
    border: 1px solid var(--border); border-top: none; border-radius: 0 0 var(--radius-lg) var(--radius-lg);
    box-shadow: var(--shadow-md); overflow: hidden; background: var(--surface);
}
.sp-grid-wrapper { max-height: 68vh; overflow: auto; }

.sp-grid { border-collapse: separate; border-spacing: 0; font-size: .84rem; width: max-content; min-width: 100%; color: var(--text); }
.sp-grid th, .sp-grid td { padding: .6rem .95rem; white-space: nowrap; font-variant-numeric: tabular-nums; border-bottom: 1px solid var(--border); }
.sp-grid tbody tr:last-child td { border-bottom: none; }
.sp-grid tbody tr:nth-child(even) td { background: color-mix(in srgb, var(--surface-2) 45%, var(--surface)); }

/* isolation alone gives the sticky header/column their own stacking context (cheap, no known
   side effects). The more aggressive "force a GPU layer" trick - will-change/transform/
   backface-visibility - was tried here too, but it turned out to be solving the wrong problem
   (the actual "see-through" bug was a genuinely translucent background color, fixed at its
   required-col rule below) and instead introduced a NEW visual bug: a clipped/torn-looking bar at
   the sticky column's edge while scrolling, from the promoted layer's tile boundary not lining up
   with the row underneath. Don't re-add it without a concrete symptom that needs it. */
.sp-grid thead th, .sp-grid .sp-sticky-col {
    isolation: isolate;
}

.sp-grid thead {
    background: var(--surface-2); /* backstop behind the th's own background at the row-group level */
}
.sp-grid thead th {
    position: sticky; top: 0; background: var(--surface-2); color: var(--text-muted); font-weight: 700;
    font-size: .68rem; text-transform: uppercase; letter-spacing: .05em; font-family: var(--font-mono);
    z-index: 2; text-align: left; user-select: none;
    border-bottom: 1px solid var(--border-strong);
    box-shadow: 0 1px 0 var(--border-strong), 0 8px 12px -8px rgba(0, 0, 0, .18);
}
/* .sp-field-row's top:30px below only applies when it's actually stacked under a .sp-group-row
   (Import Preview's two-tier header). A single-row header table (Deliveries table view) must NOT
   use the sp-field-row class, or its header sticks 30px too low - leaving a gap the scrolling body
   shows through. */
.sp-grid thead tr.sp-group-row th {
    top: 0; height: 34px; background: var(--surface-3); color: var(--section-label); font-weight: 800;
    font-size: .64rem; letter-spacing: .06em; border-bottom: 1px solid var(--border-strong); box-shadow: none;
}
/* Must match .sp-group-row's actual height above, or the field-row header sticks at the wrong
   offset and the two rows overlap/gap - see the earlier colspan+sticky misalignment bug. */
.sp-grid thead tr.sp-field-row th { top: 34px; }
/* Must be fully opaque, unlike most "-soft" tokens - this cell is position:sticky, so a
   translucent background blends with whatever's scrolling underneath it during compositing, not
   just a solid backdrop. That's exactly what reads as "still see-through." color-mix produces an
   opaque tint instead. */
.sp-grid thead tr.sp-field-row th.required-col { background: color-mix(in srgb, var(--accent) 14%, var(--surface-2)); }
.sp-grid thead th.sortable { cursor: pointer; transition: background .12s ease, color .12s ease; }
.sp-grid thead th.sortable:hover { background: var(--surface-3); color: var(--text); }
.sp-grid thead th .sort-arrow { display: inline-block; width: .9em; font-size: .6rem; color: var(--accent); opacity: .85; }

.sp-grid tbody tr { transition: background-color .1s ease; }
.sp-grid tbody tr:hover td { background: var(--surface-2) !important; }

.sp-grid .sp-sticky-col { position: sticky; left: 0; background: var(--surface); z-index: 1; min-width: 168px; box-shadow: 1px 0 0 var(--border); font-weight: 600; }
.sp-grid tbody tr:nth-child(even) td.sp-sticky-col { background: color-mix(in srgb, var(--surface-2) 45%, var(--surface)); }
.sp-grid thead .sp-sticky-col { z-index: 3; background: var(--surface-2); }
.sp-grid thead tr.sp-group-row .sp-sticky-col { background: var(--surface-3); }
.sp-grid tbody tr:hover td.sp-sticky-col { background: var(--surface-2) !important; }

.sp-grid td.text-end, .sp-grid th.text-end { text-align: right; }
.sp-grid td.text-center, .sp-grid th.text-center { text-align: center; }

/* Marks the first column of each per-region column group (Fuel Price Management) with a thin
   rule, so the eye can tell where one region's columns end and the next begins at a glance. */
.sp-grid .region-sep { border-left: 1px solid var(--border-strong); }

/* ============================================================================
   Table view: Excel/SharePoint-Grid-View-style inline cell editing (Deliveries
   Table view - see the grid-cell-* JS block in Views/Deliveries/Index.cshtml)
   ============================================================================ */
/* Deliberately NOT raising z-index on any of these states (active/editing/saving) above 0 - the
   sticky Tracking # column sits at z-index:1 specifically so it stays opaque and on top while
   scrolled-under content passes underneath it. An editable cell that happens to be scrolled to a
   position currently hidden behind that sticky column would otherwise "win" the stacking fight
   whenever it became active/editing/saving (its own z-index being higher), bleeding its text
   through on top of the sticky column instead of staying correctly hidden behind it - exactly the
   overlapping-text bug this was fixed for. Everything below relies purely on paint/DOM order
   (later siblings and absolutely-positioned children already paint above earlier ones) instead.
   Editing is also gated behind .grid-edit-mode on the grid itself (see the toolbar toggle) - all
   of these selectors are scoped under it so a read-only grid never shows any of this styling. */
.sp-grid.grid-edit-mode td.grid-cell { cursor: cell; position: relative; outline: none; }
.sp-grid.grid-edit-mode td.grid-cell:hover { box-shadow: inset 0 0 0 1px var(--border-strong); }
.sp-grid.grid-edit-mode td.grid-cell.grid-active { box-shadow: inset 0 0 0 2px var(--accent); }
.sp-grid.grid-edit-mode td.grid-cell.grid-editing { padding: 0; box-shadow: inset 0 0 0 2px var(--accent); }
.sp-grid.grid-edit-mode td.grid-cell.grid-editing .grid-cell-display { visibility: hidden; }
.sp-grid.grid-edit-mode td.grid-cell .grid-cell-editor {
    position: absolute; inset: 0; width: 100%; height: 100%; border: none; border-radius: 0;
    font: inherit; padding: .6rem .95rem; background: var(--surface); color: var(--text);
}
.sp-grid.grid-edit-mode td.grid-cell .grid-cell-editor:focus { outline: none; }
/* Small spinner in the corner while a cell's save request is in flight. */
.sp-grid.grid-edit-mode td.grid-cell.grid-saving::after {
    content: ''; position: absolute; top: .3rem; right: .3rem; width: .55rem; height: .55rem;
    border-radius: 50%; border: 2px solid var(--accent); border-top-color: transparent;
    animation: grid-cell-spin .6s linear infinite;
}
@keyframes grid-cell-spin { to { transform: rotate(360deg); } }
.sp-grid.grid-edit-mode td.grid-cell.grid-save-success { box-shadow: inset 0 0 0 2px var(--success); transition: box-shadow .5s ease .15s; }

/* Action-item cells (🚨 - see DeliveryTableRow.ActionItem) - a tinted background scoped to just
   that cell, not the whole row/column, so a delivery with one bad field is easy to spot without
   the rest of its row competing for attention. Deliberately NOT scoped under .grid-edit-mode -
   the tint and 🚨 need to be visible (and clickable, see Index.cshtml) whether or not the grid is
   currently in edit mode, since clicking 🚨 is what turns edit mode on in the first place. */
.sp-grid td.grid-cell.has-action-item { background: var(--warning-soft); }
/* .sp-grid tbody tr:hover td (below) sets every cell in a hovered row to a flat neutral
   background via !important - without this override, hovering ANYWHERE in an action-item cell's
   row (not just that cell) would blank out its orange tint instead of just its own plain hover
   highlight. Extra specificity (.grid-cell.has-action-item on top of tr:hover td) beats that rule
   outright, so !important vs !important comes down to specificity, not source order. */
.sp-grid tbody tr:hover td.grid-cell.has-action-item { background: var(--warning-soft-strong) !important; }
.sp-grid td.grid-cell .grid-cell-alert,
.sp-grid td.grid-cell .grid-cell-reactivate { cursor: pointer; }
.sp-grid.grid-edit-mode td.grid-cell.grid-save-error { box-shadow: inset 0 0 0 2px var(--danger); }
/* Press-and-drag (or shift-click) multi-cell range, Excel/SharePoint-style - a plain tint across
   every selected cell, with .grid-active's own border still marking the anchor cell within it.
   !important beats the even-row zebra-striping background, which would otherwise win by source
   order for every other row in the range. Deliberately background-COLOR, not the `background`
   shorthand - the shorthand resets background-image too, which would blank out .grid-copied's
   marching-ants pattern below on any cell that's both selected and copied at once. */
.sp-grid.grid-edit-mode td.grid-cell.grid-range-selected { background-color: var(--accent-soft) !important; }

/* "Marching ants" copied-selection indicator (Ctrl/Cmd+C - see copySelectionToClipboard/
   markAsCopied). Four linear-gradient layers, one per edge, each a repeating dash pattern;
   animating their background-position makes the dashes appear to travel along each edge - the
   classic spreadsheet "your clipboard has this" cue. Uses --info specifically so it reads as a
   different state from the accent-colored active-cell border and range tint, not a variation of
   either. Applied uniformly to every copied cell (not perimeter-only) - on an interior shared
   edge between two copied cells the two travelling lines simply overlap, which still reads
   clearly as "this whole block is what's copied" without needing to compute which edges of an
   arbitrary rectangle are actually on its outside. */
.sp-grid.grid-edit-mode td.grid-cell.grid-copied {
    background-image:
        linear-gradient(90deg, var(--info) 50%, transparent 50%),
        linear-gradient(90deg, var(--info) 50%, transparent 50%),
        linear-gradient(0deg, var(--info) 50%, transparent 50%),
        linear-gradient(0deg, var(--info) 50%, transparent 50%);
    background-repeat: repeat-x, repeat-x, repeat-y, repeat-y;
    background-size: 10px 2px, 10px 2px, 2px 10px, 2px 10px;
    background-position: 0 0, 0 100%, 0 0, 100% 0;
    animation: grid-copy-marquee .5s linear infinite;
}
@keyframes grid-copy-marquee {
    to { background-position: 10px 0, -10px 100%, 0 -10px, 100% 10px; }
}
/* The active/anchor cell normally shows .grid-active's solid box-shadow border instead of the
   marching ants above - box-shadow always paints after backgrounds, so it was silently covering
   the exact few-pixel band the dashes live in, making the anchor cell look like it had no copy
   indicator at all. Rather than layer two competing borders, drop the box-shadow here and make
   THIS cell's marching ants thicker instead (3px bars vs. the plain 2px elsewhere) - keeps the
   anchor visibly distinct from the rest of the copied range without hiding either indicator.
   Same 10px repeat length as the base rule, so it reuses the exact same @keyframes above with no
   seam in the animation. */
.sp-grid.grid-edit-mode td.grid-cell.grid-active.grid-copied {
    box-shadow: none;
    background-size: 10px 3px, 10px 3px, 3px 10px, 3px 10px;
}
/* Same box-shadow-paints-over-backgrounds issue, triggered a different way: the plain :hover
   rule above (border-strong outline) was covering the marching ants the instant the pointer sat
   over a copied cell, making them seem to "disappear on hover." Rather than fight the paint
   order again, embrace it as an explicit hover state - a solid --info border (same color as the
   dashes, just not animated) reads as "still copied, now also hovered," not as the indicator
   failing. Higher specificity than the plain :hover rule (one more class), so no !important
   needed; the active-cell variant gets one more pixel of weight, consistent with it already
   being the thicker/heavier version everywhere else this state shows up. */
.sp-grid.grid-edit-mode td.grid-cell.grid-copied:hover { box-shadow: inset 0 0 0 2px var(--info); }
.sp-grid.grid-edit-mode td.grid-cell.grid-active.grid-copied:hover { box-shadow: inset 0 0 0 3px var(--info); }

.sp-flag-dot { display: inline-block; width: .4rem; height: .4rem; border-radius: 50%; margin-right: .45rem; vertical-align: 1px; }
.cell-missing { background: var(--danger-soft); color: var(--danger); }
.cell-missing .sp-flag-dot { background: var(--danger); }
.cell-unmatched { background: var(--warning-soft); color: var(--warning); }
.cell-unmatched .sp-flag-dot { background: var(--warning); }
.cell-unparseable { background: var(--info-soft); color: var(--info); }
.cell-unparseable .sp-flag-dot { background: var(--info); }

.sp-legend { display: flex; gap: 1.15rem; align-items: center; font-size: .76rem; color: var(--text-muted); }
.sp-legend .swatch { display: inline-block; width: .55rem; height: .55rem; border-radius: 50%; margin-right: .35rem; }

.list-table-wrap { background: var(--surface); border-radius: var(--radius-lg); border: 1px solid var(--border); overflow: hidden; box-shadow: var(--shadow-sm); }
/* Pairs with .sp-toolbar directly above it (same pattern as .sp-table-frame + .sp-grid-wrapper in
   the Table view) - squares off the top corners/border so the toolbar and table read as one
   seamless unit instead of two separately-rounded boxes with a gap between them. */
.list-table-wrap.has-toolbar { border-top: none; border-radius: 0 0 var(--radius-lg) var(--radius-lg); }
/* Caps the table at a viewport-relative height with its OWN scrollbar, instead of a long list
   (e.g. hundreds of deliveries) pushing the whole page tall and making you scroll past the
   sidebar/topbar just to see more rows. Targets the .table-responsive wrapper that's already
   nested inside .list-table-wrap wherever this component is used, rather than requiring a new
   element in every view. */
.list-table-wrap .table-responsive { max-height: 68vh; overflow-y: auto; }
.list-table { width: 100%; border-collapse: collapse; font-size: .86rem; margin: 0; color: var(--text); }
.list-table thead th {
    position: sticky; top: 0; z-index: 1;
    background: var(--surface-2); color: var(--text-muted); font-weight: 700; font-size: .69rem; text-transform: uppercase;
    letter-spacing: .05em; font-family: var(--font-mono); padding: .85rem 1.1rem; border-bottom: 1px solid var(--border-strong); text-align: left; white-space: nowrap;
}
.list-table tbody td { padding: .85rem 1.1rem; border-bottom: 1px solid var(--border); vertical-align: middle; color: var(--text); }
.list-table tbody tr:last-child td { border-bottom: none; }
.list-table tbody tr:hover td { background: var(--surface-2); }

/* ---- .ind-theme / .list-theme now no-op aliases: everything above is already global ---- */
.ind-theme, .list-theme { background: transparent; padding: 0; border-radius: 0; color: inherit; font-family: inherit; }
