/* siteconsole — console UI
 *
 * Structure follows the Cloudscape app-layout pattern that AWS's own console is
 * built on: a top navigation bar, a collapsible side navigation grouped into
 * sections, and a content area carrying breadcrumbs, a notifications flashbar,
 * a page header, and containers with their own headers and counters. Contextual
 * resource details open in a side (split) panel so the list stays visible.
 *
 * Visual system: ui-ux-pro-max "Data-Dense Dashboard", Fira Sans / Fira Code
 * self-hosted, density 9/10, motion 3/10.
 *
 * Fonts are self-hosted deliberately: the CSP is default-src 'self', and an
 * infrastructure console has to render when outbound internet is down.
 *
 * Tokens are three-layer: primitive -> semantic -> usage. Never reference a
 * primitive below the semantic block; contrast.js validates the semantic pairs.
 */

/* --- fonts ----------------------------------------------------------------- */

@font-face { font-family:'Fira Sans'; font-style:normal; font-weight:400; font-display:swap;
  src:url('/fonts/fira-sans-400.woff2') format('woff2'); }
@font-face { font-family:'Fira Sans'; font-style:normal; font-weight:500; font-display:swap;
  src:url('/fonts/fira-sans-500.woff2') format('woff2'); }
@font-face { font-family:'Fira Sans'; font-style:normal; font-weight:600; font-display:swap;
  src:url('/fonts/fira-sans-600.woff2') format('woff2'); }
@font-face { font-family:'Fira Sans'; font-style:normal; font-weight:700; font-display:swap;
  src:url('/fonts/fira-sans-700.woff2') format('woff2'); }
@font-face { font-family:'Fira Code'; font-style:normal; font-weight:400; font-display:swap;
  src:url('/fonts/fira-code-400.woff2') format('woff2'); }

/* --- layer 1: primitives --------------------------------------------------- */

:root {
  --slate-950:#020617; --slate-900:#0f172a; --slate-850:#141d2f; --slate-800:#1e293b;
  --slate-700:#334155; --slate-600:#475569; --slate-400:#94a3b8; --slate-300:#cbd5e1;
  --slate-200:#e2e8f0; --slate-100:#f1f5f9; --slate-50:#f8fafc; --white:#ffffff;

  --green-400:#4ade80; --green-500:#22c55e; --green-700:#15803d;
  --blue-400:#60a5fa;  --blue-600:#2563eb;
  --amber-400:#fbbf24; --amber-700:#a16207;
  --red-400:#f87171;   --red-500:#ef4444;  --red-700:#b91c1c;

  --space-1:4px; --space-2:8px; --space-3:12px;
  --space-4:16px; --space-5:20px; --space-6:24px; --space-8:32px;

  --radius-sm:4px; --radius:6px; --radius-lg:8px;
  --tap:44px;
  --dur:180ms;
  --ease:cubic-bezier(.4,0,.2,1);

  --topbar-h:48px;
  --sidenav-w:240px;
  --drawer-w:360px;

  --font-sans:'Fira Sans', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --font-mono:'Fira Code', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* The top bar stays dark in both schemes, the way a service console's global
     bar does — it is chrome, not content. */
  --topnav-bg:#0b1524;
  --topnav-fg:#eef2f7;
  --topnav-muted:#a8b8cc;
  --topnav-hover:#1b2b42;
}

/* --- layer 2: semantic — dark (default) ------------------------------------ */

:root {
  --bg:var(--slate-950);
  --surface:var(--slate-900);
  --surface-2:var(--slate-850);
  --surface-3:var(--slate-800);
  --fg:var(--slate-50);
  --fg-muted:var(--slate-400);
  --fg-subtle:#7d8da3;
  --border:var(--slate-700);
  --border-strong:var(--slate-600);
  /* Boundaries that identify an interactive control must clear 3:1
     (WCAG 1.4.11). Dividers must not, and shouldn't — loud rules make a dense
     table unreadable. Two tokens, because they are two different jobs. */
  --border-control:#64748b;

  --accent:var(--green-500);
  --accent-fg:#04180c;
  --accent-text:var(--green-400);

  --info:var(--blue-400);
  --warn:var(--amber-400);
  --danger:var(--red-400);
  --danger-solid:var(--red-500);
  --danger-fg:var(--white);

  --ring:var(--green-400);
  --shadow:0 1px 2px rgb(0 0 0 / .4), 0 4px 12px rgb(0 0 0 / .25);
  --log-bg:#01040d;
  --log-fg:#cbd5e1;
}

/* --- layer 2: semantic — light --------------------------------------------- */

/* Applies when the OS asks for light AND no theme is pinned, or when light is
 * chosen explicitly. The two blocks are generated from one source; keep them
 * identical if you edit either. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --bg:var(--slate-100);
    --surface:var(--white);
    --surface-2:var(--slate-50);
    --surface-3:var(--slate-200);
    --fg:var(--slate-900);
    --fg-muted:var(--slate-600);
    --fg-subtle:#64748b;
    --border:var(--slate-300);
    --border-strong:var(--slate-400);
    --border-control:#64748b;

    --accent:var(--green-700);
    --accent-fg:var(--white);
    --accent-text:var(--green-700);

    --info:var(--blue-600);
    --warn:var(--amber-700);
    --danger:var(--red-700);
    --danger-solid:var(--red-700);

    --ring:var(--blue-600);
    --shadow:0 1px 2px rgb(15 23 42 / .06), 0 4px 12px rgb(15 23 42 / .05);
    --log-bg:var(--slate-900);
    --log-fg:#d7dee8;
  }
}

:root[data-theme="light"] {
  --bg:var(--slate-100);
  --surface:var(--white);
  --surface-2:var(--slate-50);
  --surface-3:var(--slate-200);
  --fg:var(--slate-900);
  --fg-muted:var(--slate-600);
  --fg-subtle:#64748b;
  --border:var(--slate-300);
  --border-strong:var(--slate-400);
  --border-control:#64748b;

  --accent:var(--green-700);
  --accent-fg:var(--white);
  --accent-text:var(--green-700);

  --info:var(--blue-600);
  --warn:var(--amber-700);
  --danger:var(--red-700);
  --danger-solid:var(--red-700);

  --ring:var(--blue-600);
  --shadow:0 1px 2px rgb(15 23 42 / .06), 0 4px 12px rgb(15 23 42 / .05);
  --log-bg:var(--slate-900);
  --log-fg:#d7dee8;
}

/* --- base ------------------------------------------------------------------ */

* { box-sizing:border-box; }
html { -webkit-text-size-adjust:100%; }

body {
  margin:0;
  background:var(--bg);
  color:var(--fg);
  font:400 14px/1.5 var(--font-sans);
  overflow-wrap:break-word;
}

a { color:var(--accent-text); }

:focus-visible { outline:2px solid var(--ring); outline-offset:2px; border-radius:var(--radius-sm); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration:.01ms !important;
    transition-duration:.01ms !important;
    scroll-behavior:auto !important;
  }
}

.sr-only { position:absolute; width:1px; height:1px; overflow:hidden; clip-path:inset(50%); white-space:nowrap; }
[hidden] { display:none !important; }
.mono { font-family:var(--font-mono); }

/* --- top navigation --------------------------------------------------------- */

.top-nav {
  position:fixed; inset:0 0 auto 0; z-index:40;
  height:var(--topbar-h);
  display:flex; align-items:center; gap:var(--space-2);
  background:var(--topnav-bg); color:var(--topnav-fg);
  padding:0 max(var(--space-3), env(safe-area-inset-right)) 0 max(var(--space-2), env(safe-area-inset-left));
}

.identity { display:flex; align-items:center; gap:var(--space-2); color:inherit; text-decoration:none; min-width:0; }
.identity .mark {
  width:24px; height:24px; flex:0 0 auto; display:grid; place-items:center;
  border-radius:var(--radius-sm); background:var(--accent); color:var(--accent-fg);
}
.identity .mark svg { width:14px; height:14px; }
.identity-name { font-size:14px; font-weight:600; white-space:nowrap; letter-spacing:-.01em; }

.top-spacer { flex:1 1 auto; }

.top-actions { display:flex; align-items:center; gap:var(--space-1); min-width:0; }
.top-btn {
  display:inline-flex; align-items:center; gap:var(--space-2);
  height:32px; padding:0 var(--space-3);
  background:transparent; border:1px solid transparent; border-radius:var(--radius);
  color:var(--topnav-fg); font:500 13px var(--font-sans); cursor:pointer;
  white-space:nowrap;
  transition:background var(--dur) var(--ease);
}
.top-btn:hover { background:var(--topnav-hover); }
.top-btn svg { width:15px; height:15px; flex:0 0 auto; }
@media (pointer: coarse) { .top-btn { height:var(--tap); } }

.icon-btn {
  display:inline-flex; align-items:center; justify-content:center;
  width:34px; height:34px; padding:0; flex:0 0 auto;
  background:transparent; border:1px solid transparent; border-radius:var(--radius);
  color:inherit; cursor:pointer;
  transition:background var(--dur) var(--ease);
}
.icon-btn svg { width:18px; height:18px; }
.nav-toggle:hover { background:var(--topnav-hover); }
@media (pointer: coarse) { .icon-btn { width:var(--tap); height:var(--tap); } }

.top-nav .meta { color:var(--topnav-muted); font-size:12px; font-family:var(--font-mono); }
.top-nav .conn { display:inline-flex; align-items:center; gap:var(--space-2);
  font-size:12px; color:var(--topnav-muted); font-family:var(--font-mono); white-space:nowrap; }
.conn .dot { width:7px; height:7px; border-radius:50%; background:var(--accent); flex:0 0 auto; }
.conn.down .dot { background:var(--danger); }

/* --- shell ------------------------------------------------------------------ */

.shell {
  display:grid;
  grid-template-columns:var(--sidenav-w) minmax(0, 1fr);
  padding-top:var(--topbar-h);
  min-height:100vh;
}
/*
 * A collapsed nav declares ONE fewer column, not a zero-width one.
 *
 * .side-nav is display:none when collapsed, so it leaves the grid entirely.
 * Declaring `0 minmax(0,1fr)` then leaves auto-placement to drop <main> into
 * column 1 -- the 0px one -- squeezing the whole page to its min-content width
 * and wrapping headings to one character per line. The column count has to
 * match the number of items actually in the grid.
 */
.shell.nav-collapsed { grid-template-columns:minmax(0, 1fr); }
.shell.drawer-open { grid-template-columns:var(--sidenav-w) minmax(0, 1fr) var(--drawer-w); }
.shell.nav-collapsed.drawer-open { grid-template-columns:minmax(0, 1fr) var(--drawer-w); }

/* --- side navigation --------------------------------------------------------- */

.side-nav {
  position:sticky; top:var(--topbar-h);
  height:calc(100vh - var(--topbar-h));
  overflow-y:auto; overflow-x:hidden;
  background:var(--surface);
  border-right:1px solid var(--border);
  padding:var(--space-3) var(--space-2) var(--space-6);
  display:flex; flex-direction:column; gap:2px;
}
.shell.nav-collapsed .side-nav { display:none; }

.nav-heading {
  margin:var(--space-4) var(--space-3) var(--space-1);
  font-size:11px; font-weight:700; letter-spacing:.08em; text-transform:uppercase;
  color:var(--fg-muted);
}

.nav-item {
  display:flex; align-items:center; gap:var(--space-3);
  min-height:34px; padding:var(--space-1) var(--space-3);
  border-radius:var(--radius);
  color:var(--fg); text-decoration:none;
  font-size:13.5px; font-weight:500;
  transition:background var(--dur) var(--ease);
}
.nav-item svg { width:16px; height:16px; flex:0 0 auto; color:var(--fg-muted); }
.nav-item:hover { background:var(--surface-2); }
.nav-item[aria-current="page"] {
  background:var(--surface-3); font-weight:600;
  box-shadow:inset 3px 0 0 var(--accent);
}
.nav-item[aria-current="page"] svg { color:var(--accent-text); }
@media (pointer: coarse) { .nav-item { min-height:var(--tap); } }

.nav-count, .nav-badge {
  margin-left:auto; flex:0 0 auto;
  font-size:11px; font-family:var(--font-mono); color:var(--fg-muted);
}
.nav-badge {
  font-family:var(--font-sans); font-weight:600;
  color:var(--accent-text); border:1px solid var(--accent);
  border-radius:999px; padding:0 var(--space-2);
}
.nav-count.alert { color:var(--danger); font-weight:700; }

.nav-foot { margin-top:auto; padding:var(--space-4) var(--space-3) 0; }
.nav-foot .meta { color:var(--fg-subtle); font-size:11px; font-family:var(--font-mono); }

/* --- content ---------------------------------------------------------------- */

.content {
  min-width:0;
  padding:var(--space-4) max(var(--space-5), env(safe-area-inset-right))
          max(var(--space-8), env(safe-area-inset-bottom)) var(--space-5);
  display:flex; flex-direction:column; gap:var(--space-4);
}

.crumbs { display:flex; align-items:center; flex-wrap:wrap; gap:var(--space-1); font-size:12.5px; }
.crumbs a { color:var(--fg-muted); text-decoration:none; }
.crumbs a:hover { color:var(--fg); text-decoration:underline; }
.crumbs .sep { color:var(--fg-subtle); }
.crumbs .here { color:var(--fg); font-weight:600; }

.page-head { display:flex; align-items:flex-start; gap:var(--space-4); flex-wrap:wrap; }
.page-head-text { flex:1 1 320px; min-width:0; }
.page-head h1 { margin:0; font-size:22px; font-weight:700; letter-spacing:-.02em; }
.page-desc { margin:var(--space-1) 0 0; color:var(--fg-muted); font-size:13.5px; max-width:76ch; }
.page-actions { display:flex; gap:var(--space-2); flex-wrap:wrap; flex:0 0 auto; }

.page { display:flex; flex-direction:column; gap:var(--space-4); min-width:0; }
.form-col { display:flex; flex-direction:column; gap:var(--space-4); max-width:820px; }

/* --- flashbar ---------------------------------------------------------------- */

.flashbar { display:flex; flex-direction:column; gap:var(--space-2); }
.flashbar:empty { display:none; }
.flash {
  display:flex; align-items:flex-start; gap:var(--space-3);
  padding:var(--space-3) var(--space-3);
  border-radius:var(--radius); border:1px solid;
  font-size:13.5px;
}
.flash svg { width:16px; height:16px; flex:0 0 auto; margin-top:1px; }
.flash .flash-text { flex:1 1 auto; min-width:0; }
.flash .flash-title { font-weight:600; }
.flash-close {
  flex:0 0 auto; background:transparent; border:0; color:inherit; cursor:pointer;
  padding:0; width:22px; height:22px; display:grid; place-items:center; opacity:.75;
}
.flash-close:hover { opacity:1; }
.flash-close svg { width:14px; height:14px; margin:0; }
.flash.success { border-color:var(--accent); color:var(--accent-text);
  background:color-mix(in srgb, var(--accent) 10%, transparent); }
.flash.error   { border-color:var(--danger); color:var(--danger);
  background:color-mix(in srgb, var(--danger) 10%, transparent); }
.flash.warning { border-color:var(--warn); color:var(--warn);
  background:color-mix(in srgb, var(--warn) 10%, transparent); }
.flash.info    { border-color:var(--info); color:var(--info);
  background:color-mix(in srgb, var(--info) 10%, transparent); }

/* --- containers -------------------------------------------------------------- */

.container {
  background:var(--surface); border:1px solid var(--border);
  border-radius:var(--radius-lg); min-width:0; box-shadow:var(--shadow);
}
.container-head {
  display:flex; align-items:center; gap:var(--space-3);
  min-height:46px; padding:var(--space-2) var(--space-4);
  cursor:pointer; list-style:none;
  -webkit-user-select:none; user-select:none;
  border-radius:var(--radius-lg);
  transition:background var(--dur) var(--ease);
}
.container-head::-webkit-details-marker { display:none; }
.container-head::marker { content:''; }
.container-head:hover { background:var(--surface-2); }
.container[open] > .container-head {
  border-bottom:1px solid var(--border);
  border-radius:var(--radius-lg) var(--radius-lg) 0 0;
}
.container-title { font-size:15px; font-weight:600; flex:0 0 auto; }
.container-count {
  font-size:13px; color:var(--fg-muted); font-family:var(--font-mono);
  min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.container-actions { margin-left:auto; display:flex; gap:var(--space-1); flex:0 0 auto; }
.chev {
  flex:0 0 auto; width:8px; height:8px;
  border-right:2px solid var(--fg-muted); border-bottom:2px solid var(--fg-muted);
  transform:rotate(45deg); transition:transform var(--dur) var(--ease);
}
.container-actions ~ .chev { margin-left:var(--space-2); }
.container-head > .chev:first-of-type:not(.container-actions ~ .chev) { margin-left:auto; }
.container[open] > .container-head .chev { transform:rotate(-135deg) translate(-2px,-2px); }
.container-body { padding:var(--space-4); }

.desc { margin:0 0 var(--space-3); color:var(--fg-muted); font-size:13px; max-width:80ch; }

/* --- buttons ----------------------------------------------------------------- */

button { font-family:var(--font-sans); }

.btn-primary, .btn-normal, .btn-danger {
  display:inline-flex; align-items:center; justify-content:center; gap:var(--space-2);
  min-height:34px; padding:var(--space-2) var(--space-4);
  border-radius:var(--radius); border:1px solid transparent;
  font-size:13.5px; font-weight:600; cursor:pointer; touch-action:manipulation;
  transition:background var(--dur) var(--ease), border-color var(--dur) var(--ease), opacity var(--dur) var(--ease);
}
.btn-primary { background:var(--accent); color:var(--accent-fg); }
.btn-normal  { background:var(--surface-2); color:var(--fg); border-color:var(--border-control); }
.btn-danger  { background:var(--danger-solid); color:var(--danger-fg); }
.btn-primary:hover:not(:disabled), .btn-danger:hover:not(:disabled) { filter:brightness(1.08); }
.btn-normal:hover:not(:disabled) { background:var(--surface-3); }
.btn-primary:disabled, .btn-normal:disabled, .btn-danger:disabled { opacity:.45; cursor:not-allowed; }
.btn-primary svg, .btn-normal svg, .btn-danger svg { width:15px; height:15px; flex:0 0 auto; }
@media (pointer: coarse) { .btn-primary, .btn-normal, .btn-danger { min-height:var(--tap); } }

.btn-plain {
  min-height:28px; padding:2px var(--space-3);
  background:transparent; color:var(--fg-muted);
  border:1px solid var(--border-control); border-radius:var(--radius);
  font-size:12.5px; font-weight:600; cursor:pointer;
  transition:background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.btn-plain:hover:not(:disabled) { background:var(--surface-3); color:var(--fg); }
.btn-plain:disabled { opacity:.45; cursor:not-allowed; }
.btn-plain.danger { color:var(--danger); border-color:var(--danger); }
@media (pointer: coarse) { .btn-plain { min-height:var(--tap); } }

/* --- forms ------------------------------------------------------------------- */

label { display:block; font-size:12.5px; color:var(--fg); margin:0 0 var(--space-1); font-weight:600; }
.field { margin-bottom:var(--space-4); min-width:0; }
.row { display:flex; gap:var(--space-4); flex-wrap:wrap; }
.row > .field { flex:1 1 220px; }

input[type=text], input[type=number], input[type=password], select {
  width:100%; min-height:34px;
  padding:var(--space-2) var(--space-3);
  background:var(--surface-2); color:var(--fg);
  border:1px solid var(--border-control); border-radius:var(--radius);
  /* 16px keeps iOS Safari from zooming the viewport on focus. */
  font-size:16px; font-family:var(--font-mono);
  transition:border-color var(--dur) var(--ease);
}
@media (min-width: 700px) {
  input[type=text], input[type=number], input[type=password], select { font-size:13.5px; }
}
input:hover:not(:disabled), select:hover { border-color:var(--fg-muted); }
input::placeholder { color:var(--fg-subtle); }
input[type=number] { appearance:textfield; -moz-appearance:textfield; }
input[type=number]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button { -webkit-appearance:none; margin:0; }
select { cursor:pointer; }
@media (pointer: coarse) {
  input[type=text], input[type=number], input[type=password], select { min-height:var(--tap); font-size:16px; }
}

.help { font-size:12px; color:var(--fg-muted); margin:var(--space-1) 0 0; }
.fqdn { font-family:var(--font-mono); color:var(--accent-text); overflow-wrap:anywhere; }

.check { display:flex; align-items:center; gap:var(--space-2); }
.check input[type=checkbox] { width:16px; height:16px; flex:0 0 auto; accent-color:var(--accent); cursor:pointer; }
/* The 16px box is well under the touch minimum, so the label carries the target. */
.check label {
  margin:0; font-weight:400; font-size:13.5px; color:var(--fg);
  flex:1 1 auto; min-height:var(--tap); display:flex; align-items:center; cursor:pointer;
}

.form-actions { display:flex; gap:var(--space-2); flex-wrap:wrap; margin-top:var(--space-4); }

/* --- alerts ------------------------------------------------------------------ */

.alert {
  display:flex; align-items:flex-start; gap:var(--space-2);
  padding:var(--space-2) var(--space-3); border-radius:var(--radius);
  border:1px solid; font-size:13px; margin-bottom:var(--space-3);
}
.alert svg { width:15px; height:15px; flex:0 0 auto; margin-top:2px; }
.alert.error { border-color:var(--danger); color:var(--danger);
  background:color-mix(in srgb, var(--danger) 10%, transparent); }
.alert.warn  { border-color:var(--warn); color:var(--warn);
  background:color-mix(in srgb, var(--warn) 10%, transparent); }

/* --- KPI cards ---------------------------------------------------------------- */

.kpis { display:grid; gap:var(--space-3); grid-template-columns:repeat(2, minmax(0,1fr)); }
.kpi {
  background:var(--surface); border:1px solid var(--border);
  border-radius:var(--radius-lg); padding:var(--space-3) var(--space-4);
  display:flex; flex-direction:column; gap:2px; min-width:0; box-shadow:var(--shadow);
}
.kpi .k-label {
  font-size:11px; font-weight:600; letter-spacing:.06em; text-transform:uppercase;
  color:var(--fg-muted); display:flex; align-items:center; gap:var(--space-2);
}
.kpi .k-label svg { width:13px; height:13px; flex:0 0 auto; }
.kpi .k-value {
  font-family:var(--font-mono); font-size:22px; font-weight:500;
  line-height:1.2; letter-spacing:-.02em;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.kpi .k-sub { font-size:12px; color:var(--fg-muted); }
.kpi.ok .k-value { color:var(--accent-text); }
.kpi.info .k-value { color:var(--info); }
.kpi.warn .k-value { color:var(--warn); }
.kpi.alert .k-value { color:var(--danger); }

/* --- table tools --------------------------------------------------------------- */

.table-tools {
  display:flex; align-items:center; gap:var(--space-3);
  flex-wrap:wrap; margin-bottom:var(--space-3);
}
.search { position:relative; flex:1 1 260px; min-width:0; }
.search svg {
  position:absolute; left:var(--space-3); top:50%; transform:translateY(-50%);
  width:15px; height:15px; color:var(--fg-muted); pointer-events:none;
}
.search input { padding-left:34px; font-family:var(--font-sans); }
.table-count { font-size:12.5px; color:var(--fg-muted); font-family:var(--font-mono); flex:0 0 auto; margin-left:auto; }

.chips { display:flex; gap:var(--space-1); flex-wrap:wrap; }
.chip {
  min-height:var(--tap); padding:var(--space-1) var(--space-3);
  font-size:12px; font-weight:600;
  background:var(--surface-2); color:var(--fg-muted);
  border:1px solid var(--border-control); border-radius:999px; cursor:pointer;
}
@media (pointer: fine) { .chip { min-height:30px; } }
.chip:hover { color:var(--fg); background:var(--surface-3); }
.chip.active { background:var(--accent); color:var(--accent-fg); border-color:var(--accent); }

.bulk-bar {
  display:flex; align-items:center; gap:var(--space-3); flex-wrap:wrap;
  padding:var(--space-2) var(--space-3); margin-bottom:var(--space-3);
  background:var(--surface-3); border:1px solid var(--border-control); border-radius:var(--radius);
}
.bulk-count { font-size:13px; font-weight:600; flex:0 0 auto; }
.bulk-actions { display:flex; gap:var(--space-1); flex-wrap:wrap; margin-left:auto; }

/* --- tables -------------------------------------------------------------------- */

.scroll { overflow-x:auto; -webkit-overflow-scrolling:touch; }
table { width:100%; border-collapse:collapse; font-size:13px; }
th, td { text-align:left; padding:var(--space-2) var(--space-3); border-bottom:1px solid var(--border); }
th {
  color:var(--fg-muted); font-weight:600; font-size:11px;
  text-transform:uppercase; letter-spacing:.05em; white-space:nowrap;
  position:sticky; top:0; background:var(--surface); z-index:1;
}
td.mono { font-family:var(--font-mono); font-size:12.5px; }
tbody tr:last-child td { border-bottom:0; }
tbody tr.selected { background:color-mix(in srgb, var(--accent) 8%, transparent); }
.sel-col { width:34px; }
.sel-col input[type=checkbox] { width:16px; height:16px; accent-color:var(--accent); cursor:pointer; }

th[data-sort] { cursor:pointer; -webkit-user-select:none; user-select:none; }
th[data-sort]:hover { color:var(--fg); }
th[data-sort]::after { content:''; display:inline-block; width:0; height:0; margin-left:5px; }
th[data-sort][aria-sort="ascending"]::after {
  border-left:4px solid transparent; border-right:4px solid transparent; border-bottom:5px solid currentColor;
}
th[data-sort][aria-sort="descending"]::after {
  border-left:4px solid transparent; border-right:4px solid transparent; border-top:5px solid currentColor;
}

.empty-state { padding:var(--space-8) var(--space-4); text-align:center; color:var(--fg-muted); }
.empty-state .es-title { font-size:15px; font-weight:600; color:var(--fg); margin-bottom:var(--space-1); }
.empty-state .es-body { font-size:13px; margin-bottom:var(--space-4); }

/* Loading skeleton: a plain shimmer, so a 5-second fleet query does not look
   like a hang. Respects reduced motion via the global rule above. */
.skeleton { display:flex; flex-direction:column; gap:var(--space-2); padding:var(--space-2) 0; }
.skeleton i {
  display:block; height:14px; border-radius:var(--radius-sm);
  background:linear-gradient(90deg, var(--surface-2) 25%, var(--surface-3) 50%, var(--surface-2) 75%);
  background-size:200% 100%;
  animation:shimmer 1.4s linear infinite;
}
@keyframes shimmer { from { background-position:200% 0; } to { background-position:-200% 0; } }

/* Phones: rows become labelled cards. Explicit ARIA roles live in the markup
   because display:block on table elements strips the implicit ones. */
@media (max-width: 699px) {
  table, thead, tbody, tr, th, td { display:block; }
  thead { position:absolute; width:1px; height:1px; overflow:hidden; clip-path:inset(50%); }
  tbody tr {
    border:1px solid var(--border); border-radius:var(--radius);
    padding:var(--space-1) var(--space-3); margin-bottom:var(--space-2); background:var(--surface-2);
  }
  tbody tr:last-child { margin-bottom:0; }
  tbody td {
    display:flex; align-items:baseline; justify-content:space-between;
    gap:var(--space-4); padding:var(--space-2) 0;
    border-bottom:1px solid var(--border);
    white-space:normal; text-align:right; overflow-wrap:anywhere;
  }
  tbody td:last-child { border-bottom:0; }
  tbody td::before {
    content:attr(data-label);
    color:var(--fg-muted); font-size:11px; font-weight:600;
    text-transform:uppercase; letter-spacing:.05em;
    text-align:left; flex:0 0 auto; font-family:var(--font-sans);
  }
  tbody tr.placeholder { border:0; background:transparent; padding:0; }
  tbody tr.placeholder td { justify-content:flex-start; text-align:left; border-bottom:0; }
  tbody tr.placeholder td::before { content:''; }
}
@media (min-width: 700px) {
  tbody tr[data-clickable] { cursor:pointer; transition:background var(--dur) var(--ease); }
  tbody tr[data-clickable]:hover { background:var(--surface-2); }
  th, td { white-space:nowrap; }
}

/* --- address list --------------------------------------------------------------- */

.addr-list {
  list-style:none; margin:0; padding:0;
  border:1px solid var(--border); border-radius:var(--radius);
  overflow:hidden auto; max-height:60vh; -webkit-overflow-scrolling:touch;
}
.addr {
  display:flex; align-items:baseline; gap:var(--space-3);
  padding:var(--space-2) var(--space-3);
  border-bottom:1px solid var(--border); border-left:3px solid transparent;
  background:var(--surface); min-height:34px;
  transition:background var(--dur) var(--ease);
}
.addr:last-child { border-bottom:0; }
.addr:nth-child(even) { background:var(--surface-2); }
.addr:hover { background:var(--surface-3); }
.addr .ip { font-family:var(--font-mono); font-size:12.5px; flex:0 0 auto; min-width:104px; }
.addr .nm { flex:1 1 auto; min-width:0; font-size:13px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.addr .nm.none { color:var(--fg-subtle); }
.addr .extra { flex:0 0 auto; font-family:var(--font-mono); font-size:11px; color:var(--fg-muted); }
.addr .tag { flex:0 0 auto; font-size:10.5px; font-weight:600; text-transform:uppercase; letter-spacing:.05em; }

.addr.used { border-left-color:var(--info); }              .addr.used .tag { color:var(--info); }
.addr.reserved { border-left-color:var(--warn); }          .addr.reserved .tag { color:var(--warn); }
.addr.infrastructure { border-left-color:var(--border-strong); }
.addr.infrastructure .tag { color:var(--fg-muted); }
.addr.free { border-left-color:var(--accent); }            .addr.free .tag { color:var(--accent-text); }
.addr.excluded { border-left-color:var(--border); }        .addr.excluded .tag { color:var(--fg-subtle); }
.addr.unknown .tag { color:var(--fg-subtle); }
.addr.next { box-shadow:inset 0 0 0 1px var(--accent); }
.addr.conflict { border-left-color:var(--danger); }        .addr.conflict .tag { color:var(--danger); }

@media (max-width: 540px) {
  .addr { flex-wrap:wrap; gap:var(--space-1) var(--space-3); }
  .addr .extra { flex-basis:100%; }
}

.legend { display:flex; gap:var(--space-3); flex-wrap:wrap; margin-top:var(--space-3); font-size:12px; color:var(--fg-muted); }
.legend span { display:inline-flex; align-items:center; gap:var(--space-1); }
.legend i { display:inline-block; width:3px; height:12px; border-radius:2px; }
.legend .free i { background:var(--accent); }
.legend .used i { background:var(--info); }
.legend .reserved i { background:var(--warn); }
.legend .infra i { background:var(--border-strong); }
.legend .excluded i { background:var(--border); }

/* --- log ------------------------------------------------------------------------ */

#log {
  background:var(--log-bg); color:var(--log-fg);
  border:1px solid var(--border); border-radius:var(--radius);
  padding:var(--space-3);
  height:44vh; min-height:200px; max-height:420px;
  overflow-y:auto; -webkit-overflow-scrolling:touch;
  font-family:var(--font-mono); font-size:12px; line-height:1.6;
  white-space:pre-wrap; overflow-wrap:anywhere;
}
#log .err { color:var(--red-400); }
#log .empty { color:var(--slate-600); font-style:italic; }

/* --- pills / health -------------------------------------------------------------- */

.pill {
  display:inline-block; padding:1px var(--space-2); border-radius:999px;
  font-size:11px; font-weight:600; border:1px solid; white-space:nowrap;
}
.pill.running, .pill.Running, .pill.succeeded, .pill.ok { color:var(--accent-text); border-color:var(--accent); }
.pill.Off, .pill.failed, .pill.expired, .pill.critical, .pill.error { color:var(--danger); border-color:var(--danger); }
.pill.Paused, .pill.Saved, .pill.soon, .pill.denied { color:var(--warn); border-color:var(--warn); }
.pill.template, .pill.none, .pill.unknown { color:var(--fg-muted); border-color:var(--border-control); }

.health { display:inline-flex; align-items:center; gap:var(--space-2); white-space:nowrap; }
.health .dot { width:7px; height:7px; border-radius:50%; flex:0 0 auto; background:var(--fg-subtle); }
.health.up .dot { background:var(--accent); }
.health.down .dot { background:var(--danger); }
.health.degraded .dot { background:var(--warn); }
.health .ms { color:var(--fg-muted); font-family:var(--font-mono); font-size:11px; }

.row-actions { display:flex; gap:var(--space-1); flex-wrap:wrap; }

/*
 * Attach and detach touch three separate systems, and a partial result is a
 * real outcome -- the MAC can move while the DHCP write fails. So the result is
 * reported per step rather than as one success or failure.
 */
.step-list { list-style:none; margin:var(--space-4) 0 0; padding:0; display:grid; gap:var(--space-1); }
.step {
  font-size:12px; padding:var(--space-2) var(--space-3);
  border:1px solid var(--border-control); border-radius:var(--radius-1);
  border-left-width:3px; color:var(--fg-muted);
}
.step strong { color:var(--fg); font-weight:600; }
.step.ok { border-left-color:var(--accent); }
.step.failed { border-left-color:var(--danger); color:var(--danger); }

/* A help line that is warning the operator rather than merely informing them. */
.help.warn-text { color:var(--warn); }

/* Leading text in a dialog needs room before the first field, or it reads as
   that field's label rather than as the dialog's own explanation. */
.dlg-intro { margin:0 0 var(--space-4); }

/* Connection test outcome, shown in the container header. */
.container-count.ok { color:var(--accent-text); }
.container-count.bad { color:var(--danger); }

/* Credential forms stay narrow: a URL field the width of the page invites the
   eye to scan past it, and these are values worth reading before saving. */
.conn-form { max-width:560px; }
.conn-form input { width:100%; }

/* --- drawer (split panel) --------------------------------------------------------- */

.drawer {
  position:sticky; top:var(--topbar-h);
  height:calc(100vh - var(--topbar-h));
  overflow-y:auto;
  background:var(--surface); border-left:1px solid var(--border);
  display:flex; flex-direction:column;
}
.drawer-head {
  display:flex; align-items:center; justify-content:space-between; gap:var(--space-3);
  padding:var(--space-3) var(--space-4);
  border-bottom:1px solid var(--border);
  position:sticky; top:0; background:var(--surface); z-index:1;
}
.drawer-head h2 { margin:0; font-size:15px; font-weight:600; }
.drawer-body { padding:var(--space-4); overflow-y:auto; }

.dlg-section { margin-top:var(--space-4); }
.dlg-section h3 {
  font-size:11px; text-transform:uppercase; letter-spacing:.06em;
  color:var(--fg-muted); margin:0 0 var(--space-2); font-weight:700;
}
.dlg-actions { display:flex; flex-wrap:wrap; gap:var(--space-2); }

.kv { display:grid; grid-template-columns:auto minmax(0,1fr); gap:var(--space-1) var(--space-4); margin:0; }
.kv dt { color:var(--fg-muted); font-size:11.5px; font-weight:600; text-transform:uppercase;
  letter-spacing:.04em; white-space:nowrap; }
.kv dd { margin:0; font-size:12.5px; font-family:var(--font-mono); overflow-wrap:anywhere; }
@media (max-width: 540px) {
  .kv { grid-template-columns:minmax(0,1fr); }
  .kv dt { margin-top:var(--space-2); }
}

.notice {
  display:flex; gap:var(--space-2); align-items:flex-start;
  background:color-mix(in srgb, var(--warn) 12%, transparent);
  border:1px solid var(--warn); color:var(--warn);
  padding:var(--space-2) var(--space-3); border-radius:var(--radius);
  font-size:12.5px; margin-bottom:var(--space-3);
}
.notice svg { width:15px; height:15px; flex:0 0 auto; margin-top:2px; }

/* --- dialogs ---------------------------------------------------------------------- */

dialog {
  width:min(680px, calc(100vw - 2 * var(--space-4)));
  max-height:min(80vh, 760px); padding:0;
  background:var(--surface); color:var(--fg);
  border:1px solid var(--border); border-radius:var(--radius-lg);
  box-shadow:0 12px 48px rgb(0 0 0 / .5);
}
dialog::backdrop { background:rgb(2 6 23 / .6); backdrop-filter:blur(2px); }
.dlg-head {
  display:flex; align-items:center; justify-content:space-between; gap:var(--space-3);
  padding:var(--space-3) var(--space-4); border-bottom:1px solid var(--border);
  position:sticky; top:0; background:var(--surface); z-index:1;
}
.dlg-head h2 { font-size:15px; margin:0; font-weight:600; }
.dlg-body { padding:var(--space-4); overflow-y:auto; max-height:calc(80vh - 60px); }

#cmdDialog { width:min(560px, calc(100vw - 2 * var(--space-4))); }
#cmdInput {
  width:100%; border:0; border-bottom:1px solid var(--border);
  border-radius:var(--radius-lg) var(--radius-lg) 0 0;
  background:var(--surface); font-size:16px; font-family:var(--font-sans);
  padding:var(--space-4);
}
#cmdInput:focus-visible { outline:none; border-bottom-color:var(--accent); }
.cmd-list { list-style:none; margin:0; padding:var(--space-2); max-height:46vh; overflow-y:auto; }
.cmd-item {
  display:flex; align-items:center; gap:var(--space-3);
  padding:var(--space-2) var(--space-3); border-radius:var(--radius);
  cursor:pointer; min-height:38px; font-size:13.5px;
}
.cmd-item[aria-selected="true"] { background:var(--surface-3); }
.cmd-item .cmd-group { margin-left:auto; font-size:11px; color:var(--fg-muted);
  text-transform:uppercase; letter-spacing:.05em; flex:0 0 auto; }
.cmd-item .cmd-key { font-family:var(--font-mono); font-size:11px; color:var(--fg-muted);
  border:1px solid var(--border-control); border-radius:var(--radius-sm); padding:1px 5px; flex:0 0 auto; }
.cmd-empty { padding:var(--space-4); color:var(--fg-muted); font-size:13px; }
.cmd-hint { padding:0 var(--space-4) var(--space-3); margin:0; }

/* --- toast ------------------------------------------------------------------------- */

.toast {
  position:fixed; z-index:60; left:50%; transform:translateX(-50%);
  bottom:max(var(--space-5), env(safe-area-inset-bottom));
  background:var(--surface-3); color:var(--fg);
  border:1px solid var(--border-control); border-radius:var(--radius);
  padding:var(--space-2) var(--space-4); font-size:13px;
  box-shadow:var(--shadow); max-width:calc(100vw - 2 * var(--space-4));
}
.toast.err { border-color:var(--danger); color:var(--danger); }

/* --- probe / register ---------------------------------------------------------------- */

.probe-row { display:flex; gap:var(--space-4); align-items:flex-end; flex-wrap:wrap; margin-bottom:var(--space-3); }
.probe-row .field { margin-bottom:0; flex:1 1 180px; }
.probe-row button { flex:0 0 auto; }
.probe-result {
  font-family:var(--font-mono); font-size:13px;
  padding:var(--space-2) var(--space-3); border-radius:var(--radius);
  border:1px solid var(--border-control); background:var(--surface-2);
}
.probe-result.up { border-color:var(--accent); color:var(--accent-text); }
.probe-result.down { border-color:var(--danger); color:var(--danger); }
.probe-result.degraded { border-color:var(--warn); color:var(--warn); }

.reg-form { margin-bottom:var(--space-5); padding-bottom:var(--space-4); border-bottom:1px solid var(--border); }

/* --- login ------------------------------------------------------------------------- */

.login-wrap {
  min-height:100svh; display:grid; place-items:center;
  padding:max(var(--space-5), env(safe-area-inset-top)) max(var(--space-4), env(safe-area-inset-right))
          max(var(--space-5), env(safe-area-inset-bottom)) max(var(--space-4), env(safe-area-inset-left));
}
.login-card {
  width:100%; max-width:380px;
  background:var(--surface); border:1px solid var(--border);
  border-radius:var(--radius-lg); padding:var(--space-6); box-shadow:var(--shadow);
}
.login-card .brand { display:flex; align-items:center; gap:var(--space-2); margin-bottom:var(--space-4); }
.login-card .brand .mark {
  width:30px; height:30px; display:grid; place-items:center; flex:0 0 auto;
  border-radius:var(--radius-sm); background:var(--accent); color:var(--accent-fg);
}
.login-card .brand .mark svg { width:17px; height:17px; }
.login-card h1 { font-size:17px; font-weight:600; margin:0; }
.login-card p.sub { margin:0 0 var(--space-5); color:var(--fg-muted); font-size:13px; }
.login-card .btn-primary { width:100%; margin-top:var(--space-2); }
.login-card .alert { margin-bottom:var(--space-4); }

/* --- responsive --------------------------------------------------------------------- */

@media (max-width: 1023px) {
  /* Below this, the side navigation overlays rather than displacing content —
     a 240px column plus a table leaves nothing usable on a tablet. */
  .shell, .shell.nav-collapsed,
  .shell.drawer-open, .shell.nav-collapsed.drawer-open { grid-template-columns:minmax(0,1fr); }
  .side-nav {
    position:fixed; top:var(--topbar-h); left:0; z-index:35;
    width:var(--sidenav-w); box-shadow:var(--shadow);
  }
  .shell.nav-collapsed .side-nav { display:none; }
  .drawer {
    position:fixed; top:var(--topbar-h); right:0; z-index:36;
    width:min(var(--drawer-w), 100vw);
  }
  .content { padding-left:var(--space-4); padding-right:var(--space-4); }
}

@media (max-width: 819px) {
  .top-btn span { display:none; }
  .top-btn { padding:0 var(--space-2); }
  .top-nav .meta { display:none; }
}

@media (min-width: 620px) { .kpis { grid-template-columns:repeat(3, minmax(0,1fr)); } }
@media (min-width: 1280px) { .kpis { grid-template-columns:repeat(6, minmax(0,1fr)); } }

/*
 * Download progress. A multi-gigabyte ISO fetch is the longest-running thing
 * this console does; without a bar it is indistinguishable from a hang.
 */
.dl-progress { margin:var(--space-3) 0; }
.dl-bar {
  height:6px; border-radius:3px; overflow:hidden;
  background:var(--border-control); border:1px solid var(--border-control);
}
.dl-bar span {
  display:block; height:100%; width:0%; background:var(--accent);
  transition:width 400ms ease-out;
}
.dl-progress.failed .dl-bar span { background:var(--danger); }

/* --- meters ----------------------------------------------------------------
 *
 * A number without its denominator does not say much: "2 vCPU" is meaningless
 * until you know the host has 80. Every meter here shows a value against what
 * it is a fraction OF, and the bar is the fastest way to read that ratio.
 *
 * Colour is a threshold signal, not decoration — it only leaves the neutral
 * accent when the ratio is worth acting on.
 */
.meters { display:grid; gap:var(--space-4); margin:var(--space-3) 0 0; }

.meter { display:grid; gap:var(--space-1); min-width:0; }
.meter-head { display:flex; align-items:baseline; gap:var(--space-2); font-size:12px; }
.meter-name { color:var(--fg-muted); flex:0 0 auto; }
.meter-value { margin-left:auto; font-family:var(--font-mono); color:var(--fg); white-space:nowrap; }
.meter-track {
  height:6px; border-radius:3px; overflow:hidden;
  background:var(--surface-3); border:1px solid var(--border-control);
}
.meter-fill { display:block; height:100%; background:var(--accent); border-radius:3px 0 0 3px; }
.meter.warn .meter-fill { background:var(--warn); }
.meter.high .meter-fill { background:var(--danger-solid); }
.meter-note { font-size:11px; color:var(--fg-subtle); }

/* Stacked distribution: several parts of one whole, in one bar. */
.statbar { display:flex; height:8px; border-radius:4px; overflow:hidden; background:var(--surface-3);
           border:1px solid var(--border-control); }
.statbar span { display:block; height:100%; }
.statbar .s-running { background:var(--accent); }
.statbar .s-off     { background:var(--fg-subtle); }
.statbar .s-paused  { background:var(--warn); }
.statbar .s-other   { background:var(--info); }

.statkey { display:flex; flex-wrap:wrap; gap:var(--space-3); margin-top:var(--space-2); font-size:12px; }
.statkey span { display:inline-flex; align-items:center; gap:var(--space-1); color:var(--fg-muted); }
.statkey i { width:8px; height:8px; border-radius:2px; flex:0 0 auto; }
.statkey .s-running i { background:var(--accent); }
.statkey .s-off i     { background:var(--fg-subtle); }
.statkey .s-paused i  { background:var(--warn); }
.statkey .s-other i   { background:var(--info); }

/* Detail drawer: cards rather than one long key-value list. */
.detail-card {
  border:1px solid var(--border); border-radius:var(--radius);
  background:var(--surface-2); padding:var(--space-4); margin-bottom:var(--space-4);
}
.detail-card > h3 {
  margin:0 0 var(--space-3); font-size:11px; font-weight:600;
  text-transform:uppercase; letter-spacing:.06em; color:var(--fg-muted);
}
.detail-card table { font-size:12px; }
.detail-card table th { font-size:10px; }

/* The status line at the top of a VM's detail. */
.vm-status { display:flex; align-items:center; gap:var(--space-4); flex-wrap:wrap;
             margin-bottom:var(--space-4); }
.vm-status .vm-state { display:inline-flex; align-items:center; gap:var(--space-2);
                       font-size:15px; font-weight:600; }
.vm-status .vm-dot { width:9px; height:9px; border-radius:50%; background:var(--fg-subtle); flex:0 0 auto; }
.vm-status.running .vm-dot { background:var(--accent); }
.vm-status.paused  .vm-dot { background:var(--warn); }
.vm-status .vm-meta { color:var(--fg-muted); font-size:12px; }
.vm-status .vm-meta.mono { font-family:var(--font-mono); }

/*
 * Detail-card tables always live in the 360px side panel, so they get the
 * stacked treatment unconditionally rather than only below a breakpoint.
 * Scrolling a four-column table sideways inside a narrow drawer is worse than
 * reading it as labelled rows.
 */
.detail-card table thead { display:none; }
.detail-card table,
.detail-card tbody,
.detail-card tbody tr,
.detail-card tbody td { display:block; width:100%; }
.detail-card tbody tr {
  border:1px solid var(--border); border-radius:var(--radius-sm);
  padding:var(--space-2); margin-bottom:var(--space-2); background:var(--surface);
}
.detail-card tbody tr:last-child { margin-bottom:0; }
.detail-card tbody td {
  display:flex; gap:var(--space-3); align-items:baseline;
  padding:2px 0; border:0; white-space:normal; word-break:break-word;
}
.detail-card tbody td::before {
  content:attr(data-label);
  color:var(--fg-muted); font-size:10px; font-weight:600;
  text-transform:uppercase; letter-spacing:.05em;
  flex:0 0 68px; font-family:var(--font-sans);
}
.detail-card tbody td > div { flex:1 1 auto; min-width:0; }
.detail-card .scroll { overflow:visible; }
