/*
 * Zagel Admin — 2026 design system
 * -------------------------------------------------------------------------
 * A refined, atomic system inspired by Linear / Stripe / shadcn-ui, layered
 * on top of Bootstrap 5 primitives (no build step required).
 *
 *   Primary   : Indigo-600 (#4F46E5)
 *   Neutrals  : Slate (backgrounds, borders, text)
 *   Surfaces  : white cards on a slate-50 page
 *   Elevation : thin 1px slate borders; soft shadows reserved for overlays
 *   Radii     : 8px (sm) inputs/buttons · 12px (md) cards/containers
 *   Type      : Inter / Geist for UI · JetBrains Mono for code + technical data
 *
 * The class names from the previous skin are all preserved, so existing views
 * inherit the new look without markup changes. A dark "Midnight" theme ships
 * behind [data-theme="dark"].
 * ------------------------------------------------------------------------- */

/* ========================================================================
   1. Design tokens
   ======================================================================== */
:root {
  /* Brand / primary — Indigo. A deployment's ZagelBranding colours override every
     --z-primary* / --z-on-primary token below (see _BrandHead.cshtml), so brand-coloured
     rules must use these tokens, never literal values. */
  --z-primary: #4f46e5;        /* indigo-600 */
  --z-primary-hover: #4338ca;  /* indigo-700 */
  --z-primary-active: #3730a3; /* indigo-800 */
  --z-primary-soft: #eef2ff;   /* indigo-50  */
  --z-primary-ring: rgba(79, 70, 229, .35);
  --z-primary-rgb: 79, 70, 229;
  --z-primary-accent: #7c73ff;        /* second gradient stop */
  --z-primary-accent-rgb: 124, 115, 255;
  --z-primary-deep-rgb: 55, 48, 163;  /* indigo-800, login backdrop on dark */
  --z-on-primary: #ffffff;            /* text on filled brand surfaces */

  /* Slate neutrals */
  --z-slate-50:  #f8fafc;
  --z-slate-100: #f1f5f9;
  --z-slate-200: #e2e8f0;
  --z-slate-300: #cbd5e1;
  --z-slate-400: #94a3b8;
  --z-slate-500: #64748b;
  --z-slate-600: #475569;
  --z-slate-700: #334155;
  --z-slate-800: #1e293b;
  --z-slate-900: #0f172a;

  /* Semantic */
  --z-success: #059669;  /* emerald-600 */
  --z-success-soft: #ecfdf5;
  --z-warning: #d97706;  /* amber-600  */
  --z-warning-soft: #fffbeb;
  --z-danger:  #e11d48;  /* rose-600   */
  --z-danger-soft: #fff1f2;
  --z-info:    #0284c7;  /* sky-600    */
  --z-info-soft: #f0f9ff;

  /* Roles */
  --z-bg: var(--z-slate-50);
  --z-surface: #ffffff;
  --z-surface-2: var(--z-slate-50);
  --z-border: var(--z-slate-200);
  --z-border-strong: var(--z-slate-300);
  --z-text: var(--z-slate-700);
  --z-text-muted: var(--z-slate-500);
  --z-heading: var(--z-slate-900);
  /* Theme-aware roles for what used to be raw slate values. The --z-slate-* scale is a
     fixed palette the dark theme does not touch, so components must not use it for text
     or fills directly: slate-100 hover fills and slate-600 labels vanish on Midnight. */
  --z-text-secondary: var(--z-slate-600);  /* labels, secondary data */
  --z-hover-bg: var(--z-slate-100);        /* hovered menu items, icon buttons */
  --z-fill: var(--z-slate-100);            /* neutral chips, tracks, tags */

  /* Sidebar / topbar (light "slim-to-wide" surfaces) */
  --z-sidebar-bg: #ffffff;
  --z-sidebar-border: var(--z-slate-200);
  --z-sidebar-text: var(--z-slate-500);
  --z-sidebar-text-active: var(--z-primary);
  --z-sidebar-hover-bg: var(--z-slate-100);
  --z-sidebar-active-bg: var(--z-primary-soft);
  --z-topbar-bg: #ffffff;
  --z-topbar-border: var(--z-slate-200);
  --z-topbar-text: var(--z-slate-700);

  /* Radius scale */
  --z-radius-sm: 8px;   /* inputs, buttons, badges */
  --z-radius-md: 12px;  /* cards, containers */
  --z-radius-lg: 16px;  /* auth card, large panels */

  /* Elevation — restrained; borders do the work, shadows only for overlays */
  --z-shadow-xs: 0 1px 2px rgba(15, 23, 42, .04);
  --z-shadow-sm: 0 1px 3px rgba(15, 23, 42, .06), 0 1px 2px rgba(15, 23, 42, .04);
  --z-shadow-soft: 0 2px 4px rgba(15, 23, 42, .06), 0 4px 12px rgba(15, 23, 42, .06);
  --z-shadow-pop: 0 10px 30px rgba(15, 23, 42, .12), 0 2px 8px rgba(15, 23, 42, .08);

  /* Type */
  --z-font-sans: "Inter", "Geist Sans", -apple-system, BlinkMacSystemFont,
                 "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --z-font-mono: "JetBrains Mono", "Geist Mono", ui-monospace, SFMono-Regular,
                 Menlo, Consolas, "Liberation Mono", monospace;

  --z-sidebar-w: 250px;
  --z-sidebar-w-slim: 72px;

  /* ---- Bootstrap variable bridge ---- */
  --bs-primary: var(--z-primary);
  --bs-primary-rgb: var(--z-primary-rgb);
  --bs-link-color: var(--z-primary);
  --bs-link-color-rgb: var(--z-primary-rgb);
  --bs-link-hover-color: var(--z-primary-hover);
  --bs-body-color: var(--z-text);
  --bs-body-bg: var(--z-bg);
  --bs-border-color: var(--z-border);
  --bs-border-radius: var(--z-radius-sm);
  --bs-border-radius-lg: var(--z-radius-md);
  --bs-body-font-family: var(--z-font-sans);
  --bs-font-monospace: var(--z-font-mono);
  --bs-emphasis-color: var(--z-heading);
}

/* ---- Midnight (dark) theme ---- */
[data-theme="dark"] {
  --z-primary: #6366f1;        /* indigo-500, brighter on dark */
  --z-primary-hover: #818cf8;
  --z-primary-active: #a5b4fc;
  --z-primary-soft: rgba(99, 102, 241, .16);
  --z-primary-ring: rgba(129, 140, 248, .4);
  --z-primary-rgb: 99, 102, 241;

  --z-bg: #0b1220;             /* deep navy */
  --z-surface: #111a2e;
  --z-surface-2: #0e1626;
  --z-border: #1e293b;
  --z-border-strong: #334155;
  --z-text: #cbd5e1;
  --z-text-muted: #94a3b8;
  --z-heading: #f1f5f9;
  --z-text-secondary: #cbd5e1;
  --z-hover-bg: rgba(255, 255, 255, .06);
  --z-fill: rgba(255, 255, 255, .06);

  --z-sidebar-bg: #0d1526;
  --z-sidebar-border: #1e293b;
  --z-sidebar-text: #94a3b8;
  --z-sidebar-text-active: var(--z-primary-active);
  --z-sidebar-hover-bg: rgba(255, 255, 255, .04);
  --z-sidebar-active-bg: var(--z-primary-soft);
  --z-topbar-bg: #0d1526;
  --z-topbar-border: #1e293b;
  --z-topbar-text: #e2e8f0;

  --z-success-soft: rgba(5, 150, 105, .16);
  --z-warning-soft: rgba(217, 119, 6, .16);
  --z-danger-soft: rgba(225, 29, 72, .16);
  --z-info-soft: rgba(2, 132, 199, .16);

  --z-shadow-xs: 0 1px 2px rgba(0, 0, 0, .4);
  --z-shadow-sm: 0 1px 3px rgba(0, 0, 0, .5);
  --z-shadow-soft: 0 4px 14px rgba(0, 0, 0, .5);
  --z-shadow-pop: 0 12px 34px rgba(0, 0, 0, .6);

  --bs-body-bg: var(--z-bg);
  --bs-body-color: var(--z-text);
  --bs-border-color: var(--z-border);
  --bs-emphasis-color: var(--z-heading);
  --bs-secondary-bg: var(--z-surface-2);
  --bs-tertiary-bg: var(--z-surface-2);
  /* .bg-body / .bg-body-secondary / .bg-body-tertiary read the -rgb forms, which
     data-bs-theme="dark" would otherwise set to Bootstrap's grey, off our navy palette. */
  --bs-body-bg-rgb: 11, 18, 32;
  --bs-secondary-bg-rgb: 14, 22, 38;
  --bs-tertiary-bg-rgb: 14, 22, 38;
  color-scheme: dark;
}

/* ========================================================================
   2. Base
   ======================================================================== */
body {
  font-family: var(--z-font-sans);
  background-color: var(--z-bg);
  color: var(--z-text);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-feature-settings: "cv11", "ss01";
  letter-spacing: -0.006em;
}

a { color: var(--z-primary); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--z-primary-hover); }

h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
  color: var(--z-heading);
  letter-spacing: -0.02em;
}

::selection { background: var(--z-primary-soft); color: var(--z-primary-active); }

/* Technical data — phone numbers, TIS, IDs, tokens */
.font-mono, .text-mono, code, kbd, samp, pre, .font-monospace {
  font-family: var(--z-font-mono);
  font-feature-settings: "zero", "ss01";
}
.text-mono { font-size: .875em; letter-spacing: -0.01em; }

/* ========================================================================
   3. Buttons & form controls
   ======================================================================== */
.btn {
  --bs-btn-border-radius: var(--z-radius-sm);
  font-weight: 500;
  letter-spacing: -0.01em;
}
.btn,
.form-control,
.form-select,
.form-check-input {
  transition: border-color .15s ease, box-shadow .15s ease,
              background-color .15s ease, color .15s ease, transform .08s ease;
}
.btn:active { transform: translateY(.5px); }

.btn-primary {
  --bs-btn-color: var(--z-on-primary);
  --bs-btn-hover-color: var(--z-on-primary);
  --bs-btn-active-color: var(--z-on-primary);
  --bs-btn-disabled-color: var(--z-on-primary);
  --bs-btn-bg: var(--z-primary);
  --bs-btn-border-color: var(--z-primary);
  --bs-btn-hover-bg: var(--z-primary-hover);
  --bs-btn-hover-border-color: var(--z-primary-hover);
  --bs-btn-active-bg: var(--z-primary-active);
  --bs-btn-active-border-color: var(--z-primary-active);
  --bs-btn-disabled-bg: var(--z-primary);
  --bs-btn-disabled-border-color: var(--z-primary);
  box-shadow: var(--z-shadow-xs);
}
.btn-outline-primary {
  --bs-btn-color: var(--z-primary);
  --bs-btn-border-color: var(--z-border-strong);
  --bs-btn-hover-bg: var(--z-primary-soft);
  --bs-btn-hover-color: var(--z-primary-hover);
  --bs-btn-hover-border-color: var(--z-primary);
  --bs-btn-active-bg: var(--z-primary-soft);
  --bs-btn-active-color: var(--z-primary-active);
  --bs-btn-active-border-color: var(--z-primary);
}

.form-control,
.form-select {
  border-radius: var(--z-radius-sm);
  border-color: var(--z-border);
  background-color: var(--z-surface);
  color: var(--z-text);
}
.form-control::placeholder { color: var(--z-slate-400); }
.form-control:focus,
.form-select:focus {
  border-color: var(--z-primary);
  box-shadow: 0 0 0 3px var(--z-primary-ring);
  background-color: var(--z-surface);
  color: var(--z-text);
}
.form-label { font-weight: 500; color: var(--z-text-secondary); font-size: .875rem; margin-bottom: .35rem; }

.form-check-input { border-color: var(--z-border-strong); }
.form-check-input:checked {
  background-color: var(--z-primary);
  border-color: var(--z-primary);
}
.form-check-input:focus {
  border-color: var(--z-primary);
  box-shadow: 0 0 0 3px var(--z-primary-ring);
}

.btn-icon {
  border: none;
  background: transparent;
  color: var(--z-text-muted);
  width: 2.25rem;
  height: 2.25rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--z-radius-sm);
}
.btn-icon:hover { background-color: var(--z-hover-bg); color: var(--z-heading); }

/* Keyboard shortcut hint (Command palette ⌘K etc.) */
kbd, .kbd {
  display: inline-flex; align-items: center; gap: .1rem;
  padding: .05rem .4rem;
  font-size: .72rem;
  line-height: 1.4;
  color: var(--z-text-muted);
  background: var(--z-surface);
  border: 1px solid var(--z-border);
  border-bottom-width: 2px;
  border-radius: 6px;
  box-shadow: none;
}

/* ========================================================================
   4. App shell
   ======================================================================== */
.app-shell { display: flex; flex-direction: column; min-height: 100vh; }

.app-topbar {
  display: flex;
  align-items: center;
  gap: .75rem;
  height: 60px;
  padding: 0 1rem 0 1.25rem;
  background: var(--z-topbar-bg);
  color: var(--z-topbar-text);
  position: sticky;
  top: 0;
  z-index: 1030;
  border-bottom: 1px solid var(--z-topbar-border);
}
.app-topbar .btn-icon { color: var(--z-text-muted); }
.app-topbar-spacer { flex: 1 1 auto; }

.app-brand { display: inline-flex; align-items: center; gap: .6rem; text-decoration: none; color: var(--z-heading); }
.app-brand-mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2rem; height: 2rem; border-radius: var(--z-radius-sm);
  background: linear-gradient(135deg, var(--z-primary), var(--z-primary-accent));
  color: var(--z-on-primary); font-weight: 700; font-size: 1.05rem;
  box-shadow: 0 2px 8px rgba(var(--z-primary-rgb), .35);
}
.app-brand-name { font-weight: 600; letter-spacing: -0.01em; color: var(--z-heading); }
/* Deployment logo (ZagelBranding:LogoUrl). With a separate dark variant, show the one that
   matches the active theme; without one, give the light-background logo a white backing on
   dark so dark ink (navy, grey wordmarks) stays visible. */
.app-brand-logo { display: block; height: 2rem; width: auto; max-width: 180px; object-fit: contain; }
.app-brand-logo-dark { display: none; }
[data-theme="dark"] .app-brand-logo-light { display: none; }
[data-theme="dark"] .app-brand-logo-dark { display: block; }
[data-theme="dark"] .app-brand-logo-solo {
  box-sizing: border-box; padding: 3px 7px;
  background: #fff; border-radius: var(--z-radius-sm);
}

.user-menu .dropdown-toggle { color: var(--z-text); gap: .4rem; width: auto; padding: 0 .5rem; height: 2.25rem; }

/* Theme switcher — show the check only next to the active choice */
.theme-menu .dropdown-toggle::after { display: none; }
.theme-menu .dropdown-item { display: flex; align-items: center; }
.theme-menu .dropdown-item .theme-check { visibility: hidden; color: var(--z-primary); }
.theme-menu .dropdown-item.active .theme-check { visibility: visible; }
.theme-menu .dropdown-item.active { background: var(--z-primary-soft); color: var(--z-primary-active); }
.user-menu .dropdown-toggle::after { color: var(--z-slate-400); }

/* Workspace / instance switcher (Slack/Vercel style) */
.instance-selector { margin-right: .25rem; }
.instance-selector .btn {
  color: var(--z-text);
  background: var(--z-surface);
  border-color: var(--z-border);
  border-radius: var(--z-radius-sm);
  font-weight: 500;
  box-shadow: var(--z-shadow-xs);
}
.instance-selector .btn:hover {
  color: var(--z-heading);
  background: var(--z-surface-2);
  border-color: var(--z-border-strong);
}

.app-body { display: flex; flex: 1 1 auto; min-height: 0; }

/* ========================================================================
   5. Sidebar — slim-to-wide, light surface, Lucide-ready
   ======================================================================== */
.app-sidebar {
  width: var(--z-sidebar-w);
  flex: 0 0 var(--z-sidebar-w);
  background: var(--z-sidebar-bg);
  border-right: 1px solid var(--z-sidebar-border);
  overflow-y: auto;
  overflow-x: hidden;
  padding: .75rem .625rem 1.5rem;
  scrollbar-width: thin;
  scrollbar-color: var(--z-border-strong) transparent;
  transition: width .18s ease, flex-basis .18s ease;
}
.app-sidebar::-webkit-scrollbar { width: 6px; }
.app-sidebar::-webkit-scrollbar-thumb { background: var(--z-border-strong); border-radius: 3px; }
.app-sidebar::-webkit-scrollbar-track { background: transparent; }

/* Collapsed "slim" state (toggle .app-shell.sidebar-slim on desktop) */
.app-shell.sidebar-slim .app-sidebar {
  width: var(--z-sidebar-w-slim);
  flex-basis: var(--z-sidebar-w-slim);
}
.app-shell.sidebar-slim .app-sidebar .nav-link span,
.app-shell.sidebar-slim .app-sidebar .nav-caret,
.app-shell.sidebar-slim .app-sidebar .nav-collapse { display: none; }
.app-shell.sidebar-slim .app-sidebar .nav-link { justify-content: center; padding-inline: .5rem; }

.app-sidebar-backdrop { display: none; }

.app-main { flex: 1 1 auto; min-width: 0; padding: 1.75rem 1.75rem 2.5rem; }

.sidebar-nav .nav-item { width: 100%; }
.sidebar-nav .nav-section-label {
  font-size: .68rem; font-weight: 600; text-transform: uppercase;
  letter-spacing: .07em; color: var(--z-slate-400);
  padding: .9rem .75rem .35rem;
}

.sidebar-nav .nav-link {
  display: flex;
  align-items: center;
  gap: .65rem;
  width: 100%;
  padding: .5rem .7rem;
  margin-bottom: 1px;
  color: var(--z-sidebar-text);
  border: 0;
  border-radius: var(--z-radius-sm);
  background: transparent;
  font-size: .875rem;
  font-weight: 500;
  text-align: left;
  transition: color .12s ease, background-color .12s ease;
}
.sidebar-nav .nav-link:hover {
  color: var(--z-heading);
  background: var(--z-sidebar-hover-bg);
}
.sidebar-nav .nav-link.active {
  color: var(--z-sidebar-text-active);
  background: var(--z-sidebar-active-bg);
  font-weight: 600;
}
.sidebar-nav .nav-link i:first-child {
  font-size: 1.05rem;
  width: 1.2rem;
  text-align: center;
  flex: 0 0 auto;
  opacity: .85;
}
.sidebar-nav .nav-link.active i:first-child { opacity: 1; }

/* Collapsible groups */
.sidebar-nav .nav-group-toggle .nav-caret {
  margin-left: auto;
  font-size: .7rem;
  opacity: .6;
  transition: transform .18s ease;
}
.sidebar-nav .nav-group-toggle[aria-expanded="true"] .nav-caret { transform: rotate(180deg); }
.sidebar-nav .nav-group.active > .nav-group-toggle { color: var(--z-heading); }

.sidebar-nav .nav-collapse {
  list-style: none;
  margin: .1rem 0 .35rem;
  padding: 0 0 0 1.9rem;
  position: relative;
}
.sidebar-nav .nav-collapse::before {
  content: "";
  position: absolute;
  left: 1.4rem;
  top: .1rem;
  bottom: .1rem;
  width: 1px;
  background: var(--z-border);
}
.sidebar-nav .nav-sublink {
  display: block;
  padding: .38rem .7rem;
  color: var(--z-sidebar-text);
  font-size: .8rem;
  text-decoration: none;
  border-radius: 6px;
  transition: color .12s ease, background-color .12s ease;
}
.sidebar-nav .nav-sublink:hover {
  color: var(--z-heading);
  background: var(--z-sidebar-hover-bg);
}
.sidebar-nav .nav-sublink.active {
  color: var(--z-sidebar-text-active);
  background: var(--z-sidebar-active-bg);
  font-weight: 600;
}

/* Nested sub-groups (e.g. Management → Billing → Credits) --------------------------------
   The sub-group header (Billing) is a toggle that must read exactly like a second-level
   sublink, and its children (Credits/Transactions) must read exactly like sublinks too, just
   one indent deeper. Buttons don't inherit the app font by default, so force it here. */
.sidebar-nav .nav-subgroup { list-style: none; width: 100%; }
.sidebar-nav .nav-subgroup-toggle {
  display: flex;
  align-items: center;
  gap: .4rem;
  width: 100%;
  border: 0;
  background: transparent;
  text-align: left;
  cursor: pointer;
  font: inherit;                     /* match sublink typography, not the browser button font */
  /* inherits padding/color/size/hover from .nav-sublink (both classes are applied) */
}
.sidebar-nav .nav-subgroup-toggle .nav-caret {
  margin-left: auto;
  font-size: .68rem;
  opacity: .6;
  transition: transform .18s ease;
}
.sidebar-nav .nav-subgroup-toggle[aria-expanded="true"] .nav-caret { transform: rotate(180deg); }
.sidebar-nav .nav-subgroup.active > .nav-subgroup-toggle { color: var(--z-heading); font-weight: 600; }

/* Third level: its own indented list + guide line, fully declared so it never depends on the
   base .nav-collapse rules winning the cascade. */
.sidebar-nav .nav-subcollapse {
  list-style: none;
  margin: .1rem 0 .3rem;
  padding: 0 0 0 .85rem;
  position: relative;
}
.sidebar-nav .nav-subcollapse::before {
  content: "";
  position: absolute;
  left: .3rem;
  top: .1rem;
  bottom: .1rem;
  width: 1px;
  background: var(--z-border);
}
.sidebar-nav .nav-subcollapse .nav-sublink { font-size: .82rem; }

[dir="rtl"] .sidebar-nav .nav-subcollapse { padding: 0 .85rem 0 0; }
[dir="rtl"] .sidebar-nav .nav-subcollapse::before { left: auto; right: .3rem; }
[dir="rtl"] .sidebar-nav .nav-subgroup-toggle .nav-caret { margin-left: 0; margin-right: auto; }

@media (max-width: 991.98px) {
  .app-sidebar {
    position: fixed;
    inset: 60px 0 0 auto;
    left: -290px;
    z-index: 1040;
    transition: left .2s ease;
    box-shadow: none;
  }
  .app-sidebar.show { left: 0; box-shadow: var(--z-shadow-pop); }
  .app-sidebar-backdrop.show {
    display: block;
    position: fixed; inset: 60px 0 0 0; background: rgba(15, 23, 42, .4); z-index: 1035;
  }
}

/* ========================================================================
   6. Cards / surfaces
   ======================================================================== */
.card {
  --bs-card-bg: var(--z-surface);
  border: 1px solid var(--z-border);
  border-radius: var(--z-radius-md);
  box-shadow: var(--z-shadow-xs);
  color: var(--z-text);
}
.card-title { color: var(--z-heading); font-weight: 600; }

.card > .card-header {
  background: transparent;
  border-bottom: 1px solid var(--z-border);
  padding: .85rem 1.25rem;
  color: var(--z-heading);
  font-weight: 600;
}
.card > .card-header i { color: var(--z-primary); }
.card > .card-footer {
  background: var(--z-surface-2);
  border-top: 1px solid var(--z-border);
  padding: .75rem 1.25rem;
}

/* KPI / stat cards with sparkline + trend support */
.stat-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: .3rem;
  padding: 1.15rem 1.3rem;
  overflow: hidden;
  transition: box-shadow .15s ease, transform .15s ease, border-color .15s ease;
}
.stat-card:hover {
  box-shadow: var(--z-shadow-soft);
  transform: translateY(-2px);
  border-color: var(--z-border-strong);
}
.stat-card .stat-label {
  font-size: .78rem; font-weight: 500; color: var(--z-text-muted);
  text-transform: uppercase; letter-spacing: .04em;
}
.stat-card .stat-value {
  font-size: 2rem; font-weight: 700; line-height: 1.1;
  color: var(--z-heading); letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
.stat-card .stat-secondary { font-size: .8rem; color: var(--z-text-muted); }
.stat-card a.stretched-link { text-decoration: none; }

/* Reusable hover lift + shadow, matching the KPI stat cards above. Applied to other
   clickable cards (e.g. the dashboard Sent/Failed/Retries/Rejected widget tables) so they
   animate on hover the same way. */
.card-hover {
  transition: box-shadow .15s ease, transform .15s ease, border-color .15s ease;
}
.card-hover:hover {
  box-shadow: var(--z-shadow-soft);
  transform: translateY(-2px);
  border-color: var(--z-border-strong);
}

/* Fixed-height chart container so Chart.js (maintainAspectRatio:false) fills a stable box —
   keeps the line and bar variants exactly the same height and stops the card growing on
   re-render / chart-type toggle. */
.chart-box { position: relative; height: 220px; width: 100%; }
.chart-box > canvas { position: absolute; inset: 0; }
@media (max-width: 575.98px) { .chart-box { height: 190px; } }

/* Sparkline pinned to the card corner */
.stat-spark {
  position: absolute;
  right: 1rem;
  bottom: .9rem;
  width: 84px;
  height: 34px;
  opacity: .9;
  pointer-events: none;
}

/* Trend delta pill */
.stat-delta {
  display: inline-flex; align-items: center; gap: .2rem;
  font-size: .78rem; font-weight: 600; width: fit-content;
  padding: .05rem .35rem; border-radius: 6px;
  font-variant-numeric: tabular-nums;
}
.stat-delta.up   { color: var(--z-success); background: var(--z-success-soft); }
.stat-delta.down { color: var(--z-danger);  background: var(--z-danger-soft); }
.stat-delta.flat { color: var(--z-text-muted); background: var(--z-fill); }

/* ========================================================================
   7. Page header / breadcrumbs
   ======================================================================== */
.page-header { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: .75rem; margin-bottom: 1.5rem; }
.page-header h1 { font-size: 1.4rem; font-weight: 700; color: var(--z-heading); margin: 0; display: flex; align-items: center; gap: .55rem; letter-spacing: -0.025em; }
.page-header h1 i { color: var(--z-primary); font-size: 1.2rem; }
.page-subtitle { color: var(--z-text-muted); font-size: .875rem; margin-top: .2rem; }

.breadcrumb { font-size: .82rem; --bs-breadcrumb-divider-color: var(--z-slate-400); }
.breadcrumb-item a { color: var(--z-text-muted); text-decoration: none; }
.breadcrumb-item a:hover { color: var(--z-primary); }
.breadcrumb-item.active { color: var(--z-heading); font-weight: 500; }

/* ========================================================================
   8. Empty / loading (skeleton shimmer)
   ======================================================================== */
.empty-state { text-align: center; padding: 3rem 1.5rem; color: var(--z-text); }
.empty-state-panel { background: var(--z-surface); border: 1px dashed var(--z-border-strong); border-radius: var(--z-radius-md); }
.empty-state-icon { font-size: 2.5rem; color: var(--z-slate-400); margin-bottom: .75rem; display: block; }

.skeleton {
  background: linear-gradient(90deg,
    var(--z-slate-100) 25%, var(--z-slate-200) 37%, var(--z-slate-100) 63%);
  background-size: 400% 100%;
  animation: skeleton-loading 1.4s ease infinite;
  border-radius: 6px;
}
[data-theme="dark"] .skeleton {
  background: linear-gradient(90deg, #16223a 25%, #1e2c47 37%, #16223a 63%);
  background-size: 400% 100%;
}
@keyframes skeleton-loading { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

/* ========================================================================
   9. Tables
   ======================================================================== */
.table-toolbar { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin-bottom: 1rem; }
.table-toolbar .search-box { max-width: 320px; }

table.data-table { --bs-table-bg: var(--z-surface); color: var(--z-text); }
table.data-table thead th {
  font-size: .72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--z-text-muted);
  background: var(--z-surface-2);
  border-bottom: 1px solid var(--z-border);
  white-space: nowrap;
  padding-top: .7rem; padding-bottom: .7rem;
}
table.data-table tbody tr { transition: background-color .1s ease; border-color: var(--z-border); }
table.data-table.table-hover tbody tr:hover,
table.data-table tbody tr:hover { background-color: var(--z-primary-soft); }
table.data-table th a { color: inherit; text-decoration: none; display: inline-flex; align-items: center; gap: .3rem; }
table.data-table th.sortable { cursor: pointer; white-space: nowrap; }
table.data-table td { vertical-align: middle; border-color: var(--z-border); }

/* Selected row (bulk actions) */
table.data-table tbody tr.selected { background-color: var(--z-primary-soft); }

/* Phone numbers / IDs align nicely in monospace */
table.data-table td .text-mono,
table.data-table td .font-mono { color: var(--z-text-secondary); }

/* Ghost / background bar inside a cell (traffic share in grouped reports) */
.cell-bar { position: relative; display: block; padding: .1rem .1rem; }
.cell-bar > .cell-bar-fill {
  position: absolute; inset: 0 auto 0 0;
  width: var(--bar, 0%);
  background: var(--z-primary-soft);
  border-radius: 4px;
  z-index: 0;
}
.cell-bar > .cell-bar-value {
  position: relative; z-index: 1;
  font-variant-numeric: tabular-nums;
}
[dir="rtl"] .cell-bar > .cell-bar-fill { inset: 0 0 0 auto; }

/* Search highlight */
/* Dark text always: the yellow stays light on both themes, so inherited (light) text on
   Midnight would vanish. */
mark.search-hit { background: #fde68a; color: var(--z-slate-900); padding: 0 .1em; border-radius: 3px; }

/* Truncated body preview */
.cell-truncate { max-width: 320px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: inline-block; vertical-align: bottom; }

/* Floating bulk action bar */
.bulk-action-bar {
  position: sticky; bottom: 1rem; z-index: 20;
  display: flex; align-items: center; gap: .75rem;
  margin-top: 1rem; padding: .6rem .6rem .6rem 1rem;
  background: var(--z-heading); color: #fff;
  border-radius: var(--z-radius-md);
  box-shadow: var(--z-shadow-pop);
}
/* --z-heading turns near-white on Midnight, which would put white text on white. */
[data-theme="dark"] .bulk-action-bar {
  background: var(--z-surface-2); color: var(--z-heading);
  border: 1px solid var(--z-border-strong);
}
.bulk-action-bar .bulk-count { font-weight: 600; font-variant-numeric: tabular-nums; }
.bulk-action-bar .btn { --bs-btn-border-radius: var(--z-radius-sm); }

/* ---------- Card tabs (segmented, replaces group-by dropdowns) ---------- */
.card-tabs { display: inline-flex; flex-wrap: wrap; gap: .25rem; padding: .25rem; background: var(--z-slate-100); border-radius: var(--z-radius-md); border: 1px solid var(--z-border); }
[data-theme="dark"] .card-tabs { background: var(--z-surface-2); }
.card-tabs .card-tab {
  display: inline-flex; align-items: center; gap: .4rem;
  padding: .45rem .85rem; border: 0; background: transparent;
  color: var(--z-text-muted); font-size: .85rem; font-weight: 500;
  border-radius: var(--z-radius-sm); cursor: pointer;
  transition: background-color .12s ease, color .12s ease, box-shadow .12s ease;
}
.card-tabs .card-tab:hover { color: var(--z-heading); }
.card-tabs .card-tab.active {
  background: var(--z-surface); color: var(--z-primary);
  box-shadow: var(--z-shadow-xs); font-weight: 600;
}
.card-tabs .card-tab .card-tab-count {
  font-size: .72rem; font-weight: 600; padding: 0 .4rem;
  border-radius: 999px; background: var(--z-primary-soft); color: var(--z-primary);
}

/* ---------- DataTables (Bootstrap 5 dress) harmonised with the system ---------- */
.dataTables_wrapper .dt-search input,
.dataTables_wrapper .dataTables_filter input {
  border: 1px solid var(--z-border); border-radius: var(--z-radius-sm);
  padding: .4rem .7rem; background: var(--z-surface); color: var(--z-text);
}
.dataTables_wrapper .dt-search input:focus,
.dataTables_wrapper .dataTables_filter input:focus {
  border-color: var(--z-primary); box-shadow: 0 0 0 3px var(--z-primary-ring); outline: none;
}
.dataTables_wrapper .dt-length select,
.dataTables_wrapper .dataTables_length select {
  border: 1px solid var(--z-border); border-radius: var(--z-radius-sm);
  background: var(--z-surface); color: var(--z-text); padding: .3rem 1.6rem .3rem .6rem;
}
.dataTables_wrapper .dt-info,
.dataTables_wrapper .dataTables_info { color: var(--z-text-muted); font-size: .82rem; }
.dataTables_wrapper .dt-paging .page-link,
.dataTables_wrapper .pagination .page-link { border-radius: var(--z-radius-sm) !important; margin: 0 2px; }
table.dataTable thead th {
  font-size: .72rem; font-weight: 600; text-transform: uppercase; letter-spacing: .05em;
  color: var(--z-text-muted); background: var(--z-surface-2);
}
table.dataTable thead th.dt-orderable-asc:hover,
table.dataTable thead th.dt-orderable-desc:hover { color: var(--z-heading); cursor: pointer; }
table.dataTable tbody tr:hover > * { box-shadow: inset 0 0 0 9999px var(--z-primary-soft); }
table.dataTable.dt-loading tbody { opacity: .45; transition: opacity .15s ease; }

/* ========================================================================
   10. Badges — semantic status pills
   ======================================================================== */
.badge { font-weight: 600; letter-spacing: .01em; border-radius: 999px; padding: .3em .65em; }

.badge-status {
  display: inline-flex; align-items: center; gap: .32rem;
  font-size: .74rem; font-weight: 600;
  padding: .25rem .6rem; border-radius: 999px;
  border: 1px solid transparent;
}
.badge-status::before {
  content: ""; width: .45rem; height: .45rem; border-radius: 50%;
  background: currentColor; flex: 0 0 auto;
}
/* amber — WaitingModeration / pending / queued */
.badge-status.is-pending { color: var(--z-warning); background: var(--z-warning-soft); border-color: rgba(217,119,6,.2); }
/* emerald — Sent / delivered / success */
.badge-status.is-sent,
.badge-status.is-success { color: var(--z-success); background: var(--z-success-soft); border-color: rgba(5,150,105,.2); }
/* rose — Failed / rejected / error */
.badge-status.is-failed { color: var(--z-danger); background: var(--z-danger-soft); border-color: rgba(225,29,72,.2); }
/* sky — Processing / info */
.badge-status.is-info { color: var(--z-info); background: var(--z-info-soft); border-color: rgba(2,132,199,.2); }
/* slate — neutral / draft / unknown */
.badge-status.is-neutral { color: var(--z-text-secondary); background: var(--z-fill); border-color: var(--z-border); }
/* indigo — highlighted */
.badge-status.is-primary { color: var(--z-primary); background: var(--z-primary-soft); border-color: rgba(var(--z-primary-rgb),.2); }

/* "Time in spool" cell on the spool browse grid - colored by the message's queue state.
   Idle (not currently claimed by any worker) is left uncolored/default. */
.tis-selected { color: var(--z-info); font-weight: 600; }
.tis-processing { color: var(--z-warning); font-weight: 600; }

/* Classification widgets (AI functions / flags) — progress bars */
.classification-row { margin-bottom: .7rem; }
.classification-row:last-child { margin-bottom: 0; }
.classification-label { font-size: .82rem; font-weight: 500; color: var(--z-text-secondary); }
.classification-count { font-size: .8rem; font-weight: 600; color: var(--z-heading); }
.classification-track { height: 6px; border-radius: 999px; background: var(--z-slate-100); overflow: hidden; }
.classification-fill {
  height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--z-primary), var(--z-primary-accent));
  transition: width .5s ease;
}
[data-theme="dark"] .classification-track { background: rgba(255,255,255,.06); }

/* Live feed indicator */
.live-dot {
  display: inline-flex; align-items: center; gap: .35rem;
  font-size: .74rem; font-weight: 600; color: var(--z-success);
}
.live-dot::before {
  content: ""; width: .5rem; height: .5rem; border-radius: 50%;
  background: var(--z-success);
  box-shadow: 0 0 0 0 rgba(5, 150, 105, .5);
  animation: live-pulse 1.8s ease-out infinite;
}
@keyframes live-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(5, 150, 105, .5); }
  70%  { box-shadow: 0 0 0 6px rgba(5, 150, 105, 0); }
  100% { box-shadow: 0 0 0 0 rgba(5, 150, 105, 0); }
}

/* ========================================================================
   11. Pagination / toasts / overlays
   ======================================================================== */
.pagination {
  --bs-pagination-active-bg: var(--z-primary);
  --bs-pagination-active-border-color: var(--z-primary);
  --bs-pagination-active-color: var(--z-on-primary);
  --bs-pagination-color: var(--z-text);
  --bs-pagination-bg: var(--z-surface);
  --bs-pagination-border-color: var(--z-border);
  --bs-pagination-hover-color: var(--z-primary-hover);
  --bs-pagination-hover-bg: var(--z-primary-soft);
  --bs-pagination-focus-color: var(--z-primary-hover);
  --bs-pagination-border-radius: var(--z-radius-sm);
}

.toast-host { position: fixed; top: 76px; right: 1rem; z-index: 1080; display: flex; flex-direction: column; gap: .5rem; }
.toast { box-shadow: var(--z-shadow-pop); border-radius: var(--z-radius-md); border: 1px solid var(--z-border); background: var(--z-surface); color: var(--z-text); }
[dir="rtl"] .toast-host { right: auto; left: 1rem; }

/* Overlays get the only real shadows in the system */
.modal-content { border: 1px solid var(--z-border); border-radius: var(--z-radius-md); box-shadow: var(--z-shadow-pop); background: var(--z-surface); color: var(--z-text); }
.modal-header, .modal-footer { border-color: var(--z-border); }
.dropdown-menu {
  --bs-dropdown-bg: var(--z-surface);
  --bs-dropdown-border-color: var(--z-border);
  --bs-dropdown-link-color: var(--z-text);
  --bs-dropdown-link-hover-bg: var(--z-hover-bg);
  --bs-dropdown-link-hover-color: var(--z-heading);
  --bs-dropdown-link-active-bg: var(--z-primary-soft);
  --bs-dropdown-link-active-color: var(--z-primary-active);
  border-radius: var(--z-radius-md);
  box-shadow: var(--z-shadow-pop);
  font-size: .9rem;
  padding: .35rem;
}
.dropdown-item { padding: .45rem .75rem; border-radius: 6px; }
.dropdown-item i { width: 1.1rem; display: inline-block; text-align: center; margin-right: .25rem; color: var(--z-slate-400); }

/* ========================================================================
   12. Code editor (ScriptManager IDE view)
   ======================================================================== */
.code-editor-frame {
  border: 1px solid var(--z-border);
  border-radius: var(--z-radius-md);
  overflow: hidden;
}
.code-editor-frame:focus-within {
  border-color: var(--z-primary);
  box-shadow: 0 0 0 3px var(--z-primary-ring);
}
.code-editor-frame .CodeMirror {
  height: 420px;
  font-size: .85rem;
  font-family: var(--z-font-mono);
}
.code-editor-frame.code-editor-sm .CodeMirror { height: 180px; }

.hook-methods {
  background: var(--z-surface-2);
  border: 1px solid var(--z-border);
  border-radius: var(--z-radius-sm);
  padding: .6rem .75rem;
  min-height: 3rem;
  max-height: 220px;
  overflow: auto;
  white-space: pre-wrap;
  margin: 0;
  font-family: var(--z-font-mono);
  color: var(--z-text);
}

.test-console {
  background: #0d1526;
  color: #cbd5e1;
  border-radius: var(--z-radius-sm);
  padding: .75rem .9rem;
  font-size: .8rem;
  font-family: var(--z-font-mono);
  min-height: 8rem;
  max-height: 300px;
  overflow: auto;
  white-space: pre-wrap;
}

.nav-tabs-sm .nav-link { padding: .3rem .75rem; font-size: .82rem; color: var(--z-text-muted); }
.nav-tabs-sm .nav-link.active { color: var(--z-primary); font-weight: 600; }

/* ========================================================================
   13. Validation
   ======================================================================== */
/* asp-validation tag helpers always render their element (tagged -valid when
   empty); hide that state so empty colored boxes don't show before validation. */
.validation-summary-valid,
.field-validation-valid { display: none; }
.invalid-feedback { color: var(--z-danger); }

/* ========================================================================
   14. Auth pages
   ======================================================================== */
.auth-body {
  background:
    radial-gradient(1200px 600px at 15% -10%, rgba(var(--z-primary-rgb), .18), transparent 60%),
    radial-gradient(900px 500px at 100% 110%, rgba(var(--z-primary-accent-rgb), .16), transparent 55%),
    var(--z-slate-50);
  min-height: 100vh;
}
[data-theme="dark"] .auth-body {
  background:
    radial-gradient(1200px 600px at 15% -10%, rgba(var(--z-primary-rgb), .22), transparent 60%),
    radial-gradient(900px 500px at 100% 110%, rgba(var(--z-primary-deep-rgb), .28), transparent 55%),
    var(--z-bg);
}
.auth-shell { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 1.5rem; }
.auth-card {
  width: 100%; max-width: 420px;
  background: var(--z-surface);
  border: 1px solid var(--z-border);
  border-radius: var(--z-radius-lg);
  padding: 2.25rem;
  box-shadow: var(--z-shadow-pop);
}
.auth-brand { display: flex; align-items: center; gap: .6rem; margin-bottom: 1.75rem; }
.auth-brand .app-brand-name { color: var(--z-heading); font-size: 1.15rem; }
.auth-brand .app-brand-logo { height: 2.5rem; max-width: 240px; }

/* Error inputs pulse (login) */
.input-error { border-color: var(--z-danger) !important; animation: input-pulse .9s ease; }
@keyframes input-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(225, 29, 72, .45); }
  70%  { box-shadow: 0 0 0 6px rgba(225, 29, 72, 0); }
  100% { box-shadow: 0 0 0 0 rgba(225, 29, 72, 0); }
}

/* Floating-label field (auth inputs) */
.field-float { position: relative; }
.field-float > .form-control { height: 3.25rem; padding: 1.25rem .85rem .35rem; }
.field-float > label {
  position: absolute; top: .95rem; inset-inline-start: .9rem;
  color: var(--z-slate-400); font-size: .95rem;
  pointer-events: none; transition: all .14s ease; margin: 0;
}
.field-float > .form-control:focus + label,
.field-float > .form-control:not(:placeholder-shown) + label {
  top: .4rem; font-size: .72rem; color: var(--z-primary);
}

/* ========================================================================
   15. Command palette (⌘K) scaffold
   ======================================================================== */
.cmdk-backdrop { position: fixed; inset: 0; background: rgba(15, 23, 42, .45); backdrop-filter: blur(2px); z-index: 1090; display: none; }
.cmdk-backdrop.show { display: flex; align-items: flex-start; justify-content: center; padding-top: 12vh; }
.cmdk-panel {
  width: 100%; max-width: 560px;
  background: var(--z-surface); border: 1px solid var(--z-border);
  border-radius: var(--z-radius-md); box-shadow: var(--z-shadow-pop);
  overflow: hidden;
}
.cmdk-input { width: 100%; border: 0; border-bottom: 1px solid var(--z-border); padding: 1rem 1.1rem; font-size: 1rem; background: transparent; color: var(--z-text); }
.cmdk-input:focus { outline: none; }
.cmdk-list { max-height: 360px; overflow-y: auto; padding: .35rem; }
.cmdk-item { display: flex; align-items: center; gap: .6rem; padding: .55rem .75rem; border-radius: 6px; cursor: pointer; color: var(--z-text); }
.cmdk-item:hover, .cmdk-item.active { background: var(--z-primary-soft); color: var(--z-primary-active); }

/* ========================================================================
   16. RTL adjustments (Arabic content)
   ======================================================================== */
[dir="rtl"] body { letter-spacing: 0; }
[dir="rtl"] .app-sidebar { border-right: 0; border-left: 1px solid var(--z-sidebar-border); }
[dir="rtl"] .sidebar-nav .nav-collapse { padding: 0 1.9rem 0 0; }
[dir="rtl"] .sidebar-nav .nav-collapse::before { left: auto; right: 1.4rem; }
[dir="rtl"] .sidebar-nav .nav-group-toggle .nav-caret { margin-left: 0; margin-right: auto; }
[dir="rtl"] .dropdown-item i { margin-right: 0; margin-left: .25rem; }
[dir="rtl"] .user-menu .dropdown-toggle::after { margin-left: 0; margin-right: .3rem; }

/* Arabic script reads heavier — nudge weights down a touch for balance */
:lang(ar), [lang="ar"], .text-arabic {
  font-family: "Noto Sans Arabic", "Segoe UI", Tahoma, var(--z-font-sans);
  letter-spacing: 0;
}
:lang(ar) .stat-card .stat-value { font-weight: 600; }

/* ========================================================================
   18. Responsive — tablet & phone
   ======================================================================== */

/* Guard against accidental horizontal overflow from wide inline content. */
html, body { max-width: 100%; }
.app-main, .app-body, .app-shell { min-width: 0; }

/* DataTables Responsive: theme the expand/collapse control + child rows. */
table.dataTable > tbody > tr td.dtr-control:before,
table.dataTable > tbody > tr th.dtr-control:before {
  background-color: var(--z-primary);
  border-color: var(--z-primary);
  box-shadow: none;
}
table.dataTable > tbody > tr.parent td.dtr-control:before { background-color: var(--z-danger); border-color: var(--z-danger); }
ul.dtr-details { width: 100%; }
ul.dtr-details > li { border-bottom: 1px solid var(--z-border); padding: .4rem 0; }
.dtr-title { color: var(--z-text-muted); font-weight: 600; }
.dtr-modal .dtr-modal-content { background: var(--z-surface); color: var(--z-text); border-radius: var(--z-radius-md); }

/* Tablet and below: roomier touch targets, lighter page padding. */
@media (max-width: 991.98px) {
  .app-main { padding: 1.1rem 1rem 2rem; }
  .btn-icon { width: 2.5rem; height: 2.5rem; }        /* ≥44px touch targets */
  .card-tabs { max-width: 100%; }
  .stat-card .stat-value { font-size: 1.7rem; }
}

/* DataTables control rows (length / search / info / paging) stack on narrow. */
@media (max-width: 767.98px) {
  .dt-layout-row { flex-direction: column; align-items: stretch; gap: .5rem; row-gap: .5rem; }
  .dt-layout-cell { width: 100%; justify-content: flex-start !important; text-align: left !important; }
  .dt-search, .dataTables_filter { text-align: left; }
  .dt-search input, .dataTables_filter input { width: 100%; }
  .dt-paging .pagination, .dataTables_paginate .pagination { flex-wrap: wrap; }
}

/* Phone: stack filter toolbars and page-header actions full width. */
@media (max-width: 575.98px) {
  .app-topbar { padding: 0 .5rem; gap: .4rem; }
  .app-brand-name { display: none; }
  .app-topbar .instance-selector .btn { max-width: 128px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  .page-header { flex-direction: column; align-items: stretch; gap: .5rem; }
  .page-header h1 { font-size: 1.2rem; }
  .page-header .btn-group,
  .page-header > .d-flex { width: 100%; }
  .page-header .btn-group .btn,
  .page-header > .d-flex > .btn { flex: 1 1 0; }

  /* Filter rows: one control per line, edge to edge (overrides inline max-widths). */
  .table-toolbar { flex-direction: column; align-items: stretch; }
  .table-toolbar .form-control,
  .table-toolbar .form-select,
  .table-toolbar .search-box { max-width: none !important; width: 100%; }
  .table-toolbar .btn { width: 100%; }

  /* Grouped-report / spool filter grids: full-width fields. */
  .row.g-2 > [class*="col-"] { flex: 0 0 100%; max-width: 100%; }

  .bulk-action-bar { flex-wrap: wrap; }
  .bulk-action-bar .ms-auto { width: 100%; }

  .stat-card .stat-value { font-size: 1.5rem; }
  .stat-spark { display: none; }        /* too small to read on a phone */
}

/* ========================================================================
   19. Motion / accessibility
   ======================================================================== */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; }
}

/* ========================================================================
   20. select2 (bootstrap-5 theme) — align with app theme + dark mode
   The bootstrap-5 theme handles sizing/shape; these overrides remap its
   hard-coded light colors onto the app's theme variables so the control
   looks native in both light and Midnight (dark) themes.
   ======================================================================== */
.select2-container--bootstrap-5 .select2-selection {
  background-color: var(--bs-body-bg);
  border-color: var(--bs-border-color);
  color: var(--bs-body-color);
  border-radius: var(--bs-border-radius);
}
.select2-container--bootstrap-5 .select2-selection--single .select2-selection__rendered {
  color: var(--bs-body-color);
}
.select2-container--bootstrap-5 .select2-selection__placeholder {
  color: var(--bs-secondary-color, #6c757d);
}
.select2-container--bootstrap-5.select2-container--focus .select2-selection,
.select2-container--bootstrap-5.select2-container--open .select2-selection {
  border-color: var(--z-primary, var(--bs-primary));
  box-shadow: 0 0 0 .25rem rgba(var(--bs-primary-rgb), .25);
}
.select2-container--bootstrap-5 .select2-dropdown {
  background-color: var(--bs-body-bg);
  border-color: var(--bs-border-color);
  color: var(--bs-body-color);
}
.select2-container--bootstrap-5 .select2-results__option {
  color: var(--bs-body-color);
}
.select2-container--bootstrap-5 .select2-results__option--highlighted,
.select2-container--bootstrap-5 .select2-results__option--highlighted[aria-selected] {
  background-color: var(--bs-primary);
  color: var(--z-on-primary);
}
.select2-container--bootstrap-5 .select2-results__option--selected {
  background-color: var(--bs-secondary-bg);
  color: var(--bs-body-color);
}
.select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__choice {
  background-color: var(--bs-secondary-bg);
  border-color: var(--bs-border-color);
  color: var(--bs-body-color);
}
.select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__choice__remove {
  color: var(--bs-body-color);
}
.select2-container--bootstrap-5 .select2-search__field {
  color: var(--bs-body-color);
}
/* Keep filter selects a sensible width inside toolbars. */
.table-toolbar .select2-container,
.select2-container { min-width: 150px; }

/* Compact multi-select: render like a normal dropdown showing an "N selected" summary
   on a single line, instead of an area that grows with a removable tag per choice. */
.select2-selection--multiple.z-select2-count {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  overflow: hidden;
  min-height: calc(1.5em + .75rem + 2px);
}
.select2-selection--multiple.z-select2-count .select2-selection__rendered {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  overflow: hidden;
  white-space: nowrap;
  width: 100%;
  padding: 0 .75rem;
}
/* Hide the individual tag chips... */
.select2-selection--multiple.z-select2-count .select2-selection__choice { display: none !important; }
/* ...and the inline search box (kept in the DOM off-screen for focus/a11y) so the control
   reads as a single-line dropdown. Options are still chosen from the opened dropdown list. */
.select2-selection--multiple.z-select2-count .select2-search--inline {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
}
/* Show the selected labels ("Idle, Selected, Processing") in the collapsed control. */
.select2-selection--multiple.z-select2-count .select2-selection__rendered::after {
  content: attr(data-summary);
  color: var(--bs-body-color);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Multi-select dropdown list: keep every option listed (select2 4.1) and mark the selected
   ones with a right-aligned checkmark instead of removing them, so the menu behaves like a
   checklist you toggle (paired with closeOnSelect:false). */
.select2-container--bootstrap-5 .select2-results__option {
  position: relative;
  padding-right: 2rem;
}
.select2-container--bootstrap-5 .select2-results__option[aria-selected="true"] {
  display: list-item;
  background-color: transparent;
  color: var(--bs-body-color);
}
.select2-container--bootstrap-5 .select2-results__option[aria-selected="true"]::after {
  content: "\2713"; /* ✓ */
  position: absolute;
  right: .75rem;
  font-weight: 700;
  color: var(--bs-primary);
}
/* Keep the hover/highlight color readable even on an already-selected row. */
.select2-container--bootstrap-5 .select2-results__option--highlighted[aria-selected="true"]::after {
  color: var(--z-on-primary);
}

/* ---- Global loading spinner overlay ---------------------------------------
   A full-viewport backdrop + centered spinner shown during grid refreshes,
   ajax operations and other time-intensive work. Toggled by adding `.show`
   (see Zagel.spinner in site.js). z-index sits above Bootstrap modals (1055)
   so it also covers in-modal ajax. */
.z-spinner-overlay {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: none;
  align-items: center;
  justify-content: center;
  background: rgba(15, 23, 42, .38);
  -webkit-backdrop-filter: blur(1.5px);
  backdrop-filter: blur(1.5px);
  opacity: 0;
  transition: opacity .15s ease;
}
.z-spinner-overlay.show {
  display: flex;
  opacity: 1;
}
.z-spinner-box {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 4.5rem;
  height: 4.5rem;
  border-radius: var(--z-radius-md);
  background: var(--z-surface);
  box-shadow: var(--z-shadow-pop);
}
.z-spinner-box .spinner-border {
  width: 2.25rem;
  height: 2.25rem;
  color: var(--z-primary);
}
[data-theme="dark"] .z-spinner-overlay {
  background: rgba(0, 0, 0, .55);
}
@media (prefers-reduced-motion: reduce) {
  .z-spinner-overlay { transition: none; }
}

/* ========================================================================
   21. 2026 audit pass — cross-cutting polish
   Sticky headers, contrast fixes, copy affordance, RTL body cells, data
   heat-mapping, connecting-badge pulse, split PIN input, command palette.
   ======================================================================== */

/* ---- 21.1 Sticky table headers ------------------------------------------
   Long grids (Node Stats, spool lists) keep their column labels in view when
   the body scrolls. Works for plain server-rendered tables and DataTables.
   `.table-sticky` opts a wrapper's table in; DataTables gets it globally. */
.table-responsive .table-sticky thead th,
.table-sticky thead th,
table.dataTable thead th {
  position: sticky;
  top: 0;
  z-index: 2;
}
/* The header sits on the surface tint so scrolled rows don't bleed through. */
.table-sticky thead th { background: var(--z-surface-2); }

/* ---- 21.2 Contrast fixes (WCAG AA) --------------------------------------
   Breadcrumbs, DataTables "entries per page" / info, and page-size selects
   were slate-400 (~2.5:1). Bump to slate-500/600 for >=4.5:1 on white. */
.breadcrumb { --bs-breadcrumb-divider-color: var(--z-slate-500); }
.breadcrumb-item a,
.breadcrumb-item.active { color: var(--z-slate-600); }
.breadcrumb-item a:hover { color: var(--z-primary); }
.page-subtitle { color: var(--z-slate-600); }
.dataTables_wrapper .dt-info,
.dataTables_wrapper .dataTables_info,
.dataTables_wrapper .dt-length,
.dataTables_wrapper .dataTables_length,
.dataTables_wrapper .dt-length label,
.dataTables_wrapper .dataTables_length label { color: var(--z-slate-600); }
[data-theme="dark"] .breadcrumb-item a,
[data-theme="dark"] .breadcrumb-item.active,
[data-theme="dark"] .page-subtitle,
[data-theme="dark"] .dataTables_wrapper .dt-info,
[data-theme="dark"] .dataTables_wrapper .dt-length { color: var(--z-slate-300); }

/* ---- 21.3 Copy-to-clipboard affordance ----------------------------------
   Wrap a long id/number in `.copyable` (or add data-copy) and a copy icon
   fades in on hover; wiring lives in site.js. */
.copyable { position: relative; display: inline-flex; align-items: center; gap: .3rem; }
.copyable > .copy-btn {
  border: 0; background: transparent; cursor: pointer;
  color: var(--z-slate-400); padding: 0 .15rem; line-height: 1;
  opacity: 0; transition: opacity .12s ease, color .12s ease;
  font-size: .8rem;
}
.copyable:hover > .copy-btn,
.copy-btn:focus-visible { opacity: 1; }
.copyable > .copy-btn:hover { color: var(--z-primary); }
.copy-btn.copied { color: var(--z-success); opacity: 1; }

/* ---- 21.4 RTL-aware message body cells ----------------------------------
   Body cells render as a compact, read-only textarea so operators can scroll
   and select long message text inline without opening every row. The textarea
   auto-detects script direction (Arabic reads right-to-left) via dir="auto". */
.msg-body-ta {
  display: block;
  width: 100%;
  max-width: 340px;
  min-width: 220px;
  resize: vertical;
  white-space: pre-wrap;
  word-break: break-word;
  overflow-wrap: anywhere;
  line-height: 1.4;
  padding: .25rem .4rem;
  font-size: .82rem;
  color: var(--z-body-color, inherit);
  background: var(--z-input-bg, transparent);
  border: 1px solid var(--z-border, rgba(0,0,0,.12));
  border-radius: var(--z-radius-sm, .25rem);
  cursor: text;
}
.msg-body-ta:focus {
  outline: none;
  border-color: var(--z-primary, #0d6efd);
}
/* Arabic body text a touch larger for legibility, native Arabic font. */
.msg-body-ta[dir="rtl"], .msg-body-ta:lang(ar) {
  font-family: "Noto Sans Arabic", "Segoe UI", Tahoma, var(--z-font-sans);
}

/* ---- 21.5 Data heat-mapping for numeric grids ---------------------------
   Inline micro-bars + red wash for failure columns (Node Stats). A cell gets
   `.cell-num` for tabular figures; `.cell-fail.hot` washes light red when a
   failure count is > 0 so a failing node jumps out of the wall of numbers. */
.cell-num { font-variant-numeric: tabular-nums; font-family: var(--z-font-mono); }
.cell-fail.hot {
  background: var(--z-danger-soft);
  color: var(--z-danger);
  font-weight: 600;
  border-radius: 6px;
}
.cell-fail.hot::before {
  content: "\F33A"; /* bi-exclamation-triangle-ish marker via bootstrap-icons */
  font-family: "bootstrap-icons";
  font-size: .7em; margin-right: .3rem; opacity: .8;
}
/* Inline data bar behind a numeric value (submitted / current volume). */
.num-bar { position: relative; display: inline-block; min-width: 3.5rem; padding: .05rem .35rem; border-radius: 4px; }
.num-bar > .num-bar-fill {
  position: absolute; inset: 0 auto 0 0; width: var(--bar, 0%);
  background: var(--z-primary-soft); border-radius: 4px; z-index: 0;
}
.num-bar > .num-bar-val { position: relative; z-index: 1; font-variant-numeric: tabular-nums; }
[dir="rtl"] .num-bar > .num-bar-fill { inset: 0 0 0 auto; }

/* ---- 21.6 Connecting badge — distinct + pulsing -------------------------
   "Connecting" (amber) previously read almost identical to "Connected"
   (green). Give it a distinct amber treatment and a soft pulse so a stuck
   connecting gateway is obviously not yet up. */
.badge.status-connecting,
.badge.text-bg-warning.status-connecting {
  position: relative;
  color: #7c4a03 !important;
  background-color: var(--z-warning-soft) !important;
  border: 1px solid rgba(217, 119, 6, .35);
}
.badge.status-connecting::after {
  content: ""; display: inline-block;
  width: .45rem; height: .45rem; margin-left: .35rem;
  border-radius: 50%; background: var(--z-warning);
  box-shadow: 0 0 0 0 rgba(217, 119, 6, .5);
  animation: connecting-pulse 1.4s ease-out infinite;
}
[data-theme="dark"] .badge.status-connecting { color: #fbbf24 !important; }
@keyframes connecting-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(217, 119, 6, .5); }
  70%  { box-shadow: 0 0 0 5px rgba(217, 119, 6, 0); }
  100% { box-shadow: 0 0 0 0 rgba(217, 119, 6, 0); }
}

/* ---- 21.7 Tailwind-style neutral status badge ---------------------------
   Light background + same-hue dark text (replaces low-contrast text-bg-light
   white-on-light chips used for user type / hook / "Normal"). */
.badge-soft {
  font-weight: 600; border-radius: 999px; padding: .3em .65em;
  background: var(--z-slate-100); color: var(--z-slate-700);
  border: 1px solid var(--z-border);
}
[data-theme="dark"] .badge-soft { background: rgba(255,255,255,.06); color: var(--z-slate-200); }
/* Bootstrap keeps .text-bg-light white even under data-bs-theme="dark"; on Midnight those
   chips ("0 selected", "Inherit", priority/route fallbacks) would glare, so soften them to
   match .badge-soft. */
/* Bootstrap's .text-secondary grey (#6c757d) is only ~3.4:1 on Midnight; use our muted text.
   Overridden on the utility itself, not --bs-secondary-rgb, so .text-bg-secondary keeps
   its white-on-grey contrast. */
[data-theme="dark"] .text-secondary { color: var(--z-text-muted) !important; }
[data-theme="dark"] .text-bg-light {
  color: var(--z-text) !important;
  background-color: rgba(255, 255, 255, .08) !important;
}

/* ---- 21.8 Split 6-digit PIN input (2FA) ---------------------------------
   Six individual boxes that auto-advance; friendlier than one field and
   avoids the non-standard in-field Paste button on mobile. */
.pin-group { display: flex; gap: .5rem; justify-content: center; }
.pin-group .pin-box {
  width: 3rem; height: 3.5rem;
  text-align: center; font-size: 1.4rem; font-weight: 600;
  font-family: var(--z-font-mono);
  border: 1px solid var(--z-border-strong); border-radius: var(--z-radius-sm);
  background: var(--z-surface); color: var(--z-heading);
}
.pin-group .pin-box:focus {
  border-color: var(--z-primary);
  box-shadow: 0 0 0 3px var(--z-primary-ring);
  outline: none;
}
@media (max-width: 400px) {
  .pin-group { gap: .3rem; }
  .pin-group .pin-box { width: 2.5rem; height: 3rem; font-size: 1.2rem; }
}

/* ---- 21.9 Per-row moderation buttons ------------------------------------
   Compact green Approve / red Reject buttons rendered in every moderation
   row for true one-click moderation. */
.btn-mod {
  --bs-btn-padding-y: .2rem; --bs-btn-padding-x: .5rem; --bs-btn-font-size: .78rem;
  font-weight: 600;
}
.btn-mod-approve {
  --bs-btn-color: #fff; --bs-btn-bg: var(--z-success); --bs-btn-border-color: var(--z-success);
  --bs-btn-hover-bg: #047857; --bs-btn-hover-border-color: #047857; --bs-btn-hover-color: #fff;
  --bs-btn-active-bg: #065f46; --bs-btn-active-border-color: #065f46;
}
.btn-mod-reject {
  --bs-btn-color: #fff; --bs-btn-bg: var(--z-danger); --bs-btn-border-color: var(--z-danger);
  --bs-btn-hover-bg: #be123c; --bs-btn-hover-border-color: #be123c; --bs-btn-hover-color: #fff;
  --bs-btn-active-bg: #9f1239; --bs-btn-active-border-color: #9f1239;
}

/* ---- 21.10 In-button loading spinner ------------------------------------
   Refresh / reload actions show a spinner in place of their icon while the
   request is in flight (driven by Zagel.buttonBusy in site.js). */
.btn.is-busy { pointer-events: none; opacity: .75; }
.btn.is-busy > .bi { display: none; }
.btn.is-busy::before {
  content: ""; display: inline-block;
  width: 1em; height: 1em; margin-right: .4rem;
  vertical-align: -.125em;
  border: 2px solid currentColor; border-right-color: transparent;
  border-radius: 50%; animation: btn-spin .7s linear infinite;
}
@keyframes btn-spin { to { transform: rotate(360deg); } }

/* ---- 21.12 Message details component (modal + standalone page) -----------
   A 2-column description list with grey labels and dark-slate values, an RTL-aware
   read-only body view, and a pretty-printed Tags block. Shared by both surfaces. */
.msg-details dl.row { margin-bottom: .5rem; }
.msg-details dt {
  color: var(--z-text-muted);      /* grey labels */
  font-weight: 500;
  font-size: .82rem;
  padding-top: .28rem;
  padding-bottom: .28rem;
}
.msg-details dd {
  color: var(--z-heading);         /* dark-slate values */
  font-size: .875rem;
  margin-bottom: 0;
  padding-top: .28rem;
  padding-bottom: .28rem;
}
.msg-details dt + dd { border-bottom: 1px solid var(--z-border); }
.msg-details dt { border-bottom: 1px solid var(--z-border); }
.msg-details dl.row > dt:last-of-type,
.msg-details dl.row > dd:last-of-type { border-bottom: 0; }

.md-section-label {
  display: block;
  color: var(--z-text-muted);
  font-size: .78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  margin-bottom: .35rem;
}

/* Read-only, RTL-aware body (replaces the old textarea) */
.msg-body-view {
  border: 1px solid var(--z-border);
  border-radius: var(--z-radius-sm);
  background: var(--z-surface-2);
  color: var(--z-heading);
  padding: .55rem .75rem;
  min-height: 3.2rem;
  max-height: 220px;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-word;
  overflow-wrap: anywhere;
  line-height: 1.5;
}
.msg-body-view:lang(ar), .msg-body-view[dir="rtl"] {
  font-family: "Noto Sans Arabic", "Segoe UI", Tahoma, var(--z-font-sans);
}

/* Pretty-printed Tags JSON */
.msg-tags-view {
  margin: 0;
  border: 1px solid var(--z-border);
  border-radius: var(--z-radius-sm);
  background: var(--z-surface-2);
  color: var(--z-text);
  padding: .55rem .75rem;
  max-height: 220px;
  overflow: auto;
  font-family: var(--z-font-mono);
  font-size: .8rem;
  line-height: 1.45;
  white-space: pre;
}

/* ---- 21.11 Command palette trigger (topbar) -----------------------------
   A search pill in the top bar that opens the ⌘K palette; the palette panel
   styles already ship in section 15. */
.cmdk-trigger {
  display: inline-flex; align-items: center; gap: .5rem;
  height: 2.25rem; padding: 0 .7rem;
  color: var(--z-text-muted); background: var(--z-surface);
  border: 1px solid var(--z-border); border-radius: var(--z-radius-sm);
  font-size: .85rem; cursor: pointer;
  transition: border-color .12s ease, color .12s ease, background-color .12s ease;
}
.cmdk-trigger:hover { border-color: var(--z-border-strong); color: var(--z-heading); }
.cmdk-trigger .cmdk-trigger-label { min-width: 6.5rem; text-align: left; }
.cmdk-trigger kbd { margin-left: .25rem; }
@media (max-width: 767.98px) {
  .cmdk-trigger .cmdk-trigger-label, .cmdk-trigger kbd { display: none; }
  .cmdk-trigger { padding: 0 .6rem; }
}
.cmdk-item .cmdk-item-group { margin-left: auto; font-size: .72rem; color: var(--z-text-muted); }
.cmdk-empty { padding: 1.25rem; text-align: center; color: var(--z-text-muted); font-size: .875rem; }
[dir="rtl"] .cmdk-trigger kbd { margin-left: 0; margin-right: .25rem; }
