/* ProCMS design system
   ============================================================================
   An instrument panel for time. An agent's real question on every screen is
   "how long before this breaches", so the SLA clock is the one element allowed
   any visual intensity; everything else stays quiet so the eye finds it.

   Rules this file holds itself to:
     - One flat accent. No gradient fills on interactive elements — white text
       over the old blue→cyan gradient fell to 1.98:1 at the cyan end.
     - Every text token clears WCAG AA (4.5:1) on every surface it lands on;
       component boundaries (inputs, checkboxes) clear 3:1 per WCAG 1.4.11.
     - Numbers are data: they render in --font-mono with tabular figures.
     - Radii are small and consistent. --r-full is only for avatars and the
       notification count, never for buttons, tabs, filters or badges.
     - Nothing is sized by hand: use the --sp-*, --fs-* and --r-* scales.
   Dark stays the default theme; light is the topbar toggle.
   ========================================================================= */

:root {
  /* ---- Type ---------------------------------------------------------------
     Inter carries all UI text. IBM Plex Mono carries anything that is a
     measurement — SLA countdowns, case numbers, counts, timestamps, sizes —
     which is what a case desk actually reads. */
  --font-ui: "Inter", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, Helvetica, Arial, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, "Cascadia Mono", Menlo, Consolas, monospace;
  --font-display: var(--font-ui);   /* kept as an alias; no separate display face */

  --fs-1: 11px;   /* micro labels, table headers, keycaps */
  --fs-2: 12px;   /* metadata, captions, chip text */
  --fs-3: 13px;   /* secondary body, table cells */
  --fs-4: 14px;   /* base body — deliberately dense for a data tool */
  --fs-5: 16px;   /* card/section titles, modal titles */
  --fs-6: 18px;   /* case title */
  --fs-7: 20px;   /* page title */
  --fs-8: 24px;   /* KPI values, donut centre */

  --lh-tight: 1.25;
  --lh-snug: 1.4;
  --lh-body: 1.55;

  --fw-normal: 400;
  --fw-med: 500;
  --fw-semi: 600;

  /* ---- Spacing (4px base) ---- */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px;
  --sp-5: 20px; --sp-6: 24px; --sp-7: 32px; --sp-8: 48px;

  /* ---- Radii ---- */
  --r-xs: 3px; --r-sm: 5px; --r-md: 7px; --r-lg: 10px; --r-full: 999px;
  --radius-sm: var(--r-sm);   /* legacy aliases */
  --radius: var(--r-md);
  --radius-lg: var(--r-lg);

  /* ---- Motion — short, and only where it aids comprehension ---- */
  --dur-1: 80ms; --dur-2: 140ms; --dur-3: 220ms;
  --ease: cubic-bezier(.2, .7, .2, 1);

  /* ---- Layers ---- */
  --z-sticky: 3; --z-notif: 40; --z-modal: 50; --z-menu: 60;
  --z-cmdk: 70; --z-tip: 80; --z-toast: 90;

  /* ---- Layout ---- */
  --content-max: 1280px;
  --sidenav-w: 220px;
  --topbar-h: 52px;
  /* Breakpoints (documented — CSS vars cannot be used in @media):
     640px phone · 900px tablet/rail · 1200px wide */

  /* ---- Surfaces: neutral slate, so the one blue reads as emphasis -------- */
  --page: #0b0d10;
  --surface: #12151a;
  --surface-2: #171b21;
  --surface-3: #1e232b;

  /* Text — all verified >= 4.5:1 on --page, --surface and --surface-2 */
  --ink: #e8eaed;      /* 15.18:1 */
  --ink-2: #a6adb8;    /*  8.09:1 */
  --muted: #868f9b;    /*  5.59:1 (was #5f6f88 at 3.60:1 — failed AA) */

  /* Lines. Hairlines are decoration; --border-input identifies a control
     and therefore clears 3:1 against the field it outlines. */
  --border: #242a33;
  --border-strong: #2f3742;
  --border-input: #666d78;
  --grid: var(--border);
  --baseline: var(--border-strong);

  /* ---- Accent: one colour, four jobs ------------------------------------
     primary button · focus ring · active-nav marker · single-series data. */
  --accent: #2f6fe0;
  --accent-hover: #2560c9;
  --accent-active: #1e50ad;
  --accent-ink: #ffffff;         /* 4.70:1 on --accent */
  --accent-strong: #7fb3ff;      /* accent AS TEXT on dark — 8.53:1 */
  --tint: rgba(47, 111, 224, 0.14);
  --wash: rgba(47, 111, 224, 0.10);
  --wash-strong: rgba(47, 111, 224, 0.38);
  --row-hover: rgba(255, 255, 255, 0.035);
  --focus: #7fb3ff;

  /* Brand family retained for the logo mark only */
  --brand-blue: #2f6fe0;
  --brand-azure: #0e9fe0;
  --brand-teal: #06b8cf;
  --brand-cyan: #06ccd6;

  /* ---- Semantic states — text-safe variants are the *-text tokens ---- */
  --good: #2fa96a;      --good-text: #4ec77f;    /* 8.54:1 */
  --warning: #cf9430;   --warning-text: #e0a53a; /* 8.37:1 */
  --critical: #e2564f;  --critical-text: #f6807c;/* 7.23:1 */
  --critical-base: #e2564f;
  --serious: var(--warning);
  --gold: var(--warning-text);   /* escalation */

  /* data marks — single series */
  --seq-1: #1f3357; --seq-2: #27538f; --seq-3: #2f6fe0; --seq-4: #7fb3ff;
  --data: #2f6fe0;

  /* categorical series — kept from the validated set (CVD-checked, >=3:1) */
  --c1: #2f6fe0;  /* blue   */
  --c2: #199e70;  /* green  */
  --c3: #c98500;  /* amber  */
  --c4: #9085e9;  /* violet */

  /* ---- Elevation: two levels, no glow ---- */
  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.30);
  --shadow-2: 0 4px 12px rgba(0, 0, 0, 0.36), 0 1px 3px rgba(0, 0, 0, 0.28);
  --shadow-btn: none;
  --ring: 0 0 0 2px var(--surface), 0 0 0 4px var(--focus);

  --ghost-bg: transparent;
  --ghost-bg-hover: rgba(255, 255, 255, 0.055);
  --input-bg: #0f1216;
  --skel-a: #171b21;
  --skel-b: #21262e;
  --scroll-thumb: #2f3742;
}

/* Light theme — the topbar toggle. Same neutral ramp inverted; every text
   token re-verified against #ffffff, #f7f8f9 AND #f2f3f5, because muted text
   lands on all three. */
[data-theme="light"] {
  --page: #f7f8f9;
  --surface: #ffffff;
  --surface-2: #f2f3f5;
  --surface-3: #e9ebee;

  --ink: #14181d;      /* 17.82:1 */
  --ink-2: #5a626d;    /*  6.17:1 */
  --muted: #646b75;    /*  5.38:1 on white, 4.85:1 on --surface-2
                          (was #9ca3af at 2.54:1 — failed AA outright) */

  --border: #e3e6ea;
  --border-strong: #d3d8de;
  --border-input: #8d939c;   /* 3:1 against a white field */
  --grid: var(--border);
  --baseline: var(--border-strong);

  --accent: #2f6fe0;
  --accent-hover: #2560c9;
  --accent-active: #1e50ad;
  --accent-ink: #ffffff;
  --accent-strong: #1d4ed8;      /* accent as text on light — 6.70:1 */
  --tint: #eef3fd;
  --wash: #f4f7fe;
  --wash-strong: rgba(47, 111, 224, 0.32);
  --row-hover: rgba(15, 23, 42, 0.028);
  --focus: #1d4ed8;

  --good: #1a8f52;      --good-text: #15803d;    /* 5.02:1 */
  --warning: #b0700c;   --warning-text: #a1620a; /* 4.92:1 */
  --critical: #c62c2c;  --critical-text: #b91c1c;/* 6.47:1 */
  --critical-base: #c62c2c;
  --serious: var(--warning);
  --gold: var(--warning-text);

  --seq-1: #d7e4f9; --seq-2: #8fb2ee; --seq-3: #2f6fe0; --seq-4: #1e50ad;
  --data: #2f6fe0;

  /* categorical series (validated on #ffffff) */
  --c1: #2f6fe0;
  --c2: #1baf7a;
  --c3: #eda100;
  --c4: #4a3aa7;

  --shadow-1: 0 1px 2px rgba(15, 23, 42, 0.05);
  --shadow-2: 0 4px 12px rgba(15, 23, 42, 0.09), 0 1px 3px rgba(15, 23, 42, 0.05);
  --shadow-btn: none;
  --ring: 0 0 0 2px var(--surface), 0 0 0 4px var(--focus);

  --ghost-bg: transparent;
  --ghost-bg-hover: rgba(15, 23, 42, 0.045);
  --input-bg: #ffffff;
  --skel-a: #eaecef;
  --skel-b: #f4f5f7;
  --scroll-thumb: #c8cdd4;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }
body {
  font-family: var(--font-ui);
  font-size: var(--fs-4); line-height: var(--lh-body); color: var(--ink);
  background: var(--page);   /* flat. no glows, no grid overlay */
  -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility;
  font-variant-numeric: tabular-nums;
}
#root { position: relative; }
button { font: inherit; cursor: pointer; color: inherit; background: none; border: none; }
input, select, textarea { font: inherit; color: var(--ink); }
a { color: var(--accent-strong); text-decoration: none; transition: color var(--dur-2); }
a:hover { color: var(--accent-strong); text-decoration: underline; }

/* Numbers-as-data. Applied by class so prose never turns monospace. */
.mono, .num, td.num, .sla-pill, .sla-kpi .c, .tile .v, code.knum,
.kbd, .attach-chip .asz, .owner-bar .val, .tile .delta {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* One focus treatment everywhere: a 2px ring held off the element by a
   surface-coloured spacer, so it reads on any background. */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}
/* Mouse users don't get the ring, keyboard users always do. */
:focus:not(:focus-visible) { outline: none; }

/* #main is a programmatic focus target — it receives focus after a navigation
   and from the skip link so the keyboard starts at the content. It is not a
   control, and a ring drawn around the entire content area is just noise; the
   screen change and the screen-reader announcement are the feedback. */
#main:focus, #main:focus-visible { outline: none; }

/* ---- Motion primitives -------------------------------------------------
   Two short movements, reused everywhere: a fade for scrims, and a 4px rise
   for anything that appears over the page (modals, menus, popovers). */
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes rise-in {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
}

/* Applied by toggleTheme() for one frame while the theme attribute flips.
   Blink will not re-resolve var() inside a transitioned property when only a
   custom property changed, which left transitioned colours showing the
   OUTGOING theme. Killing transitions across the swap forces a clean recalc —
   and a theme change should land instantly, not animate. */
.theme-swap, .theme-swap *, .theme-swap *::before, .theme-swap *::after {
  transition: none !important;
}

/* ---- Icons ---- */
svg.ic {
  width: 16px; height: 16px; stroke: currentColor; fill: none;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
  vertical-align: -3px; flex: 0 0 auto;
}
svg.ic.sm { width: 14px; height: 14px; vertical-align: -2px; }
svg.ic.lg { width: 22px; height: 22px; }

/* ---- App shell ---- */
#app { display: flex; flex-direction: column; height: 100vh; }
/* Topbar: the reference app bar — dark glass in BOTH themes, blur + saturate.
   Brand anchors left, actions anchor right, and the search pill is absolutely
   centered on the bar itself (not merely between the unequal side groups). */
.topbar {
  position: relative;
  display: flex; align-items: center;
  gap: var(--sp-3); padding: 0 var(--sp-4); height: var(--topbar-h);
  background: var(--surface);
  border-bottom: 1px solid var(--border); flex: 0 0 auto;
}
.topbar .brand {
  display: flex; align-items: center; gap: 10px; white-space: nowrap; min-width: 0;
}
/* Brand, then search, then actions pushed right by auto margin. The search
   field used to be absolutely centred on the bar, which meant it drifted out
   of alignment with everything else and had to be re-hacked at every width. */
.topbar-actions { display: flex; align-items: center; gap: var(--sp-1); margin-left: auto; }
.topbar .searchbtn { margin-left: var(--sp-4); flex: 0 1 300px; }
@media (max-width: 900px) {
  .topbar { padding: 0 var(--sp-3); }
  /* search collapses to a square icon button; the label and keycap go */
  .topbar .searchbtn {
    flex: 0 0 auto; margin-left: var(--sp-2);
    width: 32px; height: 32px; padding: 0; justify-content: center;
  }
}
@media (max-width: 640px) {
  .topbar .brand .wordmark { display: none; } /* logo stays; text yields space */
}
.topbar .brand .wordmark {
  font-weight: var(--fw-semi); font-size: var(--fs-5);
  letter-spacing: -0.017em; color: var(--ink);
}
.topbar .brand .wm-accent { color: var(--accent-strong); }
.topbar .spacer { flex: 1; }

.icon-btn {
  width: 32px; height: 32px; border-radius: var(--r-md); border: 1px solid transparent;
  background: transparent; color: var(--ink-2);
  display: inline-flex; align-items: center; justify-content: center;
  transition: background .15s, color .15s, border-color .15s;
}
.icon-btn:hover { background: var(--ghost-bg-hover); color: var(--ink); }
.icon-btn svg.ic { vertical-align: 0; }

.shell { display: flex; flex: 1; min-height: 0; }
/* Keyboard users get a way past the chrome; it only appears when focused. */
.skip-link {
  position: absolute; left: var(--sp-3); top: -40px; z-index: 100;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  padding: var(--sp-2) var(--sp-3); font-size: var(--fs-3); font-weight: var(--fw-med);
  transition: top var(--dur-2);
}
.skip-link:focus { top: var(--sp-2); text-decoration: none; }

.sidenav {
  width: var(--sidenav-w); flex: 0 0 auto; background: var(--surface);
  border-right: 1px solid var(--border);
  padding: var(--sp-3) var(--sp-2); overflow-y: auto;
}
.nav-group + .nav-group { margin-top: var(--sp-4); }
.nav-group-t {
  font-size: var(--fs-1); font-weight: var(--fw-semi); color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.07em;
  padding: 0 var(--sp-3) var(--sp-2);
}
.sidenav a {
  position: relative;   /* anchors the .active marker */
  display: flex; align-items: center; gap: var(--sp-3);
  padding: 7px var(--sp-3); border-radius: var(--r-sm);
  color: var(--ink-2); font-weight: var(--fw-med); font-size: var(--fs-3);
  margin-bottom: 1px;
  transition: background var(--dur-2), color var(--dur-2);
}
.sidenav a svg.ic { width: 16px; height: 16px; vertical-align: 0; flex: 0 0 auto; }
.sidenav a:hover { background: var(--ghost-bg-hover); color: var(--ink); text-decoration: none; }
/* Active nav: a flat tint plus a 2px accent marker on the leading edge. The
   marker, not colour alone, is what says "you are here". */
.sidenav a.active {
  background: var(--tint); color: var(--accent-strong);
  font-weight: var(--fw-semi);
}
.sidenav a.active::before {
  content: ""; position: absolute; left: 0; top: 5px; bottom: 5px;
  width: 2px; border-radius: 0 1px 1px 0; background: var(--accent);
}

/* Tablet and below: collapse to an icon rail so the content keeps the width.
   The label is removed from the DOM flow rather than set to font-size:0, and
   each link carries aria-label + title so the name survives for both screen
   readers and hover. */
@media (max-width: 900px) {
  .sidenav { width: 52px; padding: var(--sp-2) var(--sp-1); }
  .sidenav a { justify-content: center; padding: var(--sp-2); gap: 0; }
  .sidenav a .nl { display: none; }
  .sidenav a.active::before { top: 3px; bottom: 3px; }
  /* group headings would be unreadable at 52px; the dividers carry the grouping */
  .nav-group-t { display: none; }
  .nav-group + .nav-group {
    margin-top: var(--sp-2); padding-top: var(--sp-2);
    border-top: 1px solid var(--border);
  }
}
.main { flex: 1; overflow-y: auto; padding: var(--sp-6) var(--sp-6) var(--sp-8); min-width: 0; }
/* Cap and centre every view's content on wide screens */
.main > * { max-width: var(--content-max); margin-inline: auto; }
@media (max-width: 900px) { .main { padding: var(--sp-4) var(--sp-4) var(--sp-7); } }
@media (max-width: 640px) { .main { padding: var(--sp-3) var(--sp-3) var(--sp-6); } }

/* ---- Generic UI ---- */
.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: var(--sp-4);
}
.row { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
.grid { display: grid; gap: 16px; }
/* ---- Page header --------------------------------------------------------
   Title → context → actions, closed with one hairline. Produced by pageHead()
   in app.js so the vertical rhythm is identical on all seven screens. */
.page-head { margin-bottom: var(--sp-5); }
.page-back {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  font-size: var(--fs-2); color: var(--ink-2); font-weight: var(--fw-med);
  margin-bottom: var(--sp-2);
}
.page-back:hover { color: var(--ink); text-decoration: none; }
.page-back svg.ic { width: 13px; height: 13px; }
.page-head-row {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--sp-4); flex-wrap: wrap;
  padding-bottom: var(--sp-3); border-bottom: 1px solid var(--border);
}
.page-head-t { min-width: 0; }
.page-head-t .sub { margin-top: 1px; }
.page-head-a { display: flex; align-items: center; gap: var(--sp-2); flex: 0 0 auto; }
@media (max-width: 640px) {
  .page-head-a { width: 100%; }
  .page-head-a .btn { flex: 1; }
}

/* Headings sit on the scale. A page title at 20px leaves the emphasis budget
   for the data instead of spending it on the word "Cases". */
h1 {
  font-size: var(--fs-7); font-weight: var(--fw-semi);
  letter-spacing: -0.011em; line-height: var(--lh-tight);
}
h2 {
  font-size: var(--fs-5); font-weight: var(--fw-semi);
  letter-spacing: -0.008em; line-height: var(--lh-tight);
  margin-bottom: var(--sp-3); display: flex; align-items: center; gap: var(--sp-2);
}
h2 svg.ic { color: var(--muted); }
h3 {
  font-size: var(--fs-4); font-weight: var(--fw-semi);
  letter-spacing: -0.005em; line-height: var(--lh-snug);
}
.sub { color: var(--ink-2); font-size: var(--fs-3); line-height: var(--lh-body); }
.muted { color: var(--muted); }
.small { font-size: var(--fs-2); }
.mt { margin-top: 16px; }
.mb { margin-bottom: 16px; }

/* ---- Buttons -----------------------------------------------------------
   Four levels and one shape. .btn on its own is the SECONDARY control —
   bordered, transparent fill. Add .primary for the one action a screen is
   for, .ghost for tertiary, .danger for destructive. Feedback is colour
   only: buttons don't move, because a lift on every press reads as a toy.  */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  border: 1px solid var(--border-strong); background: var(--ghost-bg); color: var(--ink);
  padding: 6px var(--sp-3); min-height: 32px;
  border-radius: var(--r-sm);
  font-weight: var(--fw-med); font-size: var(--fs-3); white-space: nowrap;
  transition: background var(--dur-2), border-color var(--dur-2), color var(--dur-2);
}
.btn:hover { background: var(--ghost-bg-hover); border-color: var(--ink-2); }
.btn:active { background: var(--surface-3); }
.btn svg.ic { width: 14px; height: 14px; vertical-align: 0; }

/* Tertiary: no chrome until you touch it. For actions that must be present
   but should not compete — "Cancel", row-level links, overflow triggers. */
.btn.ghost { border-color: transparent; color: var(--ink-2); }
.btn.ghost:hover { border-color: transparent; background: var(--ghost-bg-hover); color: var(--ink); }
.btn.primary {
  background: var(--accent); border-color: var(--accent); color: var(--accent-ink);
}
.btn.primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.btn.primary:active { background: var(--accent-active); border-color: var(--accent-active); }
/* Destructive: red text, red edge on approach. Reserved for actions that
   remove data, and always paired with a confirmation. */
.btn.danger { color: var(--critical-text); border-color: var(--border-strong); }
.btn.danger:hover {
  background: color-mix(in srgb, var(--critical) 12%, transparent);
  border-color: var(--critical); color: var(--critical-text);
}
.btn.danger.solid {
  background: var(--critical); border-color: var(--critical); color: #ffffff;
}
.btn.danger.solid:hover { background: color-mix(in srgb, var(--critical) 86%, #000); }

.btn.small { padding: 3px var(--sp-2); min-height: 26px; font-size: var(--fs-2); gap: var(--sp-1); }
.btn.small svg.ic { width: 13px; height: 13px; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
/* In-flight: the label stays put and a spinner replaces the icon, so the
   button never changes width mid-request. */
.btn.busy { pointer-events: none; opacity: .75; }
.btn.busy svg.ic { animation: spin .7s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ---- Fields -------------------------------------------------------------
   One height (32px), one radius, and a border that clears 3:1 against the
   field fill so the control's boundary is actually identifiable. */
input[type="text"], input[type="number"], input[type="email"], input[type="password"],
input[type="datetime-local"], input[type="date"], input[type="search"], select, textarea {
  background: var(--input-bg); border: 1px solid var(--border-input);
  border-radius: var(--r-sm);
  padding: 6px var(--sp-3); width: 100%;
  font-size: var(--fs-3); line-height: 1.35; min-height: 32px;
  transition: border-color var(--dur-2), box-shadow var(--dur-2);
}
select { cursor: pointer; }
input::placeholder, textarea::placeholder { color: var(--muted); }
input:hover, select:hover, textarea:hover { border-color: var(--ink-2); }
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--accent); box-shadow: var(--ring);
}
input:disabled, select:disabled, textarea:disabled {
  opacity: .55; cursor: not-allowed; background: var(--surface-2);
}
textarea { min-height: 76px; resize: vertical; line-height: var(--lh-body); }

/* Invalid field: red border AND a message — never colour alone. */
input.invalid, select.invalid, textarea.invalid { border-color: var(--critical); }
.field-err {
  display: flex; align-items: flex-start; gap: var(--sp-1); margin-top: var(--sp-1);
  font-size: var(--fs-2); color: var(--critical-text);
}
.field-err svg.ic { width: 13px; height: 13px; flex: 0 0 auto; margin-top: 1px; }

label.f { display: block; margin-bottom: var(--sp-4); }
label.f > span {
  display: block; font-size: var(--fs-2); font-weight: var(--fw-med);
  color: var(--ink-2); margin-bottom: var(--sp-1);
}
/* Optional is the exception worth marking; required is the norm on these forms. */
label.f > span .opt { color: var(--muted); font-weight: var(--fw-normal); }
label.f > span .req { color: var(--critical-text); margin-left: 2px; }
.field-hint { font-size: var(--fs-2); color: var(--muted); margin-top: var(--sp-1); }

.form-2col { display: grid; grid-template-columns: 1fr 1fr; gap: 0 var(--sp-4); }
@media (max-width: 640px) { .form-2col { grid-template-columns: 1fr; } }

/* Grouped sections inside long forms, so a big dialog reads as a few short
   ones rather than a wall of inputs. */
.form-sec { border-top: 1px solid var(--border); margin-top: var(--sp-4); padding-top: var(--sp-4); }
.form-sec:first-child { border-top: none; margin-top: 0; padding-top: 0; }
.form-sec > .form-sec-t {
  font-size: var(--fs-1); font-weight: var(--fw-semi); color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: var(--sp-3);
}

/* ---- Checkbox / radio ---------------------------------------------------
   Admin previously shipped raw browser checkboxes — the one place the design
   system stopped. These are the native controls, restyled and still native. */
input[type="checkbox"], input[type="radio"] {
  appearance: none; -webkit-appearance: none;
  width: 16px; height: 16px; min-height: 0; flex: 0 0 auto; padding: 0;
  border: 1px solid var(--border-input); background: var(--input-bg);
  border-radius: var(--r-xs); cursor: pointer; position: relative;
  transition: background var(--dur-1), border-color var(--dur-1);
}
input[type="radio"] { border-radius: var(--r-full); }
input[type="checkbox"]:hover, input[type="radio"]:hover { border-color: var(--ink-2); }
input[type="checkbox"]:checked, input[type="radio"]:checked {
  background: var(--accent); border-color: var(--accent);
}
/* the tick is drawn, not a font glyph, so it never depends on an icon set */
input[type="checkbox"]:checked::after {
  content: ""; position: absolute; left: 4px; top: 1px;
  width: 6px; height: 10px; border: solid var(--accent-ink);
  border-width: 0 2px 2px 0; transform: rotate(42deg);
}
input[type="radio"]:checked::after {
  content: ""; position: absolute; inset: 3px;
  border-radius: var(--r-full); background: var(--accent-ink);
}
input[type="checkbox"]:disabled, input[type="radio"]:disabled { opacity: .5; cursor: not-allowed; }

/* Clickable label wrapping a checkbox — gives the control a real hit area. */
label.check {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-3); color: var(--ink); cursor: pointer;
  padding: var(--sp-1) 0; min-height: 28px;
}

/* ---- Badges (status colours always paired with a label, never colour-alone) ---- */
.badge {
  display: inline-flex; align-items: center; gap: var(--sp-1); padding: 2px 7px;
  border-radius: var(--r-sm); font-size: var(--fs-1); font-weight: var(--fw-med);
  border: 1px solid var(--border);
  color: var(--ink-2); white-space: nowrap; background: var(--surface);
}
.badge svg.ic { width: 12px; height: 12px; vertical-align: 0; }
.badge .dot { width: 6px; height: 6px; border-radius: var(--r-full); background: var(--muted); flex: 0 0 auto; }
.badge.p-low .dot { background: var(--baseline); }
.badge.p-normal .dot { background: var(--brand-azure); }
.badge.p-high .dot { background: var(--warning); }
.badge.p-urgent .dot { background: var(--critical); }
.badge.s-active .dot { background: var(--brand-azure); }
.badge.s-resolved .dot { background: var(--good); }
.badge.s-cancelled .dot, .badge.s-merged .dot { background: var(--muted); }
.badge.esc { color: var(--gold); border-color: color-mix(in srgb, var(--gold) 45%, transparent); }

/* ---- Tables (reference: recessed uppercase header band, brand-tint row hover) ---- */
table.list { width: 100%; border-collapse: collapse; }
table.list th {
  text-align: left; font-size: var(--fs-1); color: var(--muted);
  font-weight: var(--fw-semi); text-transform: uppercase; letter-spacing: 0.055em;
  padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
table.list td {
  padding: var(--sp-3); border-bottom: 1px solid var(--border);
  vertical-align: middle; font-size: var(--fs-3);
}
/* The title column carries the weight. It also absorbs the leftover width and
   ellipses instead of pushing the table wider: max-width:1px with width:100%
   is the reliable way to make a table cell shrink-and-truncate, since a plain
   max-width in px is still overridden by the table's intrinsic sizing. */
table.list td.t-main { font-weight: var(--fw-med); color: var(--ink); }
table.list td.t-trunc {
  max-width: 1px; width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Compact variant for a table inside a narrow dashboard card: the outer cells
   give up their padding to the card's own, which is what stopped the at-risk
   table from fitting. */
table.list.compact td { padding: var(--sp-2) var(--sp-2); }
table.list.compact td:first-child { padding-left: 0; }
table.list.compact td:last-child { padding-right: 0; }
table.list.compact tr:last-child td { border-bottom: none; }

/* Secondary columns clip at a sane ceiling but never absorb spare width. */
table.list td.c-clip {
  max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.esc-flag { color: var(--warning-text); }
table.list tbody tr { transition: background .12s; }
table.list tbody tr:hover { background: var(--row-hover); cursor: pointer; }
table.list tbody tr:last-child td { border-bottom: none; }
table.list td.num, table.list th.num { text-align: right; font-variant-numeric: tabular-nums; }
/* Scroll wide tables inside their card instead of bleeding past its edge */
.table-wrap { overflow-x: auto; }

/* ---- Routing-rule drag reorder ---- */
.rule-row[draggable="true"] { cursor: default; }
.rule-order { white-space: nowrap; }
.drag-grip {
  display: inline-flex; align-items: center; color: var(--muted);
  cursor: grab; vertical-align: middle; margin-right: 2px; touch-action: none;
}
.drag-grip:active { cursor: grabbing; }
.drag-grip svg.ic { width: 15px; height: 15px; vertical-align: 0; }
.rule-row.dragging { opacity: .4; background: var(--tint); }
/* border-collapse eats row borders, so draw the drop line with an inset shadow */
.rule-row.drop-above td { box-shadow: inset 0 2px 0 0 var(--accent); }
.rule-row.drop-below td { box-shadow: inset 0 -2px 0 0 var(--accent); }

/* ---- Chips / saved views (reference pill-nav: gradient active pill) ---- */
.chips { display: flex; gap: 8px; flex-wrap: wrap; }
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--border-strong); background: var(--ghost-bg); border-radius: var(--r-sm);
  padding: 5px var(--sp-3); font-size: var(--fs-2); color: var(--ink-2); font-weight: var(--fw-med);
  transition: background .15s, color .15s, border-color .15s;
}
.chip:hover { background: var(--ghost-bg-hover); color: var(--ink); text-decoration: none; }
/* Selected filter: a solid accent fill, no glow. Reads as "applied", and the
   selected state survives greyscale because the fill/text invert. */
.chip.active {
  background: var(--accent); color: var(--accent-ink); border-color: var(--accent);
}
.chip.active:hover { background: var(--accent-hover); border-color: var(--accent-hover); }

/* ---- Dashboard (reference KPI cards: uppercase labels, Poppins values) ---- */
/* auto-fit + minmax(0,…) so five tiles wrap instead of running off-screen —
   the old 168px floor with no wrap is what clipped the SLA card. */
.tiles {
  display: grid; gap: var(--sp-3);
  grid-template-columns: repeat(auto-fit, minmax(min(170px, 100%), 1fr));
}
.tile {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: var(--sp-3) var(--sp-4);
  transition: border-color var(--dur-2);
}
.tile .k {
  font-size: var(--fs-1); color: var(--muted); font-weight: var(--fw-med);
  text-transform: uppercase; letter-spacing: 0.055em;
  display: flex; align-items: center; gap: var(--sp-2);
}
.tile .k svg.ic { width: 14px; height: 14px; color: var(--muted); vertical-align: 0; }
.tile .v {
  font-family: var(--font-mono);
  font-size: var(--fs-8); font-weight: var(--fw-med);
  letter-spacing: -0.02em; margin-top: var(--sp-1); line-height: var(--lh-tight);
}
.tile .d { font-size: var(--fs-2); color: var(--muted); margin-top: 2px; }
.tile .v.good { color: var(--good-text); }
.tile .v.bad { color: var(--critical-text); }

/* ---- Charts ----
   Thin marks, 4px rounded data-ends (square at the baseline), hairline
   recessive grid, direct labels in text tokens, hover tooltips. Series
   colors come from the validated --c1..--c4 slots; single-series charts
   use --data. */

/* Horizontal bars */
.hbar { display: grid; grid-template-columns: 128px 1fr 52px; gap: 10px 12px; align-items: center; }
.hbar .lab { font-size: 12.5px; color: var(--ink-2); text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hbar .track { height: 10px; position: relative; background: var(--surface-2); border-radius: 0 4px 4px 0; }
.hbar .fill { position: absolute; inset: 0 auto 0 0; background: var(--data); border-radius: 0 4px 4px 0; min-width: 2px; transition: width .35s cubic-bezier(.2,.7,.2,1); }
.hbar .fill.over { background: var(--critical); }
.hbar .val { font-size: 12px; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.hbar .cap-mark { position: absolute; top: -3px; bottom: -3px; width: 2px; background: var(--baseline); border-radius: 1px; }

/* Donut (part-to-whole, ≤ 6 slices) + legend */
.donut-wrap { display: flex; align-items: center; gap: 24px; flex-wrap: wrap; }
.donut-wrap svg { flex: 0 0 auto; }
.donut-center-n {
  font-family: var(--font-display); font-size: 26px; font-weight: 700;
  fill: var(--ink);
}
.donut-center-l { font-size: 10px; font-weight: 600; letter-spacing: 0.07em; text-transform: uppercase; fill: var(--muted); }
.donut-seg { transition: opacity .15s; cursor: default; }
.donut-wrap:has(.donut-seg:hover) .donut-seg:not(:hover) { opacity: .45; }
.vlegend { display: flex; flex-direction: column; gap: 8px; min-width: 0; flex: 1; }
.vlegend .li { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--ink-2); }
.vlegend .sw { width: 10px; height: 10px; border-radius: 3px; flex: 0 0 auto; }
.vlegend .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vlegend .n { margin-left: auto; font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
.vlegend .pc { color: var(--muted); font-variant-numeric: tabular-nums; width: 38px; text-align: right; }

/* Line / area trend */
.trend svg { display: block; width: 100%; height: auto; }
.trend .grid-line { stroke: var(--grid); stroke-width: 1; }
.trend .baseline { stroke: var(--baseline); stroke-width: 1; }
.trend .axis-t { font-size: 10px; fill: var(--muted); }
.trend .tick-t { font-size: 10px; fill: var(--muted); font-variant-numeric: tabular-nums; }
.trend .lbl-t { font-size: 11px; font-weight: 600; fill: var(--ink); font-variant-numeric: tabular-nums; }
.trend .hover-dot { opacity: 0; pointer-events: none; transition: opacity .1s; }

/* Dashboard chart grid */
.charts { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }
@media (min-width: 980px) { .charts .span2 { grid-column: span 2; } }
/* Phones: single column (the 320px track minimum would overflow), tighter
   main padding, and wide tables scroll inside their card instead of the page */
@media (max-width: 560px) {
  .main { padding: 16px 12px 32px; }
  .charts { grid-template-columns: 1fr; }
  .charts .card { overflow-x: auto; }
}

/* Cases by owner — bar chart: avatar + name | rounded bar with the count
   riding its end. Bars grow in on load (staggered), hover lifts the row. */
.owner-rows { display: grid; gap: 12px; }
.owner-row {
  display: grid; grid-template-columns: minmax(110px, 170px) 1fr;
  gap: 12px; align-items: center;
  border-radius: var(--radius-sm); padding: 2px 4px;
  transition: background .15s ease;
}
.owner-row:hover { background: var(--row-hover); }
.owner-row .owner-id { min-width: 0; }
.owner-bar { display: flex; align-items: center; gap: 8px; min-width: 0; }
.owner-bar .fill {
  display: block; height: 12px; border-radius: 999px;
  width: var(--w, 0%); min-width: 4px; flex: 0 1 auto;
  background: var(--data);
  animation: owner-grow .7s var(--ease) backwards;
}
.owner-bar .fill.un { background: var(--muted); box-shadow: none; }
.owner-bar .val {
  font-family: var(--font-display); font-size: 12.5px; font-weight: 700;
  color: var(--ink); font-variant-numeric: tabular-nums; flex: 0 0 auto;
}
@keyframes owner-grow { from { width: 0; } }
@media (prefers-reduced-motion: reduce) { .owner-bar .fill { animation: none; } }
.av-un {
  width: 24px; height: 24px; border-radius: 7px; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--ghost-bg-hover); color: var(--muted);
  border: 1px solid var(--baseline);
}
/* Narrow screens: name takes its own line, the bar gets the full width */
@media (max-width: 560px) {
  .owner-row { grid-template-columns: 1fr; gap: 6px; }
}

/* Shared chart tooltip */
#viz-tip {
  position: fixed; z-index: 80; pointer-events: none; display: none;
  background: var(--surface-3); color: var(--ink); border-radius: var(--radius-sm);
  border: 1px solid var(--baseline);
  padding: 6px 10px; font-size: 12px; font-weight: 500; line-height: 1.45;
  box-shadow: var(--shadow-2); max-width: 260px;
}
#viz-tip b { font-weight: 700; }

/* ---- Knowledge cards ---- */
.art-t { margin-top: var(--sp-2); }
.art-x { margin-top: var(--sp-1); }
.art-m { margin-top: var(--sp-2); }

/* ---- Case detail header ---- */
.case-head { display: flex; align-items: flex-start; gap: var(--sp-4); flex-wrap: wrap; }
.case-head .case-t {
  font-size: var(--fs-6); margin-top: var(--sp-2);
  line-height: var(--lh-snug); overflow-wrap: anywhere;
}
.case-head .meta {
  display: flex; gap: var(--sp-3) var(--sp-5); flex-wrap: wrap; margin-top: var(--sp-3);
}
.case-head .meta .m { font-size: var(--fs-3); color: var(--ink); min-width: 0; }
.case-head .meta .m b {
  display: block; font-size: var(--fs-1); color: var(--muted);
  font-weight: var(--fw-med); text-transform: uppercase; letter-spacing: 0.05em;
  margin-bottom: 1px;
}
/* The SLA panel on case detail. Single definition — this used to be declared
   twice (right-aligned/184px here, then left-aligned/224px 300 lines later),
   which is what clipped the meter labels. */
.sla-widget {
  text-align: left;
  flex: 0 1 264px; min-width: 232px;
  background: var(--surface-2);
  border: 1px solid var(--border); border-radius: var(--r-md);
  padding: var(--sp-3) var(--sp-4);
}
/* ---- The SLA instrument -------------------------------------------------
   The signature element. Label, then the time as the largest thing in the
   panel, then a hairline rail. The label used to sit BESIDE the value and got
   ellipsed to "First resp..." whenever the value was long ("35m 01s overdue");
   stacking them removes the competition for width entirely. */
.sla-kpi { margin-bottom: var(--sp-3); }
.sla-kpi:last-child { margin-bottom: 0; }
.sla-kpi .t {
  font-size: var(--fs-1); color: var(--muted); font-weight: var(--fw-med);
  text-transform: uppercase; letter-spacing: 0.055em;
}
.sla-kpi .c {
  font-family: var(--font-mono);
  font-size: var(--fs-5); font-weight: var(--fw-med);
  letter-spacing: -0.02em; font-variant-numeric: tabular-nums;
  display: inline-flex; align-items: center; gap: var(--sp-1);
  margin-top: 1px;
}
.sla-kpi .c svg.ic { width: 14px; height: 14px; vertical-align: 0; flex: 0 0 auto; }
.sla-kpi .c.warn { color: var(--warning-text); }
.sla-kpi .c.breach { color: var(--critical-text); }
.sla-kpi .c.met { color: var(--good-text); }

/* BPF stage bar */
.bpf { display: flex; gap: 4px; margin: 16px 0; }
.bpf button {
  flex: 1; border: 1px solid var(--border); background: var(--surface); color: var(--ink-2);
  padding: 8px; font-weight: 600; font-size: 12.5px; position: relative;
  transition: background .15s, color .15s;
}
.bpf button:first-child { border-radius: 8px 4px 4px 8px; }
.bpf button:last-child { border-radius: 4px 8px 8px 4px; }
.bpf button:not(:first-child):not(:last-child) { border-radius: 4px; }
.bpf button.done { background: var(--tint); color: var(--accent-strong); border-color: transparent; }
/* Current stage: tinted, accent-texted, and marked with a 2px underline so the
   position in the process survives greyscale and colour-blindness. */
.bpf button.current {
  background: var(--tint); color: var(--accent-strong);
  border-color: var(--wash-strong);
}
.bpf button.current::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0;
  height: 2px; background: var(--accent);
}
.bpf button:disabled { cursor: default; opacity: .7; }

.case-body { display: grid; grid-template-columns: minmax(0, 1fr) 370px; gap: 16px; }
@media (max-width: 1000px) { .case-body { grid-template-columns: 1fr; } }

/* Tabs scroll horizontally rather than wrapping — Admin has nine of them. */
.tabs {
  display: flex; gap: var(--sp-1); border-bottom: 1px solid var(--border);
  margin-bottom: var(--sp-4); overflow-x: auto; scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tabs button {
  padding: var(--sp-2) var(--sp-3); font-weight: var(--fw-med); font-size: var(--fs-3);
  color: var(--ink-2); white-space: nowrap;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  transition: color var(--dur-2), border-color var(--dur-2);
}
.tabs button:hover { color: var(--ink); }
.tabs button.active { color: var(--accent-strong); border-bottom-color: var(--accent); }

/* Timeline */
.timeline-item { display: flex; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--grid); }
.timeline-item:last-child { border-bottom: none; }
.timeline-item .ico {
  width: 32px; height: 32px; border-radius: 8px; background: var(--tint); color: var(--accent-strong);
  display: flex; align-items: center; justify-content: center; flex: 0 0 auto;
}
.timeline-item .ico svg.ic { width: 15px; height: 15px; vertical-align: 0; }
.timeline-item .bd { min-width: 0; flex: 1; }
.timeline-item .bd .s { font-weight: 600; font-size: 13px; }
.timeline-item .bd .b { font-size: 13px; color: var(--ink-2); white-space: pre-wrap; margin-top: 2px; }
.timeline-item .bd .m2 { font-size: 11.5px; color: var(--muted); margin-top: 4px; }
.timeline-item.open .ico { background: color-mix(in srgb, var(--gold) 16%, transparent); color: var(--gold); }

.composer {
  border: 1px solid var(--grid); border-radius: 12px; padding: 16px;
  margin-bottom: 16px; background: var(--surface-2);
}
.composer input[type="text"], .composer textarea { background: var(--surface); }
.composer .types { display: flex; gap: 6px; margin-bottom: 12px; flex-wrap: wrap; }
.composer .types button {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--border); background: var(--surface); border-radius: var(--r-sm);
  padding: 4px 10px; font-size: var(--fs-2); font-weight: var(--fw-med); color: var(--ink-2);
  transition: background .15s, color .15s;
}
.composer .types button svg.ic { width: 12.5px; height: 12.5px; vertical-align: 0; }
.composer .types button.active {
  background: var(--accent); color: var(--accent-ink); border-color: var(--accent);
}

/* ---- Modal (reference dialog: navy backdrop blur, radius-lg) ---- */
.overlay {
  position: fixed; inset: 0; background: rgba(6, 8, 11, 0.62);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 8vh var(--sp-4) var(--sp-4); z-index: var(--z-modal);
  animation: fade-in var(--dur-2) var(--ease);
}
/* Dialog. Three widths only: .narrow for a single decision, default for a
   form, .wide for an editor. The header is sticky so the title stays with the
   content on a long form, and actions sit bottom-right in reading order:
   cancel then confirm. */
.modal {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg);
  width: 100%; max-width: 560px; max-height: 88vh; overflow-y: auto;
  padding: var(--sp-5);
  box-shadow: var(--shadow-2);
  animation: rise-in var(--dur-3) var(--ease);
}
.modal.narrow { max-width: 420px; }
.modal.wide { max-width: 760px; }
.modal h2 { margin-bottom: var(--sp-4); font-size: var(--fs-5); }
.modal > .m-sub {
  color: var(--ink-2); font-size: var(--fs-3); margin: calc(var(--sp-4) * -1) 0 var(--sp-4);
}
.modal .actions {
  display: flex; justify-content: flex-end; gap: var(--sp-2);
  margin-top: var(--sp-5); padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
}
/* A destructive dialog names the consequence above the actions. */
.modal .danger-note {
  display: flex; gap: var(--sp-2); align-items: flex-start;
  background: color-mix(in srgb, var(--critical) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--critical) 34%, transparent);
  border-radius: var(--r-sm); padding: var(--sp-3);
  font-size: var(--fs-3); color: var(--ink);
}
.modal .danger-note svg.ic { color: var(--critical-text); flex: 0 0 auto; margin-top: 1px; }

/* ---- Notifications ---- */
.bell { position: relative; }
.bell .cnt {
  position: absolute; top: 1px; right: -2px; background: var(--critical-base); color: #fff;
  font-size: 9.5px; font-weight: 700; line-height: 1; border-radius: 999px;
  padding: 3px 5px; min-width: 16px;
  text-align: center; border: 2px solid #0a101d; /* ring matches the dark bar */
  font-variant-numeric: tabular-nums;
}
.notif-panel {
  position: absolute; right: 16px; top: 64px; width: 368px; max-height: 60vh; overflow-y: auto;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-2); z-index: 40; padding: 8px;
}
.notif-panel .notif-head {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  padding: 8px 12px 8px; font-weight: 700; font-size: 13.5px;
  border-bottom: 1px solid var(--grid); margin-bottom: 4px;
}
/* Rows are <button> elements now (they were divs with a click handler, so a
   keyboard user could not reach them) — hence the width/text-align reset. */
.notif-panel .n-item {
  display: flex; gap: var(--sp-2); align-items: flex-start;
  width: 100%; text-align: left;
  padding: var(--sp-2) var(--sp-3); border-radius: var(--r-sm); font-size: var(--fs-3);
  color: var(--ink);
}
.notif-panel .n-item:hover { background: var(--ghost-bg-hover); cursor: pointer; }
.notif-panel .n-item.unread { font-weight: var(--fw-semi); }
.notif-panel .n-item .nico {
  width: 26px; height: 26px; border-radius: var(--r-sm); flex: 0 0 auto;
  background: var(--tint); color: var(--accent-strong);
  display: flex; align-items: center; justify-content: center;
}
.notif-panel .n-item .nico svg.ic { width: 14px; height: 14px; vertical-align: 0; }
.notif-panel .n-item .nbd { min-width: 0; }
.notif-panel .n-item .t {
  font-size: 11px; color: var(--muted); font-weight: 400; margin-top: 2px;
  display: flex; align-items: center; gap: 6px;
}
.notif-panel .ndot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); }

/* ---- Login (sits on the body's navy glow + ledger grid; card carries the
   reference sign-in signature: a 4px blue→cyan gradient bar across the top) ---- */
.login-wrap {
  min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 24px;
  position: relative; z-index: 1;
}
.login-card {
  max-width: 424px; width: 100%; padding: 40px; border-radius: var(--radius-lg);
  box-shadow: var(--shadow-2); position: relative; overflow: hidden;
}
.login-card::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: var(--accent);
}
.login-card .mark { margin-bottom: 24px; }
.login-card h1 { font-size: 32px; }
/* Brand accent works inside the login card as well as the topbar */
.login-card h1 .wm-accent { color: var(--accent-strong); }
/* ---- SSO sign-in options ----
   A quiet "or" rule, then one full-width secondary button per provider. The
   brand marks keep their own colours; everything else is the standard button. */
.sso-sep {
  display: flex; align-items: center; gap: var(--sp-3);
  margin: var(--sp-4) 0; color: var(--muted); font-size: var(--fs-2);
}
.sso-sep::before, .sso-sep::after {
  content: ""; flex: 1; border-top: 1px solid var(--border);
}
.sso-btn {
  width: 100%; margin-bottom: var(--sp-2);
  color: var(--ink); text-decoration: none;
}
.sso-btn:hover { text-decoration: none; color: var(--ink); }
.sso-btn svg { flex: 0 0 auto; }

/* Secondary auth links: "Forgot password?", "Back to sign in" */
.auth-alt { font-size: 13px; text-align: right; }
.auth-alt a { color: var(--accent-strong); font-weight: 600; }
.auth-alt a:hover { color: var(--accent-strong); text-decoration: underline; }
.login-card .auth-alt:has(a[href="#/login"]) { text-align: center; }
.auth-note {
  display: flex; gap: 10px; align-items: flex-start;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 10px 14px;
  font-size: 12.5px; color: var(--ink-2); line-height: 1.5;
}
.auth-note svg.ic { color: var(--accent-strong); flex: 0 0 auto; margin-top: 1px; }

/* ---- Toasts (reference: surface panel with a status dot) ---- */
#toasts { position: fixed; bottom: 24px; right: 24px; display: flex; flex-direction: column; gap: 8px; z-index: 90; }
.toast {
  display: flex; align-items: flex-start; gap: var(--sp-2);
  background: var(--surface-3); color: var(--ink);
  padding: var(--sp-3); border-radius: var(--r-md);
  border: 1px solid var(--border-strong);
  font-size: var(--fs-3); max-width: 400px; box-shadow: var(--shadow-2);
  animation: rise-in var(--dur-3) var(--ease);
}
.toast::before {
  content: ""; margin-top: 5px; width: 8px; height: 8px;
  border-radius: var(--r-full); background: var(--accent); flex: 0 0 auto;
}
.toast.err::before { background: var(--critical); }
.toast.warn2::before { background: var(--warning); }

/* ---- Empty and error states -------------------------------------------
   An empty screen is an invitation to act, so .empty takes a headline, a line
   of explanation and an optional action. .empty.error is the same shape for a
   request that failed, and says what to do next rather than apologising. */
.empty {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: var(--sp-1); color: var(--ink-2);
  padding: var(--sp-8) var(--sp-4); font-size: var(--fs-3);
}
.empty svg.ic { width: 22px; height: 22px; color: var(--muted); margin-bottom: var(--sp-1); }
.empty .e-t { font-size: var(--fs-4); font-weight: var(--fw-semi); color: var(--ink); }
.empty .e-d { color: var(--muted); max-width: 42ch; line-height: var(--lh-body); }
.empty .btn { margin-top: var(--sp-3); }
.empty.error svg.ic { color: var(--critical-text); }
/* Compact variant for inside a card or a table cell. */
.empty.sm { padding: var(--sp-5) var(--sp-4); }
.kb-hit { border-bottom: 1px solid var(--grid); padding: 12px 2px; }
.kb-hit:last-child { border-bottom: none; }
.kb-hit .t { font-weight: 600; font-size: 13px; }
.tree-node { padding: 4px 0; }
code.knum {
  background: var(--tint); color: var(--accent-strong); border-radius: 6px; padding: 2px 8px;
  font-size: 11.5px; font-weight: 600; font-family: inherit; font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ---- User guide (role-specific help) ---- */
.guide { max-width: 880px; }
.guide p, .guide li { font-size: 13.5px; color: var(--ink-2); }
.guide p { margin: 6px 0; }
.guide ul, .guide ol { margin: 4px 0 8px; padding-left: 20px; }
.guide li { margin: 6px 0; }
.guide li::marker { color: var(--muted); }
.guide b { color: var(--ink); font-weight: 600; }
.guide .tip {
  display: flex; gap: 10px; align-items: flex-start;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: 10px;
  padding: 10px 14px; margin: 12px 0 2px; font-size: 13px; color: var(--ink-2);
}
.guide .tip svg.ic { color: var(--accent-strong); margin-top: 2px; }

/* ---- Brand entrance animation (logo + wordmark on load) ----
   The logo pops in with a slight rotate/scale settle; the name follows a beat
   later, sliding in from the left. Used on the login screen and, once per page
   load, in the topbar (.brand-enter is added only on the first shell render). */
@keyframes brand-logo-in {
  from { opacity: 0; transform: translateY(-6px) scale(0.7) rotate(-12deg); }
  60%  { opacity: 1; transform: translateY(0) scale(1.06) rotate(2deg); }
  to   { opacity: 1; transform: none; }
}
@keyframes brand-name-in {
  from { opacity: 0; transform: translateX(-10px); }
  to   { opacity: 1; transform: none; }
}
.topbar .brand.brand-enter > svg {
  animation: brand-logo-in 1.1s cubic-bezier(.34, 1.4, .5, 1) both;
}
.topbar .brand.brand-enter .wordmark {
  animation: brand-name-in .5s cubic-bezier(.2, .7, .2, 1) .16s both;
}
.login-card .mark > svg {
  animation: brand-logo-in 1.4s cubic-bezier(.34, 1.4, .5, 1) both;
}
.login-card h1 {
  animation: brand-name-in .6s cubic-bezier(.2, .7, .2, 1) .2s both;
}
@media (prefers-reduced-motion: reduce) {
  .topbar .brand.brand-enter > svg, .topbar .brand.brand-enter .wordmark,
  .login-card .mark > svg, .login-card h1 { animation: none; }
}

/* ---- Interactive feedback ----
   Colour and background only. Nothing translates on hover: the old 1px lift
   fired on every button, chip and nav item at once, which made the whole page
   feel loose. Cards and tiles have never moved and still don't. */
.icon-btn, .chip, .sidenav a,
.composer .types button, .notif-panel .n-item {
  transition: background var(--dur-2), color var(--dur-2), border-color var(--dur-2);
}

/* ---- Avatars (initials chips; hue is stable per person) ---- */
.avchip { display: inline-flex; align-items: center; gap: 8px; min-width: 0; max-width: 100%; }
.avchip .av {
  width: 24px; height: 24px; border-radius: 50%; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 700; letter-spacing: 0.02em; color: var(--ink);
  background: color-mix(in srgb, var(--av) 18%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--av) 36%, transparent);
}
.avchip.sq .av { border-radius: 7px; }
.avchip .avn { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; }

/* ---- SLA pills (tables) & meters (case detail) ---- */
.sla-pill {
  display: inline-flex; align-items: center; gap: var(--sp-1); padding: 2px 7px;
  border-radius: var(--r-sm); font-size: var(--fs-1); font-weight: var(--fw-med); white-space: nowrap;
  font-variant-numeric: tabular-nums;
  background: var(--surface-2); color: var(--ink-2); border: 1px solid var(--border);
}
.sla-pill svg.ic { width: 12px; height: 12px; vertical-align: 0; }
.sla-pill.ok { color: var(--accent-strong); background: var(--tint); border-color: color-mix(in srgb, var(--accent) 34%, transparent); }
.sla-pill.warn { color: var(--warning-text); background: color-mix(in srgb, var(--warning) 12%, var(--surface)); border-color: color-mix(in srgb, var(--warning) 38%, transparent); }
.sla-pill.breach { color: var(--critical-text); background: color-mix(in srgb, var(--critical) 12%, var(--surface)); border-color: color-mix(in srgb, var(--critical) 38%, transparent); }
.sla-pill.met { color: var(--good-text); background: color-mix(in srgb, var(--good) 10%, var(--surface)); border-color: color-mix(in srgb, var(--good) 32%, transparent); }

.sla-meter {
  position: relative; height: 4px; border-radius: var(--r-full); overflow: hidden;
  background: var(--surface-3); margin-top: var(--sp-2);
}
.sla-meter .f {
  position: absolute; inset: 0 auto 0 0; border-radius: 999px;
  background: var(--accent); min-width: 3px; transition: width 1s linear;
}
.sla-meter.warn { background: color-mix(in srgb, var(--warning) 18%, var(--surface)); }
.sla-meter.warn .f { background: var(--warning); }
.sla-meter.breach { background: color-mix(in srgb, var(--critical) 16%, var(--surface)); }
.sla-meter.breach .f { background: var(--critical); }
.sla-meter.met { background: color-mix(in srgb, var(--good) 14%, var(--surface)); }
.sla-meter.met .f { background: var(--good); }
.sla-meter.paused .f { background: var(--baseline); }

/* Label above value — no horizontal competition, so nothing truncates. */
.sla-kpi .row2 { display: block; min-width: 0; }

/* ---- Tables: sticky headers + sortable columns ---- */
table.list thead th {
  position: sticky; top: 0; z-index: var(--z-sticky); background: var(--surface-2);
  border-bottom: none; box-shadow: inset 0 -1px 0 var(--border);
}
th.sortable { cursor: pointer; user-select: none; white-space: nowrap; }
th.sortable:hover { color: var(--ink); }
th.sortable .si { display: inline-block; width: 10px; opacity: .9; margin-left: 2px; color: var(--accent-strong); }
/* A wide table scrolls inside its own card at EVERY width. This used to be
   gated behind a 900px query, so on a laptop the table pushed the whole page
   sideways instead — the page body must never scroll horizontally. */
.table-card { padding: 0; overflow-x: auto; }

/* Same guarantee for the cards that hold a table directly (Queues, Customers,
   Admin): the table scrolls inside its own card instead of handing the overflow
   up to .main. Scoped with :has so it never applies to cards containing a
   popover menu, which overflow-x would clip. */
.card:has(> table.list) { overflow-x: auto; }
td.right, th.right { text-align: right; }
td.nowrap { white-space: nowrap; font-variant-numeric: tabular-nums; }

/* ---- Command palette ---- */
.cmdk-overlay {
  position: fixed; inset: 0; background: rgba(6, 8, 11, 0.62);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 12vh var(--sp-4) var(--sp-4); z-index: var(--z-cmdk);
  animation: fade-in var(--dur-2) var(--ease);
}
.cmdk {
  width: 100%; max-width: 560px; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-2); overflow: hidden;
}
.cmdk input[type="text"] {
  border: none; border-bottom: 1px solid var(--grid); border-radius: 0;
  padding: 14px 16px; font-size: 15px; background: transparent;
}
.cmdk input[type="text"]:focus { box-shadow: none; border-color: var(--grid); }
.cmdk .res { max-height: min(420px, 55vh); overflow-y: auto; padding: 6px; }
.cmdk .grp {
  font-size: 11px; font-weight: 700; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.06em; padding: 10px 10px 4px;
}
.cmdk .it {
  display: flex; align-items: center; gap: 10px; padding: 9px 10px;
  border-radius: 8px; cursor: pointer; font-size: 13.5px; min-width: 0;
}
.cmdk .it > span:first-of-type { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cmdk .it svg.ic { color: var(--muted); flex: 0 0 auto; }
.cmdk .it .sub2 {
  color: var(--muted); font-size: 12px; margin-left: auto; padding-left: 12px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 45%; flex: 0 1 auto;
}
.cmdk .it.sel { background: var(--tint); }
.cmdk .it.sel svg.ic { color: var(--accent-strong); }
.cmdk .foot {
  display: flex; gap: 14px; padding: 8px 14px; border-top: 1px solid var(--grid);
  color: var(--muted); font-size: 11.5px;
}
.kbd {
  display: inline-block; border: 1px solid var(--border); border-bottom-width: 2px;
  border-radius: 6px; padding: 0 6px; font-size: 11px; font-weight: 600;
  color: var(--ink-2); background: var(--surface-2); font-family: inherit;
}
/* Search trigger. Theme-aware now — it used to carry fixed dark rgba values
   because the topbar was always dark. */
.searchbtn {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  border: 1px solid var(--border); background: var(--surface-2);
  color: var(--muted);
  border-radius: var(--r-md); padding: 5px var(--sp-2) 5px var(--sp-3);
  font-size: var(--fs-2); font-weight: var(--fw-normal); min-width: 0;
  transition: background var(--dur-2), color var(--dur-2), border-color var(--dur-2);
}
.searchbtn:hover { border-color: var(--border-strong); color: var(--ink-2); }
.searchbtn .kbd { margin-left: auto; }
.searchbtn svg.ic { width: 14px; height: 14px; }
@media (max-width: 900px) { .searchbtn .lbl, .searchbtn .kbd { display: none; } }

/* ---- Topbar: ghost icon buttons + avatar menu ---- */
.avbtn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 50%; padding: 0;
}
.avbtn .av2 {
  width: 28px; height: 28px; border-radius: var(--r-full);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: var(--fs-1); font-weight: var(--fw-semi); letter-spacing: 0.01em;
  color: var(--accent-ink); background: var(--accent);
}
.avbtn:hover .av2 { background: var(--accent-hover); }
.menuwrap { position: relative; }
.menu {
  position: absolute; right: 0; top: calc(100% + 8px); min-width: 200px; z-index: 60;
  background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
  box-shadow: var(--shadow-2); padding: 6px;
}
.menu .mhead { padding: 8px 10px 6px; border-bottom: 1px solid var(--grid); margin-bottom: 6px; }
.menu .mhead b { display: block; font-size: 13px; }
.menu .mhead i { font-style: normal; font-size: 11.5px; color: var(--muted); text-transform: capitalize; }
.menu button {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  padding: 8px 10px; border-radius: 8px; font-size: 13px; font-weight: 500; color: var(--ink);
}
.menu button:hover { background: var(--tint); color: var(--accent-strong); }
.menu button.danger2 { color: var(--critical-text); }
.menu button.danger2:hover {
  background: color-mix(in srgb, var(--critical) 12%, transparent);
  color: var(--critical-text);
}
.menu .sep { height: 1px; background: var(--grid); margin: 6px 4px; }

/* ---- Case action row: overflow menu shares .menu ---- */
.actions-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

/* ---- Timeline: type-coloured icons + day dividers ---- */
.timeline-item.t-email .ico { background: color-mix(in srgb, var(--c1) 14%, transparent); color: var(--c1); }
.timeline-item.t-call .ico { background: color-mix(in srgb, var(--c2) 14%, transparent); color: var(--c2); }
.timeline-item.t-task .ico { background: color-mix(in srgb, var(--c4) 14%, transparent); color: var(--c4); }
.timeline-item.t-appointment .ico { background: color-mix(in srgb, var(--gold) 15%, transparent); color: var(--gold); }
.tl-day {
  font-size: 10.5px; font-weight: 700; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.07em;
  padding: 14px 0 4px; border-bottom: 1px solid var(--grid);
}
.tl-day:first-child { padding-top: 2px; }

/* ---- Email attachment chips (timeline) ---- */
.attach-row { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.attach-chip {
  display: inline-flex; align-items: center; gap: 6px; max-width: 100%;
  border: 1px solid var(--baseline); background: var(--ghost-bg);
  color: var(--ink); border-radius: var(--radius-sm);
  padding: 5px 10px; font-size: 12px; font-weight: 600; text-align: left;
  transition: background .15s, border-color .15s, color .15s;
}
.attach-chip svg.ic { color: var(--accent-strong); flex: 0 0 auto; }
.attach-chip .an { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 220px; }
.attach-chip .asz { color: var(--muted); font-weight: 500; font-variant-numeric: tabular-nums; flex: 0 0 auto; }
.attach-chip i {
  font-style: normal; font-size: 10.5px; font-weight: 700; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.05em;
}
.attach-chip:not(.missing):hover {
  background: var(--tint); border-color: var(--wash-strong); color: var(--accent-strong);
}
.attach-chip:disabled { opacity: .55; cursor: progress; }
.attach-chip.missing { cursor: default; border-style: dashed; color: var(--ink-2); }
.attach-chip.missing svg.ic { color: var(--warning-text); }
@media (max-width: 560px) { .attach-chip .an { max-width: 140px; } }

/* Composer collapses to one line until focused */
.composer.collapsed .types, .composer.collapsed textarea, .composer.collapsed .c-foot { display: none; }
.composer.collapsed { padding: 10px 12px; }

/* ---- Knowledge article images ---- */
.art-thumb {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--baseline); background: var(--ghost-bg);
  border-radius: var(--radius-sm); padding: 4px 6px;
}
.art-thumb img {
  height: 40px; width: 56px; object-fit: cover;
  border-radius: 4px; display: block;
}
.art-preview {
  border: 1px solid var(--baseline); background: var(--ghost-bg);
  border-radius: var(--radius-sm); padding: 12px 14px;
  max-height: 260px; overflow-y: auto; font-size: 13.5px; line-height: 1.55;
}
.art-img, .art-preview img {
  max-width: 100%; display: block; margin: 8px 0;
  border-radius: var(--radius-sm); border: 1px solid var(--baseline);
}

/* ---- Skeleton loading (reference shimmer colours) ---- */
@keyframes skel { from { background-position: 200% 0; } to { background-position: -200% 0; } }
.skel {
  border-radius: var(--r-sm);
  background: linear-gradient(90deg, var(--skel-a) 20%, var(--skel-b) 40%, var(--skel-a) 60%);
  background-size: 220% 100%; animation: skel 1.2s linear infinite;
}
.skel.line { height: 14px; }
.skel.tile { height: 92px; border-radius: var(--radius); }
.skel.block { height: 220px; border-radius: var(--radius); }
@media (prefers-reduced-motion: reduce) { .skel { animation: none; } }

/* ---- Admin: destructive actions revealed on row hover ---- */
.admin-card table .btn.danger { opacity: 0; transition: opacity .12s; }
.admin-card table tr:hover .btn.danger,
.admin-card table .btn.danger:focus-visible { opacity: 1; }
@media (hover: none) { .admin-card table .btn.danger { opacity: 1; } }

/* (old brand-fingerprint bar removed — active nav is now the gradient pill) */
/* Dashboard tiles as links */
a.tile { display: block; color: inherit; }
a.tile:hover { text-decoration: none; box-shadow: var(--shadow-2); border-color: var(--wash-strong); }

/* Delta chips (direction × goodness) */
.tile .delta {
  display: inline-flex; align-items: baseline; gap: 4px; margin-top: 6px;
  font-size: 11.5px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.tile .delta i { font-style: normal; font-weight: 500; color: var(--muted); }
.delta.good { color: var(--good-text); }
.delta.bad { color: var(--critical-text); }
.delta.neutral { color: var(--muted); }

/* Dashboard range filter (scopes flow metrics: trend, deltas, windowed SLA) */
.range-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.range-row .rlabel {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 600; color: var(--muted); margin-right: 2px;
}
.range-row .rlabel svg.ic { width: 14px; height: 14px; }
.range-row .sub.small { margin-left: 8px; }

/* ---- Scrollbars (reference: thin, navy thumb) ---- */
* { scrollbar-width: thin; scrollbar-color: var(--scroll-thumb) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb {
  background: var(--scroll-thumb); border-radius: 999px;
  border: 2px solid transparent; background-clip: content-box;
}
::-webkit-scrollbar-track { background: transparent; }
