/* portal.css — Warren portal design system.
 * Phase 0 of the "Instrument" redesign (2026-07-01): tokens-first, light+dark,
 * self-hosted assets, no build. The :root token layer + @font-face were added
 * and every component's hardcoded colour was mapped to a token, so the existing
 * markup instantly gets the new palette, fonts, dark mode and dot-grid
 * substrate. Component *structure* is unchanged here — Phases 1-2 restyle the
 * chrome + components into the full Instrument language. Old token names are
 * kept as aliases so no template breaks.
 */

/* ===== Self-hosted fonts (latin + cyrillic; /static/fonts) ================= */
@font-face{font-family:"Inter";src:url("/static/fonts/inter-latin.woff2") format("woff2");
  font-weight:100 900;font-display:swap;
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+2074,U+20AC,U+2122,U+2212;}
@font-face{font-family:"Inter";src:url("/static/fonts/inter-cyrillic.woff2") format("woff2");
  font-weight:100 900;font-display:swap;
  unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;}
@font-face{font-family:"IBM Plex Mono";src:url("/static/fonts/ibm-plex-mono-latin-400.woff2") format("woff2");font-weight:400;font-display:swap;unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+2074,U+20AC,U+2122,U+2212;}
@font-face{font-family:"IBM Plex Mono";src:url("/static/fonts/ibm-plex-mono-cyrillic-400.woff2") format("woff2");font-weight:400;font-display:swap;unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;}
@font-face{font-family:"IBM Plex Mono";src:url("/static/fonts/ibm-plex-mono-latin-500.woff2") format("woff2");font-weight:500;font-display:swap;unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+2074,U+20AC,U+2122,U+2212;}
@font-face{font-family:"IBM Plex Mono";src:url("/static/fonts/ibm-plex-mono-cyrillic-500.woff2") format("woff2");font-weight:500;font-display:swap;unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;}
@font-face{font-family:"IBM Plex Mono";src:url("/static/fonts/ibm-plex-mono-latin-600.woff2") format("woff2");font-weight:600;font-display:swap;unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+2074,U+20AC,U+2122,U+2212;}
@font-face{font-family:"IBM Plex Mono";src:url("/static/fonts/ibm-plex-mono-cyrillic-600.woff2") format("woff2");font-weight:600;font-display:swap;unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;}
@font-face{font-family:"IBM Plex Mono";src:url("/static/fonts/ibm-plex-mono-latin-700.woff2") format("woff2");font-weight:700;font-display:swap;unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+2074,U+20AC,U+2122,U+2212;}
@font-face{font-family:"IBM Plex Mono";src:url("/static/fonts/ibm-plex-mono-cyrillic-700.woff2") format("woff2");font-weight:700;font-display:swap;unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;}

/* ===== Tokens (light-first, one electric-blue signal; AA both themes) ====== */
:root {
  color-scheme: light dark;

  /* surfaces & text */
  --bg:            light-dark(#f7f8fb, #12151c);
  --surface:       light-dark(#ffffff, #1a1e27);
  --surface-2:     light-dark(#eef1f7, #212632);
  --surface-3:     light-dark(#e7ebf3, #283040);
  --text:          light-dark(#2a2f39, #e9ecf3);
  --text-muted:    light-dark(#565d6b, #99a2b3);
  --border:        light-dark(#e6e8ee, #2b3140);
  --border-strong: light-dark(#cfd4e0, #3b4356);

  /* the one electric-blue signal */
  --accent:        light-dark(#2a5cff, #6f9bff);
  --accent-strong: light-dark(#1e46d6, #93b4ff);
  --accent-ink:    light-dark(#ffffff, #0a0f1d);
  --accent-tint:   light-dark(color-mix(in oklch,#2a5cff 8%,#fff),
                              color-mix(in oklch,#6f9bff 16%,#1a1e27));
  --accent-line:   light-dark(color-mix(in oklch,#2a5cff 55%,#cfd6e6),
                              color-mix(in oklch,#6f9bff 62%,#2b3140));
  --link:          light-dark(#1e46d6, #9cbaff);
  --focus:         var(--accent);

  /* instrument substrate + node-network motif */
  --dot:      light-dark(rgba(42,47,57,.085), rgba(233,236,243,.065));
  --grid:     light-dark(rgba(42,47,57,.10),  rgba(233,236,243,.09));
  --net-line: light-dark(#c2cadd, #333c4f);
  --net-dot:  light-dark(#aab4cc, #46516a);
  --net-idle: light-dark(#94a0bb, #566280);

  /* semantic states */
  --danger-fg: light-dark(#b3271b, #ff9a8f);
  --danger-bg: light-dark(#fdecea, #33201e);
  --danger-bd: light-dark(#f0c4bd, #5a3630);
  --danger:    light-dark(#c53030, #e5675c);   /* solid — usable as a badge fill */
  --warn-fg:   light-dark(#8a5a06, #f2c064);
  --warn-bg:   light-dark(#fbf1de, #322a1a);
  --warn-bd:   light-dark(#ecd6a6, #5a4a2a);
  --warning:   light-dark(#e6a700, #e0a83a);   /* solid amber — DRIFT badge fill */
  --ok-fg:     light-dark(#1c7a4b, #5cd39a);
  --ok-bg:     light-dark(#e8f6ee, #17281f);
  --ok-bd:     light-dark(#bfe3cd, #2e5540);

  /* fluid type / spacing */
  --step--2: clamp(.72rem,.70rem + .10vw,.78rem);
  --step--1: clamp(.83rem,.80rem + .16vw,.94rem);
  --step-0:  clamp(1rem,.96rem + .22vw,1.08rem);
  --step-1:  clamp(1.2rem,1.08rem + .55vw,1.5rem);
  --step-2:  clamp(1.5rem,1.3rem + .95vw,2.05rem);
  --space-2xs:.5rem; --space-xs:.75rem; --space-s:1rem; --space-m:1.5rem;
  --space-l:2rem; --space-xl:3rem;

  --radius: 6px;
  --sans:"Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono:"IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* --- back-compat aliases (old token names used across templates/CSS) --- */
  --fg: var(--text);
  --fg-muted: var(--text-muted);
  --bg-alt: var(--surface);
  --accent-hover: var(--accent-strong);
  --danger-hover: light-dark(#9b2222, #f0837a);
}
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"]  { color-scheme: dark; }

/* Fallback for engines without light-dark(): follow OS via prefers-color-scheme */
@supports not (color: light-dark(#000,#fff)) {
  :root { color-scheme: light; }
  @media (prefers-color-scheme: dark) {
    :root {
      --bg:#12151c; --surface:#1a1e27; --surface-2:#212632; --surface-3:#283040;
      --text:#e9ecf3; --text-muted:#99a2b3; --border:#2b3140; --border-strong:#3b4356;
      --accent:#6f9bff; --accent-strong:#93b4ff; --accent-ink:#0a0f1d; --link:#9cbaff;
      --dot:rgba(233,236,243,.065); --grid:rgba(233,236,243,.09);
      --net-line:#333c4f; --net-dot:#46516a; --net-idle:#566280;
      --danger-fg:#ff9a8f; --danger:#e5675c; --warn-fg:#f2c064; --warning:#e0a83a; --ok-fg:#5cd39a;
    }
  }
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  color: var(--text);
  background-color: var(--bg);
  /* dot-grid instrument substrate */
  background-image: radial-gradient(circle at 1px 1px, var(--dot) 1px, transparent 1.4px);
  background-size: 22px 22px;
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* ===== Instrument shell frame (mockup) ====================================
   Every full page renders inside a bordered, rounded surface card on the
   dot-grid substrate. `.wrap` is the max-width container (the substrate shows
   in its outer padding, around the card). `.shell` is the framed surface: it
   holds the nav at its top + the padded content below, corners clipped. The
   Instrument look breathes wider (helps admin tables); forms/inputs stay
   capped at their own readable max-widths (see the form rules further down).
   HTMX partials are chrome-less, so the wrap/shell exist only on full loads. */
.wrap {
  width: 100%;
  /* 1600 (operator pick 2026-07-04, from rendered 1400/1600/1920 variants on a
     2560 canvas): tables breathe on big monitors, the substrate frame stays. */
  max-width: var(--wrap-max, 1600px);
  margin-inline: auto;
  padding: clamp(1.5rem, 4vw, 2.6rem) clamp(1rem, 4vw, 2rem);
}
.shell {
  border: 1px solid var(--border);
  border-radius: 12px;
  background-color: var(--surface);
  overflow: clip;
}
/* content pad — the shell's inner body padding (mockup `.body-pad`). */
main { padding: clamp(1.3rem, 3vw, 2rem); }

/* ===== Nav chrome (Instrument) — brand mark, home, account, lang, theme =====
   Full-width at the top of the shell (no own max-width/centering — the `.wrap`
   owns that now); a hairline bottom border separates it from the content. */
.navbar {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  padding: .85rem 1.2rem;
  border-bottom: 1px solid var(--border);
  background-color: var(--surface);
}
/* Phone: the bar still wraps, just denser — and the mono "/portal" meta is
   ornament, not information, so it yields its space to the real controls. */
@media (max-width: 560px) {
  .navbar { gap: .5rem .8rem; padding: .7rem .9rem; }
  .brand__meta { display: none; }
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  text-decoration: none;
  color: var(--text);
}
.brand:hover { text-decoration: none; color: var(--text); }
.brand__mark { flex: none; width: 26px; height: 26px; }
.brand__word {
  font-weight: 720;
  font-size: var(--step-1);
  letter-spacing: -.03em;
}
/* mono "/portal" meta beside the wordmark (mockup) */
.brand__meta {
  font-family: var(--mono);
  font-size: var(--step--2);
  color: var(--text-muted);
  letter-spacing: .02em;
}

/* Section links row (logged-out: О проекте · Приватность · Статус). */
.wnav__links {
  display: flex;
  gap: .3rem;
  flex-wrap: wrap;
}
.wnav__links a {
  color: var(--text-muted);
  text-decoration: none;
  font-size: var(--step--1);
  padding: .35rem .6rem;
  border-radius: 5px;
}
.wnav__links a:hover {
  color: var(--text);
  background: var(--surface-2);
  text-decoration: none;
}
.wnav__links a[aria-current="page"] {
  color: var(--text);
  background: var(--surface-2);
  font-weight: 600;
}

/* Right control cluster — lang picker + theme toggle (+ account when logged-in). */
.wnav__ctl { margin-left: auto; }

.auth-state {
  display: inline-flex;
  align-items: center;
  gap: .8rem;
  flex-wrap: wrap;
  margin-left: auto;             /* controls hug the right edge */
  color: var(--text-muted);
  font-size: var(--step--1);
}
.auth-state > a {
  color: var(--text-muted);
  text-decoration: none;
  padding: .3rem .55rem;
  border-radius: 5px;
}
.auth-state > a:hover {
  color: var(--text);
  background: var(--surface-2);
  text-decoration: none;
}
/* The anonymous top-bar Sign-in is a real CTA — the muted link paint above
   must not wash out its accent-ink label, the generic flow margin must not
   push it below the picker's centre line, and the compact padding has to
   out-rank the `.auth-state > a` chrome padding. */
.auth-state > a.cta {
  color: var(--accent-ink);
  margin: 0;
  padding: .32rem .7rem;
}
.auth-state > a.cta:hover { color: var(--accent-ink); background: var(--accent-strong); }

/* Account identity — mono readout, framed like an instrument label. */
.who {
  font-family: var(--mono);
  font-size: var(--step--2);
  color: var(--text-muted);
  letter-spacing: .02em;
  border: 1px dashed var(--border-strong);
  border-radius: 5px;
  padding: .28rem .5rem;
}

h1, h2 { margin-top: 0; letter-spacing: -.02em; }
p { margin: 0.5rem 0 1rem; }
p.muted { color: var(--text-muted); font-size: 0.9rem; }

a { color: var(--link); }
a:hover { color: var(--accent-strong); }

/* ===== Alerts / notices (Instrument) ===================================
   Tinted panel with a left accent border. `.alert` is the reusable base
   Phase 3 will use for the visible login-error fix; the bare `p.error` /
   `.warning` / `p.success` notices reuse the same language so every state
   reads as a framed instrument readout. AA-legible in both themes. */
.alert {
  display: flex;
  gap: .65rem;
  align-items: flex-start;
  margin: 0 0 1.25rem;
  padding: .75rem .9rem;
  border: 1px solid var(--border);
  border-left: 3px solid var(--text-muted);
  border-radius: var(--radius);
  background: var(--surface-2);
  color: var(--text);
  font-size: var(--step--1);
  line-height: 1.45;
}
.alert__icon {
  flex: none;
  width: 1.3rem;
  height: 1.3rem;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-family: var(--mono);
  font-weight: 700;
  font-size: .8rem;
  background: var(--text-muted);
  color: var(--surface);
}
.alert strong { display: block; color: var(--text); font-weight: 640; }
.alert__sub { color: var(--text-muted); }
.alert--error {
  border-color: var(--danger-bd);
  border-left-color: var(--danger-fg);
  background: var(--danger-bg);
  color: var(--danger-fg);
}
.alert--error .alert__icon { background: var(--danger-fg); color: var(--danger-bg); }
.alert--error strong { color: var(--danger-fg); }
.alert--warn {
  border-color: var(--warn-bd);
  border-left-color: var(--warn-fg);
  background: var(--warn-bg);
  color: var(--warn-fg);
}
.alert--warn .alert__icon { background: var(--warn-fg); color: var(--warn-bg); }
.alert--ok {
  border-color: var(--ok-bd);
  border-left-color: var(--ok-fg);
  background: var(--ok-bg);
  color: var(--ok-fg);
}
.alert--ok .alert__icon { background: var(--ok-fg); color: var(--ok-bg); }

/* Toast rail — fixed slot for transient 5xx/network alerts (the htmx error
   contract in base.html). Reuses the `.alert` language; stacks bottom-right,
   above the shell, never blocks clicks outside its own cards. */
.toast-rail {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  z-index: 100;
  display: flex;
  flex-direction: column;
  gap: .5rem;
  max-width: min(26rem, calc(100vw - 2rem));
  pointer-events: none;
}
.toast-rail .toast {
  margin: 0;
  box-shadow: 0 6px 24px rgb(0 0 0 / .18);
  pointer-events: auto;
}

/* Bare inline notices — same tinted-panel language as `.alert`. */
p.error, .warning, .settings-error {
  margin: .5rem 0 1rem;
  padding: .65rem .9rem;
  border: 1px solid var(--danger-bd);
  border-left: 3px solid var(--danger-fg);
  border-radius: var(--radius);
  background: var(--danger-bg);
  color: var(--danger-fg);
  font-size: var(--step--1);
  line-height: 1.45;
}
p.success, .settings-saved {
  margin: .5rem 0 1rem;
  padding: .65rem .9rem;
  border: 1px solid var(--ok-bd);
  border-left: 3px solid var(--ok-fg);
  border-radius: var(--radius);
  background: var(--ok-bg);
  color: var(--ok-fg);
  font-size: var(--step--1);
  line-height: 1.45;
}
.admin-override-banner {
  border: 1px solid var(--warn-bd);
  border-left: 3px solid var(--warn-fg);
  border-radius: var(--radius);
  background: var(--warn-bg);
  color: var(--warn-fg);
  padding: .65rem .9rem;
  margin: 1rem 0;
}
.admin-override-banner .tooltip { text-decoration: underline dotted; cursor: help; }

/* ===== Empty state (Instrument) — muted, inviting, framed like a plot ====
   For "no devices / no servers / no soaks". A dashed instrument frame with a
   mono coordinate label; optional `.empty__label` corner tag. */
.empty {
  position: relative;
  margin: 1rem 0;
  padding: 1.4rem;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius);
  background: color-mix(in oklch, var(--surface) 55%, transparent);
  text-align: center;
}
.empty__label {
  position: absolute;
  top: .55rem;
  right: .7rem;
  font-family: var(--mono);
  font-size: var(--step--2);
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--text-muted);
}
.empty__coord {
  display: block;
  margin-bottom: .5rem;
  font-family: var(--mono);
  font-size: var(--step--2);
  letter-spacing: .05em;
  color: var(--accent);
}
.empty__h { font-weight: 640; font-size: var(--step-0); margin-bottom: .3rem; }
.empty__p {
  max-width: 40ch;
  margin: 0 auto .9rem;
  color: var(--text-muted);
  font-size: var(--step--1);
}

code {
  font-family: var(--mono);
  background: var(--surface-2);
  border: 1px solid var(--border);
  padding: 0 0.25rem;
  border-radius: 3px;
}

/* focus + reduced-motion (quality floor) */
:where(a,button,input,select,summary,textarea,[tabindex]):focus-visible {
  outline: 2px solid var(--focus); outline-offset: 2px; border-radius: 3px;
}
@media (prefers-reduced-motion: reduce) {
  *,*::before,*::after { animation-duration:.01ms!important; transition-duration:.01ms!important; }
}
.sr-only {
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}

/* theme toggle (markup + inline JS live in base.html) — labelled instrument
   switch: "◐ Светлая" / "◐ Тёмная". The state word is emitted by CSS from the
   active :root[data-theme]; the localized strings arrive as the --theme-light /
   --theme-dark custom properties set inline on the button, so the label is both
   translatable AND flips with no JS flash (matches the no-flash theme script). */
.theme-toggle {
  appearance: none; cursor: pointer;
  display: inline-flex; align-items: center; gap: .4rem;
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border-strong); border-radius: 5px;
  padding: .32rem .55rem; font-family: var(--mono); font-size: var(--step--2);
  letter-spacing: .03em; line-height: 1.2;
  transition: color .15s, border-color .15s;
}
.theme-toggle:hover { border-color: var(--accent); }
.theme-toggle > [aria-hidden="true"]:first-child { color: var(--text-muted); }
/* default (no explicit theme) follows the OS: light label unless OS is dark */
.theme-toggle__state::after { content: var(--theme-light, "Light"); }
@media (prefers-color-scheme: dark) {
  .theme-toggle__state::after { content: var(--theme-dark, "Dark"); }
}
/* an explicit user choice overrides the OS default in both directions */
:root[data-theme="light"] .theme-toggle__state::after { content: var(--theme-light, "Light"); }
:root[data-theme="dark"]  .theme-toggle__state::after { content: var(--theme-dark, "Dark"); }

/* ===== .eyebrow — signature section label (leading rule + mono accent) =====
   Reusable header for Phase 2/4 screens. */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  font-family: var(--mono);
  font-size: var(--step--1);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--accent);
  font-weight: 700;
}
.eyebrow::before {
  content: "";
  width: 1.7em;
  height: 0;
  border-top: 3px solid currentColor;
}
/* One label — one paint (operator, 2026-07-03): container prose rules
   (.form-head p / .auth-aside p) washed the <p class="eyebrow"> variants out
   to muted grey while the span variants stayed accent. Pin the accent. */
.form-head p.eyebrow,
.auth-aside p.eyebrow { color: var(--accent); }

/* ===== Forms (Instrument) — flat surfaces, strong-border inputs, accent
   focus ring. Labels wrap their inputs (block); width caps kept at 360/480. */
form fieldset {
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  padding: 1rem;
  margin: 0 0 1rem;
  background: var(--surface);
}

form legend {
  font-family: var(--mono);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 0 0.35rem;
}
form label {
  display: block;
  margin-bottom: 0.75rem;
  font-size: var(--step--1);
  font-weight: 600;
}

form input[type="text"],
form input[type="email"],
form input[type="password"],
form input[type="number"],
form input[type="url"],
form input[type="date"],
form input:not([type]),
form select,
form textarea {
  display: block;
  width: 100%;
  max-width: 360px;
  margin-top: .35rem;
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-weight: 400;
  transition: border-color .15s, box-shadow .15s, background-color .15s;
}
/* mono for the code-ish inputs (ids, patterns, keys, values) */
form textarea,
form input[name="private_key"],
form input[name="pattern"],
form input[name="value"],
form input[name="fleet_member_id"],
.settings-edit input,
.settings-edit select { font-family: var(--mono); }

form input::placeholder,
form textarea::placeholder { color: var(--text-muted); }

form input:focus-visible,
form select:focus-visible,
form textarea:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--accent) 22%, transparent);
}

form textarea {
  max-width: 480px;
  resize: vertical;
}

/* Checkboxes/radios must NOT be full-width-blocked — keep them inline with
   their label text. */
form input[type="checkbox"],
form input[type="radio"] {
  display: inline-block;
  width: auto;
  margin: 0 0.4rem 0 0;
  accent-color: var(--accent);
}

/* ===== Buttons (Instrument) — accent-fill primary, red danger, link ghost.
   Covers <button>, <a class="button"> and <a class="cta"> link-buttons. */
button,
a.button,
.cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  background: var(--accent);
  color: var(--accent-ink);
  border: 1px solid var(--accent);
  padding: 0.5rem 1rem;
  border-radius: var(--radius);
  font: inherit;
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .15s, border-color .15s, color .15s;
}
button:hover,
a.button:hover,
.cta:hover {
  background: var(--accent-strong);
  border-color: var(--accent-strong);
  color: var(--accent-ink);
  text-decoration: none;
}
/* Compact variant for the top-bar Sign-in (same family as the hero CTA). */
.cta--sm { padding: .32rem .7rem; font-size: var(--step--1); }
a.button, .cta { margin-top: .5rem; }

button.link {
  display: inline;
  background: transparent;
  border: 0;
  color: var(--link);
  padding: 0;
  font-weight: inherit;
}
button.link:hover {
  background: transparent;
  color: var(--accent-strong);
  text-decoration: underline;
}

button.danger {
  background: transparent;
  color: var(--danger-fg);
  border-color: var(--danger-bd);
}
button.danger:hover {
  background: var(--danger-bg);
  border-color: var(--danger-fg);
  color: var(--danger-fg);
}

.cancel { margin-left: 0.75rem; }

/* ===== Tables (Instrument) — surface panel, mono uppercase header on
   --surface-2, hairline rows, clear hover, rounded per --radius. Long RU
   strings wrap instead of forcing overflow. */
table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;                 /* clip corners to the rounded panel */
}

th, td {
  padding: 0.6rem 0.75rem;
  border-bottom: 1px solid var(--border);
  text-align: left;
  vertical-align: top;
  overflow-wrap: anywhere;          /* wrap-friendly for long RU/host strings */
}

thead th {
  font-family: var(--mono);
  font-size: var(--step--2);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--text-muted);
  background: var(--surface-2);
  white-space: nowrap;
  vertical-align: middle;
}

tbody td { font-size: var(--step--1); }
tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover td { background: color-mix(in oklch, var(--surface-2) 55%, transparent); }

/* Mono the data/id/coordinate cells (versions, shas, timestamps, hosts). */
.mono, .num,
.settings-key, .settings-current, .settings-envdefault,
.soaks-table td { font-family: var(--mono); }
.num, .soaks-table td { font-variant-numeric: tabular-nums; }

/* code inside a cell shouldn't double-frame */
td code { background: transparent; border: 0; padding: 0; }

.inline { display: inline; margin-left: 0.5rem; }

.htmx-indicator {
  display: none;
  margin-left: 0.5rem;
  color: var(--text-muted);
}
.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator { display: inline-block; }

/* ===== Admin portal (Phase 7 — /portal/admin/*) ===================== */

/* Admin tabs — Instrument tab-rail (mono labels, accent underline on active) */
.admin-tabs {
  display: flex;
  gap: .2rem;
  flex-wrap: wrap;
  /* NO overflow-x:auto: the row WRAPS, and auto only ever produced a phantom
     scrollbar (overflow-x:auto forces overflow-y to auto — a 1px underline
     overhang rendered a vertical thumb next to the tabs). */
  overflow: visible;
  margin-bottom: 1.4rem;
  border-bottom: 1px solid var(--border);
}
.admin-tabs a {
  font-family: var(--mono);
  font-size: var(--step--1);
  letter-spacing: .02em;
  color: var(--text-muted);
  text-decoration: none;
  padding: .55rem .7rem;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  white-space: nowrap;
}
.admin-tabs a:hover { color: var(--text); text-decoration: none; }
.admin-tabs a.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
  font-weight: 600;
}

/* Status / health text-state classes — mono, semantic tint, legible both
   themes. Rendered inline in table cells (`status-{{ status }}` etc.). */
.status-alpha, .status-beta, .status-stable, .status-quarantined,
.health-healthy, .health-degraded, .health-unhealthy,
.health-unknown, .health-quarantined {
  font-family: var(--mono);
  font-size: var(--step--2);
  letter-spacing: .03em;
}
.status-alpha { color: var(--warn-fg); }
.status-beta { color: var(--accent); }
.status-stable { color: var(--ok-fg); }
.status-quarantined { color: var(--danger-fg); font-weight: 700; }

.health-healthy { color: var(--ok-fg); }
.health-degraded { color: var(--warn-fg); }
.health-unhealthy { color: var(--danger-fg); }
.health-unknown { color: var(--text-muted); }
.health-quarantined { color: var(--danger-fg); font-weight: 700; }

/* soak per-axis rate legibility */
.samples-ok { color: var(--ok-fg); }
.samples-low { color: var(--warn-fg); }

/* ===== Dashboard cards (Instrument) — surface panels with corner
   registration marks; mono eyebrow-style title, tabular numerals for counts. */
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); gap: 1rem; }
.card {
  position: relative;
  border: 1px solid var(--border);
  background: var(--surface);
  padding: 1.1rem;
  border-radius: var(--radius);
}
/* subtle top-edge registration line — the instrument-panel cue */
.cards > .card { border-top: 2px solid var(--accent-line, var(--border-strong)); }
.card > h2 {
  font-family: var(--mono);
  font-size: var(--step--2);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--text-muted);
  margin: 0 0 .6rem;
}
.card > p { font-variant-numeric: tabular-nums; }
.card ul { margin: .4rem 0 0; padding-left: 1.1rem; font-size: var(--step--1); }
.card ul li { font-variant-numeric: tabular-nums; }

/* ----- Summary card v2 (Instrument, `§04` dashboard) — the mockup `.scard`:
   corner registration marks, a mono `›`-prefixed label, a big tabular headline
   count, and a stack of `.kv` status rows (dot + label + right-aligned value).
   `.ver-pill` = amber pending-promotion tag; `.auditlog` = mono event feed. */
.scard { padding: 1.1rem; --mko: 8px; }
.scard__label {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin: 0 0 .75rem;
  font-family: var(--mono);
  font-size: var(--step--2);
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--text-muted);
}
.scard__label .k { color: var(--accent); }
.scard__big {
  margin: 0;
  font-size: var(--step-3);
  font-weight: 740;
  letter-spacing: -.03em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.scard__big small {
  margin-left: .4rem;
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0;
  color: var(--text-muted);
}
.scard__rows { margin-top: .7rem; display: grid; gap: .4rem; }
.kv { display: flex; align-items: center; gap: .5rem; font-size: var(--step--1); }
.kv .k { color: var(--text-muted); }
.kv .v { margin-left: auto; font-family: var(--mono); font-variant-numeric: tabular-nums; }
.sdot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.sdot--ok { background: var(--ok-fg); }
.sdot--warn { background: var(--warn-fg); }
.sdot--danger { background: var(--danger-fg); }
.ver-pill {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .25rem .5rem;
  border: 1px solid var(--warn-bd);
  border-radius: 5px;
  background: var(--warn-bg);
  color: var(--warn-fg);
  font-family: var(--mono);
  font-weight: 600;
  font-size: var(--step--1);
}
.auditlog { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; }
.auditlog li {
  display: flex;
  gap: .5rem;
  align-items: baseline;
  font-family: var(--mono);
  font-size: var(--step--2);
  color: var(--text);
  /* One line per event; the tail span ellipsizes instead of vanishing. */
  overflow: hidden;
  white-space: nowrap;
}
.auditlog .tail {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
.auditlog .t { color: var(--text-muted); flex: none; }
.auditlog .op { color: var(--accent); }

/* Channels grid */
.channels-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; }
.channel-column { border: 1px solid var(--border); background: var(--surface); padding: 1rem; border-radius: var(--radius); }

/* Pagination (Instrument) — mono, hairline pill controls, muted position. */
.pagination {
  display: flex;
  gap: .75rem;
  align-items: center;
  padding: .6rem 0;
  font-family: var(--mono);
  font-size: var(--step--2);
  color: var(--text-muted);
}
.pagination a {
  text-decoration: none;
  padding: .3rem .6rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  color: var(--text-muted);
  letter-spacing: .03em;
}
.pagination a:hover { color: var(--text); border-color: var(--accent); background: var(--surface-2); }

/* Filter bar */
.filter-bar { display: flex; flex-wrap: wrap; gap: .5rem; margin: .5rem 0; align-items: center; }
.inline-form { display: inline-flex; flex-wrap: wrap; gap: .35rem; align-items: center; }

/* Inputs/selects inside inline + filter forms must NOT collapse to the
   full-width block rule above. */
.filter-bar input,
.filter-bar select,
.inline-form input,
.inline-form select,
.table-action input,
.table-action select {
  display: inline-block;
  width: auto;
  max-width: none;
  min-width: 8rem;
  margin: 0;
}
.table-action select { min-width: 6rem; }

/* Table action column — wrap instead of forcing overflow. */
.row-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
  align-items: center;
}

/* ----- Fleet table v2 (Instrument) ----
   Denser than the landing mockup's 5-col summary: 8 columns + a stacked
   action cluster. Sits inside a scroll-safe `.table-wrap`, so cells keep their
   tokens intact (no mid-word break) rather than shattering `ru-core` / version
   strings at a narrow viewport. Only the long owner-email cell may wrap. */
.fleet-table { width: 100%; table-layout: auto; min-width: 760px; }
.fleet-table th, .fleet-table td {
  padding: .5rem .6rem;
  font-size: var(--step--1);
}
.fleet-table td .cell-main,
.fleet-table td.mono { white-space: nowrap; }
.fleet-table .fleet-meta { overflow-wrap: anywhere; }

.fleet-identity { line-height: 1.3; }
.fleet-name { display: block; font-weight: 600; color: var(--text); }
.fleet-hostname {
  display: block;
  margin-top: .1rem;
  font-size: var(--step--2);
  color: var(--text-muted);
  font-family: var(--mono);
}

.fleet-meta { display: flex; flex-direction: column; gap: .2rem; }
.fleet-meta span { font-size: var(--step--2); }

/* Badges (Instrument) — legible tinted pill using the semantic tint tokens,
   AA in BOTH themes. UNSAFE = danger-red, DRIFT = amber, removed = muted. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  padding: .1rem .45rem;
  border: 1px solid;
  border-radius: var(--radius);
  font-family: var(--mono);
  font-size: var(--step--2);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  line-height: 1.4;
  white-space: nowrap;
  vertical-align: middle;
}
.badge.unsafe { color: var(--danger-fg); background: var(--danger-bg); border-color: var(--danger-bd); }
.badge.removed { color: var(--text-muted); background: var(--surface-2); border-color: var(--border); }
/* Config-drift alert — warning amber, distinct from the danger-red UNSAFE. */
.badge.drift { color: var(--warn-fg); background: var(--warn-bg); border-color: var(--warn-bd); cursor: help; }

/* Collapsed "Removed" section (Instrument disclosure). */
.fleet-removed { margin-top: 1rem; }
.fleet-removed > summary {
  cursor: pointer;
  padding: .45rem .6rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-2);
  font-family: var(--mono);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: .02em;
  color: var(--text-muted);
}
.fleet-removed > summary:hover { color: var(--text); border-color: var(--border-strong); }
.fleet-removed[open] > summary { color: var(--text); margin-bottom: .6rem; }
.fleet-removed .fleet-table { opacity: .85; }

/* Responsive tables. */
.table-scroll {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* Language picker (base.html navbar) — segmented instrument switch. Endonyms
   ("English" / "Русский") stay in their native form (never translated). */
.lang-picker {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--border-strong);
  border-radius: 5px;
  overflow: hidden;
  background: var(--surface);
}
.lang-picker .lang-link {
  text-decoration: none;
  padding: .3rem .55rem;
  font-family: var(--mono);
  font-size: var(--step--2);
  letter-spacing: .02em;
  color: var(--text-muted);
  line-height: 1.2;
  white-space: nowrap;
}
.lang-picker .lang-link + .lang-link { border-left: 1px solid var(--border); }
.lang-picker .lang-link:hover { color: var(--text); background: var(--surface-2); text-decoration: none; }
.lang-picker .lang-link.active {
  color: var(--accent-ink);
  background: var(--accent);
  font-weight: 600;
  text-decoration: none;
}

/* ----- Customer self-service deploy surface (Phase 8) ----- */
.my-servers { margin-top: 2rem; border-top: 1px solid var(--border); padding-top: 1rem; }
.my-servers-table { width: 100%; }
.my-servers-table th, .my-servers-table td { padding: .5rem .6rem; }
.shared-pool-toggle {
  display: flex;
  align-items: center;             /* autosave: switch + inline ✓ ack row */
  gap: .8rem;
  flex-wrap: wrap;
  margin: .2rem 0 1.1rem;
  padding: 0;
}
/* the inline ✓-saved ack must not add block margins to the actions row */
#shared-pool-result .alert { margin: 0; padding: .3rem .6rem; }
/* `.cta` / `.warning` / `.admin-override-banner` are styled in the buttons /
   alerts sections above (Instrument language). */

/* ===== §0N · ROUTE ruler (Instrument) — the per-screen section header ======
   Ported from the mockup (.screen__tag). A mono uppercase readout — accented
   section id + path + coordinates — trailed by a dotted ruler scale. Reusable:
   any screen drops a `.screen-tag` band under the nav (§01 landing, §02 login,
   §03 devices, §04 admin …). */
.screen-tag {
  display: flex;
  align-items: center;
  gap: .9rem;
  flex-wrap: wrap;
  margin: 0 0 1.4rem;
  font-family: var(--mono);
  font-size: var(--step--2);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.screen-tag__sec { color: var(--accent); font-weight: 600; }
.screen-tag__path { color: var(--text); }
/* The ruler navigates (operator, 2026-07-03): the section label jumps one
   level up; the path is REAL per-segment breadcrumbs (each anchor = its own
   level; segments without a route stay plain spans). Quiet by default,
   accent on hover — the band must not read as a row of buttons. */
a.screen-tag__link,
.screen-tag__path a { color: inherit; text-decoration: none; }
a.screen-tag__link:hover,
.screen-tag__path a:hover { color: var(--accent); text-decoration: underline; }
.screen-tag::after {
  content: "";
  flex: 1 1 60px;
  height: 8px;
  align-self: flex-end;
  margin-bottom: 3px;
  /* ruler ticks — coordinate scale */
  background:
    repeating-linear-gradient(90deg, var(--border-strong) 0 1px, transparent 1px 8px) bottom / 100% 4px no-repeat,
    repeating-linear-gradient(90deg, var(--border-strong) 0 1px, transparent 1px 40px) bottom / 100% 8px no-repeat;
}

/* ============================================================================
   Landing / hero (Instrument) — the signature public screen.
   Warren as a self-owned "parallel internet": a node-network figure whose
   active electric-blue route reroutes around a struck-out blocked node.
   NOT a VPN — no shields/locks/globe. Reuses .eyebrow + .cta + tokens. Namespaced
   (.landing-hero / .net-fig / .net / .pillar) so nothing collides.
   ========================================================================== */

/* two-column hero: text + framed node-network figure */
.landing-hero {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(1.5rem, 4vw, 2.6rem);
  align-items: center;
}
@media (min-width: 920px) {
  .landing-hero { grid-template-columns: 1.02fr 1.04fr; }
}

.landing-hero .eyebrow { margin-bottom: 1rem; }

.landing-hero__h1 {
  /* bold tight hero — mockup --step-4 */
  font-size: clamp(2.5rem, 1.65rem + 3.7vw, 4.6rem);
  font-weight: 760;
  letter-spacing: -.035em;
  line-height: 1.06;
  max-width: 15ch;
  overflow-wrap: break-word;
  text-wrap: balance;
}
@media (max-width: 480px) {
  .landing-hero__h1 { font-size: clamp(1.9rem, 7.4vw, 2.5rem); }
}
/* accent phrase — the electric-blue second part of the heading (mockup) */
.landing-hero__h1 .accent-word { color: var(--accent); }

.landing-hero__sub {
  margin-top: 1.1rem;
  color: var(--text-muted);
  font-size: var(--step-1);
  line-height: 1.5;
  max-width: 52ch;
  font-weight: 450;
}

.landing-hero__access {
  margin-top: 1.4rem;
  font-size: var(--step-0);
  max-width: 52ch;
  display: flex;
  gap: .55rem;
  align-items: baseline;
  flex-wrap: wrap;
}
.landing-hero__coord {
  color: var(--accent);
  font-family: var(--mono);
  font-size: var(--step--2);
}

.landing-hero__cta { display: flex; gap: .7rem; flex-wrap: wrap; margin-top: 1.4rem; }
/* the hero CTA is a real link-button — cancel the default .cta top-margin */
.landing-hero__cta .cta { margin-top: 0; padding: .72rem 1.15rem; }

.landing-hero__privacy {
  margin-top: 1.6rem;
  padding-top: 1.1rem;
  border-top: 1px solid var(--border);
  font-family: var(--mono);
  font-size: var(--step--1);
  line-height: 1.6;
  color: var(--text-muted);
  max-width: 60ch;
}

/* --- the node-network figure (signature) — framed plot on a grid substrate -- */
.net-fig {
  margin: 0;
  border: 1.5px solid var(--border-strong);
  border-radius: 10px;
  background:
    linear-gradient(var(--grid) 1px, transparent 1px) 0 0 / 26px 26px,
    linear-gradient(90deg, var(--grid) 1px, transparent 1px) 0 0 / 26px 26px,
    var(--surface);
  padding: .95rem;
  position: relative;
}
.net-fig__head {
  display: flex;
  align-items: center;
  gap: .6rem;
  flex-wrap: wrap;
  font-family: var(--mono);
  font-size: var(--step--2);
  letter-spacing: .04em;
  color: var(--text-muted);
  padding: 0 .3rem .55rem;
}
.net-fig__id { color: var(--accent); font-weight: 600; }
.net-fig__t { text-transform: uppercase; }
.net-fig__live {
  color: var(--ok-fg);
  display: inline-flex;
  align-items: center;
  gap: .4em;
}
.net-fig__d { width: .5em; height: .5em; border-radius: 50%; background: currentColor; }
/* figure dimension readout — pushed to the far right (mockup: 440×340) */
.net-fig__dim { margin-left: auto; color: var(--text-muted); }
.net-fig svg { width: 100%; height: auto; }
.net-fig svg text { font-family: var(--mono); }

.net-fig__legend {
  list-style: none;
  margin: .7rem 0 0;
  padding: .6rem .3rem 0;
  border-top: 1px solid var(--border);
  display: flex;
  gap: 1.1rem;
  flex-wrap: wrap;
  font-family: var(--mono);
  font-size: var(--step--2);
  color: var(--text-muted);
}
.net-fig__legend li { display: inline-flex; align-items: center; gap: .45rem; }
.net-lg { width: 16px; height: 0; border-top-width: 2px; border-top-style: solid; display: inline-block; }
.net-lg--route { border-top-color: var(--accent); border-top-width: 2.6px; }
.net-lg--reserve { border-top-color: var(--net-idle); }
.net-lg--dead { border-top-style: dashed; border-top-color: var(--danger-fg); }

/* --- SVG network classes — bold hero route on the plot --- */
.net .net__edge  { fill: none; stroke: var(--net-line); stroke-width: 1.4; }
.net .net__dead  { fill: none; stroke: var(--danger-fg); stroke-width: 1.6; stroke-dasharray: 4 4; opacity: .8; }
.net .net__route { fill: none; stroke: var(--accent); stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; }
.net .net__node circle { fill: var(--surface); stroke: var(--net-dot); stroke-width: 1.5; }
.net .net__core { fill: var(--accent); stroke: none; }
.net .net__node--on circle { stroke: var(--accent); }
.net .net__block circle { fill: var(--surface); stroke: var(--danger-fg); stroke-width: 1.7; }
.net .net__block line { stroke: var(--danger-fg); stroke-width: 1.7; stroke-linecap: round; }
.net .net__lbl { fill: var(--text-muted); font-size: 11px; letter-spacing: .02em; }
.net .net__lbl--on { fill: var(--accent); }
.net .net__lbl--block { fill: var(--danger-fg); font-size: 10px; }
.net .net__coord { fill: var(--text-muted); font-size: 8.5px; letter-spacing: .02em; }
.net .net__axis { stroke: var(--border-strong); stroke-width: 1; }
.net .net__axis-lbl { fill: var(--text-muted); font-size: 8.5px; }

/* draw-in animation — gated behind reduced-motion (→ static rerouted state) */
.net .net__edge, .net .net__dead, .net .net__route { stroke-dasharray: 1; stroke-dashoffset: 1; }
.net .net__edge  { animation: net-draw .8s ease forwards; }
.net .net__dead  { animation: net-draw .6s ease forwards .55s; }
.net .net__route { animation: net-draw 1.25s ease forwards .55s; }
.net .net__e1 { animation-delay: .05s } .net .net__e2 { animation-delay: .12s }
.net .net__e3 { animation-delay: .19s } .net .net__e4 { animation-delay: .26s }
.net .net__e5 { animation-delay: .33s } .net .net__e6 { animation-delay: .4s }
.net .net__e7 { animation-delay: .47s } .net .net__e8 { animation-delay: .54s }
.net .net__node, .net .net__block, .net .net__labels { opacity: 0; animation: net-fade .5s ease forwards .9s; }
@keyframes net-draw { to { stroke-dashoffset: 0; } }
@keyframes net-fade { to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .net .net__edge, .net .net__dead, .net .net__route { stroke-dashoffset: 0; animation: none; }
  .net .net__node, .net .net__block, .net .net__labels { opacity: 1; animation: none; }
}

/* --- corner registration marks (Instrument framing) — ported from the mockup.
   Eight layered linear-gradients paint L-brackets in each corner of any boxed
   element (`.marks` on a `.pillar`, card, empty-state, …). Tunable via the
   local custom props: --mkl length, --mkt thickness, --mko inset offset,
   --mkc colour. `.marks--accent` recolours the brackets electric-blue. --- */
.marks {
  --mkl: 9px; --mkt: 1.5px; --mko: 7px; --mkc: var(--border-strong);
  background-image:
    linear-gradient(var(--mkc), var(--mkc)), linear-gradient(var(--mkc), var(--mkc)),
    linear-gradient(var(--mkc), var(--mkc)), linear-gradient(var(--mkc), var(--mkc)),
    linear-gradient(var(--mkc), var(--mkc)), linear-gradient(var(--mkc), var(--mkc)),
    linear-gradient(var(--mkc), var(--mkc)), linear-gradient(var(--mkc), var(--mkc));
  background-repeat: no-repeat;
  background-size:
    var(--mkl) var(--mkt), var(--mkt) var(--mkl),
    var(--mkl) var(--mkt), var(--mkt) var(--mkl),
    var(--mkl) var(--mkt), var(--mkt) var(--mkl),
    var(--mkl) var(--mkt), var(--mkt) var(--mkl);
  background-position:
    left var(--mko) top var(--mko),     left var(--mko) top var(--mko),
    right var(--mko) top var(--mko),    right var(--mko) top var(--mko),
    left var(--mko) bottom var(--mko),  left var(--mko) bottom var(--mko),
    right var(--mko) bottom var(--mko), right var(--mko) bottom var(--mko);
}
.marks--accent { --mkc: var(--accent); }

/* --- pillar triad — three nodes, not a sequence --- */
.pillars {
  display: grid;
  gap: 1rem;
  margin-top: clamp(1.6rem, 4vw, 2.6rem);
}
@media (min-width: 720px) {
  .pillars { grid-template-columns: repeat(3, 1fr); }
}
.pillar {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  /* background-color (not the shorthand) so a co-classed `.marks` corner-bracket
     background-image is NOT reset — the L-brackets paint over this surface. */
  background-color: var(--surface);
  padding: 1.15rem 1.15rem 1.25rem;
  border-top: 2px solid var(--accent-line, var(--border-strong));
  --mko: 8px;                        /* corner-marks inset for `.pillar.marks` */
}
.pillar__id {
  margin: 0 0 .85rem;
  font-family: var(--mono);
  font-size: var(--step--2);
  color: var(--text-muted);
  letter-spacing: .03em;
  display: flex;
  align-items: center;
  gap: .5rem;
}
.pillar__k { color: var(--accent); }
.pillar h3 { font-size: var(--step-1); margin: 0 0 .4rem; letter-spacing: -.02em; }
.pillar p { margin: 0; color: var(--text-muted); font-size: var(--step-0); }

/* ============================================================================
   §02 Login + §03 Devices (Instrument) — ported from the mockup. These two
   inner screens share the mockup's component vocabulary: the `.btn` link/action
   buttons, the `.card--auth` login panel with its `.readout` + `.field`s, the
   two-column `.auth-wrap`, the `.page__head` / `.subsec` section scaffolding,
   the instrument `.chip`s, `.cell-main`/`.cell-sub` table cells, status
   `.badge--ok/--flag` and the `.switch` toggle. All namespaced; tokens only;
   reuses the shared `.screen-tag` / `.eyebrow` / `.alert` / `.empty` above.
   ========================================================================== */

/* --- mockup button system (.btn) — layered so it wins over the base
   `button`/`.cta` element rules on these two screens. accent primary, ghost
   outline, danger outline; --sm compact; --block full-width. --------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  font-family: var(--sans);
  font-weight: 600;
  font-size: var(--step-0);
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  padding: .72rem 1.15rem;
  border-radius: var(--radius);
  border: 1px solid transparent;
  background: transparent;
  color: var(--text);
  transition: background-color .15s, border-color .15s, color .15s, transform .06s;
}
.btn:hover { text-decoration: none; }
.btn:active { transform: translateY(1px); }
.btn--primary { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.btn--primary:hover { background: var(--accent-strong); border-color: var(--accent-strong); color: var(--accent-ink); }
.btn--ghost { background: transparent; color: var(--text); border-color: var(--border-strong); }
.btn--ghost:hover { background: var(--surface-2); border-color: var(--accent); color: var(--text); }
.btn--danger { background: transparent; color: var(--danger-fg); border-color: var(--danger-bd); }
.btn--danger:hover { background: var(--danger-bg); border-color: var(--danger-fg); color: var(--danger-fg); }
.btn--sm { padding: .42rem .7rem; font-size: var(--step--1); }
.btn--block { width: 100%; }

/* --- mono instrument readout: "● AUTH · /portal/login" (card header cue) --- */
.readout {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin: 0 0 .9rem;
  font-family: var(--mono);
  font-size: var(--step--2);
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.readout__dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-tint);
}
.readout .k { color: var(--accent); }

/* --- login: two-column aside + auth card ----------------------------------- */
.auth-wrap {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(1.4rem, 4vw, 3rem);
  align-items: center;
  padding-block: 1rem;
}
@media (min-width: 860px) {
  .auth-wrap { grid-template-columns: .9fr 1.1fr; }
}
.auth-aside .eyebrow { margin-bottom: .7rem; }
.auth-aside h2 { font-size: var(--step-2); letter-spacing: -.03em; margin: 0 0 .6rem; max-width: 20ch; }
.auth-aside p { color: var(--text-muted); max-width: 36ch; }
/* compact node-network figure in the aside — reuses the landing `.net` classes
   on a gridded plot substrate (matches the landing `.net-fig` language). */
.mini-fig {
  margin: 1.5rem 0 0;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background:
    linear-gradient(var(--grid) 1px, transparent 1px) 0 0 / 24px 24px,
    linear-gradient(90deg, var(--grid) 1px, transparent 1px) 0 0 / 24px 24px,
    var(--surface);
  padding: .9rem;
  max-width: 26rem;
}
.mini-fig .net-fig__head { padding: 0 .3rem .4rem; }
.mini-fig svg { width: 100%; height: auto; }
.mini-fig svg text { font-family: var(--mono); }

.card--auth {
  width: min(430px, 100%);
  padding: clamp(1.4rem, 4vw, 2rem);
  justify-self: start;
}
.card--auth .card__h { font-size: var(--step-2); margin: 0 0 .2rem; letter-spacing: -.02em; }
.card__sub {
  font-family: var(--mono);
  font-size: var(--step--2);
  color: var(--text-muted);
  letter-spacing: .05em;
  margin: 0 0 1.1rem;
}

/* form field — label + full-width input + optional mono hint (login card). */
.field { margin-bottom: 1rem; }
.field label {
  display: block;
  font-size: var(--step--1);
  font-weight: 600;
  margin-bottom: .35rem;
}
/* :not() lifts specificity above the base `form input[type=…]` 360px cap —
   without it text/password inputs stayed 360 while the sibling select and
   the block button ran the full card width (ragged column on invite).
   Checkboxes/radios stay excluded: they must keep their inline layout. */
.field input:not([type="checkbox"], [type="radio"]) {
  width: 100%;
  max-width: none;                 /* override the 360px form cap on this card */
  margin: 0;
  padding: .65rem .75rem;
  font: inherit;
  font-size: var(--step-0);
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  transition: border-color .15s, box-shadow .15s, background-color .15s;
}
.field input::placeholder { color: var(--text-muted); }
.field input:focus-visible {
  background: var(--surface);
  border-color: var(--accent);
  outline: none;
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--accent) 22%, transparent);
}
.field .spinner { margin-left: .5rem; }
.hint {
  font-family: var(--mono);
  font-size: var(--step--2);
  color: var(--text-muted);
  margin: .55rem 0 0;
  line-height: 1.55;
}
/* A hint that INTRODUCES its control (label → hint → control) needs air
   below itself too — flush against the select it read as one cramped blob. */
.field label + .hint { margin: .15rem 0 .6rem; }
.muted-note { color: var(--text-muted); font-size: var(--step--1); }
form + .muted-note { margin-top: 1rem; display: block; text-align: center; }
/* …but the my-servers empty note is a plain left-aligned status line, not a
   centered post-form banner (it happens to follow the toggle form). */
.my-servers > .muted-note { text-align: left; margin: .2rem 0 1rem; }

/* --- devices/servers: page head + sub-section scaffolding ------------------ */
.page__head {
  display: flex;
  align-items: flex-end;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.2rem;
}
.page__head .peb { display: flex; }
.page__head h1 { font-size: var(--step-2); margin: .35rem 0 0; }
.page__head .spacer,
.subsec__head .spacer { flex: 1; }

.subsec { margin-top: clamp(1.6rem, 4vw, 2.4rem); }
.subsec__head {
  display: flex;
  align-items: flex-end;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}
.subsec__head .peb { display: flex; }
.subsec__head h2 { font-size: var(--step-1); margin: .3rem 0 0; }
.subsec__foot {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: 1rem;
}
.subsec__foot .btn { margin-top: 0; }
.subsec__foot .muted-note { margin: 0; }
/* the section-level table border-top registration line, like the landing cards */
.table-wrap > table { border-top: 2px solid var(--accent-line, var(--border-strong)); }
/* Actually scroll-safe (2026-07-04): the wrap CLAIMED scroll-safety but had no
   overflow rule — on phones tables were CLIPPED and row actions unreachable.
   min-width keeps cells readable; the wrap pans horizontally under the finger. */
.table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.table-wrap > table { min-width: 640px; }

/* stacked device-name cell — bold name over a mono sub-id. */
.cell-main { font-weight: 600; color: var(--text); }
/* mono ids never shatter char-by-char — one line, ellipsis (full id in title/scroll) */
.cell-main.mono {
  max-width: 26ch;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cell-sub {
  font-family: var(--mono);
  font-size: var(--step--2);
  color: var(--text-muted);
  margin-top: .15rem;
}
/* table action cluster (mockup uses `.actions`; base has `.row-actions`). */
.actions {
  display: flex;
  gap: .4rem;
  flex-wrap: wrap;
  align-items: center;
}
.actions .btn { margin-top: 0; }

/* Per-row «⋯» menu (fleet actions) — Alpine island. The panel is
   position:fixed because every ancestor clips overflow (table + .shell);
   the toggle computes top/left inline at open time. */
[x-cloak] { display: none !important; }
.rowmenu { display: inline-flex; }
.rowmenu__toggle { min-width: 2.1rem; font-weight: 700; }
.rowmenu__panel {
  position: fixed;
  z-index: 60;
  min-width: 180px;
  padding: .3rem;
  display: flex;
  flex-direction: column;
  gap: .1rem;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: 0 8px 24px rgb(0 0 0 / .18);
}
.rowmenu__item {
  display: block;
  width: 100%;
  text-align: left;
  padding: .45rem .6rem;
  border: 0;
  border-radius: calc(var(--radius) - 2px);
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: var(--step--1);
  cursor: pointer;
}
.rowmenu__item:hover { background: var(--surface-2); }
.rowmenu__item--danger { color: var(--danger-fg); margin-top: .15rem; }
.rowmenu__item--danger::before {
  content: "";
  display: block;
  border-top: 1px solid var(--border);
  margin: -.45rem -.6rem .45rem;
}
.rowmenu__item--danger:hover { background: var(--danger-bg); }

/* ===== Status page (§05) — full-width panels + the 30-day uptime bars.
   A cell = one UTC day; fill state derives from resource_rollup_hourly
   reporting coverage (empty cell = no data that day). */
.status-panel { margin-top: 1rem; padding: 1rem 1.1rem; }
.status-panel > .scard__label { margin-bottom: .8rem; }
.upline {
  display: flex;
  align-items: center;
  gap: .8rem;
  padding: .35rem 0;
}
.upline__name {
  flex: none;
  min-width: 9rem;
  font-weight: 600;
  font-size: var(--step--1);
}
.upbar { display: flex; gap: 2px; flex: 1 1 auto; min-width: 0; }
.upbar__cell {
  flex: 1 1 0;
  max-width: 10px;
  height: 18px;
  border-radius: 2px;
  background: var(--surface-2);
}
.upbar__cell--ok { background: var(--ok-fg); }
.upbar__cell--warn { background: var(--warn-fg); }
.upbar__cell--danger { background: var(--danger); }
.upline__pct {
  flex: none;
  min-width: 4.5rem;
  text-align: right;
  font-size: var(--step--1);
  color: var(--text-muted);
}
/* Narrow screens: name+pct on the first row, the 30-day strip gets the FULL
   width below — inline the strip collapsed to sub-pixel cells on phones. */
@media (max-width: 640px) {
  .upline { flex-wrap: wrap; row-gap: .3rem; }
  .upline__name { flex: 1 1 auto; min-width: 0; }
  .upline__pct { order: 2; }
  .upbar { order: 3; flex-basis: 100%; }
}
/* ===== Admin · Flags (ADR-0019 toggle surface) — readability pass ===== */
.flags-lede { margin: -.4rem 0 1rem; max-width: 60ch; }
.flag-list { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }
.flag-card { display: flex; flex-direction: column; padding: 1.1rem 1.2rem; }
.flag-card__head { display: flex; align-items: baseline; gap: .6rem; flex-wrap: wrap; }
.flag-card__name { font-size: var(--step-1); margin: 0; }
.flag-card__key { font-size: var(--step--2); color: var(--text-muted); overflow-wrap: anywhere; }
.flag-card__desc { margin: .4rem 0 .9rem; font-size: var(--step--1); color: var(--text-muted); }
/* State line — the primary affordance */
.flag-state { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
.flag-state .spacer { flex: 1 1 auto; }
.flag-state__badge { display: inline-flex; align-items: center; gap: .35rem; font-weight: 600; font-size: var(--step--1); }
.flag-state__badge--on { color: var(--ok-fg); }
.flag-state__badge--off { color: var(--text-muted); }
.flag-state__src { font-size: var(--step--2); color: var(--text-muted); }
/* Demoted technical meta */
.flag-meta {
  display: grid; grid-template-columns: auto 1fr; gap: .2rem .8rem;
  margin: .9rem 0 0; padding-top: .8rem; border-top: 1px solid var(--border);
  font-size: var(--step--2);
}
.flag-meta > div { display: contents; }
.flag-meta dt { color: var(--text-muted); }
.flag-meta dd { margin: 0; color: var(--text); }
.flag-scoped { margin-top: .9rem; }
.flag-scoped summary { cursor: pointer; font-size: var(--step--1); color: var(--accent); }
.flag-scoped__row { display: flex; gap: .4rem; flex-wrap: wrap; align-items: center; margin-top: .5rem; }
.flag-scoped__row input[type="text"] { flex: 1 1 9rem; min-width: 0; width: auto; }
.flag-scoped__row select { width: auto; }
.flags-log { margin-top: 1rem; }

/* ===== Dashboard: clickable summary cards + expandable audit rows ===== */
.scard--link { text-decoration: none; color: inherit; transition: border-color .12s, transform .12s; }
.scard--link:hover { border-color: var(--accent); text-decoration: none; color: inherit; }
.scard--link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.scard__more { margin-left: auto; font-size: var(--step--2); color: var(--accent); font-family: var(--sans); text-transform: none; letter-spacing: 0; }
.scard__label { display: flex; align-items: baseline; gap: .4rem; }

/* Dashboard audit-card rows: the event name links its event page. */
.auditlog a.op:hover { text-decoration: underline; }

/* Audit event detail page */
.audit-detail { padding: 1.1rem 1.2rem; margin-bottom: 1rem; }
.audit-detail__grid, .audit-detail__raw {
  display: grid; grid-template-columns: minmax(8rem, auto) 1fr; gap: .4rem .9rem; margin: 0;
}
.audit-detail__raw { margin-top: .6rem; font-size: var(--step--1); }
.audit-detail dt { color: var(--text-muted); }
.audit-detail dd { margin: 0; overflow-wrap: anywhere; }

/* ===== Admin · Settings — named + described + grouped ===== */
/* Settings (dense-row rework, operator 2026-07-06): the card spans the full
   shell width and each setting is ONE grid row — identity (name over
   key · description) | inline control + quiet Save | right-aligned mono meta.
   Under 960px the grid stacks back to the single-column block flow. */
.settings-card.card--form { width: 100%; }
/* Section divider = the signature eyebrow band (operator 2026-07-06: the
   muted caps line blended into the rows): accent leading rule + accent mono
   caps + a hairline stretching to the card edge, with clear air above. */
.settings-section {
  display: flex; align-items: center; gap: .55rem;
  font-family: var(--mono); font-size: var(--step--1); font-weight: 700;
  text-transform: uppercase; letter-spacing: .14em; color: var(--accent);
  margin: 2.6rem 0 .5rem; padding: 0; border-bottom: 0;
}
.settings-section::before {
  content: ""; flex: none; width: 1.7em; border-top: 3px solid currentColor;
}
.settings-section::after {
  content: ""; flex: 1; border-top: 1px solid var(--border-strong);
}
.settings-section:first-of-type { margin-top: 1.2rem; }
.settings-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(14rem, 22rem);
  gap: .2rem 1.4rem;
  align-items: center;
  padding: .55rem 0;
  border-bottom: 1px solid var(--border);
}
.settings-row:last-of-type { border-bottom: 0; }
.settings-row__id { min-width: 0; }
.settings-name { display: block; font-weight: 600; font-size: var(--step--1); color: var(--text); }
.settings-sub { margin: .15rem 0 0; font-size: var(--step--2); color: var(--text-muted); }
.settings-key {
  font-family: var(--mono); color: var(--text-muted);
  background: var(--surface-2); border-radius: 4px; padding: .02rem .3rem;
  overflow-wrap: anywhere;
}
.settings-desc { color: var(--text-muted); }
.settings-row.row-error .settings-name { color: var(--danger-fg); }

/* Event-feed severity words — outrank the generic `.auditlog .op` accent. */
.auditlog .op.health-unhealthy { color: var(--danger-fg); }
.auditlog .op.health-degraded { color: var(--warn-fg); }

/* instrument chip — mono pill for protocol / host-class tags. */
.chip {
  display: inline-flex;
  align-items: center;
  font-family: var(--mono);
  font-size: var(--step--2);
  letter-spacing: .02em;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: .12rem .4rem;
  /* A chip is one token — never break it mid-word ("realit/y"). */
  white-space: nowrap;
}

/* status/flag badges — extend the base `.badge` with semantic tints + a dot.
   `.badge--ok` = active-green, `.badge--flag` = uppercase UNSAFE. Base already
   ships `.badge` + `.unsafe`; these add the mockup's dot + ok variant. */
.badge .d { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.badge--ok { color: var(--ok-fg); background: var(--ok-bg); border-color: var(--ok-bd); }
.badge--warn { color: var(--warn-fg); background: var(--warn-bg); border-color: var(--warn-bd); }
.badge--danger { color: var(--danger-fg); background: var(--danger-bg); border-color: var(--danger-bd); }
.badge--flag { text-transform: uppercase; }

/* accessible toggle switch — the shared-pool control (mockup `.switch`). The
   ВКЛ/ВЫКЛ state word is emitted by CSS; its localized strings arrive as
   --switch-on / --switch-off custom properties (set inline on the label), so
   the label flips with the checkbox and stays translatable. */
.switch {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  cursor: pointer;
  /* no auto-margin: the toggle lives on its own left-aligned row now (the
     old margin-left:auto right-shoved it when it sat in the section head). */
}
.switch input {
  position: absolute;
  opacity: 0;
  width: 1px; height: 1px;
  margin: 0;
}
.switch__track {
  width: 42px; height: 23px;
  border-radius: 99px;
  background: var(--surface-3);
  border: 1px solid var(--border-strong);
  position: relative;
  transition: background-color .15s, border-color .15s;
  flex: none;
}
.switch__thumb {
  position: absolute;
  top: 2px; left: 2px;
  width: 17px; height: 17px;
  border-radius: 50%;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  transition: transform .15s;
}
.switch:has(input:checked) .switch__track { background: var(--accent); border-color: var(--accent); }
.switch:has(input:checked) .switch__thumb { transform: translateX(19px); border-color: var(--accent-strong); }
.switch input:focus-visible + .switch__track { outline: 2px solid var(--focus); outline-offset: 2px; }
.switch__label { font-size: var(--step--1); font-weight: 400; }
.switch__state {
  font-family: var(--mono);
  font-size: var(--step--2);
  color: var(--text-muted);
  letter-spacing: .06em;
}
.switch:has(input:checked) .switch__state::after { content: var(--switch-on, "ON"); }
.switch:has(input:not(:checked)) .switch__state::after { content: var(--switch-off, "OFF"); }

/* ============================================================================
   Onboarding / wizard / config screens (Instrument) — extends the login-card
   `.field` + `.card` + `.btn` + `.readout` vocabulary to the five customer
   forms: invite redeem, device wizard, device-create result partial,
   self-service add-server, and the customer safe-subset config. All namespaced
   / token-only / light+dark / AA. No new fonts, colours, or CDN assets.
   ========================================================================== */

/* --- page head for a single-card form screen (eyebrow + heading) ----------- */
.form-head { margin: 0 0 1.2rem; }
.form-head .eyebrow { margin-bottom: .55rem; }
.form-head h1 { font-size: var(--step-2); margin: .3rem 0 0; letter-spacing: -.02em; }
.form-head p { color: var(--text-muted); max-width: 56ch; margin: .5rem 0 0; }

/* form card — a `.card` that carries the login-card's top registration line and
   a comfortable max width so a lone form column reads like the auth card. */
.card--form {
  border-top: 2px solid var(--accent-line, var(--border-strong));
  width: min(560px, 100%);
  padding: clamp(1.4rem, 4vw, 2rem);
}
.card--form .card__h { font-size: var(--step-1); margin: 0 0 .2rem; letter-spacing: -.02em; }

/* `.field` extended beyond the login card's text inputs: selects + textareas
   share the input treatment; the leading form rules cap them at 360/480px, so
   re-assert full width inside a field. */
.field select,
.field textarea {
  width: 100%;
  max-width: none;
  margin: 0;
  padding: .65rem .75rem;
  font: inherit;
  font-size: var(--step-0);
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  transition: border-color .15s, box-shadow .15s, background-color .15s;
}
.field textarea { font-family: var(--mono); resize: vertical; }
.field select:focus-visible,
.field textarea:focus-visible {
  background: var(--surface);
  border-color: var(--accent);
  outline: none;
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--accent) 22%, transparent);
}
/* Custom select chevron — the native arrow is tiny and hugs the edge.
   Longhands only (the earlier `background:` shorthands stay in charge of the
   fill); the muted-grey stroke reads on both themes. Listed with BOTH
   selectors so the (0,1,1) `.field select` shorthand cannot wipe the image. */
form select,
.field select {
  appearance: none;
  padding-right: 2.4rem;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5l5 5 5-5' stroke='%2398A2B3' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right .85rem center;
}
/* checkbox row inside a field — inline control + its label, not block-stacked */
.field--check { display: flex; align-items: flex-start; gap: .55rem; }
.field--check input[type="checkbox"] {
  width: auto;
  margin: .15rem 0 0;
  accent-color: var(--accent);
  flex: none;
}
.field--check .field__text { font-size: var(--step--1); font-weight: 400; color: var(--text); }

/* --- segmented option list (protocol choice, checkbox groups) — a stacked set
   of selectable rows; the selected radio highlights its row with the accent. */
.opt-set { display: grid; gap: .55rem; margin: 0; }
.opt {
  display: flex;
  align-items: flex-start;
  gap: .6rem;
  padding: .7rem .8rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface-2);
  cursor: pointer;
  transition: border-color .15s, background-color .15s;
}
.opt:hover { border-color: var(--accent); }
.opt input { width: auto; margin: .2rem 0 0; accent-color: var(--accent); flex: none; }
.opt__text { font-size: var(--step--1); font-weight: 500; color: var(--text); }
.opt:has(input:checked) {
  border-color: var(--accent);
  background: var(--accent-tint);
}
.opt:has(input:focus-visible) { outline: 2px solid var(--focus); outline-offset: 2px; }

/* --- readout instrument sub-block (issue/expiry meta, protocol · id) -------- */
.readout-meta {
  display: flex;
  flex-wrap: wrap;
  gap: .3rem 1rem;
  margin: 0 0 1rem;
  font-family: var(--mono);
  font-size: var(--step--2);
  letter-spacing: .03em;
  color: var(--text-muted);
}
.readout-meta .k { color: var(--accent); }
.readout-meta strong { color: var(--text); font-weight: 600; }

/* --- device-create result partial (QR · config · copy · downloads · apps) --- */
.result-card { width: min(560px, 100%); }
.result-card .readout { margin-bottom: .9rem; }
.qr-block {
  margin: 1rem 0;
  padding: 1rem;
  display: flex;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background:
    linear-gradient(var(--grid) 1px, transparent 1px) 0 0 / 24px 24px,
    linear-gradient(90deg, var(--grid) 1px, transparent 1px) 0 0 / 24px 24px,
    var(--surface);
}
.qr-block img {
  display: block;
  width: 200px; height: 200px;
  image-rendering: pixelated;
  background: #fff;
  padding: 8px;
  border-radius: 4px;
}
/* copy-row: a mono URI readout + its copy button (VLESS / value). */
.copy-row {
  display: flex;
  align-items: stretch;
  gap: .5rem;
  margin: .5rem 0 0;
}
.copy-row code {
  flex: 1 1 auto;
  min-width: 0;
  overflow-x: auto;
  white-space: nowrap;
  padding: .55rem .65rem;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  font-size: var(--step--1);
}
.config-block { margin: 1rem 0 0; }
.config-block > summary {
  cursor: pointer;
  font-family: var(--mono);
  font-size: var(--step--1);
  color: var(--text-muted);
  letter-spacing: .03em;
}
.config-block > summary:hover { color: var(--text); }
.config-block pre {
  margin: .6rem 0 0;
  padding: .8rem;
  overflow-x: auto;
  font-family: var(--mono);
  font-size: var(--step--2);
  line-height: 1.5;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
/* download + back action row */
.result-actions { display: flex; flex-wrap: wrap; gap: .5rem; margin: 1rem 0 0; align-items: center; }

/* client app-store links block — mono list, hairline framed. */
.app-links { margin: 1.2rem 0 0; }
.app-links > summary {
  cursor: pointer;
  font-family: var(--mono);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: .03em;
  color: var(--text);
}
.app-links > summary:hover { color: var(--accent); }
.app-links ul {
  list-style: none;
  margin: .7rem 0 0;
  padding: .8rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-2);
  font-size: var(--step--1);
}
.app-links ul li { padding: .18rem 0; }
.app-links p { color: var(--text-muted); font-size: var(--step--1); }

/* ============================================================================
   §04 Admin console — table/list screens (versions · pins · channels · audit ·
   soaks) rebuilt to the Instrument look. Reuses the shared vocabulary above
   (`.screen-tag`, `.eyebrow`, `.page__head`, `.card`, `.table-wrap`, `.btn`,
   `.chip`, `.status-*`, `.filter-bar`, `.inline-form`, `.pagination`). Only two
   genuinely-new pieces below: the Channels tag list and the Pins "new pin"
   `<details>` panel. Namespaced / token-only / light+dark. No new CDN/fonts. */

/* Channels — three maturity columns as instrument `.card`s. A mono tag list;
   each row is one candidate version + its dwell-time note. */
.channel-list {
  list-style: none;
  margin: .7rem 0 0;
  padding: 0;
  display: grid;
  gap: .4rem;
}
.channel-list li {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  font-size: var(--step--1);
}
.channel-list li small { color: var(--text-muted); font-family: var(--mono); font-size: var(--step--2); }

/* Pins — the "new pin" disclosure is a `.card.card--form` used as a `<details>`.
   Its `<summary>` is the mono instrument affordance; the form fields inside
   reuse the login/wizard `.field` vocabulary. */
.pins-new { margin: 0 0 1rem; }
.pins-new > summary {
  cursor: pointer;
  list-style: none;
  font-family: var(--mono);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: .03em;
  color: var(--text);
}
.pins-new > summary::-webkit-details-marker { display: none; }
.pins-new > summary::before { content: "+ "; color: var(--accent); }
.pins-new[open] > summary::before { content: "− "; }
.pins-new > summary:hover { color: var(--accent); }
.pins-new[open] > summary { margin-bottom: 1rem; }

/* Settings — the runtime-override editor rebuilt as instrument `.field` rows
   inside a `.card--form`. Each row is: a mono key label, an inline edit form
   (control + Save), then a mono meta line (now / reverts / bounds). Namespaced /
   token-only / light+dark. Reuses `.field` / `.inline-form` / `.hint` above;
   only the per-row divider, the wider control, the meta emphasis and the
   rejected-row accent are new here. */
.settings-card .readout + .settings-help { margin-top: -.4rem; margin-bottom: 1.2rem; }
.settings-row .settings-form { margin: 0; align-items: center; flex-wrap: nowrap; }
.settings-row .settings-form input,
.settings-row .settings-form select {
  min-width: 9rem; max-width: 14rem; font-family: var(--mono);
}
.settings-row .settings-meta {
  margin: 0; font-size: var(--step--2);
  justify-self: end; text-align: right;
}
.settings-row .settings-meta .k { color: var(--accent); }
.settings-row .settings-meta .settings-current,
.settings-row .settings-meta .settings-envdefault,
.settings-row .settings-meta .settings-bounds { color: var(--text); }
/* Long values (SHA-256, URLs) ellipsize; the full value is in title= and the
   control itself. */
.settings-row .settings-meta .settings-current,
.settings-row .settings-meta .settings-envdefault {
  display: inline-block; max-width: 22ch;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  vertical-align: bottom;
}
.settings-row.row-error {
  border-left: 3px solid var(--danger-fg);
  border-bottom-color: var(--danger-bd);
  padding-left: .7rem;
  margin-left: -.7rem;
  background: var(--danger-bg);
  border-radius: var(--radius);
}
@media (max-width: 960px) {
  .settings-row { grid-template-columns: minmax(0, 1fr); gap: .35rem; align-items: start; }
  .settings-row .settings-meta { justify-self: start; text-align: left; }
}
.settings-soak-actions { margin-top: 1.4rem; }
.settings-soak-actions .hint { max-width: 60ch; }
.settings-soak-actions .settings-form { margin-top: .6rem; }
