/* hoster admin UI: a hand-written stylesheet, no build step (ADR-0021, ADR-0054).
 *
 * Colours are role tokens; pages and components never name a palette colour. Light mode is
 * Catppuccin Latte, dark mode Catppuccin Mocha, picked by prefers-color-scheme. Every text and
 * status colour meets 4.5:1 on the backgrounds it sits on (--bg, --surface, --inset and the
 * 10% *-tint of its own colour over them) in both flavours.
 *
 * Latte's own accent, blue, green, peach, red, teal and yellow fall short of 4.5:1 on its light
 * backgrounds (green and peach reach about 2.5:1 and 2.2:1, yellow 2:1), so the Latte tokens use
 * the same hues darkened until they pass; each is noted below. Mocha's colours are used as they
 * are. Its dimmest text is overlay2 (#9399b2), which only reaches 4.45:1 on surface0, so nothing
 * dim sits on surface0 (--hover); Latte's dimmest is subtext1 (#5c5f77), see ADR-0054.
 *
 * Fonts: JetBrains Mono (OFL, Latin subset, vendored in assets/) for everything machine-derived,
 * through .mono and the table, pill, KPI and code rules; system-ui for prose. The font URLs are
 * plain file names that the server rewrites to their hashed names (src/web/assets.rs).
 */

@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("jetbrains-mono-400.9498a2e109ca.woff2") format("woff2");
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("jetbrains-mono-500.17b79a17c3dc.woff2") format("woff2");
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("jetbrains-mono-600.5f07c7835171.woff2") format("woff2");
}

/* Catppuccin Latte. */
:root {
  --bg: #e6e9ef;          /* mantle: the page */
  --surface: #eff1f5;     /* base: cards, the header */
  --inset: #ffffff;       /* inputs, code and logs, lighter than the card they sit in */
  --hover: #dce0e8;       /* crust: hovered rows and ghost buttons */
  --border: #ccd0da;      /* surface0 */
  --divider: #dce0e8;     /* crust: lines inside a card */
  --input-border: #7c7f93; /* overlay2: 3:1 on input and card (surface1 is 1.8:1) */
  --text: #4c4f69;        /* text */
  --text-2: #54576e;      /* between text and subtext1 */
  --muted: #5c5f77;       /* subtext1: the dimmest text allowed (overlay2, subtext0 fail) */
  --accent: #7420e3;      /* mauve #8839ef darkened from 3.9:1 (also on its 12% tint) */
  --on-accent: #ffffff;
  --link: #0a52e0;        /* blue #1e66f5 darkened from 3.6:1 */
  --ok: #2c6e1d;          /* green #40a02b darkened from 2.5:1 */
  --progress: #0a52e0;    /* blue #1e66f5 darkened from 3.6:1 */
  --warn: #a53d01;        /* peach #fe640b darkened from 2.2:1 */
  --fail: #ba0d33;        /* red #d20f39 darkened from 3.8:1 */
  --p50: #116a6f;         /* teal #179299 darkened from 2.8:1 */
  --p95: #855511;         /* yellow #df8e1d darkened from 2:1 */
  color-scheme: light;
}

/* Catppuccin Mocha. */
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #1e1e2e;          /* base */
    --surface: #181825;     /* mantle */
    --inset: #11111b;       /* crust */
    --hover: #313244;       /* surface0 */
    --border: #313244;      /* surface0 */
    --divider: #26263a;
    --input-border: #6c7086; /* overlay0: 3:1 on input and card (surface1 is 2:1) */
    --text: #cdd6f4;        /* text */
    --text-2: #a6adc8;      /* subtext0 */
    --muted: #9399b2;       /* overlay2: the dimmest text allowed (overlay0/1 fail) */
    --accent: #cba6f7;      /* mauve */
    --on-accent: #11111b;   /* crust */
    --link: #89b4fa;        /* blue */
    --ok: #a6e3a1;          /* green */
    --progress: #89b4fa;    /* blue */
    --warn: #fab387;        /* peach */
    --fail: #f38ba8;        /* red */
    --p50: #94e2d5;         /* teal */
    --p95: #f9e2af;         /* yellow */
    color-scheme: dark;
  }
}

/* Tints: a status colour at about 10% over whatever is behind it, for pills and highlights. */
:root {
  --accent-tint: color-mix(in srgb, var(--accent) 12%, transparent);
  --ok-tint: color-mix(in srgb, var(--ok) 10%, transparent);
  --progress-tint: color-mix(in srgb, var(--progress) 10%, transparent);
  --warn-tint: color-mix(in srgb, var(--warn) 10%, transparent);
  --fail-tint: color-mix(in srgb, var(--fail) 10%, transparent);
  --neutral-tint: color-mix(in srgb, var(--muted) 10%, transparent);
  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --sans: system-ui, -apple-system, "Segoe UI", sans-serif;
  --radius-card: 10px;
  --radius-control: 8px;
  --radius-pill: 10px;
}

/* ---- Base ---------------------------------------------------------------------------------- */

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 14px/1.5 var(--sans);
}

a { color: var(--link); text-decoration: none; }
a:hover { text-decoration: underline; }

h1 { margin: 0 0 1rem; font-size: 26px; font-weight: 600; line-height: 1.25; letter-spacing: -0.01em; }
h2 { margin: 1.75rem 0 0.75rem; font-size: 16px; font-weight: 600; }
h3 { margin: 1.25rem 0 0.5rem; font-size: 14px; font-weight: 600; }
p { margin: 0 0 0.75rem; }

code, pre, .mono { font-family: var(--mono); }
code { font-size: 0.92em; overflow-wrap: anywhere; }
.mono { font-variant-numeric: tabular-nums; }

.muted { color: var(--muted); }
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---- Shell (ADR-0054): a 232 px sidebar beside the page, stacked above it when narrow ------- */

.shell {
  display: grid;
  grid-template-columns: 232px minmax(0, 1fr);
  min-height: 100vh;
}

.sidebar {
  position: sticky;
  top: 0;
  display: flex;
  flex-direction: column;
  gap: 22px;
  height: 100vh;
  overflow-y: auto;
  padding: 20px 12px;
  border-right: 1px solid var(--border);
  background: var(--surface);
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 8px;
  color: var(--text);
}
a.brand:hover { text-decoration: none; }
.brand-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  flex-shrink: 0;
  border-radius: var(--radius-control);
  background: var(--accent);
  color: var(--on-accent);
}
.brand-mark .icon { width: 18px; height: 18px; margin: 0; }
.brand-text { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
.brand-name { font-family: var(--mono); font-size: 15px; font-weight: 600; }
.brand-meta {
  overflow: hidden;
  color: var(--muted);
  font-family: var(--mono);
  font-size: 11px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nav { display: flex; flex-direction: column; gap: 2px; margin: 0; padding: 0; list-style: none; }
.nav a {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 38px;
  padding: 8px 10px;
  border-radius: 7px;
  color: var(--text-2);
  font-weight: 500;
}
.nav a .icon { width: 18px; height: 18px; margin: 0; }
.nav a:hover { background: var(--hover); color: var(--text); text-decoration: none; }
.nav a[aria-current="page"] { background: var(--hover); color: var(--text); }
.nav a[aria-current="page"] .icon { color: var(--accent); }
.nav-count {
  margin-left: auto;
  color: var(--text-2);
  font-family: var(--mono);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}
.nav-count-alert {
  padding: 1px 7px;
  border-radius: 9px;
  background: var(--fail);
  color: var(--on-accent);
  font-weight: 600;
}

/* The signed-in admin, at the bottom of the sidebar. */
.account {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 4px 8px;
  margin-top: auto;
  padding: 14px 0 0;
  border-top: 1px solid var(--border);
}
.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--border);
  color: var(--text);
  font-family: var(--mono);
  font-size: 14px;
  font-weight: 600;
}
.account-who { display: flex; flex-direction: column; min-width: 0; line-height: 1.3; }
.account-login { overflow: hidden; font-weight: 500; text-overflow: ellipsis; white-space: nowrap; }
.account-session {
  overflow: hidden;
  color: var(--muted);
  font-family: var(--mono);
  font-size: 10.5px;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.icon-button {
  width: 44px;
  min-height: 44px;
  padding: 0;
  border-color: var(--border);
  color: var(--text-2);
}
.icon-button .icon { width: 18px; height: 18px; margin: 0; }
.account-everywhere {
  grid-column: 1 / -1;
  justify-self: start;
  min-height: 28px;
  padding: 0 6px;
  font-size: 12px;
}

.content { min-width: 0; padding: 28px 32px 48px; }

/* ---- Page header: a ~/path breadcrumb, the h1 and the page's actions ----------------------- */

.page-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  margin: 0 0 22px;
}
.page-title { min-width: 0; }
.crumb {
  margin: 0;
  color: var(--muted);
  font-family: var(--mono);
  font-size: 12px;
  overflow-wrap: anywhere;
}
.crumb a {
  color: var(--text-2);
  text-decoration: underline;
  text-decoration-color: var(--input-border);
  text-underline-offset: 2px;
}
.crumb a:hover { color: var(--link); }
.page-head h1 { margin: 4px 0 0; overflow-wrap: anywhere; }
.page-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.page-actions:empty { display: none; }

@media (max-width: 760px) {
  /* The content row takes any spare height, so the sidebar keeps its natural one. */
  .shell { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto 1fr; }
  .sidebar {
    position: static;
    height: auto;
    gap: 14px;
    padding: 14px 16px;
    border-right: 0;
    border-bottom: 1px solid var(--border);
  }
  .nav { flex-direction: row; flex-wrap: wrap; gap: 4px; }
  .nav a { min-height: 36px; padding: 6px 10px; }
  .nav-count { margin-left: 2px; }
  /* One row: who, then both log-out actions. */
  .account { grid-template-columns: auto minmax(0, 1fr) auto auto; margin-top: 0; padding-top: 12px; }
  .account-everywhere { grid-column: 3; grid-row: 1; min-height: 44px; }
  .account .icon-button { grid-column: 4; grid-row: 1; }
  .content { padding: 20px 16px 40px; }
}

/* ---- Public pages (sign in): one centred card, no shell ------------------------------------ */

.public {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  padding: 24px 16px;
}
.auth-card {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 4px;
  width: 100%;
  max-width: 400px;
  padding: 28px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface);
}
.auth-card .brand { padding: 0; margin: 0 0 18px; }
.auth-card h1 { margin: 0 0 12px; font-size: 22px; }
.auth-card p { color: var(--text-2); }
.auth-card .button { margin-top: 8px; }

/* ---- Cards ---------------------------------------------------------------------------------- */

.card {
  margin: 0 0 1.25rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--surface);
}
.card-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
}
.card-head h2 { margin: 0; font-size: 14px; }
.card-body { padding: 14px 18px; }
.card-foot { padding: 11px 18px; border-top: 1px solid var(--divider); color: var(--muted); font-size: 12px; }

/* A wide table scrolls inside its card (or on its own), never the page. Positioned, so the
   visually hidden header labels inside are contained (and clipped) by the scroller instead of
   widening the page. */
.table-scroll { position: relative; max-width: 100%; overflow-x: auto; margin: 0 0 1.25rem; }
.table-scroll > table { margin: 0; }
.card .table-scroll { margin: 0; }

/* ---- Tables --------------------------------------------------------------------------------- */

table { width: 100%; border-collapse: collapse; }

th {
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  color: var(--muted);
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-align: left;
  text-transform: uppercase;
  white-space: nowrap;
}
th[scope="row"] {
  vertical-align: top;
  color: var(--text);
  font-size: 13px;
  letter-spacing: normal;
  text-transform: none;
  white-space: normal;
}
td {
  padding: 11px 14px;
  border-bottom: 1px solid var(--divider);
  font-size: 13px;
  vertical-align: top;
}
tbody tr:last-child > *, tbody:last-child tr:last-child > * { border-bottom: 0; }
/* Short identifiers in cells stay on one line; long ones (refs, full digests, image
   references) carry class="wrap" so they break instead of widening the table past its card. */
td code { white-space: nowrap; overflow-wrap: normal; }
td code.wrap { white-space: normal; overflow-wrap: anywhere; }
td.num, th.num { text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums; }

/* A table that is its own card (pages that do not wrap it in one yet). */
table.list {
  margin: 0 0 1.25rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  border-collapse: separate;
  border-spacing: 0;
  background: var(--surface);
}
.card table.list { margin: 0; border: 0; border-radius: 0; background: none; }
/* Wrapped in a scroller, the scroller is the card, so a wide table scrolls inside its frame. */
.table-scroll:has(> table.list) {
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--surface);
}
.card .table-scroll:has(> table) { border: 0; border-radius: 0; background: none; }
.table-scroll > table.list { border: 0; border-radius: 0; background: none; }

/* ---- Buttons -------------------------------------------------------------------------------- */

button, .button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  min-height: 36px;
  padding: 0 14px;
  border: 1px solid var(--input-border);
  border-radius: var(--radius-control);
  background: transparent;
  color: var(--text);
  font: 500 14px/1.2 var(--sans);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
button:hover, .button:hover { background: var(--hover); text-decoration: none; }
button .icon, .button .icon { margin-inline-end: 0; }

/* The page's main action: accent, and a 44 px target. */
.primary, button.primary {
  min-height: 44px;
  padding: 0 16px;
  border-color: var(--accent);
  background: var(--accent);
  color: var(--on-accent);
  font-weight: 600;
}
.primary:hover, button.primary:hover { background: color-mix(in srgb, var(--accent) 88%, var(--text)); }

.ghost, button.ghost { border-color: transparent; background: transparent; color: var(--text-2); }
.ghost:hover, button.ghost:hover { background: var(--hover); color: var(--text); }

.danger, button.danger { border-color: var(--fail); color: var(--fail); }
.danger:hover, button.danger:hover { background: var(--fail-tint); }

button:disabled { opacity: 0.6; cursor: not-allowed; }

.actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }

/* ---- Forms ---------------------------------------------------------------------------------- */

input, textarea {
  min-height: 36px;
  padding: 7px 10px;
  border: 1px solid var(--input-border);
  border-radius: var(--radius-control);
  background: var(--inset);
  color: var(--text);
  font: 14px/1.4 var(--sans);
}
::placeholder { color: var(--muted); opacity: 1; }
input[type="checkbox"] { min-height: 0; accent-color: var(--accent); }
input[type="file"] { padding: 5px 8px; }
input[type="file"]::file-selector-button {
  margin-inline-end: 10px;
  padding: 3px 10px;
  border: 1px solid var(--input-border);
  border-radius: 6px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  cursor: pointer;
}
input:focus, textarea:focus { border-color: var(--accent); outline: 2px solid var(--accent-tint); outline-offset: 0; }
input:focus-visible, textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
label { color: var(--text-2); }

.inline-form { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin: 0 0.25rem 0.25rem 0; }

/* ---- Status pills (src/web/ui.rs, Tone) ------------------------------------------------------ */

.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
  padding: 1px 8px;
  border-radius: var(--radius-pill);
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  line-height: 1.5;
  white-space: nowrap;
}
.pill .icon { width: 1em; height: 1em; margin: 0; vertical-align: 0; }
.pill-ok { background: var(--ok-tint); color: var(--ok); }
.pill-progress { background: var(--progress-tint); color: var(--progress); }
.pill-warn { background: var(--warn-tint); color: var(--warn); }
.pill-fail { background: var(--fail-tint); color: var(--fail); }
.pill-neutral { background: var(--neutral-tint); color: var(--muted); }
/* A long message (a stack's flag) wraps at spaces instead of widening its table: inline, so the
   icon flows with the first word and every line keeps its tint. */
.pill-long {
  display: inline;
  padding: 1px 6px;
  line-height: 1.75;
  white-space: normal;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
.pill-long .icon { margin-inline-end: 0.3em; vertical-align: -0.125em; }
/* A cell holding one keeps room for a few words per line on a narrow screen. */
th:has(> .pill-long), td:has(> .pill-long) { min-width: 11rem; }

/* ---- Meters (src/web/ui.rs, Meter): an SVG bar whose geometry is attributes ----------------- */

/* Rounded in CSS: the viewBox stretches to the meter's width, which would stretch an rx too. */
.meter { display: block; width: 100%; height: 6px; border-radius: 3px; overflow: hidden; }
.meter-track { fill: var(--border); }
.meter-fill { fill: var(--muted); }
.meter-ok .meter-fill { fill: var(--ok); }
.meter-progress .meter-fill { fill: var(--progress); }
.meter-warn .meter-fill { fill: var(--warn); }
.meter-fail .meter-fill { fill: var(--fail); }

/* ---- KPI tiles ------------------------------------------------------------------------------ */

.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin: 0 0 1.25rem; }
.kpi {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--surface);
}
.kpi-label { color: var(--muted); font-family: var(--mono); font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; }
.kpi-value { font-family: var(--mono); font-size: 21px; font-weight: 600; font-variant-numeric: tabular-nums; }
.kpi-sub { color: var(--text-2); font-family: var(--mono); font-size: 11px; }
.kpi dd { margin: 0; overflow-wrap: anywhere; }
.kpi-ok .kpi-value { color: var(--ok); }
.kpi-progress .kpi-value { color: var(--progress); }
.kpi-warn .kpi-value { color: var(--warn); }
.kpi-fail .kpi-value { color: var(--fail); }

/* ---- Flash messages ------------------------------------------------------------------------- */

#flash:empty { display: none; }
.flash {
  margin: 0 0 1rem;
  padding: 0.6rem 0.85rem;
  border: 1px solid var(--border);
  border-left-width: 3px;
  border-radius: var(--radius-control);
  background: var(--surface);
  overflow-wrap: anywhere;
}
.flash-info { border-left-color: var(--progress); background: var(--progress-tint); }
.flash-success { border-left-color: var(--ok); background: var(--ok-tint); }
.flash-error { border-left-color: var(--fail); background: var(--fail-tint); }

/* ---- Container logs (ADR-0044): the stack's logs tab and a leftover's log page --------------
   One bordered box: a mono toolbar of chips and GET options, the log one block per line with
   stderr set apart, and a footer whose line count is a CSS counter over the streamed lines. */

.log-view {
  counter-reset: log-line;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--inset);
  overflow: hidden;
}
.log-toolbar {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  font: 12px/1.4 var(--mono);
}
.log-choices, .log-options, .log-since { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.log-options { gap: 8px 16px; }
.log-label { color: var(--muted); }
.log-chip, .log-preset {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 30px;
  padding: 0 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
  color: var(--text-2);
}
.log-preset { min-height: 28px; padding: 0 8px; }
.log-chip:hover, .log-preset:hover { background: var(--hover); color: var(--text); text-decoration: none; }
.log-chip[aria-current], .log-preset[aria-current] {
  border-color: var(--accent);
  background: var(--hover);
  box-shadow: inset 0 -2px 0 var(--accent);
  color: var(--text);
  font-weight: 600;
}
.log-chip-detail { color: var(--text-2); white-space: nowrap; }
.log-containers .log-chip { flex-wrap: wrap; gap: 0 6px; min-height: 28px; padding-block: 3px; overflow-wrap: anywhere; }
.dot.dot-s0 { background: var(--accent); }
.dot.dot-s1 { background: var(--progress); }
.dot.dot-s2 { background: var(--p50); }
.dot.dot-s3 { background: var(--p95); }
.log-toolbar input { min-height: 30px; padding: 4px 8px; font: 12px/1.4 var(--mono); }
.log-since input[type="text"] { width: 15rem; max-width: 100%; }
.log-tail input { width: 5.5rem; }
.log-options button { min-height: 30px; padding: 0 12px; font: 500 12px/1.2 var(--mono); }

/* The follow switch: a checkbox drawn as a track with a knob, green while on. */
.switch {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 30px;
  padding: 0 10px 0 8px;
  border: 1px solid var(--border);
  border-radius: 15px;
  color: var(--text-2);
  cursor: pointer;
}
.switch input { position: absolute; width: 1px; height: 1px; margin: 0; opacity: 0; }
.switch-track {
  position: relative;
  flex: none;
  width: 26px;
  height: 14px;
  border-radius: 7px;
  background: var(--border);
  box-shadow: inset 0 0 0 1px var(--muted);
}
.switch-track::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--text-2);
}
.switch:has(input:checked) { border-color: var(--ok); background: var(--ok-tint); color: var(--ok); }
.switch input:checked + .switch-track { background: var(--ok); box-shadow: none; }
.switch input:checked + .switch-track::after { left: 14px; background: var(--inset); }
.switch:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 1px; }

.log {
  min-height: 12rem;
  max-height: 70vh;
  overflow: auto;
  margin: 0;
  padding: 8px 0;
  font: 12.5px/1.6 var(--mono);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.log:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.log-line { display: block; padding: 0 12px 0 9px; border-left: 3px solid transparent; counter-increment: log-line; }
.log-line time { margin-inline-end: 0.6em; color: var(--muted); }
.log-stderr { border-left-color: var(--fail); background: var(--fail-tint); }
.log-notice { display: block; padding: 4px 12px; color: var(--muted); font-style: italic; }
.log-foot {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
  margin: 0;
  padding: 8px 12px;
  border-top: 1px solid var(--border);
  color: var(--muted);
  font: 11px/1.4 var(--mono);
}
.log-foot code { color: var(--text-2); font-size: inherit; overflow-wrap: anywhere; }
.log-detail { white-space: nowrap; }
.log-key { display: inline-flex; align-items: center; gap: 6px; }
.log-key-swatch {
  width: 12px;
  height: 10px;
  border-left: 3px solid var(--fail);
  background: var(--fail-tint);
}
.log-count::before { content: counter(log-line); color: var(--text-2); }
.log-live { display: inline-flex; align-items: center; gap: 6px; }
.log-following { color: var(--ok); }
.log-ended { display: none; }
/* The stream's closing notice is the last thing it sends: it no longer follows. */
.log-panel:has(.log-notice) .log-live { display: none; }
.log-panel:has(.log-notice) .log-ended { display: inline; }
.log-empty { margin: 0; padding: 24px 12px; color: var(--muted); }
/* At phone width the toolbar's controls are touch targets. */
@media (max-width: 760px) {
  .log-chip, .log-preset, .log-containers .log-chip, .switch, .log-toolbar input, .log-options button { min-height: 44px; }
}

/* ---- Stack pages: the apply page, its plan and pre-flight, problems and the diff ------------
   `/apply` (src/web/stacks/apply.rs): the editor card and the aside wrap side by side, the aside
   below on narrow screens. The aside stays in view while a long editor scrolls; it sits in its
   own row, so sticking never takes it over the diff card under both. */

.dns-detail { display: block; margin-top: 0.25rem; font-size: 12px; }
.apply-layout { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 20px; margin: 0 0 20px; }
.apply-editor { flex: 999 1 560px; min-width: 0; margin: 0; }
.apply-aside { position: sticky; top: 16px; flex: 1 1 340px; min-width: 0; }
.apply-result { display: flex; flex-direction: column; gap: 16px; }
.apply-result > .card, .apply-result > .flash { margin: 0; }
.step-head { justify-content: flex-start; gap: 12px; padding-inline: 20px; }
.step-head h2 { font-size: 15px; }
.step-no {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 6px;
  background: var(--hover);
  color: var(--accent);
  font: 700 12px/1 var(--mono);
}
.apply-form { display: flex; flex-direction: column; gap: 14px; padding: 18px 20px; }
.apply-form textarea { width: 100%; min-height: 24rem; font: 13px/1.5 var(--mono); tab-size: 4; resize: vertical; }
.apply-form-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px 16px; }
.apply-upload { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; min-width: 0; font-size: 13px; }
.apply-upload input { max-width: 100%; font-size: 13px; }
.apply-form-foot .primary { padding-inline: 24px; }
.plan-empty { margin: 0; color: var(--text-2); font-size: 13px; line-height: 1.55; }
.plan-empty strong { color: var(--text); }

/* A plan: one mono line per thing that appears (+), changes (~), goes away (−) or stays (=). */
.plan {
  display: flex;
  flex-direction: column;
  gap: 9px;
  margin: 0;
  padding: 14px 18px;
  list-style: none;
  font: 12px/1.5 var(--mono);
}
.plan li { display: flex; gap: 8px; min-width: 0; }
.plan-mark { flex: none; width: 1ch; font-weight: 700; }
.plan-add .plan-mark { color: var(--ok); }
.plan-change .plan-mark { color: var(--progress); }
.plan-remove .plan-mark { color: var(--fail); }
.plan-keep .plan-mark { color: var(--muted); }
.plan-text { min-width: 0; color: var(--text-2); overflow-wrap: anywhere; }
.plan-text strong { color: var(--text); font-weight: 600; }
.plan-text a strong { color: var(--link); }
.plan-note { color: var(--muted); }
.plan-detail { display: block; color: var(--muted); }
.plan-detail code { color: var(--text-2); font-size: inherit; }

/* Pre-flight checks and problems: ✓ passed, ! a warning, ✗ a problem, each with its source line. */
.checks {
  display: flex;
  flex-direction: column;
  gap: 9px;
  margin: 0;
  padding: 14px 18px;
  list-style: none;
  font: 12px/1.5 var(--mono);
}
.checks + .checks { padding-top: 0; }
.checks li { display: flex; gap: 8px; min-width: 0; }
.check-mark { flex: none; width: 1ch; font-weight: 700; }
.check-ok .check-mark { color: var(--ok); }
.check-warn .check-mark { color: var(--warn); }
.check-fail .check-mark { color: var(--fail); }
.check-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; color: var(--text-2); overflow-wrap: anywhere; }
.problem-where { color: var(--muted); }
.problem-at { color: var(--text); font-weight: 600; }
.problem-path { color: var(--text-2); font-size: inherit; }
.problem-message { color: var(--text); }
.problem-source {
  margin: 2px 0 0;
  padding: 6px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--inset);
  color: var(--text);
  font-size: 12px;
  overflow-x: auto;
}
.flash .checks { padding: 4px 0 2px; }
.preflight-fail {
  border-color: color-mix(in srgb, var(--fail) 45%, var(--border));
  background: color-mix(in srgb, var(--fail) 7%, var(--surface));
}
.preflight-fail .card-head { border-bottom-color: color-mix(in srgb, var(--fail) 25%, var(--border)); }
.preflight-fail .card-head h2, .preflight-fail .card-note { color: var(--fail); }
.preflight-fail > .card-body { margin: 0; color: var(--text); font-size: 13px; }
.preflight-fail > .checks { padding-top: 0; }

/* The confirm form: full width under the aside's cards, a sentence card-foot in a re-resolve. */
.plan-confirm { display: flex; flex-direction: column; gap: 8px; margin: 0; }
.apply-result .plan-confirm button { width: 100%; }
.plan-hint { margin: 0; color: var(--muted); font: 11.5px/1.5 var(--mono); }
.apply-result .plan-hint { text-align: center; }
.plan-cancel { align-self: center; padding: 6px 10px; font: 12px/1.4 var(--mono); }
.reresolve .plan-confirm { align-items: flex-start; padding: 14px 18px; border-top: 1px solid var(--divider); }
.reresolve > p.card-body { margin: 0; font-size: 13px; }
.diff-card { margin: 0; }
.diff-card > p.card-body { margin: 0; font-size: 13px; }
.diff-card .diff { margin: 0; border: 0; border-radius: 0 0 var(--radius-card) var(--radius-card); }
.diff {
  margin: 0 0 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--inset);
  overflow-x: auto;
}
.diff-hunk { width: 100%; border-collapse: collapse; font: 12.5px/1.5 var(--mono); }
.diff-hunk + .diff-hunk { border-top: 1px dashed var(--border); }
.diff-hunk td { padding: 0 0.5rem; border: 0; font-size: inherit; white-space: pre; }
.diff-no { width: 3rem; color: var(--muted); text-align: right; user-select: none; }
.diff-sign { width: 1rem; user-select: none; }
.diff-add { background: var(--ok-tint); }
.diff-remove { background: var(--fail-tint); }
/* At phone width the cancel link and the upload input are touch targets. */
@media (max-width: 760px) {
  .plan-cancel { display: inline-flex; align-items: center; min-height: 44px; }
  .apply-upload input { min-height: 44px; }
}

/* Stacks list (src/web/stacks/list.rs): a status filter of links, then a grid of cards that is
   one column at narrow widths. */
.filters { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 18px; font-family: var(--mono); }
.filter {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 34px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: 17px;
  color: var(--text-2);
  font-size: 12px;
}
.filter:hover { background: var(--hover); color: var(--text); text-decoration: none; }
.filter[aria-current="page"] { border-color: var(--accent); background: var(--accent-tint); color: var(--text); font-weight: 600; }
.filter-count { color: var(--text-2); font-variant-numeric: tabular-nums; }
.filter[aria-current="page"] .filter-count { color: var(--text); }
.stacks-empty { margin: 0 0 18px; }
.stack-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(360px, 100%), 1fr));
  gap: 14px;
}
/* Managed containers whose stack is gone, under the cards. */
.card.leftovers { margin-top: 1.25rem; }
.stack-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 0;
  margin: 0;
  padding: 16px 18px;
  border-radius: 12px;
}
.stack-card p { margin: 0; }
.stack-card-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 10px; }
.stack-card-head h2 { min-width: 0; margin: 0; font: 600 16px/1.3 var(--mono); overflow-wrap: anywhere; }
.stack-card-head h2 a { color: var(--text); }
.stack-card-source { display: flex; flex-direction: column; gap: 4px; color: var(--text-2); font: 12px/1.6 var(--mono); }
.stack-card-source code { color: var(--p95); font-size: inherit; }
.stack-card-source .pill { font-size: 11px; }
.stack-card-repo { overflow-wrap: anywhere; }
.chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 0; list-style: none; }
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg);
  color: var(--text-2);
  font: 11px/1.4 var(--mono);
}
.dot { flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--muted); }
.dot-ok { background: var(--ok); }
.dot-progress { background: var(--progress); }
.dot-warn { background: var(--warn); }
.dot-fail { background: var(--fail); }
.chip-state { color: var(--muted); }
.chip-state-progress { color: var(--progress); }
.chip-state-warn { color: var(--warn); }
.chip-state-fail { color: var(--fail); }
.routes { display: flex; flex-wrap: wrap; gap: 4px 12px; margin: 0; padding: 0; list-style: none; color: var(--link); font: 12px/1.5 var(--mono); overflow-wrap: anywhere; }
.stack-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
  margin: auto 0 0;
  padding-top: 12px;
  border-top: 1px solid var(--divider);
  font-family: var(--mono);
}
p.stack-stats { font-size: 12px; }
.stack-stats div { display: flex; flex-direction: column; gap: 2px; }
.stack-stats dt { color: var(--muted); font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; }
.stack-stats dd { margin: 0; font-size: 15px; font-weight: 600; font-variant-numeric: tabular-nums; }
.stat-warn { color: var(--warn); }
.stat-fail { color: var(--fail); }
.add-stack {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 200px;
  padding: 20px;
  border: 1px dashed var(--input-border);
  border-radius: 12px;
  color: var(--text-2);
  text-align: center;
}
.add-stack:hover { background: var(--surface); text-decoration: none; }
.add-stack-mark {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 10px;
  background: var(--hover);
  color: var(--accent);
}
.add-stack-mark .icon { width: 20px; height: 20px; margin: 0; }
.add-stack-title { color: var(--text); font-weight: 600; }
.add-stack-hint { font: 12px/1.4 var(--mono); }

/* Stack header (src/web/stacks/frame.rs): breadcrumb, name and pill, a mono meta line and the
   actions, then the tab bar across the full width. */
.stack-head { align-items: flex-start; gap: 14px 16px; margin-bottom: 20px; }
.stack-head .page-title { display: flex; flex: 1 1 420px; flex-direction: column; gap: 8px; }
.stack-head .page-actions { padding-top: 22px; }
.stack-title { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.stack-title h1 { margin: 0; font: 600 26px/1.2 var(--mono); letter-spacing: -0.02em; overflow-wrap: anywhere; }
.stack-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 18px;
  margin: 0;
  color: var(--text-2);
  font: 12px/1.6 var(--mono);
}
.stack-meta code { color: var(--p95); font-size: inherit; }
.stack-meta .pill { font-size: 11px; }
.stack-meta-repo { overflow-wrap: anywhere; }
.stack-flag { margin: 0; }
/* min-width: 0 lets the bar shrink to the header, so the tablist scrolls instead of the page.
   The underline is an inset shadow, so nothing sticks out of the scroll box. */
.tabs { flex: 1 0 100%; min-width: 0; }
.tabs [role="tablist"] {
  display: flex;
  gap: 4px;
  overflow-x: auto;
  overflow-y: hidden;
  box-shadow: inset 0 -1px var(--border);
  font: 13px/1.2 var(--mono);
}
.tabs a { padding: 10px 14px 12px; color: var(--text-2); white-space: nowrap; }
.tabs a:hover { color: var(--text); text-decoration: none; }
.tabs a:focus-visible { outline-offset: -2px; }
.tabs a[aria-selected="true"] { box-shadow: inset 0 -2px var(--accent); color: var(--text); font-weight: 600; }
#stack-action-result:empty, #reresolve-result:empty { display: none; }
#reresolve-result .plan-card { margin: 0 0 1.25rem; }

/* Stack overview (src/web/stacks/overview.rs) */
.card-count, .card-note { color: var(--muted); font-family: var(--mono); font-size: 12px; font-weight: 400; }
.card > p.card-body { margin: 0; border-bottom: 1px solid var(--divider); font-size: 13px; }
.card > p.card-body:last-child { border-bottom: 0; }
.card-result:not(:empty) { padding: 0 18px 4px; }
.tag {
  display: inline-block;
  margin-left: 4px;
  padding: 1px 7px;
  border-radius: 4px;
  background: var(--accent-tint);
  color: var(--accent);
  font: 11px/1.5 var(--mono);
  white-space: nowrap;
}
.deploy-form { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; }
.deploy-form p { margin: 0; font-size: 13px; }
.deploy-fields { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 10px 16px; width: 100%; }
.deploy-fields label { display: flex; flex-direction: column; gap: 4px; font: 12px/1.4 var(--mono); }
.deploy-fields input { width: 100%; font: 13px/1.4 var(--mono); }
.apply-link { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; margin: 0 0 1.25rem; font-size: 13px; }
table.rejections { min-width: 1000px; }
table.services { min-width: 880px; }
/* Each service is its own tbody: its row, then its other containers as muted rows. */
table.services tbody + tbody > tr:first-child > * { border-top: 1px solid var(--divider); }
table.services tbody > tr:not(:last-child) > * { border-bottom: 0; }
table.services tbody > tr.row-muted > * { padding-top: 4px; }
.service-name { display: block; font-weight: 600; }
.service-container, .service-digest { display: block; margin-top: 2px; color: var(--muted); font: 11.5px/1.5 var(--mono); }
.row-muted td { color: var(--muted); font-size: 12px; }
.row-muted code { color: var(--muted); }
td.nowrap, .nowrap { white-space: nowrap; }
td.row-actions { text-align: right; white-space: nowrap; }
.card > p.card-error { border-left: 3px solid var(--fail); background: var(--fail-tint); }

/* The danger zone: the last card of the overview, its border and head tinted red. */
.danger-zone {
  border-color: color-mix(in srgb, var(--fail) 45%, var(--border));
  background: color-mix(in srgb, var(--fail) 4%, var(--surface));
}
.danger-zone .card-head { border-bottom-color: color-mix(in srgb, var(--fail) 25%, var(--border)); }
.danger-zone .card-head h2 { color: var(--fail); }
.danger-body { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 16px 32px; padding: 18px; }
.danger-what { display: flex; flex: 1 1 360px; flex-direction: column; gap: 8px; min-width: 0; }
.danger-what h3 { margin: 0; font-size: 14px; }
.danger-what p { margin: 0; color: var(--text-2); font-size: 13px; line-height: 1.5; }
.danger-what .muted { color: var(--muted); }
.volumes { display: flex; flex-direction: column; gap: 2px; margin: 0; padding: 0; list-style: none; font: 12px/1.6 var(--mono); overflow-wrap: anywhere; }
.danger-check { display: flex; align-items: center; gap: 10px; color: var(--text); font: 12px/1.4 var(--mono); }
.danger-check input { width: 16px; height: 16px; accent-color: var(--fail); }
.danger-confirm { display: flex; flex: 1 1 320px; flex-direction: column; gap: 8px; min-width: 0; }
.danger-confirm label { font: 12px/1.4 var(--mono); }
.danger-confirm strong { color: var(--text); }
.danger-row { display: flex; gap: 8px; }
.danger-row input { flex: 1; min-width: 0; min-height: 44px; font: 13px/1.4 var(--mono); }
.danger-row button.danger { min-height: 44px; }

/* Slowest routes: the p95 bar in the p95 colour unless the route is flagged slow. */
.slow-routes { display: flex; flex-direction: column; gap: 14px; margin: 0; list-style: none; font: 12px/1.5 var(--mono); }
.slow-routes li { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.slow-route-head { display: flex; justify-content: space-between; gap: 10px; }
.slow-route-name { min-width: 0; color: var(--text); overflow-wrap: anywhere; }
.slow-route-p95 { flex: none; color: var(--p95); font-weight: 600; font-variant-numeric: tabular-nums; }
.slowest .meter-neutral .meter-fill { fill: var(--p95); }
.slow-route-counts { display: flex; flex-wrap: wrap; gap: 2px 14px; margin: 0; color: var(--text-2); }
.slow-route-counts div { display: flex; gap: 5px; }
.slow-route-counts dt { color: var(--muted); }
.slow-route-counts dd { margin: 0; font-variant-numeric: tabular-nums; }
.slow-route-counts .pill { font-size: 11px; }

/* Routes and volumes, side by side where there is room. */
.card-pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 380px), 1fr)); gap: 0 16px; }
.card-pair > .card { min-width: 0; }
.route-rows, .volume-rows { display: flex; flex-direction: column; gap: 10px; margin: 0; list-style: none; font: 12px/1.6 var(--mono); }
.route-rows li { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; min-width: 0; }
.route-url { color: var(--link); overflow-wrap: anywhere; }
.route-arrow { color: var(--muted); }
.route-target { color: var(--text); }
.route-tags { display: inline-flex; flex-wrap: wrap; gap: 4px; }
.route-tags .tag { margin-left: 0; }
.route-tags .pill { font-size: 11px; }
.route-tls { text-decoration: none; }
.tag-ok { background: var(--ok-tint); color: var(--ok); }
.volume-rows { gap: 6px; }
.volume-rows li { overflow-wrap: anywhere; }
p.card-foot { margin: 0; }

@media (max-width: 760px) {
  .stack-head .page-actions { padding-top: 0; }
  .tabs a { padding: 10px 9px; }
  .danger-row { flex-wrap: wrap; }
  .danger-row input { flex-basis: 100%; }
}

/* Stack environment tab (src/web/stacks/environment.rs) */
table.env { min-width: 760px; }
table.env td { vertical-align: middle; }
.env-key { background: none; padding: 0; color: var(--text); font-weight: 500; }
.env-value { font-size: 12px; overflow-wrap: anywhere; }
.env-secret { color: var(--accent); font-size: 12px; }
.env-changed { display: block; margin-top: 2px; color: var(--muted); font: 11.5px/1.5 var(--mono); }
.env-type { margin-left: 0; }
.tag-neutral { background: var(--neutral-tint); color: var(--text-2); }
.env-service { font-size: 12px; color: var(--text-2); }
.env-service.muted { color: var(--muted); }
td.row-actions a, .row-button { margin-left: 10px; font: 12px/1.5 var(--mono); }
td.row-actions a { display: inline-block; padding: 4px 6px; border-radius: 6px; }
td.row-actions a:hover { background: var(--hover); text-decoration: none; }
.row-form { margin: 0; }
.row-button {
  min-height: 0;
  padding: 4px 6px;
  border: 0;
  border-radius: 6px;
  color: var(--link);
}
.row-button.row-danger { color: var(--fail); }
.row-button.row-danger:hover { background: var(--fail-tint); }
.secret-form { display: flex; flex-direction: column; align-items: flex-start; gap: 12px; }
.secret-form > p { margin: 0; font-size: 13px; }
.secret-fields { display: grid; grid-template-columns: minmax(200px, 1fr) minmax(0, 2fr); gap: 12px 16px; width: 100%; }
.secret-field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.secret-field label { font: 12px/1.4 var(--mono); }
.secret-name {
  display: flex;
  align-items: stretch;
  border: 1px solid var(--input-border);
  border-radius: var(--radius-control);
  background: var(--inset);
}
.secret-name:focus-within { border-color: var(--accent); outline: 2px solid var(--accent-tint); }
.secret-prefix { display: flex; align-items: center; padding: 0 0 0 10px; color: var(--muted); font: 13px/1.4 var(--mono); }
.secret-name input { flex: 1; min-width: 0; border: 0; background: transparent; padding-left: 1px; font: 13px/1.4 var(--mono); }
.secret-name input:focus { outline: 0; }
.secret-name input:focus-visible { outline: 0; }
.secret-name:has(input:focus-visible) { border-color: var(--accent); outline: 2px solid var(--accent); outline-offset: 1px; }
.secret-field textarea { width: 100%; min-height: 68px; font: 13px/1.45 var(--mono); resize: vertical; }
.confirm-box {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  margin: 0 0 14px;
  padding: 12px 14px;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--border));
  border-radius: var(--radius-control);
  background: var(--accent-tint);
  font-size: 13px;
}
.confirm-box p { margin: 0; }
.confirm-box ul.redeploy { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 0; list-style: none; }
.confirm-box ul.redeploy li { padding: 1px 8px; border-radius: var(--radius-pill); background: var(--neutral-tint); color: var(--text); font: 12px/1.5 var(--mono); }
.confirm-danger { border-color: color-mix(in srgb, var(--fail) 45%, var(--border)); background: var(--fail-tint); }
.confirm-danger button.danger { background: var(--inset); }
.confirm-danger button.danger:hover { background: color-mix(in srgb, var(--fail) 8%, var(--inset)); }
.confirm-danger .flash { margin: 0; }
.confirm-form { display: flex; flex-direction: column; gap: 6px; width: 100%; max-width: 560px; }
.confirm-form label { font: 12px/1.4 var(--mono); }
.confirm-form strong { color: var(--text); }
.card-result > .flash { margin: 0 0 14px; }
#delete-result:not(:empty) { padding-top: 14px; }

@media (max-width: 760px) {
  .secret-fields { grid-template-columns: minmax(0, 1fr); }
}

/* Stack deployments tab and a deployment's page (src/web/stacks/deployments.rs) */
table.deployments { min-width: 900px; }
table.deployments td { vertical-align: middle; }
.deploy-trigger { font-size: 12px; }
.deploy-commit { display: block; margin-top: 2px; color: var(--muted); font: 11.5px/1.5 var(--mono); }
.deploy-commit code { color: var(--p95); font-size: inherit; }
.deploy-repo { overflow-wrap: anywhere; }
.deploy-digests { font: 12px/1.6 var(--mono); }
.deploy-digests .digest { display: block; white-space: nowrap; }
.deploy-digests code { color: var(--text-2); font-size: inherit; }
.deploy-duration { max-width: 320px; font-size: 12px; }
.deploy-why { color: var(--muted); font: 12px/1.5 var(--mono); overflow-wrap: anywhere; }
.row-ghost { min-height: 30px; padding: 0 10px; font: 500 12px/1.2 var(--mono); }
#cancel-result:empty, #redeploy-result:empty { display: none; }
.deployment-title { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; min-width: 0; }
.deployment-title h2 { font: 600 15px/1.3 var(--mono); }
.deployment-actions { display: flex; flex-wrap: wrap; gap: 8px; }
dl.kv { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 6px 18px; margin: 0; font: 12px/1.6 var(--mono); }
dl.kv dt { color: var(--muted); }
dl.kv dd { margin: 0; min-width: 0; color: var(--text); overflow-wrap: anywhere; }
dl.kv code { font-size: inherit; }
dl.kv code.wrap { overflow-wrap: anywhere; }
table.events { min-width: 640px; }
table.events .shrink { width: 1%; white-space: nowrap; }

@media (max-width: 760px) {
  .row-ghost, .deployment-actions button, .row-button.row-danger,
  .apply-link .button, .actions .button { min-height: 44px; }
  dl.kv { grid-template-columns: minmax(0, 1fr); gap: 0; }
  dl.kv dd { margin-bottom: 8px; }
}

/* Dashboard (src/web/dashboard.rs): tiles, the warnings alert, the stacks table, certificates. */
.live-note { display: inline-flex; align-items: center; gap: 7px; color: var(--text-2); font: 12px/1.4 var(--mono); }
.dash-kpis { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
.alert h2.alert-title { margin: 0; font-size: 14px; }
.alert.alert-warn { border-color: color-mix(in srgb, var(--warn) 40%, var(--border)); background: color-mix(in srgb, var(--warn) 10%, var(--surface)); }
.alert.alert-warn > .icon { color: var(--warn); }
ul.warnings { display: flex; flex-direction: column; gap: 6px; margin: 4px 0 0; padding: 0; list-style: none; }
ul.warnings li { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; min-width: 0; }
ul.warnings li a { font-family: var(--mono); font-size: 13px; overflow-wrap: anywhere; }
.warning-detail { min-width: 0; color: var(--text-2); font: 12px/1.55 var(--mono); overflow-wrap: anywhere; }
.card-link { color: var(--link); font: 12px/1.4 var(--mono); white-space: nowrap; }
table.dash-stacks { min-width: 1060px; }
table.dash-stacks td, table.dash-stacks th[scope="row"] { vertical-align: middle; }
table.dash-stacks th, table.dash-stacks td { padding-inline: 10px; }
table.dash-stacks th:first-child, table.dash-stacks td:first-child { padding-left: 18px; }
table.dash-stacks th:last-child, table.dash-stacks td:last-child { padding-right: 18px; }
table.dash-stacks td.dash-restarts { min-width: 5.5rem; white-space: normal; }
td.dash-restarts .dash-sub { white-space: normal; }
table.dash-stacks td.num { white-space: nowrap; }
.dash-stack { font: 600 13px/1.4 var(--mono); }
.dash-flag { display: block; margin-top: 4px; }
th:has(> .dash-flag) { min-width: 12rem; }
.dash-flag .pill { font-size: 11px; }
.dash-sub { display: block; margin-top: 2px; color: var(--muted); font: 11.5px/1.5 var(--mono); white-space: nowrap; }
.dash-deploys { font: 12px/1.5 var(--mono); white-space: nowrap; }
.dash-last { min-width: 13rem; font-size: 12px; }
.dash-last a { font-family: var(--mono); }
.dash-last .pill { font-size: 11px; }
.dash-last .dash-ago { white-space: nowrap; }
.dash-other { margin: 0; line-height: 1.6; overflow-wrap: anywhere; }
.dash-other .mono { color: var(--text-2); }
.glance {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
  gap: 16px 28px;
  margin: 0;
  padding: 16px 18px;
  list-style: none;
}
.glance li { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 6px 12px; min-width: 0; }
.glance-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 4px 8px; grid-column: 1 / -1; min-width: 0; }
.glance-host { color: var(--text); font-size: 12.5px; overflow-wrap: anywhere; }
.glance-head .pill { font-size: 11px; }
.glance-left { color: var(--text-2); font: 12px/1.4 var(--mono); white-space: nowrap; }
.glance li > .glance-left.muted { grid-column: 1 / -1; color: var(--muted); }

/* System (src/web/system.rs): a version card beside the update card, then the host's facts. */
.system-row { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 16px; margin: 0 0 16px; }
.system-row > .card { margin: 0; min-width: 0; }
.eyebrow { color: var(--muted); font: 500 11px/1.4 var(--mono); letter-spacing: 0.06em; text-transform: uppercase; }
.eyebrow-progress { color: var(--progress); }
h2.eyebrow { margin: 0; }
.version-card { display: flex; flex: 1 1 320px; flex-direction: column; gap: 14px; padding: 18px 20px; }
.version-block { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.version-block + .version-block { padding-top: 14px; border-top: 1px solid var(--divider); }
.version-now { font: 700 30px/1.2 var(--mono); letter-spacing: -0.02em; }
.version-prev { color: var(--text-2); font: 600 16px/1.4 var(--mono); }
.version-meta { color: var(--text-2); font: 12px/1.6 var(--mono); overflow-wrap: anywhere; }
.version-meta code { color: inherit; font-size: inherit; }
.version-hint { margin: 4px 0 0; color: var(--muted); font-size: 12px; line-height: 1.55; }
.version-hint code { color: var(--text-2); }
.version-hint a, .card-foot a { text-decoration: underline; text-underline-offset: 2px; }
code.version-command { display: block; width: fit-content; max-width: 100%; margin: 4px 0 0; padding: 6px 10px; overflow-wrap: anywhere; border: 1px solid var(--border); border-radius: 6px; background: var(--inset); color: var(--text); }
.version-card > .flash { margin: 0; }
.update-card { display: flex; flex: 2 1 520px; flex-direction: column; }
.update-card:has(.update-offer) { border-color: color-mix(in srgb, var(--progress) 40%, var(--border)); }
.update-check { display: flex; flex: 1 1 auto; flex-direction: column; gap: 14px; padding: 18px 20px; }
.update-check > .flash { margin: 0; }
.update-idle { margin: 0; color: var(--text-2); font-size: 13px; line-height: 1.55; }
.update-offer { display: flex; flex-direction: column; gap: 14px; }
.update-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; }
.update-title { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.update-version { font: 700 24px/1.25 var(--mono); overflow-wrap: anywhere; }
.update-meta { color: var(--muted); font-size: 12px; font-weight: 400; }
.update-changelog { font: 12px/1.4 var(--mono); }
pre.release-notes {
  max-height: 14rem;
  margin: 0;
  overflow: auto;
  padding: 10px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
  background: var(--inset);
  color: var(--text-2);
  font: 12.5px/1.55 var(--mono);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.update-apply { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 10px 18px; margin: 0; }
.update-steps { flex: 1 1 240px; color: var(--text-2); font: 12px/1.5 var(--mono); }
.update-steps code { color: inherit; font-size: inherit; }
.update-blocked { flex: 1 1 240px; margin: 0; color: var(--warn); font-size: 12.5px; line-height: 1.5; }
.update-apply button { padding-inline: 18px; }
.update-note { margin: 0; color: var(--muted); font: 11.5px/1.5 var(--mono); }
.update-steps-list { display: flex; flex-direction: column; gap: 6px; margin: 0; padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius-control); background: var(--inset); font: 12px/1.5 var(--mono); list-style: none; overflow-wrap: anywhere; }
.update-steps-list code { color: inherit; font-size: inherit; }
.update-steps-list li { padding-left: 1.4em; text-indent: -1.4em; }
.step-done { color: var(--ok); }
.step-now { color: var(--progress); }
.host-card { max-width: 100%; }
dl.host-facts { display: grid; grid-template-columns: max-content minmax(0, 1fr); margin: 0; font: 12px/1.5 var(--mono); }
dl.host-facts dt, dl.host-facts dd { margin: 0; padding: 9px 18px; border-bottom: 1px solid var(--divider); }
dl.host-facts dt { color: var(--muted); }
dl.host-facts dd { min-width: 0; color: var(--text); overflow-wrap: anywhere; }
dl.host-facts dt:last-of-type, dl.host-facts dd:last-of-type { border-bottom: 0; }
.host-note { color: var(--muted); }

@media (max-width: 760px) {
  .version-card, .update-check { padding: 16px; }
  .version-now { font-size: 26px; }
  .update-meta { display: block; margin-top: 2px; }
  .update-apply button { width: 100%; }
  dl.host-facts dt, dl.host-facts dd { padding: 8px 16px; }
}

/* Certificates (src/web/certificates.rs) */
.page-help { max-width: 72rem; margin: -10px 0 18px; color: var(--muted); font-size: 12.5px; line-height: 1.55; }
.page-help code { color: var(--text-2); }
.page-help strong { color: var(--text-2); }
#cert-result:empty { display: none; }
/* The ACME tile's figure is a name, not a number. */
.cert-kpis .kpi:last-child .kpi-value { font-size: 15px; line-height: 1.9; }
/* An alert banner for the page's worst problem: the fail tint with a red rule. */
.alert {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 10px 14px;
  margin: 0 0 1.25rem;
  padding: 14px 16px;
  border: 1px solid color-mix(in srgb, var(--fail) 40%, var(--border));
  border-radius: var(--radius-card);
  /* Tinted from the card surface, not the page, so text, links and pills on it keep 4.5:1. */
  background: color-mix(in srgb, var(--fail) 10%, var(--surface));
}
/* A pill's own tint over the alert's would fall below 4.5:1 in light mode. */
.alert .pill-fail, .alert .pill-warn { background: var(--surface); }
.alert > .icon { width: 18px; height: 18px; margin: 1px 0 0; color: var(--fail); }
.alert-text { display: flex; flex: 1 1 0; flex-direction: column; gap: 4px; min-width: min(100%, 220px); }
.alert-dns:empty { display: none; }
.alert-dns { font-size: 12px; }
.alert-text p { margin: 0; }
.alert-title { color: var(--text); font-weight: 600; overflow-wrap: anywhere; }
.alert-detail { color: var(--text-2); font: 12px/1.55 var(--mono); overflow-wrap: anywhere; }
.alert-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.alert-actions .inline-form { margin: 0; }
.alert-actions button { min-height: 32px; padding: 0 12px; font: 500 12px/1.2 var(--mono); }
table.certificates { min-width: 1040px; }
table.certificates th, table.certificates td { padding-inline: 10px; }
table.certificates th:first-child, table.certificates td:first-child { padding-left: 18px; }
table.certificates th:last-child, table.certificates td:last-child { padding-right: 18px; }
table.certificates .cert-host { color: var(--text); font-weight: 500; }
td.cert-expiry { min-width: 9rem; font-family: var(--mono); font-size: 12px; }
.cert-expiry-head { display: flex; justify-content: space-between; gap: 10px; margin-bottom: 5px; white-space: nowrap; }
.cert-expiry-head span { color: var(--text-2); }
td.cert-status { min-width: 12rem; max-width: 17rem; }
/* The two row actions stack, so the table fits a laptop-width card. */
table.certificates td.row-actions { width: 1%; }
table.certificates td.row-actions .inline-form { display: flex; justify-content: flex-end; }
table.certificates td.row-actions .row-button { margin-left: 0; }
td.cert-nowrap { white-space: nowrap; }
.cert-error { display: block; margin-top: 4px; color: var(--fail); font: 11.5px/1.5 var(--mono); overflow-wrap: break-word; }
.cert-next { display: block; margin-top: 3px; color: var(--muted); font: 11.5px/1.5 var(--mono); }
td.cert-dns { min-width: 9rem; max-width: 15rem; }
td.row-actions .inline-form { margin: 0; }

@media (max-width: 760px) {
  .page-help { margin-top: -6px; }
  .alert-actions button { min-height: 44px; }
  table.certificates .row-button, .page-actions button { min-height: 44px; }
}

/* Settings (src/web/settings.rs): a grouped sub-nav beside one card per section, each field a
   row with its label and help on the left and the value or control on the right. */
.settings { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 24px; }
.settings-nav { display: flex; flex: 1 1 200px; flex-direction: column; gap: 14px; max-width: 260px; font: 13px/1.4 var(--mono); }
.settings-group { display: flex; flex-direction: column; gap: 2px; }
.settings-group-label { padding: 0 10px 4px; color: var(--muted); font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; }
.settings-group ul { display: flex; flex-direction: column; gap: 2px; margin: 0; padding: 0; list-style: none; }
.settings-group a { display: flex; gap: 8px; padding: 8px 10px; border-radius: 7px; color: var(--text-2); }
.settings-group a:hover { background: var(--hover); color: var(--text); text-decoration: none; }
.settings-group a[aria-current="page"] { background: var(--hover); color: var(--text); }
.settings-note { margin-left: auto; color: var(--text-2); font-size: 11px; font-variant-numeric: tabular-nums; }
.settings-body { display: flex; flex: 999 1 480px; flex-direction: column; gap: 16px; min-width: 0; }
.settings-card { margin: 0; }
.settings-head { padding: 16px 20px; border-bottom: 1px solid var(--border); }
.settings-head h2 { margin: 0; font-size: 16px; }
.settings-head .field-help { margin: 4px 0 0; }
.settings-head code { color: var(--text-2); }
.field { display: flex; flex-wrap: wrap; gap: 8px 32px; padding: 18px 20px; }
.field + .field { border-top: 1px solid var(--divider); }
.field-label { display: flex; flex: 1 1 240px; flex-direction: column; gap: 4px; min-width: 0; }
.field-name { color: var(--text); font-weight: 500; }
code.field-name { font-size: 13px; overflow-wrap: anywhere; }
.field-help { color: var(--muted); font-size: 12px; line-height: 1.5; }
.field-control { display: flex; flex: 2 1 320px; flex-direction: column; align-items: flex-start; gap: 8px; min-width: 0; }
.field-control input { width: 100%; max-width: 440px; font: 13px/1.4 var(--mono); }
.field-value { color: var(--text); font: 13px/1.5 var(--mono); overflow-wrap: anywhere; }
.field-value code { font-size: inherit; }
.field-note { color: var(--muted); font: 12px/1.5 var(--mono); }
.field-text { margin: 0; color: var(--text-2); font-size: 13px; line-height: 1.5; }
.field-env {
  padding: 1px 8px;
  border-radius: var(--radius-pill);
  background: var(--progress-tint);
  color: var(--progress);
  font: 11px/1.6 var(--mono);
  overflow-wrap: anywhere;
}
.field-env code { color: inherit; font-size: inherit; }
.field-actions { flex: 0 1 auto; flex-direction: row; flex-wrap: wrap; align-items: center; }
.field-actions .inline-form { margin: 0; }
.field-inline { flex-direction: row; flex-wrap: wrap; align-items: center; }
.field-inline input { flex: 1 1 220px; }
.field-empty { margin: 0; padding: 18px 20px; color: var(--muted); }
.registry-rows { margin: 0; padding: 0; list-style: none; }
.registry-user { color: var(--text-2); font-family: var(--mono); }
.settings-submit { display: flex; justify-content: flex-end; padding: 14px 20px; border-top: 1px solid var(--divider); }
.settings-card > .card-result:not(:empty) { padding: 0 20px; }
.settings-card > .card-result > .flash { margin: 0 0 16px; }
.ghost.row-danger { color: var(--fail); }
.ghost.row-danger:hover { background: var(--fail-tint); }
.settings-foot { padding: 12px 20px; overflow-wrap: anywhere; }
.settings-foot code { color: var(--text-2); }
/* The CA choice, drawn like radio cards; read-only, so there is no input. */
.choice-cards { display: flex; flex-direction: column; gap: 8px; width: 100%; margin: 0; padding: 0; list-style: none; }
.choice-card { display: flex; align-items: flex-start; gap: 12px; padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius-control); }
.choice-on { border-color: var(--accent); background: var(--bg); }
.choice-mark { flex: none; width: 14px; height: 14px; margin-top: 3px; border: 1.5px solid var(--input-border); border-radius: 50%; }
.choice-on .choice-mark { border-color: var(--accent); box-shadow: inset 0 0 0 2.5px var(--bg), inset 0 0 0 7px var(--accent); }
.choice-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.choice-label { color: var(--text); font-weight: 500; }
.choice-label .pill { margin-left: 6px; font-size: 11px; }
.choice-detail { color: var(--muted); font: 11px/1.5 var(--mono); overflow-wrap: anywhere; }

@media (max-width: 760px) {
  .settings { gap: 16px; }
  .settings-nav { flex-direction: row; flex-wrap: wrap; gap: 10px 16px; max-width: none; flex-basis: 100%; }
  .settings-group ul { flex-direction: row; flex-wrap: wrap; }
  .settings-group a { min-height: 36px; align-items: center; }
  .field { padding: 14px 16px; }
  .settings-head { padding: 14px 16px; }
  .field-actions { flex-basis: 100%; }
  .field-actions .row-ghost { min-height: 44px; }
  .field-inline button { min-height: 44px; }
}

/* ---- Icons (ADR-0053): an inline <svg> that <use>s a symbol of the sprite. It is sized to the
   text and drawn in currentColor, so it follows links, buttons, pills and dark mode. */
.icon {
  display: inline-block;
  width: 1.1em;
  height: 1.1em;
  margin-inline-end: 0.35em;
  vertical-align: -0.2em;
  flex-shrink: 0;
}
