/*
  Aurora Mesh · framed — shared uikit stylesheet (WS-4).

  Transcribed verbatim (token values, radii, layering) from the design
  source of record, docs/webui-split-redesign/design/aurora-mesh-framed.html
  (WS-D-06) — do not "improve" colors/spacing here without a new owner-gated
  design decision. The design source's ".mock" wrapper only existed so the
  artifact could show a floating preview panel inside a fake browser chrome
  (".mock-chrome", ".wrap", ".masthead", ".note" in that file); none of that
  scaffolding is reproduced below. This stylesheet applies the SAME token set
  directly to :root/body instead, because a real uikit page IS the page,
  full-bleed — there is no outer "shell" wrapping it.

  Two token layers existed in the source (an outer "--shell-*" palette for
  the artifact's own preview chrome, and the ".mock"-scoped palette below,
  which is the actual "Aurora Mesh" design-system token set). This file keeps
  ONLY the ".mock" palette (the one PLAN.md/DECISIONS.md name explicitly:
  --bg/--ink/--muted/--accent/--surface/--border/--good/--warn+-soft/
  --grad-a/b/c/--dot/radii/--shadow, plus every other token in that same
  block) and drops the outer --shell-* names entirely — components that read
  design tokens (including .theme-toggle, which in the source read the OUTER
  --shell-* palette because it lived outside .mock) are re-pointed at this
  single merged set. This is a mechanical renaming only: no color/radius
  value was changed, re-derived, or approximated.

  2026-08-16 owner-gated amendment (live-browser UAT of WS-1..WS-8): the
  light --bg token was corrected (see its own comment below — restores a
  contrast step the merge above accidentally dropped, using the source's
  own darker value, not an invented one) and a set of layout/sizing rules
  were added (.field/.field-wide/.field-stack width discipline, .btn-block,
  td.desc/td.edit-cell, the form vertical-rhythm rule) to fix controls that
  rendered structurally correct but visually cramped/oversized/under-
  contrasted once exercised in a real browser rather than only through
  `go test` (which checks markup/behavior, never applied CSS).
*/

:root {
  --font-head: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-body: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: ui-monospace, "SF Mono", Consolas, monospace;
  --r-card: 16px; --r-btn: 11px; --r-input: 11px; --r-pill: 999px; --r-table: 12px;
  /* --bg (page background, light mode) is owner-amended 2026-08-16: the
     design source of record (design/aurora-mesh-framed.html) actually
     defines TWO light backgrounds — an outer "--shell-bg: #eceef3" (the
     artifact's own page chrome, around its floating preview panel) and the
     ".mock"-scoped "--bg: #f4f5fb" (the preview panel's OWN background,
     one step lighter, meant to sit atop --shell-bg). WS-4 merged these two
     layers into one token (this file's header comment) and picked the
     lighter ".mock" value — which, on a real full-bleed page, collapses
     the page background and the --surface (#ffffff) panel background to
     within ~4% luminance of each other: panels stop reading as panels.
     Restoring the source's OWN darker --shell-bg value here (not inventing
     a new color) reinstates the contrast step the merge dropped. Dark mode
     was not affected (its --bg/--shell-bg values were already ~identical
     in the source) and is untouched. */
  --bg: #eceef3; --chrome: #edeef7; --topbar: #ffffff; --surface: #ffffff; --surface-2: #eef0f9;
  --ink: #191b2e; --muted: #63667e; --frame: #e4e5f1; --border: #e7e8f2; --hair: #eef0f7;
  --input: #ffffff; --row-hover: #f6f7fd; --thead: #f3f4fb;
  --accent: #5a4fe0; --accent-ink: #ffffff; --accent-soft: #eae8fd;
  --good: #2a8f6a; --good-soft: #e2f3ec; --warn: #b06a12; --warn-soft: #f8ecd6;
  --dot: #9aa0d8; --grad-a: #4f46e5; --grad-b: #8b5cf6; --grad-c: #4361cf;
  --shadow: 0 22px 55px -30px rgba(30,28,80,.55);
}

:root[data-theme="dark"] {
  --bg: #0b0d19; --chrome: #0e1020; --topbar: #14172b; --surface: #14172b; --surface-2: #1c2038;
  --ink: #e8e9f6; --muted: #969ac0; --frame: #232744; --border: #232744; --hair: #1c2038;
  --input: #101324; --row-hover: #191d34; --thead: #14172a;
  --accent: #8f88ff; --accent-ink: #0a0c1a; --accent-soft: #201f42;
  --good: #4fc691; --good-soft: #12271f; --warn: #dca85a; --warn-soft: #271f12;
  --dot: #3a3f6b; --grad-a: #4f46e5; --grad-b: #7c3aed; --grad-c: #3b4fb0;
  --shadow: 0 24px 60px -30px rgba(0,0,0,.7);
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  line-height: 1.5;
  transition: background .35s ease, color .35s ease;
}

/* Page-content width cap. NOTE (2026-08-16 live-UAT fix): a ".uikit-page"
   rule with this exact max-width existed here from WS-4 onward but was
   NEVER applied by any template (every page div is plain "uikit-body") —
   so real pages rendered completely unconstrained, full-bleed to the
   viewport edge on any desktop monitor wider than ~1080px: every panel,
   form-grid column, and field stretched to match, which is what actually
   produced the "everything is too wide / a 4-field form spans the whole
   screen" defect — not a per-page sizing bug, a missing container. Folded
   the constraint directly into .uikit-body (the class every page actually
   uses) instead of leaving a second, easy-to-forget-to-apply class around.
   1200px (up from the unused rule's 1080px) — this app's own content
   (override/grants tables, multi-field forms) benefits from a bit more
   room than the original narrower artifact-preview measure. */
.uikit-body { max-width: 1200px; margin: 0 auto; padding: 1.4rem 1.5rem 1.75rem; }

/* ===================== topbar / masthead ===================== */
.topbar { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: .85rem 1.25rem; background: var(--topbar); border-bottom: 1px solid var(--border); }
.brand { display: flex; align-items: center; gap: .7rem; }
.brand svg { width: 30px; height: 30px; display: block; }
.brand-txt { display: flex; flex-direction: column; line-height: 1.1; }
.brand-name { font-weight: 680; font-size: .98rem; letter-spacing: -.01em; }
.brand-sub { font-size: .62rem; letter-spacing: .2em; text-transform: uppercase; color: var(--muted); }
.topnav { display: flex; align-items: center; gap: .35rem; }
.topnav a { color: var(--muted); text-decoration: none; font-size: .82rem; font-weight: 500; padding: .35rem .6rem; border-radius: var(--r-btn); }
.topnav a.active { color: var(--ink); background: var(--accent-soft); }
.who { font-size: .74rem; color: var(--muted); display: inline-flex; align-items: center; gap: .4rem; }
.who b { color: var(--ink); font-weight: 600; }
.who .role { font-family: var(--font-mono); font-size: .66rem; color: var(--accent); background: var(--accent-soft); padding: .1rem .4rem; border-radius: var(--r-pill); }
.topnav form.inline { display: inline; margin: 0; }
.topnav button.linklike { font: inherit; font-size: .82rem; font-weight: 500; color: var(--muted); background: transparent; border: 0; cursor: pointer; padding: .35rem .6rem; border-radius: var(--r-btn); }
.topnav button.linklike:hover { color: var(--ink); }

/* ===================== theme toggle (pill buttons) ===================== */
.theme-toggle { display: inline-flex; gap: .1rem; background: var(--surface); border: 1px solid var(--border); border-radius: 999px; padding: 4px; }
.theme-toggle button { font: inherit; font-size: .82rem; font-weight: 600; cursor: pointer; border: 0; background: transparent; color: var(--muted); padding: .4rem .95rem; border-radius: 999px; }
.theme-toggle button[aria-pressed="true"] { background: var(--ink); color: var(--bg); }
.theme-toggle button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---- the framed header (D structure + A dot-grid, composed) ---- */
.page-head {
  position: relative; isolation: isolate; overflow: hidden;
  border: 1px solid var(--border); border-radius: var(--r-card);
  background: var(--surface); padding: 1.35rem 1.4rem 1.4rem; margin: 1.4rem 0;
  display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;
}
/* layer 1 — dot grid, anchored left, masked so it fades before the glow */
.page-head::before {
  content: ""; position: absolute; inset: 0; z-index: -2;
  background-image: radial-gradient(var(--dot) 1.15px, transparent 1.15px);
  background-size: 13px 13px; background-position: -2px -2px; opacity: .55;
  -webkit-mask-image: linear-gradient(100deg, #000 6%, rgba(0,0,0,.35) 34%, transparent 60%);
          mask-image: linear-gradient(100deg, #000 6%, rgba(0,0,0,.35) 34%, transparent 60%);
}
/* layer 2 — contained violet-blue mesh, anchored top-right */
.page-head::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(150px 120px at 92% -18%, var(--grad-b), transparent 68%),
    radial-gradient(200px 150px at 108% 8%, var(--grad-a), transparent 70%),
    radial-gradient(120px 100px at 78% 128%, var(--grad-c), transparent 66%);
  opacity: .20;
}
.head-txt { position: relative; }
.eyebrow { font-size: .66rem; letter-spacing: .2em; text-transform: uppercase; color: var(--accent); font-weight: 700; }
.page-head h1 { font-family: var(--font-head); margin: .35rem 0 .3rem; font-size: 1.55rem; letter-spacing: -.02em; font-weight: 720; color: var(--ink); }
/* signal bar — A's idea, tinted into D's gradient */
.page-head h1::after { content: ""; display: block; width: 44px; height: 3px; margin-top: .5rem; border-radius: 2px; background: linear-gradient(90deg, var(--grad-a), var(--grad-b)); }
.page-head .sub { margin: 0; color: var(--muted); font-size: .85rem; }
.head-cta { margin-left: auto; position: relative; }
/* refined corner tick (kept small so the frame reads clean) */
.head-tick { position: absolute; top: 0; right: 0; width: 20px; height: 20px; z-index: 0; background: var(--accent); opacity: .9; -webkit-clip-path: polygon(100% 0, 0 0, 100% 100%); clip-path: polygon(100% 0, 0 0, 100% 100%); border-top-right-radius: var(--r-card); }

.btn { font: inherit; font-size: .8rem; font-weight: 600; cursor: pointer; border: 1px solid var(--border); background: var(--surface); color: var(--ink); padding: .5rem .9rem; border-radius: var(--r-btn); display: inline-flex; align-items: center; justify-content: center; gap: .4rem; min-width: 6rem; transition: transform .12s ease, filter .12s ease; }
/* Any disabled button (e.g. a row control gated by edit-lock.js while
   locked) reads as genuinely inert, not just an ordinary button that
   happens not to respond — was previously only defined for .btn-danger. */
.btn:disabled { opacity: .5; cursor: not-allowed; transform: none; filter: none; }
.btn:hover { transform: translateY(-1px); }
.btn-primary { background: var(--accent); color: var(--accent-ink); border-color: transparent; }
.btn-primary:hover { filter: brightness(1.06); }
/* Equal-width paired action buttons (e.g. Save credential / Revoke
   credential) — a shared min-width wider than either label alone, so two
   buttons of visibly different text length still read as a matched pair.
   Opt-in per button via class, not global .btn default, since most .btn
   usage (table-row Enable/Disable, compact toolbar actions) wants to stay
   content-sized. */
.btn-block { min-width: 11rem; }
/* Destructive action (Delete service, and the dialog's own confirm
   button) — reuses --warn (this design system has no separate --danger
   token; --warn already reads as the "this needs attention" color and is
   already used for the Delete-service panel's border/heading). */
.btn-danger { background: var(--warn-soft); color: var(--warn); border-color: var(--warn); }
.btn-danger:hover { filter: brightness(1.04); }

/* ===================== toggle switch (binary mode/enable buttons) ===================== */
/* A .switch-btn is still a REAL <button type="submit"> — same semantics,
   same no-JS-safe plain form POST as before — only its visual skin
   changes: it shows CURRENT state (track color + thumb position) rather
   than reading as an arbitrary action label, so a row of unrelated
   Enable/Disable-shaped controls reads as switches, not as a list of
   buttons. .is-on / .is-off is set by the template from the actual
   current state (never inferred from label text). */
.switch-btn { min-width: 0; padding: .3rem .6rem .3rem .5rem; gap: .5rem; }
.switch-track { position: relative; width: 2.35rem; height: 1.3rem; border-radius: var(--r-pill); background: var(--surface-2); border: 1px solid var(--border); flex: none; transition: background .15s ease, border-color .15s ease; }
.switch-thumb { position: absolute; top: 1px; left: 1px; width: 1.05rem; height: 1.05rem; border-radius: 50%; background: var(--surface); box-shadow: 0 1px 2px rgba(0,0,0,.25); transition: transform .15s ease; }
.switch-btn.is-on .switch-track { background: var(--good); border-color: var(--good); }
.switch-btn.is-on .switch-thumb { transform: translateX(1.05rem); background: var(--accent-ink); }
.switch-btn .switch-label { font-size: .78rem; font-weight: 600; color: var(--muted); }
.switch-btn.is-on .switch-label { color: var(--good); }

/* Visually separates two adjacent-but-UNRELATED action groups that would
   otherwise read as one cluster just because they sit in the same panel
   (e.g. a mode-toggle form immediately followed by an unrelated "re-sync
   data" form) — a rule, not just extra margin, so the break is legible at
   a glance. */
.action-divide { margin-top: 1.5rem; padding-top: 1.1rem; border-top: 1px dashed var(--border); }

/* A deliberate exception to this app's default left-aligned single-action
   forms (Publish state, Endpoint, Tool-list mode, credential save/revoke
   all sit flush with their panel's left edge, matching the field/label
   they act on) — reserved for a form that is the ONE terminal, standalone
   action in its panel and should read as visually set apart, not just
   another item in the same left-aligned list (currently: Delete service
   only). Do not reach for this on a routine action form; consistent
   alignment within a group of related actions matters more than any one
   form "looking nice" in isolation. */
.action-center { display: flex; flex-direction: column; align-items: center; text-align: center; }

/* A visually distinct sub-section WITHIN a .panel — e.g. an "add new row"
   form sitting below a table of existing rows in the same panel needs its
   own boundary so it reads as a separate group (Gestalt proximity), not a
   continuation of the table above it. Uses --bg (the page background,
   already a step darker than --surface, see --bg's own comment above) so
   it reads as a shallow recess rather than a second full elevated card. */
.subpanel { border: 1px solid var(--border); border-radius: var(--r-table); background: var(--bg); padding: 1rem 1.1rem; margin-top: 1.25rem; }
.subpanel-head { margin: 0 0 .75rem; font-size: .78rem; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; color: var(--muted); }

/* ===================== confirm dialog (type-to-confirm destructive actions) ===================== */
.confirm-dialog { border: 1px solid var(--border); border-radius: var(--r-card); background: var(--surface); color: var(--ink); padding: 1.3rem 1.4rem; max-width: 28rem; width: calc(100% - 2rem); box-shadow: var(--shadow); }
.confirm-dialog::backdrop { background: rgba(10, 12, 20, .55); }
.confirm-dialog h3 { margin: 0 0 .5rem; font-size: 1.05rem; }
.confirm-dialog p { margin: 0 0 .9rem; color: var(--muted); font-size: .85rem; }
.confirm-dialog .field { max-width: none; margin-bottom: 1rem; }
.dialog-actions { display: flex; justify-content: flex-end; gap: .6rem; }

/* U10 (agent-tool-awareness): the admin support view's catalog dialog needs
   room for a service description/instructions table plus a per-tool table —
   .confirm-dialog's 28rem cap (sized for a short confirm message) is too
   narrow. A sibling class, combined with .confirm-dialog (which still
   supplies border/background/backdrop/heading/paragraph styling) so this
   widens ONLY max-width, per this unit's own scope note — the base class
   itself is untouched. Widened 68rem (owner feedback, live UAT,
   2026-08-25): 48rem still cramped the Description/Instructions column.
   td.desc's own 34rem app-wide cap (used by every OTHER table in this app —
   service overrides, discovered tools, metadata panel) is overridden
   WIDER, scoped to this dialog only, so those other tables are untouched. */
.catalog-dialog { max-width: 68rem; }
.catalog-dialog td.desc { max-width: 48rem; }
/* Owner feedback, live UAT, 2026-08-25: the dialog's two stacked
   .table-scroll blocks (service fields, then per-tool rows) had zero
   spacing between them — their borders touched directly. 8-point-grid
   rhythm (1.1rem, matching .panel's own vertical spacing unit). */
.catalog-dialog .table-scroll + .table-scroll { margin-top: 1.1rem; }

.panel { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-card); padding: 1.1rem 1.2rem; margin-bottom: 1.1rem; }
.panel-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: .85rem; }
.panel-head h3 { margin: 0; font-size: 1rem; font-weight: 660; }
.panel-head .count { font-size: .74rem; color: var(--muted); font-variant-numeric: tabular-nums; }
/* A destructive-action panel (Delete service) needs to draw more attention
   than a routine settings panel — same display typeface the page-level H1
   uses (var(--font-head)), bolder and slightly larger than the default
   panel heading, but still clearly a level below the H1 itself. Replaces
   the old ad-hoc inline style="color:var(--warn)" with one reusable rule. */
.panel-danger { border-color: var(--warn); }
.panel-danger .panel-head h3 { font-family: var(--font-head); font-size: 1.15rem; font-weight: 720; color: var(--warn); }

.table-scroll { overflow-x: auto; border-radius: var(--r-table); border: 1px solid var(--border); }
table { border-collapse: collapse; width: 100%; min-width: 560px; font-size: .82rem; }
thead th { text-align: left; font-weight: 600; font-size: .68rem; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); background: var(--thead); padding: .6rem .8rem; border-bottom: 1px solid var(--border); white-space: nowrap; }
tbody td { padding: .62rem .8rem; border-bottom: 1px solid var(--hair); vertical-align: middle; }
tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover td { background: var(--row-hover); }
td.key { font-family: var(--font-mono); font-size: .78rem; }
td.name { font-weight: 600; }
/* Long free-text table cells (tool descriptions, etc.) wrap instead of
   forcing the column — and every column after it, including Edit — to
   shrink to make room for one unbroken line. */
td.desc { max-width: 34rem; white-space: normal; overflow-wrap: anywhere; }
/* The Edit column carries an inline curation form (.field-stack) — give it
   room to lay out two-plus fields before .table-scroll's horizontal
   scrollbar has to kick in. */
td.edit-cell { min-width: 19rem; }
.manage { color: var(--accent); text-decoration: none; font-weight: 600; font-size: .78rem; }

.pill { display: inline-flex; align-items: center; gap: .35rem; font-size: .7rem; font-weight: 600; padding: .18rem .55rem; border-radius: var(--r-pill); white-space: nowrap; }
.pill::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.pill-good { color: var(--good); background: var(--good-soft); }
.pill-off { color: var(--muted); background: var(--surface-2); }
.chip { display: inline-flex; align-items: center; font-size: .7rem; font-weight: 600; padding: .16rem .5rem; border-radius: var(--r-pill); color: var(--accent); background: var(--accent-soft); }
.chip-plain { color: var(--muted); background: var(--surface-2); font-family: var(--font-mono); font-weight: 500; }
.tag-warn { font-size: .64rem; font-weight: 700; color: var(--warn); background: var(--warn-soft); padding: .1rem .4rem; border-radius: var(--r-pill); margin-left: .35rem; letter-spacing: .02em; text-transform: uppercase; }

.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: .8rem 1rem; }
@media (max-width: 560px) { .form-grid { grid-template-columns: 1fr; } }
/* A standalone .field (one control, its own <form>, not inside .form-grid
   or .field-stack) defaults to a content-appropriate width rather than
   stretching to its panel's full measure — a "Status" <select> or a short
   text input filling an entire panel row reads as a layout bug, not a
   design choice. .field-wide opts a specific field OUT of this cap for
   controls that genuinely want the room (a URL, a secret, a long-text
   description edit). */
.field { display: flex; flex-direction: column; gap: .3rem; max-width: 22rem; }
.form-grid .field { max-width: none; }
.field-wide { max-width: 40rem; }
.field label { font-size: .7rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); }
/* A bare <select> (list of short words: "enabled"/"active"/"api_key") is
   capped narrower than the .field default — nothing about its content
   needs a wide box, and an oversized dropdown reads as unfinished. */
select { max-width: 14rem; }
.form-grid select, .field-stack select, .field-wide select { max-width: none; }
/* Base theming for any text-entry control — applies whether or not it sits
   inside a .field wrapper, so a page that forgets the wrapper still renders
   themed rather than falling through to unstyled browser chrome. Excludes
   checkbox/radio/hidden/submit/button/file, which need no or different
   styling. .field input/.field select is intentionally folded into this
   same rule (was previously duplicated with identical declarations). */
input:not([type=checkbox]):not([type=radio]):not([type=hidden]):not([type=submit]):not([type=button]):not([type=file]), select, textarea {
  font: inherit; font-size: .82rem; color: var(--ink); background: var(--input); border: 1px solid var(--border); border-radius: var(--r-input); padding: .5rem .65rem;
}
input::placeholder, textarea::placeholder { color: var(--muted); opacity: .7; }
input:not([type=checkbox]):not([type=radio]):not([type=hidden]):not([type=submit]):not([type=button]):not([type=file]):focus, select:focus, textarea:focus {
  outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent);
}
/* U7 (agent-tool-awareness, orchestrator-authorized bounded exception — the
   metadata override editor's <textarea>s are this app's first, so the base
   text-entry rule above never covered them; see HANDOFF.md's U7 Status row
   for why touching this one file, additive-only, two selector-list tokens
   plus one width rule, was decided in-place rather than escalated).
   Textareas default to the same max-width as .field-wide's own children so
   a multi-line control never looks narrower than the single-line inputs
   beside it. */
textarea { width: 100%; max-width: 40rem; box-sizing: border-box; resize: vertical; }
/* margin-top comes from the generic form-rhythm rule below (higher
   specificity than a plain class would give this anyway, since .form-foot
   is a direct form child too — kept as one source of truth, not doubled). */
.form-foot { display: flex; justify-content: flex-end; }
/* Small utility for grouping .field blocks (+ an action button) inside a
   cramped table cell — a strict single-column stack (2026-08-16 live-UAT
   fix: an earlier flex-wrap-based version let 2 fields land on one row
   whenever the cell happened to be wide enough and only 1 on the next,
   which read as clutter/disorder rather than a form — one field per line,
   always, regardless of available width, is the predictable version). */
.field-stack { display: flex; flex-direction: column; align-items: flex-start; gap: .6rem; }
.field-stack .field { width: 100%; max-width: 22rem; }
.field-stack .field.field-wide { max-width: 32rem; }

/* Vertical rhythm: a plain (non-.inline) form's direct children stack with
   a consistent gap by default — a <select>/<input>/.field immediately
   followed by its submit <button> previously touched with zero gap between
   them, and two stacked <form>s in the same .panel (e.g. "Save credential"
   then "Revoke credential") had no separation at all. .inline forms (single
   compact table-row actions) are exempted — their sizing/spacing is
   governed by .field-stack or plain inline flow instead. */
form:not(.inline) > *:not(:first-child) { margin-top: .75rem; }

/* ===================== misc: error banner (existing webui convention) ===================== */
.uikit-error { color: var(--warn); background: var(--warn-soft); border: 1px solid var(--border); border-radius: var(--r-btn); padding: .6rem .9rem; font-size: .85rem; font-weight: 600; margin: 1rem 1.5rem 0; }
/* TASK_BOARD.md §9d (agent-tool-awareness, owner-directed 2026-08-26,
   revised same day after live-UAT): a plain, borderless colored status
   line directly above the button it explains — NOT a panel-scoped banner
   like .uikit-error above. The full-box treatment was tried first and, in
   live testing, read as misaligned/disconnected from the button it was
   reporting on; this instead mirrors ordinary form-field validation-hint
   styling — colored text only, no background, no border, sitting right
   above the control the way a field's own inline error text sits above
   that field. .status-good/.status-warn set only the color, kept separate
   from .uikit-status-line's own sizing/spacing so either could be reused
   independently later. CSS-only fade, no JavaScript: htmx replaces this
   element's whole parent fragment on every Re-probe press, so a freshly
   inserted .uikit-fade element always restarts its animation from the
   beginning — nothing to reset, nothing to listen for. */
.uikit-status-line { display: flex; align-items: center; gap: .4rem; font-size: .82rem; font-weight: 600; margin: 0 0 .5rem; }
.uikit-status-line.status-good { color: var(--good); }
.uikit-status-line.status-warn { color: var(--warn); }
.uikit-status-icon { width: 1rem; height: 1rem; flex: none; }
/* Second live-UAT round (2026-08-26): the wrapper around .uikit-status-line
   is ALWAYS rendered (never conditional itself, unlike its two child <p>
   elements) and reserves one line's height, so the Re-probe button does
   not shift position the instant a message appears or the fade finishes
   and it disappears again. */
.uikit-status-slot { min-height: 1.5rem; }
@keyframes uikitFadeOut { 0% { opacity: 1; } 80% { opacity: 1; } 100% { opacity: 0; } }
.uikit-fade { animation: uikitFadeOut 5s ease-in forwards; }
/* A compact, ROW-scoped status message meant to sit inside a narrow table
   cell beside the button it explains (e.g. services_list.html's per-row
   "Refresh tools" failure) — unlike .uikit-error above, which is always a
   full-width <p> banner at panel/page scope, this is deliberately NOT that:
   no border/background/padding, only text color. 2026-08-17 owner-live-
   testing fix: .uikit-error was previously reused here on an inline <span>
   inside a <td>, and an inline (or even block) element's vertical padding/
   border paints outside its own line box without affecting the table row's
   layout height — the error box visually overlapped the ROW ABOVE it. Do
   not "restore" padding/border on this rule thinking it was accidentally
   dropped; their absence is the fix, not an oversight. */
.uikit-error-cell { display: block; color: var(--warn); font-size: .78rem; font-weight: 600; margin: 0 0 .5rem; max-width: 14rem; }
/* A short inline label paired with a standalone switch that sits between
   panels rather than inside one (e.g. the override tool-list edit-lock,
   deliberately rendered OUTSIDE any htmx swap target — see
   service_detail.html) — keeps it from reading as an orphaned control. */
.uikit-hint { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; color: var(--muted); font-size: .82rem; font-weight: 600; margin: 1.1rem 0; }
