/* ==========================================================================
   UNOS — base stylesheet
   Theme colours live in themes.css, generated by ThemeRegistry::toCss().
   See docs/DESIGN_NOTES.md for the reasoning behind these choices.
   ========================================================================== */

/* --- 1. Neutral surfaces ------------------------------------------------ */
/* Neutrals are built from the theme tint so a surface is never flat grey, but
   the tint is kept to a few percent — the data supplies the colour. */

:root {
  --tint: 120 120 130;

  --density: 1;

  /* Type scale. Everything derives from --density, so one preference changes
     the information capacity of every screen at once. */
  --fs-micro: calc(10.5px * var(--density));
  --fs-xs:    calc(11.5px * var(--density));
  --fs-sm:    calc(12.5px * var(--density));
  --fs-base:  calc(13.5px * var(--density));
  --fs-md:    calc(15px   * var(--density));
  --fs-lg:    calc(18px   * var(--density));
  --fs-xl:    calc(23px   * var(--density));
  --fs-2xl:   calc(32px   * var(--density));

  --lh-tight: 1.25;
  --lh-base: 1.45;

  /* Spacing */
  --sp-1: calc(2px  * var(--density));
  --sp-2: calc(4px  * var(--density));
  --sp-3: calc(6px  * var(--density));
  --sp-4: calc(8px  * var(--density));
  --sp-5: calc(12px * var(--density));
  --sp-6: calc(16px * var(--density));
  --sp-7: calc(24px * var(--density));
  --sp-8: calc(32px * var(--density));

  /* Radius encodes role: inline controls are nearly square, floating
     surfaces are rounded, status dots are circles. */
  --r-inline: 2px;
  --r-float: 6px;
  --r-pill: 999px;

  --row-h: calc(30px * var(--density));
  --control-h: calc(30px * var(--density));

  --sidebar-w: calc(232px * var(--density));
  --sidebar-w-collapsed: 52px;
  --topbar-h: calc(46px * var(--density));

  --font-ui: "Inter", "Inter var", -apple-system, BlinkMacSystemFont, "Segoe UI",
             "Noto Sans", "Noto Sans Devanagari", Roboto, Ubuntu, sans-serif;
  --font-mono: "JetBrains Mono", "IBM Plex Mono", "SFMono-Regular", Menlo,
               Consolas, "Liberation Mono", monospace;

  --dur: 120ms;
  --ease: cubic-bezier(0.2, 0, 0.15, 1);
}

[data-mode="dark"] {
  --bg:        rgb(from rgb(var(--tint)) 0 0 0 / 0);
  --bg-base:   #0d0f14;
  --bg-sunken: #090b0f;
  --bg-raised: #14171e;
  --bg-overlay:#1a1e27;
  --bg-hover:  rgba(var(--tint) / 0.10);
  --bg-active: rgba(var(--tint) / 0.16);
  --bg-input:  #0a0c11;

  --line:        rgba(255 255 255 / 0.09);
  --line-strong: rgba(255 255 255 / 0.16);

  --text:      #e7eaf0;
  --text-mid:  #a6adbb;
  --text-dim:  #757d8c;
  --text-faint:#4d5462;

  --shadow-float: 0 4px 16px rgba(0 0 0 / 0.5), 0 1px 2px rgba(0 0 0 / 0.4);
  --scrollbar: rgba(255 255 255 / 0.14);
  color-scheme: dark;
}

[data-mode="light"] {
  --bg-base:   #f7f8fa;
  --bg-sunken: #eceef2;
  --bg-raised: #ffffff;
  --bg-overlay:#ffffff;
  --bg-hover:  rgba(var(--tint) / 0.07);
  --bg-active: rgba(var(--tint) / 0.13);
  --bg-input:  #ffffff;

  --line:        rgba(16 22 34 / 0.11);
  --line-strong: rgba(16 22 34 / 0.20);

  --text:      #14181f;
  --text-mid:  #4a5261;
  --text-dim:  #6d7583;
  --text-faint:#9aa1ad;

  --shadow-float: 0 4px 14px rgba(16 22 34 / 0.10), 0 1px 2px rgba(16 22 34 / 0.06);
  --scrollbar: rgba(16 22 34 / 0.18);
  color-scheme: light;
}

/* --- 2. Reset ----------------------------------------------------------- */

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

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

body {
  font-family: var(--font-ui);
  font-size: var(--fs-base);
  line-height: var(--lh-base);
  color: var(--text);
  background: var(--bg-base);
  -webkit-font-smoothing: antialiased;
  font-feature-settings: "cv05" 1, "ss01" 1;
  min-height: 100vh;
}

/* Numbers in tables must align vertically; proportional figures make a column
   of IDs impossible to scan. */
.mono, td.num, .num, code, kbd, pre {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.94em;
  letter-spacing: -0.01em;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 2px; }

img, svg { display: block; }
button, input, select, textarea { font: inherit; color: inherit; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-radius: var(--r-inline);
}
:focus:not(:focus-visible) { outline: none; }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--scrollbar);
  border-radius: var(--r-pill);
  border: 2px solid transparent;
  background-clip: content-box;
}

/* Stroke properties are set here rather than on the sprite symbols: they are inherited
   CSS properties, so they cascade into the <use> shadow tree, and an icon therefore
   picks up currentColor from whatever it sits inside. */
.ico {
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* --- 3. Application shell ---------------------------------------------- */

.shell {
  display: grid;
  grid-template-columns: var(--sidebar-w) 1fr;
  grid-template-rows: var(--topbar-h) 1fr;
  grid-template-areas: "brand topbar" "sidebar main";
  min-height: 100vh;
}
.shell[data-nav="collapsed"] { grid-template-columns: var(--sidebar-w-collapsed) 1fr; }

.brand {
  grid-area: brand;
  display: flex; align-items: center; gap: var(--sp-4);
  padding: 0 var(--sp-5);
  background: var(--bg-raised);
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  overflow: hidden;
}
/* Brand lockup ----------------------------------------------------------- */
/* Two files per lockup — one drawn for light surfaces, one for dark. The choice is
   made here rather than in PHP because app.js rewrites data-mode when the operating
   system's colour preference changes under "system" mode, and a server-rendered
   <img> would stay wrong until the next page load. */

.logo { display: inline-flex; align-items: center; flex: none; }
.logo__img { display: block; width: auto; }
[data-mode="light"] .logo__img--dark,
[data-mode="dark"]  .logo__img--light { display: none; }

.brand__word  .logo__img { height: calc(24px * var(--density)); }
.brand__glyph .logo__img { height: calc(23px * var(--density)); }

/* Expanded shows the wordmark, collapsed shows the glyph. */
.brand__glyph { display: none; }
.shell[data-nav="collapsed"] .brand__word  { display: none; }
.shell[data-nav="collapsed"] .brand__glyph { display: inline-flex; }
.shell[data-nav="collapsed"] .brand { justify-content: center; padding: 0; }

/* Sidebar ---------------------------------------------------------------- */

.sidebar {
  grid-area: sidebar;
  background: var(--bg-raised);
  border-right: 1px solid var(--line);
  overflow-y: auto;
  overflow-x: hidden;
  padding: var(--sp-4) 0 var(--sp-7);
  display: flex; flex-direction: column;
}
.nav-section { padding: var(--sp-3) var(--sp-4) 0; }
.nav-section__label {
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--text-faint);
  padding: var(--sp-4) var(--sp-4) var(--sp-2);
  text-transform: uppercase;
}
.shell[data-nav="collapsed"] .nav-section__label { display: none; }

.nav-link {
  display: flex; align-items: center; gap: var(--sp-4);
  padding: 0 var(--sp-4);
  height: calc(30px * var(--density));
  border-radius: var(--r-inline);
  color: var(--text-mid);
  font-size: var(--fs-sm);
  font-weight: 500;
  white-space: nowrap;
  position: relative;
}
.nav-link:hover { background: var(--bg-hover); color: var(--text); text-decoration: none; }
.nav-link[aria-current="page"] {
  background: var(--accent-lo);
  color: var(--accent);
  font-weight: 600;
}
/* The active marker is a spine, not a filled block: it survives every theme
   and does not compete with severity colour in the content area. */
.nav-link[aria-current="page"]::before {
  content: ""; position: absolute; left: calc(-1 * var(--sp-4));
  top: 15%; bottom: 15%; width: 2px;
  background: var(--accent); border-radius: 0 2px 2px 0;
}
.nav-link .ico { color: currentColor; opacity: 0.85; }
.nav-link__text { overflow: hidden; text-overflow: ellipsis; }
.shell[data-nav="collapsed"] .nav-link__text,
.shell[data-nav="collapsed"] .nav-link__badge { display: none; }
.shell[data-nav="collapsed"] .nav-link { justify-content: center; padding: 0; }

.nav-link__badge {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-dim);
  background: var(--bg-sunken);
  padding: 1px var(--sp-3);
  border-radius: var(--r-pill);
}
.nav-link--locked { opacity: 0.42; cursor: not-allowed; }
.nav-link--locked:hover { background: none; color: var(--text-mid); }

.sidebar__foot { margin-top: auto; padding: var(--sp-5) var(--sp-6) 0; }
.license-chip {
  display: flex; align-items: center; gap: var(--sp-3);
  font-size: var(--fs-micro); color: var(--text-dim);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--r-float);
  background: var(--bg-sunken);
}
.shell[data-nav="collapsed"] .sidebar__foot { display: none; }

/* Topbar ----------------------------------------------------------------- */

.topbar {
  grid-area: topbar;
  display: flex; align-items: center; gap: var(--sp-5);
  padding: 0 var(--sp-6);
  background: var(--bg-raised);
  border-bottom: 1px solid var(--line);
}

.icon-btn {
  display: grid; place-items: center;
  width: var(--control-h); height: var(--control-h);
  border: 1px solid transparent; background: none;
  color: var(--text-mid); border-radius: var(--r-inline);
  cursor: pointer; position: relative;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.icon-btn:hover { background: var(--bg-hover); color: var(--text); }
.icon-btn__dot {
  position: absolute; top: 5px; right: 5px;
  width: 6px; height: 6px; border-radius: var(--r-pill);
  background: var(--sev-critical);
  border: 1.5px solid var(--bg-raised);
}

/* The scope ribbon answers "where am I" — tenant, geography, site. Breadcrumbs
   alone are not enough when the same screen exists for every tenant. */
.scope {
  display: flex; align-items: center; gap: var(--sp-3);
  font-size: var(--fs-xs); color: var(--text-dim);
  min-width: 0;
}
.scope__item { display: flex; align-items: center; gap: var(--sp-2); white-space: nowrap; }
.scope__item strong { color: var(--text); font-weight: 600; }
.scope__sep { color: var(--text-faint); }
.scope__tenant {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  background: var(--accent-lo); color: var(--accent);
  padding: 1px var(--sp-3); border-radius: var(--r-inline);
  font-weight: 600; font-size: var(--fs-xs);
}

.topbar__spacer { margin-left: auto; }

.search {
  position: relative; display: flex; align-items: center;
  width: calc(260px * var(--density));
  max-width: 32vw;
}
.search .ico { position: absolute; left: var(--sp-4); color: var(--text-faint); }
.search input {
  width: 100%; height: var(--control-h);
  padding: 0 var(--sp-4) 0 calc(var(--sp-4) * 2 + 14px);
  background: var(--bg-input);
  border: 1px solid var(--line);
  border-radius: var(--r-inline);
  font-size: var(--fs-sm);
}
.search input::placeholder { color: var(--text-faint); }
.search input:focus { border-color: var(--accent); outline: none; }
.search kbd {
  position: absolute; right: var(--sp-3);
  font-size: var(--fs-micro); color: var(--text-faint);
  border: 1px solid var(--line); border-radius: 3px;
  padding: 0 var(--sp-2);
}

/* Main ------------------------------------------------------------------- */

.main { grid-area: main; overflow-y: auto; }
.page { padding: var(--sp-6) var(--sp-7) var(--sp-8); max-width: 1720px; }
.page--wide { max-width: none; }

.page-head {
  display: flex; align-items: flex-start; gap: var(--sp-5);
  margin-bottom: var(--sp-6);
  flex-wrap: wrap;
}
.page-head__text { min-width: 0; }
.page-title {
  font-size: var(--fs-xl); font-weight: 640;
  letter-spacing: -0.02em; line-height: var(--lh-tight);
}
.page-sub { font-size: var(--fs-sm); color: var(--text-dim); margin-top: var(--sp-2); }
.page-head__actions { margin-left: auto; display: flex; gap: var(--sp-3); flex-wrap: wrap; }

.crumbs {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-xs); color: var(--text-dim);
  margin-bottom: var(--sp-3);
}
.crumbs a { color: var(--text-dim); }
.crumbs a:hover { color: var(--text); }
.crumbs .ico { color: var(--text-faint); }

/* --- 4. Surfaces -------------------------------------------------------- */

/* Layering is done with a hairline border, not a shadow. Shadow is reserved
   for surfaces that genuinely float above the page. */
.card {
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: var(--r-float);
}
.card__head {
  display: flex; align-items: center; gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--line);
  min-height: calc(38px * var(--density));
}
.card__title { font-size: var(--fs-sm); font-weight: 620; letter-spacing: -0.01em; }
.card__sub { font-size: var(--fs-xs); color: var(--text-dim); }
.card__actions { margin-left: auto; display: flex; align-items: center; gap: var(--sp-3); }
.card__body { padding: var(--sp-5); }
.card__body--flush { padding: 0; }
.card__foot {
  padding: var(--sp-4) var(--sp-5);
  border-top: 1px solid var(--line);
  display: flex; align-items: center; gap: var(--sp-4);
  font-size: var(--fs-xs); color: var(--text-dim);
}

.grid { display: grid; gap: var(--sp-5); }
.grid--stats { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.grid--split { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
@media (max-width: 1100px) { .grid--split { grid-template-columns: 1fr; } }

/* Stat tile -------------------------------------------------------------- */

.stat { padding: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-2); }
.stat__label {
  font-size: var(--fs-xs); color: var(--text-dim);
  display: flex; align-items: center; gap: var(--sp-3);
}
.stat__value {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-2xl);
  font-weight: 600;
  letter-spacing: -0.035em;
  line-height: 1.05;
}
.stat__meta { font-size: var(--fs-xs); color: var(--text-dim); display: flex; align-items: center; gap: var(--sp-2); }
.stat--critical .stat__value { color: var(--sev-critical); }
.stat--major .stat__value { color: var(--sev-major); }
.stat--ok .stat__value { color: var(--sev-ok); }
.trend-up { color: var(--sev-ok); }
.trend-down { color: var(--sev-critical); }

/* --- 5. Dense data table ------------------------------------------------ */

.table-wrap { overflow-x: auto; }
table.data {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--fs-sm);
}
table.data th {
  text-align: left;
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.045em;
  text-transform: uppercase;
  color: var(--text-dim);
  padding: var(--sp-3) var(--sp-4);
  background: var(--bg-sunken);
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
  position: sticky; top: 0; z-index: 2;
}
table.data th a {
  color: inherit; display: inline-flex; align-items: center; gap: var(--sp-2);
}
table.data th a:hover { color: var(--text); text-decoration: none; }
table.data th[aria-sort] a { color: var(--text); }

table.data td {
  padding: 0 var(--sp-4);
  height: var(--row-h);
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
  white-space: nowrap;
}
table.data td.wrap { white-space: normal; min-width: 200px; }
table.data tbody tr:hover td { background: var(--bg-hover); }
table.data td.num { text-align: right; }
table.data .col-shrink { width: 1%; }

/* Severity is a 3px spine on the row plus a dot in the cell. A full-width
   pill on every row turns an alarm list into a colour field and destroys the
   scanning advantage colour is supposed to give. */
tr[data-sev] td:first-child { box-shadow: inset 3px 0 0 var(--row-spine, transparent); }
tr[data-sev="critical"] { --row-spine: var(--sev-critical); }
tr[data-sev="major"]    { --row-spine: var(--sev-major); }
tr[data-sev="minor"]    { --row-spine: var(--sev-minor); }
tr[data-sev="warning"]  { --row-spine: var(--sev-warning); }
tr[data-sev="info"]     { --row-spine: var(--sev-info); }
tr[data-sev="ok"]       { --row-spine: var(--sev-ok); }

.dot {
  display: inline-block; width: 7px; height: 7px;
  border-radius: var(--r-pill); flex: none;
  background: var(--text-faint);
}
.dot--critical { background: var(--sev-critical); }
.dot--major    { background: var(--sev-major); }
.dot--minor    { background: var(--sev-minor); }
.dot--warning  { background: var(--sev-warning); }
.dot--info     { background: var(--sev-info); }
.dot--ok       { background: var(--sev-ok); }
.dot--pulse { animation: pulse 2s var(--ease) infinite; }
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.35; } }

.status {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  font-size: var(--fs-xs); font-weight: 500;
  white-space: nowrap;
}
.status--critical { color: var(--sev-critical); }
.status--major { color: var(--sev-major); }
.status--minor { color: var(--sev-minor); }
.status--warning { color: var(--sev-warning); }
.status--info { color: var(--sev-info); }
.status--ok { color: var(--sev-ok); }
.status--muted { color: var(--text-dim); }

.badge {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-micro); font-weight: 600;
  padding: 1px var(--sp-3);
  border-radius: var(--r-inline);
  background: var(--bg-sunken);
  color: var(--text-mid);
  border: 1px solid var(--line);
  white-space: nowrap;
}
.badge--accent { background: var(--accent-lo); color: var(--accent); border-color: transparent; }
.badge--ok { color: var(--sev-ok); border-color: color-mix(in srgb, var(--sev-ok) 35%, transparent); background: color-mix(in srgb, var(--sev-ok) 10%, transparent); }
.badge--warn { color: var(--sev-minor); border-color: color-mix(in srgb, var(--sev-minor) 35%, transparent); background: color-mix(in srgb, var(--sev-minor) 10%, transparent); }
.badge--danger { color: var(--sev-critical); border-color: color-mix(in srgb, var(--sev-critical) 35%, transparent); background: color-mix(in srgb, var(--sev-critical) 10%, transparent); }

.toolbar {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--line);
  flex-wrap: wrap;
}
.toolbar__spacer { margin-left: auto; }

.pagination {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  font-size: var(--fs-xs); color: var(--text-dim);
}
.pagination__pages { margin-left: auto; display: flex; gap: var(--sp-2); align-items: center; }
.page-link {
  min-width: calc(24px * var(--density)); height: calc(24px * var(--density));
  display: grid; place-items: center; padding: 0 var(--sp-3);
  border: 1px solid var(--line); border-radius: var(--r-inline);
  color: var(--text-mid); font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
}
.page-link:hover { background: var(--bg-hover); color: var(--text); text-decoration: none; }
.page-link[aria-current] { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.page-link[aria-disabled] { opacity: 0.4; pointer-events: none; }

.empty {
  padding: var(--sp-8) var(--sp-6);
  text-align: center; color: var(--text-dim);
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-4);
}
.empty .ico { color: var(--text-faint); }
.empty__title { font-size: var(--fs-md); color: var(--text); font-weight: 600; }

/* --- 6. Controls -------------------------------------------------------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-3);
  height: var(--control-h);
  padding: 0 var(--sp-5);
  border-radius: var(--r-inline);
  border: 1px solid var(--line-strong);
  background: var(--bg-raised);
  color: var(--text);
  font-size: var(--fs-sm); font-weight: 550;
  cursor: pointer; white-space: nowrap;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.btn:hover { background: var(--bg-hover); text-decoration: none; }
.btn:disabled, .btn[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }
.btn--primary {
  background: var(--accent); border-color: var(--accent); color: var(--on-accent);
}
.btn--primary:hover { background: var(--accent-hi); border-color: var(--accent-hi); }
.btn--ghost { border-color: transparent; background: none; color: var(--text-mid); }
.btn--ghost:hover { background: var(--bg-hover); color: var(--text); }
.btn--danger { border-color: color-mix(in srgb, var(--sev-critical) 45%, transparent); color: var(--sev-critical); }
.btn--danger:hover { background: color-mix(in srgb, var(--sev-critical) 12%, transparent); }
.btn--sm { height: calc(24px * var(--density)); padding: 0 var(--sp-4); font-size: var(--fs-xs); }
.btn--block { width: 100%; }
.btn--lg { height: calc(38px * var(--density)); font-size: var(--fs-md); }

.field { display: flex; flex-direction: column; gap: var(--sp-3); margin-bottom: var(--sp-5); }
.field__label {
  font-size: var(--fs-xs); font-weight: 600; color: var(--text-mid);
  display: flex; align-items: center; gap: var(--sp-3);
}
.field__label .req { color: var(--sev-critical); }
.field__hint { font-size: var(--fs-xs); color: var(--text-dim); margin: 4px 0 0; }
.field__error { font-size: var(--fs-xs); color: var(--sev-critical); display: flex; align-items: center; gap: var(--sp-2); }

.input, .select, .textarea {
  width: 100%;
  height: var(--control-h);
  padding: 0 var(--sp-4);
  background: var(--bg-input);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-inline);
  font-size: var(--fs-sm);
  color: var(--text);
  transition: border-color var(--dur) var(--ease);
}
.textarea { height: auto; min-height: calc(72px * var(--density)); padding: var(--sp-4); line-height: var(--lh-base); resize: vertical; }
.input:focus, .select:focus, .textarea:focus { border-color: var(--accent); outline: none; }
.input[aria-invalid="true"], .select[aria-invalid="true"] { border-color: var(--sev-critical); }
.input::placeholder, .textarea::placeholder { color: var(--text-faint); }
.select {
  appearance: none;
  padding-right: var(--sp-7);
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: right var(--sp-5) center, right calc(var(--sp-5) - 4px) center;
  background-size: 4px 4px, 4px 4px;
  background-repeat: no-repeat;
}
.input--mono { font-family: var(--font-mono); letter-spacing: 0.02em; }

.checkline { display: flex; align-items: flex-start; gap: var(--sp-4); font-size: var(--fs-sm); cursor: pointer; }
.checkline input { margin-top: 3px; accent-color: var(--accent); flex: none; }
.checkline__text { color: var(--text-mid); }
.checkline__text strong { color: var(--text); font-weight: 550; display: block; }

.switch-row {
  display: flex; align-items: center; gap: var(--sp-5);
  padding: var(--sp-4) 0;
  border-bottom: 1px solid var(--line);
}
.switch-row:last-child { border-bottom: none; }
.switch-row__text { min-width: 0; }
.switch-row__text strong { font-size: var(--fs-sm); font-weight: 600; display: block; }
.switch-row__text span { font-size: var(--fs-xs); color: var(--text-dim); }
.switch-row__control { margin-left: auto; }

.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 0 var(--sp-5); }
.form-grid .field--full { grid-column: 1 / -1; }

/* --- 7. Flash and alerts ------------------------------------------------ */

.flash-stack {
  position: fixed; top: var(--sp-6); right: var(--sp-6); z-index: 60;
  display: flex; flex-direction: column; gap: var(--sp-3);
  max-width: 380px;
}
.flash {
  display: flex; align-items: flex-start; gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5);
  background: var(--bg-overlay);
  border: 1px solid var(--line-strong);
  border-left: 3px solid var(--text-dim);
  border-radius: var(--r-float);
  box-shadow: var(--shadow-float);
  font-size: var(--fs-sm);
}
.flash--success { border-left-color: var(--sev-ok); }
.flash--success .ico { color: var(--sev-ok); }
.flash--error { border-left-color: var(--sev-critical); }
.flash--error .ico { color: var(--sev-critical); }
.flash--warning { border-left-color: var(--sev-minor); }
.flash--warning .ico { color: var(--sev-minor); }
.flash--info { border-left-color: var(--sev-info); }
.flash--info .ico { color: var(--sev-info); }
.flash__body { min-width: 0; }
.flash__detail { font-size: var(--fs-xs); color: var(--text-dim); margin-top: var(--sp-2); }
.flash__close { margin-left: auto; }

.notice {
  display: flex; align-items: flex-start; gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5);
  border: 1px solid var(--line);
  border-left: 3px solid var(--sev-info);
  border-radius: var(--r-inline);
  background: var(--bg-sunken);
  font-size: var(--fs-sm);
  margin-bottom: var(--sp-5);
}
.notice--warning { border-left-color: var(--sev-minor); }
.notice--danger { border-left-color: var(--sev-critical); }
.notice--ok { border-left-color: var(--sev-ok); }
.notice .ico { margin-top: 1px; color: var(--text-dim); }
.notice__title { font-weight: 600; }
.notice__body { color: var(--text-mid); }

/* --- 8. Menus and dialogs ---------------------------------------------- */

.pop { position: relative; }
.pop__panel {
  position: absolute; right: 0; top: calc(100% + var(--sp-3));
  min-width: 230px; z-index: 50;
  background: var(--bg-overlay);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-float);
  box-shadow: var(--shadow-float);
  padding: var(--sp-3);
  display: none;
}
.pop__panel--wide { min-width: 320px; }
.pop[data-open="true"] .pop__panel { display: block; }
.pop__head {
  padding: var(--sp-3) var(--sp-4) var(--sp-4);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--sp-3);
}
.pop__title { font-size: var(--fs-xs); font-weight: 600; color: var(--text-dim); }
.menu-item {
  display: flex; align-items: center; gap: var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-inline);
  font-size: var(--fs-sm); color: var(--text-mid);
  width: 100%; border: none; background: none; cursor: pointer; text-align: left;
}
.menu-item:hover { background: var(--bg-hover); color: var(--text); text-decoration: none; }
.menu-item--danger { color: var(--sev-critical); }
.menu-sep { height: 1px; background: var(--line); margin: var(--sp-3) 0; }

.user-chip {
  display: flex; align-items: center; gap: var(--sp-4);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-inline);
  cursor: pointer; border: 1px solid transparent; background: none;
}
.user-chip:hover { background: var(--bg-hover); }
.avatar {
  width: calc(26px * var(--density)); height: calc(26px * var(--density));
  border-radius: var(--r-pill); flex: none;
  display: grid; place-items: center;
  background: var(--accent-lo); color: var(--accent);
  font-size: var(--fs-xs); font-weight: 650;
}
.user-chip__text { text-align: left; line-height: 1.2; }
.user-chip__name { font-size: var(--fs-xs); font-weight: 600; }
.user-chip__role { font-size: var(--fs-micro); color: var(--text-dim); }

/* --- 9. Theme picker ---------------------------------------------------- */

.theme-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: var(--sp-4); }
.theme-card {
  border: 1px solid var(--line); border-radius: var(--r-float);
  padding: var(--sp-4); cursor: pointer; background: var(--bg-raised);
  display: flex; flex-direction: column; gap: var(--sp-3);
  text-align: left; width: 100%;
}
.theme-card:hover { border-color: var(--line-strong); }
.theme-card[aria-pressed="true"] { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.theme-card__swatch { display: flex; gap: var(--sp-2); height: 22px; }
.theme-card__swatch span { flex: 1; border-radius: var(--r-inline); }
.theme-card__name { font-size: var(--fs-sm); font-weight: 600; display: flex; align-items: center; gap: var(--sp-3); }
.theme-card__desc { font-size: var(--fs-micro); color: var(--text-dim); line-height: 1.35; }

.seg {
  display: inline-flex; padding: 2px;
  background: var(--bg-sunken); border: 1px solid var(--line);
  border-radius: var(--r-inline);
}
.seg button {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: 0 var(--sp-4); height: calc(24px * var(--density));
  border: none; background: none; cursor: pointer;
  font-size: var(--fs-xs); font-weight: 550; color: var(--text-dim);
  border-radius: 1px;
}
.seg button[aria-pressed="true"] { background: var(--bg-raised); color: var(--text); box-shadow: 0 1px 2px rgba(0 0 0 / 0.12); }

/* --- 10. Authentication screens ---------------------------------------- */

.auth {
  min-height: 100vh;
  display: grid; grid-template-columns: 1fr minmax(380px, 440px);
  background: var(--bg-base);
}
.auth__aside {
  padding: var(--sp-8);
  background: var(--bg-sunken);
  border-right: 1px solid var(--line);
  display: flex; flex-direction: column; justify-content: space-between;
  background-image: radial-gradient(circle at 1px 1px, var(--line) 1px, transparent 0);
  background-size: 22px 22px;
}

/* This block has to come after .auth__aside, not before it. Both selectors have the
   same specificity, so whichever is written last wins and the earlier placement left
   the aside showing at every width — the narrow layout never took effect. */
@media (max-width: 900px) { .auth { grid-template-columns: 1fr; } .auth__aside { display: none; } }
/* Large enough that the tagline under the wordmark is readable rather than decorative. */
.auth__logo .logo__img { height: 72px; }
.auth__aside-inner { max-width: 460px; margin: auto 0; }

/* The panel carries the brand only where the aside is hidden; above 900px the aside
   already shows the full lockup and a second one would read as a duplicate. */
.auth__logo-sm { display: none; margin-bottom: var(--sp-6); }
.auth__logo-sm .logo__img { height: 30px; }
@media (max-width: 900px) { .auth__logo-sm { display: inline-flex; } }
.auth__headline {
  font-size: var(--fs-2xl); font-weight: 650;
  letter-spacing: -0.03em; line-height: 1.15;
  margin-bottom: var(--sp-5);
}
.auth__lede { font-size: var(--fs-md); color: var(--text-mid); line-height: 1.5; }
.auth__points { margin-top: var(--sp-7); display: flex; flex-direction: column; gap: var(--sp-4); }
.auth__point { display: flex; gap: var(--sp-4); align-items: flex-start; font-size: var(--fs-sm); color: var(--text-mid); }
.auth__point .ico { color: var(--accent); margin-top: 2px; }

.auth__panel {
  display: flex; flex-direction: column; justify-content: center;
  padding: var(--sp-8) var(--sp-7);
  background: var(--bg-raised);
}
.auth__form { width: 100%; max-width: 350px; margin: 0 auto; }
.auth__brand { display: flex; align-items: center; gap: var(--sp-4); margin-bottom: var(--sp-7); }
.auth__title { font-size: var(--fs-lg); font-weight: 640; letter-spacing: -0.02em; }
.auth__sub { font-size: var(--fs-sm); color: var(--text-dim); margin-top: var(--sp-2); margin-bottom: var(--sp-6); }
.auth__foot { margin-top: var(--sp-7); font-size: var(--fs-xs); color: var(--text-faint); text-align: center; line-height: 1.5; }

.sso-list { display: flex; flex-direction: column; gap: var(--sp-3); margin-bottom: var(--sp-5); }
.divider {
  display: flex; align-items: center; gap: var(--sp-4);
  margin: var(--sp-6) 0; color: var(--text-faint); font-size: var(--fs-micro);
  text-transform: uppercase; letter-spacing: 0.08em;
}
.divider::before, .divider::after { content: ""; flex: 1; height: 1px; background: var(--line); }

/* One box per digit is faster to check against a phone than a single field. */
.code-input {
  display: flex; gap: var(--sp-3); justify-content: center;
  margin: var(--sp-6) 0;
}
.code-input input {
  width: calc(42px * var(--density)); height: calc(50px * var(--density));
  text-align: center;
  font-family: var(--font-mono); font-size: var(--fs-xl); font-weight: 600;
  background: var(--bg-input);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-inline);
}
.code-input input:focus { border-color: var(--accent); outline: none; }

.qr-panel {
  display: flex; gap: var(--sp-6); align-items: flex-start;
  padding: var(--sp-5);
  background: var(--bg-sunken);
  border: 1px solid var(--line);
  border-radius: var(--r-float);
  margin-bottom: var(--sp-5);
}
.qr-panel__code { background: #fff; padding: var(--sp-4); border-radius: var(--r-inline); flex: none; }
.qr-panel__code svg { width: 148px; height: 148px; }
.secret-box {
  font-family: var(--font-mono); font-size: var(--fs-sm);
  background: var(--bg-input); border: 1px solid var(--line);
  border-radius: var(--r-inline); padding: var(--sp-3) var(--sp-4);
  word-break: break-all; letter-spacing: 0.06em;
  display: flex; align-items: center; gap: var(--sp-3);
}
.recovery-codes {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-3);
  font-family: var(--font-mono); font-size: var(--fs-sm);
  padding: var(--sp-5); background: var(--bg-sunken);
  border: 1px solid var(--line); border-radius: var(--r-float);
  margin: var(--sp-5) 0;
}
.recovery-codes span { letter-spacing: 0.04em; }

.strength { display: flex; gap: 3px; margin-top: var(--sp-3); }
.strength span { flex: 1; height: 3px; border-radius: var(--r-pill); background: var(--line-strong); }
.strength[data-score="1"] span:nth-child(-n+1) { background: var(--sev-critical); }
.strength[data-score="2"] span:nth-child(-n+2) { background: var(--sev-major); }
.strength[data-score="3"] span:nth-child(-n+3) { background: var(--sev-minor); }
.strength[data-score="4"] span { background: var(--sev-ok); }

.policy-list { list-style: none; padding: 0; font-size: var(--fs-xs); color: var(--text-dim); display: grid; gap: var(--sp-2); }
.policy-list li { display: flex; align-items: center; gap: var(--sp-3); }
.policy-list li[data-met="true"] { color: var(--sev-ok); }

/* --- 11. Detail lists and misc ----------------------------------------- */

.deflist { display: grid; grid-template-columns: max-content 1fr; gap: var(--sp-3) var(--sp-6); font-size: var(--fs-sm); }
.deflist dt { color: var(--text-dim); font-size: var(--fs-xs); }
.deflist dd { margin: 0; }

.timeline { display: flex; flex-direction: column; }
.timeline__item {
  display: grid; grid-template-columns: max-content 1fr;
  gap: var(--sp-5); padding: var(--sp-4) 0;
  border-bottom: 1px solid var(--line);
}
.timeline__item:last-child { border-bottom: none; }
.timeline__time { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--text-dim); white-space: nowrap; }
.timeline__body { font-size: var(--fs-sm); min-width: 0; }
.timeline__meta { font-size: var(--fs-xs); color: var(--text-dim); margin-top: var(--sp-2); }

.bar { height: 4px; background: var(--bg-sunken); border-radius: var(--r-pill); overflow: hidden; }
.bar__fill { height: 100%; background: var(--accent); border-radius: var(--r-pill); }
.bar__fill--warn { background: var(--sev-minor); }
.bar__fill--danger { background: var(--sev-critical); }

.spark { display: flex; align-items: flex-end; gap: 2px; height: 28px; }
.spark span { flex: 1; background: var(--accent-lo); border-radius: 1px 1px 0 0; min-height: 2px; }
.spark span:last-child { background: var(--accent); }

.kv-mono { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--text-mid); }
.text-dim { color: var(--text-dim); }
.text-mid { color: var(--text-mid); }
.text-sm { font-size: var(--fs-sm); }
.text-xs { font-size: var(--fs-xs); }
.mt-4 { margin-top: var(--sp-4); }
.mt-5 { margin-top: var(--sp-5); }
.mt-6 { margin-top: var(--sp-6); }
.mb-5 { margin-bottom: var(--sp-5); }
.flex { display: flex; align-items: center; gap: var(--sp-4); }
.flex-between { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); }
.flex-col { display: flex; flex-direction: column; gap: var(--sp-4); }
.gap-2 { gap: var(--sp-2); }
.gap-3 { gap: var(--sp-3); }
.wrap-any { white-space: normal; word-break: break-word; }

/* --- 12. Error pages ---------------------------------------------------- */

.error-page {
  min-height: 100vh; display: grid; place-items: center; padding: var(--sp-7);
}
.error-card { max-width: 460px; text-align: center; }
.error-code {
  font-family: var(--font-mono); font-size: calc(64px * var(--density));
  font-weight: 600; letter-spacing: -0.05em; line-height: 1;
  color: var(--text-faint);
}
.error-title { font-size: var(--fs-xl); font-weight: 640; margin: var(--sp-5) 0 var(--sp-4); letter-spacing: -0.02em; }
.error-body { color: var(--text-mid); font-size: var(--fs-sm); line-height: 1.55; }
.error-meta { margin-top: var(--sp-6); font-family: var(--font-mono); font-size: var(--fs-micro); color: var(--text-faint); }
.error-actions { margin-top: var(--sp-7); display: flex; gap: var(--sp-4); justify-content: center; }

/* --- 13. Responsive ----------------------------------------------------- */

@media (max-width: 860px) {
  .shell { grid-template-columns: 1fr; grid-template-areas: "topbar" "main"; }
  .brand { display: none; }
  .sidebar {
    position: fixed; inset: 0 auto 0 0; z-index: 70;
    width: var(--sidebar-w); transform: translateX(-100%);
    transition: transform var(--dur) var(--ease);
    box-shadow: var(--shadow-float);
  }
  .shell[data-nav="open"] .sidebar { transform: none; }
  .page { padding: var(--sp-5) var(--sp-5) var(--sp-8); }
  .search { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

@media print {
  .sidebar, .topbar, .brand, .page-head__actions, .flash-stack { display: none !important; }
  .shell { display: block; }
  .card { border-color: #ccc; break-inside: avoid; }
}

/* --- 14. Utilities ------------------------------------------------------
   The Content-Security-Policy is style-src 'self' with a nonce, and a nonce does not
   authorise style="" attributes — browsers drop them. Everything that would otherwise be an
   inline style therefore lives here as a class, and the handful of genuinely dynamic values
   (theme swatches, capacity bars) are emitted as generated rules in themes.css instead.
   ------------------------------------------------------------------------ */

/* layout */
.flex-start { align-items: flex-start; }
.flex-center { justify-content: center; }
.flex-wrap { flex-wrap: wrap; }
.flex-1 { flex: 1; }
.min0 { min-width: 0; }
.w-full { width: 100%; }
.w-auto { width: auto; }
.w-narrow { width: calc(110px * var(--density)); }
.ml-auto { margin-left: auto; }
.block { display: block; }
.relative { position: relative; }
.pointer { cursor: pointer; }

.stack-2 { display: flex; flex-direction: column; gap: var(--sp-2); }
.stack-3 { display: flex; flex-direction: column; gap: var(--sp-3); }
.stack-4 { display: flex; flex-direction: column; gap: var(--sp-4); }
.stack-5 { display: flex; flex-direction: column; gap: var(--sp-5); }

.gap-4 { gap: var(--sp-4); }
.gap-5 { gap: var(--sp-5); }
.grid-tight { gap: var(--sp-2) var(--sp-6); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
.grid-gap-2 { gap: var(--sp-2); }
.grid-gap-3 { gap: var(--sp-3); }

/* spacing */
.p-3 { padding: var(--sp-3); }
.p-6 { padding: var(--sp-6); }
.py-3 { padding: var(--sp-3) 0; }
.py-4 { padding: var(--sp-4) 0; }
.px-4 { padding: 0 var(--sp-4); }
.pop-body { padding: 0 var(--sp-4) var(--sp-4); }
.pl-0 { padding-left: 0; }
.my-3 { margin: var(--sp-3) 0; }
.indent-3 { margin: var(--sp-3) 0 0 var(--sp-7); }
.mb-0 { margin-bottom: 0; }
.mb-2 { margin-bottom: var(--sp-2); }
.mb-3 { margin-bottom: var(--sp-3); }
.mt-dot { margin-top: 6px; }
.row-sep { border-bottom: 1px solid var(--line); }

/* type */
.fs-sm { font-size: var(--fs-sm); }
.fs-lg { font-size: var(--fs-lg); }
.fs-xl { font-size: var(--fs-xl); }
.fw-400 { font-weight: 400; }
.fw-550 { font-weight: 550; }
.fw-600 { font-weight: 600; }
.text-strong { color: var(--text); }
.ta-center { text-align: center; }
.ta-right { text-align: right; }

/* measure — prose is unreadable past roughly 45 characters at these sizes */
.measure-sm { max-width: 44ch; }
.measure { max-width: 46ch; }
.field-sm { max-width: calc(260px * var(--density)); }
.field-md { max-width: calc(280px * var(--density)); }
.field-lg { max-width: calc(300px * var(--density)); }

/* password reveal button, pinned inside its field */
.field-affix { position: relative; }
.field-affix .input { padding-right: 36px; }
.field-affix__btn { position: absolute; right: 0; top: 0; height: 100%; }

/* dots and swatch sizes */
.dot--lg { width: 12px; height: 12px; }
.avatar--lg { width: calc(34px * var(--density)); height: calc(34px * var(--density)); }
.avatar--square { border-radius: var(--r-inline); }
.swatch-sm { height: 16px; }

/* segmented control rendered as links rather than buttons */
.seg a.seg__link {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: 0 var(--sp-4); height: calc(24px * var(--density));
  border-radius: 1px; color: var(--text-dim);
  font-size: var(--fs-xs); font-weight: 550;
}
.seg a.seg__link:hover { color: var(--text); text-decoration: none; }
.seg a.seg__link[aria-current] { background: var(--bg-raised); color: var(--text); }

/* a permission the actor cannot grant */
.is-blocked { opacity: 0.45; cursor: not-allowed; }

/* debug output, only ever rendered when app.debug is on */
.trace {
  text-align: left; overflow: auto; max-height: 280px;
  background: var(--bg-sunken); padding: var(--sp-5);
  border-radius: var(--r-float); border: 1px solid var(--line);
}

/* ==========================================================================
   Phase 2 — NMS and inventory
   ========================================================================== */

/* Severity summary strip above the alarm console. Counts are the primary object
   on this screen, so they are set large and tabular. */
.sev-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: var(--sp-2);
  margin-bottom: var(--sp-4);
}
.sev-tile {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--line);
  border-left-width: 3px;
  border-radius: var(--r-inline);
  background: var(--bg-raised);
  text-decoration: none;
  color: inherit;
  transition: background var(--dur), border-color var(--dur);
}
.sev-tile:hover { background: var(--bg-hover); }
.sev-tile.is-selected { border-color: var(--accent); background: var(--bg-hover); }
.sev-tile__count {
  font-size: var(--fs-2xl);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.sev-tile__label {
  font-size: var(--fs-xs);
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: .04em;
}
.sev-tile--critical { border-left-color: var(--sev-critical); }
.sev-tile--major    { border-left-color: var(--sev-major); }
.sev-tile--minor    { border-left-color: var(--sev-minor); }
.sev-tile--warning  { border-left-color: var(--sev-warning); }
.sev-tile--info     { border-left-color: var(--sev-info); }
.sev-tile--total    { border-left-color: var(--accent); }

/* A 3px spine on the row carries severity without colouring the whole row, which
   would fight the text for legibility on a dense table. */
.row-sev { box-shadow: inset 3px 0 0 0 transparent; }
.row-sev--critical { box-shadow: inset 3px 0 0 0 var(--sev-critical); }
.row-sev--major    { box-shadow: inset 3px 0 0 0 var(--sev-major); }
.row-sev--minor    { box-shadow: inset 3px 0 0 0 var(--sev-minor); }
.row-sev--warning  { box-shadow: inset 3px 0 0 0 var(--sev-warning); }
.row-sev--info     { box-shadow: inset 3px 0 0 0 var(--sev-info); }

.bulk-bar {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid var(--line);
  background: var(--bg-sunken);
}
.bulk-bar__hint { font-size: var(--fs-xs); color: var(--text-dim); }

.inline-form { display: inline-flex; align-items: center; gap: var(--sp-2); }

/* Reachability dot. Shape as well as colour, so it survives a monochrome print
   and does not rely on colour vision alone. */
.rdot {
  display: inline-block;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--text-faint);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--text-faint) 22%, transparent);
}
.rdot--up      { background: var(--sev-ok);   box-shadow: 0 0 0 2px color-mix(in srgb, var(--sev-ok) 22%, transparent); }
.rdot--down    { background: var(--sev-critical); box-shadow: 0 0 0 2px color-mix(in srgb, var(--sev-critical) 22%, transparent); }
.rdot--degraded{ background: var(--sev-minor); box-shadow: 0 0 0 2px color-mix(in srgb, var(--sev-minor) 22%, transparent); }
.rdot--unknown { background: var(--text-faint); }

.metric-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: var(--sp-3);
  margin-bottom: var(--sp-4);
}
.metric {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--r-inline);
  background: var(--bg-raised);
  text-decoration: none;
  color: inherit;
}
a.metric:hover { background: var(--bg-hover); }
.metric__label { font-size: var(--fs-xs); color: var(--text-dim); text-transform: uppercase; letter-spacing: .04em; }
.metric__value { font-size: var(--fs-2xl); font-weight: 600; font-variant-numeric: tabular-nums; line-height: 1.15; }
.metric__value--sm { font-size: var(--fs-lg); }
.metric__unit { font-size: var(--fs-sm); font-weight: 400; color: var(--text-dim); margin-left: 2px; }
.metric__foot { font-size: var(--fs-xs); color: var(--text-faint); }
.metric--ok    { border-top: 2px solid var(--sev-ok); }
.metric--warn  { border-top: 2px solid var(--sev-minor); }
.metric--bad   { border-top: 2px solid var(--sev-critical); }
.metric--muted { border-top: 2px solid var(--line-strong); }

/* Availability heat strip: one cell per day, thirty days at a glance. */
.heat { display: flex; gap: 3px; flex-wrap: wrap; padding: var(--sp-2) 0; }
.heat__cell { width: 15px; height: 15px; border-radius: 3px; background: var(--bg-sunken); }
.heat__cell--a { background: var(--sev-ok); }
.heat__cell--b { background: color-mix(in srgb, var(--sev-ok) 62%, var(--bg-raised)); }
.heat__cell--c { background: var(--sev-minor); }
.heat__cell--d { background: var(--sev-critical); }
.heat__cell--x { background: var(--bg-sunken); border: 1px dashed var(--line-strong); }
.heat-legend {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-xs); color: var(--text-dim);
  padding-top: var(--sp-2); flex-wrap: wrap;
}
.heat-legend .heat__cell { width: 11px; height: 11px; }

/* Bar chart, CSS only. Heights come from the generated .h-p* utility classes
   because the CSP forbids style attributes and a nonce does not cover them. */
.bars {
  display: flex; align-items: flex-end; gap: 2px;
  height: 120px; padding: var(--sp-3) 0;
}
.bars__col { flex: 1 1 0; height: 100%; display: flex; align-items: flex-end; min-width: 3px; }
.bars__bar { width: 100%; border-radius: 2px 2px 0 0; min-height: 2px; background: var(--accent); }
.bars__bar--ok   { background: var(--sev-ok); }
.bars__bar--warn { background: var(--sev-minor); }
.bars__bar--bad  { background: var(--sev-critical); }

.meter-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-3); }
.meter { display: flex; flex-direction: column; gap: 3px; }
.meter__head { display: flex; justify-content: space-between; align-items: baseline; gap: var(--sp-2); }
.meter__value { font-variant-numeric: tabular-nums; font-weight: 600; }
.meter__track { height: 6px; border-radius: 3px; background: var(--bg-sunken); overflow: hidden; }
.meter__fill { height: 100%; background: var(--accent); border-radius: 3px; }
.meter__fill--ok { background: var(--sev-ok); }
.meter__fill--warn { background: var(--sev-minor); }
.meter__fill--bad { background: var(--sev-critical); }
.meter__foot { font-size: var(--fs-xs); color: var(--text-faint); }

/* Topology canvas. */
.topo { width: 100%; overflow: auto; background: var(--bg-sunken); border-radius: var(--r-inline); }
.topo__svg { width: 100%; height: auto; min-height: 420px; max-height: 70vh; display: block; }
.topo__link { stroke: var(--line-strong); stroke-width: 1.5; }
.topo__link--down { stroke: var(--sev-critical); stroke-width: 2; stroke-dasharray: 5 3; }
.topo__link--degraded { stroke: var(--sev-minor); stroke-dasharray: 3 2; }
.topo__link--planned { stroke: var(--text-faint); stroke-dasharray: 2 4; }
.topo__node { fill: var(--sev-ok); stroke: var(--bg-raised); stroke-width: 2.5; cursor: pointer; }
.topo__node--critical { fill: var(--sev-critical); }
.topo__node--major    { fill: var(--sev-major); }
.topo__node--minor    { fill: var(--sev-minor); }
.topo__node--warning  { fill: var(--sev-warning); }
.topo__node--info     { fill: var(--sev-info); }
.topo__node--down     { fill: var(--sev-critical); }
.topo__node--degraded { fill: var(--sev-minor); }
.topo__node--unknown  { fill: var(--text-faint); }
.topo__node-link:hover .topo__node { stroke: var(--accent); stroke-width: 3; }
.topo__label {
  fill: var(--text-dim);
  font-size: 10px;
  font-family: var(--font-ui);
  pointer-events: none;
  /* A halo in the page colour keeps labels readable where they cross a link line. */
  paint-order: stroke;
  stroke: var(--bg-sunken);
  stroke-width: 3px;
  stroke-linejoin: round;
}
.topo-legend {
  display: flex; gap: var(--sp-4); flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-xs); color: var(--text-dim);
  border-top: 1px solid var(--line);
}
.topo-legend > span { display: inline-flex; align-items: center; gap: 5px; }
.topo-key { width: 9px; height: 9px; border-radius: 50%; display: inline-block; background: var(--text-faint); }
.topo-key--ok { background: var(--sev-ok); }
.topo-key--critical { background: var(--sev-critical); }
.topo-key--major { background: var(--sev-major); }
.topo-key--minor { background: var(--sev-minor); }
.topo-key--down { background: var(--sev-critical); }
.topo-key--unknown { background: var(--text-faint); }

.evlog { list-style: none; margin: 0; padding: 0 0 0 var(--sp-4); position: relative; }
.evlog::before {
  content: ''; position: absolute; left: 4px; top: 6px; bottom: 6px;
  width: 1px; background: var(--line);
}
.evlog__item { position: relative; padding: 0 0 var(--sp-4) var(--sp-4); }
.evlog__dot {
  position: absolute; left: -4px; top: 5px;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--line-strong); border: 2px solid var(--bg-raised);
}
.evlog__item--raised .evlog__dot     { background: var(--sev-major); }
.evlog__item--escalated .evlog__dot  { background: var(--sev-critical); }
.evlog__item--cleared .evlog__dot    { background: var(--sev-ok); }
.evlog__item--acknowledged .evlog__dot { background: var(--accent); }
.evlog__title { font-size: var(--fs-sm); font-weight: 600; margin: 0; }
.evlog__note { font-size: var(--fs-sm); color: var(--text-dim); margin: 2px 0 0; }
.evlog__time { font-size: var(--fs-xs); color: var(--text-faint); font-variant-numeric: tabular-nums; }

.list-plain { list-style: none; margin: 0; padding: 0; }
.list-plain__item {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--line);
}
.list-plain__item:last-child { border-bottom: 0; }

.chip--count { font-variant-numeric: tabular-nums; }
.num--bad { color: var(--sev-critical); }
.card--flush { padding: 0; overflow: hidden; }
.select--xs { font-size: var(--fs-xs); padding: 2px 22px 2px 6px; height: auto; }
.check--inline { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-sm); white-space: nowrap; }
.crumb { font-size: var(--fs-xs); color: var(--text-dim); margin: 0 0 2px; }
.crumb__sep { opacity: .5; margin: 0 4px; }
.link-strong { font-weight: 600; }
.empty--sm { padding: var(--sp-5) var(--sp-4); }
.card__note { font-size: var(--fs-xs); color: var(--text-faint); margin: var(--sp-2) 0 0; }

/* Compact inline summary under a card head — reachability counts on the dashboard. */
.mini-strip {
  display: flex; gap: var(--sp-4); flex-wrap: wrap;
  padding: var(--sp-2) var(--sp-4);
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-xs); color: var(--text-dim);
}
.mini-strip__item { display: inline-flex; align-items: center; gap: 6px; }

/* ==========================================================================
   Phase 3 — OSS and service desk
   ========================================================================== */

/* SLA badge. Shows time remaining, not time consumed: an operator choosing what
   to work next needs "22m left", not "78%". The bar carries the proportion. */
.sla {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 6px;
  border-radius: var(--r-pill);
  font-size: var(--fs-micro);
  line-height: 1.5;
  white-space: nowrap;
  background: var(--bg-sunken);
  border: 1px solid var(--line);
}
.sla + .sla { margin-left: 4px; }
.sla__metric { text-transform: uppercase; letter-spacing: .04em; color: var(--text-faint); }
.sla__label { font-variant-numeric: tabular-nums; font-weight: 600; }
.sla__track { width: 34px; height: 3px; border-radius: 2px; background: var(--line); overflow: hidden; }
.sla__fill { height: 100%; border-radius: 2px; background: var(--sev-ok); }
.sla__fill--warn { background: var(--sev-minor); }
.sla__fill--bad  { background: var(--sev-critical); }
.sla--ok    { border-color: color-mix(in srgb, var(--sev-ok) 40%, var(--line)); }
.sla--warn  { border-color: var(--sev-minor); }
.sla--bad   { border-color: var(--sev-critical); color: var(--sev-critical); }
.sla--muted { opacity: .6; }
.sla-cell { white-space: nowrap; }

/* SLA clock detail on a record page. */
.clock { padding: var(--sp-3) 0; border-bottom: 1px solid var(--line); }
.clock:last-child { border-bottom: 0; }
.clock__head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; }
.clock__metric { font-weight: 600; font-size: var(--fs-sm); }
.clock__foot { font-size: var(--fs-xs); color: var(--text-dim); margin-top: 5px; font-variant-numeric: tabular-nums; }

/* The recorded working behind a clock. Collapsed, because it only matters when
   somebody disputes the total — but it must always be there when they do. */
.segments { margin-top: var(--sp-2); }
.segments summary {
  cursor: pointer; font-size: var(--fs-xs); color: var(--text-dim);
  padding: 4px 0; user-select: none;
}
.segments summary:hover { color: var(--text); }
.data--compact th, .data--compact td { padding: 3px 8px; font-size: var(--fs-xs); }

.action-row {
  display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: center;
  padding-bottom: var(--sp-3);
}
.assign-row {
  display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap;
  padding-top: var(--sp-3); border-top: 1px solid var(--line);
}

/* Case conversation. Inbound and outbound are offset so the direction of a
   message is legible without reading the label. */
.thread { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-3); }
.thread__item {
  border: 1px solid var(--line);
  border-radius: var(--r-inline);
  padding: var(--sp-3);
  background: var(--bg-raised);
  max-width: 78%;
}
.thread__item--inbound { align-self: flex-start; border-left: 3px solid var(--line-strong); }
.thread__item--outbound { align-self: flex-end; border-left: 3px solid var(--accent); }
/* An internal note is visually distinct from a sent reply, because mistaking one
   for the other is how private remarks reach a member of the public. */
.thread__item--internal {
  background: var(--bg-sunken);
  border-style: dashed;
  border-left-color: var(--sev-minor);
  align-self: stretch;
  max-width: 100%;
}
.thread__meta { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; margin-bottom: 5px; }
.thread__author { font-weight: 600; font-size: var(--fs-sm); }
.thread__time { font-size: var(--fs-micro); color: var(--text-faint); font-variant-numeric: tabular-nums; margin-left: auto; }
.thread__body { margin: 0; font-size: var(--fs-sm); }
.thread__reply { padding-top: var(--sp-4); margin-top: var(--sp-4); border-top: 1px solid var(--line); }

.form { display: flex; flex-direction: column; gap: var(--sp-4); }
.form__actions { display: flex; gap: var(--sp-3); align-items: center; flex-wrap: wrap; }

/* ==========================================================================
   Phase 4 — CRM and billing
   ========================================================================== */

/* Invoice totals. A definition list rather than a table: these are label/value
   pairs, and the grand total needs to be the thing the eye lands on. */
.totals {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 4px var(--sp-5);
  justify-content: end;
  max-width: 26rem;
  margin-left: auto;
  padding: var(--sp-4) 0 0;
  border-top: 1px solid var(--line);
}
.totals dt { color: var(--text-dim); font-size: var(--fs-sm); }
.totals dd {
  margin: 0; text-align: right;
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-sm);
}
.totals__grand {
  padding-top: var(--sp-2);
  margin-top: var(--sp-2);
  border-top: 1px solid var(--line-strong);
  font-size: var(--fs-md);
  font-weight: 700;
  color: var(--text);
}

/* Receivables ageing. Buckets side by side with a proportional bar, so the shape
   of the debt is legible before any number is read. */
.ageing {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
  gap: var(--sp-4);
}
.ageing__bucket { display: flex; flex-direction: column; gap: 5px; }
.ageing__label {
  font-size: var(--fs-micro);
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--text-faint);
}
.ageing__value {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  font-size: var(--fs-sm);
}

/* ==========================================================================
   Phase 5 — map, drill-down, dashboards
   ========================================================================== */

/* The map. A fixed viewBox scaled by the container, so the projection is computed
   once server-side and the browser only stretches it. */
.mapframe {
  border: 1px solid var(--line);
  border-radius: var(--r-inline);
  background: var(--bg-sunken);
  overflow: hidden;
}
.mapsvg { display: block; width: 100%; height: auto; }

.maplayer--accent { --map-ink: var(--accent); }
.maplayer--ok     { --map-ink: var(--sev-ok); }
.maplayer--warn   { --map-ink: var(--sev-warning); }
.maplayer--info   { --map-ink: var(--sev-info); }

.mapline {
  fill: none;
  stroke: var(--map-ink, var(--accent));
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
  opacity: .75;
}
.mapdot {
  fill: var(--map-ink, var(--accent));
  stroke: var(--bg-raised);
  stroke-width: 1.5;
}
/* Severity beats layer colour: an element carrying a critical alarm must read as
   critical wherever it sits. */
.mapdot--critical { fill: var(--sev-critical); }
.mapdot--major    { fill: var(--sev-critical); }
.mapdot--minor    { fill: var(--sev-warning); }
.mapdot--warning  { fill: var(--sev-warning); }
.mapdot--down     { fill: var(--sev-critical); }
.mapdot--unknown  { fill: var(--text-faint); }

.mapscale line { stroke: var(--text-dim); stroke-width: 1; }
.mapscale text {
  fill: var(--text-dim);
  font-size: 11px;
  font-family: var(--font-mono);
}

/* Layer toggles and dashboard switcher. */
.layer-bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  padding: var(--sp-3) 0;
}
.layer-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 4px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: var(--fs-sm);
  color: var(--text-dim);
  text-decoration: none;
  background: var(--bg-raised);
}
.layer-chip:hover { border-color: var(--line-strong); color: var(--text); }
.layer-chip--on {
  border-color: var(--accent);
  color: var(--text);
  background: var(--tint);
}
.layer-chip__swatch { width: 9px; height: 9px; border-radius: 2px; background: var(--accent); }
.layer-chip__swatch--ok   { background: var(--sev-ok); }
.layer-chip__swatch--warn { background: var(--sev-warning); }
.layer-chip__swatch--info { background: var(--sev-info); }
.layer-chip__count {
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-micro);
  color: var(--text-faint);
}

/* Administrative drill-down. */
.drill {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  gap: var(--sp-3);
}
.drill__item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-inline);
  text-decoration: none;
  background: var(--bg-raised);
}
.drill__item:hover { border-color: var(--accent); }
.drill__name { font-weight: 600; color: var(--text); }
.drill__meta { font-size: var(--fs-micro); color: var(--text-faint); }

/* Dashboard grid. Widths are declared in twelfths, matching the stored grid. */
.widgets {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--sp-4);
}
.widget {
  grid-column: span 12;
  padding: var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--r-inline);
  background: var(--bg-raised);
}
.widget__title {
  margin: 0 0 var(--sp-3);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: .04em;
}
.widget__number { margin: 0; font-size: 2.4rem; font-weight: 700; line-height: 1; }
.widget__number--ok   { color: var(--sev-ok); }
.widget__number--warn { color: var(--sev-warning); }
.widget__number--bad  { color: var(--sev-critical); }
.widget__caption { margin: var(--sp-2) 0 0; font-size: var(--fs-sm); color: var(--text-faint); }
.widget__error { margin: 0; font-size: var(--fs-sm); color: var(--sev-critical); }
.widget__bars { list-style: none; margin: 0; padding: 0; display: grid; gap: 7px; }
.widget__bar {
  display: grid;
  grid-template-columns: 8rem 1fr auto;
  align-items: center;
  gap: var(--sp-3);
  font-size: var(--fs-sm);
}
.widget__bar-label { color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.widget__bar-value { font-variant-numeric: tabular-nums; }

@media (min-width: 60rem) {
  .widget--w3 { grid-column: span 3; }
  .widget--w4 { grid-column: span 4; }
  .widget--w6 { grid-column: span 6; }
  .widget--w8 { grid-column: span 8; }
}

/* An inline reason field on a dismissal, kept narrow so it does not dominate the row. */
.dismiss-form { display: inline-flex; gap: var(--sp-2); align-items: center; }
.input--xs {
  height: 26px;
  padding: 0 var(--sp-2);
  font-size: var(--fs-micro);
  max-width: 9rem;
}

/* ==========================================================================
   Phase 6 — communications and the report designer
   ========================================================================== */

/* Column pickers in the report designer. Many short checkboxes read better in
   columns than in a single long list. */
.check-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: var(--sp-2) var(--sp-4);
}

/* ==========================================================================
   Peach — theme chrome
   ==========================================================================
   Every other theme is carried entirely by the five tokens ThemeRegistry emits.
   Peach is the exception: its character is the blue-to-rose wash down the
   navigation and the sky-blue panel headers, neither of which a token can express.

   The stops below are sampled from the reference build rather than chosen by eye —
   a gradient guessed from a description lands in the right family and the wrong
   place, and this one is the product's face. Everything is scoped to the theme, so
   no rule here can reach another palette, and all of it is chrome: no data surface,
   no severity colour, no control. */

/* Navigation: sky blue at the masthead, through lavender, to rose at the foot. */
[data-theme="peach"][data-mode="light"] .sidebar,
[data-theme="peach"][data-mode="light"] .brand {
  background-image: linear-gradient(180deg,
    #d0edff 0%, #d2e5f6 12%, #d6dde7 24%, #d6d3e4 34%,
    #e1d5e3 46%, #e5cfdc 58%, #efc4ce 76%, #f6bec9 88%, #fab6c1 100%);
}
[data-theme="peach"][data-mode="light"] .brand {
  border-bottom-color: rgba(16 22 34 / 0.09);
}
[data-theme="peach"][data-mode="dark"] .sidebar,
[data-theme="peach"][data-mode="dark"] .brand {
  background-image: linear-gradient(180deg,
    #101a28 0%, #141c2a 32%, #1a1a26 52%, #241a22 76%, #2d1a20 100%);
}

/* The brand block sits at the top of the same column as the sidebar, so it takes the
   masthead end of the gradient rather than a gradient of its own. */
[data-theme="peach"] .brand { background-size: 100% 100vh; background-repeat: no-repeat; }
[data-theme="peach"] .sidebar { background-size: 100% 100%; }

/* Panel headers: near-white at the left, sky blue at the right, so a card reads as
   part of the chrome rather than as a cut-out. A wash only — the header holds a
   title, never data. */
[data-theme="peach"][data-mode="light"] .card__head {
  background-image: linear-gradient(90deg, #fbf6f8 0%, #e2effb 55%, #c9e9fe 100%);
  border-bottom-color: rgba(16 22 34 / 0.10);
}
[data-theme="peach"][data-mode="dark"] .card__head {
  background-image: linear-gradient(90deg, #171a22 0%, #16202e 55%, #15293d 100%);
}

/* The wash puts a tinted surface behind the navigation, so hover needs more weight
   than the shared neutral to stay visible against it. The selected state keeps the
   shared treatment: --accent-lo is a solid pale sky fill, which reads at every point
   down the gradient. */
[data-theme="peach"][data-mode="light"] .nav-link:hover { background: rgba(255 255 255 / 0.55); }
[data-theme="peach"][data-mode="dark"]  .nav-link:hover { background: rgba(var(--tint) / 0.20); }

/* Sign-in: the first thing anyone sees of the palette, so it carries the same wash.
   The dot grid is a background-image too, and a second layer needs its own size or
   the gradient tiles at 22px along with the dots. */
[data-theme="peach"][data-mode="light"] .auth__aside {
  background-size: 22px 22px, cover;
  background-image:
    radial-gradient(circle at 1px 1px, var(--line) 1px, transparent 0),
    linear-gradient(160deg, #cfeafb 0%, #dcdfee 46%, #eecbd7 78%, #f9bac3 100%);
}
[data-theme="peach"][data-mode="dark"] .auth__aside {
  background-size: 22px 22px, cover;
  background-image:
    radial-gradient(circle at 1px 1px, var(--line) 1px, transparent 0),
    linear-gradient(160deg, #101a28 0%, #1a1a26 52%, #2d1a20 100%);
}
