/* Cloudify admin — shared design system.
   Airgap-safe: no external fonts/CDNs; icons are inline-SVG data-URIs used as
   CSS masks so they inherit currentColor. Keeps the established palette + Inter. */

:root {
  --bg: #0c0d0f; --bg-2: #101012;
  --surface: #17181b; --surface-2: #1d1f23; --surface-3: #232529;
  /* recessed/raised surfaces that were hardcoded ~40x across templates+JS */
  --surface-inset: #101113;   /* text inputs, wells */
  --surface-0: #0d0e11;       /* popovers, toasts, console bars */
  --on-green: #062b21;        /* text on a green (primary) fill */
  --border: #2c2f34; --border-soft: #24262b;
  --line: #24262b;            /* was referenced via var(--line,#23262b) but never defined */
  --text: #f4f5f6; --text-2: #c9cdd2; --muted: #8a9099;
  --green: #13d39e; --green-2: #0fa97e; --green-soft: rgba(19,211,158,.12);
  --amber: #f5a623; --red: #e5484d; --blue: #4aa3ff; --violet: #a78bfa;
  --font: "Inter", "Inter 28pt", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, monospace;
  --radius: 14px;
  --shadow: 0 1px 0 rgba(255,255,255,.03) inset, 0 12px 30px -12px rgba(0,0,0,.6);
  --shadow-lg: 0 24px 60px -20px rgba(0,0,0,.7);
  --appbar-h: 57px;
  --side-w: 240px;
  --rail-w: 62px;
}
* { box-sizing: border-box; }
html, body { min-height: 100%; }
/* app-like feel: no text I-beam over content; pointer only on interactive bits */
body { cursor: default; }
a, button, .btn, select, [role="button"], summary { cursor: pointer; }
input, textarea { cursor: text; }
body {
  margin: 0; font: 14px/1.55 var(--font); color: var(--text);
  background:
    radial-gradient(900px 520px at 12% -8%, rgba(19,211,158,.10), transparent 60%),
    radial-gradient(820px 560px at 108% 118%, rgba(74,163,255,.06), transparent 55%),
    var(--bg);
  background-attachment: fixed;
}
/* the constellation artwork, very low opacity, fixed behind everything */
body::before {
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background: url("bg-mesh.svg") center/cover no-repeat;
  opacity: .32;
  -webkit-mask-image: radial-gradient(120% 100% at 50% 0%, #000 40%, transparent 92%);
          mask-image: radial-gradient(120% 100% at 50% 0%, #000 40%, transparent 92%);
}
a { color: var(--green); text-decoration: none; }
a:hover { color: var(--green-2); }

/* ---- app header (glass) ---- */
.appbar {
  display: flex; align-items: center; gap: .9rem; padding: .8rem 1.5rem;
  border-bottom: 1px solid var(--border-soft); position: sticky; top: 0; z-index: 20;
  background: linear-gradient(180deg, rgba(20,21,24,.86), rgba(16,16,18,.72));
  backdrop-filter: blur(14px) saturate(1.2); -webkit-backdrop-filter: blur(14px) saturate(1.2);
}
.appbar::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(19,211,158,.5), transparent);
}
/* Brand lockup: the geometric mark (a text-free SVG) + "Atun" as live text in
   the app font. The retired logo drew the old product wordmark as vector paths,
   so renaming the file could never have fixed what it visually said. */
.appbar img.logo { height: 24px; display: block; }
.brandmark { display: inline-flex; align-items: center; gap: .5rem; }
.brandmark .wordmark {
  font-size: 1.02rem; font-weight: 700; letter-spacing: -.01em; color: var(--text);
  line-height: 1;
}
.appbar .spacer { flex: 1; }
.appbar .who { color: var(--muted); font-size: .82rem; }
.appbar .who b { color: var(--text-2); font-weight: 600; }
.tag {
  font-size: .62rem; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  color: var(--green); border: 1px solid rgba(19,211,158,.35); background: var(--green-soft);
  padding: .18rem .5rem; border-radius: 999px;
}
.back { color: var(--muted); font-size: .85rem; display: inline-flex; align-items: center; gap: .35rem; }
.back:hover { color: var(--text); }
.btn {
  padding: .4rem .8rem; font: inherit; font-size: .8rem; cursor: pointer; color: var(--text-2);
  border: 1px solid var(--border); border-radius: 9px; background: rgba(255,255,255,.02);
  display: inline-flex; align-items: center; gap: .4rem; transition: .15s;
}
.btn:hover { border-color: var(--muted); color: var(--text); background: rgba(255,255,255,.05); }
/* Canonical primary button. Lived only in clusters.css/registry.css before, so
   `class="btn primary"` silently rendered as a plain grey .btn on every page
   that loaded neither (node, index, backups, settings, tenant-detail). */
.btn.primary {
  /* ⚠ TRANSPARENT 1px BORDER, NOT `border: 0`. Every other .btn carries a 1px
     border, so a borderless primary is 2px SHORTER than anything standing next to
     it — visible as mismatched heights wherever a primary and a plain/danger button
     share a row (the Backups page's "New instance…" beside "Delete…"). A
     transparent border keeps the gradient look identical and restores box parity
     everywhere at once, instead of patching each row that happens to pair them. */
  color: var(--on-green); border: 1px solid transparent; font-weight: 650;
  background: linear-gradient(180deg, var(--green), var(--green-2));
}
.btn.primary:hover { filter: brightness(1.06); color: var(--on-green); }

/* ---- file inputs -------------------------------------------------------------
   The browser default ("Choose File | no file selected") ignores every token on
   the page — wrong font, wrong colours, a grey OS button on a dark panel. Two
   file inputs exist (registry upload, settings bundle restore) and BOTH looked
   unstyled. Global, not page-local, so a third one is styled the day it is added
   — the `.detail-top`/`.scrim` page-local trap has cost this project twice.
   ::file-selector-button is the standard selector; ::-webkit-file-upload-button
   is kept for older WebKit. */
input[type=file] {
  width: 100%; font: inherit; font-size: .8rem; color: var(--text-2);
  border: 1px dashed var(--border); border-radius: 9px;
  padding: .45rem .55rem; background: rgba(255,255,255,.02);
  cursor: pointer; transition: .15s;
}
input[type=file]:hover { border-color: var(--muted); color: var(--text); }
input[type=file]::file-selector-button,
input[type=file]::-webkit-file-upload-button {
  font: inherit; font-size: .78rem; font-weight: 600; cursor: pointer;
  margin-right: .6rem; padding: .3rem .7rem; border-radius: 7px;
  border: 1px solid var(--border); color: var(--text-2);
  background: rgba(255,255,255,.04); transition: .15s;
}
input[type=file]:hover::file-selector-button,
input[type=file]:hover::-webkit-file-upload-button {
  border-color: var(--muted); color: var(--text);
}
/* Section/panel/card headers force their icons green. A primary button sitting
   inside one of those headers would render a green icon on a green fill, so the
   icon must inherit the button's own text colour instead. */
.btn.primary .ico,
.section-h .btn.primary .ico, .panel-h .btn.primary .ico, .card-h .btn.primary .ico { color: inherit; }
.btn.primary:disabled, .btn:disabled { opacity: .45; cursor: default; filter: none; }
.btn.danger { color: #ff9ea0; border-color: rgba(229,72,77,.4); }
.btn.danger:hover { background: rgba(229,72,77,.14); color: #ffb3b5; }

/* One focus ring for the whole app. Keyboard users get a visible ring even
   where a component clears the native outline. */
:where(a, button, .btn, select, input, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--green); outline-offset: 2px; border-radius: inherit;
}

/* Screen-reader-only text — gives icon-only controls and status dots a name. */
.vh {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* One spinner. Was reimplemented 5 ways with @keyframes spin declared 4 times. */
.spinner {
  display: inline-block; width: var(--spinner-size, 12px); height: var(--spinner-size, 12px);
  border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%;
  animation: spin .7s linear infinite; vertical-align: -1px;
}
.spinner.busy { border-color: rgba(245,166,35,.3); border-top-color: var(--amber); }
@keyframes spin { to { transform: rotate(360deg); } }

/* ---- shell: sidebar + content ---- */
.navtoggle { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; border: 1px solid var(--border); border-radius: 9px; background: rgba(255,255,255,.02); color: var(--text-2); cursor: pointer; }
.navtoggle:hover { color: var(--text); border-color: var(--muted); }
.shell { display: flex; align-items: flex-start; }
.side {
  width: var(--side-w); flex-shrink: 0; position: sticky; top: var(--appbar-h);
  height: calc(100vh - var(--appbar-h)); overflow-y: auto; overflow-x: hidden;
  border-right: 1px solid var(--border-soft); background: linear-gradient(180deg, rgba(20,21,24,.55), rgba(14,14,16,.35));
  padding: .9rem .6rem 1.4rem; transition: width .16s ease;
}
.side::-webkit-scrollbar { width: 8px; } .side::-webkit-scrollbar-thumb { background: #2a2c31; border-radius: 8px; }
.shell > main, .shell > .content { flex: 1; min-width: 0; }
.grp { font-size: .64rem; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); font-weight: 700; padding: .9rem .7rem .35rem; }
.grp:first-child { padding-top: .2rem; }
/* collapsible groups (accordion) — the .grp label is a real <button> inside a
   .nav-group wrapper, so it needs the element resets a button doesn't inherit,
   and it is STYLED as a button: its own surface, border and hover/open states. */
.nav-group { margin-bottom: .55rem; }          /* air between the top-level buttons */
.nav-group:last-child { margin-bottom: 0; }
.side .grp {
  display: flex; align-items: center; gap: .4rem; width: 100%; cursor: pointer;
  font-family: inherit; font-size: .76rem; letter-spacing: .06em; font-weight: 700;
  padding: .58rem .7rem; border-radius: 9px; text-align: left;
  background: rgba(255,255,255,.03); border: 1px solid var(--border-soft); color: var(--text-2);
  transition: background .14s ease, border-color .14s ease, color .14s ease;
}
.side .grp:hover { background: rgba(255,255,255,.06); border-color: var(--border); color: var(--text); }
.nav-group.open > .grp { background: rgba(255,255,255,.055); border-color: var(--border); color: var(--text); }
.nav-group > ul { display: none; }
/* sub-items sit indented under their button, with a guide line to read as children */
.nav-group.open > ul {
  display: block; margin: .3rem 0 0 .85rem; padding-left: .5rem;
  border-left: 1px solid var(--border-soft);
}
.grp .chev { margin-left: auto; width: .85rem; height: .85rem; opacity: .55; transition: transform .16s ease; }
.nav-group:not(.open) > .grp .chev { transform: rotate(-90deg); }
/* a collapsed group still shows where you are */
.nav-group.has-active:not(.open) > .grp { color: var(--green); border-color: var(--green-soft); }
/* ★ THIRD NAV LEVEL — Managed Services (2026-07-28). A .nav-sub is a level-2 row that
   TOGGLES instead of navigating; its <ul> holds the level-3 service links. Deliberately
   reuses .nav-item for the leaves (see leaf() in nav.js) so active/hover/soon styling can
   never drift between levels — the only difference is the indent below. */
.side .grp .grp-i { width: 1rem; height: 1rem; opacity: .8; flex-shrink: 0; }
.nav-sub > .sub-h {
  display: flex; align-items: center; gap: .65rem; width: 100%; cursor: pointer;
  font-family: inherit; font-size: .82rem; font-weight: 600; text-align: left;
  padding: .46rem .7rem; margin: .1rem 0; border-radius: 9px;
  background: none; border: 1px solid transparent; color: var(--text-2);
  transition: background .14s ease, color .14s ease;
}
.nav-sub > .sub-h:hover { background: rgba(255,255,255,.04); color: var(--text); }
.nav-sub > .sub-h .ico { flex-shrink: 0; width: 1.15rem; height: 1.15rem; opacity: .85; }
.nav-sub > .sub-h .txt { white-space: nowrap; }
/* the count sits where a leaf's SOON chip does, so the two columns line up */
.nav-sub > .sub-h .sub-n {
  margin-left: auto; font-size: .6rem; font-weight: 700; color: var(--muted);
  background: rgba(255,255,255,.05); border-radius: 999px; padding: .05rem .38rem; min-width: 1.1rem; text-align: center;
}
.nav-sub > .sub-h .chev { width: .8rem; height: .8rem; opacity: .5; margin-left: .3rem; transition: transform .16s ease; }
.nav-sub:not(.open) > .sub-h .chev { transform: rotate(-90deg); }
.nav-sub.has-active:not(.open) > .sub-h { color: var(--green); }
.nav-sub > ul { display: none; }
.nav-sub.open > ul { display: block; margin: .1rem 0 .25rem .95rem; padding-left: .55rem; border-left: 1px solid var(--border-soft); }
/* level-3 leaf: one indent step in, slightly smaller, and its active marker moves onto
   the inner guide line the same way .nav-group > ul does for level 2. */
.nav-item.sub-item { font-size: .82rem; padding: .4rem .6rem; }
.nav-item.sub-item .ico { width: 1rem; height: 1rem; opacity: .75; }
.nav-sub > ul .nav-item.active::before { left: -9px; }
.nav-item {
  display: flex; align-items: center; gap: .65rem; padding: .5rem .7rem; margin: .1rem 0; border-radius: 9px;
  color: var(--text-2); font-size: .86rem; font-weight: 500; white-space: nowrap; position: relative; cursor: pointer;
}
.nav-item:hover { background: rgba(255,255,255,.04); color: var(--text); }
.nav-item .ico { flex-shrink: 0; width: 1.15rem; height: 1.15rem; opacity: .85; }
.nav-item.active { color: var(--green); background: var(--green-soft); }
.nav-item.active::before { content: ""; position: absolute; left: -6px; top: 8px; bottom: 8px; width: 3px; border-radius: 3px; background: var(--green); }
/* inside a group the marker lands ON the guide line, so the active item lights up its segment */
.nav-group > ul .nav-item.active::before { left: -9px; }
.nav-item.soon { color: var(--muted); }
.nav-item.soon:hover { color: var(--text-2); }
.nav-item .soon-chip { margin-left: auto; font-size: .56rem; font-weight: 700; letter-spacing: .05em; color: var(--muted); border: 1px solid var(--border); border-radius: 5px; padding: .05rem .3rem; }
/* rail (whole-sidebar collapse) — ★ INERT since 2026-07-27: the toggle control was
   removed and nothing sets `body.rail` any more (the sidebar is fixed open, sections
   collapse individually instead). Kept so the mode can be revived without rewriting it. */
body.rail .side { width: var(--rail-w); padding: .9rem .5rem 1.4rem; }
/* in the rail there is no label to put on a button, and no room to indent under
   one — so the group button drops its chrome back to a plain "•••" separator. */
body.rail .side .grp { text-align: center; font-size: 0; padding: .55rem 0 .2rem; justify-content: center; background: none; border-color: transparent; }
body.rail .side .grp:hover { background: none; border-color: transparent; }
body.rail .side .grp::after { content: "•••"; font-size: .6rem; letter-spacing: .1em; color: var(--border); }
/* the rail has no labels to collapse under, so every group stays open there */
body.rail .nav-group { margin-bottom: .2rem; }
body.rail .nav-group > ul, body.rail .nav-group.open > ul { display: block; margin: 0; padding-left: 0; border-left: 0; }
body.rail .grp .chev { display: none; }
body.rail .nav-item { justify-content: center; gap: 0; padding: .55rem 0; }
body.rail .nav-item .txt, body.rail .nav-item .soon-chip { display: none; }
body.rail .nav-item.active::before { left: -5px; }

main { padding: 1.6rem; max-width: 1360px; margin: 0 auto; }

/* ---- section heading ---- */
.section-h { display: flex; align-items: center; gap: .55rem; font-weight: 650; font-size: .95rem; margin: 0 0 .85rem; }
.section-h .muted { color: var(--muted); font-weight: 400; font-size: .8rem; }
.section-h .ico { color: var(--green); }

/* ---- stat tiles ---- */
.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(158px, 1fr)); gap: 1rem; margin-bottom: 1.6rem; }
.tile {
  position: relative; padding: 1rem 1.15rem; border-radius: var(--radius); overflow: hidden;
  border: 1px solid var(--border); background: linear-gradient(180deg, var(--surface-2), var(--surface));
  box-shadow: var(--shadow);
}
.tile::before { content: ""; position: absolute; inset: 0 auto 0 0; width: 3px; background: var(--muted); opacity: .5; }
.tile.up::before { background: var(--green); opacity: 1; }
.tile.down::before { background: var(--red); opacity: 1; }
.tile .thead { display: flex; align-items: center; gap: .45rem; color: var(--muted); font-size: .72rem; text-transform: uppercase; letter-spacing: .06em; }
.tile .n { font-size: 2rem; font-weight: 750; line-height: 1.15; margin-top: .35rem; letter-spacing: -.02em; }
.tile.up .n { color: var(--green); } .tile.down .n { color: var(--red); }

/* ---- panels / cards ---- */
.panel { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; background: var(--surface); box-shadow: var(--shadow); }
.panel + .panel, .panel.my { margin-top: 1.4rem; }
.panel-h { padding: .85rem 1.15rem; border-bottom: 1px solid var(--border-soft); font-weight: 640; font-size: .9rem; display: flex; align-items: center; gap: .55rem; }
.panel-h .ico { color: var(--green); }
.panel-h .muted { color: var(--muted); font-weight: 400; font-size: .8rem; }
.card { border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); overflow: hidden; box-shadow: var(--shadow); }
.card-h { padding: .75rem 1rem; border-bottom: 1px solid var(--border-soft); font-weight: 620; font-size: .86rem; display: flex; align-items: center; gap: .5rem; }
.card-h .ico { color: var(--green); }
.card-h .muted { color: var(--muted); font-weight: 400; font-size: .78rem; }
.card-b { padding: .95rem 1rem; }

/* ---- tables ---- */
.scroll { overflow-x: auto; }
table { border-collapse: collapse; width: 100%; font-size: .85rem; white-space: nowrap; }
thead th { position: sticky; top: 0; }
th, td { padding: .58rem 1rem; border-bottom: 1px solid var(--border-soft); vertical-align: middle; }
/* Headers align LEFT to match the browser's native left-aligned <td>. A centered
   default made every header label float right of its own column's values, which
   read as "the values belong to the wrong header" — the bug had to be re-fixed
   per page and was still missed on tenant-detail / tenants-overview / manage.
   Opt a column out with .tl/.tc/.tr on BOTH its <th> and its <td>. */
th { font-size: .67rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); font-weight: 650; text-align: left; background: var(--surface-2); }
th.tl, td.tl { text-align: left; }
th.tc, td.tc { text-align: center; }
th.tr, td.tr { text-align: right; }
tbody tr:last-child td { border-bottom: 0; }
tbody tr { transition: background .1s; }
tbody tr:hover { background: rgba(255,255,255,.025); }

/* fixed-layout + truncation helper — add `tbl-fixed` to a <table> and give each
   column a width; long cells then ellipsis instead of forcing a horizontal
   scrollbar. Cells that must stay full (an ops menu, a pill group) get `.nowrap-full`. */
table.tbl-fixed { table-layout: fixed; }
table.tbl-fixed th, table.tbl-fixed td { overflow: hidden; text-overflow: ellipsis; }
table.tbl-fixed td.no-ellipsis { overflow: visible; text-overflow: clip; }

/* ---- shared "Ops" row-action popup menu (was inline-duplicated in manage /
   tenant-vms; promoted here so every page uses the same component). The menu is
   position:fixed + JS-positioned so it never spawns a scrollbar inside a
   .scroll wrapper. Keep the .opsmenu class name — nav.js uiBusy() keys on it. */
.ops { position: relative; display: inline-flex; }
.opsbtn { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 26px;
  border: 1px solid var(--border); border-radius: 8px; background: rgba(255,255,255,.03); color: var(--text-2); cursor: pointer; }
.opsbtn:hover { color: var(--text); border-color: var(--muted); }
.opsmenu { position: fixed; z-index: 40; min-width: 176px; padding: .3rem; background: #0d0e11;
  border: 1px solid var(--border); border-radius: 10px; box-shadow: var(--shadow-lg); }
.opsmenu[hidden] { display: none; }
.opsmenu button { display: flex; align-items: center; gap: .55rem; width: 100%; text-align: left; font: inherit;
  font-size: .82rem; color: var(--text-2); background: none; border: 0; padding: .45rem .55rem; border-radius: 7px; cursor: pointer; }
.opsmenu button:hover { background: rgba(255,255,255,.05); color: var(--text); }
.opsmenu button.danger { color: #ff9ea0; }
.opsmenu button.danger:hover { background: rgba(229,72,77,.14); }
.opsmenu button:disabled { opacity: .4; cursor: default; }
.opsmenu .sep { height: 1px; background: var(--border-soft); margin: .25rem .2rem; }
.opsmenu .ico { width: .95rem; height: .95rem; }

/* ---- status dot / chips / badges / pills ---- */
.dot { display: inline-block; width: .62rem; height: .62rem; border-radius: 50%; }
.dot.up { background: var(--green); box-shadow: 0 0 9px rgba(19,211,158,.7); }
.dot.down { background: #4a2b2c; border: 1px solid var(--red); }
.chip { display: inline-flex; align-items: center; gap: .3rem; font-size: .72rem; padding: .13rem .5rem; border-radius: 7px; color: var(--text-2); background: var(--surface-3); border: 1px solid var(--border); }
.chip .ico { opacity: .8; }
.egip { font-family: ui-monospace, monospace; font-size: .78rem; color: var(--blue); }
.chip.compute { color: #9fe6d4; } .chip.gpu { color: var(--violet); } .chip.cphost { color: var(--blue); } .chip.network { color: #7dd3fc; } .chip.mixed { color: var(--amber); } .chip.controlplane { color: var(--green); }
/* agent debug-on flag (fleet views) */
.dbgb { font-size: .58rem; font-weight: 700; letter-spacing: .04em; color: var(--amber); border: 1px solid rgba(245,166,35,.45); background: rgba(245,166,35,.12); border-radius: 5px; padding: .05rem .3rem; vertical-align: 1px; }
.state { font-size: .78rem; color: var(--text-2); }
.state.enrolled, .state.prepped { color: var(--amber); }
.state.decommissioned, .state.removed, .state.cordoned { color: var(--muted); }
.state.decommissioning { color: var(--amber); }  /* in progress: agent cleanup + reboot */
.state.ok { color: var(--green); } .state.bad { color: var(--red); }
.badge { font-size: .63rem; font-weight: 700; letter-spacing: .04em; padding: .12rem .45rem; border-radius: 6px; margin-left: .4rem; vertical-align: middle; display: inline-flex; align-items: center; gap: .25rem; }
.badge.cordoned { color: var(--amber); border: 1px solid rgba(245,166,35,.4); background: rgba(245,166,35,.12); }
.badge.notready { color: var(--red); border: 1px solid rgba(229,72,77,.4); background: rgba(229,72,77,.12); }
.badge.drift { color: var(--red); border: 1px solid rgba(229,72,77,.5); background: rgba(229,72,77,.14); }
/* was #fff on --red = 3.91:1, under the 4.5:1 floor for this small bold text */
.badge.conflict { color: #2a0507; border: 1px solid #ff8b8e; background: #ff8b8e; }
.pill { font-size: .7rem; font-weight: 600; padding: .12rem .5rem; border-radius: 999px; border: 1px solid var(--border); color: var(--text-2); }
.pill.ok { color: var(--green); border-color: rgba(19,211,158,.4); background: var(--green-soft); }
.pill.warn { color: var(--amber); border-color: rgba(245,166,35,.4); background: rgba(245,166,35,.12); }
.pill.bad { color: var(--red); border-color: rgba(229,72,77,.4); background: rgba(229,72,77,.12); }
.cert.soon { color: var(--amber); } .cert.crit { color: var(--red); }
.seen { color: var(--muted); font-size: .8rem; }
.mono { font-family: var(--mono); font-size: .82rem; }
a.nodelink { color: var(--text); border-bottom: 1px dotted color-mix(in srgb, var(--green) 55%, transparent); }
a.nodelink:hover { color: var(--green); }

/* ---- resource meter cell ---- */
.meter { display: flex; flex-direction: column; gap: .24rem; min-width: 104px; }
.meter .mlbl { font-size: .78rem; color: var(--text-2); }
.meter .bar { height: 5px; border-radius: 4px; background: #2a2c30; overflow: hidden; }
.meter .bar > i { display: block; height: 100%; background: linear-gradient(90deg, var(--green-2), var(--green)); border-radius: 4px; }
.meter .bar > i.warn { background: linear-gradient(90deg, #c8871a, var(--amber)); }
.meter .bar > i.crit { background: linear-gradient(90deg, #b83a3e, var(--red)); }

/* ---- icons (CSS mask, inherit currentColor) ---- */
.ico { display: inline-block; width: 1.05em; height: 1.05em; background: currentColor; vertical-align: -.16em;
  -webkit-mask: var(--i) center/contain no-repeat; mask: var(--i) center/contain no-repeat; }
.ico-server{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round"><rect x="3" y="4" width="18" height="7" rx="1.5"/><rect x="3" y="13" width="18" height="7" rx="1.5"/><circle cx="7" cy="7.5" r=".6" fill="black"/><circle cx="7" cy="16.5" r=".6" fill="black"/></svg>');}
.ico-up{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>');}
.ico-down{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round"><path d="M18 6 6 18M6 6l12 12"/></svg>');}
.ico-cpu{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><rect x="7" y="7" width="10" height="10" rx="1.5"/><path d="M9 2v3M15 2v3M9 19v3M15 19v3M2 9h3M2 15h3M19 9h3M19 15h3" stroke-linecap="round"/></svg>');}
.ico-mem{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><rect x="3" y="7" width="18" height="10" rx="1.5"/><path d="M7 17v2M12 17v2M17 17v2M7 11v2M12 11v2M17 11v2" stroke-linecap="round"/></svg>');}
.ico-disk{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="3"/><path d="M12 3v6" stroke-linecap="round"/></svg>');}
.ico-shield{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><path d="M12 3l7 3v5c0 4.5-3 7.5-7 9-4-1.5-7-4.5-7-9V6z"/></svg>');}
.ico-clock{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>');}
.ico-cert{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><circle cx="12" cy="9" r="5"/><path d="M9 13l-2 8 5-3 5 3-2-8" stroke-linecap="round"/></svg>');}
.ico-network{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8"><circle cx="5" cy="6" r="2"/><circle cx="19" cy="6" r="2"/><circle cx="12" cy="18" r="2"/><path d="M6.5 7.5 11 16M17.5 7.5 13 16M7 6h10" stroke-linecap="round"/></svg>');}
/* ★ Managed Services (2026-07-28). Four icons the set was missing — same stroke-only 24x24
   shape language as the rest, so they mask identically through .ico's currentColor mask. */
/* ★ 2026-07-28 (Eslam): EVERY nav entry above the service leaves must carry its OWN icon —
   28 slots, and the set only had 15 distinct ones that suit a nav. These eight close the gap.
   Same stroke-only 24x24 language so they mask identically; no # or % (the data URI is
   unescaped utf8) and no apostrophes (the url() is single-quoted). */
/* ★ 2026-07-28 (Eslam): the 17 SERVICE LEAVES get their own icons too, so all 45 nav entries
   are unique. Deliberately NOT vendor logos (trademark, and they do not survive a 16px mask):
   each glyph states the engine's DATA MODEL or role, and the six relational-ish engines get
   distinct SHAPES rather than cylinder-variants — the plain cylinder belongs to the parent
   "Database Services", so a leaf reusing it would read as the section, not the product. */
.ico-dbrel{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="1.8"/><path d="M3 9h18M3 14.5h18M9.5 9v11"/></svg>');}
.ico-dbwave{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="1.8"/><path d="M6 10c2-2 4 2 6 0s4-2 6 0M6 15c2-2 4 2 6 0s4-2 6 0" stroke-linecap="round"/></svg>');}
.ico-dbfork{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round"><path d="M12 21V12M12 12L6.5 6.5M12 12l5.5-5.5"/><circle cx="5" cy="5" r="1.8"/><circle cx="19" cy="5" r="1.8"/></svg>');}
.ico-dbglobe{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8"><circle cx="12" cy="12" r="9"/><path d="M3 12h18"/><ellipse cx="12" cy="12" rx="4" ry="9"/></svg>');}
.ico-leaf{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><path d="M20 4c0 9-6 15-15 15 0-9 6-15 15-15z"/><path d="M5.5 18.5c4-4 7.5-6.5 11.5-8.5" stroke-linecap="round"/></svg>');}
.ico-ring{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8"><circle cx="12" cy="12" r="7.5"/><circle cx="12" cy="4.5" r="1.7"/><circle cx="18.5" cy="15.8" r="1.7"/><circle cx="5.5" cy="15.8" r="1.7"/></svg>');}
.ico-vector{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4.5 19.5L18 6"/><path d="M18 6h-5M18 6v5"/><circle cx="8.5" cy="9" r="1.4"/><circle cx="15.5" cy="17" r="1.4"/></svg>');}
.ico-bolt{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><path d="M13 2.5L5 13.5h6l-2 8 8-11h-6z"/></svg>');}
.ico-slabs{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><rect x="3" y="4" width="18" height="4" rx="1.2"/><rect x="3" y="10" width="18" height="4" rx="1.2"/><rect x="3" y="16" width="18" height="4" rx="1.2"/></svg>');}
.ico-stream{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7h11l-2.5-2.5M3 12h15l-2.5-2.5M3 17h8l-2.5-2.5"/></svg>');}
.ico-envelope{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3.5 7.5l8.5 6 8.5-6" stroke-linecap="round"/></svg>');}
.ico-inbox{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><path d="M3 13l3-8h12l3 8v5a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><path d="M3 13h5l1.5 3h5L16 13h5"/></svg>');}
.ico-lens{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round"><path d="M4 6h9M4 10h6M4 14h4.5"/><circle cx="15.5" cy="14" r="4.8"/><path d="M19.2 17.6L21.5 20"/></svg>');}
.ico-compass{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M15.8 8.2l-2.2 5.4-5.4 2.2 2.2-5.4z"/></svg>');}
.ico-bucket{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><path d="M4 7.5h16l-1.6 12a2 2 0 0 1-2 1.7H7.6a2 2 0 0 1-2-1.7z"/><ellipse cx="12" cy="7" rx="8" ry="2.6"/></svg>');}
.ico-crate{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><rect x="3" y="6" width="18" height="14" rx="1.6"/><path d="M3 11h18M9 6v14M15 6v14"/></svg>');}
.ico-pulse{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h4l3-7 4 14 3-7h4"/></svg>');}
.ico-org{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><rect x="4" y="3" width="16" height="18" rx="1.6"/><path d="M9 7h2M13 7h2M9 11h2M13 11h2M9 15h2M13 15h2" stroke-linecap="round"/></svg>');}
.ico-gauge{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round"><path d="M4 18a8 8 0 1 1 16 0"/><path d="M12 18l4.5-5.5"/></svg>');}
.ico-vm{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><rect x="3" y="4" width="18" height="12" rx="1.8"/><path d="M8.5 20h7M12 16v4" stroke-linecap="round"/></svg>');}
.ico-link{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round"><path d="M10.5 13.5a4 4 0 0 0 5.7 0l2-2a4 4 0 0 0-5.7-5.7l-1 1"/><path d="M13.5 10.5a4 4 0 0 0-5.7 0l-2 2a4 4 0 0 0 5.7 5.7l1-1"/></svg>');}
.ico-archive{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><rect x="3" y="4" width="18" height="4" rx="1.2"/><path d="M5 8v11a1.5 1.5 0 0 0 1.5 1.5h11A1.5 1.5 0 0 0 19 19V8"/><path d="M10 12h4" stroke-linecap="round"/></svg>');}
.ico-ruler{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><rect x="2.5" y="8" width="19" height="8" rx="1.5"/><path d="M7 8v3M11 8v4M15 8v3M19 8v4" stroke-linecap="round"/></svg>');}
.ico-sliders{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round"><path d="M4 7h9M19 7h1M4 17h5M15 17h5"/><circle cx="16" cy="7" r="2.2"/><circle cx="12" cy="17" r="2.2"/></svg>');}
.ico-services{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><rect x="3" y="3" width="8" height="8" rx="1.6"/><rect x="13" y="3" width="8" height="8" rx="1.6"/><rect x="3" y="13" width="8" height="8" rx="1.6"/><circle cx="17" cy="17" r="4"/></svg>');}
.ico-database{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8"><ellipse cx="12" cy="6" rx="8" ry="3"/><path d="M4 6v12c0 1.7 3.6 3 8 3s8-1.3 8-3V6"/><path d="M4 12c0 1.7 3.6 3 8 3s8-1.3 8-3"/></svg>');}
.ico-queue{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><rect x="2.5" y="5" width="5" height="14" rx="1.4"/><rect x="9.5" y="5" width="5" height="14" rx="1.4"/><rect x="16.5" y="5" width="5" height="14" rx="1.4"/></svg>');}
.ico-search{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round"><circle cx="11" cy="11" r="7"/><path d="M20 20l-4.4-4.4"/></svg>');}
.ico-layers{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><path d="M12 3l9 5-9 5-9-5z"/><path d="M3 13l9 5 9-5"/></svg>');}
.ico-gpu{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><rect x="2" y="6" width="20" height="12" rx="2"/><circle cx="8" cy="12" r="2.4"/><circle cx="15" cy="12" r="2.4"/></svg>');}
.ico-history{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round"><path d="M3 12a9 9 0 1 0 3-6.7L3 8"/><path d="M3 3v5h5"/><path d="M12 8v4l3 2"/></svg>');}
.ico-logs{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z"/><path d="M14 3v5h5"/><path d="M8.5 13h7M8.5 16.5h7"/></svg>');}
.ico-chev{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"/></svg>');}
.ico-dots{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black"><circle cx="12" cy="5" r="1.7"/><circle cx="12" cy="12" r="1.7"/><circle cx="12" cy="19" r="1.7"/></svg>');}
.ico-wrench{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M14.7 6.3a4 4 0 0 0-5.4 5.2L3 17.8 6.2 21l6.3-6.3a4 4 0 0 0 5.2-5.4l-2.6 2.6-2.3-.6-.6-2.3z"/></svg>');}
.ico-check{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>');}
.ico-power{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v9"/><path d="M6.4 6.4a8 8 0 1 0 11.2 0"/></svg>');}
.ico-trash{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7h16M9 7V4h6v3M6 7l1 13h10l1-13"/></svg>');}
.ico-trend{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 15l5-5 4 3 6-7"/><path d="M21 6v4h-4"/></svg>');}
.ico-box{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><path d="M21 8l-9-5-9 5 9 5 9-5z"/><path d="M3 8v8l9 5 9-5V8"/></svg>');}
.ico-alert{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3 2 20h20z"/><path d="M12 9v5M12 17.5v.5"/></svg>');}
.ico-info{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round"><circle cx="12" cy="12" r="9"/><path d="M12 11v5M12 8v.5"/></svg>');}
.ico-fleet{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><rect x="3" y="4" width="7" height="7" rx="1.2"/><rect x="14" y="4" width="7" height="7" rx="1.2"/><rect x="3" y="14" width="7" height="6" rx="1.2"/><rect x="14" y="14" width="7" height="6" rx="1.2"/></svg>');}
.ico-users{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="8" r="3.2"/><path d="M3.5 20a5.5 5.5 0 0 1 11 0"/><path d="M16 5.2a3.2 3.2 0 0 1 0 6.1M17.5 14.4A5.5 5.5 0 0 1 20.5 20"/></svg>');}
.ico-gear{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3M4.9 4.9l2.1 2.1M17 17l2.1 2.1M19.1 4.9L17 7M7 17l-2.1 2.1"/></svg>');}
.ico-menu{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.9" stroke-linecap="round"><path d="M4 7h16M4 12h16M4 17h16"/></svg>');}
.ico-plus{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.9" stroke-linecap="round"><path d="M12 5v14M5 12h14"/></svg>');}
.ico-grid{--i:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7" rx="1.2"/><rect x="14" y="3" width="7" height="7" rx="1.2"/><rect x="3" y="14" width="7" height="7" rx="1.2"/><rect x="14" y="14" width="7" height="7" rx="1.2"/></svg>');}

/* ---- filter bar ---- */
.filterbar { display: flex; gap: .6rem; align-items: center; padding: .7rem 1.1rem; border-bottom: 1px solid var(--border-soft); flex-wrap: wrap; }
.filterbar .field { position: relative; display: inline-flex; align-items: center; }
.filterbar .field .ico { position: absolute; left: .55rem; color: var(--muted); pointer-events: none; }
.filterbar input, .filterbar select {
  font: inherit; font-size: .82rem; color: var(--text); background: #101113;
  border: 1px solid var(--border); border-radius: 9px; padding: .44rem .6rem;
}
.filterbar input { min-width: 220px; padding-left: 2rem; }
.filterbar input:focus, .filterbar select:focus { outline: none; border-color: var(--green); box-shadow: 0 0 0 3px var(--green-soft); }
.filterbar .grow { flex: 1; }
.filterbar .cnt { color: var(--muted); font-size: .78rem; white-space: nowrap; }
.filterbar .clear { color: var(--muted); font-size: .78rem; background: none; border: 0; padding: .2rem .4rem; }
.filterbar .clear:hover { color: var(--text); }
.pager { display: flex; align-items: center; justify-content: flex-end; gap: .9rem; padding: .6rem 1.1rem; border-top: 1px solid var(--border-soft); }
.pager:empty { display: none; }
.pg-info { color: var(--muted); font-size: .78rem; white-space: nowrap; font-variant-numeric: tabular-nums; }
.pg-btn { font-size: .76rem; padding: .28rem .7rem; }

/* ---- tooltip (single fixed panel, centered in the header band) ---- */
th[data-tip] { text-decoration: underline dotted color-mix(in srgb, var(--text) 30%, transparent); text-underline-offset: 3px; }
#tipbox {
  position: fixed; top: 11px; left: 50%; z-index: 250; max-width: 360px; padding: .5rem .85rem;
  font: 400 .74rem/1.5 var(--font); color: var(--text-2); white-space: pre-line; text-align: center;
  background: rgba(8,8,10,.96); border: 1px solid var(--border); border-radius: 11px; box-shadow: var(--shadow-lg);
  opacity: 0; transform: translate(-50%, -5px); transition: opacity .13s, transform .13s; pointer-events: none;
}
#tipbox.show { opacity: 1; transform: translate(-50%, 0); }

.note { margin-top: 1.3rem; font-size: .76rem; color: #63666c; }
.empty { color: var(--muted); font-size: .82rem; padding: .3rem 0; }

/* The appbar logo doubles as "home" — it navigates to Fleet Status (the root).
   display:flex keeps the img metrics identical to the un-wrapped version. */
.appbar a.logo-home { display: flex; align-items: center; text-decoration: none; cursor: pointer; }
.appbar a.logo-home:hover { opacity: .85; }

/* control-plane / fleet nice-name button + k8s-ready inline marker */
/* opacity:.5 on --muted rendered ~2.33:1 — an enabled control below AA. Dim via
   colour instead so the contrast is knowable. */
.nick-btn { border: none; background: none; cursor: pointer; color: #7c828b; font-size: .78rem; padding: 0 .25rem; margin-left: .15rem; transition: .12s; }
.nick-btn:hover { color: var(--green); opacity: 1; }
.kok { color: var(--green); font-size: .78rem; }

/* nice-name modal (mid-page, HTML) */
.nmodal { position: fixed; inset: 0; z-index: 300; background: rgba(0,0,0,.55); backdrop-filter: blur(2px); display: grid; place-items: center; padding: 2rem; }
.nmodal[hidden] { display: none; }
.nmodal-box { width: min(440px, 94vw); border: 1px solid var(--border); border-radius: 14px; background: var(--surface); box-shadow: var(--shadow-lg); overflow: hidden; }
.nmodal-h { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: .8rem 1rem; border-bottom: 1px solid var(--border-soft); font-weight: 600; font-size: .88rem; }
.nmodal-h .ico { color: var(--green); }
.nmodal-x { border: none; background: none; color: var(--muted); cursor: pointer; font-size: 1rem; line-height: 1; }
.nmodal-x:hover { color: var(--text); }
.nmodal-body { padding: 1rem; }
.nmodal-body input { width: 100%; padding: .55rem .7rem; border: 1px solid var(--border); border-radius: 8px; background: var(--surface-2); color: var(--text); font: inherit; box-sizing: border-box; }
.nmodal-body input:focus { outline: none; border-color: var(--green); }
.nmodal-body .hint { font-size: .74rem; color: var(--muted); margin: .5rem 0 0; }
.nmodal-actions { display: flex; justify-content: flex-end; gap: .6rem; margin-top: 1rem; }

/* platform control-plane services — 5 evenly-sized compact stat tiles */
.cpv-tiles { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: .8rem; margin-bottom: 1.4rem; }
.cpv-tiles .tile { min-width: 0; padding: .8rem .85rem; }
.cpv-tiles .n.cpv-n { font-size: 1.2rem; margin-top: .3rem; font-family: var(--mono); }
.cpv-tiles .n.cpv-dbgn { font-family: inherit; font-size: 1rem; }
.cpv-sub { font-size: .72rem; color: var(--muted); margin-top: .4rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.btn.tiny { height: 24px; padding: 0 .6rem; font-size: .72rem; }
@media (max-width: 900px){ .cpv-tiles { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); } }

/* needs-attention band */
.attn { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; padding: .6rem .9rem; margin-bottom: 1.4rem; border: 1px solid var(--border); border-radius: 10px; background: var(--surface-2); }
.attn-h { display: inline-flex; align-items: center; gap: .45rem; font-weight: 650; font-size: .8rem; color: var(--text-2); }
.attn-h .ico { color: var(--amber); }
.attn-item { font-size: .76rem; padding: .18rem .6rem; border-radius: 999px; border: 1px solid var(--border); }
.attn-item.bad { color: var(--red); border-color: var(--red); background: rgba(220,60,60,.08); }
.attn-item.warn { color: var(--amber); border-color: var(--amber); background: rgba(217,154,43,.08); }
.attn-item.drift { color: var(--violet); border-color: var(--violet); background: rgba(192,96,208,.08); }
.attn-node { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.attn-node:hover { opacity: .75; }
.vwarn { color: var(--amber); font-weight: 600; }

/* (recent-activity grid removed 2026-07-28 — .recent-list/.recent-row/.rc-name/.rc-node/.rc-by/
   .rc-when styled a widget no template or script builds. These are LITERAL compound class names,
   never assembled from data, so "no reference" really does mean unused here — unlike .cni.flannel
   or .chip.compute below, which ARE built as "cni "+cluster.cni / "chip "+node_type and would look
   equally unreferenced to a grep. Do not sweep those. */

/* resource scheduler/live toggle */
.res-toggle { display: inline-flex; align-items: center; gap: .45rem; font-size: .72rem; color: var(--muted); }
.rsegs { display: inline-flex; }
.rseg { border: 1px solid var(--border); background: none; color: var(--muted); font: inherit; font-size: .72rem; padding: .12rem .5rem; cursor: pointer; }
.rseg:first-child { border-radius: 6px 0 0 6px; border-right: none; }
.rseg:last-child { border-radius: 0 6px 6px 0; }
.rseg.on + .rseg { border-left-color: var(--green); }
.rseg.on { color: var(--green); border-color: var(--green); background: var(--green-soft, rgba(60,200,120,.1)); }

/* clickable table-row name → enriched detail view */
.rowlink{color:var(--green);text-decoration:none;font-weight:640}
.rowlink:hover{text-decoration:underline}

/* ★ NATIVE <select> POPUPS DO NOT INHERIT THE SELECT'S BACKGROUND (2026-07-28).
   The OPTION list is rendered by the browser on its OWN default surface — white — while
   inheriting the page's --text, which on this dark theme is near-white. Result: white text on a
   white list, i.e. an invisible dropdown. MEASURED on the VM live-migrate picker.
   ⚠ NOT specific to that dialog: NO select in this admin styled its options, so every dropdown
   carried the same latent bug (the backup restore-point picker included). One rule, global —
   options are otherwise unstyled everywhere, so this cannot collide with anything. */
select option,
select optgroup {
  background-color: var(--surface-2);
  color: var(--text);
}

/* ---- shared modal (.scrim2 / .modal2) -------------------------------------
   Moved here from registry.css 2026-08-08. It was page-local, so Settings had no
   modal at all and the mirror roll fell back to a native confirm() — a browser
   dialog in the middle of an otherwise styled UI. Any page may use it now. */
/* modal (k8s add + confirmations) */
.scrim2 { position: fixed; inset: 0; background: rgba(0,0,0,.55); display: flex;
  align-items: center; justify-content: center; z-index: 50; }
.scrim2[hidden] { display: none; }
.modal2 { width: min(560px, 92vw); max-height: 80vh; display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-lg); overflow: hidden; }
.modal2-h { padding: .9rem 1.1rem; border-bottom: 1px solid var(--border-soft); font-weight: 640; }
.modal2-b { padding: 1rem 1.1rem; overflow: auto; }
.modal2-f { padding: .8rem 1.1rem; border-top: 1px solid var(--border-soft);
  display: flex; gap: .5rem; align-items: center; }
.modal2-f .sp { flex: 1; }
