/*
  The console shell's stylesheet (monitor/console): the page, the sidebar, the status bar, the
  dialogs (wizard, one-step confirm, one-time panel), the pagers and filter chips, and (at the end) the
  components every app's pages draw with -- cards, page heads, tables, buttons, badges, flash messages --
  the header's theme switch and the toasts. Loaded after the theme's custom properties
  (`/static/theme.<digest>.css`, which also carries the light scheme `<html data-theme>` picks) and
  before the app's own stylesheets, which may build on it but never restate it.
*/

* { box-sizing: border-box; }
/* The inlined icon sprite (_icons.html) is the first child of <body>. `hidden` is an HTML
       attribute and the browser does not apply it to an <svg>, so without this rule the sprite
       lays out as a 150px block above the header -- the "gap in the header". */
#icon-sprite { display: none; }
html { background: var(--bg); }
body {
      margin: 0;
      min-height: 100vh;
      color: var(--fg);
      font: 15px/1.5 ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
      background:
        radial-gradient(1200px 600px at 10% -10%, rgb(126 184 255 / 14%), transparent 55%),
        radial-gradient(900px 500px at 110% 0%, rgb(157 140 255 / 12%), transparent 50%),
        var(--bg);
      /* A light page's glow is fainter (light-dark() follows the theme's color-scheme; an older browser keeps the
         line above). */
      background:
        radial-gradient(1200px 600px at 10% -10%, light-dark(rgb(126 184 255 / 9%), rgb(126 184 255 / 14%)), transparent 55%),
        radial-gradient(900px 500px at 110% 0%, light-dark(rgb(157 140 255 / 7%), rgb(157 140 255 / 12%)), transparent 50%),
        var(--bg);
    }
@layer kit { a { color: var(--accent); } }
main {
      max-width: 52rem;
      margin: 0 auto;
      padding: 2rem 1.25rem 5rem;
    }
body.gui main {
      max-width: 92rem;
      padding-top: 3.25rem;
    }
.site-head {
      position: fixed;
      top: 0;
      left: 0;
      right: 0;
      z-index: 10000;
      display: grid;
      grid-template-columns: minmax(0, max-content) minmax(0, 1fr) minmax(0, max-content) minmax(0, max-content);
      align-items: center;
      gap: 0.35rem 0.65rem;
      padding: 0.4rem 1.25rem;
      border-bottom: 1px solid var(--line);
      background: color-mix(in oklab, var(--panel) 92%, var(--bg));
      color: var(--muted);
      font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
      font-size: 0.78rem;
    }
.site-head h1 {
      justify-self: start;
      display: flex;
      flex-wrap: nowrap;
      align-items: center;
      gap: 0.35rem;
      font-family: inherit;
      font-size: inherit;
      font-weight: 500;
      letter-spacing: 0;
      margin: 0;
      min-width: 0;
      white-space: nowrap;
    }
.site-head-cluster {
      display: flex;
      flex-wrap: nowrap;
      min-width: 0;
      overflow: hidden;
      align-items: center;
      justify-content: center;
      gap: 0.35rem 0.65rem;
    }
.site-head-cluster > span:not(.status-sep) {
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      min-width: 0;
    }
.site-head-end {
      justify-self: end;
      display: flex;
      flex-wrap: nowrap;
      align-items: center;
      justify-content: flex-end;
      gap: 0.35rem 0.65rem;
      font-family: inherit;
      font-size: inherit;
      font-weight: 500;
      color: inherit;
      min-width: 0;
      overflow: hidden;
    }
.site-head-end > span {
      font-variant-numeric: tabular-nums;
      white-space: nowrap;
    }
/* The hostname is never clipped: the h1 column is max-content, and the middle cluster
       (rtt / uptime / load) is the one that gives way. On a phone it wraps instead. */
#status-host {
      overflow: visible;
      text-overflow: clip;
      max-width: none;
    }
/* Where the node is (a looking-glass probe's city), when its app says (presence.header(place=...)). */
#status-place:empty { display: none; }
#status-place { color: var(--muted); }
#status-place::before { content: "·"; margin: 0 0.4em; }
@media (max-width: 52rem) {
  .site-head h1 { white-space: normal; flex-wrap: wrap; }
  #status-host { overflow-wrap: anywhere; }
}
.status-bar {
      position: fixed;
      bottom: 0;
      left: 0;
      right: 0;
      z-index: 10000;
      display: grid;
      grid-template-columns: 1fr auto 1fr;
      align-items: center;
      gap: 0.35rem 0.65rem;
      padding: 0.4rem 1.25rem;
      border-top: 1px solid var(--line);
      background: color-mix(in oklab, var(--panel) 92%, var(--bg));
      color: var(--muted);
      font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
      font-size: 0.78rem;
    }
/* Each span is pinned to its column, so docs / who stays at the right edge whatever else
       the bar is or is not rendering (guest view, no windows). */
.status-start {
      grid-column: 1;
      justify-self: start;
      display: inline-flex;
      flex-wrap: wrap;
      align-items: center;
      gap: 0.45rem 0.55rem;
      min-width: 0;
    }
.status-start button, .status-end button {
      appearance: none;
      border: 0;
      background: transparent;
      color: var(--accent);
      cursor: pointer;
      font: inherit;
      padding: 0;
    }
.status-start button:hover, .status-end button:hover { color: var(--fg); }
.status-start button.is-down, .status-end button.is-down, .site-head-end span.is-down { color: var(--bad); }
.status-start button.is-warn, .status-end button.is-warn { color: var(--warn); }
.status-start [hidden], .status-end [hidden] { display: none !important; }
.status-end {
      grid-column: 3;
      position: relative;
      justify-self: end;
      display: inline-flex;
      align-items: center;
      gap: 0.75rem;
    }
.status-end .status-version {
      font-size: 0.9em;
      white-space: nowrap;
      font-variant-numeric: tabular-nums;
    }
#status-time {
      justify-self: end;
      white-space: nowrap;
      font-variant-numeric: tabular-nums;
    }

:root {
  --nav-w: 15.5rem;
  --nav-w-rail: 3.5rem;
  --z-nav: 9000;          /* under .site-head (10000), over --z-overlay (400) */
  --z-inspect: 200;
  --z-window-max: 399;
  --z-overlay: 400;
}
html {
  scrollbar-width: thin;
  scrollbar-color: color-mix(in oklab, var(--muted) 55%, var(--line)) var(--panel);
}
body.gui main { max-width: none; }
.status-start a {
  color: var(--accent);
  text-decoration: none;
}
.status-start a:hover,
.status-start a.is-active { color: var(--fg); }
.status-start button {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--accent);
  cursor: pointer;
  font: inherit;
  padding: 0;
}
.status-start button:hover { color: var(--fg); }
.site-head .chip { font-size: 0.82rem; }
html { overflow-x: hidden; }
.table-pager {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem 0.75rem;
  margin-left: auto;
  flex: 0 0 auto;
  white-space: nowrap;
}
.table-pager[hidden] {
  display: none !important;
}
.table-pager label,
.table-pager select,
.table-pager button {
  flex: 0 0 auto;
}
.table-pager label {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}
.table-pager[hidden] {
  display: none !important;
}
.table-pager select {
  appearance: none;
  -webkit-appearance: none;
  width: auto;
  min-width: 5rem;
  padding: 0.22rem 1.55rem 0.22rem 0.5rem;
  margin-right: 0.35rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  background-color: var(--bg);
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%),
    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 0.85rem) 50%, calc(100% - 0.55rem) 50%;
  background-size: 0.3rem 0.3rem, 0.3rem 0.3rem;
  background-repeat: no-repeat;
  color: inherit;
  font: inherit;
}
.table-pager-bar {
  display: flex;
  justify-content: flex-end;
  flex: 0 0 auto;
  gap: 0.55rem;
  margin: 0 0 0.45rem;
}
.table-pager-bar-bottom {
  margin: 0.45rem 0 0;
}
.pager-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2rem;
  padding: 0.22rem 0.4rem;
}
.pager-btn svg {
  display: block;
}
.who-menu {
  position: fixed;
  z-index: var(--z-overlay);
  min-width: 10rem;
  padding: 0.4rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  box-shadow: 0 8px 24px color-mix(in oklab, #000 25%, transparent);
}
.who-menu button {
  appearance: none;
  width: 100%;
  border: 0;
  background: transparent;
  color: var(--accent);
  cursor: pointer;
  font: inherit;
  text-align: left;
  padding: 0.35rem 0.5rem;
  border-radius: 8px;
}
.who-menu button:hover { color: var(--fg); background: color-mix(in oklab, var(--panel-2) 80%, transparent); }
.status-end #status-who {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  font: inherit;
  padding: 0;
}
.status-end #status-who:hover { color: var(--fg); }
.status-end #status-who::after {
  content: " ▾";
  font-size: 0.65em;
  opacity: 0.7;
}
.tab-badge {
  display: inline-block;
  min-width: 1.15em;
  margin-left: 0.35em;
  padding: 0 0.35em;
  border-radius: 999px;
  font-size: 0.75em;
  font-weight: 700;
  line-height: 1.35;
  background: var(--bad);
  color: var(--bg);
  vertical-align: middle;
}
.tab-badge[hidden] { display: none !important; }
.site-head-end span.is-down { color: var(--bad); }
.status-start button.is-down { color: var(--bad); }
.status-end button.is-down { color: var(--bad); }
.status-end button.is-warn { color: var(--warn); }
body.gui #console-pop-host {
  position: fixed;
  z-index: var(--z-overlay);
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  background: color-mix(in oklab, var(--bg) 55%, transparent);
}
body.gui #console-pop-host[hidden] {
  display: none !important;
}
body.gui #console-pop-host .pop-confirm,
body.gui #console-pop-host .pop-panel {
  pointer-events: auto;
  z-index: var(--z-overlay);
  min-width: min(28rem, calc(100vw - 2rem));
  max-width: 36rem;
  margin: 0;
  box-shadow: 0 8px 32px color-mix(in oklab, #000 45%, transparent);
}
body.gui #console-pop-host .pop-panel {
  padding: 0.75rem 0.85rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: color-mix(in oklab, var(--panel) 92%, transparent);
}
/* The console's confirm: the same card as a wizard dialog (dialog.wz), sized like dialog.wz-sm. */
body.gui .pop-confirm {
  width: min(32rem, calc(100vw - 2rem));
  margin: 0.65rem 0 0.35rem;
  padding: 1rem 1.1rem 0.85rem;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
}
body.gui #console-pop-host .pop-confirm {
  box-shadow: 0 18px 60px color-mix(in oklab, #000 45%, transparent);
}
body.gui .pop-confirm-title {
  margin: 0 0 0.5rem;
  font-size: 1.15rem;
  font-weight: 650;
}
body.gui .pop-confirm-copy {
  margin: 0 0 0.85rem;
  color: var(--fg);
}
body.gui .pop-confirm-type,
body.gui .pop-confirm-note,
body.gui .pop-confirm-prompt {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  margin: 0 0 0.65rem;
}
/* "Type delete to confirm" over a full-width box, the way Cloudflare and DigitalOcean ask. */
body.gui .pop-confirm-type,
.wz-confirm .wz-body label.wz-word {
  flex-direction: column;
  align-items: stretch;
  gap: 0.35rem;
  margin: 0 0 0.85rem;
}
body.gui .pop-confirm-type strong,
.wz-word strong {
  color: var(--fg);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
body.gui .pop-confirm-note {
  flex-direction: column;
  align-items: stretch;
}
body.gui .pop-confirm-note textarea {
  min-height: 4rem;
  resize: vertical;
}
body.gui .pop-confirm-actions {
  justify-content: flex-end;
}
/* The console's wizard (console/_wizard.html; console/js/wizard.js opens it as a modal). */
dialog.wz {
  width: min(56rem, 94vw);
  max-height: min(88vh, 60rem);
  padding: 0;
  display: flex;
  flex-direction: column;
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: 0 18px 60px color-mix(in oklab, #000 45%, transparent);
  overflow: hidden;
}
dialog.wz:not([open]) { display: none; }
/* Heard by a screen reader, never seen (wizard.js announces the step a move lands on). */
.console-sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
/* A one-step confirm (console/_modal.html): the same dialog, narrower. */
dialog.wz.wz-sm { width: min(32rem, 94vw); }
.wz-confirm { display: flex; flex-direction: column; min-height: 0; }
.wz-confirm .wz-body label { display: flex; flex-direction: column; gap: 0.3rem; margin: 0 0 0.75rem; }
.wz-confirm .wz-body textarea { min-height: 4.5rem; resize: vertical; }
.wz-confirm .wz-foot { justify-content: flex-end; }
/* Find strays: "Select all" and the count on one line, above the two sections. */
.wz-confirm .strays-bar { display: flex; align-items: center; gap: 1rem; margin: 0.75rem 0; }
.wz-confirm .wz-body label.strays-all { flex-direction: row; align-items: center; gap: 0.5rem; margin: 0; }
.wz-confirm .strays-result { margin: 0.5rem 0; color: var(--ok); }
dialog.wz::backdrop { background: color-mix(in oklab, var(--bg) 62%, transparent); }
/* Inside the open wizard the confirm host is a child of the dialog (see wizard.js), still fixed over
   the viewport. */
dialog.wz > #console-pop-host { position: fixed; }
.wz-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  padding: 0.85rem 1.1rem 0.6rem;
}
.wz-head h2 { margin: 0; font-size: 1.15rem; font-weight: 650; }
.wz-draft { margin: 0 1.1rem 0.35rem; display: flex; gap: 0.5rem; align-items: center; }
.wz-steps {
  display: flex;
  list-style: none;
  margin: 0;
  padding: 0.45rem 1.1rem 0.75rem;
  gap: 0;
  border-bottom: 1px solid var(--line);
  overflow-x: auto;
}
/* The dialog is a column of capped height: its head, draft line, steps and foot keep their height and only the body
   scrolls. (The steps scroll sideways, and a scroller's automatic minimum height is zero: without this a long step
   body squeezed the stepper until its numbers were cut off.) */
.wz-head, .wz-draft, .wz-steps, .wz-note, .wz-foot { flex-shrink: 0; }
/* Each step is as wide as its own number and label; the line before it takes what is left, at least a short dash,
   and never runs under a long label ("Description & features"). Too many to fit: the steps scroll. */
.wz-step { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; }
.wz-step:first-child { flex-grow: 0; }
.wz-step + .wz-step::before {
  content: "";
  flex: 1 1 0;
  min-width: 0.75rem;
  height: 2px;
  margin: 0 0.4rem;
  background: var(--line);
}
.wz-step.is-done + .wz-step::before,
.wz-step.is-current::before { background: var(--accent); }
.wz-step-btn {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.2rem 0.3rem;
  border: 0;
  background: none;
  color: var(--muted);
  font: inherit;
  white-space: nowrap;
}
.wz-num {
  display: inline-grid;
  place-items: center;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 50%;
  border: 2px solid var(--line);
  font-size: 0.85rem;
  font-weight: 650;
}
.wz-step.is-done .wz-num { border-color: var(--accent); background: color-mix(in oklab, var(--accent) 22%, transparent); }
.wz-step.is-current .wz-num { border-color: var(--accent); background: var(--accent); color: var(--bg); }
.wz-step.is-current .wz-step-btn { color: var(--fg); font-weight: 650; }
.wz-note { margin: 0.6rem 1.1rem 0; }
.wz-form { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.wz-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 0.9rem 1.1rem; }
.wz-foot {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.7rem 1.1rem;
  border-top: 1px solid var(--line);
}
.wz-count { margin-right: auto; order: -1; }
.wz-after { padding: 0 1.1rem 1rem; overflow-y: auto; max-height: 30vh; }
.wz-danger { margin-top: 1rem; }
@media (prefers-reduced-motion: no-preference) {
  dialog.wz[open] { animation: wz-in 140ms ease-out; }
  dialog.wz.wz-moved[open] { animation: none; }
}
@media (max-width: 40rem) {
  dialog.wz { width: 100vw; max-width: 100vw; max-height: 100dvh; height: 100dvh; border-radius: 0; }
  .wz-label { display: none; }
  .wz-step.is-current .wz-label { display: inline; }
}
.wz-step-body h3 {
  margin: 0 0 0.35rem;
  font-size: 1.15rem;
}
.wz-step-body .lede {
  margin: 0 0 1rem;
  max-width: 42rem;
  line-height: 1.45;
  color: var(--muted, inherit);
}
.filter-chip { display: inline-flex; align-items: center; cursor: pointer; color: var(--muted);
  padding: 0.28rem 0.6rem; border-radius: 10px; }
/* The same chip for a checkbox (several chosen at once, e.g. the Runs looking-glass picks). */
.filter-chip > input[type="radio"],
.filter-chip > input[type="checkbox"] {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
.filter-chip:hover { color: var(--fg); }
.filter-chip:has(> input:checked) {
  color: var(--fg); font-weight: 650;
  background: color-mix(in oklab, var(--accent) 18%, transparent);
  box-shadow: inset 2px 0 0 var(--accent);
}
.filter-chip:has(> input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
/* A chip that is a link (`chip_links`): the current one drawn as a checked chip. */
a.filter-chip { text-decoration: none; }
a.filter-chip[aria-current="page"] {
  color: var(--fg); font-weight: 650;
  background: color-mix(in oklab, var(--accent) 18%, transparent);
  box-shadow: inset 2px 0 0 var(--accent);
}
/* A group of chips (`chips`, `chip_group`, `chip_links`): its legend and chips on one wrapping line, no fieldset box;
   several groups on one line (`chip_bar`). */
.filter-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 0.15rem 0.25rem; margin: 0; padding: 0;
  border: 0; min-width: 0; }
.filter-chips > legend { float: left; margin-right: 0.4rem; padding: 0; color: var(--muted); font-size: 0.875rem; }
.filter-chip-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 0.65rem 1rem; }
/* htmx's in-flight class. includeIndicatorCSS is false, so this is the only definition: one rule
   instead of the hx-pending / hx-browser-indicator extensions, and it cannot touch --z-*. */
.hx-busy { cursor: progress; }
.hx-busy button, .hx-busy input, .hx-busy select { cursor: progress; }
button.hx-busy, a.hx-busy { opacity: 0.6; }
@media (prefers-reduced-motion: no-preference) {
  button.hx-busy, a.hx-busy { transition: opacity 120ms ease; }
}
/* Left sidebar (console/_home_nav.html, items from the app's NavTree).
   Selection is [aria-current="page"] -- deliberately NOT .is-open, which is the in-pane tab
   vocabulary; keeping the two apart is what makes the JS selectors unambiguous. */
.home-nav {
  grid-column: 1;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: color-mix(in oklab, var(--panel) 88%, transparent);
  box-shadow: var(--shadow);
}
/* The head holds only the phone drawer's menu button; on desktop there is nothing to collapse. */
.home-nav-head { display: none; flex: 0 0 auto; padding: 0.3rem 0.35rem; border-bottom: 1px solid var(--line); }
.home-nav-body { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 0.4rem 0.35rem; }
.home-nav-foot { flex: 0 0 auto; padding: 0.3rem 0.35rem; border-top: 1px solid var(--line); }
.home-nav-menu {
  appearance: none; width: 100%; display: flex; align-items: center; gap: 0.45rem;
  border: 0; background: transparent; color: var(--muted); cursor: pointer;
  padding: 0.35rem 0.5rem; border-radius: 10px; font: inherit; font-size: 0.78rem;
}
.home-nav-menu:hover { color: var(--fg); background: color-mix(in oklab, var(--accent) 10%, transparent); }
/* Section titles you can find at a glance: larger, brighter, and set off by a hairline. */
.home-nav-group + .home-nav-group { margin-top: 0.9rem; padding-top: 0.6rem; border-top: 1px solid var(--line); }
.home-nav-group-label {
  margin: 0 0 0.3rem; padding: 0 0.55rem;
  font: 700 0.72rem/1.4 ui-sans-serif, system-ui, sans-serif;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: color-mix(in oklab, var(--fg) 75%, var(--muted));
}
.home-nav-list { list-style: none; margin: 0; padding: 0; }
.home-nav-item[hidden] { display: none; }
.home-nav-row { display: flex; align-items: stretch; gap: 0.1rem; }
.home-nav-link {
  position: relative; flex: 1 1 auto; min-width: 0;
  display: flex; align-items: center; gap: 0.45rem;
  padding: 0.38rem 0.55rem; border-radius: 10px;
  color: var(--muted); text-decoration: none; font-size: 0.86rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Each section's icons carry its own colour, so the groups read apart at a glance; the label stays
   muted until hovered or current. */
.home-nav-group { --nav-tone: var(--accent); }
.home-nav-group[data-nav-group="platform"] { --nav-tone: var(--cyan); }
.home-nav-group[data-nav-group="admin"] { --nav-tone: var(--violet); }
.home-nav-link { transition: background-color 120ms ease, color 120ms ease; }
.home-nav-link .home-nav-icon {
  color: color-mix(in oklab, var(--nav-tone, var(--accent)) 80%, var(--muted));
  transition: color 120ms ease, transform 120ms ease;
}
.home-nav-link:hover {
  color: var(--fg);
  background: color-mix(in oklab, var(--nav-tone, var(--accent)) 14%, transparent);
}
.home-nav-link:hover .home-nav-icon,
.home-nav-link[aria-current="page"] .home-nav-icon { color: var(--nav-tone, var(--accent)); }
.home-nav-link:hover .home-nav-icon { transform: translateX(1px) scale(1.08); }
@media (prefers-reduced-motion: reduce) {
  .home-nav-link, .home-nav-link .home-nav-icon { transition: none; }
  .home-nav-link:hover .home-nav-icon { transform: none; }
}
.home-nav-link:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.home-nav-link[aria-current="page"] {
  color: var(--fg); font-weight: 650;
  background: color-mix(in oklab, var(--nav-tone, var(--accent)) 18%, transparent);
  box-shadow: inset 2px 0 0 var(--nav-tone, var(--accent));
}
/* The parent of the current child: the trail is visible, but only one link claims the page. */
.home-nav-link.is-branch { color: var(--fg); background: color-mix(in oklab, var(--accent) 7%, transparent); }
.home-nav-icon { flex: 0 0 auto; display: inline-flex; }
.home-nav-icon .i { display: block; }
.home-nav-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.home-nav-link .tab-badge { margin-left: auto; flex: 0 0 auto; }
.home-nav-link.is-alert { color: var(--bad); font-weight: 700; }
.home-nav-link.is-alert[aria-current="page"] {
  background: color-mix(in oklab, var(--bad) 20%, transparent);
  box-shadow: inset 2px 0 0 var(--bad);
}
.home-nav-twisty {
  flex: 0 0 auto; width: 1.5rem; display: inline-flex; align-items: center; justify-content: center;
  appearance: none; border: 0; background: transparent; color: var(--muted);
  cursor: pointer; border-radius: 8px;
}
.home-nav-twisty:hover { color: var(--fg); }
.home-nav-twisty .i { transition: transform 120ms ease; }
.home-nav-twisty[aria-expanded="true"] .i { transform: rotate(90deg); }
.home-nav-sub {
  list-style: none; margin: 0.1rem 0 0.3rem 1.05rem; padding: 0 0 0 0.5rem;
  border-left: 1px solid var(--line);
}
.home-nav-sub[hidden] { display: none; }
.home-nav-link-sub { font-size: 0.82rem; padding-block: 0.3rem; gap: 0.4rem; }
/* Every level has its icon; below the top they are smaller and quieter so the tree still reads as
   a tree. A third level nests one step further in and a touch smaller. */
.home-nav-link-sub .home-nav-icon { opacity: 0.8; }
.home-nav-sub .home-nav-sub { margin-left: 0.55rem; }
.home-nav-link-l3 { font-size: 0.78rem; padding-block: 0.25rem; }
/* The drag handle of a top-level item: shown on hover or focus, the item itself is what drags. */
.home-nav-grip {
  flex: 0 0 auto; display: inline-flex; align-items: center; padding: 0 0.1rem;
  color: var(--muted); opacity: 0; cursor: grab;
}
.home-nav-item[data-nav-order]:hover > .home-nav-row > .home-nav-grip,
.home-nav-item[data-nav-order]:focus-within > .home-nav-row > .home-nav-grip { opacity: 0.7; }
.home-nav-item.is-dragging { opacity: 0.5; }
/* The filter box sits above the first group and stays put while the list scrolls under it. */
.home-nav-tools {
  position: sticky; top: -0.4rem; z-index: 1;
  display: flex; align-items: center; gap: 0.35rem;
  margin: -0.4rem -0.35rem 0.45rem; padding: 0.4rem 0.35rem 0.35rem;
  background: color-mix(in oklab, var(--panel) 96%, var(--bg));
  border-bottom: 1px solid var(--line);
}
/* The search box spans the sidebar, its magnifier inside on the left. */
.home-nav-search { position: relative; flex: 1 1 auto; min-width: 0; display: flex; }
.home-nav-search-icon {
  position: absolute; left: 0.5rem; top: 50%; transform: translateY(-50%);
  display: inline-flex; color: var(--muted); pointer-events: none;
}
.home-nav-search:focus-within .home-nav-search-icon { color: var(--accent); }
.home-nav-filter {
  flex: 1; min-width: 0; width: 100%;
  font: inherit; font-size: 0.82rem;
  padding: 0.3rem 0.5rem 0.3rem 1.7rem;
  color: var(--fg);
  background: color-mix(in oklab, var(--bg) 70%, transparent);
  border: 1px solid var(--line); border-radius: calc(var(--radius) - 2px);
}
.home-nav-filter:focus-visible { outline: 2px solid var(--accent); outline-offset: -1px; }
.home-nav-filter::placeholder { color: var(--muted); }
.home-nav-filter-count { flex: 0 0 auto; font-size: 0.72rem; color: var(--muted); white-space: nowrap; }
.home-nav-filter-count:empty { display: none; }
/* Filtered out: distinct from `hidden`, which a capability sets. */
.home-nav-item[data-nav-filtered] { display: none; }
.home-nav-group[hidden] { display: none; }
@media (prefers-reduced-motion: reduce) {
  .home-nav-twisty .i { transition: none; }
}
@media (max-width: 52rem) {
  .home-nav-head { display: block; }
  .home-nav {
    position: fixed; z-index: var(--z-nav);
    top: 3.4rem; left: 0.6rem;
    width: min(17rem, calc(100vw - 1.2rem));
    max-height: calc(100dvh - 7.5rem);
  }
}
.wz-step-body:has(input[name="glass_scope"][value="all"]:checked) .pkg-glasses,
.wz-step-body:has(input[name="glass_scope"][value="package"]:checked) .pkg-glasses { display: none; }
.wz-confirm:has(input[name="type"][value="email_managed"]:checked) .alerts-fields[data-type="email_managed"],
.wz-confirm:has(input[name="type"][value="slack"]:checked) .alerts-fields[data-type="slack"],
.wz-confirm:has(input[name="type"][value="discord"]:checked) .alerts-fields[data-type="discord"],
.wz-confirm:has(input[name="type"][value="teams"]:checked) .alerts-fields[data-type="teams"],
.wz-confirm:has(input[name="type"][value="telegram"]:checked) .alerts-fields[data-type="telegram"],
.wz-confirm:has(input[name="type"][value="webhook"]:checked) .alerts-fields[data-type="webhook"],
.wz-confirm:has(input[name="type"][value="pagerduty"]:checked) .alerts-fields[data-type="pagerduty"] { display: grid; }

/* The apps bar (console/base.html `apps`, sdllc_kit.console.apps.bar): each console a link, the one you are on marked,
   each group (the looking glasses) a native <details> menu. A narrow screen keeps the bar on one line and scrolls it. */
.apps-bar { display: flex; align-items: center; gap: 0.15rem; min-width: 0; max-width: 100%; overflow-x: auto; scrollbar-width: none; }
.apps-bar::-webkit-scrollbar { display: none; }
.apps-link { flex: none; padding: 0.15rem 0.45rem; border-radius: 6px; color: var(--muted); text-decoration: none; font-size: 0.85rem; white-space: nowrap; }
.apps-link:hover, .apps-link:focus-visible { color: var(--text); background: var(--panel-2); }
.apps-link[aria-current="page"] { color: var(--text); background: var(--panel-2); font-weight: 600; }
.apps-menu { position: relative; margin-left: 0.5rem; flex: none; }
.apps-bar .apps-menu { margin-left: 0; position: static; }
.apps-menu > summary { list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: 0.25rem; padding: 0.15rem 0.45rem; border-radius: 6px; color: var(--muted); font-size: 0.85rem; white-space: nowrap; }
.apps-menu > summary[aria-current] { color: var(--text); font-weight: 600; }
.apps-menu > ul a[aria-current="page"] { font-weight: 600; background: var(--panel-2); }
.apps-menu > summary::-webkit-details-marker { display: none; }
.apps-menu > summary:hover, .apps-menu[open] > summary { color: var(--text); background: var(--panel-2); }
.apps-menu > ul { position: absolute; right: 0; top: calc(100% + 0.35rem); z-index: var(--z-overlay); min-width: 12rem; margin: 0; padding: 0.35rem; list-style: none; background: var(--panel); border: 1px solid var(--line); border-radius: 8px; }
.apps-menu > ul a { display: flex; align-items: center; gap: 0.5rem; padding: 0.35rem 0.5rem; border-radius: 6px; color: var(--text); text-decoration: none; }
.apps-menu > ul a:hover, .apps-menu > ul a:focus-visible { background: var(--panel-2); }

/* Text never outgrows its card, in either console, on a desktop or a phone. A card is a grid or flex child that may
   shrink; a long word (an id, a hostname, a URL, a schema name) breaks where it must; a field is never wider than its
   card; and on a phone a wide table scrolls inside its card instead of widening the page. Zero specificity (`:where`):
   an app's own card rules still win. */
:where(.card, [class*="-card"], .kpi) { min-width: 0; overflow-wrap: anywhere; }
:where(.card, [class*="-card"]) :where(table) { overflow-wrap: normal; }
:where(.card, [class*="-card"]) :where(td, th) { overflow-wrap: break-word; }
:where(.card, [class*="-card"]) :where(pre) { white-space: pre-wrap; }
:where(input, select, textarea) { max-width: 100%; }
@media (max-width: 52rem) {
  :where(.card, [class*="-card"]) :where(table) { display: block; max-width: 100%; overflow-x: auto; }
}

/* A sortable head's control (console/_macros.html `sort_head`): a real button that looks like the header it sits in --
   no button chrome, the cell's font and colour (an app's `th.is-sorted` colour reaches it), the whole cell's width. */
/* In the kit's layer, so `.status-table`'s cell padding (and an app's own rules) win over this reset. */
@layer kit {
  th.is-sortable > .sort-btn {
    display: block; width: 100%; margin: 0; padding: 0; border: 0; border-radius: 0; background: none; box-shadow: none;
    font: inherit; color: inherit; text-align: inherit; text-transform: inherit; letter-spacing: inherit; cursor: pointer;
  }
  th.is-sortable > .sort-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
}

/* The log viewer (console/_logview.html) and the lists (console/_lists.html): filter bar, table, outcome badge, a row's detail. */
.log-filters, .list-filters { display: flex; flex-wrap: wrap; gap: .5rem 1rem; align-items: end; margin: 0 0 .75rem; }
.log-filter, .list-filter { display: flex; flex-direction: column; gap: .25rem; font-size: .85em; color: var(--muted); }
/* An empty list's next action (console/_macros.html empty_row, empty_item). */
.empty .empty-action { margin-left: .35rem; }
.log-table { width: 100%; border-collapse: collapse; }
.log-table th, .log-table td { padding: .35rem .5rem; text-align: left; vertical-align: top; border-bottom: 1px solid var(--line); }
.log-table details > summary { cursor: pointer; color: var(--muted); }
.log-table .cell-json { margin: .25rem 0 0; white-space: pre-wrap; word-break: break-word; }
.log-outcome { font-size: .85em; }
.log-outcome.is-ok { color: var(--ok); }
.log-outcome.is-refused { color: var(--warn); }
.log-outcome.is-error { color: var(--bad); }
.log-row.is-fail td:first-child { box-shadow: inset 2px 0 0 var(--bad); }

/* The session list (console/_sessions.html): the table, this session's badge, the sign-out forms. */
/* The status line stays displayed while empty: a live region that is display:none is not read out when it fills. */
.session-notice { margin: 0; color: var(--ok); }
.session-notice:not(:empty) { margin-bottom: .5rem; }
.session-notice .session-warn { color: var(--warn); }
.error-detail-host:not(:empty) { margin-top: 1rem; padding-top: .75rem; border-top: 1px solid var(--line); }
.session-table { width: 100%; border-collapse: collapse; }
.session-table th, .session-table td { padding: .35rem .5rem; text-align: left; vertical-align: middle; border-bottom: 1px solid var(--line); }
.session-row.is-current td:first-child { box-shadow: inset 2px 0 0 var(--accent); }
.session-this { display: inline-block; margin-left: .5rem; padding: 0 .4rem; border: 1px solid var(--accent); border-radius: 999px; font-size: .8em; color: var(--accent); }
.session-form { margin: 0; }
.session-list > .session-form { margin-top: .75rem; }
.session-sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }

/* The platform inspector (console/_inspect.html): monitor's and billing's service cards. A card is a fieldset whose
   legend says what it is (and, with a state, a dot and its word); its facts are a key/value grid. */
.inspect-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 18rem), 1fr)); gap: .75rem; align-items: stretch; margin-bottom: .75rem; }
.inspect-cards > .inspect-card.is-wide { grid-column: 1 / -1; }
.inspect-card { margin: 0 0 .75rem; padding: .75rem .9rem .85rem; border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel); min-width: 0; box-sizing: border-box; }
.inspect-cards > .inspect-card { margin: 0; height: 100%; }
.inspect-card legend { padding: 0 .35rem; font-size: .7rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.inspect-card.is-table { overflow-x: auto; }
.inspect-pill { display: inline-flex; align-items: center; gap: .3rem; margin-left: .35rem; font-weight: 500; font-size: .78rem; text-transform: none; letter-spacing: 0; color: var(--muted); }
.inspect-kv { display: grid; grid-template-columns: 8.5rem minmax(0, 1fr); gap: .2rem .75rem; margin: 0; font-size: .82rem; }
.inspect-kv.is-wide { grid-template-columns: 9rem minmax(0, 1fr) 9rem minmax(0, 1fr); }
.inspect-kv dt { color: var(--muted); }
.inspect-kv dd { margin: 0; min-width: 0; overflow-wrap: anywhere; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.inspect-table td { vertical-align: top; overflow-wrap: anywhere; }
.inspect-dot { display: inline-block; width: .5rem; height: .5rem; border-radius: 50%; margin-right: .35rem; vertical-align: middle; background: var(--muted); }
.inspect-dot.is-up { background: var(--ok); }
.inspect-dot.is-down { background: var(--bad); }
@media (max-width: 44rem) {
  .inspect-kv.is-wide { grid-template-columns: 8.5rem minmax(0, 1fr); }
}

/* The nodes of this app (console/_nodes.html): a row a node, its roles as a list, this node's badge. */
.node-table { width: 100%; border-collapse: collapse; }
.node-table th, .node-table td { padding: .35rem .5rem; text-align: left; vertical-align: top; border-bottom: 1px solid var(--line); }
.node-row.is-here td:first-child { box-shadow: inset 2px 0 0 var(--accent); }
.node-row.is-stale td:first-child, .node-row.is-never td:first-child { color: var(--muted); }
.node-here { display: inline-block; margin-left: .5rem; padding: 0 .4rem; border: 1px solid var(--accent); border-radius: 999px; font-size: .8em; color: var(--accent); }
.node-roles { display: flex; flex-wrap: wrap; gap: .25rem .75rem; margin: 0; padding: 0; list-style: none; }
.node-state.is-stale, .node-state.is-never { color: var(--muted); }
.node-lease + .node-lease { margin-top: .2rem; }

/* The settings page (console/_settings.html, sdllc_kit.console.settings): the search, the groups' index beside the
   groups, one row per setting (its badges are `.badge`), the review panel and the history. */
.settings { display: grid; grid-template-columns: minmax(10rem, 14rem) minmax(0, 1fr); gap: .75rem 1rem; align-items: start; }
.settings-search { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .75rem; margin: 0; }
.settings-search input[type="search"] { flex: 1 1 16rem; min-width: 0; }
.settings-index { position: sticky; top: .75rem; }
.settings-index ul { margin: 0; padding: 0; list-style: none; }
.settings-index li { display: flex; justify-content: space-between; gap: .5rem; padding: .2rem 0; }
.settings-main { display: grid; gap: .75rem; min-width: 0; }
.settings-group h3 { margin-top: 0; }
.settings-form { display: grid; gap: .75rem; margin: 0; }
.settings-row { display: grid; gap: .3rem; padding: .6rem 0; border-top: 1px solid var(--line); min-width: 0; }
.settings-row.is-invalid { box-shadow: inset 2px 0 0 var(--bad); padding-left: .6rem; }
.settings-row.is-fixed { color: var(--muted); }
.settings-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: .35rem .5rem; }
.settings-label { font-weight: 600; }
.settings-key, .settings-hint { font-size: .8em; overflow-wrap: anywhere; }
.settings-help, .settings-meta { margin: 0; color: var(--muted); font-size: .88em; }
.settings-control { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin: 0; min-width: 0; }
.settings-control input, .settings-control select, .settings-control textarea { max-width: 100%; }
.settings-unit { color: var(--muted); font-size: .88em; }
.settings-error { margin: 0; }
.settings-multi { display: flex; flex-wrap: wrap; gap: .25rem .75rem; margin: 0; padding: 0; border: 0; }
.settings-multi legend { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.settings-check { display: inline-flex; align-items: center; gap: .3rem; }
.settings-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .75rem; }
.settings-panel { margin: 0; }
.settings-panel:empty { display: none; }
.settings-changes { width: 100%; }
.settings-restore { display: inline; margin: 0; }
.settings-history { grid-column: 1 / -1; }
@media (max-width: 720px) {
  .settings { grid-template-columns: minmax(0, 1fr); }
  .settings-index { position: static; }
}

/* ============================================================================================================
   Components: the one copy of what monitor's, billing's, notify's and looking-glass's stylesheets each kept
   (consoles.css, notify.css, lg.css, monitor.css/gui.css). Every rule is in the `kit` cascade layer, so any
   rule of an app's -- whatever its specificity -- still wins until the app deletes its own copy; what an app
   never set comes from here. Colours are the theme's roles only, so each reads in the light scheme and the dark.
   One primary button (`go`) and one danger button (`danger`); `go danger` is a destructive dialog's confirm.
   Bare form elements (button, input, select, textarea, label, `.row`) only on `body.kit-forms`
   (AppShell.form_styles): monitor's differ, and they would otherwise reach every page it draws.
   ============================================================================================================ */
@layer kit {
  [hidden] { display: none !important; }

  /* The one-page frame: the page is exactly the viewport and never grows; header, main and bar are a grid's rows,
     main and #app pass the height down to .status-layout, and the sidebar's body and the open pane scroll on their
     own. A phone (the shell's 52rem drawer) scrolls the page instead. */
  body.gui:has(.status-layout) {
    height: 100vh; min-height: 0; overflow: hidden; display: grid;
    grid-template-rows: auto minmax(0, 1fr) auto; grid-template-columns: minmax(0, 1fr);
  }
  body.gui:has(.status-layout) > .site-head,
  body.gui:has(.status-layout) > .status-bar { position: static; }
  body.gui:has(.status-layout) main {
    width: 100%; margin: 0; padding: 0.75rem 1rem; min-height: 0; overflow: hidden; display: flex; flex-direction: column;
  }
  body.gui:has(.status-layout) #app { flex: 1; min-height: 0; display: flex; flex-direction: column; }
  .status-layout {
    display: grid; grid-template-columns: var(--nav-w, 15rem) minmax(0, 1fr); gap: 1rem; align-items: stretch;
    flex: 1; min-height: 0; overflow: hidden;
  }
  .status-main { min-width: 0; min-height: 0; overflow: hidden; display: flex; flex-direction: column; gap: 1rem; }
  [data-home-pane] { display: flex; flex-direction: column; gap: 1rem; padding-bottom: 2rem; }
  [data-home-pane]:not([hidden]) { flex: 1; min-height: 0; overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; }
  .home-nav-body,
  [data-home-pane]:not([hidden]) { scrollbar-width: thin; scrollbar-color: var(--muted) transparent; }
  .home-nav-body::-webkit-scrollbar-track,
  [data-home-pane]:not([hidden])::-webkit-scrollbar-track { background: transparent; }
  .home-nav-twisty { padding: 0; }
  .home-nav-search { flex-direction: row; gap: 0; font-size: inherit; }
  @media (max-width: 52rem) {
    body.gui:has(.status-layout) { height: auto; min-height: 100vh; overflow: auto; }
    body.gui:has(.status-layout) main { height: auto; overflow: auto; }
    .status-layout { grid-template-columns: minmax(0, 1fr); }
    [data-home-pane]:not([hidden]) { overflow: visible; }
    .status-main { padding-top: 2.6rem; }
    .card:has(> .status-table), .card:has(> .table-wrap) { overflow-x: auto; }
    body.gui[data-nav-collapsed="1"] .home-nav { width: auto; }
    body.gui[data-nav-collapsed="1"] .home-nav-body,
    body.gui[data-nav-collapsed="1"] .home-nav-foot { display: none; }
  }

  /* A page's head: its title, and its actions at the end. */
  .pane-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
  .pane-head > * { min-width: 0; max-width: 100%; }
  .pane-head h2 { margin: 0; font-size: 1.2rem; display: flex; align-items: center; gap: 0.45rem; }
  .pane-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }

  /* Words. */
  .muted { color: var(--muted); }
  .hint { color: var(--muted); font-size: 0.85rem; }
  .hint, .flash, .error { margin-block: 0; }  /* the container's gap spaces them; a <p>'s margins doubled it */
  .small { font-size: 0.82rem; }
  .mono, code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.85em; }
  .stack { display: flex; flex-direction: column; gap: 0.8rem; }
  .stack > * { min-width: 0; max-width: 100%; }

  /* Cards: a surface one step above the page; `.cards` a grid of them; a KPI's label and value. */
  .card {
    background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 1rem 1.1rem;
    box-shadow: var(--shadow); min-width: 0; max-width: 100%;
  }
  .card h3, .card h4 { margin: 0 0 0.6rem; font-size: 1rem; }
  .cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 14rem), 1fr)); gap: 1rem; }
  .cards > * { min-width: 0; }
  .kpi .k { color: var(--muted); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em; }
  .kpi .v { font-size: 1.4rem; line-height: 1.25; margin-top: 0.2rem; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
  .kpi dd, .kpi dt { margin: 0; }

  /* Flash messages: info by default, and the four levels a toast has. `.error` is the error one. */
  .flash, .error {
    border: 1px solid var(--accent-ring); background: color-mix(in oklab, var(--accent) 10%, var(--panel));
    color: var(--fg); padding: 0.6rem 0.8rem; border-radius: var(--radius); overflow-wrap: anywhere;
  }
  .flash.is-success { border-color: var(--ok); background: color-mix(in oklab, var(--ok) 10%, var(--panel)); }
  .flash.is-warning { border-color: var(--warn); background: color-mix(in oklab, var(--warn) 12%, var(--panel)); }
  .error, .flash.is-error { border-color: var(--bad); background: color-mix(in oklab, var(--bad) 12%, var(--panel)); }
  td.error { border-radius: 0; }

  /* Buttons. `.button` is the look on a link or a button; `go` the one primary, `ghost` a quiet secondary,
     `quiet` (or `link`) a button that reads as a link, `danger` the one danger style (filled when it is also
     `go`: a destructive dialog's confirm), `small` a row's. `is-danger` is danger's other spelling (looking-glass,
     the shell's modal). Only on a button or a `.button`: `danger` on a paragraph is an app's own. */
  .button, button:is(.go, .ghost, .danger, .is-danger, .quiet, .link) {
    font: inherit; cursor: pointer; border-radius: 0.6rem; padding: 0.5rem 0.95rem; border: 1px solid var(--line);
    background: var(--panel-2); color: var(--fg); text-decoration: none; line-height: 1.25;
    display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem;
  }
  :is(button, .button):focus-visible { outline: 2px solid var(--accent-ring); outline-offset: 2px; }
  .button:hover, :is(button, .button).ghost:hover { border-color: var(--accent-ring); }
  :is(button, .button).go { background: var(--accent); border-color: var(--accent); color: var(--on-accent); font-weight: 600; }
  :is(button, .button).go:hover { background: var(--accent-lift); border-color: var(--accent-lift); }
  :is(button, .button).ghost { background: transparent; color: var(--fg); }
  :is(button, .button):is(.quiet, .link) {
    background: none; border: 0; padding: 0; color: var(--accent); text-align: left; border-radius: 0.2rem;
  }
  :is(button, .button):is(.quiet, .link):hover { text-decoration: underline; }
  :is(button, .button):is(.danger, .is-danger) { background: transparent; border-color: var(--bad); color: var(--bad); }
  :is(button, .button):is(.danger, .is-danger):hover { background: var(--bad); color: var(--on-accent); }
  :is(button, .button).go:is(.danger, .is-danger) { background: var(--bad); border-color: var(--bad); color: var(--on-accent); }
  :is(button, .button).go:is(.danger, .is-danger):hover { background: var(--bad-lift); border-color: var(--bad-lift); }
  :is(button, .button).small { padding: 0.2rem 0.6rem; font-size: 0.8rem; border-radius: 0.45rem; }
  :is(button, .button):is([disabled], [aria-disabled="true"]) { opacity: 0.55; cursor: not-allowed; pointer-events: none; }
  .actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }

  /* Tables: `.status-table` inside a `.table-wrap` that scrolls sideways; numbers and money right-aligned. */
  .table-wrap { overflow-x: auto; max-width: 100%; }
  .status-table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
  .status-table caption {
    text-align: left; color: var(--muted); font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.06em;
    padding: 0.2rem 0 0.4rem;
  }
  .status-table th, .status-table td {
    text-align: left; padding: 0.5rem 0.6rem; border-bottom: 1px solid var(--line); vertical-align: top;
    overflow-wrap: break-word;
  }
  .status-table th { color: var(--muted); font-weight: 500; font-size: 0.8rem; }
  .status-table th.is-sortable { padding: 0; user-select: none; }
  .status-table th.is-sortable > .sort-btn { padding: 0.5rem 0.6rem; }
  .status-table th.is-sorted { color: var(--fg); }
  .status-table th[aria-sort="ascending"] > .sort-btn::after { content: " \2191"; }
  .status-table th[aria-sort="descending"] > .sort-btn::after { content: " \2193"; }
  .status-table tbody tr:hover > td { background: color-mix(in oklab, var(--panel-2) 55%, transparent); }
  .status-table .num, .status-table .money { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
  .status-table td.wrap { overflow-wrap: anywhere; }
  .status-table td.nw { white-space: nowrap; }
  .status-table tr.is-selected > td { background: color-mix(in oklab, var(--accent) 10%, var(--panel)); }
  .table-tools { display: flex; justify-content: space-between; align-items: flex-end; gap: 1rem; flex-wrap: wrap; }

  /* A table's columns by number (tablesort.Column, `Table.layout()` on the <table>), so the app's rows need no class on
     a cell: `c<n>-r` right-aligns the n-th column in tabular figures (a number, money), `c<n>-c` centres it, `c<n>-p3`
     hides it under 52rem and `c<n>-p2` on a phone (under 40rem). A cell may say the same itself: `num`, `money`,
     `al-r`, `al-c`, `p-2`, `p-3` (the head's own classes). An empty row's one cell is never moved. */
  table.c1-r > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(1),
  table.c2-r > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(2),
  table.c3-r > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(3),
  table.c4-r > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(4),
  table.c5-r > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(5),
  table.c6-r > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(6),
  table.c7-r > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(7),
  table.c8-r > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(8),
  table.c9-r > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(9),
  table.c10-r > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(10),
  table.c11-r > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(11),
  table.c12-r > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(12),
  table.c13-r > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(13),
  table.c14-r > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(14),
  table.c15-r > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(15),
  table.c16-r > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(16),
  .status-table .al-r { text-align: right; font-variant-numeric: tabular-nums; }
  table.c1-c > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(1),
  table.c2-c > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(2),
  table.c3-c > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(3),
  table.c4-c > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(4),
  table.c5-c > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(5),
  table.c6-c > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(6),
  table.c7-c > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(7),
  table.c8-c > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(8),
  table.c9-c > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(9),
  table.c10-c > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(10),
  table.c11-c > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(11),
  table.c12-c > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(12),
  table.c13-c > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(13),
  table.c14-c > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(14),
  table.c15-c > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(15),
  table.c16-c > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(16),
  .status-table .al-c { text-align: center; }
  .status-table .al-l { text-align: left; }
  @media (max-width: 52rem) {
    table.c1-p3 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(1),
    table.c2-p3 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(2),
    table.c3-p3 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(3),
    table.c4-p3 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(4),
    table.c5-p3 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(5),
    table.c6-p3 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(6),
    table.c7-p3 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(7),
    table.c8-p3 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(8),
    table.c9-p3 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(9),
    table.c10-p3 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(10),
    table.c11-p3 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(11),
    table.c12-p3 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(12),
    table.c13-p3 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(13),
    table.c14-p3 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(14),
    table.c15-p3 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(15),
    table.c16-p3 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(16),
    .status-table .p-3 { display: none !important; }
  }
  @media (max-width: 40rem) {
    table.c1-p2 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(1),
    table.c2-p2 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(2),
    table.c3-p2 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(3),
    table.c4-p2 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(4),
    table.c5-p2 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(5),
    table.c6-p2 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(6),
    table.c7-p2 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(7),
    table.c8-p2 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(8),
    table.c9-p2 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(9),
    table.c10-p2 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(10),
    table.c11-p2 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(11),
    table.c12-p2 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(12),
    table.c13-p2 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(13),
    table.c14-p2 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(14),
    table.c15-p2 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(15),
    table.c16-p2 > :is(thead, tbody, tfoot) > tr:not(.empty) > :nth-child(16),
    .status-table .p-2 { display: none !important; }
  }

  /* A head that stays in view (`list_table(..., sticky=true)`): the box scrolls both ways, at most --table-max-h tall,
     and is a tab stop so a keyboard can scroll it. `.status-table.is-sticky` alone sticks to the pane that scrolls. */
  .table-wrap.is-sticky { max-height: var(--table-max-h, 70vh); overflow: auto; overscroll-behavior: contain; }
  .table-wrap.is-sticky:focus-visible { outline: 2px solid var(--accent-ring); outline-offset: 2px; }
  .table-wrap.is-sticky > table > thead > tr > th,
  .status-table.is-sticky > thead > tr > th {
    position: sticky; top: 0; z-index: 1; background: var(--panel); box-shadow: inset 0 -1px 0 var(--line);
  }

  /* A row's actions (`_macros.row_actions`): at the row's end, never wrapping; more than a few are a menu. */
  .status-table :is(td, th).is-actions { text-align: right; white-space: nowrap; width: 1%; }
  .row-actions { display: inline-flex; align-items: center; justify-content: flex-end; gap: 0.35rem; }
  .row-action-form { display: contents; }
  .row-menu { position: relative; display: inline-block; text-align: left; }
  .row-menu > summary { list-style: none; cursor: pointer; min-width: 2rem; }
  .row-menu > summary::-webkit-details-marker { display: none; }
  .row-menu-list {
    position: absolute; right: 0; top: calc(100% + 0.25rem); z-index: 20; display: flex; flex-direction: column;
    gap: 0.15rem; min-width: 10rem; padding: 0.3rem; background: var(--panel); border: 1px solid var(--line);
    border-radius: 0.6rem; box-shadow: var(--shadow);
  }
  .row-menu-list .row-menu-item { justify-content: flex-start; width: 100%; border-color: transparent; }
  .row-menu-list .row-menu-item:hover { border-color: var(--accent-ring); }

  /* Meaningful colour: an edge on a row that needs attention (`is-attention`/`is-warn`, `is-bad`, `is-ok`), a value
     that went up or down (`is-up`, `is-down`: words or an arrow say it too), and `aria-selected` like `is-selected`. */
  .status-table tr:is(.is-attention, .is-warn) > td:first-child { box-shadow: inset 3px 0 0 var(--warn); }
  .status-table tr.is-bad > td:first-child { box-shadow: inset 3px 0 0 var(--bad); }
  .status-table tr.is-ok > td:first-child { box-shadow: inset 3px 0 0 var(--ok); }
  .status-table .is-up { color: var(--ok); }
  .status-table .is-down { color: var(--bad); }
  .status-table tr[aria-selected="true"] > td { background: color-mix(in oklab, var(--accent) 10%, var(--panel)); }

  /* A phone's stacked rows (`list_table(..., stack=true)`): each row a card, each cell its column's label and value
     (`_macros.cell` writes `data-label`); the head stays for a screen reader only. */
  @media (max-width: 40rem) {
    .status-table.is-stacked > thead {
      position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
    }
    .status-table.is-stacked, .status-table.is-stacked > tbody, .status-table.is-stacked > tbody > tr { display: block; width: 100%; }
    .status-table.is-stacked > tbody > tr {
      margin: 0 0 0.6rem; padding: 0.35rem 0; border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel);
    }
    .status-table.is-stacked > tbody > tr > td {
      display: grid; grid-template-columns: minmax(6rem, 38%) minmax(0, 1fr); gap: 0.6rem; padding: 0.25rem 0.75rem;
      border: 0; text-align: left; width: auto; white-space: normal;
    }
    .status-table.is-stacked > tbody > tr > td:not([data-label]) { display: block; }
    .status-table.is-stacked > tbody > tr > td[data-label]::before { content: attr(data-label); color: var(--muted); font-size: 0.8rem; }
    .status-table.is-stacked > tbody > tr > td.is-actions { display: flex; justify-content: flex-end; }
  }

  /* Badges: a pill of a state's colour, that wraps inside its card rather than widen it (rounded corners, not a
     pill's ends, when it does). `ok`/`bad`/`warn` are looking-glass's spellings. */
  .badge {
    display: inline-block; max-width: 100%; padding: 0.1rem 0.5rem; border-radius: 0.75rem; font-size: 0.75rem;
    line-height: 1.4; border: 1px solid var(--line); vertical-align: middle; overflow-wrap: anywhere;
  }
  /* In a table cell a badge is one state word: whole, never broken mid-word ("firi ng"). */
  .status-table .badge { white-space: nowrap; overflow-wrap: normal; }
  .badge.is-ok, .badge.ok, .badge.is-success { border-color: var(--ok); color: var(--ok); }
  .badge.is-bad, .badge.bad, .badge.is-error { border-color: var(--bad); color: var(--bad); }
  .badge.is-warn, .badge.warn, .badge.is-warning { border-color: var(--warn); color: var(--warn); }
  .badge.is-info { border-color: var(--accent-ring); color: var(--accent); }
  .badge.is-muted { color: var(--muted); }

  /* A state's dot, a key/value list, a code box. */
  .dot { display: inline-block; width: 0.5rem; height: 0.5rem; border-radius: 50%; margin-right: 0.35rem; vertical-align: middle; background: var(--muted); }
  .dot.on { background: var(--ok); }
  .dot.off { background: var(--bad); }
  dl.kv { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 0.35rem 1rem; margin: 0; }
  dl.kv dt { color: var(--muted); }
  dl.kv dd { margin: 0; overflow-wrap: anywhere; }
  .codebox {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; background: var(--ink); color: var(--fg);
    border: 1px solid var(--line); border-radius: 0.6rem; padding: 0.7rem; overflow: auto; max-height: 32rem;
    white-space: pre-wrap; overflow-wrap: anywhere; margin: 0;
  }

  /* The sign-in page's card. */
  .login-wrap { display: flex; justify-content: center; padding: 3rem 1rem; }
  .login-card { width: min(28rem, 100%); }
  .login-card h1 { font-size: 1.3rem; margin: 0 0 0.3rem; }

  /* Bare form elements: the kit's only where the app asks (AppShell.form_styles). */
  :where(body.kit-forms) :where(button) {
    font: inherit; cursor: pointer; border-radius: 0.6rem; padding: 0.5rem 0.95rem; border: 1px solid var(--line);
    background: var(--panel-2); color: var(--fg); line-height: 1.25;
    display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem;
  }
  :where(body.kit-forms) :where(button):hover { border-color: var(--accent-ring); }
  :where(body.kit-forms) :where(button[disabled]) { opacity: 0.55; cursor: not-allowed; }
  :where(body.kit-forms) :where(label) { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.9rem; }
  :where(body.kit-forms) :where(label.row, label.inline) { flex-direction: row; align-items: center; gap: 0.45rem; }
  :where(body.kit-forms) :where(input, select, textarea) {
    font: inherit; color: var(--fg); background: var(--panel-2); border: 1px solid var(--line);
    border-radius: 0.6rem; padding: 0.5rem 0.65rem; max-width: 100%;
  }
  :where(body.kit-forms) :where(input[type="checkbox"], input[type="radio"]) { padding: 0; accent-color: var(--accent); }
  :where(body.kit-forms) :where(select) {
    appearance: none; -webkit-appearance: none; padding-right: 2rem; line-height: 1.4;
    background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%);
    background-position: calc(100% - 1rem) 52%, calc(100% - 0.7rem) 52%;
    background-size: 0.3rem 0.3rem; background-repeat: no-repeat;
  }
  :where(body.kit-forms) :where(select[multiple]) { background-image: none; padding-right: 0.65rem; }
  :where(body.kit-forms) :where(input, select, textarea, button, a):focus-visible { outline: 2px solid var(--accent-ring); outline-offset: 2px; }
  :where(body.kit-forms) :where([aria-invalid="true"]) { border-color: var(--bad); }
  :where(body.kit-forms) :where(fieldset) { border: 1px solid var(--line); border-radius: var(--radius); padding: 0.5rem 0.8rem; }
  :where(body.kit-forms) :where(.row) { display: flex; gap: 0.6rem; flex-wrap: wrap; align-items: center; }
  :where(body.kit-forms) :where(.row) > * { min-width: 0; max-width: 100%; }
  :where(body.kit-forms) :where(.row:has(> label:not(.row))) { align-items: flex-end; }

  /* Tabs for the sections of one record (console/_tabs.html, console/js/tabs.js): a row of links over a line, the
     chosen one underlined in the accent; a count beside a tab's name. Scrolls sideways on a phone, never wraps. */
  .tabs { display: flex; flex-direction: column; gap: 0.9rem; min-width: 0; }
  .tab-list {
    display: flex; gap: 0.25rem; border-bottom: 1px solid var(--line); overflow-x: auto; scrollbar-width: thin;
  }
  .tab-list[aria-orientation="vertical"] { flex-direction: column; border-bottom: 0; border-right: 1px solid var(--line); }
  .tab-list > .tab {
    display: inline-flex; align-items: center; gap: 0.4rem; padding: 0.5rem 0.8rem; margin-bottom: -1px;
    border-bottom: 2px solid transparent; color: var(--muted); text-decoration: none; white-space: nowrap;
    border-radius: 0.4rem 0.4rem 0 0;
  }
  .tab-list > .tab:hover { color: var(--fg); }
  .tab-list > .tab[aria-selected="true"] { color: var(--fg); border-bottom-color: var(--accent); font-weight: 600; }
  .tab-list > .tab:focus-visible { outline: 2px solid var(--accent-ring); outline-offset: -2px; }
  .tab-count {
    min-width: 1.4em; padding: 0 0.4em; border-radius: 999px; font-size: 0.75em; line-height: 1.5; text-align: center;
    background: var(--panel-2); color: var(--fg); font-variant-numeric: tabular-nums;
  }
  .tab-panel { min-width: 0; }
  .tab-panel:focus-visible { outline: 2px solid var(--accent-ring); outline-offset: 2px; border-radius: 0.3rem; }

  /* A refused form (console/_forms.html): the summary at the top, each field's error above its control and the
     control's edge, in the danger colour; the words say it too ("Error:"), so colour is never the only sign. */
  .form-errors {
    border: 1px solid var(--bad); border-left-width: 4px; border-radius: var(--radius); padding: 0.7rem 0.9rem;
    background: color-mix(in oklab, var(--bad) 8%, var(--panel)); margin: 0 0 1rem;
  }
  .form-errors:focus-visible { outline: 2px solid var(--accent-ring); outline-offset: 2px; }
  .form-errors-title { margin: 0 0 0.35rem; font-size: 1rem; }
  .form-errors ul { margin: 0; padding-left: 1.1rem; }
  .form-errors a { color: var(--bad); font-weight: 600; }
  .field { display: flex; flex-direction: column; gap: 0.3rem; margin: 0 0 0.9rem; min-width: 0; }
  .field > label { font-size: 0.9rem; }
  .field-check { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 0.45rem; }
  .field-check > :is(.field-hint, .field-error) { flex-basis: 100%; }
  .field-hint { margin: 0; color: var(--muted); font-size: 0.82rem; }
  .field-error { margin: 0; color: var(--bad); font-size: 0.85rem; font-weight: 600; }
  .field.is-invalid :is(input, select, textarea)[aria-invalid="true"] { border-color: var(--bad); box-shadow: inset 3px 0 0 var(--bad); }
}

/* The header's tools (console/base.html): the Light / Dark / System switch and the apps menu. */
.site-head-tools { justify-self: end; display: flex; align-items: center; gap: 0.5rem; min-width: 0; }
.site-head-tools .apps-menu { margin-left: 0; }
.theme-switch { display: inline-flex; align-items: center; gap: 1px; padding: 1px; border: 1px solid var(--line); border-radius: 999px; }
.theme-switch > button {
  appearance: none; display: inline-flex; align-items: center; justify-content: center; margin: 0;
  padding: 0.15rem 0.35rem; border: 0; border-radius: 999px; background: transparent; color: var(--muted);
  font: inherit; line-height: 1; cursor: pointer;
}
.theme-switch > button:hover { color: var(--fg); }
.theme-switch > button[aria-pressed="true"] { background: var(--panel-2); color: var(--fg); }
.theme-switch > button:focus-visible { outline: 2px solid var(--accent-ring); outline-offset: 1px; }
.theme-switch .i { display: block; }

/* Toasts (console/js/toast.js): a column at the bottom right, over the status bar; one on a phone's whole width.
   A level's colour is its edge and its border; the words stay the page's own colour. */
.toasts {
  position: fixed; right: 1rem; bottom: 2.75rem; z-index: 10001; display: flex; flex-direction: column;
  align-items: flex-end; gap: 0.5rem; width: min(26rem, calc(100vw - 2rem)); pointer-events: none;
}
.toast-stack { display: flex; flex-direction: column; align-items: stretch; gap: 0.5rem; width: 100%; }
.toast-stack:empty { display: none; }
.toast {
  pointer-events: auto; display: flex; align-items: flex-start; gap: 0.6rem; padding: 0.6rem 0.6rem 0.6rem 0.85rem;
  border: 1px solid var(--line); border-left: 4px solid var(--accent); border-radius: 0.6rem;
  background: var(--panel); color: var(--fg); box-shadow: var(--shadow); font-size: 0.9rem;
}
.toast.is-success { border-left-color: var(--ok); }
.toast.is-info { border-left-color: var(--accent); }
.toast.is-warning { border-color: var(--warn); border-left-color: var(--warn); }
.toast.is-error { border-color: var(--bad); border-left-color: var(--bad); }
.toast-msg { flex: 1 1 auto; min-width: 0; margin: 0.1rem 0 0; overflow-wrap: anywhere; }
.toast-undo {
  flex: 0 0 auto; margin: 0; padding: 0.15rem 0.55rem; border: 1px solid var(--line); border-radius: 0.45rem;
  background: transparent; color: var(--accent); font: inherit; font-weight: 600; cursor: pointer;
}
.toast-undo:hover { border-color: var(--accent-ring); }
.toast-close {
  flex: 0 0 auto; margin: 0; padding: 0 0.35rem; border: 0; border-radius: 0.35rem; background: none;
  color: var(--muted); font: inherit; font-size: 1.15rem; line-height: 1.3; cursor: pointer;
}
.toast-close:hover { color: var(--fg); }
.toast-undo:focus-visible, .toast-close:focus-visible { outline: 2px solid var(--accent-ring); outline-offset: 1px; }
.toast.is-leaving { opacity: 0; transform: translateY(0.25rem); }
@media (prefers-reduced-motion: no-preference) {
  .toast { animation: toast-in 160ms ease-out; transition: opacity 180ms ease, transform 180ms ease; }
  @keyframes toast-in { from { opacity: 0; transform: translateY(0.4rem); } }
}
@media (max-width: 40rem) {
  .toasts { right: 0.5rem; left: 0.5rem; width: auto; align-items: stretch; }
}

/* The customer header (console/_customer.html, AppShell.customer_header): the app menu, Help, the account and its
   switcher, Sign out -- in the page's sans-serif, not the operator header's monospace -- and on a phone the sidebar's
   drawer carries the app menu, Help and Sign out (the account and the theme stay in the header). Each control is at
   least 28px high (WCAG 2.2's 24px target), its focus ring the accent's. */
@layer kit {
  .customer-head {
    display: flex; align-items: center; gap: 0.35rem; min-width: 0;
    font: 500 0.84rem/1.3 ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  }
  .customer-menu { position: relative; min-width: 0; }
  .customer-menu > summary { list-style: none; }
  .customer-menu > summary::-webkit-details-marker { display: none; }
  .customer-menu-button, .customer-help, .customer-signout-button, .customer-account {
    display: inline-flex; align-items: center; gap: 0.35rem; min-height: 1.75rem; max-width: 100%;
    margin: 0; padding: 0.2rem 0.55rem; border: 1px solid transparent; border-radius: 8px;
    background: transparent; color: var(--fg); font: inherit; text-decoration: none; white-space: nowrap;
  }
  .customer-menu-button, .customer-help, .customer-signout-button { cursor: pointer; }
  .customer-menu-button:hover, .customer-help:hover, .customer-signout-button:hover,
  .customer-menu[open] > .customer-menu-button { background: var(--panel-2); border-color: var(--line); }
  .customer-menu-button:focus-visible, .customer-help:focus-visible, .customer-signout-button:focus-visible,
  .customer-menu-item:focus-visible { outline: 2px solid var(--accent-ring); outline-offset: 1px; }
  .customer-help, .customer-menu-button .i { color: var(--muted); }
  .customer-help:hover { color: var(--fg); }
  .customer-account-name, .customer-app-name { min-width: 0; max-width: 16rem; overflow: hidden; text-overflow: ellipsis; }
  .customer-accounts .customer-account-name { font-weight: 650; }
  .customer-chevron { flex: 0 0 auto; transition: transform 120ms ease; }
  .customer-menu[open] .customer-chevron { transform: rotate(180deg); }
  .customer-signout { margin: 0; }
  .customer-signout-button { border-color: var(--line); }
  .customer-menu-panel {
    position: absolute; right: 0; top: calc(100% + 0.35rem); z-index: var(--z-overlay, 400);
    width: max-content; min-width: 14rem; max-width: min(22rem, calc(100vw - 1rem));
    max-height: min(70vh, 32rem); overflow-y: auto; overscroll-behavior: contain;
    padding: 0.35rem; border: 1px solid var(--line); border-radius: 10px; background: var(--panel);
    box-shadow: var(--shadow); color: var(--fg);
  }
  .customer-menu-person { margin: 0 0 0.3rem; padding: 0.3rem 0.5rem 0.45rem; border-bottom: 1px solid var(--line);
    color: var(--muted); font-size: 0.8rem; overflow-wrap: anywhere; }
  .customer-menu-label { margin: 0.35rem 0 0.15rem; padding: 0 0.5rem; color: var(--muted);
    font-size: 0.7rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; }
  .customer-menu-list { list-style: none; margin: 0; padding: 0; }
  .customer-switch { margin: 0; }
  .customer-menu-item {
    display: flex; align-items: center; gap: 0.45rem; width: 100%; min-height: 2rem; margin: 0;
    padding: 0.3rem 0.5rem 0.3rem 1.65rem; border: 0; border-radius: 6px; background: transparent;
    color: var(--fg); font: inherit; text-align: left; text-decoration: none; cursor: pointer;
  }
  .customer-menu-item:hover { background: var(--panel-2); }
  .customer-menu-item.is-current { padding-left: 0.5rem; font-weight: 650; cursor: default; }
  .customer-menu-item.is-current .customer-tick { flex: 0 0 auto; width: 0.75rem; color: var(--accent); }
  span.customer-menu-item.is-current:hover { background: transparent; }
  .customer-menu-text { min-width: 0; overflow-wrap: anywhere; }
  .customer-menu-foot { margin-top: 0.3rem; padding-left: 0.5rem; border-top: 1px solid var(--line);
    border-radius: 0 0 6px 6px; color: var(--accent); }
  /* On a phone's drawer only. */
  .customer-drawer { display: none; flex: 0 0 auto; padding: 0.4rem 0.35rem; border-top: 1px solid var(--line); }
  .customer-drawer .home-nav-group-label { margin-top: 0.1rem; }
  .customer-drawer .home-nav-link .i { flex: 0 0 auto; }
  .customer-drawer-signout { margin: 0; display: flex; }
  .customer-drawer-signout > button {
    appearance: none; flex: 1 1 auto; display: flex; align-items: center; min-height: 2rem; margin: 0;
    padding: 0.38rem 0.55rem; border: 0; border-radius: 10px; background: transparent; color: var(--muted);
    font: inherit; font-size: 0.86rem; text-align: left; cursor: pointer;
  }
  .customer-drawer-signout > button:hover { color: var(--fg); background: color-mix(in oklab, var(--accent) 14%, transparent); }
  .customer-drawer-signout > button:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
  @media (max-width: 52rem) {
    .customer-drawer { display: block; }
    body.gui[data-nav-collapsed="1"] .customer-drawer { display: none; }
    body:has(.customer-drawer) .customer-head > :is(.customer-apps, .customer-help, .customer-signout) { display: none; }
    .customer-account-name { max-width: 9rem; }
    .customer-accounts .customer-menu-panel { position: fixed; top: 3rem; right: 0.5rem; left: 0.5rem; width: auto; max-width: none; }
  }
  @media (prefers-reduced-motion: reduce) {
    .customer-chevron { transition: none; }
  }

  /* The way back to the page of the fleet that opened this one (console/_backlinks.html, web.backlinks). */
  .kit-back { margin: 0 0 0.75rem; font-size: 0.86rem; }
  .kit-back-link {
    display: inline-flex; align-items: center; gap: 0.3rem; min-height: 1.75rem;
    color: var(--muted); text-decoration: none;
  }
  .kit-back-link:hover { color: var(--fg); text-decoration: underline; }
  .kit-back-link:focus-visible { outline: 2px solid var(--accent-ring); outline-offset: 1px; border-radius: 4px; }

  /* A setup checklist (console/_checklist.html): the progress, the steps, the next one set off with its action. */
  .checklist {
    display: flex; flex-direction: column; gap: 0.6rem; padding: 1rem 1.1rem;
    border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel);
  }
  .checklist-head { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; flex-wrap: wrap; }
  .checklist-title { margin: 0; font-size: 1.05rem; }
  .checklist-title:focus { outline: none; }
  .checklist-title:focus-visible { outline: 2px solid var(--accent-ring); outline-offset: 2px; }
  .checklist-progress { margin: 0; color: var(--muted); font-size: 0.85rem; font-variant-numeric: tabular-nums; }
  .checklist-bar { width: 100%; height: 0.5rem; accent-color: var(--accent); }
  .checklist-steps { list-style: none; margin: 0.25rem 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.35rem; }
  .checklist-step {
    display: flex; align-items: center; gap: 0.7rem; padding: 0.45rem 0.6rem;
    border: 1px solid transparent; border-radius: 10px;
  }
  .checklist-mark {
    flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
    width: 1.6rem; height: 1.6rem; border: 2px solid var(--line); border-radius: 999px;
    color: var(--muted); font-size: 0.8rem; font-weight: 700; font-variant-numeric: tabular-nums;
  }
  .checklist-step.is-done .checklist-mark { border-color: var(--ok); background: var(--ok); color: var(--on-accent); }
  .checklist-step.is-done .checklist-label { color: var(--muted); }
  .checklist-step.is-unknown .checklist-mark { border-style: dashed; color: var(--muted); }
  .checklist-step.is-next {
    border-color: var(--accent-ring); background: color-mix(in oklab, var(--accent) 8%, var(--panel));
  }
  .checklist-step.is-next .checklist-mark { border-color: var(--accent); color: var(--fg); }
  .checklist-step.is-next .checklist-label { font-weight: 650; }
  .checklist-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 0.15rem; }
  .checklist-label, .checklist-hint { margin: 0; overflow-wrap: anywhere; }
  .checklist-hint { color: var(--muted); font-size: 0.85rem; }
  .checklist-action { flex: 0 0 auto; }
  .checklist-restore { margin: 0; }
  @media (max-width: 40rem) {
    .checklist-step { flex-wrap: wrap; }
    .checklist-step.is-next .checklist-action { margin-left: 2.3rem; }
  }
}
/* What an Explorer table is for (`tables_read(describe=)`): prose, under its monospaced name. */
.inspect-desc { font-family: inherit; white-space: normal; max-width: 48rem; }
