/* ==========================================================================
   tasmofleet stylesheet, design v2.
   Tokens, fonts and metrics are the Claude Design v2 prototype's (binding
   source: design/v2/README.md, docs/spec/design-system.md),
   with the app's --color- prefix. Values are copied verbatim, oklch() included;
   there is no ramp generator.

   Theme selection: data-theme="light|dark" on <html> (theme.js resolves
   "system" from prefers-color-scheme); data-theme-auto is the no-JS fallback.
   Token names are the same in both themes.
   ========================================================================== */

/* ---- fonts: self-hosted Geist and Geist Mono (variable wght, SIL OFL 1.1, geist-OFL.txt) */
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("geist-latin-ext.woff2") format("woff2");
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
    U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("geist-latin.woff2") format("woff2");
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212,
    U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Geist Mono";
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url("geist-mono-latin-ext.woff2") format("woff2");
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
    U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Geist Mono";
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url("geist-mono-latin.woff2") format("woff2");
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212,
    U+2215, U+FEFF, U+FFFD;
}

/* ---- tokens that do not depend on the theme ----------------------------- */
:root {
  /* type */
  --font-sans: "Geist", ui-sans-serif, system-ui, sans-serif;
  --font-mono: "Geist Mono", ui-monospace, Menlo, monospace;
  --fs-base: 14px; /* body */
  --fs-h1: 22px; /* page title */
  --fs-h2-lg: 15px; /* page section and card headings */
  --fs-h2: 14px; /* sub headings */
  --fs-h2-sm: 13px; /* headings inside small cards */
  --fs-body: 13.5px; /* list rows, form text, controls */
  --fs-ui: 13px; /* buttons, nav, tabs, table cells */
  --fs-meta: 12.5px; /* secondary lines, crumbs */
  --fs-small: 12px; /* hints, field help, table headers */
  --fs-badge: 11.5px; /* badges, counters, pills */
  --fs-stat: 28px; /* stat tile number: 600 28px/1, tabular (measured in WP F4) */
  --lh-tight: 1.15; /* @kind other */
  --lh-body: 1.45; /* @kind other */
  --grid-cols: 12; /* @kind other */

  /* space: the prototype is not on a 4px grid; one token per pixel value its markup uses */
  --sp-1: 1px;
  --sp-2: 2px;
  --sp-3: 3px;
  --sp-4: 4px;
  --sp-5: 5px;
  --sp-6: 6px;
  --sp-7: 7px;
  --sp-8: 8px;
  --sp-9: 9px;
  --sp-10: 10px;
  --sp-11: 11px;
  --sp-12: 12px;
  --sp-14: 14px;
  --sp-16: 16px;
  --sp-18: 18px;
  --sp-20: 20px;
  --sp-22: 22px;
  --sp-24: 24px;
  --sp-28: 28px;
  --sp-32: 32px;
  --sp-36: 36px;
  --sp-40: 40px;

  /* shape */
  --r-control: 7px; /* buttons, inputs, selects, segmented controls */
  --r-card: 10px; /* sections, cards, tables */
  --card-gap: var(--sp-12); /* between sibling cards, both ways (device overview, pages of cards) */
  --r-panel: 12px; /* auth card, dialogs, menus */
  --r-banner: 9px;
  --r-code: 8px; /* pre, console, diff */
  --r-sm: 6px;
  --r-badge: 5px;
  --r-xs: 4px;
  --r-pill: 999px;
  --hair-w: 1px; /* borders and dividers */

  /* controls: one height per size */
  --ctl: 34px;
  --ctl-sm: 28px;
  --ctl-lg: 40px;
  --ctl-pad: 14px;
  --ctl-pad-sm: 10px;

  /* layout; --page-pad: without a size container, cqw is the viewport width with the scrollbar,
     which is what the prototype's root measures (its scrollbar sits inside the root) */
  --gutter: var(--sp-16);
  --container: 1640px;
  --page-pad: clamp(12px, 2.4cqw, 32px);

  /* layers, lowest to highest: the only z-index scale. Page content has none (auto). Values of 1 to 4
     inside one component (pinned cells, column handles) stay local and lie below --z-sticky.
     header.top is a stacking context of its own, so everything that must lie over the page content
     below the header (menus of the toolbar, rows and tables) has to rank under --z-header, and
     the header's own menus (--z-header-menu) only compete inside it. */
  --z-sticky: 10; /* @kind other: sticky table parts, bulk bar, save bar */
  --z-menu: 20; /* @kind other: toolbar and row menus, tooltips */
  --z-header: 30; /* @kind other: the top bar and the phone action bar */
  --z-header-menu: 40; /* @kind other: the top bar's menus (user menu) */
  --z-dialog: 1000; /* @kind other: dialogs and drawers (their own top layer, kept for fallbacks) */
  --z-toast: 1001; /* @kind other: toasts */

  /* values the prototype writes inline, the same in both themes */
  --backdrop: rgba(10, 14, 18, 0.5);
  --shadow-knob: 0 1px 2px rgba(0, 0, 0, 0.3);
  --shadow-bar: 0 -6px 20px rgba(0, 0, 0, 0.08);
  --color-console-rule: rgba(255, 255, 255, 0.08);
  --color-console-line: rgba(255, 255, 255, 0.14);
}

/* ---- light theme (default) --------------------------------------------- */
:root,
[data-theme="light"] {
  color-scheme: light;
  --color-bg: #f4f5f7;
  --color-surface: #fff;
  --color-surface-2: #f0f2f4;
  --color-surface-3: #e5e8ec;
  --color-border: #dfe3e7;
  --color-border-strong: #c2c9d0;
  --color-text: #13171c;
  --color-text-2: #48535e;
  --color-text-3: #5c6772;
  --color-accent: oklch(0.5 0.13 250);
  --color-accent-hover: oklch(0.44 0.13 250);
  --color-accent-bg: oklch(0.95 0.025 250);
  --color-accent-fg: oklch(0.45 0.13 250);
  --color-on-accent: #fff;
  --color-ok: oklch(0.63 0.14 155);
  --color-ok-fg: oklch(0.44 0.1 155);
  --color-ok-bg: oklch(0.95 0.035 155);
  --color-warn: oklch(0.76 0.14 75);
  --color-warn-fg: oklch(0.47 0.1 65);
  --color-warn-bg: oklch(0.96 0.045 85);
  --color-danger: oklch(0.58 0.19 27);
  --color-danger-fg: oklch(0.49 0.17 27);
  --color-danger-bg: oklch(0.96 0.025 27);
  --color-danger-solid: oklch(0.52 0.19 27);
  --color-neutral: #98a1ab;
  --color-neutral-fg: #4f5964;
  --color-neutral-bg: #eceff2;
  --color-term-bg: #12161b;
  --color-term-fg: #d3d9df;
  --color-term-dim: #8b95a1;
  --color-term-cmd: #93c3ff;
  --color-term-err: #ff9d8f;
  --color-grip-hover: color-mix(in oklab, var(--color-accent) 30%, transparent);
  --shadow-lg:
    0 14px 44px rgba(16, 24, 32, 0.18), 0 2px 6px rgba(16, 24, 32, 0.08);
}

/* ---- dark theme: system preference without JS -------------------------
   theme.js resolves "system" to data-theme="light|dark" and removes
   data-theme-auto; pages put data-theme-auto on <html> as the no-JS fallback.
   The --color-term-* tokens other than the background are not redefined. */
@media (prefers-color-scheme: dark) {
  :root[data-theme-auto] {
    color-scheme: dark;
    --color-bg: #0d1013;
    --color-surface: #14181c;
    --color-surface-2: #1a1f24;
    --color-surface-3: #242a31;
    --color-border: #262c33;
    --color-border-strong: #3a424b;
    --color-text: #e4e7ea;
    --color-text-2: #a9b2bb;
    --color-text-3: #939da7;
    --color-accent: oklch(0.7 0.12 250);
    --color-accent-hover: oklch(0.77 0.11 250);
    --color-accent-bg: oklch(0.27 0.05 250);
    --color-accent-fg: oklch(0.8 0.1 250);
    --color-on-accent: #0b1015;
    --color-ok: oklch(0.72 0.15 155);
    --color-ok-fg: oklch(0.8 0.13 155);
    --color-ok-bg: oklch(0.27 0.05 155);
    --color-warn: oklch(0.8 0.14 80);
    --color-warn-fg: oklch(0.85 0.12 85);
    --color-warn-bg: oklch(0.29 0.05 75);
    --color-danger: oklch(0.68 0.18 25);
    --color-danger-fg: oklch(0.8 0.13 25);
    --color-danger-bg: oklch(0.29 0.07 25);
    --color-danger-solid: oklch(0.55 0.17 25);
    --color-neutral: #6b7581;
    --color-neutral-fg: #b0b8c1;
    --color-neutral-bg: #242a31;
    --color-term-bg: #090c0f;
    --color-grip-hover: color-mix(
      in oklab,
      var(--color-accent) 30%,
      transparent
    );
    --shadow-lg: 0 14px 44px rgba(0, 0, 0, 0.6);
  }
}
/* ---- dark theme: explicit override ------------------------------------- */
:root[data-theme="dark"],
[data-theme="dark"] {
  color-scheme: dark;
  --color-bg: #0d1013;
  --color-surface: #14181c;
  --color-surface-2: #1a1f24;
  --color-surface-3: #242a31;
  --color-border: #262c33;
  --color-border-strong: #3a424b;
  --color-text: #e4e7ea;
  --color-text-2: #a9b2bb;
  --color-text-3: #939da7;
  --color-accent: oklch(0.7 0.12 250);
  --color-accent-hover: oklch(0.77 0.11 250);
  --color-accent-bg: oklch(0.27 0.05 250);
  --color-accent-fg: oklch(0.8 0.1 250);
  --color-on-accent: #0b1015;
  --color-ok: oklch(0.72 0.15 155);
  --color-ok-fg: oklch(0.8 0.13 155);
  --color-ok-bg: oklch(0.27 0.05 155);
  --color-warn: oklch(0.8 0.14 80);
  --color-warn-fg: oklch(0.85 0.12 85);
  --color-warn-bg: oklch(0.29 0.05 75);
  --color-danger: oklch(0.68 0.18 25);
  --color-danger-fg: oklch(0.8 0.13 25);
  --color-danger-bg: oklch(0.29 0.07 25);
  --color-danger-solid: oklch(0.55 0.17 25);
  --color-neutral: #6b7581;
  --color-neutral-fg: #b0b8c1;
  --color-neutral-bg: #242a31;
  --color-term-bg: #090c0f;
  --color-grip-hover: color-mix(in oklab, var(--color-accent) 30%, transparent);
  --shadow-lg: 0 14px 44px rgba(0, 0, 0, 0.6);
}

/* ==========================================================================
   Base
   ========================================================================== */
*,
*::before,
*::after {
  box-sizing: border-box;
}
html {
  -webkit-text-size-adjust: 100%;
  /* The scrollbar's room is kept on every page, so nothing moves sideways between a short and a long
     page (v0.10.1; 0.10.0 had dropped it for the empty strip it leaves right of the top bar on short
     pages with classic scrollbars, and the whole layout jumped on every page switch instead). */
  scrollbar-gutter: stable;
}
body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font: 400 var(--fs-base) / var(--lh-body) var(--font-sans);
  -webkit-font-smoothing: antialiased;
}
h1,
h2,
h3,
h4 {
  font-family: var(--font-sans);
  line-height: var(--lh-tight);
  letter-spacing: -0.015em;
  margin: 0 0 var(--sp-12);
}
h1 {
  font-size: var(--fs-h1);
  font-weight: 600;
}
h2 {
  font-size: var(--fs-h2-lg);
  font-weight: 600;
}
h3 {
  font-size: var(--fs-h2);
  font-weight: 600;
}
h4 {
  font-size: var(--fs-h2-sm);
  font-weight: 600;
}
p {
  margin: 0 0 var(--sp-12);
}
a {
  color: var(--color-accent-fg);
  text-underline-offset: 0.18em;
  text-decoration-thickness: 1px;
}
a:hover,
a.is-hover {
  text-decoration-thickness: 2px;
}
:focus-visible,
.is-focus {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}
::selection {
  background: color-mix(in srgb, var(--color-accent) 30%, transparent);
}
small,
.small {
  font-size: var(--fs-small);
}
.muted {
  color: var(--color-text-2);
}
.lead {
  color: var(--color-text-2);
  max-width: 70ch;
}
code,
pre,
kbd {
  font-family: var(--font-mono);
  font-size: 0.92em;
}
code {
  background: var(--color-surface-2);
  padding: 0.05em 0.3em;
  overflow-wrap: anywhere;
}
pre {
  background: var(--color-surface-2);
  border: var(--hair-w) solid var(--color-border);
  padding: var(--sp-12) var(--sp-16);
  overflow-x: auto;
  white-space: pre-wrap;
}
hr,
.hr {
  border: 0;
  border-top: var(--hair-w) solid var(--color-border);
  margin: var(--sp-24) 0;
}
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
[hidden] {
  display: none !important;
}
.ico {
  /* inline Lucide SVG: stroke="currentColor", stroke-width 2 */
  width: 16px;
  height: 16px;
  flex: none;
  vertical-align: -3px;
}

/* ==========================================================================
   Layout: top bar, page container, page header, columns
   ========================================================================== */

main {
  max-width: var(--container);
  margin: 0 auto;
  padding: var(--sp-16) var(--page-pad) 120px;
}

/* Page header: title left, at most one primary action right (more → secondary
   buttons or an Actions menu). The crumb sits above the title. */
.page-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "crumb crumb" "title actions";
  align-items: center;
  gap: var(--sp-4) var(--sp-16);
  margin: 0 0 var(--sp-24);
}
.page-head h1 {
  grid-area: title;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-8) var(--sp-12);
  margin: 0;
  min-height: var(--ctl);
}
.page-head .actions {
  grid-area: actions;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--sp-8);
}

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-8);
  align-items: center;
}
.actions form {
  margin: 0;
}

/* Columns: 12-column modular grid. */
.grid {
  /* NEW: explicit modular grid, children span with .span-N */
  display: grid;
  grid-template-columns: repeat(var(--grid-cols), minmax(0, 1fr));
  gap: var(--gutter);
}
.span-3 {
  grid-column: span 3;
}
.span-4 {
  grid-column: span 4;
}
.span-6 {
  grid-column: span 6;
}
.span-8 {
  grid-column: span 8;
}
.span-12 {
  grid-column: 1 / -1;
}
.cols {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0 var(--gutter);
  align-items: start;
}
@media (min-width: 68.75rem) {
  .cols {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .cols.wide-left {
    grid-template-columns: 7fr 5fr;
  }
}

/* ==========================================================================
   Buttons. Labels are centered (compact and in-table buttons); only .block
   buttons (full width) are flush left. One fixed height per size.
   ========================================================================== */
button,
.button {
  font: inherit;
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--fs-body);
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: var(--ctl);
  padding: 0 var(--ctl-pad);
  border-radius: var(--r-control);
  border: var(--hair-w) solid var(--color-border-strong);
  background: var(--color-surface);
  color: var(--color-text);
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  vertical-align: middle;
}
button:hover,
button.is-hover,
.button:hover,
.button.is-hover {
  background: color-mix(in srgb, var(--color-text) 7%, var(--color-surface));
  border-color: var(--color-text);
}
button:active,
button.is-active,
.button:active,
.button.is-active {
  background: color-mix(in srgb, var(--color-text) 14%, var(--color-surface));
}
button.primary,
.button.primary {
  background: var(--color-accent);
  border-color: var(--color-accent);
  color: var(--color-on-accent);
}
button.primary:hover,
button.primary.is-hover,
.button.primary:hover,
.button.primary.is-hover {
  background: var(--color-accent-hover);
  border-color: var(--color-accent-hover);
}
button.primary:active,
button.primary.is-active,
.button.primary:active,
.button.primary.is-active {
  background: var(--color-accent-hover);
  border-color: var(--color-accent-hover);
}
button.danger,
.button.danger {
  color: var(--color-danger-fg);
  border-color: var(--color-danger);
}
button.danger:hover,
button.danger.is-hover,
.button.danger:hover,
.button.danger.is-hover {
  background: var(--color-danger-bg);
  border-color: var(--color-danger);
}
button.danger:active,
button.danger.is-active,
.button.danger:active,
.button.danger.is-active {
  background: color-mix(in srgb, var(--color-danger) 22%, var(--color-surface));
}
button.ghost,
.button.ghost {
  background: transparent;
  border-color: transparent;
  color: var(--color-accent-fg);
}
button.ghost:hover,
button.ghost.is-hover,
.button.ghost:hover,
.button.ghost.is-hover {
  background: var(--color-surface-2);
  border-color: transparent;
}
button.sm,
.button.sm {
  height: var(--ctl-sm);
  padding: 0 var(--ctl-pad-sm);
  font-size: var(--fs-ui);
}
button.lg,
.button.lg {
  /* NEW: large size, e.g. sign-in */
  height: var(--ctl-lg);
  padding: 0 18px;
}
button.block,
.button.block {
  /* NEW: full-width button, flush-left label (Modernist) */
  display: flex;
  width: 100%;
  justify-content: flex-start;
}
button.icon,
.button.icon {
  /* NEW: icon-only square button; needs aria-label */
  width: var(--ctl);
  padding: 0;
}
button.icon.sm,
.button.icon.sm {
  width: var(--ctl-sm);
}
button[aria-pressed="true"],
.button.is-current {
  background: var(--color-text);
  border-color: var(--color-text);
  color: var(--color-surface);
}
button[disabled],
button[aria-disabled="true"],
.button[aria-disabled="true"],
.button.is-off {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}
button[aria-busy="true"] {
  cursor: progress;
}
button[aria-busy="true"]::after {
  content: "";
  width: 10px;
  height: 10px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%; /* a spinner glyph, not a corner */
  animation: ds-spin 0.8s linear infinite;
}
@keyframes ds-spin {
  to {
    transform: rotate(360deg);
  }
}
@media (prefers-reduced-motion: reduce) {
  button[aria-busy="true"]::after {
    animation: none;
  }
}

/* (i) info button: the help of a label or heading, text in a tooltip. */
button.info {
  width: 22px;
  height: 22px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--color-text-2);
  font-family: Georgia, "Times New Roman", serif;
  font-style: italic;
  font-weight: 700;
  font-size: 12px;
  position: relative;
  vertical-align: -5px;
}
button.info::before {
  content: "";
  position: absolute;
  inset: 3px;
  border: var(--hair-w) solid currentColor;
  border-radius: 50%; /* an icon shape, not a corner */
}
button.info > span {
  position: relative;
}
button.info:hover,
button.info.is-hover,
button.info:focus-visible,
button.info.is-focus {
  color: var(--color-accent);
  background: transparent;
}

/* ==========================================================================
   Forms
   ========================================================================== */
label {
  display: grid;
  gap: var(--sp-4);
  font-size: var(--fs-ui);
  font-weight: 600;
  color: var(--color-text);
}
label > .lbl {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-4);
}
label small,
.hint {
  font-size: var(--fs-small);
  font-weight: 400;
  color: var(--color-text-2);
}
input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
select,
textarea {
  font: inherit;
  font-weight: 400;
  font-size: var(--fs-body);
  color: var(--color-text);
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border-strong);
  border-radius: var(--r-control);
  height: var(--ctl);
  padding: 0 10px;
  min-width: 0;
  width: 100%;
}
textarea {
  height: auto;
  min-height: 84px;
  padding: 8px 10px;
  line-height: var(--lh-body);
}
select {
  appearance: none;
  padding-right: 30px;
  background-image:
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position:
    calc(100% - 15px) 50%,
    calc(100% - 10px) 50%;
  background-size: 5px 5px;
  background-repeat: no-repeat;
}
/* the native popup of a select takes its rows' colours from the options, not from the theme: a
   select with a transparent ground (the filter pills) left the popup white under light option
   text in the dark theme (v0.11.1 feedback 3). Every option paints the theme's surface and text. */
option,
optgroup {
  color: var(--color-text);
  background-color: var(--color-surface);
}
input::placeholder,
textarea::placeholder {
  color: var(--color-text-2);
  opacity: 1;
}
input:not([type="checkbox"]):not([type="radio"]):hover,
input:not([type="checkbox"]):not([type="radio"]).is-hover,
select:hover,
select.is-hover,
textarea:hover,
textarea.is-hover {
  border-color: var(--color-text);
}
input:not([type="checkbox"]):not([type="radio"]):focus-visible,
input:not([type="checkbox"]):not([type="radio"]).is-focus,
select:focus-visible,
select.is-focus,
textarea:focus-visible,
textarea.is-focus {
  outline: 2px solid var(--color-accent);
  outline-offset: -1px;
  border-color: var(--color-accent);
}
input[disabled],
select[disabled],
textarea[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}
/* a locked row's checkbox stays readable: the browser's own disabled look is nearly invisible on a light ground */
input[type="checkbox"][disabled] {
  opacity: 1;
  outline: 1px solid var(--color-text-3);
  outline-offset: -1px;
}
/* a locked checked box is drawn by hand: the native one greys its check mark into the ground in the light theme */
input[type="checkbox"][disabled]:checked {
  appearance: none;
  border-radius: 3px;
  outline: 0;
  background-color: var(--color-text-2);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 8.5l2.5 2.5L12 5.5' fill='none' stroke='white' stroke-width='2'/%3E%3C/svg%3E");
  background-size: 100% 100%;
}
input[aria-invalid="true"],
select[aria-invalid="true"],
textarea[aria-invalid="true"] {
  border-color: var(--color-danger);
  box-shadow: inset 3px 0 0 var(--color-danger);
}
input[type="checkbox"],
input[type="radio"] {
  accent-color: var(--color-accent);
  width: 18px;
  height: 18px;
  margin: 0;
}
label.inline {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-8);
  font-weight: 400;
  font-size: var(--fs-body);
}
fieldset {
  /* legend-style frame, same as a card */
  margin: var(--sp-24) 0 var(--sp-16);
  padding: var(--sp-20) var(--sp-16) var(--sp-16);
  border: var(--hair-w) solid var(--color-border);
  border-top: var(--hair-w) solid var(--color-border);
  display: grid;
  gap: var(--sp-12);
  min-width: 0;
}
legend {
  padding: 0 var(--sp-8);
  margin-left: calc(var(--sp-8) * -1);
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: var(--fs-ui);
}
.stack {
  display: grid;
  gap: var(--sp-16);
  max-width: 34rem;
}
.stack.wide {
  max-width: none;
}
/* cards stacked in a .stack: the stack's gap is the only space between them, the standard card gap
   (the cards' own margins would add up to about 70px) */
.stack:has(> section.card) {
  gap: var(--sp-32);
}
.stack > section.card {
  margin-bottom: 0;
}
.stack > section.card:not(:first-child) {
  margin-top: 0;
}
/* the row header of a comparison table keeps its words on one line and carries the row rule like the cells */
@media (min-width: 45rem) {
  table.dense tbody th[scope="row"] {
    white-space: nowrap;
    text-align: left;
    border-bottom: var(--hair-w) solid var(--color-border);
  }
}
.filters label.grow select {
  width: 100%;
}
.filters {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: var(--sp-12);
  margin: 0 0 var(--sp-16);
}
.filters label {
  flex: 1 1 10rem;
  max-width: 16rem;
}
.filters label.grow {
  flex: 3 1 16rem;
  max-width: 28rem;
}
.field-error,
small.error {
  /* field-level error text (small.error exists in app.css) */
  color: var(--color-danger-fg);
  font-size: var(--fs-small);
  font-weight: 600;
}
.hit {
  /* checkbox hit area in tables */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 28px;
  min-height: 28px;
  cursor: pointer;
}

/* ==========================================================================
   Cards: framed title on the top rule (legend style)
   ========================================================================== */
.card {
  position: relative;
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  padding: var(--sp-24) var(--sp-16) var(--sp-16);
}
section.card {
  margin: var(--sp-32) 0 var(--sp-20);
}
section.card:first-child {
  margin-top: var(--sp-12);
}
.card > h2:first-child,
.card > .card-head,
.card > details.m-fold.fold-h:first-child > summary,
.card > details.fold.fold-h:first-child > summary {
  position: absolute;
  top: calc(var(--hair-w) / -2);
  left: var(--sp-12);
  transform: translateY(-50%);
  max-width: calc(100% - 2 * var(--sp-12));
  margin: 0;
  padding: 0 var(--sp-8);
  background: var(--color-surface);
  font-family: var(--font-sans);
  font-size: var(--fs-h2-lg);
  font-weight: 800;
  letter-spacing: -0.01em;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.card > .card-head {
  display: flex;
  align-items: center;
  gap: var(--sp-8);
}
.card > *:last-child {
  margin-bottom: 0;
}
.card .card-kicker {
  /* NEW (from Modernist): small uppercase label above content */
  display: block;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-accent-fg);
  margin-bottom: var(--sp-4);
}

/* facts: label/value list (device identity) */
.facts {
  display: grid;
  grid-template-columns: minmax(7rem, max-content) minmax(0, 1fr);
  gap: 0;
  margin: 0;
  font-size: var(--fs-ui);
}
.facts dt,
.facts dd {
  padding: 6px 0;
  border-bottom: var(--hair-w) solid var(--color-border);
  margin: 0;
}
.facts dt {
  color: var(--color-text-2);
  padding-right: var(--sp-16);
}
.facts dt:last-of-type,
.facts dt:last-of-type + dd {
  border-bottom: 0;
}
.facts dd small {
  color: var(--color-text-2);
}

/* ==========================================================================
   Stat tiles (dashboard)
   ========================================================================== */
.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 0;
  list-style: none;
  margin: 0 0 var(--sp-12);
  padding: 0;
  border-left: var(--hair-w) solid var(--color-border);
}
.stats > li {
  display: flex;
}
.stat {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding: var(--sp-12) var(--sp-16) var(--sp-16);
  color: var(--color-text);
  text-decoration: none;
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-left: 0;
  border-top: 4px solid var(--tone, var(--color-neutral));
}
a.stat:hover,
a.stat.is-hover {
  background: var(--color-surface-2);
}
a.stat:hover .what,
a.stat.is-hover .what {
  color: var(--color-text);
  text-decoration: underline;
}
.stat .num {
  font-family: var(--font-sans);
  font-size: var(--fs-stat);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.03em;
}
.stat .what {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--color-text-2);
  font-size: var(--fs-ui);
  font-weight: 600;
}
.stat .what::before {
  content: attr(data-glyph);
  color: var(--tone-text, var(--color-text-2));
  font-weight: 800;
  width: 1em;
  text-align: center;
}
.stat.zero .num {
  color: var(--color-text-3);
}
.stat.zero {
  border-top-color: var(--color-border);
}
.tone-ok {
  --tone: var(--color-ok);
  --tone-text: var(--color-ok-fg);
}
.tone-warn {
  --tone: var(--color-warn);
  --tone-text: var(--color-warn-fg);
}
.tone-bad {
  --tone: var(--color-danger);
  --tone-text: var(--color-danger-fg);
}
.tone-info {
  --tone: var(--color-accent);
  --tone-text: var(--color-accent-fg);
}
.tone-neutral {
  --tone: var(--color-neutral);
  --tone-text: var(--color-neutral-fg);
}
.summary {
  margin: var(--sp-8) 0 0;
  font-size: var(--fs-ui);
}

/* ==========================================================================
   Status badge and tag. Always glyph + word + colour (CVD safe).
   ========================================================================== */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  white-space: nowrap;
  height: 20px;
  padding: 0 7px 0 6px;
  border-radius: var(--r-badge);
  font-size: var(--fs-small);
  font-weight: 700;
  line-height: 1;
  background: var(--color-neutral-bg);
  color: var(--color-neutral-fg);
  border: var(--hair-w) solid transparent;
  vertical-align: middle;
}
.badge::before {
  content: "\2013";
  font-weight: 800;
  width: 0.9em;
  text-align: center;
}
.badge.tone-ok {
  background: var(--color-ok-bg);
  color: var(--color-ok-fg);
}
.badge.tone-ok::before {
  content: "\2713";
}
.badge.tone-warn {
  background: var(--color-warn-bg);
  color: var(--color-warn-fg);
}
.badge.tone-warn::before {
  content: "!";
}
.badge.tone-bad {
  background: var(--color-danger-bg);
  color: var(--color-danger-fg);
}
.badge.tone-bad::before {
  content: "\2715";
}
.badge.tone-info {
  background: var(--color-accent-bg);
  color: var(--color-accent-fg);
}
.badge.tone-info::before {
  content: "\2192";
}
.badge.st-unknown::before {
  content: "?";
}
.badge.accent {
  /* NEW: the one accent badge (e.g. "recommended"); not a status */
  background: transparent;
  border-color: var(--color-accent);
  color: var(--color-accent-fg);
}
.badge.accent::before {
  content: "\2605";
}
.page-head .badge {
  height: 22px;
  font-size: var(--fs-ui);
}
.tag {
  display: inline-flex;
  align-items: center;
  height: 20px;
  padding: 0 6px;
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--color-text-2);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-badge);
  background: var(--color-surface);
  white-space: nowrap;
  text-indent: 0; /* inherited from pre.log > span (hanging indent), it pushed the text out of the box */
}

/* ==========================================================================
   Inline alerts: success (.notice), info (.notice.plain), warning, error.
   Glyph + colour + a 3px status rule on the left.
   ========================================================================== */
.notice,
.warning,
.error:not(span):not(small) {
  position: relative;
  display: block;
  margin: var(--sp-12) 0;
  padding: 10px var(--sp-12) 10px 40px;
  max-width: 76ch;
  font-size: var(--fs-body);
  border: var(--hair-w) solid;
  border-left: 4px solid;
  border-radius: var(--r-banner);
}
.notice::before,
.warning::before,
.error:not(span):not(small)::before {
  position: absolute;
  left: 12px;
  top: 11px;
  width: 18px;
  height: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: 12px;
  color: var(--color-surface);
}
.notice {
  border-color: var(--color-ok);
  border-left-color: var(--color-ok);
  background: var(--color-ok-bg);
  color: var(--color-ok-fg);
}
.notice::before {
  background: var(--color-ok);
  content: "\2713";
}
.notice.plain {
  border-color: var(--color-accent);
  border-left-color: var(--color-accent);
  background: var(--color-accent-bg);
  color: var(--color-accent-fg);
}
.notice.plain::before {
  background: var(--color-accent);
  content: "i";
  font-family: Georgia, serif;
  font-style: italic;
}
.warning {
  border-color: var(--color-warn);
  border-left-color: var(--color-warn);
  background: var(--color-warn-bg);
  color: var(--color-warn-fg);
}
.warning::before {
  background: var(--color-warn);
  content: "!";
}
.error:not(span):not(small) {
  border-color: var(--color-danger);
  border-left-color: var(--color-danger);
  background: var(--color-danger-bg);
  color: var(--color-danger-fg);
}
.error:not(span):not(small)::before {
  background: var(--color-danger);
  content: "\2715";
}
.notice a,
.warning a,
.error a {
  color: inherit;
  font-weight: 700;
}
span.error {
  color: var(--color-danger-fg);
  font-weight: 600;
}
span.error::before {
  content: "\2715\00a0";
}

/* ==========================================================================
   Empty state
   ========================================================================== */
.empty-state {
  display: grid;
  gap: var(--sp-4);
  justify-items: start;
  padding: var(--sp-20) var(--sp-16);
  background: var(--color-surface-2);
  border-left: var(--hair-w) solid var(--color-border);
  color: var(--color-text-2);
  font-size: var(--fs-ui);
}
.empty-state strong {
  color: var(--color-text);
  font-size: var(--fs-body);
}
.empty-state .button,
.empty-state button {
  margin-top: var(--sp-8);
}

/* ==========================================================================
   Tables. table.dense = the admin list. Row selection, sortable headers,
   row actions (at most two buttons, otherwise an Actions menu).
   ========================================================================== */
.table-scroll {
  overflow-x: auto;
}
table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-ui);
}
thead th {
  text-align: left;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--color-text-2);
  padding: 8px 10px;
  border-bottom: var(--hair-w) solid var(--color-border);
  white-space: nowrap;
  vertical-align: bottom;
}
td {
  padding: 6px 10px;
  border-bottom: var(--hair-w) solid var(--color-border);
  vertical-align: middle;
}
table.dense td {
  height: 44px;
}
tbody tr:hover td,
tbody tr.is-hover td {
  background: var(--color-surface-2);
}
tbody tr.is-selected td,
tbody tr:has(> td.sel input:checked) td {
  background: var(--color-accent-bg);
}
tbody tr.is-selected td:first-child,
tbody tr:has(> td.sel input:checked) td:first-child {
  box-shadow: inset 3px 0 0 var(--color-accent);
}
thead th.sel {
  vertical-align: middle;
}
td.rowacts {
  /* NEW: the row-actions cell; on phones it joins the first line */
  text-align: right;
  white-space: nowrap;
}
td.sel,
th.sel {
  width: 40px;
  padding-left: 6px;
  padding-right: 0;
}
td.p1 a,
td a:not(.button) {
  color: var(--color-text);
  font-weight: 600;
  text-decoration: none;
}
td.p1 a:hover,
td.p1 a.is-hover,
td a:not(.button):hover,
td a:not(.button).is-hover {
  color: var(--color-accent-fg);
  text-decoration: underline;
}
td.empty {
  padding: var(--sp-24) var(--sp-16);
  color: var(--color-text-2);
}
td.end,
th.end {
  text-align: right;
}
td.nowrap,
th.nowrap {
  white-space: nowrap;
}
td.hash code {
  display: inline-block;
  max-width: 14ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
}
/* sortable headers */
th .sortlink {
  color: inherit;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
th .sortlink:hover,
th .sortlink.is-hover {
  color: var(--color-text);
}
.sortmark {
  display: inline-block;
  width: 8px;
  height: 10px;
  opacity: 0.35;
  background:
    linear-gradient(to top right, transparent 50%, currentColor 50%) top left /
      50% 40% no-repeat,
    linear-gradient(to top left, transparent 50%, currentColor 50%) top right /
      50% 40% no-repeat,
    linear-gradient(to bottom right, transparent 50%, currentColor 50%) bottom
      left / 50% 40% no-repeat,
    linear-gradient(to bottom left, transparent 50%, currentColor 50%) bottom
      right / 50% 40% no-repeat;
}
.sortlink:hover .sortmark,
.sortlink.is-hover .sortmark {
  opacity: 0.7;
}
.sortlink.is-asc,
.sortlink.is-desc {
  color: var(--color-text);
}
.sortlink.is-asc .sortmark {
  opacity: 1;
  background:
    linear-gradient(to top right, transparent 50%, var(--color-accent) 50%) top
      left / 50% 40% no-repeat,
    linear-gradient(to top left, transparent 50%, var(--color-accent) 50%) top
      right / 50% 40% no-repeat;
}
.sortlink.is-desc .sortmark {
  opacity: 1;
  background:
    linear-gradient(to bottom right, transparent 50%, var(--color-accent) 50%)
      bottom left / 50% 40% no-repeat,
    linear-gradient(to bottom left, transparent 50%, var(--color-accent) 50%)
      bottom right / 50% 40% no-repeat;
}
/* row actions: at most two buttons; more go into details.rowmenu */
.row-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-4);
  white-space: nowrap;
}
.row-actions form {
  margin: 0;
}
/* table toolbar above a list */
.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-8);
  margin: 0 0 var(--sp-12);
}
.toolbar .muted {
  font-size: var(--fs-ui);
}
/* cell content helpers */
.chan {
  font-size: 11px;
  font-weight: 700;
  padding: 0 4px;
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-xs);
}
.chan-bad {
  color: var(--color-danger-fg);
  border-color: var(--color-danger);
}
.pager {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-4);
  margin-top: var(--sp-12);
  font-size: var(--fs-ui);
}
.pager .muted {
  margin-left: var(--sp-12);
}

/* ==========================================================================
   Power toggle: on / off / unknown. Ink, not a status colour: power is a
   state the user sets, not a health signal.
   ========================================================================== */
.relay-state {
  font-size: var(--fs-ui);
  color: var(--color-text-2);
}

/* ==========================================================================
   Overlays: menu, Actions menu, tooltip, popover, dialog. One step above the
   page: overlay surface, visible 1px border, shadow, in both themes.
   ========================================================================== */
.menu,
.rowmenu-body,
.popover,
.tooltip,
dialog.dlg {
  background: var(--color-surface);
  color: var(--color-text);
  border: var(--hair-w) solid var(--color-border-strong);
  border-radius: var(--r-panel);
  box-shadow: var(--shadow-lg);
}

.menu,
.rowmenu-body {
  min-width: 12rem;
  max-width: calc(100vw - 2 * var(--sp-12));
  padding: var(--sp-4) 0;
  display: grid;
}
.menu a,
.menu button,
.rowmenu-body a,
.rowmenu-body button {
  /* menu items are list rows: flush-left, full width */
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: var(--sp-8);
  width: 100%;
  height: 36px;
  padding: 0 var(--sp-12);
  border: 0;
  background: transparent;
  color: var(--color-text);
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: var(--fs-ui);
  text-decoration: none;
  white-space: nowrap;
}
.menu a:hover,
.menu a.is-hover,
.menu button:hover,
.menu button.is-hover,
.rowmenu-body a:hover,
.rowmenu-body a.is-hover,
.rowmenu-body button:hover,
.rowmenu-body button.is-hover {
  background: var(--color-surface-2);
  border: 0;
}
.menu a:active,
.menu a.is-active,
.rowmenu-body a:active,
.rowmenu-body a.is-active,
.rowmenu-body button:active,
.rowmenu-body button.is-active {
  background: var(--color-surface-3);
}
.menu a:focus-visible,
.menu a.is-focus,
.menu button:focus-visible,
.menu button.is-focus,
.rowmenu-body a:focus-visible,
.rowmenu-body a.is-focus,
.rowmenu-body button:focus-visible,
.rowmenu-body button.is-focus {
  outline-offset: -2px;
}
.menu a[aria-current="page"],
.rowmenu-body [aria-current="true"] {
  font-weight: 700;
  box-shadow: inset 3px 0 0 var(--color-accent);
}
.menu [aria-disabled="true"],
.rowmenu-body [disabled],
.rowmenu-body [aria-disabled="true"] {
  opacity: 0.45;
  pointer-events: none;
}
.rowmenu-body .danger,
.menu .danger {
  color: var(--color-danger-fg);
}
.menu hr,
.rowmenu-body hr {
  margin: var(--sp-4) 0;
  border: 0;
  border-top: var(--hair-w) solid var(--color-border);
}

.rowmenu-body form {
  margin: 0;
}
details.rowmenu {
  position: relative;
  display: inline-block;
}
details.rowmenu > summary {
  list-style: none;
}
details.rowmenu > summary::-webkit-details-marker {
  display: none;
}
details.rowmenu > summary::after {
  content: "";
  width: 5px;
  height: 5px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
}
details.rowmenu > summary.icon::after {
  display: none;
}
details.rowmenu[open] > summary {
  background: var(--color-text);
  border-color: var(--color-text);
  color: var(--color-surface);
}
details.rowmenu > .rowmenu-body {
  position: absolute;
  z-index: var(--z-menu);
  right: 0;
  top: calc(100% + 4px);
}
.tooltip {
  position: fixed;
  z-index: var(--z-menu);
  max-width: 32ch;
  padding: 6px 10px;
  font: 400 var(--fs-small) / 1.45 var(--font-sans);
  box-shadow: var(--shadow-lg);
  white-space: pre-line;
  pointer-events: none;
}
.tooltip.is-static {
  /* NEW, previews only: a tooltip in the flow */
  position: relative;
  display: inline-block;
}
.popover {
  /* NEW: generic overlay panel (column picker, filters) */
  padding: var(--sp-12) var(--sp-16);
  min-width: 16rem;
  display: grid;
  gap: var(--sp-8);
}
dialog.dlg {
  width: min(40rem, calc(100vw - 2 * var(--sp-16)));
  max-height: 85vh;
  padding: 0;
  overflow: hidden;
}
dialog.dlg[open] {
  display: flex;
  flex-direction: column;
}
dialog.dlg::backdrop,
.backdrop {
  background: var(--backdrop);
}
.backdrop {
  /* NEW, previews only: the ::backdrop as an element */
  position: absolute;
  inset: 0;
}
.dlg-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--sp-16);
  padding: var(--sp-12) var(--sp-16);
  border-bottom: var(--hair-w) solid var(--color-border);
}
.dlg-head h2 {
  margin: 0;
  font-size: var(--fs-h2-lg);
  font-weight: 800;
  display: flex;
  align-items: center;
  gap: var(--sp-8);
}
.dlg-body {
  padding: var(--sp-16);
  overflow: auto;
}
.dlg-foot {
  /* NEW: dialog actions, primary rightmost */
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-8);
  padding: var(--sp-12) var(--sp-16);
  border-top: var(--hair-w) solid var(--color-border);
}

/* ==========================================================================
   Bulk-action bar: sticks to the bottom while rows are selected
   ========================================================================== */
.bulkbar {
  position: sticky;
  bottom: var(--sp-16);
  z-index: var(--z-sticky);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-8);
  margin: var(--sp-16) 0 0;
  padding: var(--sp-8) var(--sp-12);
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border-strong);
  border-top: 2px solid var(--color-accent);
  box-shadow: var(--shadow-lg);
  border-radius: var(--r-panel);
}
.bulk-count {
  margin-right: auto;
  font-size: var(--fs-ui);
}
.bulk-count strong {
  font-family: var(--font-sans);
  font-weight: 800;
  font-size: var(--fs-h2-lg);
  margin-right: 2px;
}

/* ==========================================================================
   Tabs
   ========================================================================== */
.tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0;
  margin: 0 0 var(--sp-20);
  border-bottom: var(--hair-w) solid var(--color-border);
}
.tabs a {
  display: flex;
  align-items: center;
  height: 38px;
  padding: 0 var(--sp-16);
  margin-bottom: -1px;
  color: var(--color-text-2);
  font-weight: 600;
  font-size: var(--fs-body);
  text-decoration: none;
  border-bottom: 3px solid transparent;
}
.tabs a:hover,
.tabs a.is-hover {
  color: var(--color-text);
  background: var(--color-surface-2);
}
.tabs a:active,
.tabs a.is-active {
  background: var(--color-surface-3);
}
.tabs a:focus-visible,
.tabs a.is-focus {
  outline-offset: -2px;
}
.tabs a[aria-current="page"],
.tabs a[aria-selected="true"] {
  color: var(--color-text);
  border-bottom-color: var(--color-accent);
}
.tabs a[aria-disabled="true"] {
  opacity: 0.45;
  pointer-events: none;
}
.tabs .count {
  /* NEW: number after a tab label */
  margin-left: 6px;
  font-size: var(--fs-small);
  color: var(--color-text-2);
}

/* ==========================================================================
   Collapsible section. Collapsed = header only.
   details.fold: a section with a rule; details.m-fold: the app's phone fold
   (same look); .fold-h inside a card: the summary is the framed title.
   ========================================================================== */
details.fold,
details.m-fold {
  border-top: var(--hair-w) solid var(--color-border);
  margin: var(--sp-16) 0;
}
details.fold > summary,
details.m-fold > summary {
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  min-height: 40px;
  cursor: pointer;
  list-style: none;
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: var(--fs-body);
}
details.fold > summary::-webkit-details-marker,
details.m-fold > summary::-webkit-details-marker {
  display: none;
}
details.fold > summary::after,
details.m-fold > summary::after {
  /* one chevron app-wide (same as the navigation): down when closed, up when open */
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  margin: 0 4px 0 auto;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform 0.12s;
}
details.fold > summary:has(.meta)::after,
details.m-fold > summary:has(.meta)::after {
  margin-left: var(--sp-12);
}
details.fold[open] > summary::after,
details.m-fold[open] > summary::after {
  transform: translateY(2px) rotate(-135deg);
}
details.fold > summary:hover,
details.fold > summary.is-hover,
details.m-fold > summary:hover,
details.m-fold > summary.is-hover {
  background: var(--color-surface-2);
}
details.fold > summary .meta,
details.m-fold > summary .meta {
  /* NEW: right-aligned summary info */
  margin-left: auto;
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: var(--fs-ui);
  color: var(--color-text-2);
}
details.fold[open] > summary,
details.m-fold[open] > summary {
  margin-bottom: var(--sp-8);
}
/* the fold inside a card: the summary is the framed title */
.card > details.fold.fold-h:first-child,
.card > details.m-fold.fold-h:first-child {
  border: 0;
  margin: 0;
}
.card > details.fold.fold-h:first-child > summary,
.card > details.m-fold.fold-h:first-child > summary {
  min-height: 0;
  margin: 0;
}
.card > details.fold-h:first-child > summary::after {
  margin-left: var(--sp-8);
}
.card > details.fold.fold-h > summary > h2,
.card > details.m-fold.fold-h > summary > h2 {
  margin: 0;
  font: inherit;
  display: inline;
}
.card:has(> details.fold-h:first-child:not([open])) {
  /* collapsed: the same framed card, just without a body (one card component, folded or not) */
  padding-bottom: var(--sp-4);
  margin-bottom: var(--sp-16);
}
@media (prefers-reduced-motion: reduce) {
  details.fold > summary::after,
  details.m-fold > summary::after {
    transition: none;
  }
}

/* ==========================================================================
   Theme switch (NEW, preview pages only; theme.js)
   ========================================================================== */
.theme-switch {
  display: inline-flex;
  gap: 0;
}
.theme-switch button {
  margin-left: -1px;
}

/* ==========================================================================
   Utilities
   ========================================================================== */
.m-only {
  display: none;
}
.nowrap {
  white-space: nowrap;
}
.mono {
  font-family: var(--font-mono);
}

/* ==========================================================================
   Phones (up to 44.99rem, the prototype switches at 720px)
   ========================================================================== */
@media (max-width: 44.99rem) {
  :root {
    /* touch targets: every control 40px on phones (both sizes) */
    --ctl: 40px;
    --ctl-sm: 40px;
  }
  .menu a,
  .menu button,
  .rowmenu-body a,
  .rowmenu-body button,
  .tabs a {
    height: 40px;
  }
  .hit {
    min-width: 40px;
    min-height: 40px;
  }
  button.info {
    width: 40px;
    height: 40px;
    margin: -9px -9px -9px -6px;
  }
  button.info::before {
    inset: 12px;
  }
  .m-only {
    display: revert;
  }
  .m-hide,
  .d-only {
    display: none !important;
  }

  /* top bar: brand and user on row 1, navigation scrolls on row 2 */

  main {
    padding-top: var(--sp-16);
  }
  .page-head {
    grid-template-columns: minmax(0, 1fr) auto;
    margin-bottom: var(--sp-16);
  }
  .page-head h1 {
    font-size: 22px;
  }
  /* more than one action: actions go under the title */
  .page-head:has(.actions > :nth-child(2)) {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "crumb" "title" "actions";
    row-gap: var(--sp-12);
  }
  .page-head:has(.actions > :nth-child(2)) .actions {
    justify-content: flex-start;
  }

  .stats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .card {
    padding: var(--sp-20) var(--sp-12) var(--sp-12);
  }

  .facts {
    grid-template-columns: minmax(0, 1fr);
  }
  .facts dt {
    border-bottom: 0;
    padding-bottom: 0;
    font-size: var(--fs-small);
  }

  /* dense tables become one block per row (flex, wrapping):
     [sel] p1 (name) .................. p2 (power)
           s  s  s  s   (secondary cells, inline, no labels)
           Label  value (one line per other cell) */
  table.dense,
  table.dense tbody {
    display: block;
  }
  table.dense colgroup,
  table.dense thead {
    display: none;
  }
  table.dense tbody tr {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px var(--sp-12);
    padding: var(--sp-8) 0;
    border-bottom: var(--hair-w) solid var(--color-border);
  }
  table.dense tbody tr::before {
    /* line break after p1 + p2 */
    content: "";
    order: 3;
    flex-basis: 100%;
    height: 0;
  }
  table.dense tbody tr:has(> td.sel) {
    padding-left: 44px;
  }
  table.dense td {
    order: 5;
    display: flex;
    align-items: center;
    gap: var(--sp-8);
    flex-basis: 100%;
    height: auto;
    min-height: 24px;
    padding: 0;
    border: 0;
    background: transparent !important;
    box-shadow: none !important;
  }
  table.dense
    td[data-label]:not(.p1):not(.p2):not(.sel):not(.s):not(.rowacts)::before {
    content: attr(data-label);
    flex: none;
    width: 6.5rem;
    font-size: var(--fs-small);
    color: var(--color-text-2);
  }
  table.dense td.s {
    order: 4;
    flex-basis: auto;
    color: var(--color-text-2);
  }
  /* td.s.lab: a secondary cell whose label is what tells the cells apart (Before / After, Old / New),
     so it stays a labelled line of its own instead of an inline value */
  table.dense td.s.lab {
    order: 5;
    flex-basis: 100%;
  }
  table.dense td.s.lab[data-label]::before {
    content: attr(data-label);
    flex: none;
    width: 6.5rem;
    font-size: var(--fs-small);
    color: var(--color-text-2);
  }
  table.dense td.sel {
    position: absolute;
    left: 0;
    top: var(--sp-8);
    width: auto;
    padding: 0;
  }
  table.dense td.p1 {
    order: 1;
    flex: 1 1 0;
    min-width: 0;
    font-size: var(--fs-body);
    min-height: 40px;
  }
  table.dense td.p2 {
    order: 2;
    flex: none;
    justify-content: flex-end;
  }
  /* A status cell that holds a Details fold (policy devices): the badge stays on its line
     and the fold takes a line of its own, wrapping long findings instead of widening the card. */
  table.dense td.p2:has(> details[open]) {
    flex: 1 1 100%;
    min-width: 0;
    flex-wrap: wrap;
    justify-content: flex-start;
  }
  table.dense td.p2 > details {
    flex: 1 1 100%;
    min-width: 0;
  }
  table.dense td.p2 > details li {
    overflow-wrap: anywhere;
  }
  table.dense tbody tr.is-selected,
  table.dense tbody tr:has(> td.sel input:checked) {
    background: var(--color-accent-bg);
    box-shadow: inset 3px 0 0 var(--color-accent);
  }
  table.dense td.rowacts {
    order: 2;
    flex: none;
  }
  table.dense td.empty {
    display: block;
  }
  table.dense td.end {
    justify-content: flex-start;
  }

  .bulkbar {
    bottom: var(--sp-8);
  }
  .bulkbar .bulk-count {
    flex: 1 1 auto;
  }
  .bulkbar button.ghost {
    flex: none;
  }
  .bulkbar button:not(.ghost) {
    flex: 1 1 45%;
  }

  .filters label,
  .filters label.grow {
    max-width: none;
    flex-basis: 100%;
  }
  .filters button,
  .filters a.button {
    flex: 1 1 100%;
  }

  dialog.dlg {
    width: 100vw;
    max-width: 100vw;
    max-height: 92vh;
    margin: auto 0 0;
  }
}

/* ==========================================================================
   Small helpers used by the app markup
   ========================================================================== */
a.ext {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
a.ext .ico {
  width: 12px;
  height: 12px;
  opacity: 0.6;
}
a.ext:hover .ico,
a.ext.is-hover .ico {
  opacity: 1;
}
td a.ext {
  font-weight: 400;
}

/* ==== nav-patterns (PORT.md) ==== */
/* tasmofleet DS: navigation and in-page patterns (proposal, port 1:1 into styles.css)
   Loads after ../../styles.css. Uses only existing tokens; no new colours or fonts.

   NEW CLASSES / TOKENS (everything else below refines existing classes)
   --bulkbar-h                 token: height of the fixed bulk bar; body gets this as bottom padding
   details.navpanel            phone navigation: compact "Menu" button + one full-width panel (m-only)
   .navpanel-body              the panel (overlay surface, full width under the top bar)
   .navpanel-sec               one group in the panel (Dashboard / Devices / Updates / System / user)
   .navpanel-label             group heading in the panel; .navpanel-sec.is-active = current group
   .crumb.trail                breadcrumb with "›" separators, last item = current page (span[aria-current]);
                               on phones only the parent remains, as a "←" back link
   .tabs .count, .count.accent count in a tab (Backups 3); accent = needs attention (Discovered)
   .bulk-actions               the bulk bar's action buttons (inline, ≥ 60rem)
   details.rowmenu.bulk-more   the same actions as one "Actions" menu (< 60rem)
   details.rowmenu.up          menu body opens upward (bulk bar, last rows of a table)
   .devtable col.c-act         width of the devices table's Actions column
   .confirm                    confirmation page = the dialog layout as a card (head, facts, foot)        #23 #55

   APP CLASSES MISSING IN styles.css (app.css has them; ported here in the DS look, same names)
   td.rowacts                  row-actions cell (styles.css calls it td.rowact: rename there)
   details.colmenu > summary.colbtn + .colpanel (.colhint .colrow .collabel .colmoves), .tabletools
                               the Columns chooser that tableprefs.go writes                              #3
   .tablewrap                  the wrapper tableprefs.go puts around a prefs-managed table
   td .cell > .dev             device-name lists (firmware "devref"): a name is one run while it fits, then wraps;
                               the comma stays with the name, 24px targets on phones                     #34 #84
   pre.log                     log box (update_batch.html): content height up to 16rem, then a scroll
                               fade; with one <span> per line the wrapped lines hang                     #40 #71
   .chips, .chips.scroll       chip lists wrap to their full height (no cut-off scroll box)              #65

   QA v0.9.0 refinements (no new names): one control height per toolbar and pager (#7), optical centring
   with text-box trim (#8), 40px row/form action links on phones (#13), open menus hide tooltips (#3),
   error glyph "!" on an octagon and info badge "i" instead of X / arrow (#24), empty cells show "-" (#51),
   ellipsis instead of hard clipping in phone rows and form controls (#65 #67 #70), all dropdowns
   left-aligned except the user menu (#75).

   Refined (no new names): header.top/.user (Sign out inside the user menu),
   td.rowacts, .table-scroll, .bulkbar (fixed to the viewport), details.fold/.m-fold (chevron right of
   the title), .card (content offset under the framed title, 40px hit area on fold titles). */

:root {
  --bulkbar-h: 58px;
}

/* ---- top bar --------------------------------------------------------------- */

.menu form {
  margin: 0;
}

/* ---- page header: breadcrumb trail ---------------------------------------- */

/* ---- tabs ------------------------------------------------------------------ */
.tabs .count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 18px;
  padding: 0 5px;
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-pill);
  background: var(--color-surface-2);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.tabs .count.accent {
  border-color: transparent;
  background: var(--color-accent-bg);
  color: var(--color-accent-fg);
}
.tabs a[aria-disabled="true"] {
  color: var(--color-text-3);
  pointer-events: none;
}
/* the page you are on is never drawn as unavailable, even when the device cannot use it right now */
.tabs a[aria-disabled="true"][aria-current="page"] {
  opacity: 1;
  color: var(--color-text);
}

/* ---- row actions ------------------------------------------------------------ */
td.rowacts {
  /* app name (styles.css: td.rowact): last cell, right-aligned, shrink-to-fit, vertically centred */
  width: 1%;
  text-align: right;
  white-space: nowrap;
  vertical-align: middle;
}
td.rowacts > .actions {
  display: inline-flex;
  gap: var(--sp-8);
  justify-content: flex-end;
  margin: 0;
}
td.rowacts details.rowmenu {
  vertical-align: middle;
}
/* import: the plan's and the result's closing actions keep their distance from the table above */
#import-result .card > form.stack,
#import-result .card > p.actions {
  margin-top: var(--sp-16);
}
/* a filter that is one checkbox: the button stays beside it instead of at the end of a 16rem label */
.filters > label.inline {
  flex: 0 0 auto;
}
/* proposals: the cell shrinks to fit, so wrapping would stack Ignore above Add device; they stay on one line */
table[data-table="discovery"] td.rowacts > .actions {
  flex-wrap: nowrap;
}
.devtable col.c-act {
  width: 6.5rem;
}
.rowmenu-body a[aria-disabled="true"] {
  color: var(--color-text-3);
  pointer-events: none;
}
.table-scroll:has(details.rowmenu[open]) {
  overflow: visible;
}
details.rowmenu.up > .rowmenu-body {
  top: auto;
  bottom: calc(100% + 4px);
}

/* ---- bulk bar: fixed to the viewport, content padded by its height ---------- */
.bulkbar {
  position: fixed;
  left: var(--page-pad);
  right: var(--page-pad);
  bottom: var(--sp-12);
  max-width: calc(var(--container) - 2 * var(--page-pad));
  min-height: var(--bulkbar-h);
  margin: 0 auto;
  flex-wrap: nowrap;
}
.bulkbar[hidden] {
  display: none;
}
body:has(.bulkbar:not([hidden])) {
  padding-bottom: calc(var(--bulkbar-h) + 2 * var(--sp-12));
}
.bulkbar .bulk-count {
  margin-right: 0;
  white-space: nowrap;
}
.bulk-actions {
  display: flex;
  gap: var(--sp-8);
  margin-left: auto;
}
details.rowmenu.bulk-more {
  display: none;
  margin-left: auto;
}
@media (max-width: 60rem) {
  .bulkbar:has(.bulk-more) .bulk-actions {
    display: none;
  }
  details.rowmenu.bulk-more {
    display: inline-block;
  }
}

/* ---- collapsible sections ---------------------------------------------------- */
details.fold > summary::after,
details.m-fold > summary::after {
  order: 1;
  margin: 0 4px 0 var(--sp-4);
}
details.fold > summary .meta,
details.m-fold > summary .meta {
  order: 2;
}
details.fold > summary:has(.meta)::after,
details.m-fold > summary:has(.meta)::after {
  margin-left: var(--sp-4);
}
.card {
  /* content starts below the framed title: title height + 0.75rem */
  padding-top: calc(var(--fs-h2-lg) * 1.2 + 0.75rem);
}
.card > details.fold-h:first-child > summary::before {
  /* 40px hit area around the framed title, without covering the rule */
  content: "";
  position: absolute;
  inset: -10px 0;
}
.card:has(> details.fold-h:first-child[open]) > details > summary + * {
  margin-top: 0;
}

/* ---- QA v0.9.0 ---------------------------------------------------------------- */
/* #7 one height per size, one size per toolbar: toolbars and pagers are always sm */
.toolbar button,
.toolbar .button,
.toolbar select,
.pager button,
.pager .button,
.pager select {
  height: var(--ctl-sm);
  padding: 0 var(--ctl-pad-sm);
  font-size: var(--fs-ui);
}
.toolbar > *,
.pager > * {
  flex: none;
}
.toolbar form {
  margin: 0;
}
.toolbar > details.rowmenu:last-child {
  margin-left: auto;
}
/* #8 labels centred in their box: label.button flex-centred, caps trimmed optically */
label.button {
  display: inline-flex;
  align-items: center;
  width: auto;
}
button,
.button,
.badge,
.tag,
.tabs a,
.tabs .count {
  text-box: trim-both cap alphabetic;
}
/* #3 an open menu hides every floating tooltip; menus never clip their labels */
body:has(details[open] > .rowmenu-body, details[open] > .menu)
  .tooltip:not(.is-static) {
  display: none;
}
/* Columns chooser: tableprefs.go markup (the prototype's chooser, D19); offered from 45rem,
   where the table (not the phone list) shows, like in tables.js */
.colmenu,
.tabletools {
  display: none;
}
.tablewrap {
  position: relative;
}
@media (min-width: 45rem) {
  .tabletools {
    display: flex;
    justify-content: flex-end;
    margin: 0 0 var(--sp-8);
  }
  .colmenu {
    display: block;
    position: relative;
    z-index: var(--z-menu);
  }
  .toolbar > .colmenu {
    margin-left: auto;
  }
  .table-scroll:has(details.colmenu[open]),
  .table-fit:has(details.colmenu[open]) {
    overflow: visible;
  }
  .colbtn {
    /* a plain sm button with a visible label; no title tooltip (#3) */
    list-style: none;
    display: inline-flex;
    align-items: center;
    gap: var(--sp-8);
    height: var(--ctl-sm);
    padding: 0 var(--ctl-pad-sm);
    border: var(--hair-w) solid var(--color-border-strong);
    border-radius: var(--r-control);
    background: var(--color-surface);
    color: var(--color-text);
    font: 600 var(--fs-ui) / 1 var(--font-sans);
    cursor: pointer;
  }
  .colbtn::-webkit-details-marker {
    display: none;
  }
  .colbtn::after {
    content: "";
    width: 5px;
    height: 5px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: translateY(-2px) rotate(45deg);
  }
  .colbtn:hover {
    background: var(--color-surface-2);
  }
  .colpanel {
    position: absolute;
    right: 0;
    top: calc(100% + 6px);
    width: 400px;
    max-width: calc(100vw - 32px);
    padding: 6px;
    background: var(--color-surface);
    /* the prototype's --border is below the 1.3:1 overlay guard (layout guard g); strong as every menu */
    border: var(--hair-w) solid var(--color-border-strong);
    border-radius: 10px;
    box-shadow: var(--shadow-lg);
    font: 400 13px / 1.3 var(--font-sans);
    color: var(--color-text);
  }
  .colpanel .colhint {
    margin: 0;
    padding: 6px 8px 8px;
    font-size: 12px;
    line-height: 1.45;
    color: var(--color-text-2);
  }
  .colpanel .colrow {
    display: flex;
    align-items: center;
    gap: 6px;
    height: 36px;
    padding: 0 4px 0 8px;
    border-radius: 6px;
  }
  .colpanel .colrow[draggable="true"]:hover {
    background: var(--color-surface-2);
  }
  .colpanel .colrow.is-fixed {
    gap: 8px;
    padding: 0 8px;
    color: var(--color-text-2);
  }
  .colpanel .colrow.drop-t {
    box-shadow: inset 0 2px 0 var(--color-accent);
  }
  .colpanel .colrow.drop-b {
    box-shadow: inset 0 -2px 0 var(--color-accent);
  }
  .colpanel .colgrip {
    flex: none;
    width: 14px;
    color: var(--color-text-3);
    letter-spacing: -2px;
    cursor: grab;
  }
  .colpanel label {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 1;
    min-width: 0;
    font-weight: 400;
    color: var(--color-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    cursor: pointer;
  }
  .colpanel .is-fixed label {
    cursor: default;
  }
  .colpanel input[type="checkbox"] {
    accent-color: var(--color-accent);
  }
  .colpanel .colfix {
    display: inline-flex;
    align-items: center;
    height: 20px;
    padding: 0 7px;
    border-radius: 5px;
    font: 500 11.5px var(--font-sans);
    white-space: nowrap;
    background: var(--color-accent-bg);
    color: var(--color-accent-fg);
  }
  .colpanel .colpin {
    flex: none;
    min-height: 0;
    height: 26px;
    padding: 0 6px;
    border-radius: 5px;
    border: var(--hair-w) solid var(--color-border);
    background: transparent;
    color: var(--color-text-2);
    font: 500 11px var(--font-sans);
    white-space: nowrap;
    box-shadow: none;
  }
  .colpanel .colpin[aria-pressed="true"] {
    background: var(--color-accent-bg);
    color: var(--color-accent-fg);
  }
  .colpanel .colfoot {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 8px;
    margin-top: 6px;
    padding: 6px 4px 2px 8px;
    border-top: var(--hair-w) solid var(--color-border);
    font-size: 11.5px;
    color: var(--color-text-3);
  }
  .colpanel .colreset {
    flex: none;
    min-height: 0;
    height: 30px;
    padding: 0 10px;
    border: 0;
    border-radius: 7px;
    background: none;
    box-shadow: none;
    color: var(--color-accent-fg);
    font: 500 13px var(--font-sans);
    white-space: nowrap;
  }
}
/* #24 error glyph: "!" on an octagon (a dismiss "X" no longer); info badge: "i" */
.error:not(span):not(small)::before {
  content: "!";
  clip-path: polygon(
    30% 0,
    70% 0,
    100% 30%,
    100% 70%,
    70% 100%,
    30% 100%,
    0 70%,
    0 30%
  );
}
span.error::before {
  content: "!\00a0";
}
.badge.tone-info::before {
  content: "i";
  font-family: Georgia, serif;
  font-style: italic;
}
/* #51 empty cells read "-" in every table */
td:empty:not(.rowacts):not(.sel)::after {
  content: "-";
  color: var(--color-text-3);
}
/* #34 #84 device-name lists (firmware devref): a name stays in one run while it fits its box, then wraps
   anywhere (never an ellipsis, see "long unbreakable text" below); the comma stays with the name */
.dev {
  display: inline-block;
  max-width: 100%;
  vertical-align: bottom;
}
.dev > a {
  color: var(--color-text);
  font-weight: 600;
  text-decoration: none;
}
.dev > a:hover,
.dev > a.is-hover {
  color: var(--color-accent-fg);
  text-decoration: underline;
}
.dev:not(:last-child)::after {
  content: ",";
  flex: none;
}
/* #40 #71 log box (pre.log): height follows the content up to 16rem, then scrolls with a fade */
pre.log {
  max-height: 16rem;
  overflow: auto;
  margin: var(--sp-8) 0 0;
  padding: var(--sp-8) var(--sp-12);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-code);
  font: 400 var(--fs-small) / 1.6 var(--font-mono);
  background:
    linear-gradient(transparent, var(--color-surface-2) 60%) center bottom /
      100% 28px no-repeat local,
    linear-gradient(
        transparent,
        color-mix(in srgb, var(--color-text) 16%, transparent)
      )
      center bottom / 100% 14px no-repeat scroll,
    var(--color-surface-2);
}
/* a device's reply is data, not prose: it keeps its lines and tokens whole and scrolls sideways */
pre.log.reply {
  white-space: pre;
  overflow-wrap: normal;
}
pre.log > span {
  display: block;
  padding-left: 3ch;
  text-indent: -3ch;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
/* #23 #55 confirmation page */
.confirm {
  max-width: 40rem;
}
.confirm .facts {
  margin: var(--sp-12) 0;
}
.confirm .dlg-foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--sp-8);
  margin: var(--sp-16) calc(var(--sp-16) * -1) 0;
  padding: var(--sp-12) var(--sp-16) 0;
  border-top: var(--hair-w) solid var(--color-border);
}
@media (max-width: 44.99rem) {
  /* the card has 12px side padding here: the rule ends exactly at the card's border, not past it */
  .confirm .dlg-foot {
    margin-inline: calc(var(--sp-12) * -1);
    padding-inline: var(--sp-12);
  }
}
label.inline:has(> input[type="checkbox"]) {
  display: flex;
  align-items: flex-start;
}
label.inline > input[type="checkbox"] {
  flex: none;
  margin-top: 2px;
}
/* #65 chip lists wrap to full height (no cut-off scroll box); controls ellipsize */
.chips,
.chips.scroll {
  max-height: none;
  overflow: visible;
}
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-4);
  margin: 0;
  padding: 0;
  list-style: none;
}
input:not([type="checkbox"]):not([type="radio"]),
select {
  text-overflow: ellipsis;
}
/* hint under a row control instead of beside it (#52) */
td .hint {
  display: block;
  margin-top: 2px;
}

/* ---- phones (up to 44.99rem: the prototype switches at 720px) ---- */
@media (max-width: 44.99rem) {
  /* #13 links that act as row or form actions get a 40px hit area */
  td a:not(.button):not(.cell a),
  .toolbar a:not(.button),
  .dlg-foot a:not(.button),
  .confirm a:not(.button) {
    display: inline-flex;
    align-items: center;
    min-height: 40px;
  }
  td .cell {
    /* a list of names is one inline run: 24px targets, 8px apart (WCAG 2.5.8 spacing), normal pitch (#84) */
    display: flex;
    flex-wrap: wrap;
    gap: 0 var(--sp-8);
    line-height: 24px;
  }
  table.dense td.rowacts {
    order: 2;
    flex: none;
    width: auto;
    min-width: max-content;
  }
  table.dense
    td.rowacts[data-label]:not(.p1):not(.p2):not(.sel):not(.s)::before {
    content: none;
  }
  td.rowacts > .actions {
    justify-content: flex-start;
  }
  /* #67 #70 phone rows: ellipsis instead of hard clipping; rows align with or without a checkbox */
  table.dense td.p1 > a,
  table.dense td.p1 > span {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  table.dense td.p1 > span > a {
    display: inline;
  }
  table.dense:has(td.sel) tbody tr:not(:has(> td.sel)) {
    padding-left: 44px;
  }
  table.dense td {
    min-width: 0;
    overflow-wrap: anywhere;
  }
  table.dense td > :not(.badge):not(.relay):not(details):not(.row-actions) {
    min-width: 0;
  }

  .card {
    padding-top: calc(40px / 2 + 0.75rem);
  }

  .bulkbar {
    left: 0;
    right: 0;
    bottom: 0;
    max-width: none;
    border-radius: 0;
    border-left: 0;
    border-right: 0;
    border-bottom: 0;
    padding-bottom: calc(var(--sp-8) + env(safe-area-inset-bottom, 0px));
  }
  body:has(.bulkbar:not([hidden])) {
    padding-bottom: calc(
      var(--bulkbar-h) + var(--sp-12) + env(safe-area-inset-bottom, 0px)
    );
  }
  .bulkbar .bulk-count,
  .bulkbar button.ghost,
  .bulkbar button:not(.ghost) {
    flex: none;
  }
}

/* ==== page rules: classes of one page or one component that the design system has no rule for ==== */
.pre {
  white-space: pre-wrap;
}
button.htmx-request[disabled] {
  cursor: progress;
}
button.htmx-request[disabled]::after {
  content: "";
  width: 0.85em;
  height: 0.85em;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}
.stack > .actionbar > p {
  margin: 0;
}
.inline-form {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  align-items: center;
  margin: 0;
}
td form.inline-form {
  display: flex;
}
td.wrap {
  min-width: 12rem;
}

@media (max-width: 44.99rem) {
  td form.inline-form {
    justify-content: flex-end;
  }
  td.wrap {
    min-width: 0;
  }
}

.picker th:first-child,
.picker td:first-child {
  width: 2.5rem;
}
.picker label {
  display: inline;
  font-weight: 550;
  font-size: inherit;
}
.picker tr:has(input:disabled) td {
  color: var(--color-text-2);
}
.picker tr:has(input:checked) td {
  background: var(--color-accent-bg) !important;
}
@media (min-width: 45rem) {
  table td.wrap code {
    white-space: pre-wrap;
  }
}
.summary-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 0.6rem;
  align-items: center;
  margin: 0 0 1rem;
  min-height: 2.35rem;
}
.jobs {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.6rem;
}
.job {
  min-width: 0;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-card);
  padding: 0.7rem 1rem;
}
.job-head {
  display: grid;
  grid-template-columns: minmax(9rem, 16rem) minmax(0, 1fr) 8.5rem 5.5rem 5.5rem;
  gap: 0.5rem 1rem;
  align-items: center;
  min-height: 2.9rem;
}
.job-dev {
  font-weight: 600;
  min-width: 0;
  overflow-wrap: break-word;
}
.job-prog {
  min-width: 0;
}
.bar {
  height: 0.5rem;
  border-radius: var(--r-xs);
  background: var(--color-surface-2);
  border: 1px solid var(--color-border);
  overflow: hidden;
}
.bar i {
  display: block;
  height: 100%;
  background: var(--color-accent);
  border-radius: var(--r-xs);
  transition: width 0.6s ease;
}
.bar.bad {
  border-color: var(--color-danger);
}
.bar i.s0 {
  width: 0;
}
.bar i.s1 {
  width: 12.5%;
}
.bar i.s2 {
  width: 25%;
}
.bar i.s3 {
  width: 37.5%;
}
.bar i.s4 {
  width: 50%;
}
.bar i.s5 {
  width: 62.5%;
}
.bar i.s6 {
  width: 75%;
}
.bar i.s7 {
  width: 87.5%;
}
.bar i.s8 {
  width: 100%;
  background: var(--color-ok);
}
.bar.bad i {
  width: 100%;
  background: var(--color-danger);
} /* a failed job is a full danger bar, not an empty pill */
.job-step {
  margin-top: 0.25rem;
  font-size: 0.86rem;
  color: var(--color-text-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-height: 1.3em;
}
.job-state {
  min-width: 0;
}
.job-time {
  text-align: right;
  color: var(--color-text-2);
  font-variant-numeric: tabular-nums;
}
.job-act {
  text-align: right;
  min-height: 1.9rem;
}
details.job-log {
  margin-top: 0.4rem;
  border-top: 1px solid var(--color-border);
  padding-top: 0.4rem;
}
details.job-log > summary {
  cursor: pointer;
  color: var(--color-text-2);
  font-size: 0.86rem;
  list-style-position: inside;
}
.job-last {
  display: inline-block;
  max-width: calc(100% - 2rem);
  vertical-align: bottom;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.log-tools {
  display: flex;
  justify-content: flex-end;
  margin-top: 0.3rem;
}
@media (max-width: 44.99rem) {
  .job-head {
    grid-template-columns: minmax(0, 1fr) auto;
  }
  .job-prog {
    grid-column: 1 / -1;
    order: 3;
  }
  .job-state {
    justify-self: end;
  }
  .job-time {
    text-align: left;
  }
  .job-act {
    grid-column: 2;
    justify-self: end;
  }
}
@media (prefers-reduced-motion: reduce) {
  .bar i,
  .badge {
    transition: none;
  }
}
.devtable col.c-sel {
  width: 2.75rem;
}
.devtable col.c-status {
  width: 12.5rem;
}
.devtable col.c-fw {
  width: 9rem;
}
.devtable col.c-fam {
  width: 6.5rem;
}
.devtable col.c-addr {
  width: 10.5rem;
}
.devtable col.c-up {
  width: 6rem;
}
.devtable col.c-wifi {
  width: 6rem;
}
.devtable col.c-restart {
  width: 9rem;
}
.devtable col.c-pow {
  width: 9rem;
}
/* A name wraps (anywhere, so even an unbroken one) instead of setting the table's width: a nowrap name
   was the table's minimum width and pushed the Actions column past the content edge (QA v0.9.0). */
@media (min-width: 45rem) {
  .devtable td.wrap {
    overflow-wrap: anywhere;
  }
}
@media (min-width: 45rem) {
  .devtable col.c-name {
    width: 14rem;
  }
}
@media (min-width: 68.75rem) {
  .cols.side {
    grid-template-columns: 16rem minmax(0, 1fr);
  }
  .cols .sticky {
    position: sticky;
    top: 1rem;
  }
}

.audittable {
  table-layout: fixed;
}
.audittable col.c-time {
  width: 9.5rem;
}
.audittable col.c-actor {
  width: 11rem;
}
.audittable col.c-action {
  width: 12.5rem;
}
.audittable col.c-target {
  width: 9rem;
}
.audittable col.c-target {
  width: 8rem;
}
.audittable col.c-res {
  width: 6rem;
}
.audittable col.c-det {
  width: 6.5rem;
}
.audittable td.nowrap {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.audittable td.res {
  white-space: normal;
  overflow-wrap: anywhere;
}
.audittable td.res .badge {
  display: -webkit-box;
  width: fit-content;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
  white-space: normal;
  border-radius: 0.8rem;
  max-width: 100%;
}
.audittable td.detail {
  position: relative;
  overflow: visible;
}
.audittable summary {
  cursor: pointer;
  list-style: none;
}
.audittable summary::-webkit-details-marker {
  display: none;
}
.audittable details[open] > summary {
  background: var(--color-accent-bg);
  color: var(--color-accent-fg);
  border-color: var(--color-accent);
}
.audittable .tip {
  display: none;
  position: absolute;
  z-index: var(--z-menu);
  right: 0;
  top: calc(100% - 0.2rem);
  width: min(34rem, 80vw);
  padding: 0.4rem 0.6rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--r-sm);
  box-shadow: var(--shadow-lg);
}
.audittable .tip pre {
  margin: 0;
  border: 0;
  padding: 0;
  background: none;
  font-size: 0.8rem;
  max-height: 15lh;
  overflow: hidden;
}
.audittable td.detail:hover .tip,
.audittable td.detail:focus-within .tip {
  display: block;
}
.audittable td.detail:has(details[open]) .tip {
  display: none;
}
.audittable tr.detail-row {
  display: none;
}
.audittable tr:has(details[open]) + tr.detail-row {
  display: table-row;
}
.audittable tr.detail-row td {
  background: var(--color-surface-2);
}
.audittable tr.detail-row p {
  margin: 0 0 0.4rem;
  overflow-wrap: anywhere;
}
.audittable tr.detail-row pre {
  margin: 0;
  font-size: 0.82rem;
  max-height: 24rem;
  overflow: auto;
}
@media (max-width: 72rem) {
  .audittable {
    table-layout: auto;
  }
}
@media (max-width: 44.99rem) {
  .audittable colgroup {
    display: none;
  }
}
.cols.side .summary-bar {
  flex-direction: column;
  align-items: flex-start;
}
@media (min-width: 68.75rem) {
  .cols.opts {
    grid-template-columns: 23rem minmax(0, 1fr);
  }
}
.cols.opts .stack {
  max-width: none;
}
.cols.opts fieldset {
  margin-top: 0;
}
@media (max-width: 68.74rem) {
  .cols.opts .sticky {
    margin-bottom: 1rem;
  }
}
.sysform fieldset.fgrid {
  background: var(--color-surface);
  padding: 1rem 1.25rem 1.25rem;
}
@media (min-width: 68.75rem) {
  .sysform fieldset.fgrid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem 1.5rem;
  }
}
.sysform label {
  display: grid;
  gap: 0.3rem;
}
.sysform input:not([type="checkbox"]),
.sysform select,
.sysform textarea {
  width: 100%;
}
.savebar {
  position: sticky;
  bottom: 0;
  z-index: var(--z-sticky);
  margin: 1rem 0 0;
  padding: 0.7rem 0;
  background: var(--color-bg);
  border-top: 1px solid var(--color-border);
}
.savebar[hidden] {
  display: none !important;
}
@media (min-width: 68.75rem) {
  .cols.disco {
    grid-template-columns: minmax(0, 1fr);
  }
}
@media (min-width: 96rem) {
  .cols.disco {
    grid-template-columns: 23rem minmax(0, 1fr);
    gap: 0 1.25rem;
  }
}
.rules-layout {
  display: grid;
  gap: 1.25rem;
  align-items: start;
}
.rules-main,
.rules-side {
  display: grid;
  gap: 1.25rem;
  min-width: 0;
}
@media (min-width: 88rem) {
  .rules-layout {
    grid-template-columns: minmax(0, 3fr) minmax(20rem, 2fr);
  }
  .rules-side {
    position: sticky;
    top: 1rem;
  }
}
.rules-layout section.card {
  margin: 0;
}
.rule-editor {
  display: grid;
  gap: 0.9rem;
}
.rule-editor .field {
  display: grid;
  gap: 0.3rem;
}
.rule-editor input:not([type="checkbox"]):not([type="radio"]),
.rule-editor select,
.rule-editor textarea {
  width: 100%;
}
.rule-editor p {
  margin: 0;
}
label.chip {
  display: inline-flex;
  gap: 0.35rem;
  align-items: center;
  padding: 0.1rem 0.55rem;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--r-control);
  background: var(--color-surface);
  font-weight: 450;
  font-size: 0.9rem;
  cursor: pointer;
  /* a chip never gets wider than its list: a long unbroken device name wraps inside it */
  max-width: 100%;
  min-width: 0;
  overflow-wrap: anywhere;
}
label.chip > input {
  flex: none;
}
label.chip:has(input:checked) {
  background: var(--color-accent-bg);
  color: var(--color-accent-fg);
  border-color: var(--color-accent);
}
label.chip:has(input:focus-visible) {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}
.tag-except {
  border-style: dashed;
}
.shortid {
  border-bottom: 1px dotted var(--color-text-2);
  cursor: help;
  font-family: var(--font-mono);
  font-size: 0.9em;
}
@media (max-width: 44.99rem) {
  main:has(.actionbar) {
    padding-bottom: 8rem;
  }
  .actionbar {
    position: fixed;
    z-index: var(--z-header);
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
    justify-content: flex-end;
    margin: 0;
    padding: 0.55rem 0.75rem;
    background: var(--color-surface);
    border-top: 1px solid var(--color-border-strong);
    box-shadow: 0 -4px 14px rgb(0 0 0 / 0.1);
  }
  .actionbar p {
    margin: 0;
  }
  .actionbar > [data-summary] {
    flex: 1 1 100%;
    font-size: 0.84rem;
    line-height: 1.3;
  }
  .actionbar > button,
  .actionbar > .button {
    flex: 1 1 0;
    min-width: 0;
  }
  .actionbar > details {
    flex: none;
  }
  table.dense td small:not(.keep) {
    display: none;
  }
  table.dense td.p1 br,
  table.dense td.ctx > .p1 br {
    display: none;
  }
  table.dense td.ctx > .p1 strong ~ .lbl {
    display: none;
  }
  table.dense td.ctx {
    display: contents;
  }
  table.dense td.ctx > .p1 {
    order: 1;
    flex: 1 1 0;
    min-width: 0;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  table.dense.rules td.ctx > .p1 {
    white-space: normal;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
  }
  table.dense.rules td.s.grow {
    flex: 1 1 auto;
    overflow: visible;
    white-space: normal;
  }
  table.dense.rules td.s .chips {
    flex-wrap: wrap;
  }
  table.dense td.ctx > details {
    order: 4;
    flex: none;
    font-size: 0.84rem;
    color: var(--color-text-2);
  }
  table.dense td.ctx > details[open] {
    order: 5;
    flex: 1 0 100%;
  }
  table.dense td.ctx > .error {
    order: 5;
    flex: 1 0 100%;
  }
  label.chip {
    padding: 0 0.5rem;
    font-size: 0.86rem;
  }
  .rule-editor {
    gap: 0.4rem;
  }
  fieldset > details.m-fold,
  .rule-editor > details.m-fold {
    margin: 0;
  }
  fieldset > details.m-fold > summary,
  .rule-editor > details.m-fold > summary {
    min-height: 1.8rem;
    padding: 0.2rem 0;
  }
  .rule-editor .notice,
  .rule-editor .error {
    margin: 0.2rem 0;
    padding: 0.4rem 0.6rem;
    font-size: 0.88rem;
    line-height: 1.35;
  }
  .rule-editor .notice,
  .rule-editor .error:not(span):not(small) {
    padding-left: 40px; /* room for the ::before glyph, as in the base callout */
  }
  .rule-editor .muted:has(+ .chips),
  .rule-editor .muted > small {
    display: none;
  }
  .rules-layout,
  .rules-main,
  .rules-side {
    gap: 0.75rem;
    grid-template-columns: minmax(0, 1fr);
  }

  .cols.opts {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0.75rem;
  }
  .picker label {
    font-weight: 550;
  }
  .picker td.p1 {
    white-space: normal;
  }
  .picker.dense tbody tr::after {
    display: none;
  }
  .picker.dense td.p2,
  .picker.dense td.s {
    order: 2;
  }
  .picker.dense .badge.st-online,
  .picker.dense td.s small {
    display: none;
  }
  .cols.opts fieldset {
    border: 0;
    padding: 0;
  }
  .cols.opts legend {
    padding: 0;
    font-size: 1.05rem;
  }
  .picker td.p1 label {
    display: inline;
  }
}
@media (max-width: 44.99rem) {
  .audittable.dense td.p1 {
    flex: none;
  }
  .audittable.dense td.p2 {
    max-width: 45%;
  }
  .audittable.dense td.p1x {
    display: block;
    order: 4; /* under the action line, after time and user: what was changed, on a line of its own */
    flex: 1 0 100%;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--color-text-2);
    font-size: 0.88rem;
  }
  /* the target needs no label here: it is the line under time and user */
  .audittable.dense
    td.p1x[data-label]:not(.p1):not(.p2):not(.sel):not(.s):not(.rowacts)::before {
    content: none;
  }
  /* the kind chip (Proxy, SSO) is for the desktop column; the name says who */
  .audittable.dense .who:not(.who-system) .tag {
    display: none;
  }
  .audittable.dense td.res .badge {
    -webkit-line-clamp: 1;
    line-clamp: 1;
  }
  .audittable.dense td.detail {
    overflow: visible;
  }
  .audittable.dense td.detail .tip {
    display: none !important;
  }
  .audittable.dense summary {
    min-height: 1.6rem;
    padding: 0.1rem 0.5rem;
    font-size: 0.82rem;
  }
  .audittable.dense tr.detail-row,
  .audittable.dense tbody tr.detail-row:nth-child(even) {
    display: none;
  }
  .audittable.dense tr:has(details[open]) + tr.detail-row,
  .audittable.dense
    tbody
    tr:has(details[open])
    + tr.detail-row:nth-child(even) {
    display: block;
    padding: 0.4rem 0.75rem;
    background: var(--color-surface-2);
  }
  .audittable.dense tr.detail-row td {
    display: block;
  }
}
@media (max-width: 44.99rem) {
  .actionbar details.rowmenu {
    position: relative;
  }
  .actionbar details.rowmenu > summary {
    list-style: none;
  }
  .actionbar details.rowmenu > summary::-webkit-details-marker {
    display: none;
  }
  .actionbar .rowmenu-body {
    position: absolute;
    right: 0;
    bottom: calc(100% + 0.6rem);
    min-width: 11rem;
    margin: 0;
    padding: 0.4rem;
    justify-items: stretch;
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--r-panel);
    box-shadow: var(--shadow-lg);
  }
  .actionbar .rowmenu-body a,
  .actionbar .rowmenu-body button {
    justify-content: flex-start;
    width: 100%;
  }
}
@media (min-width: 45rem) {
  .colpanel .colmove {
    flex: none;
    min-height: 0;
    width: 26px;
    height: 26px;
    padding: 0;
    border-radius: 5px;
    font-size: 13px;
    line-height: 1;
    box-shadow: none;
    border: 0;
    background: none;
    color: var(--color-text-2);
  }
  .colpanel .colmove:hover:not([disabled]) {
    background: var(--color-surface-3);
  }
  .colpanel .colmove[disabled] {
    opacity: 0.35;
    cursor: default;
  }
  th.drop-l {
    box-shadow: inset 3px 0 0 var(--color-accent);
  }
  th.drop-r {
    box-shadow: inset -3px 0 0 var(--color-accent);
  }
  table.tfix {
    table-layout: fixed;
  }
  table.tfix > thead > tr > th {
    overflow: hidden;
    text-overflow: ellipsis;
  }
  table.tfix > tbody > tr > td:not(.detail) {
    overflow: hidden;
    overflow-wrap: anywhere;
  }
  /* the row menu opens inside its cell: a cell that cuts off its content would hide the opened menu (v0.10.1) */
  table.tfix > tbody > tr > td.rowacts {
    overflow: visible;
  }
  table.tfix .c-fam,
  table.tfix .c-up,
  table.tfix .c-wifi,
  table.tfix .c-restart {
    display: table-cell;
  }
  table.tfix .c-fam .tag {
    white-space: nowrap;
  }
  table.hc1 > :is(thead, tbody) > tr > :is(th, td):nth-child(1):not([colspan]) {
    display: none !important;
  }
  table.hc2 > :is(thead, tbody) > tr > :is(th, td):nth-child(2):not([colspan]) {
    display: none !important;
  }
  table.hc3 > :is(thead, tbody) > tr > :is(th, td):nth-child(3):not([colspan]) {
    display: none !important;
  }
  table.hc4 > :is(thead, tbody) > tr > :is(th, td):nth-child(4):not([colspan]) {
    display: none !important;
  }
  table.hc5 > :is(thead, tbody) > tr > :is(th, td):nth-child(5):not([colspan]) {
    display: none !important;
  }
  table.hc6 > :is(thead, tbody) > tr > :is(th, td):nth-child(6):not([colspan]) {
    display: none !important;
  }
  table.hc7 > :is(thead, tbody) > tr > :is(th, td):nth-child(7):not([colspan]) {
    display: none !important;
  }
  table.hc8 > :is(thead, tbody) > tr > :is(th, td):nth-child(8):not([colspan]) {
    display: none !important;
  }
  table.hc9 > :is(thead, tbody) > tr > :is(th, td):nth-child(9):not([colspan]) {
    display: none !important;
  }
  table.hc10
    > :is(thead, tbody)
    > tr
    > :is(th, td):nth-child(10):not([colspan]) {
    display: none !important;
  }
  table.hc11
    > :is(thead, tbody)
    > tr
    > :is(th, td):nth-child(11):not([colspan]) {
    display: none !important;
  }
  table.hc12
    > :is(thead, tbody)
    > tr
    > :is(th, td):nth-child(12):not([colspan]) {
    display: none !important;
  }
  table.hc13
    > :is(thead, tbody)
    > tr
    > :is(th, td):nth-child(13):not([colspan]) {
    display: none !important;
  }
  table.hc14
    > :is(thead, tbody)
    > tr
    > :is(th, td):nth-child(14):not([colspan]) {
    display: none !important;
  }
  table.hc15
    > :is(thead, tbody)
    > tr
    > :is(th, td):nth-child(15):not([colspan]) {
    display: none !important;
  }
  table.hc16
    > :is(thead, tbody)
    > tr
    > :is(th, td):nth-child(16):not([colspan]) {
    display: none !important;
  }
  .colhandle {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 10px;
    z-index: 0; /* below the pinned columns (z-index 1): the handle of a column scrolled under them must not show through */
    cursor: col-resize;
    touch-action: none;
    user-select: none;
  }
  .colhandle::after {
    content: "";
    position: absolute;
    top: 26%;
    bottom: 26%;
    right: 4px;
    width: 1px;
    background: var(--color-border-strong);
    transition: background-color 0.12s;
  }
  .colhandle:hover::after,
  .colhandle:focus-visible::after,
  .colhandle.is-drag::after {
    background: var(--color-accent);
  }
  .colhandle:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: -2px;
    border-radius: 2px;
  }
  body.is-resizing {
    cursor: col-resize;
    user-select: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .colhandle::after {
    transition: none;
  }
}
.chip[title] {
  cursor: help;
}
@media (max-width: 44.99rem) {
  td.none {
    display: none;
  }
}
.summary-line {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0.6rem;
  align-items: center;
  margin: 0 0 0.75rem;
}
@media (max-width: 44.99rem) {
  label.chip,
  label.inline,
  label:has(> input[type="checkbox"]:not([aria-label])) {
    min-height: 2.5rem;
    display: flex;
    align-items: center;
  }
  .devtable.dense td.s small:not(.keep) {
    display: none;
  }
  .devtable.dense td.c-up:has(> .muted:only-child),
  .devtable.dense td.c-wifi:has(> .muted:only-child) {
    display: none;
  }
  .picker.dense tbody tr {
    padding-block: 0.1rem;
  }
  .audittable.dense tbody tr:not(.detail-row) {
    position: relative;
    min-height: 3.1rem;
    padding-left: var(--sp-12); /* the card has no side padding of its own */
    padding-right: 5.6rem;
  }
  .audittable.dense td.detail {
    position: absolute;
    right: 0.75rem;
    top: 50%;
    transform: translateY(-50%);
  }
}
.setgrid {
  display: grid;
  gap: 1.5rem 1.5rem;
  align-items: start;
}
@media (min-width: 72rem) {
  .setgrid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
.setgrid > .card,
.setgrid > section.card:first-child {
  margin: 0;
  scroll-margin-top: 4rem;
} /* the first card too: section.card:first-child would drop it 12px below its neighbour */
.kv {
  display: grid;
  gap: 0.3rem 0;
}
.kv-row {
  display: grid;
  grid-template-columns: minmax(7.5rem, 15rem) minmax(0, 1fr);
  gap: 0.5rem 1rem;
  align-items: center;
  padding: 0.15rem 0;
  border-bottom: 1px solid var(--color-border);
}
.kv-row:last-child {
  border-bottom: 0;
}
.kv-key {
  display: flex;
  align-items: center;
  gap: 0.1rem;
  min-width: 0;
  font-weight: 550;
}
.kv-key label {
  overflow-wrap: anywhere;
}
.kv-val {
  min-width: 0;
  display: grid;
  gap: 0.2rem;
}
.kv-val input:not([type="checkbox"]),
.kv-val select {
  width: 100%;
}
.kv-short .kv-val input {
  max-width: 9rem;
}
.kv-row.is-changed .kv-val > input:not([type="checkbox"]),
.kv-row.is-changed .kv-val > select {
  border-color: var(--color-accent);
  box-shadow: inset 3px 0 0 var(--color-accent);
}
@media (max-width: 36rem) {
  .kv-row {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.15rem;
    padding: 0.35rem 0;
  }
}
label.is-changed > input:not([type="checkbox"]),
label.is-changed > select {
  border-color: var(--color-accent);
  box-shadow: inset 3px 0 0 var(--color-accent);
}
form[data-track-changes] .savebar .actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
  margin: 0;
}
.statchips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 1.1rem;
}
.statchips a.badge {
  text-decoration: none;
  padding-block: 0.3rem;
  font-size: 0.92rem;
}
.statchips a.badge.is-on {
  outline: 2px solid var(--color-text);
  outline-offset: 1px;
}
@media (max-width: 44.99rem) {
  .statchips a.badge,
  .statchips .button {
    display: inline-flex;
    align-items: center;
    min-height: 2.5rem;
  }
}
@media (max-width: 87.99rem) {
  .rules-layout {
    grid-auto-flow: row;
  }
  .rules-layout > .rules-main,
  .rules-layout > .rules-side {
    display: contents;
  }
  .rules-layout #editor {
    order: -1;
  }
}
.sysform .fld {
  display: grid;
  gap: 0.3rem;
  align-content: start;
}
.sysform .fld label.reset {
  font-weight: 400;
  font-size: 0.9rem;
  color: var(--color-text-2);
}
@media (max-width: 44.99rem) {
  #txtable tbody tr {
    position: relative;
  }
  #txtable td.p1 > a:first-child::after {
    content: "";
    position: absolute;
    inset: 0;
  }
  #txtable td.p1 small a {
    position: relative;
    z-index: 1;
  }
}
.chan-ok {
  color: var(--color-ok-fg);
}
.colslot {
  display: none;
}

details.job-log > summary {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  list-style: none;
}
details.job-log > summary::-webkit-details-marker {
  display: none;
}
details.job-log > summary::after {
  content: "";
  flex: none;
  box-sizing: border-box;
  width: 0.45rem;
  height: 0.45rem;
  margin: 0 0.2rem 0 auto;
  border-right: 2px solid var(--color-text-2);
  border-bottom: 2px solid var(--color-text-2);
  transform: translateY(-0.12rem) rotate(45deg);
}
details.job-log[open] > summary::after {
  transform: translateY(0.1rem) rotate(225deg);
}
details.job-log > summary {
  display: flex;
}
.notes,
#detail li {
  overflow-wrap: anywhere;
}

@media (max-width: 44.99rem) {
  table.has-sel tbody tr:not(:has(> td.sel)) {
    padding-left: 3rem;
  }
}
@media (max-width: 44.99rem) {
  table.dense td.s.note {
    flex: 1 0 100%;
    white-space: normal;
  }
  .cols.disco {
    row-gap: 0;
  }
}
label.invalid {
  outline: 2px solid var(--color-danger);
  outline-offset: 0.2rem;
  border-radius: var(--r-sm);
}
.kv-key {
  display: block;
}
.kv-key label {
  display: inline;
}
.kv-key button.info {
  vertical-align: middle;
}
table.rules td[data-label="Findings"] {
  white-space: nowrap;
}
@media (max-width: 44.99rem) {
  .rule-editor input,
  .rule-editor select {
    text-overflow: ellipsis;
  }
}
.audittable col.c-time {
  width: 11.75rem;
}
.audittable col.c-actor {
  width: 12rem;
}
.audittable col.c-action {
  width: 10.5rem;
}
.audittable col.c-target {
  width: 13rem;
}
.audittable col.c-res {
  width: 7.5rem;
}
.audittable td.res .badge {
  white-space: nowrap;
}
.audittable td.res .badge:not(:has(+ *)) {
  white-space: normal;
}
@media (max-width: 44.99rem) {
  .audittable.dense td.p1x > a {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 2.5rem;
    min-height: 0;
  }
}
.savebar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.9rem;
}
.savebar small {
  flex: 1 1 14rem;
}
@media (max-width: 44.99rem) {
  .cols.side {
    row-gap: 0.5rem;
  }
}
.setup-intro {
  margin-bottom: 1.4rem;
}

/* ==== wide screens: a phone fold (details.m-fold) is plain, always-open content ====
   A fold that stays a real fold at every width carries .fold-closed (Devices filters, Firmware
   Prefetch and Custom images); every other m-fold is open from 45rem. */
/* A fold is collapsed on phones and always open on wide screens, so the
   desktop layout is the one it always was. Without ::details-content support
   the summary stays visible on wide screens and the fold simply works. */
details.m-fold > summary {
  cursor: pointer;
}
@supports selector(::details-content) {
  @media (min-width: 45rem) {
    details.m-fold:not(.fold-closed)::details-content {
      content-visibility: visible;
      display: block;
    }
    fieldset > details.m-fold:not(.fold-closed)::details-content {
      display: grid;
      gap: 0.85rem;
    }
    .stack > details.m-fold:not(.fold-closed)::details-content {
      display: grid;
      gap: 1rem;
    }
    .stack > .actionbar {
      display: contents;
    }
    .rule-editor > details.m-fold:not(.fold-closed)::details-content {
      display: grid;
      gap: 0.9rem;
    }
    details.m-fold:not(.fold-closed):not(.fold-h) > summary {
      display: none;
    }
    details.m-fold.fold-h:not(.fold-closed) > summary {
      list-style: none;
      pointer-events: none;
      cursor: default;
    }
    details.m-fold.fold-h:not(.fold-closed) > summary::-webkit-details-marker {
      display: none;
    }
    section.card > details.m-fold.fold-h:first-child > summary > h2 {
      margin-top: 0;
    }
  }
}

/* ==== phone cards for tables without .dense (Users, Firmware files this fleet needs): one block per row, label before value ==== */
@media (max-width: 44.99rem) {
  table:not(.dense),
  table:not(.dense) thead,
  table:not(.dense) tbody,
  table:not(.dense) tr,
  table:not(.dense) th,
  table:not(.dense) td {
    display: block;
  }
  table:not(.dense) thead {
    position: absolute;
    left: -9999px;
  }
  table:not(.dense) tbody tr,
  table:not(.dense) tbody tr:hover {
    margin: 0 0 var(--sp-12);
    padding: var(--sp-4) 0;
    background: var(--color-surface);
    border: var(--hair-w) solid var(--color-border);
  }
  table:not(.dense) tbody td,
  table:not(.dense) tbody tr:hover td {
    background: none;
  }
  table:not(.dense) td {
    display: flex;
    flex-wrap: wrap; /* bare children (links, tags, small notes) wrap instead of widening the page */
    gap: var(--sp-12);
    justify-content: space-between;
    align-items: baseline;
    border: 0;
    padding: var(--sp-4) var(--sp-12);
    text-align: right;
  }
  table:not(.dense) td[data-label]::before {
    content: attr(data-label);
    color: var(--color-text-2);
    font-size: var(--fs-ui);
    font-weight: 500;
    text-align: left;
    flex: none;
  }
  table:not(.dense) td.empty {
    display: block;
    text-align: center;
  }
  table:not(.dense) td.wrap {
    min-width: 0;
  }
  table:not(.dense) td .cell,
  table:not(.dense) td .chips {
    min-width: 0;
    flex: 1 1 0;
    justify-content: flex-end;
    overflow-wrap: anywhere;
  }
}

/* ==== phone targets (QA #13 #84) ==== */
@media (max-width: 44.99rem) {
  table.dense td.sel .hit {
    min-width: 40px;
  }
  td .cell .dev a {
    display: inline-block;
    min-height: 24px;
    line-height: 24px;
  }
}

/* ==== column resize handles (tables.js) sit on the right edge of their header cell ==== */
thead th {
  position: relative;
}

/* ==== phone targets, second pass: rules above lose to patterns.css's min-width: 0 ==== */
@media (max-width: 44.99rem) {
  table.dense td.sel > .hit {
    min-width: 40px !important;
  }
  table.dense td .cell {
    flex: 1 1 0;
    min-width: 0;
  }
  details.m-fold:not(.fold-h) > summary,
  details.job-log > summary {
    min-height: 40px;
  }
}

/* the bulk bar lies above the Columns button and row menus that scroll under it */
.bulkbar {
  z-index: calc(var(--z-menu) + 1);
}

/* a bare checkbox in a selection cell sits on the middle of the row */
td.sel > input[type="checkbox"] {
  display: block;
  margin: 0 auto;
}

@media (max-width: 44.99rem) {
  /* cached files: the file name keeps its width, release and chip go on the line below */
  table[data-table="firmware_files"] td.p1 {
    flex-wrap: wrap;
  }
  table[data-table="firmware_files"] td.p1 > small.keep {
    flex: 0 0 100%;
    /* Geist is wider than Archivo was: "16.1.0 · esp32c3 / tasmota" no longer fits the 130px file column
       in one run and would run into the Size column, so on a phone it may wrap between its words */
    white-space: normal;
  }
}

/* an audit result badge wraps instead of clamping: a -webkit-box has no flex gap and no centred label */
.audittable td.res .badge {
  display: inline-flex;
  -webkit-line-clamp: unset;
  line-clamp: unset;
  overflow: visible;
}

td.sel > label.hit {
  display: flex;
  margin-inline: auto;
}

/* phone device rows: two lines (name, power, Actions / status with its word), tight padding */
@media (max-width: 44.99rem) {
  .devtable.dense tbody tr {
    padding: var(--sp-4) 0;
    gap: 0 var(--sp-12);
  }
  .devtable.dense td.s {
    min-height: 20px;
  }
  .devtable.dense td.sel {
    top: var(--sp-4);
  }
}

/* phone density: one-line selection rows are exactly one touch target high; card folds sit closer */
@media (max-width: 44.99rem) {
  table.picker.dense tbody tr {
    padding-block: 0;
  }
  table.picker.dense td.sel {
    top: 0;
  }
  .card > details.m-fold:not(.fold-h) {
    margin-block: var(--sp-8);
  }
}

@media (max-width: 44.99rem) {
  table:not(.dense) td.rowacts {
    width: auto;
    white-space: normal;
  }
}

/* phone density: tight row padding in every dense list */
@media (max-width: 44.99rem) {
  table.dense tbody tr {
    padding-block: var(--sp-4);
  }
  table.dense td.s {
    min-height: 20px;
  }
  table.dense td.sel {
    top: var(--sp-4);
  }
}

/* a fold inside a table cell has no section rule above it */
td details.m-fold {
  border-top: 0;
  margin: 0;
}
td details.m-fold > summary {
  min-height: 0;
}

@media (max-width: 44.99rem) {
  section.card {
    margin: var(--sp-24) 0 var(--sp-12);
  }
  section.card:first-child {
    margin-top: var(--sp-12);
  }
}

@media (max-width: 44.99rem) {
  table[data-table="policy_devices"] tbody tr {
    padding-block: 2px;
  }
  table[data-table="policy_devices"] td.sel {
    top: 2px;
  }
}

.card > details.fold-h > .tablewrap,
.card > details.fold-h > table {
  margin-top: var(--sp-12);
}
.card > details.fold-h > form,
.card > details.fold-h > summary + p {
  margin-top: var(--sp-12);
}

/* H2 pages */
/* the pager is the same at every width: Previous, position, Next, then the page sizes (#71) */
.pager {
  justify-content: flex-start;
  row-gap: var(--sp-8);
}
.pager-of {
  font-weight: 600;
  padding-inline: var(--sp-8);
}

.pager-size {
  margin-left: auto;
  display: inline-flex;
  flex-wrap: wrap;
  gap: var(--sp-4);
  align-items: center;
}
@media (max-width: 44.99rem) {
  .pager-size {
    margin-left: 0;
    width: 100%;
  }
}
/* QA #94: the version string (v0.8.0-18-g0782517) stays inside its card at 375 px */

/* QA #79: "Finish the setup" follows the last step at every width (not sticky, not inside a step) */
.setup-finish {
  margin: var(--sp-16) 0 0;
}
.setup-finish > p {
  margin: 0;
}
/* the intro line of a framed fold keeps its distance from the title (layout guard f) */
section.card > details.fold-h > summary + p.fold-intro {
  margin-top: var(--sp-12);
}
/* phone: the page sizes of the pager are 40 px targets like every other control */
@media (max-width: 44.99rem) {
  .pager-size .button {
    min-width: 2.5rem;
    justify-content: center;
  }
}

/* QA v0.9.0 phone rows that hid what identifies them */
@media (max-width: 44.99rem) {
  /* proposals: name and kind badge share the first line, facts are labelled lines, Ignore and Add device get the last line */
  table[data-table="discovery"] td.rowacts {
    order: 6;
    flex: 0 0 100%;
  }
  /* policy devices: the name wraps instead of being clipped (a clipped name cannot be told from its neighbours);
     status and Details stay beside a short name; a name too long for that takes the first line and wraps (flex-basis auto
     breaks the line by the name's own width), with status and Details on the line below */
  table[data-table="policy_devices"] td.p1 {
    flex: 1 1 auto;
  }
  table[data-table="policy_devices"] td.p1 > a {
    white-space: normal;
    overflow-wrap: anywhere;
  }
}

/* Bulk restart confirmation: a long device name wraps instead of widening the card. */
table[data-table="bulk_command"] td.p1 a {
  overflow-wrap: anywhere;
}

/* ---- package I: users, system settings, audit ---------------------------------- */
/* The row menu holds action items only; the one field in it (new password) is padded like an item. */
.rowmenu-body form.menu-field {
  display: grid;
  gap: var(--sp-4);
  padding: var(--sp-8) var(--sp-12);
}
.rowmenu-body form.menu-field label {
  font-weight: 500;
}
.rowmenu-body form.menu-field button {
  padding: 0;
}
/* Read-only (environment) settings read like editable ones: name, small key line, value, hint. */
.sysform .fld.ro {
  gap: 0.3rem;
}
.sysform .ro-label {
  font-size: var(--fs-ui);
  font-weight: 600;
  color: var(--color-text);
}
.sysform .ro-label small {
  font-size: var(--fs-small);
  font-weight: 400;
  color: var(--color-text-2);
}
.sysform .ro-value {
  overflow-wrap: anywhere;
}
.sysform .fld.ro > small {
  font-size: var(--fs-small);
  color: var(--color-text-2);
}
@media (max-width: 44.99rem) {
  /* an Actions cell with nothing in it (SSO row without sessions, proxy row) is not a row of its own */
  table td.rowacts:empty {
    display: none;
  }
}

/* ---- QA v0.9.0 follow-up: policy pages and the phone fold on desktop (packages K, L) ---------- */

/* L: from 45rem a phone fold (details.m-fold without .fold-closed) is plain content. Its summary
   is the card's title like on every other card: no chevron, and the card is framed although the
   details element is not [open] (the wide-screen rule shows its content anyway). */
@supports selector(::details-content) {
  @media (min-width: 45rem) {
    details.m-fold.fold-h:not(.fold-closed) > summary::after {
      display: none;
    }
    .card:has(
      > details.m-fold.fold-h:first-child:not(.fold-closed):not([open])
    ) {
      background: var(--color-surface);
      border-color: var(--color-border);
      border-top-color: var(--color-border);
      padding: calc(var(--fs-h2-lg) * 1.2 + 0.75rem) var(--sp-16) var(--sp-16);
      margin-bottom: var(--sp-20);
    }
    .card:has(> details.m-fold.fold-h:first-child:not(.fold-closed):not([open]))
      > details
      > summary {
      background: var(--color-surface);
    }
    .card:has(> details.m-fold.fold-h:first-child:not(.fold-closed))
      > details
      > summary
      + * {
      margin-top: 0;
    }
  }
}
/* L: closed card folds on a phone are one 40 px target each, also when they are stacked (Setup steps) */
@media (max-width: 44.99rem) {
  .card:has(> details.fold-h:first-child:not([open])) {
    padding-top: var(--sp-16);
  }
}

/* K: the card footer of a confirmation stays inside the card's padding box on a phone */
@media (max-width: 44.99rem) {
  .confirm .dlg-foot {
    margin-inline: calc(var(--sp-12) * -1);
    padding-inline: var(--sp-12);
  }
}

/* K: policy rules on a phone: the rule name is the title, the setting its subtitle, then labelled lines */
@media (max-width: 44.99rem) {
  table.dense.rules td.ctx {
    display: block;
    order: 1;
    flex: 1 1 0;
    min-width: 0;
  }
  table.dense.rules td.ctx > .p1 {
    display: block;
    overflow: visible;
    white-space: normal;
    -webkit-line-clamp: unset;
    line-clamp: unset;
  }
  table.dense.rules td.ctx > .p1 strong ~ .lbl {
    display: block;
    font-weight: 400;
    font-size: var(--fs-ui);
    color: var(--color-text-2);
  }
  table.dense.rules td.s {
    flex-basis: 100%;
  }
  table.dense.rules td.s[data-label]::before {
    content: attr(data-label);
    flex: none;
    width: 6.5rem;
    font-size: var(--fs-small);
    color: var(--color-text-2);
  }
  table.dense.rules td.s .chips {
    flex: 1 1 0;
    min-width: 0;
  }
  /* make compliant: the commands and what is not changed carry their label too */
  table[data-table="policy_fix"] td.s {
    flex-wrap: wrap;
    align-items: flex-start;
  }
  table[data-table="policy_fix"] td.s[data-label]::before {
    content: attr(data-label);
    flex: 1 0 100%;
    font-size: var(--fs-small);
    color: var(--color-text-2);
  }
  table[data-table="policy_fix"] td.s > div {
    flex: 1 0 100%;
    min-width: 0;
  }
}
/* K: where the values came from stays on one line; the Export button keeps its distance from the table */
table[data-table="policy_devices"] td[data-label="Source"] {
  white-space: nowrap;
}
p.actions.export-row {
  margin-top: var(--sp-12);
}

/* J: a selected row of the update picker on a phone. The row paints the highlight and the accent bar
   (table.dense tr:has(> td.sel input:checked)); the desktop rule above that gives every cell its own
   background left a band in the gaps between cells, and the cells hid the accent bar on all but
   the first line. */
@media (max-width: 44.99rem) {
  .picker.dense tbody tr:has(input:checked) td {
    background: transparent !important;
  }
}

/* a table with no row has no use for its header (sort, select all, resize): tableprefs.go marks it */
table.is-empty > thead {
  display: none;
}
/* cached-file meta (release, chip / variant) stays on one run; the line may wrap between the parts of the row, not inside it */
table[data-table="firmware_files"] small.keep {
  white-space: nowrap;
}
@media (max-width: 44.99rem) {
  /* names a release needs: a left-aligned run, like the lists above it */
  table[data-table="firmware_cached"] td .cell {
    justify-content: flex-start;
    text-align: left;
  }
}

/* ---- QA v0.9.0 follow-up: global CSS, native controls, dialogs ------------------------------- */
/* zero tiles stay readable: text-3 is for disabled things only */
.stat.zero .num {
  color: var(--color-text-2);
}

/* sort icons: at least 3:1 against the header */
.sortmark {
  opacity: 0.85;
}
.sortlink:hover .sortmark,
.sortlink.is-hover .sortmark {
  opacity: 0.9;
}

/* the select-all box sits on the same line as the row boxes below it */
th.sel > input[type="checkbox"]:not([hidden]) {
  display: block;
  margin: 0 auto;
}

/* stat-card legends: the part above the rule is the page, not the card */

/* an action row or form right below a table keeps a gap */
table + .actions,
table + form,
.table-fit + .actions,
.table-fit + form,
.tablewrap + .actions,
.tablewrap + form {
  margin-top: var(--sp-16);
}

.nw {
  white-space: nowrap;
}
button.info {
  flex: none;
}

/* phone menu: left-aligned rows, a user name as written, room under the last row */

/* checkbox and radio: an invalid one is outlined, not struck by the text field's red bar */
input[type="checkbox"][aria-invalid="true"],
input[type="radio"][aria-invalid="true"] {
  box-shadow: none;
  outline: 2px solid var(--color-danger);
  outline-offset: 1px;
}
label.invalid {
  outline-offset: 0.35rem;
  border-radius: 0;
}

/* native progress: flat, full width, accent fill */
progress {
  appearance: none;
  display: block;
  width: 100%;
  height: 0.5rem;
  margin: var(--sp-12) 0;
  border: var(--hair-w) solid var(--color-border-strong);
  border-radius: var(--r-xs);
  background: var(--color-surface);
  color: var(--color-accent);
  overflow: hidden;
}
progress::-webkit-progress-bar {
  background: transparent;
  border-radius: var(--r-xs);
}
progress::-webkit-progress-value {
  background: var(--color-accent);
  border-radius: var(--r-xs);
}
progress::-moz-progress-bar {
  background: var(--color-accent);
  border-radius: var(--r-xs);
}
progress:indeterminate {
  background: linear-gradient(90deg, var(--color-accent) 50%, transparent 50%) 0
    0 / 2rem 100% repeat-x;
  animation: tf-indeterminate 1s linear infinite;
}
@keyframes tf-indeterminate {
  to {
    background-position: 2rem 0;
  }
}
@media (prefers-reduced-motion: reduce) {
  progress:indeterminate {
    animation: none;
  }
}

/* native file input: the button looks like button.sm */
input[type="file"] {
  font: inherit;
  font-size: var(--fs-body);
  color: var(--color-text);
  width: 100%;
  min-width: 0;
}
input[type="file"]::file-selector-button {
  height: var(--ctl-sm);
  margin-right: var(--sp-12);
  padding: 0 var(--ctl-pad-sm);
  border: var(--hair-w) solid var(--color-border-strong);
  border-radius: var(--r-control);
  background: var(--color-surface);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--fs-ui);
  cursor: pointer;
}
input[type="file"]::file-selector-button:hover {
  background: color-mix(in srgb, var(--color-text) 7%, var(--color-surface));
  border-color: var(--color-text);
}

@media (max-width: 44.99rem) {
  input[type="file"]::file-selector-button {
    height: 40px;
  }

  /* a label that wraps keeps its checkbox on the first line (centred on it), not in the middle of the block */
  label.chip:has(> input[type="checkbox"]),
  label.inline:has(> input[type="checkbox"]),
  label:has(> input[type="checkbox"]:not([aria-label])) {
    align-items: flex-start;
    padding-block: calc((2.5rem - 1lh) / 2);
  }
  label:not(.hit) > input[type="checkbox"]:not([aria-label]) {
    margin-top: calc((1lh - 18px) / 2);
  }
}

/* ==== long unbreakable text (QA v0.10.0) ====
   A device name, an error chain or a URL can be longer than the screen and have no break opportunity.
   It wraps inside its box instead of widening the page. One rule for prose containers (headings,
   paragraphs, list items, notes, the breadcrumb, dialog text), written with :where() so any
   specific rule still wins; table cells are not in it, because an auto-layout table would squeeze a
   column to a single letter. Flex and grid parents get min-width: 0 so the text can shrink at all. */
:where(main, dialog.dlg, .confirm)
  :where(
    h1,
    h2,
    h3,
    h4,
    p,
    li,
    dd,
    summary,
    legend,
    small,
    .crumb,
    .reason
  ):not(td *) {
  overflow-wrap: anywhere;
}
.page-head h1,
.page-head .crumb,
.dlg-head h2,
.dlg-body,
.dlg-foot {
  min-width: 0;
  overflow-wrap: anywhere;
}
.dlg-head > :not(h2) {
  flex: none; /* Close stays whole and inside the frame */
}
dialog.dlg {
  max-width: calc(100vw - 2rem);
}
dialog.dlg > * {
  min-width: 0;
}
/* overflow-wrap is inherited: in a dialog table it would let auto layout squeeze a column until words
   break mid-letter ("cache|d"); table cells keep normal wrapping, the names in them (.dev) wrap themselves */
.dlg-body table {
  overflow-wrap: normal;
}
/* the device-name rules (.dev) wrap with the same overflow-wrap */
.dev > a {
  overflow-wrap: anywhere;
}
@media (max-width: 44.99rem) {
  dialog.dlg {
    max-width: 100vw;
  }
  /* phone cards: the name is the row's identifier, so it wraps (anywhere) instead of being cut */
  table.dense td.p1 > a,
  table.dense td.p1 > span,
  table.dense td.p1 > span > a {
    overflow: visible;
    text-overflow: clip;
    white-space: normal;
    overflow-wrap: anywhere;
  }
  /* stacked phone cells hold prose (error text, name lists): it wraps inside the card */
  table.dense td,
  table.dense td .reason,
  table.dense td small {
    min-width: 0;
    overflow-wrap: anywhere;
  }
  /* a name that wraps to several lines: the checkbox, Power and Actions stay on its first line (QA #67),
     the name starts at the top edge beside them */
  .devtable.dense tbody tr {
    align-items: flex-start;
  }
  /* a wrapped name in a cell (24px link box) keeps its comma beside the last line, not on a line of its own */
  td .cell .dev {
    display: inline-flex;
    align-items: last baseline;
  }
  td .cell .dev a {
    min-width: 0;
  }
  table[data-table="transaction_retry"] td.p2 {
    flex: 1 1 0;
    flex-wrap: wrap;
    justify-content: flex-start;
  }
}

/* ==========================================================================
   Shell (design v2, WP F3): top bar, sub-navigation, user menu, phone header,
   navigation drawer, crumbs, connection banners, toasts. Values from the
   prototype's markup (design/v2/template.html, the shell before <main>).
   ========================================================================== */
@keyframes tf-pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.3;
  }
}
header.top {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background: var(--color-surface);
  border-bottom: var(--hair-w) solid var(--color-border);
}
/* the header's rows and main share one content cap; the backgrounds span the window */
.shell-in {
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 var(--page-pad);
}
.tb-in {
  height: 52px;
  display: flex;
  align-items: center;
  gap: var(--sp-22);
}
.brand {
  display: flex;
  align-items: center;
  gap: var(--sp-9);
  font: 600 15px var(--font-sans);
  letter-spacing: -0.01em;
  color: var(--color-text);
  text-decoration: none;
  white-space: nowrap;
}
.brand:hover {
  color: var(--color-text);
}
.brand-mark {
  flex: none;
  display: block;
}
.tb-groups {
  display: flex;
  gap: var(--sp-2);
}
.tb-group {
  display: inline-flex;
  align-items: center;
  height: 32px;
  padding: 0 var(--sp-12);
  border-radius: var(--r-control);
  font: 500 13.5px var(--font-sans);
  color: var(--color-text-2);
  text-decoration: none;
  white-space: nowrap;
}
.tb-group:hover {
  color: var(--color-text);
}
.tb-group[aria-current] {
  background: var(--color-surface-3);
  color: var(--color-text);
}
.tb-fill {
  flex: 1;
}

/* live indicator: data-live on <html> comes from live.js; without it the page is live */
.live {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-7);
  font: 500 12px var(--font-sans);
  color: var(--color-text-2);
  white-space: nowrap;
}
.live-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--color-ok);
  animation: tf-pulse 2.4s ease-in-out infinite;
}
.live-l {
  display: none;
}
html:not([data-live]) .live-ok,
html[data-live="live"] .live-ok,
html[data-live="reconnecting"] .live-re,
html[data-live="offline"] .live-off {
  display: inline;
}
html[data-live="reconnecting"] .live-dot {
  background: var(--color-warn);
  animation-duration: 0.9s;
}
html[data-live="offline"] .live-dot {
  background: var(--color-danger);
  animation: none;
}

/* user menu: a details element (menu.js: one open, Escape, click outside) */
details.usermenu {
  position: relative;
}
summary.um-btn {
  list-style: none;
  height: 34px;
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  padding: 0 var(--sp-8) 0 var(--sp-4);
  border-radius: var(--sp-8);
  border: var(--hair-w) solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text);
  font: 500 13px var(--font-sans);
  cursor: pointer;
}
summary.um-btn::-webkit-details-marker {
  display: none;
}
.avatar {
  position: relative;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--color-accent-bg);
  color: var(--color-accent-fg);
  display: grid;
  place-items: center;
  font: 600 11px var(--font-sans);
  flex: none;
}
.um-caret {
  color: var(--color-text-3);
  font-size: 10px;
}
.um-menu {
  position: absolute;
  right: 0;
  top: 42px;
  width: 240px;
  background: var(--color-surface);
  /* the prototype draws this one menu with --border; like every other overlay it gets the strong
     border, which layout guard (g) requires to be seen against the page (1.3:1) */
  border: var(--hair-w) solid var(--color-border-strong);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-lg);
  padding: var(--sp-6);
  z-index: var(--z-header-menu);
}
.um-who {
  padding: var(--sp-8) var(--sp-10) var(--sp-10);
  border-bottom: var(--hair-w) solid var(--color-border);
  margin-bottom: var(--sp-6);
}
.um-name {
  font-weight: 600;
}
.um-role {
  font-size: 12px;
  color: var(--color-text-2);
}
.um-theme {
  padding: var(--sp-6) var(--sp-10);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-8);
  font-size: 13px;
}
.um-note {
  margin: 0;
  padding: 0 var(--sp-10) var(--sp-6);
  font-size: 11.5px;
  color: var(--color-text-3);
  text-align: right;
}
.um-menu form {
  margin: 0;
}
.um-menu .um-item {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  text-align: left;
  height: 34px;
  padding: 0 var(--sp-10);
  border: 0;
  border-radius: var(--sp-6);
  background: none;
  color: var(--color-text);
  font: 400 13px var(--font-sans);
  text-decoration: none;
  text-box: normal;
}
.um-menu .um-item:hover {
  background: var(--color-surface-2);
}

/* segmented Light / Dark / Auto (D11) */
.seg {
  display: flex;
  border: var(--hair-w) solid var(--color-border-strong);
  border-radius: var(--r-control);
  overflow: hidden;
}
.seg button {
  height: 28px;
  padding: 0 var(--sp-9);
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--color-text);
  font: 500 12px var(--font-sans);
  text-box: normal;
}
.seg button + button {
  border-left: var(--hair-w) solid var(--color-border-strong);
}
.seg button:hover {
  background: var(--color-surface-2);
}
.seg button[aria-pressed="true"] {
  background: var(--color-surface-3);
}

/* sub-navigation: the pages of the current group */
.sn {
  border-top: var(--hair-w) solid var(--color-border);
}
.sn-in {
  height: 40px;
  display: flex;
  align-items: stretch;
  gap: var(--sp-20);
}
.sn-item {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-6);
  padding: 0 var(--sp-2);
  font: 500 13px var(--font-sans);
  color: var(--color-text-2);
  text-decoration: none;
  white-space: nowrap;
}
.sn-item:hover {
  color: var(--color-text);
}
.sn-item[aria-current="page"] {
  color: var(--color-text);
  box-shadow: inset 0 -2px 0 var(--color-accent);
}
.sn-empty {
  display: none;
}

/* phone header (below 45rem) */
.ph {
  display: none;
}
.ph-btn {
  text-decoration: none;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  color: var(--color-text);
  flex: none;
}
.burger {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}
.burger > span {
  width: 18px;
  height: 2px;
  border-radius: 1px;
  background: currentColor;
}
.ph-title {
  flex: 1;
  min-width: 0;
  font: 600 16px var(--font-sans);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ph .live {
  gap: var(--sp-6);
}
.ph .live-dot {
  width: 8px;
  height: 8px;
  margin-right: var(--sp-6);
}
.ph .live-l {
  margin-right: var(--sp-4);
}
html:not([data-live]) .ph .live-ok,
html[data-live="live"] .ph .live-ok {
  display: none;
}
.ph-me .avatar {
  width: 30px;
  height: 30px;
}
@media (max-width: 44.99rem) {
  .tb,
  .sn {
    display: none;
  }
  .ph {
    height: 55px; /* 56 with the header's bottom border, as in the prototype (border-box) */
    display: flex;
    align-items: center;
    gap: var(--sp-6);
    padding: 0 var(--sp-8);
  }
}

/* navigation drawer (phones; /nav shows the same list as a page) */
dialog.drawer {
  position: fixed;
  inset: 0 auto 0 0;
  margin: 0;
  width: min(300px, 86%);
  height: 100%;
  max-height: none;
  max-width: none;
  padding: var(--sp-10) var(--sp-10) var(--sp-24);
  border: 0;
  border-right: var(--hair-w) solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text);
  overflow: auto;
}
dialog.drawer::backdrop {
  background: rgba(10, 14, 18, 0.45);
}
/* The backdrop stops at the reserved scrollbar gutter, which shows the canvas; the prototype's
   scrim covers the full width. While the drawer is open the canvas takes the scrim-mixed page
   colour, and the body (which then paints its own background) reaches the bottom of the window,
   so nothing is dimmed twice. */
html:has(dialog.drawer:modal) {
  background: color-mix(in srgb, var(--color-bg) 55%, rgb(10, 14, 18));
}
html:has(dialog.drawer:modal) body {
  min-height: 100vh;
}
.dr-brand {
  height: 48px;
  display: flex;
  align-items: center;
  gap: var(--sp-9);
  padding: 0 var(--sp-8);
  font: 600 15px var(--font-sans);
}
.dr-group {
  margin-top: var(--sp-12);
}
.dr-label {
  margin: 0;
  padding: 0 var(--sp-10) var(--sp-4);
  font: 600 11px var(--font-sans);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text-3);
}
.dr .dr-item {
  width: 100%;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  text-align: left;
  padding: 0 var(--sp-10);
  border: 0;
  border-radius: var(--sp-8);
  background: transparent;
  color: var(--color-text);
  font: 500 14.5px var(--font-sans);
  text-decoration: none;
  text-box: normal;
}
.dr .dr-item:hover {
  background: var(--color-surface-2);
}
.dr .dr-item[aria-current="page"] {
  background: var(--color-accent-bg);
  color: var(--color-accent-fg);
}
.dr-foot {
  margin-top: var(--sp-16);
  border-top: var(--hair-w) solid var(--color-border);
  padding-top: var(--sp-12);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.dr-foot form {
  margin: 0;
}
.dr-theme {
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-8);
  padding: 0 var(--sp-10);
  font: 500 14.5px var(--font-sans);
}

/* crumbs (ui.Crumbs) and the trails of pages not ported yet (.crumb.trail) */
nav.crumbs,
.crumb.trail {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-6);
  font-size: var(--fs-meta);
  color: var(--color-text-3);
  margin: 0 0 var(--sp-8);
  min-height: 20px;
}
nav.crumbs a,
.crumb.trail a {
  color: var(--color-text-2);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: var(--color-border-strong);
}
/* a long device name in a crumb link is cut like the last crumb, or the trail widens a phone page
   (the delete page, reached from the device list's Delete…, P2) */
nav.crumbs a {
  max-width: 60cqw;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.crumb-here,
.crumb.trail > [aria-current] {
  color: var(--color-text-2);
  max-width: 60cqw;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.crumb.trail > :not(:last-child)::after {
  content: "/";
  display: inline-block;
  margin-left: var(--sp-6);
  color: var(--color-text-3);
  text-decoration: none;
}
.page-head .crumb {
  grid-area: crumb;
}

/* inline banners: flash without JavaScript, the setup notice, the connection banners */
.banner {
  display: flex;
  gap: var(--sp-12);
  align-items: center;
  flex-wrap: wrap;
  padding: var(--sp-10) var(--sp-14);
  margin: 0 0 var(--sp-14);
  border-radius: var(--r-banner);
  border: var(--hair-w) solid var(--banner-line);
  background: var(--banner-bg);
  color: var(--banner-fg);
  font-size: 13px;
}
.banner.tone-ok {
  --banner-line: var(--color-ok);
  --banner-bg: var(--color-ok-bg);
  --banner-fg: var(--color-ok-fg);
}
.banner.tone-warn {
  --banner-line: var(--color-warn);
  --banner-bg: var(--color-warn-bg);
  --banner-fg: var(--color-warn-fg);
}
.banner.tone-danger {
  --banner-line: var(--color-danger);
  --banner-bg: var(--color-danger-bg);
  --banner-fg: var(--color-danger-fg);
}
.banner-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--banner-line);
  flex: none;
}
.banner-dot.pulse {
  animation: tf-pulse 0.9s ease-in-out infinite;
}
.banner-text {
  flex: 1;
  min-width: min(200px, 100%); /* in a narrow box (the style guide's sign-in card) it may not poke out of the border */
}
.banner-text b {
  font-weight: 600;
}
.banner-text a {
  color: inherit;
}
.banner .banner-btn {
  height: var(--ctl);
  padding: 0 var(--sp-12);
  border-radius: var(--r-control);
  border: var(--hair-w) solid var(--banner-line);
  background: var(--color-surface);
  color: var(--banner-fg);
  font: 500 13px var(--font-sans);
  text-box: normal;
}
/* the connection banners float below the sticky header (header.top is their containing block):
   showing one never moves the page; z-index -1 keeps the header's own menus above them */
.conn-banners {
  position: absolute;
  z-index: -1;
  top: calc(100% + var(--sp-8));
  left: 0;
  right: 0;
  display: flex;
  justify-content: center;
  padding: 0 var(--sp-16);
  pointer-events: none;
}
.conn-banner {
  display: none;
  margin: 0;
  max-width: 760px;
  box-shadow: var(--shadow-lg);
  pointer-events: auto;
}
html[data-live="reconnecting"] .conn-banner.conn-re,
html[data-live="offline"] .conn-banner.conn-off {
  display: flex;
}

/* toasts (toast.js): bottom right, outside every size container */
.toasts {
  position: fixed;
  right: 16px;
  bottom: 16px;
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  gap: var(--sp-8);
  align-items: flex-end;
  pointer-events: none;
  max-width: calc(100% - 32px);
}
.toast {
  pointer-events: auto;
  display: flex;
  align-items: center;
  gap: var(--sp-10);
  padding: var(--sp-10) var(--sp-14);
  background: var(--color-surface);
  color: var(--color-text);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-banner);
  box-shadow: var(--shadow-lg);
  font-size: 13px;
}
.toast.has-x {
  padding: var(--sp-8) var(--sp-8) var(--sp-8) var(--sp-14);
}
.toast-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
  background: var(--color-ok);
}
.toast.tone-info .toast-dot {
  background: var(--color-accent);
}
.toast.tone-warn .toast-dot {
  background: var(--color-warn);
}
.toast.tone-danger .toast-dot {
  background: var(--color-danger);
}
.toast-text {
  min-width: 0;
  overflow-wrap: anywhere;
}
.toast .toast-x {
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--color-text-3);
  font: 400 16px var(--font-sans);
  text-box: normal;
}
@media (prefers-reduced-motion: reduce) {
  .live-dot,
  .banner-dot.pulse {
    animation: none;
  }
}

/* ==========================================================================
   Components (design v2, WP F4): internal/web/ui/components.templ, one block
   per component, values from the prototype's markup (design/v2/template.html).
   Every component is on /styleguide; docs/spec/design-system.md describes it.
   ========================================================================== */
@keyframes tf-shimmer {
  0% {
    background-position: -300px 0;
  }
  100% {
    background-position: 300px 0;
  }
}

/* page header: title and subtitle left, the page's buttons right */
.pghead {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-12);
  flex-wrap: wrap;
  margin-bottom: var(--sp-16);
}
.pghead-t {
  min-width: 0;
}
.pghead h1 {
  margin: 0;
  font: 600 22px/1.2 var(--font-sans);
  letter-spacing: -0.015em;
}
.pghead-sub {
  margin: 4px 0 0;
  color: var(--color-text-2);
  font-size: 13px;
}
.pghead-acts {
  display: flex;
  gap: var(--sp-8);
  flex-wrap: wrap;
}
.pghead-acts:empty {
  display: none;
}

/* buttons: default, primary, danger (outlined), danger-solid, ghost, link, small, icon */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-6);
  height: var(--ctl);
  padding: 0 var(--sp-12);
  border-radius: var(--r-control);
  border: var(--hair-w) solid var(--color-border-strong);
  background: var(--color-surface);
  color: var(--color-text);
  font: 500 13px var(--font-sans);
  text-box: normal;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
.btn:hover,
.btn:active {
  background: var(--color-surface-2);
  border-color: var(--color-border-strong);
  color: var(--color-text);
}
.btn.btn-primary {
  padding: 0 var(--sp-14);
  border-color: var(--color-accent);
  background: var(--color-accent);
  color: var(--color-on-accent);
  font-weight: 600;
}
.btn.btn-primary:hover,
.btn.btn-primary:active {
  border-color: var(--color-accent-hover);
  background: var(--color-accent-hover);
  color: var(--color-on-accent);
}
.btn.btn-danger,
.btn.btn-danger:hover {
  color: var(--color-danger-fg);
}
.btn.btn-danger-solid {
  padding: 0 var(--sp-14);
  border-color: var(--color-danger-solid);
  background: var(--color-danger-solid);
  color: #fff;
  font-weight: 600;
}
.btn.btn-danger-solid:hover,
.btn.btn-danger-solid:active {
  border-color: var(--color-danger);
  background: var(--color-danger);
  color: #fff;
}
.btn.btn-ghost {
  border-color: transparent;
  background: none;
}
.btn.btn-ghost:hover {
  border-color: transparent;
  background: var(--color-surface-2);
}
.btn.btn-link {
  height: auto;
  min-height: 32px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--color-accent-fg);
}
.btn.btn-link:hover {
  background: none;
  color: var(--color-accent-hover);
}
.btn.btn-sm {
  height: 32px;
}
.btn.btn-icon {
  width: var(--ctl);
  min-width: 32px;
  padding: 0;
  color: var(--color-text-2);
  font: 600 16px var(--font-sans);
}
.btn.btn-icon.btn-sm {
  width: 32px;
}
.btn.btn-tall {
  height: calc(var(--ctl) + 4px);
}
.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: default;
  pointer-events: none;
}
.btn-row {
  display: flex;
  gap: var(--sp-8);
  flex-wrap: wrap;
  align-items: center;
}

/* badges, status dots, avatar: the tone classes (.t-ok, .t-warn, .t-danger, .t-neutral: About, F3) plus the accent */
.t-accent {
  --t: var(--color-accent);
  --t-bg: var(--color-accent-bg);
  --t-fg: var(--color-accent-fg);
}
.bdg {
  display: inline-flex;
  align-items: center;
  height: 20px;
  padding: 0 7px;
  border-radius: var(--r-badge);
  font: 500 11.5px var(--font-sans);
  white-space: nowrap;
  background: var(--t-bg);
  color: var(--t-fg);
}
.sdot {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-6);
  font-size: 13px;
}
.sdot-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
  background: var(--t);
}
.uavatar {
  display: inline-grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  flex: none;
  background: var(--t-bg);
  color: var(--t-fg);
  font: 600 11px var(--font-sans);
}

/* cards: a padded section, a list card (header row, rows), key/value rows */
.ucard {
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  padding: var(--sp-16);
  display: flex;
  flex-direction: column;
  gap: var(--sp-10);
  min-width: 0;
}
.ucard > h2 {
  margin: 0 0 2px;
  font: 600 14px var(--font-sans);
  letter-spacing: normal;
}
.ucard-sub {
  margin: 0 0 4px;
  font-size: 12.5px;
  color: var(--color-text-2);
}
.ucard > .banner {
  margin: 0;
  gap: var(--sp-10);
}
.ucard > .banner .banner-text {
  min-width: 180px;
}
.ulist {
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  min-width: 0;
}
.ulist-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--sp-12) var(--sp-14);
  border-bottom: var(--hair-w) solid var(--color-border);
}
.ulist-head h2 {
  margin: 0;
  font: 600 14px var(--font-sans);
  letter-spacing: normal;
}
.ukv {
  margin: 0;
}
.ukv-row {
  display: grid;
  grid-template-columns: 118px minmax(0, 1fr);
  gap: var(--sp-10);
  padding: var(--sp-6) 0;
  border-top: var(--hair-w) solid var(--color-border);
  font-size: 13px;
}
.ukv dt {
  color: var(--color-text-2);
}
.ukv dd {
  margin: 0;
  overflow-wrap: anywhere;
}
.ukv dd.mono {
  font: 400 12.5px var(--font-mono);
  overflow-wrap: anywhere;
}

/* inline banners: the info tone and an action that is a link (the other tones are the shell's) */
.banner.tone-accent {
  --banner-line: var(--color-accent);
  --banner-bg: var(--color-accent-bg);
  --banner-fg: var(--color-accent-fg);
}
.banner a.banner-btn {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
}
.err-summary {
  max-width: 820px;
}

/* toasts in the flow (style guide) and the toast's action */
.sg-toasts {
  display: flex;
  flex-direction: column;
  gap: var(--sp-8);
  align-items: flex-end;
  padding: var(--sp-16);
  border-radius: var(--r-banner);
  background: var(--color-surface-2);
}
.toast .toast-act {
  height: 30px;
  padding: 0 var(--sp-8);
  border: 0;
  background: none;
  color: var(--color-accent-fg);
  font: 500 13px var(--font-sans);
  text-box: normal;
}
.toast .toast-act:hover {
  background: none;
  color: var(--color-accent-hover);
}
.sg-toasts .toast {
  max-width: 100%;
}
.sg-toasts .toast-text {
  overflow-wrap: anywhere;
}

/* the live indicator in one fixed state (style guide) */
.live-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 30px;
  padding: 0 var(--sp-12);
  border-radius: var(--r-pill);
  border: var(--hair-w) solid var(--color-border);
  background: var(--color-surface);
  font: 500 12px var(--font-sans);
  color: var(--color-text-2);
  min-width: 150px;
}
.live-pill-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
}
.lp-ok .live-pill-dot {
  background: var(--color-ok);
  animation: tf-pulse 2.4s ease-in-out infinite;
}
.lp-re .live-pill-dot {
  background: var(--color-warn);
  animation: tf-pulse 0.9s ease-in-out infinite;
}
.lp-off .live-pill-dot {
  background: var(--color-danger);
}

/* form fields: label above, help or the server's error below */
.ufield {
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
  font: 500 12.5px var(--font-sans);
  color: var(--color-text-2);
  min-width: 0;
}
.ufield-wide {
  grid-column: 1 / -1;
}
.ufield input.mono:not([type="checkbox"]):not([type="radio"]) {
  font-family: var(--font-mono);
}
/* as specific as the base input rule's :not() chain, which would otherwise keep its grey border */
.ufield input[aria-invalid="true"]:not([type="checkbox"]):not([type="radio"]) {
  border-color: var(--color-danger);
  box-shadow: none;
}
.ufield-err {
  font: 400 12px var(--font-sans);
  color: var(--color-danger-fg);
}
.ufield-help {
  font: 400 12px var(--font-sans);
  color: var(--color-text-3);
}
.ucheck {
  display: flex;
  align-items: center;
  gap: var(--sp-10);
  min-height: 36px;
  font: 400 13px var(--font-sans);
  color: var(--color-text);
}
.ucheck input {
  width: 16px;
  height: 16px;
  flex: none; /* a two-line label must not squeeze the box narrower than its neighbours */
}
.ucheck-text {
  display: block;
  font-size: 12px;
  color: var(--color-text-2);
}

/* radio cards: label > input, the checked card in the accent tint */
.rcards {
  margin: 0;
  padding: 0;
  border: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-8);
}
.rcards legend {
  margin: 0 0 var(--sp-5);
  padding: 0;
  font: 500 12.5px var(--font-sans);
  color: var(--color-text-2);
}
.rcard {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: var(--sp-10);
  padding: var(--sp-12) var(--sp-14);
  border-radius: var(--r-banner);
  border: var(--hair-w) solid var(--color-border);
  background: var(--color-surface);
  font: 400 13px var(--font-sans);
  cursor: pointer;
}
.rcard:has(input:checked) {
  border-color: var(--color-accent);
  background: var(--color-accent-bg);
}
.rcard input {
  width: 16px;
  height: 16px;
  margin-top: 2px;
}
.rcard-body b {
  display: block;
  font-weight: 600;
  font-size: 13.5px;
}
.rcard-body span {
  display: block;
  font-size: 12.5px;
  color: var(--color-text-2);
}

/* segmented control: radio inputs in one frame */
.useg {
  display: inline-flex;
  width: fit-content;
  border: var(--hair-w) solid var(--color-border-strong);
  border-radius: var(--r-control);
  overflow: hidden;
}
.useg label {
  display: block;
  position: relative;
}
.useg input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}
.useg span {
  display: flex;
  align-items: center;
  height: var(--ctl);
  padding: 0 var(--sp-12);
  background: var(--color-surface);
  color: var(--color-text);
  font: 500 13px var(--font-sans);
  cursor: pointer;
}
.useg label + label span {
  border-left: var(--hair-w) solid var(--color-border-strong);
}
.useg input:checked + span {
  background: var(--color-surface-3);
}
.useg input:focus-visible + span {
  outline: 2px solid var(--color-accent);
  outline-offset: -2px;
}

/* switches: a setting (with its title and line) and the power toggle of a row */
.utoggle {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--sp-12);
  padding: var(--sp-12) var(--sp-14);
  border-radius: var(--r-banner);
  border: var(--hair-w) solid var(--color-border);
  background: var(--color-surface);
  font: 400 13px var(--font-sans);
  color: var(--color-text);
  cursor: pointer;
}
.utoggle input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}
.utoggle .sw,
.pwr .sw {
  position: relative;
  flex: none;
  width: 38px;
  height: 22px;
  border-radius: 11px;
  background: var(--color-border-strong);
}
.utoggle .sw::after,
.pwr .sw::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #fff;
  box-shadow: var(--shadow-knob);
  transition: left 0.15s;
}
.utoggle input:checked + .sw {
  background: var(--color-accent);
}
.utoggle input:checked + .sw::after {
  left: 19px;
}
.utoggle input:focus-visible + .sw {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}
.utoggle-text b {
  display: block;
  font-weight: 600;
  font-size: 13.5px;
}
.utoggle-text span {
  display: block;
  font-size: 12.5px;
  color: var(--color-text-2);
}
.pwr {
  display: inline-grid;
  place-items: center;
  width: 48px;
  height: 44px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.pwr:hover,
.pwr:active {
  background: none;
}
.pwr .sw {
  width: 34px;
  height: 20px;
  border-radius: 10px;
}
.pwr .sw::after {
  left: 2px;
  width: 14px;
  height: 14px;
}
.pwr[aria-checked="true"] .sw {
  background: var(--color-accent);
}
.pwr[aria-checked="true"] .sw::after {
  left: 18px;
}
.pwr[aria-pressed="true"],
.pwr[aria-pressed="true"]:hover {
  border: 0;
  background: none;
  color: inherit;
}
.pwr:disabled {
  opacity: 0.45;
  cursor: default;
}

/* stat tiles and the fleet health bar */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--sp-10);
}
@media (max-width: 44.99rem) {
  /* two across on a phone, wherever the grid sits (the style guide's sample box is narrower than the dashboard) */
  .stat-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
.stat-tile {
  display: flex;
  flex-direction: column;
  gap: var(--sp-8);
  padding: var(--sp-14);
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  color: var(--color-text);
  text-decoration: none;
}
.stat-tile:hover {
  border-color: var(--color-border-strong);
  color: var(--color-text);
}
.stat-label {
  display: flex;
  align-items: center;
  gap: 7px;
  font: 500 12.5px var(--font-sans);
  color: var(--color-text-2);
}
.stat-value {
  font: 600 var(--fs-stat) / 1 var(--font-sans);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
.stat-hint {
  font-size: 12px;
  color: var(--color-text-3);
}
.health-bar {
  display: block;
  width: 100%;
  height: 8px;
  margin: var(--sp-12) 0 var(--sp-18);
  border-radius: 4px;
  background: var(--color-surface-2);
}
.health-bar .bar-seg,
.seg-bar .bar-seg {
  fill: var(--t);
}
.seg-bar .bar-seg.t-accent {
  opacity: 0.55;
}

/* "Needs attention" rows, transaction card and history rows */
.att-row {
  display: flex;
  align-items: center;
  gap: var(--sp-10);
  flex-wrap: wrap;
  padding: var(--sp-10) var(--sp-14);
  border-bottom: var(--hair-w) solid var(--color-border);
  min-height: 44px;
  color: var(--color-text);
  text-decoration: none;
}
a.att-row:hover {
  background: var(--color-surface-2);
  color: var(--color-text);
}
.att-prop {
  gap: var(--sp-6) var(--sp-10);
  padding: var(--sp-8) var(--sp-10) var(--sp-8) var(--sp-14);
  min-height: 52px;
}
.att-item {
  align-items: flex-start;
  flex-wrap: nowrap;
}
.att-item .sdot-dot {
  margin-top: 6px;
}
.att-text {
  flex: 1 1 180px;
  min-width: 0;
}
.att-name {
  display: block;
  font-weight: 500;
  overflow-wrap: anywhere;
}
.att-why {
  display: block;
  font-size: 12.5px;
  color: var(--color-text-2);
}
.att-acts {
  display: flex;
  gap: var(--sp-6);
}
.att-acts form {
  margin: 0;
}
.att-go {
  color: var(--color-text-3);
}
.txn-card {
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding: var(--sp-14);
  border-bottom: var(--hair-w) solid var(--color-border);
  color: var(--color-text);
  text-decoration: none;
}
.txn-card:hover {
  background: var(--color-surface-2);
  color: var(--color-text);
}
.txn-head {
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  flex-wrap: wrap;
}
.txn-id {
  font: 500 12px var(--font-mono);
  color: var(--color-text-2);
}
.txn-title {
  font-weight: 600;
}
.txn-sum {
  font-size: 12.5px;
  color: var(--color-text-2);
}
.seg-bar {
  display: block;
  width: 100%;
  height: 6px;
  border-radius: 3px;
  background: var(--color-surface-3);
}
.txn-row-title {
  flex: 1;
  min-width: 140px;
}
.txn-when {
  font-size: 12px;
  color: var(--color-text-3);
}
.mini-bar {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-8);
}
.mini-bar svg {
  display: block;
  width: 80px;
  height: 4px;
  border-radius: 2px;
}
.mini-bg {
  fill: var(--color-surface-3);
}
.mini-fill {
  fill: var(--color-accent);
}
.mini-pct {
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--color-text-2);
}

/* tabs: underline tabs; a disabled tab carries its reason as the title */
.utabs {
  display: flex;
  gap: var(--sp-20);
  border-bottom: var(--hair-w) solid var(--color-border);
  margin-bottom: var(--sp-16);
  overflow-x: auto;
}
.utab {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-6);
  height: calc(var(--ctl) + 6px);
  padding: 0 2px;
  font: 500 13.5px var(--font-sans);
  color: var(--color-text-2);
  text-decoration: none;
  white-space: nowrap;
  box-shadow: inset 0 -2px 0 transparent;
}
.utab:hover {
  color: var(--color-text);
}
.utab[aria-current="page"] {
  color: var(--color-text);
  box-shadow: inset 0 -2px 0 var(--color-accent);
}
.utab[aria-disabled="true"] {
  color: var(--color-text-3);
  cursor: default;
}

/* row menu panel (ui.RowMenu); the legacy row menus keep their look until their page is ported */
details.umenu[open] > summary.btn {
  background: var(--color-surface-2);
  border-color: transparent;
  color: var(--color-text);
}
.umenu .menu-panel {
  display: block;
  width: 250px;
  min-width: 0;
  padding: 5px;
  background: var(--color-surface);
  /* the prototype draws --color-border; the strong border keeps the 1.3:1 overlay guard (g), as the
     user menu does (F3) */
  border: var(--hair-w) solid var(--color-border-strong);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-lg);
}
.umenu .menu-panel .menu-item {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: stretch;
  gap: 1px;
  width: 100%;
  height: auto;
  min-height: var(--ctl);
  padding: 6px 10px;
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  color: var(--color-text);
  font: 400 13px var(--font-sans);
  text-align: left;
  text-decoration: none;
  white-space: normal;
  opacity: 1;
}
.umenu .menu-panel .menu-item:hover {
  background: var(--color-surface-2);
}
.umenu .menu-panel .menu-item.danger {
  color: var(--color-danger-fg);
}
.umenu .menu-panel .menu-item[aria-disabled="true"] {
  color: var(--color-text-3);
  cursor: default;
  pointer-events: none;
}
.menu-why {
  font-size: 11.5px;
  color: var(--color-text-3);
}
.umenu .menu-panel hr {
  height: 1px;
  margin: 5px 0;
  border: 0;
  background: var(--color-border);
}

/* dialogs: confirm (with a change list or a command input) and step-up */
dialog.udlg {
  width: min(480px, calc(100% - 32px));
  max-height: 90%;
  overflow: auto;
  padding: var(--sp-20);
  /* a dialog taller than the screen scrolls inside itself: a soft shadow on the cut edge says there
     is more (the "local" fades cover it once the end is reached, as for pre.log) */
  background:
    linear-gradient(var(--color-surface) 30%, transparent) center top / 100% 24px no-repeat local,
    linear-gradient(transparent, var(--color-surface) 70%) center bottom / 100% 24px no-repeat local,
    linear-gradient(
        color-mix(in srgb, var(--color-text) 14%, transparent),
        transparent
      )
      center top / 100% 12px no-repeat scroll,
    linear-gradient(
        transparent,
        color-mix(in srgb, var(--color-text) 14%, transparent)
      )
      center bottom / 100% 12px no-repeat scroll,
    var(--color-surface);
  color: var(--color-text);
  border: var(--hair-w) solid var(--color-border-strong); /* overlay guard (g), see the menu panel */
  border-radius: var(--r-panel);
  box-shadow: var(--shadow-lg);
}
dialog.udlg::backdrop {
  background: var(--backdrop);
}
/* as for the drawer: the canvas in the reserved scrollbar gutter takes the scrim-mixed page
   colour while a dialog is open (P8: "Confirm it's you" left a light strip on the right) */
html:has(dialog.udlg:modal) {
  background: color-mix(in srgb, var(--color-bg) 50%, rgb(10, 14, 18));
}
html:has(dialog.udlg:modal) body {
  min-height: 100vh;
}
dialog.stepup {
  width: min(420px, calc(100% - 32px));
}
.udlg-in {
  display: flex;
  flex-direction: column;
  gap: var(--sp-14);
  margin: 0;
}
.udlg-in h2,
.stepup h2 {
  margin: 0;
  font: 600 16px/1.3 var(--font-sans);
  letter-spacing: normal;
}
.udlg-body {
  margin: 0;
  color: var(--color-text-2);
  text-wrap: pretty;
}
.udlg-body b {
  color: var(--color-text);
  font-weight: 600;
}
.udlg-changes {
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-code);
  max-height: 220px;
  overflow: auto;
}
.udlg-changes > div {
  display: flex;
  gap: var(--sp-10);
  justify-content: space-between;
  padding: var(--sp-8) var(--sp-12);
  border-bottom: var(--hair-w) solid var(--color-border);
  font-size: 13px;
}
.udlg-changes span:first-child {
  min-width: 0;
  overflow-wrap: anywhere;
}
.udlg-changes .mono {
  font: 400 12px var(--font-mono);
  color: var(--color-text-2);
  white-space: nowrap;
}
.udlg-foot {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-8);
  flex-wrap: wrap;
  margin: 0;
}
.udlg-foot .btn {
  padding: 0 var(--sp-14);
}
.stepup-who {
  display: flex;
  align-items: center;
  gap: var(--sp-10);
}
.stepup-sub {
  font-size: 12.5px;
  color: var(--color-text-2);
}
.stepup .udlg-body {
  font-size: 13.5px;
}
.or-rule {
  display: flex;
  align-items: center;
  gap: var(--sp-10);
  font-size: 12px;
  color: var(--color-text-3);
}
.or-rule::before,
.or-rule::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--color-border);
}
.confirm-card {
  max-width: 760px;
  gap: var(--sp-14);
}
.confirm-card > h2 {
  font: 600 16px/1.3 var(--font-sans);
}

/* empty state, "no match" row, loading skeleton */
.uempty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-10);
  padding: var(--sp-40) var(--sp-20);
  text-align: center;
  background: var(--color-surface);
  border: var(--hair-w) dashed var(--color-border-strong);
  border-radius: var(--r-panel);
}
.uempty-icon {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: var(--r-panel);
  background: var(--color-surface-2);
}
.uempty-icon span {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 2px solid var(--color-text-3);
}
.uempty h2 {
  margin: 0;
  font: 600 17px var(--font-sans);
  letter-spacing: normal;
}
.uempty p {
  margin: 0;
  max-width: 420px;
  color: var(--color-text-2);
  text-wrap: pretty;
}
.uempty .btn-row {
  justify-content: center;
  margin-top: var(--sp-6);
}
.nomatch {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-10);
  padding: var(--sp-24);
  font-size: 13px;
  color: var(--color-text-2);
  text-align: center;
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
}
.skel {
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  overflow: hidden;
}
.skel-head {
  padding: var(--sp-10) var(--sp-14);
  font-size: 12.5px;
  color: var(--color-text-2);
  border-bottom: var(--hair-w) solid var(--color-border);
}
.skel-row {
  display: flex;
  align-items: center;
  gap: var(--sp-14);
  height: 44px;
  padding: 0 var(--sp-14);
  border-bottom: var(--hair-w) solid var(--color-border);
}
.skel-row:last-child {
  border-bottom: 0;
}
.skel-box {
  width: 16px;
  height: 16px;
  border-radius: var(--r-xs);
  background: var(--color-surface-3);
}
.skel-line {
  height: 10px;
  width: 60%;
  max-width: 260px;
  border-radius: var(--r-badge);
  background: linear-gradient(
    90deg,
    var(--color-surface-2) 0,
    var(--color-surface-3) 50%,
    var(--color-surface-2) 100%
  );
  background-size: 600px 100%;
  animation: tf-shimmer 1.4s linear infinite;
}
.skel-fill {
  flex: 1;
}
.skel-end {
  height: 10px;
  width: 70px;
  border-radius: var(--r-badge);
  background: var(--color-surface-2);
}

/* error page: code, title, explanation, the failed path, two ways on */
.errpage {
  min-height: 440px;
  display: flex;
  align-items: center;
  padding: var(--sp-24) 0;
}
.errpage-in {
  max-width: 560px;
  display: flex;
  flex-direction: column;
  gap: var(--sp-12);
  align-items: flex-start;
}
.errpage-code {
  font: 500 13px var(--font-mono);
  color: var(--color-text-3);
}
.errpage h1 {
  margin: 0;
  font: 600 26px/1.2 var(--font-sans);
  letter-spacing: -0.02em;
  text-wrap: balance;
}
.errpage p {
  margin: 0;
  color: var(--color-text-2);
  font-size: 14.5px;
  text-wrap: pretty;
}
.errpage-path {
  font: 400 12.5px var(--font-mono);
  color: var(--color-text-2);
  background: var(--color-surface-2);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-control);
  padding: 7px var(--sp-10);
  overflow-wrap: anywhere;
}
.errpage .btn-row {
  margin-top: var(--sp-6);
}

/* sign-in card: brand above, the card, the version footer */
.uauth {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-18);
}
.auth-card {
  width: min(420px, 100%);
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-panel);
  padding: var(--sp-24);
  display: flex;
  flex-direction: column;
  gap: var(--sp-14);
}
.auth-card h1 {
  margin: 0;
  font: 600 20px/1.2 var(--font-sans);
  letter-spacing: -0.015em;
}
.auth-card > .banner {
  margin: 0;
}
.auth-foot {
  font: 400 12px var(--font-mono);
  color: var(--color-text-3);
  text-align: center;
  text-wrap: balance;
}
.auth-foot > span {
  display: inline-block; /* version and host wrap as units, never inside */
  max-width: 100%;
  overflow-wrap: anywhere;
}

/* console: dark panel, timestamped lines, prompt, quick commands */
.console {
  background: var(--color-term-bg);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  overflow: hidden;
  color: var(--color-term-fg);
}
.console-head {
  display: flex;
  align-items: center;
  gap: var(--sp-10);
  padding: var(--sp-8) var(--sp-12);
  border-bottom: var(--hair-w) solid var(--color-console-rule);
  font: 500 12px var(--font-sans);
  color: var(--color-term-dim);
}
.console-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--color-ok);
  animation: tf-pulse 2.4s infinite;
}
.console-title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.console .console-clear,
.console .console-chip {
  height: 28px;
  padding: 0 var(--sp-10);
  border-radius: var(--r-sm);
  border: var(--hair-w) solid var(--color-console-line);
  background: none;
  color: var(--color-term-fg);
  font: 500 12px var(--font-sans);
  text-box: normal;
}
.console .console-chip {
  border-radius: var(--r-pill);
  font-family: var(--font-mono);
}
.console .console-clear:hover,
.console .console-chip:hover {
  background: var(--color-console-rule);
  border-color: var(--color-console-line);
  color: var(--color-term-fg);
}
.console-lines {
  max-height: min(440px, 52vh);
  overflow: auto;
  padding: var(--sp-12) var(--sp-14);
  font: 400 12.5px/1.65 var(--font-mono);
}
.console-line {
  display: flex;
  gap: var(--sp-12);
}
.console-time {
  color: var(--color-term-dim);
  flex: none;
}
.console-text {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  min-width: 0;
}
.console-line.is-cmd .console-text {
  color: var(--color-term-cmd);
}
.console-line.is-err .console-text {
  color: var(--color-term-err);
}
.console-form {
  display: flex;
  gap: var(--sp-8);
  margin: 0;
  padding: var(--sp-10);
  border-top: var(--hair-w) solid var(--color-console-rule);
}
.console-prompt {
  align-self: center;
  padding-left: 4px;
  color: var(--color-term-cmd);
  font: 500 14px var(--font-mono);
}
.console-form input:not([type="checkbox"]):not([type="radio"]) {
  flex: 1;
  border-color: var(--color-console-line);
  background: var(--color-console-rule);
  color: var(--color-term-fg);
  font: 400 13px var(--font-mono);
}
.console-quick {
  display: flex;
  gap: var(--sp-6);
  flex-wrap: wrap;
  margin: 0;
  padding: 0 var(--sp-10) var(--sp-10);
}

/* backup comparison: side by side or unified */
.diff {
  overflow: hidden;
}
.diff-scroll {
  overflow-x: auto;
}
.diff-grid {
  display: grid;
  grid-template-columns: minmax(150px, 0.7fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--sp-12);
  min-width: 620px;
  padding: var(--sp-8) var(--sp-16);
  border-bottom: var(--hair-w) solid var(--color-border);
}
.diff-headrow {
  background: var(--color-surface-2);
  font: 500 12px var(--font-sans);
  color: var(--color-text-2);
}
.diff-row {
  min-height: 36px;
  font: 400 12.5px var(--font-mono);
  overflow-wrap: anywhere;
  color: var(--color-text-2);
}
.diff-row.is-changed {
  background: var(--color-warn-bg);
  color: var(--color-text);
}
.diff-key {
  color: var(--color-text);
  font-weight: 500;
}
/* phone: the setting on its own line, older and newer side by side under it; nothing to scroll sideways */
@media (max-width: 44.99rem) {
  .diff-grid {
    min-width: 0;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 2px var(--sp-12);
  }
  .diff-headrow > :first-child {
    display: none;
  }
  .diff-key {
    grid-column: 1 / -1;
  }
}
.diff-uni {
  padding: var(--sp-6) 0;
  font: 400 12.5px/1.6 var(--font-mono);
}
.diff-uni-head {
  padding: 2px var(--sp-14) var(--sp-8);
  font: 500 12px var(--font-sans);
  color: var(--color-text-2);
}
.diff-line {
  display: grid;
  grid-template-columns: 16px minmax(0, 1fr);
  gap: var(--sp-8);
  padding: 3px var(--sp-14);
  color: var(--color-text-2);
  overflow-wrap: anywhere;
}
.diff-line b {
  font-weight: 500;
  color: var(--color-text);
}
.diff-line.is-del {
  background: var(--color-danger-bg);
  color: var(--color-danger-fg);
}
.diff-line.is-add {
  background: var(--color-ok-bg);
  color: var(--color-ok-fg);
}

/* release notes: text only, the breaking-change box in the warn tone */
.unotes {
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  padding: var(--sp-20) var(--sp-22);
  display: flex;
  flex-direction: column;
  gap: var(--sp-16);
  font-size: 14px;
  line-height: 1.6;
}
.unotes p,
.unotes ul {
  margin: 0;
}
.unotes ul {
  padding-left: var(--sp-20);
}
.unotes h2 {
  margin: 0;
  font: 600 15px var(--font-sans);
  letter-spacing: normal;
}
.unotes pre {
  margin: 0;
  padding: var(--sp-10) var(--sp-12);
  border-radius: var(--r-code);
  font: 400 12px/1.6 var(--font-mono);
}
.unotes pre code {
  padding: 0;
  background: none;
  font-size: inherit;
}
.unotes-breaking {
  border: var(--hair-w) solid var(--color-warn);
  background: var(--color-warn-bg);
  border-radius: var(--r-banner);
  padding: var(--sp-12) var(--sp-16);
}
.unotes-breaking h2 {
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  margin: 0 0 var(--sp-6);
  font-size: 14px;
  color: var(--color-warn-fg);
}

/* ==== page: Styleguide (/styleguide, WP F4): the prototype's UI states, then the gallery ==== */
.sg-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 460px), 1fr));
  gap: var(--sp-14);
  align-items: start;
}
.sg-live {
  grid-column: 1 / -1;
  display: block;
}
.sg-live > h2 {
  margin: 0 0 4px;
}
.sg-live > .ucard-sub {
  margin: 0 0 6px;
}
.sg-live-row {
  display: flex;
  align-items: center;
  gap: var(--sp-14);
  flex-wrap: wrap;
  padding: var(--sp-10) 0;
  border-top: var(--hair-w) solid var(--color-border);
}
.sg-live-row > span:last-child {
  flex: 1;
  min-width: 200px;
  font-size: 13px;
  color: var(--color-text-2);
}
/* the gallery starts where the prototype's screen ends (main's 120 px bottom padding), so the
   UI-states screen above it is the prototype's to the pixel and the gallery only adds below */
.sg-gallery {
  display: flex;
  flex-direction: column;
  gap: var(--sp-14);
  margin-top: 120px;
  padding-top: var(--sp-24);
  border-top: var(--hair-w) solid var(--color-border);
}
.sg-gallery-head h2 {
  margin: 0;
  font: 600 17px var(--font-sans);
  letter-spacing: -0.01em;
}
.sg-gallery-head p {
  margin: 4px 0 0;
  font-size: 13px;
  color: var(--color-text-2);
}
.sg-row {
  display: flex;
  gap: var(--sp-8);
  flex-wrap: wrap;
  align-items: center;
}
.sg-cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr));
  gap: var(--sp-14);
  align-items: start;
}
.sg-stack {
  display: flex;
  flex-direction: column;
  gap: var(--sp-12);
  align-items: flex-start;
}
.sg-form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  gap: var(--sp-14) var(--sp-18);
  max-width: 820px;
}
.sg-label {
  margin: 0 0 var(--sp-6);
  font: 500 12.5px var(--font-sans);
  color: var(--color-text-2);
}
/* open menus and dialogs in the flow (data-static: the scripts leave them alone) */
.sg-flow {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-24);
  align-items: flex-start;
}
.sg-flow details[data-static] > .rowmenu-body {
  position: static;
  margin-top: var(--sp-6);
}
.sg-flow details.usermenu {
  display: inline-block;
}
.sg-flow .um-menu {
  position: static;
  margin-top: var(--sp-8);
}
.sg-drawer .dr {
  width: min(300px, 100%);
  padding: var(--sp-10);
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
}
.sg-flow dialog[data-static] {
  position: static;
  margin: 0;
  max-height: none;
}
.sg-sec .errpage {
  min-height: 0;
}
.sg-sec .uauth {
  padding: var(--sp-24) var(--sp-16);
  border-radius: var(--r-banner);
  background: var(--color-bg);
}
@media (prefers-reduced-motion: reduce) {
  .live-pill-dot,
  .console-dot,
  .skel-line {
    animation: none;
  }
}

/* ==== page: sign-in, account and users (WP P9) ==== */
/* standalone pages (sign-in, forced password change, messages): the auth card centred */
body.page-auth main {
  padding: 0 var(--page-pad);
}
.page-auth .uauth {
  min-height: calc(100vh - 150px);
  justify-content: center;
  gap: var(--sp-20);
  padding: var(--sp-12) 0;
}
.page-auth .brand {
  gap: var(--sp-10);
  font-size: 18px;
}
.page-auth .brand-mark {
  width: 28px;
  height: 28px;
}
.auth-card .banner {
  margin: 0;
  gap: var(--sp-10);
  padding: var(--sp-10) var(--sp-12);
  align-items: flex-start;
  flex-wrap: nowrap;
}
.auth-card .banner-dot {
  margin-top: 5px;
}
.auth-card .ucheck input {
  margin: 3px 3px 3px 4px;
}
.auth-card > form.auth-form {
  display: contents;
}
.auth-card .btn-tall {
  width: 100%;
}
.auth-text {
  margin: 0;
  color: var(--color-text-2);
  font-size: 13.5px;
  text-wrap: pretty;
}
.pw-who {
  display: flex;
  align-items: center;
  gap: var(--sp-10);
  padding: var(--sp-8) var(--sp-10);
  border-radius: var(--r-control);
  background: var(--color-surface-2);
  font-size: 12.5px;
  color: var(--color-text-2);
}
.pw-who .uavatar {
  width: 26px;
  height: 26px;
  font-size: 10.5px;
}
.pw-who b {
  color: var(--color-text);
  font-weight: 600;
}
.pw-checks {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  font-size: 12.5px;
  color: var(--color-text-2);
}
.pw-checks li::before {
  content: "○";
  display: inline-block;
  width: 14px;
  margin-right: var(--sp-8);
  text-align: center;
}
.auth-signout {
  display: flex;
  justify-content: center;
  margin: 0;
}
/* account page: profile and password side by side, one column on a phone */
.acct-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr));
  gap: var(--sp-14);
  align-items: start;
  max-width: 900px;
}
.acct-grid .ukv {
  display: grid;
  gap: var(--sp-6);
}
.acct-grid .ukv-row {
  grid-template-columns: 110px minmax(0, 1fr);
  padding: 0;
  border-top: 0;
}
.acct-form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-12);
  margin: 0;
}
.acct-submit {
  align-self: flex-end;
}
.acct-edit .acct-form {
  margin-top: var(--sp-10);
}
/* user list: one wrapping row per user (who, badges, source, last sign-in, menu) */
.users-list {
  margin-bottom: var(--sp-12);
}
.urow {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-6) var(--sp-12);
  min-height: 58px;
  padding: var(--sp-6) var(--sp-6) var(--sp-6) var(--sp-16);
  border-bottom: var(--hair-w) solid var(--color-border);
}
.urow > a.btn {
  margin-right: var(--sp-10); /* the row's right padding fits the icon button, not a text one */
}
.urow-off {
  background: var(--color-surface-2);
}
.urow-who {
  flex: 2 1 220px;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--sp-10);
  padding: var(--sp-4) 0;
}
.urow-off .urow-who {
  color: var(--color-text-2);
}
.urow-names {
  min-width: 0;
}
.urow-name {
  display: flex;
  align-items: center;
  gap: var(--sp-6);
  flex-wrap: wrap;
  font-weight: 500;
  overflow-wrap: anywhere;
}
.urow-sub {
  display: block;
  font-size: 12px;
  color: var(--color-text-2);
  overflow-wrap: anywhere;
}
.urow-badges {
  flex: 1 1 190px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-6);
}
.urow-meta {
  flex: 1 1 170px;
  font-size: 12.5px;
  color: var(--color-text-2);
}
.urow > .rowmenu {
  flex: none;
}
.urow > .rowmenu > summary {
  width: 40px;
  height: 40px;
}
.urow .uavatar {
  background: var(--color-surface-3);
  color: var(--color-text-2);
}
.users-note {
  margin: 0;
  max-width: 760px;
  font-size: 12.5px;
  color: var(--color-text-2);
  text-wrap: pretty;
}
/* add-user form: two columns of fields, the password choice across, the buttons at the foot */
.useradd-sum {
  max-width: 760px;
  margin-bottom: var(--sp-14);
}
form.useradd {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  gap: var(--sp-14) var(--sp-18);
  max-width: 760px;
  padding: var(--sp-18);
  margin: 0;
}
.useradd-mode {
  grid-column: 1 / -1;
}
.useradd-mode .rcards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  gap: var(--sp-10);
}
.useradd-mode legend {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.useradd-pw {
  display: contents;
}
form.useradd:has(input[name="otp"][value="1"]:checked) .useradd-pw {
  display: none;
}
.useradd-foot {
  grid-column: 1 / -1;
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-8);
  border-top: var(--hair-w) solid var(--color-border);
  padding-top: var(--sp-14);
}

/* ==== page: About (WP F3 pilot) ==== */
.about-head {
  margin-bottom: var(--sp-16);
}
.about-head h1 {
  margin: 0;
  font: 600 22px/1.2 var(--font-sans);
  letter-spacing: -0.015em;
}
.about-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr));
  gap: var(--sp-14);
  align-items: start;
  max-width: 980px;
}
.about-card {
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
}
.about-version {
  padding: var(--sp-16);
}
.about-name {
  font: 600 18px var(--font-sans);
}
.about-build {
  font: 400 12.5px var(--font-mono);
  color: var(--color-text-2);
  margin-top: var(--sp-4);
}
.about-meta {
  font-size: 13px;
  color: var(--color-text-2);
  margin-top: var(--sp-12);
}
.about-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-8);
  margin-top: var(--sp-14);
}
.about-actions .button {
  height: var(--ctl);
  padding: 0 var(--sp-12);
  font: 500 13px var(--font-sans);
  text-box: normal;
}
.about-comps {
  overflow: hidden;
}
.about-comps h2 {
  margin: 0;
  padding: var(--sp-12) var(--sp-16);
  border-bottom: var(--hair-w) solid var(--color-border);
  font: 600 14px var(--font-sans);
  letter-spacing: normal;
}
.comp-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.comp {
  display: flex;
  align-items: center;
  gap: var(--sp-10);
  flex-wrap: wrap;
  padding: var(--sp-9) var(--sp-16);
  border-bottom: var(--hair-w) solid var(--color-border);
}
.comp-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--t);
}
.comp-text {
  flex: 1;
  min-width: 140px;
}
.comp-name {
  display: block;
  font-weight: 500;
  font-size: 13px;
}
.comp-detail {
  display: block;
  font: 400 12px var(--font-mono);
  color: var(--color-text-2);
}
.comp-state {
  display: inline-flex;
  align-items: center;
  height: 20px;
  padding: 0 var(--sp-7);
  border-radius: var(--r-badge);
  font: 500 11.5px var(--font-sans);
  background: var(--t-bg);
  color: var(--t-fg);
}
.t-ok {
  --t: var(--color-ok);
  --t-bg: var(--color-ok-bg);
  --t-fg: var(--color-ok-fg);
}
.t-warn {
  --t: var(--color-warn);
  --t-bg: var(--color-warn-bg);
  --t-fg: var(--color-warn-fg);
}
.t-danger {
  --t: var(--color-danger);
  --t-bg: var(--color-danger-bg);
  --t-fg: var(--color-danger-fg);
}
.t-neutral {
  --t: var(--color-neutral);
  --t-bg: var(--color-neutral-bg);
  --t-fg: var(--color-neutral-fg);
}
.about-config {
  margin-top: var(--sp-24);
  max-width: 980px;
}

/* count pill on a navigation entry: "Add devices 5" */
.nav-badge {
  display: inline-flex;
  align-items: center;
  height: 18px;
  padding: 0 var(--sp-6);
  border-radius: 9px;
  font: 500 11px var(--font-sans);
  white-space: nowrap;
  background: var(--color-accent);
  color: var(--color-on-accent);
}

/* phones: a crumb link is a 40 px touch target without moving the line */
@media (max-width: 44.99rem) {
  nav.crumbs a,
  .crumb.trail a {
    display: inline-block;
    padding: 11px 0;
    margin: -11px 0;
  }
}

/* ==== page: Dashboard (/, WP P1): tiles, health bar, "Needs attention" and the transactions ==== */
.dash-cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr));
  gap: var(--sp-14);
  align-items: start;
}
.dash-none {
  margin: 0;
  padding: var(--sp-14);
  font-size: 13px;
  color: var(--color-text-2);
}
/* phones: the prototype's 32 px buttons and header links keep their look and get a 40 px touch
   target from a ::after reaching 4 px past them (e2e smallTargets measures it) */
@media (max-width: 44.99rem) {
  .att-acts .btn-sm,
  .ulist-head .btn-link {
    position: relative;
  }
  .att-acts .btn-sm::after,
  .ulist-head .btn-link::after {
    content: "";
    position: absolute;
    inset: -4px 0;
  }
}

/* ==========================================================================
   F5 (design v2): data tables, pinned columns, phone device cards, bulk bar.
   Markup: ui.Table / tableprefs.go (table, Columns chooser), ui.DeviceCards,
   devices.html (bulk bar). Behaviour: tables.js, select.js.
   ========================================================================== */

/* The table frame of the prototype: a surface card whose content scrolls sideways when the
   columns need more room than the page has (from 45rem; below it the device list shows cards).
   A table inside a card keeps the card's frame. */
@media (min-width: 45rem) {
  .tablescroll {
    overflow-x: auto;
  }
  /* without tables.js nothing places an open menu outside the scrolling box: it stops clipping */
  .tablescroll:not(.is-js):has(details[open]) {
    overflow: visible;
  }
  .tablewrap:not(.card .tablewrap) > .tablescroll {
    background: var(--color-surface);
    border: var(--hair-w) solid var(--color-border);
    border-radius: 10px;
  }
  .tablescroll > table {
    border-collapse: separate;
    border-spacing: 0;
  }
  .tablescroll > table > thead > tr > th {
    height: 38px;
    padding: 0 14px 0 10px;
    background: var(--color-surface-2);
    font: 500 12px var(--font-sans);
    letter-spacing: 0;
    text-transform: none;
    color: var(--color-text-2);
    vertical-align: middle;
  }
  .tablescroll > table > thead > tr > th.sel {
    padding: 0 0 0 6px; /* as td.sel: the select-all box on the row boxes' line */
  }
  .tablewrap:not(.card .tablewrap)
    > .tablescroll
    > table
    > tbody
    > tr:last-child
    > td {
    border-bottom: 0;
  }
}

/* Pinned columns (D19): the server marks them per table (plN pinned left, prN pinned right,
   N = the column's place), tables.js measures the offsets (--plN, --prN). They stay at their
   edge while the table scrolls sideways; a line separates them from the scrolling columns.
   The background is the row's (:where keeps the hover and selection colours in charge). */
@media (min-width: 45rem) {
  table.pl1 > :is(thead, tbody) > tr > :nth-child(1),
  table.pl2 > :is(thead, tbody) > tr > :nth-child(2),
  table.pl3 > :is(thead, tbody) > tr > :nth-child(3),
  table.pl4 > :is(thead, tbody) > tr > :nth-child(4),
  table.pl5 > :is(thead, tbody) > tr > :nth-child(5),
  table.pl6 > :is(thead, tbody) > tr > :nth-child(6),
  table.pl7 > :is(thead, tbody) > tr > :nth-child(7),
  table.pl8 > :is(thead, tbody) > tr > :nth-child(8),
  table.pl9 > :is(thead, tbody) > tr > :nth-child(9),
  table.pl10 > :is(thead, tbody) > tr > :nth-child(10),
  table.pl11 > :is(thead, tbody) > tr > :nth-child(11),
  table.pl12 > :is(thead, tbody) > tr > :nth-child(12),
  table.pl13 > :is(thead, tbody) > tr > :nth-child(13),
  table.pl14 > :is(thead, tbody) > tr > :nth-child(14),
  table.pl15 > :is(thead, tbody) > tr > :nth-child(15),
  table.pl16 > :is(thead, tbody) > tr > :nth-child(16),
  table.pr1 > :is(thead, tbody) > tr > :nth-child(1),
  table.pr2 > :is(thead, tbody) > tr > :nth-child(2),
  table.pr3 > :is(thead, tbody) > tr > :nth-child(3),
  table.pr4 > :is(thead, tbody) > tr > :nth-child(4),
  table.pr5 > :is(thead, tbody) > tr > :nth-child(5),
  table.pr6 > :is(thead, tbody) > tr > :nth-child(6),
  table.pr7 > :is(thead, tbody) > tr > :nth-child(7),
  table.pr8 > :is(thead, tbody) > tr > :nth-child(8),
  table.pr9 > :is(thead, tbody) > tr > :nth-child(9),
  table.pr10 > :is(thead, tbody) > tr > :nth-child(10),
  table.pr11 > :is(thead, tbody) > tr > :nth-child(11),
  table.pr12 > :is(thead, tbody) > tr > :nth-child(12),
  table.pr13 > :is(thead, tbody) > tr > :nth-child(13),
  table.pr14 > :is(thead, tbody) > tr > :nth-child(14),
  table.pr15 > :is(thead, tbody) > tr > :nth-child(15),
  table.pr16 > :is(thead, tbody) > tr > :nth-child(16) {
    position: sticky;
    z-index: 1;
  }
  :where(
    table.pl1 > :is(thead, tbody) > tr > :nth-child(1),
    table.pl2 > :is(thead, tbody) > tr > :nth-child(2),
    table.pl3 > :is(thead, tbody) > tr > :nth-child(3),
    table.pl4 > :is(thead, tbody) > tr > :nth-child(4),
    table.pl5 > :is(thead, tbody) > tr > :nth-child(5),
    table.pl6 > :is(thead, tbody) > tr > :nth-child(6),
    table.pl7 > :is(thead, tbody) > tr > :nth-child(7),
    table.pl8 > :is(thead, tbody) > tr > :nth-child(8),
    table.pl9 > :is(thead, tbody) > tr > :nth-child(9),
    table.pl10 > :is(thead, tbody) > tr > :nth-child(10),
    table.pl11 > :is(thead, tbody) > tr > :nth-child(11),
    table.pl12 > :is(thead, tbody) > tr > :nth-child(12),
    table.pl13 > :is(thead, tbody) > tr > :nth-child(13),
    table.pl14 > :is(thead, tbody) > tr > :nth-child(14),
    table.pl15 > :is(thead, tbody) > tr > :nth-child(15),
    table.pl16 > :is(thead, tbody) > tr > :nth-child(16),
    table.pr1 > :is(thead, tbody) > tr > :nth-child(1),
    table.pr2 > :is(thead, tbody) > tr > :nth-child(2),
    table.pr3 > :is(thead, tbody) > tr > :nth-child(3),
    table.pr4 > :is(thead, tbody) > tr > :nth-child(4),
    table.pr5 > :is(thead, tbody) > tr > :nth-child(5),
    table.pr6 > :is(thead, tbody) > tr > :nth-child(6),
    table.pr7 > :is(thead, tbody) > tr > :nth-child(7),
    table.pr8 > :is(thead, tbody) > tr > :nth-child(8),
    table.pr9 > :is(thead, tbody) > tr > :nth-child(9),
    table.pr10 > :is(thead, tbody) > tr > :nth-child(10),
    table.pr11 > :is(thead, tbody) > tr > :nth-child(11),
    table.pr12 > :is(thead, tbody) > tr > :nth-child(12),
    table.pr13 > :is(thead, tbody) > tr > :nth-child(13),
    table.pr14 > :is(thead, tbody) > tr > :nth-child(14),
    table.pr15 > :is(thead, tbody) > tr > :nth-child(15),
    table.pr16 > :is(thead, tbody) > tr > :nth-child(16)
  ) {
    background-color: var(--color-surface);
  }
  :where(
    table.pl1 > thead > tr > :nth-child(1),
    table.pl2 > thead > tr > :nth-child(2),
    table.pl3 > thead > tr > :nth-child(3),
    table.pl4 > thead > tr > :nth-child(4),
    table.pl5 > thead > tr > :nth-child(5),
    table.pl6 > thead > tr > :nth-child(6),
    table.pl7 > thead > tr > :nth-child(7),
    table.pl8 > thead > tr > :nth-child(8),
    table.pl9 > thead > tr > :nth-child(9),
    table.pl10 > thead > tr > :nth-child(10),
    table.pl11 > thead > tr > :nth-child(11),
    table.pl12 > thead > tr > :nth-child(12),
    table.pl13 > thead > tr > :nth-child(13),
    table.pl14 > thead > tr > :nth-child(14),
    table.pl15 > thead > tr > :nth-child(15),
    table.pl16 > thead > tr > :nth-child(16),
    table.pr1 > thead > tr > :nth-child(1),
    table.pr2 > thead > tr > :nth-child(2),
    table.pr3 > thead > tr > :nth-child(3),
    table.pr4 > thead > tr > :nth-child(4),
    table.pr5 > thead > tr > :nth-child(5),
    table.pr6 > thead > tr > :nth-child(6),
    table.pr7 > thead > tr > :nth-child(7),
    table.pr8 > thead > tr > :nth-child(8),
    table.pr9 > thead > tr > :nth-child(9),
    table.pr10 > thead > tr > :nth-child(10),
    table.pr11 > thead > tr > :nth-child(11),
    table.pr12 > thead > tr > :nth-child(12),
    table.pr13 > thead > tr > :nth-child(13),
    table.pr14 > thead > tr > :nth-child(14),
    table.pr15 > thead > tr > :nth-child(15),
    table.pr16 > thead > tr > :nth-child(16)
  ) {
    z-index: 3;
    background-color: var(--color-surface-2);
  }
  table.pl1 > :is(thead, tbody) > tr > :nth-child(1) {
    left: var(--pl1, 0px);
  }
  table.pl2 > :is(thead, tbody) > tr > :nth-child(2) {
    left: var(--pl2, 0px);
  }
  table.pl3 > :is(thead, tbody) > tr > :nth-child(3) {
    left: var(--pl3, 0px);
  }
  table.pl4 > :is(thead, tbody) > tr > :nth-child(4) {
    left: var(--pl4, 0px);
  }
  table.pl5 > :is(thead, tbody) > tr > :nth-child(5) {
    left: var(--pl5, 0px);
  }
  table.pl6 > :is(thead, tbody) > tr > :nth-child(6) {
    left: var(--pl6, 0px);
  }
  table.pl7 > :is(thead, tbody) > tr > :nth-child(7) {
    left: var(--pl7, 0px);
  }
  table.pl8 > :is(thead, tbody) > tr > :nth-child(8) {
    left: var(--pl8, 0px);
  }
  table.pl9 > :is(thead, tbody) > tr > :nth-child(9) {
    left: var(--pl9, 0px);
  }
  table.pl10 > :is(thead, tbody) > tr > :nth-child(10) {
    left: var(--pl10, 0px);
  }
  table.pl11 > :is(thead, tbody) > tr > :nth-child(11) {
    left: var(--pl11, 0px);
  }
  table.pl12 > :is(thead, tbody) > tr > :nth-child(12) {
    left: var(--pl12, 0px);
  }
  table.pl13 > :is(thead, tbody) > tr > :nth-child(13) {
    left: var(--pl13, 0px);
  }
  table.pl14 > :is(thead, tbody) > tr > :nth-child(14) {
    left: var(--pl14, 0px);
  }
  table.pl15 > :is(thead, tbody) > tr > :nth-child(15) {
    left: var(--pl15, 0px);
  }
  table.pl16 > :is(thead, tbody) > tr > :nth-child(16) {
    left: var(--pl16, 0px);
  }
  table.pr1 > :is(thead, tbody) > tr > :nth-child(1) {
    right: var(--pr1, 0px);
  }
  table.pr2 > :is(thead, tbody) > tr > :nth-child(2) {
    right: var(--pr2, 0px);
  }
  table.pr3 > :is(thead, tbody) > tr > :nth-child(3) {
    right: var(--pr3, 0px);
  }
  table.pr4 > :is(thead, tbody) > tr > :nth-child(4) {
    right: var(--pr4, 0px);
  }
  table.pr5 > :is(thead, tbody) > tr > :nth-child(5) {
    right: var(--pr5, 0px);
  }
  table.pr6 > :is(thead, tbody) > tr > :nth-child(6) {
    right: var(--pr6, 0px);
  }
  table.pr7 > :is(thead, tbody) > tr > :nth-child(7) {
    right: var(--pr7, 0px);
  }
  table.pr8 > :is(thead, tbody) > tr > :nth-child(8) {
    right: var(--pr8, 0px);
  }
  table.pr9 > :is(thead, tbody) > tr > :nth-child(9) {
    right: var(--pr9, 0px);
  }
  table.pr10 > :is(thead, tbody) > tr > :nth-child(10) {
    right: var(--pr10, 0px);
  }
  table.pr11 > :is(thead, tbody) > tr > :nth-child(11) {
    right: var(--pr11, 0px);
  }
  table.pr12 > :is(thead, tbody) > tr > :nth-child(12) {
    right: var(--pr12, 0px);
  }
  table.pr13 > :is(thead, tbody) > tr > :nth-child(13) {
    right: var(--pr13, 0px);
  }
  table.pr14 > :is(thead, tbody) > tr > :nth-child(14) {
    right: var(--pr14, 0px);
  }
  table.pr15 > :is(thead, tbody) > tr > :nth-child(15) {
    right: var(--pr15, 0px);
  }
  table.pr16 > :is(thead, tbody) > tr > :nth-child(16) {
    right: var(--pr16, 0px);
  }
  :where(
    table.pl2 > :is(thead, tbody) > tr > :nth-child(2),
    table.pl3 > :is(thead, tbody) > tr > :nth-child(3),
    table.pl4 > :is(thead, tbody) > tr > :nth-child(4),
    table.pl5 > :is(thead, tbody) > tr > :nth-child(5),
    table.pl6 > :is(thead, tbody) > tr > :nth-child(6),
    table.pl7 > :is(thead, tbody) > tr > :nth-child(7),
    table.pl8 > :is(thead, tbody) > tr > :nth-child(8),
    table.pl9 > :is(thead, tbody) > tr > :nth-child(9),
    table.pl10 > :is(thead, tbody) > tr > :nth-child(10),
    table.pl11 > :is(thead, tbody) > tr > :nth-child(11),
    table.pl12 > :is(thead, tbody) > tr > :nth-child(12),
    table.pl13 > :is(thead, tbody) > tr > :nth-child(13),
    table.pl14 > :is(thead, tbody) > tr > :nth-child(14),
    table.pl15 > :is(thead, tbody) > tr > :nth-child(15),
    table.pl16 > :is(thead, tbody) > tr > :nth-child(16)
  ) {
    box-shadow: inset -1px 0 0 var(--color-border);
  }
  :where(
    table.pr1 > :is(thead, tbody) > tr > :nth-child(1),
    table.pr2 > :is(thead, tbody) > tr > :nth-child(2),
    table.pr3 > :is(thead, tbody) > tr > :nth-child(3),
    table.pr4 > :is(thead, tbody) > tr > :nth-child(4),
    table.pr5 > :is(thead, tbody) > tr > :nth-child(5),
    table.pr6 > :is(thead, tbody) > tr > :nth-child(6),
    table.pr7 > :is(thead, tbody) > tr > :nth-child(7),
    table.pr8 > :is(thead, tbody) > tr > :nth-child(8),
    table.pr9 > :is(thead, tbody) > tr > :nth-child(9),
    table.pr10 > :is(thead, tbody) > tr > :nth-child(10),
    table.pr11 > :is(thead, tbody) > tr > :nth-child(11),
    table.pr12 > :is(thead, tbody) > tr > :nth-child(12),
    table.pr13 > :is(thead, tbody) > tr > :nth-child(13),
    table.pr14 > :is(thead, tbody) > tr > :nth-child(14),
    table.pr15 > :is(thead, tbody) > tr > :nth-child(15),
    table.pr16 > :is(thead, tbody) > tr > :nth-child(16)
  ) {
    box-shadow: inset 1px 0 0 var(--color-border);
  }
  /* an open row menu lies over the cells of the rows below it, pinned ones included */
  .tablescroll td:has(> details.rowmenu[open]) {
    z-index: 4;
  }
}

/* Phone device cards (ui.DeviceCards): below 45rem the device list shows cards instead of the
   table; the server renders both. */
.dcards {
  display: none;
}
@media (max-width: 44.99rem) {
  .tablewrap[data-key="devices"],
  #devtable > .toolbar {
    display: none;
  }
  .dcards {
    display: flex;
    flex-direction: column;
    gap: 8px;
  }
  .dcards-all {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 40px;
    padding: 0 4px;
    font-size: 13px;
    color: var(--color-text-2);
  }
  .dcards-all[hidden] {
    display: none;
  }
  .dcards-all input,
  .dcard-sel input {
    width: 18px;
    height: 18px;
    margin: 0;
    accent-color: var(--color-accent);
  }
  .dcard-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0;
    padding: 0;
    list-style: none;
  }
  .dcard {
    display: grid;
    grid-template-columns: 40px minmax(0, 1fr) auto;
    align-items: start;
    gap: 0 4px;
    padding: 6px 6px 10px 2px;
    background: var(--color-surface);
    border: var(--hair-w) solid var(--color-border);
    border-radius: 10px;
  }
  .dcard:not(:has(.dcard-sel)) {
    grid-template-columns: minmax(0, 1fr) auto;
    padding-left: 12px;
  }
  .dcard:has(.dcard-sel input:checked) {
    background: var(--color-accent-bg);
    border-color: var(--color-accent);
  }
  .dcard-sel {
    display: grid;
    place-items: center;
    width: 40px;
    height: 44px;
  }
  .dcard-main {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
    padding: 10px 0 0;
  }
  .dcard-main a.dcard-title::after {
    content: "";
    position: absolute;
    inset: 0;
  }
  .dcard-name {
    display: flex;
    align-items: flex-start;
    gap: 7px;
  }
  .dcard-dot {
    flex: none;
    width: 8px;
    height: 8px;
    margin-top: 6px;
    border-radius: 50%;
    background: var(--color-neutral);
  }
  .dcard:has(.dcard-badges .tone-ok) .dcard-dot {
    background: var(--color-ok);
  }
  .dcard:has(.dcard-badges .tone-warn) .dcard-dot {
    background: var(--color-warn);
  }
  .dcard:has(.dcard-badges .tone-bad) .dcard-dot {
    background: var(--color-danger);
  }
  .dcard-main a.dcard-title {
    color: var(--color-text);
    font-weight: 600;
    line-height: 1.3;
    text-decoration: none;
    overflow-wrap: anywhere;
  }
  .dcard-main:hover a.dcard-title {
    color: var(--color-accent-fg);
    text-decoration: underline;
  }
  .dcard-meta {
    font: 400 12px var(--font-mono);
    color: var(--color-text-2);
    overflow-wrap: anywhere;
    text-wrap: balance; /* "addr · chip ·" / "16.0.0" becomes two even lines */
  }
  /* address, chip and version break between each other, not inside */
  .dcard-meta-part {
    display: inline-block; /* one unit for the line breaker; max-width lets a very long host still wrap */
    max-width: 100%;
  }
  .dcard-badges {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 5px;
  }
  /* the card shows the status badge and a failing channel only (the prototype's "MQTT down");
     the last-report age and the working channels are the table's detail */
  .dcard-badges > small.muted,
  .dcard-badges .chan:not(.chan-bad) {
    display: none;
  }
  .dcard-last {
    font-size: 12px;
    color: var(--color-text-3);
  }
  /* the prototype's side column: the 48 x 44 switch over the 44 x 44 "⋯", centred, no gap */
  .dcard-side {
    display: flex;
    flex-direction: column;
    align-items: center;
  }
}

/* Bulk bar (prototype): on a wide screen a dark bar centred at the bottom of the window with
   the count, Update firmware, Send command, Back up, Restart, Power on, Power off and Clear;
   on a phone a light panel across the bottom: the count and Clear, then the actions in a grid
   of three. It is fixed to the window, so it is never clipped (layout guard a). The bars of the
   pages not ported yet (no .bulk-acts) keep their old look until their package moves them. */
.bulkbar:has(> .bulk-acts) {
  position: fixed;
  z-index: var(--z-sticky);
  left: 0;
  right: 0;
  bottom: 16px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  width: fit-content;
  max-width: calc(100% - 32px);
  min-height: 0;
  margin: 0 auto;
  padding: 7px 7px 7px 16px;
  background: var(--color-text);
  color: var(--color-surface);
  border: 0;
  border-radius: 11px;
  box-shadow: var(--shadow-lg);
}
.bulkbar:has(> .bulk-acts)[hidden] {
  display: none;
}
.bulkbar:has(> .bulk-acts) .bulk-count {
  flex: none;
  margin-right: 8px;
  font: 600 13px var(--font-sans);
  white-space: nowrap;
}
.bulkbar:has(> .bulk-acts) .bulk-acts {
  display: contents;
}
.bulkbar:has(> .bulk-acts) button {
  flex: none;
  min-height: 0;
  height: 34px;
  padding: 0 12px;
  border-radius: 7px;
  border: var(--hair-w) solid
    color-mix(in oklab, var(--color-surface) 30%, transparent);
  background: transparent;
  box-shadow: none;
  color: var(--color-surface);
  font: 500 13px var(--font-sans);
  white-space: nowrap;
}
.bulkbar:has(> .bulk-acts) button.primary {
  border: 0;
  background: var(--color-accent);
  color: var(--color-on-accent);
  font-weight: 600;
}
.bulkbar:has(> .bulk-acts) .bulk-clear {
  padding: 0 10px;
  border: 0;
}
.bulkbar:has(> .bulk-acts) .bulk-sep {
  width: 1px;
  height: 20px;
  margin: 0 4px;
  background: color-mix(in oklab, var(--color-surface) 25%, transparent);
}
.bulkbar:has(> .bulk-acts) .bulk-sm {
  display: none;
}
body:has(.bulkbar:not([hidden]) > .bulk-acts) {
  padding-bottom: 80px;
}
@media (max-width: 44.99rem) {
  .bulkbar:has(> .bulk-acts) {
    bottom: 0;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 8px 6px;
    width: auto;
    max-width: none;
    padding: 10px 12px calc(14px + env(safe-area-inset-bottom, 0px));
    background: var(--color-surface);
    color: var(--color-text);
    border-top: var(--hair-w) solid var(--color-border);
    border-radius: 0;
    box-shadow: 0 -6px 20px rgba(0, 0, 0, 0.08);
  }
  .bulkbar:has(> .bulk-acts) .bulk-count {
    grid-row: 1;
    grid-column: 1;
    margin: 0;
    font-size: 13.5px;
  }
  .bulkbar:has(> .bulk-acts) .bulk-clear {
    grid-row: 1;
    grid-column: 2;
    height: 40px;
    background: none;
    color: var(--color-accent-fg);
    font-size: 13.5px;
  }
  .bulkbar:has(> .bulk-acts) .bulk-acts {
    display: grid;
    grid-column: 1 / -1;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 6px;
  }
  .bulkbar:has(> .bulk-acts) .bulk-acts button {
    height: 44px;
    padding: 0 6px;
    border-radius: 8px;
    border: var(--hair-w) solid var(--color-border-strong);
    background: var(--color-surface);
    color: var(--color-text);
    font-size: 12.5px;
  }
  .bulkbar:has(> .bulk-acts) .bulk-acts button.primary {
    border: 0;
    background: var(--color-accent);
    color: var(--color-on-accent);
  }
  .bulkbar:has(> .bulk-acts) .bulk-sep,
  .bulkbar:has(> .bulk-acts) .bulk-lg {
    display: none;
  }
  .bulkbar:has(> .bulk-acts) .bulk-sm {
    display: inline;
  }
  body:has(.bulkbar:not([hidden]) > .bulk-acts) {
    padding-bottom: calc(180px + env(safe-area-inset-bottom, 0px));
  }
}

/* ==== page: Devices (/devices, WP P2): toolbar, the device table's cells, row menu ====
   Markup: devices.templ, the row partials in partials.html. Values are the prototype's. */
.dv-list {
  position: relative;
}
.pghead:has(+ #list-notice) {
  margin-bottom: 14px;
}
.dv-tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 0 0 12px;
}
.dv-q {
  flex: 1 1 240px;
  min-width: 0;
  max-width: 380px;
  height: var(--ctl);
  padding: 0 10px;
  border: var(--hair-w) solid var(--color-border-strong);
  border-radius: 7px;
  background: var(--color-surface);
  color: var(--color-text);
  font: 400 13.5px var(--font-sans);
}
.dv-chips {
  display: flex;
  gap: 6px;
  max-width: 100%;
  padding-bottom: 2px;
  overflow-x: auto;
}
.dv-chip {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 6px;
  height: var(--ctl);
  padding: 0 11px;
  border: var(--hair-w) solid var(--color-border-strong);
  border-radius: 999px;
  background: var(--color-surface);
  color: var(--color-text);
  font: 500 12.5px var(--font-sans);
  white-space: nowrap;
  text-decoration: none;
}
.dv-chip[aria-current] {
  border-color: var(--color-text);
  background: var(--color-text);
  color: var(--color-surface);
}
.dv-n {
  font-variant-numeric: tabular-nums;
  opacity: 0.75;
}
.dv-vsep {
  flex: none;
  align-self: stretch;
  width: 1px;
  margin: 6px 2px;
  background: var(--color-border);
}
.dv-pick {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 4px;
  height: var(--ctl);
  margin: 0;
  padding: 0 2px 0 11px;
  border: var(--hair-w) solid var(--color-border-strong);
  border-radius: 999px;
  background: var(--color-surface);
  color: var(--color-text-2);
  font: 500 12.5px var(--font-sans);
  white-space: nowrap;
}
.dv-pick.on {
  border-color: var(--color-text);
}
.dv-pick select {
  appearance: auto;
  width: auto;
  min-width: 0;
  height: 100%;
  min-height: 0;
  margin: 0;
  padding: 0 6px;
  border: 0;
  border-radius: 999px;
  background-color: transparent;
  background-image: none;
  box-shadow: none;
  color: var(--color-text);
  font: 500 12.5px var(--font-sans);
  cursor: pointer;
}
.dv-grow {
  flex: 1;
}
.dv-sort {
  display: none;
  align-items: center;
  gap: 6px;
  margin: 0;
  color: var(--color-text-2);
  font: 400 12.5px var(--font-sans);
}
.dv-sort select {
  appearance: auto;
  width: auto;
  height: var(--ctl);
  min-height: 0;
  margin: 0;
  padding: 0 8px;
  border: var(--hair-w) solid var(--color-border-strong);
  border-radius: 7px;
  background-color: var(--color-surface);
  background-image: none;
  color: var(--color-text);
  font: 400 13px var(--font-sans);
}
/* the Columns chooser of the reloaded table part sits at the end of the toolbar's first row */
.dv-cols {
  display: none;
}
@media (min-width: 45rem) {
  .dv-tools {
    padding-right: 98px;
  }
  .dv-cols {
    display: block;
    position: absolute;
    top: 0;
    right: 0;
  }
  .dv-cols .colbtn {
    gap: 6px;
    height: var(--ctl);
    padding: 0 12px;
    border-radius: 7px;
    font: 500 13px var(--font-sans);
  }
  .dv-cols .colbtn::after {
    content: "▾";
    width: auto;
    height: auto;
    border: 0;
    transform: none;
    font-size: 10px;
  }
}
@media (max-width: 44.99rem) {
  .dv-sort {
    display: flex;
  }
  /* a 40 px touch target: the select covers its pill's border too */
  .dv-pick select {
    height: calc(100% + 2px);
    margin: -1px 0;
  }
}
.dv-nomatch {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 32px 16px;
  border: var(--hair-w) solid var(--color-border);
  border-radius: 10px;
  background: var(--color-surface);
  text-align: center;
}
.dv-nomatch b {
  font-weight: 600;
}
.dv-nomatch span {
  color: var(--color-text-2);
  font-size: 13px;
}

/* the device table: the prototype's fixed column widths; it scrolls sideways below their sum */
@media (min-width: 45rem) {
  /* a definite width keeps the fixed layout (max-content would fall back to auto and let a long
     address widen its column); the table is then the sum of its columns, at least the frame */
  table.devtable:not(.tfix) {
    table-layout: fixed;
    width: 1px;
    min-width: 100%;
  }
  table.devtable col.c-sel {
    width: 44px;
  }
  table.devtable col.c-name {
    width: 280px;
  }
  table.devtable col.c-status {
    width: 170px;
  }
  table.devtable col.c-reach {
    width: 150px;
  }
  table.devtable col.c-fw {
    width: 140px;
  }
  table.devtable col.c-fam {
    width: 100px;
  }
  table.devtable col.c-addr {
    width: 132px;
  }
  table.devtable col.c-up {
    width: 120px; /* "seen 30s ago" is 12 characters of 13px mono plus padding */
  }
  table.devtable col.c-wifi {
    width: 124px;
  }
  table.devtable col.c-restart {
    width: 180px;
  }
  table.devtable col.c-pow {
    width: 72px;
  }
  table.devtable col.c-act {
    width: 52px;
  }
  table.devtable {
    font-size: 13px;
  }
  .tablescroll > table.devtable > thead > tr > th.sel,
  .tablescroll > table.devtable > tbody > tr > td.sel {
    padding: 0 0 0 14px;
    text-align: left;
  }
  /* relative: a cell is the containing block of its screen-reader texts (absolute), which
     otherwise escape the scrolling box and widen the page */
  table.devtable > tbody > tr > td {
    position: relative;
    height: 44px;
    padding: 0 10px;
    border-bottom: var(--hair-w) solid var(--color-border);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: middle;
  }
  table.devtable > tbody > tr > td.dv-name {
    padding: 3px 10px;
    white-space: normal;
  }
  table.devtable td.dv-name > a {
    display: -webkit-box;
    overflow: hidden;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    color: var(--color-text);
    font: 500 13px/1.3 var(--font-sans);
    text-decoration: none;
    overflow-wrap: anywhere;
  }
  table.devtable td.dv-name > a:hover {
    color: var(--color-accent-fg);
    text-decoration: underline;
  }
  /* the row menu opens inside its cell (without JavaScript; tables.js places it fixed) */
  table.devtable > tbody > tr > td.rowacts {
    padding: 0 6px;
    overflow: visible;
  }
  /* the selection box sits 14 px in, with the browser's own checkbox margin, like the prototype's */
  table.devtable input[type="checkbox"] {
    width: 15px;
    height: 15px;
    margin: 3px 3px 3px 4px;
    vertical-align: middle;
    accent-color: var(--color-accent);
  }
  .tablescroll > table.devtable > thead > tr > th.sel > input:not([hidden]) {
    display: inline-block;
    margin: 3px 3px 3px 4px;
  }
  table.devtable td.sel > label.hit {
    display: inline;
    min-width: 0;
    min-height: 0;
    margin: 0;
    padding: 0;
  }
  table.devtable .sortlink .sortmark {
    display: none;
  }
  table.devtable .sortlink.is-asc::after {
    content: " ↑";
    white-space: pre;
  }
  table.devtable .sortlink.is-desc::after {
    content: " ↓";
    white-space: pre;
  }
}
.dv-st {
  gap: 5px;
}
.dv-dot {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--t);
}
.dv-mdown {
  display: none;
}
.dv-mono,
.dv-mono a {
  font: 400 12.5px var(--font-mono);
  color: var(--color-text-2);
}
td[data-label="Firmware"] .dv-mono {
  color: var(--color-text);
}
.dv-upd {
  height: 18px;
  font-size: 11px;
}
.dv-reach {
  font: 500 12px var(--font-mono);
}
.dv-reach .chan {
  display: inline;
  height: auto;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  font: inherit;
  color: var(--color-text-3);
}
.dv-reach .chan-ok {
  color: var(--color-ok-fg);
}
.dv-reach .chan-bad {
  color: var(--color-danger-fg);
}
.dv-reach-sep {
  color: var(--color-text-3);
}
.dv-wifi {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  vertical-align: middle;
}
.dv-wbar {
  flex: none;
}
.dv-wbg {
  fill: var(--color-surface-3);
}
.dv-wfg {
  fill: var(--color-ok);
}
.dv-wfg.weak {
  fill: var(--color-warn);
}
.dv-dbm {
  font: 400 12px var(--font-mono);
  color: var(--color-text-2);
}
/* the power switch of a row: 32 x 18 inside a 44 x 32 target; a card's is 34 x 20 in 48 x 44 */
td.pcell .pwr,
td.pcell .pwr[aria-pressed="true"] {
  width: 44px;
  height: 32px;
  border: 0;
  background: none;
  vertical-align: middle;
}
td.pcell .pwr .sw {
  width: 32px;
  height: 18px;
  border-radius: 9px;
}
.pcell .pwr[aria-pressed="true"] .sw {
  background: var(--color-accent);
}
td.pcell .pwr[aria-pressed="true"] .sw::after {
  left: 16px;
}
.dcard-side .pwr[aria-pressed="true"] {
  border: 0;
  background: none;
}
.pcell:has(.pwr + .pwr) .pwr {
  width: 36px;
}
.dcard-side .pwr {
  width: 48px;
  height: 44px;
}
.dcard-side .pwr .sw {
  width: 34px;
  height: 20px;
  border-radius: 10px;
}
.dcard-side .pwr .sw::after {
  top: 3px;
}
.dcard-side .pwr[aria-pressed="true"] .sw::after {
  left: 18px;
}
/* the row menu trigger "⋯" and its panel */
.rowacts .umenu > summary,
.dcard-side .umenu > summary {
  width: 36px;
  height: 32px;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--color-text-2);
  font: 600 16px var(--font-sans);
}
.dcard-side .umenu > summary {
  width: 44px;
  height: 44px;
  font-size: 18px;
}
.rowacts .umenu > summary:hover {
  background: var(--color-surface-3);
}
.rowacts .umenu .menu-panel,
.dcard-side .umenu .menu-panel {
  width: 200px;
}
.rowacts .umenu .menu-panel .menu-item,
.dcard-side .umenu .menu-panel .menu-item {
  height: var(--ctl);
  min-height: 0;
  padding: 0 10px;
  border-radius: 6px;
}
/* phone cards: the status badge without its dot (the name carries the dot), MQTT down last */
.dcards-all {
  font-weight: 400;
}
/* the device list's bulk bar is in the flow below the list and sticks to the window's bottom
   edge while the list is in view, as in the prototype (the page grows by the bar); the other
   bars stay fixed (F5) */
.dv-list .bulkbar:has(> .bulk-acts) {
  position: sticky;
  bottom: 16px;
  margin: 14px auto 0;
}
body:has(.dv-list .bulkbar:not([hidden])) {
  padding-bottom: 0;
}
@media (max-width: 44.99rem) {
  .dv-list .bulkbar:has(> .bulk-acts) {
    bottom: 0;
    margin: 12px calc(-1 * var(--page-pad, 12px)) -120px;
  }
  body:has(.dv-list .bulkbar:not([hidden])) {
    padding-bottom: 0;
  }
}
.dcard-st {
  display: contents;
}
.dcard .dv-dot {
  display: none;
}
.dcard .dv-mdown {
  display: inline-flex;
  order: 9;
}
.dcard-last .dv-wbar,
.dcard-last .dl-last,
.dcard-last .dl-never,
.dcard-last:has(.dv-seen) :is(.dl-up, .dl-sep, .dl-wifi),
.dcard:has(.dv-st.t-neutral) .dcard-last > :not(.dl-never) {
  display: none;
}
.dcard-last:has(.dv-seen) .dl-last,
.dcard:has(.dv-st.t-neutral) .dcard-last .dl-never {
  display: inline;
}
.dcard-last .dv-dbm {
  font: inherit;
  color: inherit;
}
.dcard:has(.dv-st.t-ok) .dcard-dot {
  background: var(--color-ok);
}
.dcard:has(.dv-st.t-warn) .dcard-dot {
  background: var(--color-warn);
}
.dcard:has(.dv-st.t-danger) .dcard-dot {
  background: var(--color-danger);
}

/* ==== page: device (WP P3): the header of every device tab, the overview's cards, the
   console, settings and drift tabs and the edit form (prototype screens "device" and "edit") ==== */
.devhd {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: var(--sp-12);
}
.devhd-t {
  min-width: 0;
  flex: 1 1 360px;
}
.devhd-name {
  display: flex;
  align-items: center;
  gap: var(--sp-10);
  flex-wrap: wrap;
}
.devhd-name h1 {
  margin: 0;
  min-width: 0;
  font: 600 22px/1.25 var(--font-sans);
  letter-spacing: -0.015em;
  overflow-wrap: anywhere;
}
.devhd-state {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 22px;
  padding: 0 var(--sp-8);
  border-radius: 5px;
  font: 500 12px var(--font-sans);
  background: var(--t-bg);
  color: var(--t-fg);
}
.devhd-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--t);
}
.devhd-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-6) var(--sp-12);
  margin-top: var(--sp-6);
  font: 400 12.5px var(--font-mono);
  color: var(--color-text-2);
}
.devhd-meta form,
.devhd-acts form,
.devdrift-bar form {
  display: flex;
  margin: 0;
}
.devhd-upd button {
  height: 22px;
  padding: 0 var(--sp-8);
  border: 0;
  border-radius: 5px;
  background: var(--color-accent-bg);
  color: var(--color-accent-fg);
  font: 500 12px var(--font-sans);
  text-box: normal;
  cursor: pointer;
}
.devhd-acts {
  display: flex;
  gap: var(--sp-6);
  flex-wrap: wrap;
}
.btn.devhd-pwr {
  gap: var(--sp-8);
  padding: 0 var(--sp-12) 0 var(--sp-8);
}
/* The generic button[aria-pressed="true"] inverts a button (ink background): right for a pressed
   toggle button, wrong here. The switch inside shows On; the button stays a neighbour of Restart
   and Back up in every state and theme. */
.btn.devhd-pwr[aria-pressed="true"] {
  background: var(--color-surface);
  border-color: var(--color-border-strong);
  color: var(--color-text);
}
.btn.devhd-pwr[aria-pressed="true"]:hover,
.btn.devhd-pwr[aria-pressed="true"]:active {
  background: var(--color-surface-2);
}
/* the switch of the header and of a relay: a track with a white knob, the accent when on */
.devsw {
  position: relative;
  flex: none;
  width: 30px;
  height: 18px;
  border-radius: 9px;
  background: var(--color-border-strong);
}
.devsw::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #fff;
  box-shadow: var(--shadow-knob);
}
[aria-pressed="true"] > .devsw,
[aria-checked="true"] > .devsw {
  background: var(--color-accent);
}
[aria-pressed="true"] > .devsw::after {
  left: 14px;
}
.devhd-off {
  display: flex;
  gap: var(--sp-10);
  align-items: center;
  flex-wrap: wrap;
  padding: var(--sp-10) 14px;
  margin-bottom: var(--sp-12);
  border-radius: 9px;
  border: var(--hair-w) solid var(--color-border);
  background: var(--color-surface);
  font-size: 13px;
}
.devhd-off > div {
  flex: 1;
  min-width: 220px;
}
.devhd-off b {
  font-weight: 600;
}
.devhd-offdot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-danger);
}
.devhd ~ .banner {
  margin: 0 0 var(--sp-12);
}

/* overview: cards in columns of at least 320 px */
.devgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
  gap: var(--card-gap);
  align-items: start;
}
/* The overview cards differ in height: columns (not grid rows) let the short ones stack under each
   other, so no row leaves a hole beside a tall card. A column box drops the bottom margin of its
   last card, so the gap to whatever follows comes from .devgrid-more's own top margin, not from
   the cards' margins (they touched the row below before). */
.devgrid:not(.devgrid-more) {
  display: block;
  columns: 320px 3;
  column-gap: var(--card-gap);
}
.devgrid-more {
  margin-top: var(--card-gap);
}
.devgrid:not(.devgrid-more) > .devcard {
  break-inside: avoid;
  margin-bottom: var(--card-gap);
}
.devcard {
  min-width: 0;
  padding: 14px var(--sp-16);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  background: var(--color-surface);
}
.devcard h2 {
  margin: 0 0 var(--sp-10);
  font: 600 13px var(--font-sans);
  letter-spacing: normal;
}
.devcard-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-10);
  margin-bottom: var(--sp-10);
}
.devcard-head h2 {
  margin: 0;
}
/* the links and the Columns chooser at the end of a card's title line */
.devcard-tools {
  display: flex;
  align-items: center;
  gap: var(--sp-8);
}
/* Identity: the Refresh link sits in the title's line without making it taller */
#identity .devcard-head {
  margin: -8px 0 2px;
}
.devcard .banner {
  margin: var(--sp-10) 0 0;
}
.devcard table {
  margin: 0;
}
.devcard-note {
  margin: 0;
  font-size: 13px;
  color: var(--color-text-2);
}
.devcard-h3 {
  margin: var(--sp-12) 0 4px;
  font: 600 12px var(--font-sans);
  color: var(--color-text-2);
}
.devpow {
  display: flex;
  align-items: flex-end;
  gap: 14px;
  margin-bottom: var(--sp-12);
}
.devpow-w {
  font: 600 30px/1 var(--font-sans);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
.devpow-w span {
  margin-left: 3px;
  font-size: 15px;
  color: var(--color-text-2);
}
.devpow-sub {
  margin-top: 4px;
  font-size: 12px;
  color: var(--color-text-3);
}
.devspark {
  flex: 1;
  height: 40px;
}
/* N8: the bars are SVG rects with presentation attributes (D6); the prototype's 2 px gaps and
   accent at .45 */
.devspark svg {
  display: block;
  width: 100%;
  height: 100%;
}
.devspark-note {
  display: flex;
  height: 100%;
  align-items: flex-end;
  justify-content: flex-end;
  font-size: 12px;
  color: var(--color-text-2);
}
.devspark-bar {
  fill: var(--color-accent);
  opacity: 0.45;
}
.devrelay {
  display: flex;
  align-items: center;
  gap: var(--sp-10);
  margin: 0;
  padding: 4px 0;
  border-top: var(--hair-w) solid var(--color-border);
}
.devrelay-n {
  flex: 1;
  font-size: 13px;
}
.devrelay-n .mono {
  font: 400 12px var(--font-mono);
  color: var(--color-text-3);
}
.devrelay-s {
  font-size: 12.5px;
  color: var(--color-text-2);
}
.devrelay-sw {
  display: grid;
  place-items: center;
  width: 44px;
  height: 36px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.devrelay-sw:disabled {
  cursor: default;
  opacity: 0.5;
}
.devrelay-sw .devsw {
  width: 32px;
}
.devrelay-sw[aria-checked="true"] .devsw::after {
  left: 16px;
}
.devwifi {
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  margin-top: var(--sp-8);
  font-size: 12px;
  color: var(--color-text-3);
}
.devwifi-bar {
  flex: 1;
  height: 6px;
  border-radius: 3px;
}
.devwifi-track {
  fill: var(--color-surface-3);
}
.devwifi-fill {
  fill: var(--color-warn);
}
.devwifi-bar.is-ok .devwifi-fill {
  fill: var(--color-ok);
}
.devpol-ok .sdot {
  gap: var(--sp-8);
}
.devdev {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin-bottom: var(--sp-6);
  padding: var(--sp-8) var(--sp-10);
  border-radius: 7px;
  background: var(--color-warn-bg);
  color: var(--color-warn-fg);
  font: 400 12.5px var(--font-mono);
}
.devdev-r {
  font: 600 12.5px var(--font-sans);
}
.btn.devpol-fix {
  margin-top: var(--sp-6);
}
.devnote {
  margin: var(--sp-10) 0 0;
  font-size: 12.5px;
  color: var(--color-text-2);
}
.devconfirm {
  margin-bottom: var(--sp-12);
}
.devconfirm p {
  margin: 0;
  font-size: 13px;
}

/* console tab: the panel's fixed height, the prompt's look and the quick commands below it */
.console-lines {
  height: min(440px, 52vh);
  max-height: none;
}
.console-line.is-dim .console-text {
  color: var(--color-term-dim);
}
.console a.console-clear {
  display: inline-flex;
  align-items: center;
  border-radius: 6px;
  border-color: var(--color-console-line);
  text-decoration: none;
}
.console-form input:not([type="checkbox"]):not([type="radio"]) {
  min-width: 0;
  padding: 0 var(--sp-10);
  border-radius: 7px;
  background: color-mix(in srgb, var(--color-console-rule) 50%, transparent);
}
/* the terminal keeps its own colours in both themes: the global placeholder grey (text-2) is
   nearly invisible on it in light mode */
.console-form input::placeholder {
  color: color-mix(in srgb, var(--color-term-fg) 62%, transparent);
  opacity: 1;
}
.console-form .console-send {
  height: var(--ctl);
  padding: 0 14px;
  border: 0;
  border-radius: 7px;
  background: var(--color-term-cmd);
  color: var(--color-term-bg);
  font: 600 13px var(--font-sans);
  text-box: normal;
  cursor: pointer;
}
.console-quick {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-6);
  margin: var(--sp-10) 0 0;
  padding: 0;
}
.console-quick-l {
  margin-right: 4px;
  font-size: 12px;
  color: var(--color-text-3);
}
.btn.console-chip {
  padding: 0 var(--sp-10);
  font: 400 12.5px var(--font-mono);
}

/* settings tab and edit form: one card, label-above fields in columns of at least 260 px */
.devform {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  gap: 14px 18px;
  max-width: 760px;
  margin: 0;
  padding: 18px;
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  background: var(--color-surface);
}
.devform-edit {
  max-width: 720px; /* the width of the Add devices form */
}
.devform-msg {
  display: flex;
  flex-direction: column;
  gap: var(--sp-12);
}
.devform-msg h2,
.devform-h {
  margin: 0;
  font: 600 13px var(--font-sans);
  letter-spacing: normal;
}
.devform-msg p {
  margin: 0;
  font-size: 13px;
  color: var(--color-text-2);
}
.devform-h {
  grid-column: 1 / -1;
  padding-top: 14px;
  border-top: var(--hair-w) solid var(--color-border);
}
.devform-foot {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--sp-8);
  padding-top: 14px;
  border-top: var(--hair-w) solid var(--color-border);
}
.devform-count {
  flex: 1 1 16rem; /* own line on a phone; a zero basis squeezed the text between the buttons */
  font-size: 12.5px;
  color: var(--color-text-2);
}
.devform-sp {
  flex: 1;
  font-size: 12.5px;
  color: var(--color-text-2);
}
.devform-err {
  color: var(--color-danger-fg);
}
.ufield-warn {
  font: 400 12px var(--font-sans);
  color: var(--color-warn-fg);
}
.devform select[aria-invalid="true"] {
  border-color: var(--color-danger);
}
.devform-checks {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-4) var(--sp-18);
}
.pghead + .err-summary,
.pghead + .banner {
  max-width: 820px;
  margin: 0 0 14px;
}

/* drift tab: the settings of the newest backup against the device, changed rows tinted */
.devdrift {
  display: flex;
  flex-direction: column;
  gap: var(--sp-12);
}
.devdrift > .banner,
.devdrift > .devnote {
  margin: 0;
}
.devdrift-lead {
  margin: 0;
  font-size: 13px;
  color: var(--color-text-2);
  text-wrap: pretty;
}
.devdrift-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-10);
}
.devdrift-bar b {
  font-weight: 600;
  font-size: 14px;
}
.devdrift-sp {
  flex: 1;
}
.devdrift-all {
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  min-height: var(--ctl);
  font-size: 13px;
  color: var(--color-text);
  text-decoration: none;
}
.devdrift-box {
  width: 16px;
  height: 16px;
  border: var(--hair-w) solid var(--color-border-strong);
  border-radius: 3px;
  background: var(--color-surface);
}
.devdrift-all[aria-checked="true"] .devdrift-box {
  border-color: var(--color-accent);
  background: var(--color-accent);
  box-shadow: inset 0 0 0 3px var(--color-surface);
}
.devdrift-tbl {
  overflow: hidden;
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  background: var(--color-surface);
}
.devdrift-scroll {
  overflow-x: auto;
}
.devdrift-in {
  min-width: 560px;
}
.devdrift-row {
  display: grid;
  grid-template-columns: minmax(140px, 0.7fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--sp-12);
  min-height: 36px;
  padding: var(--sp-8) var(--sp-16);
  border-bottom: var(--hair-w) solid var(--color-border);
  font: 400 12.5px var(--font-mono);
  overflow-wrap: anywhere;
}
.devdrift-row:last-child {
  border-bottom: 0;
}
.devdrift-head {
  min-height: 0;
  background: var(--color-surface-2);
  font: 500 12px var(--font-sans);
  color: var(--color-text-2);
}
.devdrift-row.is-changed {
  background: var(--color-warn-bg);
}
.devdrift-k {
  font-weight: 500;
  color: var(--color-text);
}
.devdrift-a {
  color: var(--color-text-2);
}
.devdrift-row.is-changed .devdrift-b {
  color: var(--color-text);
}
.console-who {
  margin-left: var(--sp-10);
  color: var(--color-term-dim);
}
/* a device's reply is data, mostly one long JSON line without spaces: it keeps its line breaks and
   spacing but wraps inside the panel, breaking a token only where nothing else fits */
.console-line.is-reply .console-text {
  white-space: pre-wrap;
  word-break: normal;
  overflow-wrap: anywhere;
}
/* a device's form is long: its Save bar stays in view at the bottom of the window while the
   form scrolls (where the form ends, it sits at its place) */
.devform-foot {
  position: sticky;
  bottom: 0;
  margin: 0 -18px -18px;
  padding: 14px 18px 18px;
  border-radius: 0 0 var(--r-card) var(--r-card);
  background: var(--color-surface);
}
/* a long device name in the trail (Devices / name / Edit) wraps inside the line instead of
   widening the page */
nav.crumbs a {
  min-width: 0;
  overflow-wrap: anywhere;
}
/* phones: the card links and the relay switches are 40 px touch targets */
@media (max-width: 44.99rem) {
  .devcard-head .btn.btn-link {
    min-height: 40px;
  }
  #identity .devcard-head {
    margin: -12px 0 -2px;
  }
  .devrelay-sw {
    height: 40px;
  }
  .devrelay {
    padding: 2px 0;
  }
}
/* the settings form's labels are <label for> elements beside the control: the field label's
   look, not the legacy form label's */
.devform label.ufield-label {
  font: 500 12.5px var(--font-sans);
  color: var(--color-text-2);
}

/* ==== page: device delete (/devices/{id}/delete, N2, WP W4): the prototype's "devdelete" ==== */
.dd-page {
  max-width: 760px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.dd-head h1 {
  margin: 0;
  font: 600 22px/1.2 var(--font-sans);
  letter-spacing: -0.015em;
  overflow-wrap: anywhere;
}
.dd-sub {
  margin: 4px 0 0;
  color: var(--color-text-2);
  font-size: 13px;
  font-family: var(--font-mono);
}
.dd-page .banner {
  margin: 0;
  padding: 10px 12px;
  gap: 10px;
  align-items: flex-start;
  border-radius: 8px;
}
.dd-page .banner-dot {
  margin-top: 5px;
}
.dd-list {
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  overflow: hidden;
}
.dd-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 14px;
  border-bottom: var(--hair-w) solid var(--color-border);
  font-size: 13px;
}
.dd-when {
  font-weight: 500;
}
.dd-what {
  color: var(--color-text-2);
}
.dd-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.dd-choice {
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
  gap: 10px;
}
.dd-choice .rcard {
  padding: 12px;
  border-radius: 9px;
}
.dd-choice .rcard input {
  flex: none;
  margin: 2px 0 0;
}
.dd-choice .rcard-body span {
  margin-top: 2px;
}
.dd-note {
  margin: 0;
  font-size: 13px;
  color: var(--color-text-2);
}
.dd-ack {
  min-height: 40px;
  cursor: pointer;
}
.dd-ack input {
  margin: 3px 3px 3px 4px;
}
.dd-acts {
  display: flex;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 8px;
}
/* like the prototype, the button looks unavailable until the box is ticked; it still posts, and
   the server answers with the field error (works without JavaScript) */
.dd-form:has(input[name="ack"]:not(:checked)) .dd-go {
  opacity: 0.45;
}

/* ==== page: Updates (WP P4): /transactions, /transactions/{batch}, /updates/new and its preview ====
   Markup: transactions.templ. The prototype's "updates", "txn", "compliant", "newupdate" screens. */

/* transactions list: the running transactions as cards, then the history */
.upd-run .txn-card {
  gap: 10px;
  margin-bottom: 14px;
  padding: 16px;
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  background: var(--color-surface);
}
.upd-run .txn-card:hover {
  border-color: var(--color-border-strong);
  background: var(--color-surface);
}
.upd-run .txn-title {
  font-size: 15px;
}
.upd-run .seg-bar {
  height: 8px;
  border-radius: 4px;
}
.upd-run .txn-sum {
  font-size: 13px;
}
.upd .ulist {
  overflow: hidden;
}
.upd .ulist-head,
.upd-pick .ulist-head,
.upd-prev .ulist-head {
  padding: 12px 16px;
}
.upd-hrow {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 4px 12px;
  align-items: center;
  min-height: 48px;
  padding: 10px 16px;
  border-bottom: var(--hair-w) solid var(--color-border);
  color: var(--color-text);
  text-decoration: none;
}
.upd-hrow:hover {
  background: var(--color-surface-2);
  color: var(--color-text);
}
.upd-hhead {
  display: none;
  gap: 4px 12px;
  align-items: center;
  min-height: 36px;
  padding: 0 16px;
  border-bottom: var(--hair-w) solid var(--color-border);
  background: var(--color-surface-2);
  font: 500 12px var(--font-sans);
  color: var(--color-text-2);
}
@media (min-width: 45rem) {
  /* fixed columns with a header row (on a phone each row is its own card) */
  .upd-hrow,
  .upd-hhead {
    grid-template-columns: 96px minmax(0, 2fr) 110px 130px minmax(0, 1.5fr);
  }
  .upd-hhead {
    display: grid;
  }
}
.upd-hid {
  font: 500 12.5px var(--font-mono);
}
.upd-htitle {
  font-weight: 500;
}
.upd-hn {
  font-size: 12.5px;
  color: var(--color-text-2);
}
.upd-hwho {
  font-size: 12.5px;
  color: var(--color-text-3);
}
/* phone: id and result on the first line, the title under them, then devices and who: one reading
   order instead of two columns that zigzag */
@media (max-width: 44.99rem) {
  .upd-hrow {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "id st"
      "title title"
      "n who";
  }
  .upd-hid {
    grid-area: id;
  }
  .upd-hst {
    grid-area: st;
  }
  .upd-htitle {
    grid-area: title;
  }
  .upd-hn {
    grid-area: n;
  }
  .upd-hwho {
    grid-area: who;
    text-align: right;
  }
}

/* one transaction: header with the state, progress, device rows and the log of one device */
.upd-head {
  align-items: flex-start;
  margin-bottom: 14px;
}
.upd-h1 {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.bdg.bdg-lg {
  height: 22px;
  padding: 0 8px;
  font-size: 12px;
}
.upd-head .mono {
  font-family: var(--font-mono);
}
.upd-links a {
  color: var(--color-accent-fg);
}
.ucard.upd-prog {
  display: block;
  margin-bottom: 14px;
  padding: 14px 16px;
}
.upd-prog .seg-bar {
  height: 10px;
  border-radius: 5px;
}
.upd-counts {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 20px;
  margin-top: 10px;
  font-size: 13px;
  color: var(--color-text-2);
}
.upd-counts b {
  font-weight: 600;
  color: var(--color-text);
}
.upd-counts b.upd-bad,
.upd-bad {
  color: var(--color-danger-fg);
}
.upd-of {
  color: var(--color-text-3);
}
.upd-cols {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  align-items: flex-start;
}
.upd-rows {
  flex: 2 1 460px;
  max-width: 100%;
  overflow: hidden;
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  background: var(--color-surface);
}
.upd-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 12px;
  min-height: 48px;
  padding: 10px 14px;
  border-bottom: var(--hair-w) solid var(--color-border);
  box-shadow: inset 2px 0 0 transparent;
  background: var(--color-surface);
  color: var(--color-text);
  text-decoration: none;
}
.upd-row:hover {
  color: var(--color-text);
}
.upd-row[aria-current="true"] {
  box-shadow: inset 2px 0 0 var(--color-accent);
  background: var(--color-surface-2);
}
.upd-row-name {
  flex: 1 1 200px;
  min-width: 0;
  font-size: 13px;
  font-weight: 500;
  overflow-wrap: anywhere;
}
.upd-row-ver {
  font: 400 12px var(--font-mono);
  color: var(--color-text-2);
}
.upd-row-state {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 170px;
}
.upd-row-state .mini-bar {
  flex: 1;
  min-width: 0;
}
.upd-row-state .mini-bar svg {
  flex: 1;
  width: auto;
  min-width: 0;
  height: 5px;
  border-radius: 3px;
}
.upd-row-state .mini-pct {
  font: 400 11.5px var(--font-mono);
  color: var(--color-text-3);
}
.upd-log {
  position: sticky;
  top: 110px;
  flex: 1 1 320px;
  max-width: 100%;
  overflow: hidden;
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  background: var(--color-term-bg);
  color: var(--color-term-fg);
}
.upd-log-head {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  padding: 9px 12px;
  border-bottom: var(--hair-w) solid var(--color-console-rule);
  font: 500 12px var(--font-sans);
  color: var(--color-term-dim);
  overflow-wrap: anywhere;
}
.upd-log-acts {
  display: flex;
  gap: 10px;
  flex: none;
}
.upd-log-acts a,
.upd-log-acts button {
  display: inline-flex;
  align-items: center;
  height: auto;
  min-height: 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--color-term-cmd);
  cursor: pointer;
  text-decoration: none;
}
.upd-log-body {
  max-height: 420px;
  overflow: auto;
  padding: 10px 12px;
  font: 400 12px/1.65 var(--font-mono);
}
.upd-log-line {
  display: flex;
  gap: 10px;
}
.upd-log-at {
  flex: none;
  color: var(--color-term-dim);
}
.upd-log-t {
  min-width: 0;
  overflow-wrap: anywhere;
}
.upd-log-err .upd-log-t {
  color: var(--color-term-err);
}

/* "Make compliant": one card per device with its changes */
.upd-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 380px), 1fr));
  gap: 10px;
  align-items: start;
}
.upd-dev {
  padding: 12px 14px;
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  background: var(--color-surface);
}
.upd-dev-head {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin-bottom: 6px;
  font-size: 13.5px;
  font-weight: 600;
  overflow-wrap: anywhere;
}
.upd-dev-head a {
  color: var(--color-text);
  text-decoration: none;
}
.upd-dev-head a:hover {
  text-decoration: underline;
}
.upd-dot {
  flex: none;
  width: 8px;
  height: 8px;
  margin-top: 6px;
  border-radius: 50%;
  background: var(--t);
}
.upd-change {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 10px;
  padding: 7px 0;
  border-top: var(--hair-w) solid var(--color-border);
}
.upd-change-t {
  flex: 1 1 180px;
  font: 400 12.5px var(--font-mono);
  overflow-wrap: anywhere;
}
.upd-why {
  margin: 0;
  font-size: 12.5px;
  color: var(--color-danger-fg);
}

/* new update: steps 1-3 beside the sticky plan; the preview (step 4) beside "What happens" */
.upd-split {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  align-items: flex-start;
}
.upd-main {
  display: flex;
  flex: 3 1 480px;
  flex-direction: column;
  gap: 14px;
  max-width: 100%;
  min-width: 0;
}
.upd-pick,
.upd-prev {
  overflow: hidden;
}
.upd-pick .ulist-head,
.upd-prev .ulist-head {
  flex-wrap: wrap;
  gap: 8px;
}
.upd-head-r {
  display: flex;
  align-items: center;
  gap: 10px;
}
.upd-n {
  font-size: 12.5px;
  color: var(--color-text-2);
}
.upd-quick {
  position: relative;
}
.upd-quick > summary {
  height: 22px;
  list-style: none;
}
.upd-quick > summary::-webkit-details-marker {
  display: none;
}
/* the quick selection floats over the list like a row menu: it is not a .rowmenu (its button is a
   text link, not the "⋯" icon), so it positions its panel itself; in the flow it grew the head to
   the menu's height  */
.upd-quick .menu-panel {
  position: absolute;
  z-index: var(--z-menu);
  top: calc(100% + 4px);
  right: 0;
  left: auto;
}
/* the card clips its rounded corners, which would cut off a menu taller than a short list */
.upd-pick:has(.upd-quick[open]) {
  overflow: visible;
}
.upd-pick-list {
  max-height: 340px;
  overflow: auto;
}
.upd-pick-row {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  padding: 6px 16px;
  border-bottom: var(--hair-w) solid var(--color-border);
  cursor: pointer;
}
.upd-pick-row input {
  flex: none;
  width: 16px;
  height: 16px;
  margin: 0;
  accent-color: var(--color-accent);
}
.upd-pick-row .upd-dot {
  width: 7px;
  height: 7px;
  margin-top: 0;
}
.upd-pick-name {
  flex: 1;
  min-width: 0;
  font-size: 13px;
  overflow-wrap: anywhere;
}
/* phone: the name gets a line of its own width and the chip and version drop under it when they do not
   fit beside it, instead of squeezing a normal name into a 4 rem column */
@media (max-width: 44.99rem) {
  .upd-pick-row {
    flex-wrap: wrap;
  }
  .upd-pick-name {
    flex: 1 1 12rem;
  }
  .upd-pick-fw {
    margin-left: auto;
  }
}
.upd-pick-why {
  font-size: 12px;
  color: var(--color-text-3);
}
.upd-pick-fw {
  font: 400 12px var(--font-mono);
  color: var(--color-text-2);
  white-space: nowrap;
}
.upd-none {
  margin: 0;
  padding: 12px 16px;
  color: var(--color-text-2);
}
.ucard.upd-rel {
  gap: 8px;
  padding: 14px 16px;
}
.ucard.upd-rel > h2 {
  margin: 0 0 4px;
}
.upd-relopt {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 12px;
  border: var(--hair-w) solid var(--color-border);
  border-radius: 8px;
  background: var(--color-surface);
  cursor: pointer;
}
.upd-relopt:has(input:checked) {
  border-color: var(--color-accent);
  background: var(--color-accent-bg);
}
.upd-relopt:has(input:focus-visible) {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}
.upd-relopt input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.upd-relopt-t {
  font-weight: 600;
}
.upd-relopt-d {
  font-size: 12px;
  color: var(--color-text-2);
}
.upd-older > .upd-relopt {
  margin-top: 8px;
}
.ucard.upd-opts {
  gap: 0;
  padding: 14px 16px;
}
.ucard.upd-opts > h2 {
  margin: 0 0 6px;
}
.upd-opt {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  min-height: 40px;
  font-size: 13px;
  cursor: pointer;
}
.upd-opt input[type="checkbox"] {
  width: 16px;
  height: 16px;
  margin: 0;
  accent-color: var(--color-accent);
}
.upd-opt select,
.upd-opt input:not([type="checkbox"]) {
  height: var(--ctl);
  padding: 0 8px;
  border: var(--hair-w) solid var(--color-border-strong);
  border-radius: var(--r-control);
  background: var(--color-surface);
  color: var(--color-text);
  font: 400 13px var(--font-sans);
}
.ucard.upd-aside {
  position: sticky;
  top: 110px;
  flex: 1 1 280px;
  max-width: 100%;
  gap: 10px;
}
.ucard.upd-aside > h2 {
  margin: 0;
}
.upd-facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 6px 14px;
  margin: 0;
  font-size: 13px;
}
.upd-facts dt {
  color: var(--color-text-2);
}
.upd-facts dd {
  margin: 0;
  font-weight: 600;
}
.upd-facts.upd-facts-wide {
  grid-template-columns: auto minmax(0, 1fr);
  gap: 7px 14px;
}
.upd-facts-wide dd {
  font-weight: 400;
  overflow-wrap: anywhere;
}
.upd-facts-wide dd b {
  font-weight: 600;
}
.upd-facts-wide dd.mono {
  font: 400 12px var(--font-mono);
}
/* the preview's head keeps its title at the top beside "Change" (the prototype's stretch) */
.upd-prev > .ulist-head {
  align-items: flex-start;
}
/* the address the devices fetch from, as the prototype writes it */
.upd-url {
  font: 400 12px var(--font-mono);
  overflow-wrap: anywhere;
}
.upd-steps {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin: 4px 0 0;
  padding-left: 18px;
  font-size: 12.5px;
  color: var(--color-text-2);
}
.upd-hint {
  margin: 0;
  font-size: 12.5px;
  color: var(--color-warn-fg);
}
.upd-aside .btn-tall {
  height: calc(var(--ctl) + 4px);
}
.upd-prev {
  flex: 3 1 520px;
  max-width: 100%;
}
.upd-prev .ulist-head .btn-link {
  height: 28px;
  padding: 0 10px;
}
.upd-prev-list {
  max-height: 420px;
  overflow: auto;
}
.upd-prow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 14px;
  min-height: 48px;
  padding: 8px 16px;
  border-bottom: var(--hair-w) solid var(--color-border);
}
.upd-prow-name {
  flex: 1 1 220px;
  min-width: 0;
  font-size: 13px;
  font-weight: 500;
  overflow-wrap: anywhere;
}
.upd-prow-ver {
  font: 400 12.5px var(--font-mono);
  white-space: nowrap;
}
.upd-prow-ver b {
  font-weight: 600;
}
.upd-from {
  color: var(--color-text-2);
}
.upd-prow-file {
  width: 190px;
  overflow: hidden;
  font: 400 12px var(--font-mono);
  color: var(--color-text-2);
  white-space: nowrap;
  text-overflow: ellipsis;
}
.upd-prow-why,
.upd-prow-note {
  flex: 1 1 100%;
  font-size: 12.5px;
  color: var(--color-text-2);
}
.ucard.upd-what {
  flex: 2 1 300px;
  gap: 12px;
}
.upd-go {
  display: flex;
  gap: 8px;
  margin-top: 4px;
}
.upd-go .btn-primary {
  flex: 1;
}
/* the cancel dialog's scrim covers the scrollbar gutter too, like the drawer's (F3) */
html:has(dialog#dlg-txn:modal) {
  background: color-mix(in srgb, var(--color-bg) 50%, rgb(10, 14, 18));
}
html:has(dialog#dlg-txn:modal) body {
  min-height: 100vh;
}
/* the page's labels are rows, not the form's stacked, bold labels */
.upd-pick-row,
.upd-opt,
.upd-relopt {
  font-weight: 400;
}
.upd-opt select {
  width: auto;
  padding: 0 30px 0 8px;
}
.upd-opts
  .upd-opt
  input:not([type="checkbox"]):not([type="radio"]):not([type="file"]) {
  width: auto;
  min-width: 220px;
  padding: 0 8px;
}
/* label + control rows of the Options card share one label column and one control width */
.upd-opts .upd-opt:has(select, input:not([type="checkbox"])) {
  display: grid;
  grid-template-columns: 9.5rem minmax(0, 20rem);
  gap: var(--sp-10);
}
.upd-opts .upd-opt select,
.upd-opts .upd-opt input:not([type="checkbox"]):not([type="radio"]):not([type="file"]) {
  width: 100%;
  min-width: 0;
}
@media (max-width: 44.99rem) {
  .upd-opts .upd-opt:has(select, input:not([type="checkbox"])) {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--sp-4, 4px);
    padding-block: var(--sp-6, 6px);
  }
}
.upd-quick > summary.btn {
  height: 18px;
  padding: 0;
}
.upd-older > summary.btn {
  justify-content: flex-start;
  width: max-content;
  height: 24px;
  padding: 0;
}
.upd-prev .ulist-head .btn.btn-link,
.upd-quick > summary.btn,
.upd-older > summary.btn {
  min-height: 0;
}
@media (max-width: 44.99rem) {
  /* a 40 px touch target without moving the layout */
  .upd-quick > summary.btn,
  .upd-older > summary.btn {
    min-height: 40px;
    margin: -11px 0;
  }
  .upd-quick > summary.btn {
    padding: 0 4px;
    margin: -11px -4px;
  }
  .upd-older > summary.btn {
    margin: -8px 0;
  }
  .upd-log-acts a,
  .upd-log-acts button {
    min-height: 40px;
    margin: -12px 0;
  }
  /* an option with a control: its name above the control, the control as wide as the card */
  .upd-opt:not(:has(> input[type="checkbox"])) {
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
    padding: 4px 0;
  }
  .upd-opt select,
  .upd-opts
    .upd-opt
    input:not([type="checkbox"]):not([type="radio"]):not([type="file"]) {
    width: 100%;
    min-width: 0;
  }
}

/* ==== page: Firmware (WP P5), values from the prototype's firmware screen ==== */
.fw-check {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 12.5px;
  color: var(--color-text-2);
  white-space: nowrap;
  align-self: center;
}
.fw-check.t-danger {
  color: var(--color-danger-fg);
}
.fw-check-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--t);
  flex: none;
}
.fw-check-dot.pulse {
  animation: tf-pulse 0.9s ease-in-out infinite;
}
.fw-check-form {
  display: contents;
}
.fw-check-form .btn:disabled {
  opacity: 0.6;
}
.fw-down {
  margin: 0;
}
.fw-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  align-items: flex-start;
}
.fw-rels {
  flex: 1 1 260px;
  max-width: 100%;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.fw-main {
  flex: 3 1 520px;
  max-width: 100%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.fw-rel {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  border-radius: var(--r-card);
  border: var(--hair-w) solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text);
  text-decoration: none;
}
.fw-rel:hover {
  color: var(--color-text);
  border-color: var(--color-border-strong);
}
.fw-rel[aria-current="true"] {
  border-color: var(--color-accent);
  background: var(--color-accent-bg);
}
.fw-rel-t {
  flex: 1;
  min-width: 0;
}
.fw-rel-h {
  display: flex;
  align-items: center;
  gap: 8px;
}
.fw-rel-v {
  font: 600 14px var(--font-mono);
}
.fw-rel-d {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  color: var(--color-text-2);
}
.fw-rel-n {
  font-size: 12px;
  color: var(--color-text-3);
  white-space: nowrap;
}
.fw-older-tg {
  display: flex;
  align-items: center;
  height: var(--ctl);
  padding: 0 4px;
  color: var(--color-accent-fg);
  font: 500 13px var(--font-sans);
  text-decoration: none;
}
.fw-older {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.fw-chip {
  padding: 5px 8px;
  border-radius: 6px;
  background: var(--color-surface-2);
  color: var(--color-text-2);
  font: 400 12px var(--font-mono);
  text-decoration: none;
}
.fw-chip:hover {
  color: var(--color-text);
}
.fw-chip[aria-current="true"] {
  background: var(--color-accent-bg);
  color: var(--color-accent-fg);
}
.fw-norel {
  padding: 12px 14px;
  border-radius: var(--r-card);
  border: var(--hair-w) dashed var(--color-border-strong);
  color: var(--color-text-2);
  font-size: 13px;
}
.fw-norel p {
  margin: 0;
}
.fw-sel {
  display: block;
}
.fw-sel-head {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  align-items: flex-start;
}
.fw-sel h2 {
  margin: 0;
  font: 600 16px var(--font-sans);
  letter-spacing: normal;
}
.fw-sel-sub {
  margin-top: 2px;
  font-size: 12.5px;
  color: var(--color-text-2);
}
.fw-excerpt {
  margin: 12px 0 0;
  padding-left: 18px;
  font-size: 13px;
  color: var(--color-text);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.fw-excerpt li {
  margin: 0;
}
.fw-files-h {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 16px 0 6px;
}
.fw-files-h h3 {
  margin: 0;
  font: 600 13px var(--font-sans);
  letter-spacing: normal;
}
.fw-files-h form {
  margin: 0;
}
.fw-files-h .btn-link {
  min-height: 0;
  font-size: 12.5px;
}
.fw-file {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 8px 0;
  border-top: var(--hair-w) solid var(--color-border);
}
.fw-file-n {
  flex: 1 1 160px;
  font: 500 12.5px var(--font-mono);
  overflow-wrap: anywhere;
}
.fw-file-c,
.fw-file-d {
  width: 80px;
  font-size: 12.5px;
  color: var(--color-text-2);
}
.fw-file-s {
  width: 60px;
  font: 400 12px var(--font-mono);
  color: var(--color-text-3);
  white-space: nowrap;
}
.fw-file .bdg {
  height: 22px;
  padding: 0 8px;
}
.fw-file-fail {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.fw-file-fail .bdg {
  height: 20px;
  padding: 0 7px;
}
.fw-file-nc {
  font-size: 12.5px;
  color: var(--color-text-3);
}
.fw-fetch {
  margin: 0;
}
.fw-fetch .btn-sm {
  height: 30px;
  padding: 0 10px;
  font-size: 12.5px;
}
.fw-file-fail .fw-fetch .btn-sm {
  padding: 0 12px;
  font-size: 13px;
}
.fw-fetching {
  text-decoration: none;
}
.fw-note {
  margin: 8px 0 0;
  font-size: 12.5px;
  color: var(--color-text-2);
}
.fw-fullnotes,
.fw-dlg-body {
  font-size: 13px;
}
.fw-fullnotes h3,
.fw-dlg-body h3 {
  margin: 14px 0 6px;
  font: 600 13px var(--font-sans);
}
.fw-fleet {
  margin: 0;
  padding-left: 18px;
}
.fw-dlg-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
dialog.fw-notes-dlg {
  width: min(720px, calc(100% - 32px));
}
/* the title and Close stay put and only the notes scroll; the shadows at the top and bottom edge
   of the notes show that there is more */
dialog.fw-notes-dlg[open] {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
dialog.fw-notes-dlg .udlg-in {
  flex: 1;
  min-height: 0;
}
dialog.fw-notes-dlg .fw-dlg-body {
  flex: 1;
  min-height: 0;
  overflow: auto;
  padding-bottom: var(--sp-8);
  background:
    linear-gradient(var(--color-surface) 30%, transparent) top / 100% 24px no-repeat local,
    linear-gradient(transparent, var(--color-surface) 70%) bottom / 100% 24px no-repeat local,
    linear-gradient(var(--color-border), transparent) top / 100% 8px no-repeat scroll,
    linear-gradient(transparent, var(--color-border)) bottom / 100% 8px no-repeat scroll;
}
.fw-cache {
  overflow: hidden;
}
.fw-cache .ulist-head {
  padding: 12px 16px;
}
.fw-cache-total {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  font-size: 12px;
  color: var(--color-text-2);
}
.fw-unused {
  margin: 0;
}
.fw-unused .btn-link {
  min-height: 0;
  font-size: 12px;
  color: var(--color-danger-fg);
}
.fw-crow {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
  gap: 4px 10px;
  align-items: center;
  padding: 8px 16px;
  border-bottom: var(--hair-w) solid var(--color-border);
  font-size: 12.5px;
}
.fw-c-f {
  font: 500 12.5px var(--font-mono);
  overflow-wrap: anywhere;
}
.fw-c-v {
  font-family: var(--font-mono);
  color: var(--color-text-2);
}
.fw-c-h {
  font-family: var(--font-mono);
  color: var(--color-text-3);
}
.fw-c-a {
  display: flex;
  justify-content: flex-end;
  gap: 6px;
  align-items: center;
  color: var(--color-text-3);
}
.fw-del,
.fw-needed {
  display: inline-flex;
  align-items: center;
  height: 32px;
  padding: 0 10px;
  color: var(--color-danger-fg);
  font: 500 12.5px var(--font-sans);
  text-decoration: none;
}
.fw-needed {
  color: var(--color-text-2);
}
.fw-cache-empty {
  margin: 0;
  padding: 12px 16px;
  font-size: 13px;
  color: var(--color-text-2);
  border-bottom: var(--hair-w) solid var(--color-border);
}
.fw-drop {
  margin: 12px 16px 16px;
  padding: 18px;
  border: 1.5px dashed var(--color-border-strong);
  border-radius: 9px;
  text-align: center;
  color: var(--color-text-2);
  font-size: 13px;
}
.fw-drop .mono {
  font-family: var(--font-mono);
}
.fw-drop a {
  color: var(--color-accent-fg);
}
.fw-drop.is-over {
  border-color: var(--color-accent);
  background: var(--color-accent-bg);
}
.fw-sum {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.fw-sum code {
  font: inherit;
  padding: 0;
  background: none;
}
.fw-sum .btn.btn-sm {
  height: 20px;
  padding: 0 7px;
  font-size: 11.5px;
}
.fw-upload {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.fw-upload-card .fw-upload {
  margin-top: 4px;
}
.fw-prefetch progress {
  width: 100%;
}
@media (prefers-reduced-motion: reduce) {
  .fw-check-dot.pulse {
    animation: none;
  }
}
/* phone: Delete and the bulk delete are 40 px touch targets like every control (QA #13) */
@media (max-width: 44.99rem) {
  .fw-del,
  .fw-needed {
    height: 40px;
  }
  .fw-unused .btn-link {
    min-height: 40px;
  }
  .fw-chip {
    display: inline-flex;
    align-items: center;
    min-height: 40px;
    padding: 0 12px;
  }
  .seg button {
    height: 40px;
  }
}
/* ==========================================================================
   Page: Add devices (design v2 screen "add", package P6): the header, the
   four tabs' bodies (internal/web/adddevices.templ). Values from the
   prototype's markup (design/v2/template.html, screen add).
   ========================================================================== */
.add-head {
  margin-bottom: var(--sp-14);
}
.add-head h1 {
  margin: 0;
  font: 600 22px/1.2 var(--font-sans);
  letter-spacing: -0.015em;
}
.add-gap {
  flex: 1;
}
.add-t2 {
  color: var(--color-text-2);
}

/* inline notice of a tab: prefill, test result, scan finished, discovery off */
.add-note {
  display: flex;
  gap: var(--sp-10);
  align-items: center;
  flex-wrap: wrap;
  padding: var(--sp-10) var(--sp-12);
  margin-bottom: var(--sp-12);
  border-radius: 8px;
  border: var(--hair-w) solid var(--note-line);
  background: var(--note-bg);
  color: var(--note-fg);
  font-size: 13px;
}
.add-note.tone-ok {
  --note-line: var(--color-ok);
  --note-bg: var(--color-ok-bg);
  --note-fg: var(--color-ok-fg);
}
.add-note.tone-warn {
  --note-line: var(--color-warn);
  --note-bg: var(--color-warn-bg);
  --note-fg: var(--color-warn-fg);
}
.add-note.tone-accent {
  --note-line: var(--color-accent);
  --note-bg: var(--color-accent-bg);
  --note-fg: var(--color-accent-fg);
}
.add-note-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
  background: var(--note-line, var(--color-accent));
}
.add-note-dot.pulse {
  animation: tf-pulse 0.9s ease-in-out infinite;
}
.add-note-text {
  flex: 1;
  min-width: 200px;
}
.add-note-text b {
  font-weight: 600;
}
.add-note .btn {
  white-space: nowrap;
}

/* Add manually */
.add-manual {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
  gap: var(--sp-14) var(--sp-18);
  max-width: 720px;
  padding: var(--sp-18);
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
}
.add-manual > .add-note,
.add-manual > .ucheck,
.add-manual > .add-off {
  grid-column: 1 / -1;
  margin: 0;
}
.add-manual .add-note .btn {
  height: 30px;
}
.add-manual input[readonly] {
  color: var(--color-text);
}
.add-more {
  grid-column: 1 / -1;
}
.add-more > summary {
  width: fit-content;
  font: 500 13px var(--font-sans);
  color: var(--color-text-2);
  cursor: pointer;
}
.add-more-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
  gap: var(--sp-14) var(--sp-18);
  margin-top: var(--sp-12);
}
.add-off {
  font-size: 12.5px;
  color: var(--color-text-2);
}
/* "Add device" comes first in the markup, so Enter in a field adds; the row shows it last */
.add-acts {
  grid-column: 1 / -1;
  display: flex;
  flex-direction: row-reverse;
  gap: var(--sp-8);
  padding-top: var(--sp-14);
  border-top: var(--hair-w) solid var(--color-border);
}

/* Discovered: address changes (and conflicts) */
.add-moves {
  margin-bottom: var(--sp-14);
  overflow: hidden;
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
}
.add-moves-head {
  padding: var(--sp-12) var(--sp-16);
  border-bottom: var(--hair-w) solid var(--color-border);
}
.add-moves-head h2,
.add-bar h2,
.add-plan-head h2 {
  margin: 0;
  font: 600 14px var(--font-sans);
  letter-spacing: normal;
}
.add-moves-sub {
  margin-top: 2px;
  font-size: 12.5px;
  color: var(--color-text-2);
}
.add-move {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-6) var(--sp-16);
  padding: var(--sp-10) var(--sp-12) var(--sp-10) var(--sp-16);
  border-bottom: var(--hair-w) solid var(--color-border);
}
.add-move-name {
  flex: 2 1 220px;
  min-width: 0;
}
.add-move-name a,
.add-move-name > span:first-child {
  display: block;
  font-weight: 500;
  color: var(--color-text);
  text-decoration: none;
  overflow-wrap: anywhere;
}
.add-move-name a:hover {
  text-decoration: underline;
}
.add-move-seen {
  display: block;
  font-size: 12px;
  color: var(--color-text-2);
}
.add-move-addr {
  flex: 1 1 220px;
  font-size: 12.5px;
  white-space: nowrap;
}
.add-move-addr b {
  font-weight: 600;
}
.add-move-why {
  flex: 2 1 240px;
  font-size: 12.5px;
  color: var(--color-text-2);
}
.add-move-acts {
  gap: var(--sp-6);
}

/* Discovered: the New devices bar, "Show ignored" (a link drawn as a checkbox) */
.add-bar {
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  flex-wrap: wrap;
  margin-bottom: var(--sp-10);
}
.add-bar h2 {
  margin-right: var(--sp-8);
}
.add-showign {
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  min-height: var(--ctl);
  font-size: 13px;
  color: var(--color-text);
  text-decoration: none;
}
.add-box {
  width: 16px;
  height: 16px;
  flex: none;
  border: var(--hair-w) solid var(--color-text-2);
  border-radius: 3px;
  background: var(--color-surface);
}
.add-showign[aria-checked="true"] .add-box {
  border-color: var(--color-accent);
  background: var(--color-accent)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 8.5l2.5 2.5L12 5.5' fill='none' stroke='white' stroke-width='2'/%3E%3C/svg%3E")
    center / 14px no-repeat;
}

/* the tables of Discovered and Network scan: fixed columns, the actions stay at the right edge */
.add-table {
  overflow-x: auto;
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
}
.add-table table {
  table-layout: fixed;
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 13px;
}
.add-disc-table table {
  min-width: 1060px;
}
.add-scan-table table {
  min-width: 880px;
}
.add-table thead th {
  height: 38px;
  padding: 0 10px;
  background: var(--color-surface-2);
  border-bottom: var(--hair-w) solid var(--color-border);
  text-align: left;
  font: 500 12px var(--font-sans);
  letter-spacing: normal;
  text-transform: none;
  color: var(--color-text-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: middle;
}
.add-table td {
  height: 52px;
  padding: 0 10px;
  border-bottom: var(--hair-w) solid var(--color-border);
  background: var(--color-surface);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.add-table th.sel,
.add-table td.sel {
  width: auto;
  padding: 0 10px 0 14px;
}
.add-table input[type="checkbox"] {
  width: 15px;
  height: 15px;
  accent-color: var(--color-accent);
}
.add-table tbody tr:hover td {
  background: var(--color-surface);
}
.add-table tbody tr:has(> td.sel input:checked) td {
  background: var(--color-accent-bg);
}
.add-table tbody tr:has(> td.sel input:checked) td:first-child {
  box-shadow: none;
}
.add-table tr.is-ign td {
  background: var(--color-surface-2);
  color: var(--color-text-2);
}
.add-table td.mono {
  font-size: 12.5px;
}
.add-table td.add-t2 {
  font-size: 12.5px;
}
.add-table td.mono.add-t2 {
  color: var(--color-text-2);
}
.add-label {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  font-weight: 500;
}
.add-sub {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  font: 400 11.5px var(--font-mono);
  color: var(--color-text-2);
}
.add-table th.act,
.add-table td.act {
  position: sticky;
  right: 0;
  text-align: right;
}
.add-disc-table th.act,
.add-disc-table td.act {
  border-left: var(--hair-w) solid var(--color-border);
}
.add-table td a.btn {
  font-weight: 500;
  text-decoration: none;
}
.add-table td a.btn-primary {
  font-weight: 600;
  color: var(--color-on-accent);
}
.add-table td .btn-sm {
  height: 32px;
}
.add-table td .btn-link {
  height: var(--ctl);
  padding: 0 10px;
}
.btn.add-ign {
  padding: 0 10px;
  color: var(--color-text-2);
}
.add-disc-table col.c-sel,
.add-scan-table col.c-sel {
  width: 44px;
}
.add-disc-table col.c-name {
  width: 22%;
}
.add-disc-table col.c-ip {
  width: 120px;
}
.add-disc-table col.c-mac {
  width: 176px;
}
.add-disc-table col.c-model {
  width: 96px;
}
.add-disc-table col.c-fw {
  width: 84px;
}
.add-disc-table col.c-src {
  width: 124px;
}
.add-disc-table col.c-first {
  width: 104px;
}
.add-disc-table col.c-last {
  width: 96px;
}
.add-disc-table col.c-act {
  width: 160px;
}
.add-scan-table col.c-name {
  width: 26%;
}
.add-scan-table col.c-ip {
  width: 130px;
}
.add-scan-table col.c-mac {
  width: 160px;
}
.add-scan-table col.c-fw {
  width: 100px;
}
.add-scan-table col.c-st {
  width: 130px;
}
.add-scan-table col.c-act {
  width: 170px;
}
.add-more-known {
  display: block;
  padding: var(--sp-10) var(--sp-16);
  font-size: 12.5px;
  color: var(--color-text-2);
  text-decoration: none;
}
.add-empty h2 {
  font-size: 16px;
}
.add-empty p {
  max-width: 440px;
  font-size: 13.5px;
}
.add-empty {
  padding: 36px var(--sp-20);
}

/* phone: cards instead of the tables */
.add-cards {
  display: none;
}
@media (max-width: 44.99rem) {
  .add-table {
    display: none;
  }
  .add-cards {
    display: flex;
    flex-direction: column;
    gap: var(--sp-8);
  }
}
.add-card {
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr);
  gap: 0 4px;
  padding: 8px 12px 10px 2px;
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
}
.add-card.is-ign {
  background: var(--color-surface-2);
}
.add-card-sel {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
}
.add-card-sel input {
  width: 18px;
  height: 18px;
  accent-color: var(--color-accent);
}
.add-card-body {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
  padding-top: 8px;
}
.add-card-title {
  display: flex;
  gap: var(--sp-6);
  align-items: flex-start;
  flex-wrap: wrap;
}
.add-card-name {
  font-weight: 600;
  overflow-wrap: anywhere;
}
.add-card.is-ign .add-card-name {
  color: var(--color-text-2);
}
.add-card-meta {
  font: 400 12px var(--font-mono);
  color: var(--color-text-2);
  overflow-wrap: anywhere;
}
.add-card-src {
  font-size: 12px;
  color: var(--color-text-3);
}
.add-card-acts {
  display: flex;
  gap: var(--sp-6);
  margin-top: 4px;
}
.add-card-acts .btn {
  flex: 1;
}
.add-card-btn {
  margin-top: 4px;
}
.add-scan-card {
  display: block;
  padding: 10px 12px;
}
.add-scan-card .add-card-body {
  padding-top: 0;
  gap: 6px;
}
.add-scan-card .add-card-title {
  justify-content: space-between;
  flex-wrap: nowrap;
}

/* Network scan */
.add-scanbar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-8);
  align-items: center;
  margin-bottom: var(--sp-12);
}
/* the id beats the global input rule (width 100 %, font inherit) */
#scan input.add-subnet {
  width: 200px;
  max-width: 100%;
  font-family: var(--font-mono);
}
.add-scanstatus {
  font-size: 12.5px;
  color: var(--color-text-2);
}
.add-scanerr {
  flex-basis: 100%;
}
.add-progress {
  margin-bottom: var(--sp-12);
  padding: var(--sp-14) var(--sp-16);
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
}
.add-progress-head {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-10);
  flex-wrap: wrap;
  margin-bottom: var(--sp-8);
  font-size: 13px;
}
.add-progress-t {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-8);
}
.add-progress-t .add-note-dot {
  background: var(--color-accent);
}
.add-progress-t b {
  font-weight: 600;
}
.add-progress progress {
  display: block;
  width: 100%;
  height: 8px;
  border: 0;
  border-radius: 4px;
  overflow: hidden;
  appearance: none;
  background: var(--color-surface-3);
}
.add-progress progress::-webkit-progress-bar {
  background: var(--color-surface-3);
}
.add-progress progress::-webkit-progress-value {
  background: var(--color-accent);
}
.add-progress progress::-moz-progress-bar {
  background: var(--color-accent);
}
.add-progress-found {
  margin-top: var(--sp-8);
  font-size: 12.5px;
  color: var(--color-text-2);
}
.add-chips {
  display: flex;
  gap: var(--sp-6);
  flex-wrap: wrap;
  align-items: center;
  margin-bottom: var(--sp-10);
}
.add-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-6);
  height: var(--ctl);
  padding: 0 11px;
  border-radius: 999px;
  border: var(--hair-w) solid var(--color-border-strong);
  background: var(--color-surface);
  color: var(--color-text);
  font: 500 12.5px var(--font-sans);
  text-decoration: none;
  white-space: nowrap;
}
.add-chip.is-on {
  border-color: var(--color-text);
  background: var(--color-text);
  color: var(--color-surface);
}
.add-chip-n {
  opacity: 0.75;
}

/* Import from TasmoAdmin */
.add-import {
  display: flex;
  flex-direction: column;
  gap: var(--sp-14);
  max-width: 1000px;
}
.add-import > .banner {
  margin: 0;
}
.add-drop {
  display: flex;
  gap: var(--sp-12);
  align-items: center;
  flex-wrap: wrap;
  padding: var(--sp-16);
  background: var(--color-surface);
  border: 1.5px dashed var(--color-border-strong);
  border-radius: var(--r-card);
}
.add-drop.is-over {
  border-color: var(--color-accent);
  background: var(--color-accent-bg);
}
.add-drop-text {
  flex: 1;
  min-width: 220px;
  font-size: 13px;
}
.add-drop-text b {
  font-weight: 600;
}
.add-drop-sub {
  display: block;
  font-size: 12.5px;
  color: var(--color-text-2);
}
.add-drop-btn {
  position: relative;
  display: inline-flex;
  font-weight: 500;
}
.add-drop-btn:focus-within {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}
/* the real file input covers its button, invisible: clicking the button opens the chooser */
.add-drop-input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
}
.add-plan {
  overflow: hidden;
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
}
.add-plan-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--sp-8);
  flex-wrap: wrap;
  padding: var(--sp-12) var(--sp-16);
  border-bottom: var(--hair-w) solid var(--color-border);
}
.add-plan-counts {
  display: flex;
  gap: var(--sp-6);
  flex-wrap: wrap;
}
.add-improw {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-6) var(--sp-14);
  min-height: 52px;
  padding: var(--sp-10) var(--sp-16);
  border-bottom: var(--hair-w) solid var(--color-border);
}
.add-impw {
  flex: none;
  width: 70px;
}
.add-impw-res {
  width: 80px;
}
.add-improw-dev {
  flex: 1 1 220px;
  min-width: 0;
}
.add-improw-name {
  display: block;
  font-size: 13px;
  font-weight: 500;
  overflow-wrap: anywhere;
}
.add-improw-ip {
  display: block;
  font-size: 12px;
  color: var(--color-text-2);
}
.add-improw-why {
  flex: 2 1 260px;
  font-size: 12.5px;
  color: var(--color-text-2);
}
.add-plan-foot {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-10);
  flex-wrap: wrap;
  align-items: center;
  padding: var(--sp-12) var(--sp-16);
  font-size: 12.5px;
}
.add-result-acts {
  justify-content: flex-end;
}
/* the prototype's fields are 13 px; this outweighs the global input rule (13.5 px) */
.add-manual input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
.add-manual textarea,
#scan input.add-subnet {
  font-size: 13px;
}
/* the dots of a prefilled default password read like a filled field */
.add-manual input[type="password"]::placeholder {
  color: var(--color-text);
}
.add-head + .utabs .bdg {
  height: 18px;
  padding: 0 var(--sp-6);
  border-radius: 9px;
  font-size: 11px;
  background: var(--color-accent);
  color: var(--color-on-accent);
}
/* ==== page: Bulk action (WP P7): scope (devices + options aside) and result ==== */
.bk-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  align-items: flex-start;
}
.bk-devs {
  flex: 3 1 460px;
  max-width: 100%;
  min-width: 0;
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  overflow: hidden;
}
.bk-devs-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  padding: 10px 8px 10px 16px;
  border-bottom: var(--hair-w) solid var(--color-border);
}
.bk-devs-head h2 {
  margin: 0;
  font: 600 14px var(--font-sans);
  letter-spacing: normal;
}
.bk-change {
  display: inline-flex;
  align-items: center;
  height: var(--ctl);
  padding: 0 10px;
  color: var(--color-accent-fg);
  font: 500 13px var(--font-sans);
  text-decoration: none;
}
.bk-change:hover {
  color: var(--color-accent-hover);
}
.bk-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 4px 4px 16px;
  border-bottom: var(--hair-w) solid var(--color-border);
  min-height: 52px;
}
.bk-dev,
.bk-rdev {
  flex: 1;
  min-width: 0;
}
.bk-name {
  display: block;
  font-weight: 500;
  font-size: 13px;
  overflow-wrap: anywhere;
}
.bk-meta {
  display: block;
  font: 400 12px var(--font-mono);
  color: var(--color-text-2);
}
.bk-row .bk-meta > span {
  display: inline;
}
.bk-x {
  width: 40px;
  height: 40px;
  flex: none;
  padding: 0;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--color-text-2);
  font: 400 18px var(--font-sans);
  cursor: pointer;
}
.bk-x:hover {
  background: var(--color-surface-2);
  color: var(--color-text-2);
}
.bk-skipnote {
  margin: 0;
  padding: 10px 16px;
  font-size: 12.5px;
  color: var(--color-text-2);
}
.bk-aside {
  flex: 2 1 300px;
  max-width: 100%;
  min-width: 0;
  position: sticky;
  top: 110px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 16px;
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
}
.bk-field {
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin: 0;
  font: 500 12.5px var(--font-sans);
  color: var(--color-text-2);
}
.bk-field input:not([type="checkbox"]),
.bk-field select {
  font: 400 13.5px var(--font-sans);
}
.bk-field select {
  padding-left: 8px;
}
.bk-field textarea {
  min-height: 0;
  padding: 8px 10px;
  font: 400 13px/1.5 var(--font-mono);
  resize: vertical;
}
.bk-help {
  display: block;
  font: 400 12px var(--font-sans);
  color: var(--color-text-3);
}
.bk-opt {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 40px;
  margin: 0;
  font: 400 13px var(--font-sans);
  color: var(--color-text);
  cursor: pointer;
}
.bk-opt input {
  width: 16px;
  height: 16px;
  margin: 0;
  flex: none;
  accent-color: var(--color-accent);
}
.bk-warn {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 10px 12px;
  border-radius: 8px;
  border: var(--hair-w) solid var(--color-warn);
  background: var(--color-warn-bg);
  color: var(--color-warn-fg);
  font-size: 13px;
}
.bk-warn-dot {
  width: 8px;
  height: 8px;
  margin-top: 5px;
  border-radius: 50%;
  flex: none;
  background: var(--color-warn);
}
.bk-sum {
  padding-top: 12px;
  border-top: var(--hair-w) solid var(--color-border);
  font-size: 13px;
  color: var(--color-text-2);
}
.bk-titlerow {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.bk-titlerow .bk-state {
  height: 22px;
}
.bk-cmdline {
  margin-bottom: 12px;
  padding: 8px 12px;
  border-radius: 8px;
  border: var(--hair-w) solid var(--color-border);
  background: var(--color-surface-2);
  font: 400 12.5px var(--font-mono);
  overflow-wrap: anywhere;
}
.bk-tiles {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
  max-width: 640px;
  margin-bottom: 14px;
}
.bk-tile {
  padding: 12px 14px;
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
}
.bk-tile-l {
  display: flex;
  align-items: center;
  gap: 7px;
  font: 500 12.5px var(--font-sans);
  color: var(--color-text-2);
}
.bk-tile-v {
  margin-top: 6px;
  font: 600 24px/1.1 var(--font-sans);
  font-variant-numeric: tabular-nums;
}
.bk-res {
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  overflow: hidden;
}
.bk-rrow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 14px;
  padding: 10px 16px;
  border-bottom: var(--hair-w) solid var(--color-border);
  min-height: 52px;
}
.bk-rdev {
  flex: 1 1 240px;
}
.bk-rbadge {
  width: 86px;
  flex: none;
}
.bk-detail {
  flex: 2 1 260px;
  min-width: 0;
  font: 400 12.5px var(--font-mono);
  color: var(--color-text-2);
  overflow-wrap: anywhere;
}
/* ==== page: System settings (design v2, WP P8) ==== */
/* the prototype keeps 14 px between the page header and the tabs */
.pghead:has(+ .utabs[aria-label="Settings sections"]) {
  margin-bottom: var(--sp-14);
}
/* one card over all tabs: 18 px padding, 16 px between its parts, the footer under a hairline */
.syscard {
  max-width: 860px;
  padding: var(--sp-18);
  gap: var(--sp-16);
}
.sys-tab {
  display: flex;
  flex-direction: column;
  gap: var(--sp-16);
}
.sys-tab[hidden] {
  display: none;
}
.sys-head h2 {
  margin: 0 0 var(--sp-4);
  font: 600 14px var(--font-sans);
  letter-spacing: normal;
}
#sec-signin .sys-head h2 {
  font-size: 15px;
}
.sys-head p {
  margin: 0;
  font-size: 13px;
  color: var(--color-text-2);
  text-wrap: pretty;
}
.sys-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  gap: var(--sp-14) var(--sp-18);
  align-items: start;
}
.sys-grid .rcards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr));
  gap: var(--sp-10);
}
.sys-grid .rcards legend {
  grid-column: 1 / -1;
}
.sys-grid .utoggle {
  padding: var(--sp-12) var(--sp-14);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-banner);
}
.sys-reset {
  min-height: 0;
  margin-top: calc(-1 * var(--sp-8));
  font-size: 12px;
  color: var(--color-text-2);
}
.sys-test {
  display: flex;
  align-items: center;
  gap: var(--sp-10);
  flex-wrap: wrap;
  grid-column: 1 / -1;
}
.sys-test-res {
  font-size: 12.5px;
  color: var(--t-fg);
}
.sys-test-help {
  font-size: 12px;
  color: var(--color-text-3);
  flex: 1 1 260px;
}
.sys-status {
  display: flex;
  align-items: center;
  gap: var(--sp-12);
  flex-wrap: wrap;
  padding: var(--sp-12) var(--sp-14);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  background: var(--color-surface);
}
.sys-status-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex: none;
  background: var(--t);
}
.sys-status-dot.t-ok {
  animation: tf-pulse 2.4s ease-in-out infinite;
}
.sys-status-text {
  flex: 1;
  min-width: 220px;
}
.sys-status-text b {
  display: block;
  font-weight: 600;
  font-size: 13.5px;
}
.sys-status-text span {
  display: block;
  font-size: 12.5px;
  color: var(--color-text-2);
}
.sys-skipped {
  margin: var(--sp-4) 0 0;
  padding-left: var(--sp-18);
}
.sys-foot {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: var(--sp-8);
  flex-wrap: wrap;
  border-top: var(--hair-w) solid var(--color-border);
  padding-top: var(--sp-14);
}
.sys-container table {
  margin-top: var(--sp-8);
}
@media (prefers-reduced-motion: reduce) {
  .sys-status-dot.t-ok {
    animation: none;
  }
}

/* ==== page: System settings, Backups storage and Reset (design v2, W5 / N9) ==== */
/* Storage: heading, four totals, the largest devices; values from the prototype's backups tab */
.sys-storage {
  display: flex;
  flex-direction: column;
  gap: var(--sp-12);
}
.sys-storage-h {
  margin: 0;
  font: 600 14px var(--font-sans);
  letter-spacing: normal;
}
.sys-sums {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: var(--sp-10);
}
.sys-sum {
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  padding: var(--sp-12) var(--sp-14);
}
.sys-sum-label {
  font-size: 12.5px;
  color: var(--color-text-2);
}
.sys-sum-value {
  margin-top: var(--sp-4);
  font: 600 22px/1.2 var(--font-sans);
  font-variant-numeric: tabular-nums;
}
.sys-store,
.sys-orphans {
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  overflow: hidden;
}
.sys-store-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 80px 80px 110px;
  gap: var(--sp-10);
  align-items: center;
  height: 40px;
  padding: 0 var(--sp-14);
  border-top: var(--hair-w) solid var(--color-border);
  font-size: 13px;
  color: var(--color-text);
  text-decoration: none;
}
a.sys-store-row:hover {
  background: var(--color-surface-2);
}
.sys-store-row.sys-store-head {
  height: auto;
  padding: var(--sp-8) var(--sp-14);
  border-top: 0;
  background: var(--color-surface-2);
  font: 500 12px var(--font-sans);
  color: var(--color-text-2);
}
.sys-store-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sys-store-last {
  color: var(--color-text-2);
  white-space: nowrap;
}
.sys-store-foot {
  padding: var(--sp-8) var(--sp-14);
  border-top: var(--hair-w) solid var(--color-border);
  font-size: 12.5px;
  color: var(--color-text-2);
}
/* backups of deleted devices: one row per run, the device backups' actions on the right */
.sys-orphan {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-10);
  flex-wrap: wrap;
  padding: var(--sp-10) var(--sp-14);
  border-top: var(--hair-w) solid var(--color-border);
}
.sys-orphan:first-child {
  border-top: 0;
}
.sys-orphan-main {
  flex: 1 1 220px;
  min-width: 0;
}
.sys-orphan-title {
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  font-size: 13px;
  font-weight: 500;
}
.sys-orphan-detail {
  font-size: 12.5px;
  color: var(--color-text-2);
}
/* Advanced: "Reset all settings" in a danger-bordered box */
.sys-danger {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--sp-12);
  flex-wrap: wrap;
  padding: var(--sp-14);
  border: var(--hair-w) solid var(--color-danger);
  border-radius: 9px;
}
.sys-danger-title {
  font-weight: 600;
  color: var(--color-danger-fg);
}
.sys-danger-text {
  font-size: 12.5px;
  color: var(--color-text-2);
}
/* phone: the prototype's four fixed columns leave the device name no width; the last
   backup moves under the name */
@media (max-width: 44.99rem) {
  .sys-store-row {
    grid-template-columns: minmax(0, 1fr) 56px 72px;
    grid-template-rows: auto auto;
    height: auto;
    padding: var(--sp-8) var(--sp-14);
    row-gap: 0;
  }
  .sys-store-row > .sys-store-last {
    grid-column: 1;
    grid-row: 2;
    font-size: 12px;
  }
  .sys-store-head > :last-child {
    display: none;
  }
}

/* ==== page: Audit log (design v2, WP P8) ==== */
/* the filter row: search (220-340 px) and the selects at their content width */
.audit-filters {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-8);
  margin: 0 0 var(--sp-12);
}
.audit-filters input[type="search"] {
  flex: 1 1 220px;
  max-width: 340px;
  font-size: 13.5px;
}
.audit-filters select {
  width: auto;
  font-size: 13px;
  padding-left: var(--sp-8);
}
.audit-filters [hidden] {
  display: none;
}
/* phone: the search over a full row, the selects two by two (three across cut "Last 7 days") */
@media (max-width: 44.99rem) {
  .audit-filters {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .audit-filters input[type="search"] {
    grid-column: 1 / -1;
    max-width: none;
  }
  .audit-filters select {
    width: 100%;
    min-width: 0;
  }
  .audit-filters .btn {
    grid-column: 1 / -1;
  }
}
.audit-choices {
  margin: var(--sp-4) 0 0;
  padding-left: var(--sp-18);
}
.audit-card {
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  /* no overflow: hidden, the Columns menu must never be clipped (0.10.1) */
}
.audit-card .pager {
  padding: var(--sp-10) var(--sp-16);
  margin: 0;
}

/* ==== page: first-run setup (design v2 "setup" step 3, WP P8) ==== */
/* a page without navigation: the brand and the card centred, 96 px from the top */
main.bare {
  padding: 96px var(--sp-16) var(--sp-40);
}
.bare .brand {
  min-height: 40px; /* a touch target on a phone, as every other control */
}
.bare .auth-card:has(.setup-steps) {
  width: min(480px, 100%);
}
.setup-steps {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  align-items: center;
  gap: var(--sp-8);
}
.setup-steps li {
  display: flex;
  align-items: center;
  gap: var(--sp-7);
  flex: 1;
  min-width: 0;
}
.setup-mark {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  flex: none;
  font: 600 11px var(--font-sans);
  background: var(--color-surface-3);
  color: var(--color-text-2);
}
.setup-steps .is-done .setup-mark {
  background: var(--color-ok);
  color: var(--color-on-accent);
}
.setup-steps .is-current .setup-mark {
  background: var(--color-accent);
  color: var(--color-on-accent);
}
.setup-label {
  font: 500 12px var(--font-sans);
  color: var(--color-text-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.setup-steps .is-current .setup-label {
  color: var(--color-text);
}
.setup-bar {
  flex: 1;
  height: 2px;
  min-width: 8px;
  border-radius: 1px;
  background: var(--color-border);
}
.setup-steps .is-done .setup-bar {
  background: var(--color-ok);
}
.setup-lead {
  margin: 0;
  color: var(--color-text-2);
  font-size: 13.5px;
  text-wrap: pretty;
}
.setup-form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-14);
}
.setup-broker {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 96px;
  gap: var(--sp-10);
}
.setup-broker + .setup-broker {
  grid-template-columns: 1fr 1fr;
}
@media (max-width: 44.99rem) {
  main.bare {
    padding-top: var(--sp-40);
  }
}
/* ==========================================================================
   P10 (design v2): the Backups tab, the backup comparison, the restore pages and the
   Replace device tab. Markup: backuppages.templ, comparepage.templ, restorepages.templ,
   replacepage.templ. Behaviour: select.js (selection bar), form.js (comparison pickers),
   dialog.js (delete and prune dialogs).
   ========================================================================== */

/* Backups tab: retention line, Prune now, total, Back up now */
.bk-bar {
  display: flex;
  align-items: center;
  gap: var(--sp-8) var(--sp-12);
  flex-wrap: wrap;
  margin-bottom: var(--sp-10);
}
.bk-retention {
  flex: 1 1 300px;
  font-size: 13px;
  color: var(--color-text-2);
  text-wrap: pretty;
}
.bk-link {
  color: var(--color-accent-fg);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.bk-total {
  font-size: 12.5px;
  color: var(--color-text-3);
}

/* the selection bar: dark, in the flow above the list (the prototype's, not the fixed bulk bar) */
.bk-selbar {
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  flex-wrap: wrap;
  padding: 6px 6px 6px 14px;
  margin-bottom: var(--sp-10);
  border-radius: 9px;
  background: var(--color-text);
  color: var(--color-surface);
}
.bk-selbar[hidden],
.bk-selbar [hidden] {
  display: none;
}
.bk-selcount {
  flex: 1;
  font: 600 13px var(--font-sans);
}
.bk-selbar .btn.btn-primary {
  padding: 0 var(--sp-12);
  border: 0;
}
.bk-selbar .btn.bk-seldel,
.bk-selbar .btn.bk-seldel:hover {
  border-color: color-mix(in oklab, var(--color-surface) 30%, transparent);
  background: transparent;
  color: var(--color-surface);
  font-weight: 500;
}

/* the rows: one per backup run or failed attempt */
.bk-list {
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  overflow: hidden;
}
.bk-list .bk-row {
  display: flex;
  align-items: center;
  gap: 6px var(--sp-12);
  flex-wrap: wrap;
  padding: 6px 10px 6px 4px;
  border-bottom: var(--hair-w) solid var(--color-border);
  min-height: 60px;
}
.bk-check {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  flex: none;
}
.bk-check input {
  width: 16px;
  height: 16px;
  margin: 0;
  accent-color: var(--color-accent);
}
.bk-main {
  flex: 1 1 260px;
  min-width: 0;
}
.bk-title {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.bk-title time {
  font-weight: 500;
}
.bk-detail {
  font-size: 12px;
  color: var(--color-text-2);
}
.bk-reason {
  margin-top: 2px;
  font-size: 12.5px;
  color: var(--color-danger-fg);
}
.bk-acts {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
  align-items: center;
}
/* when the actions wrap under the text (phone), they get the card's inner padding like the text above */
@media (max-width: 44.99rem) {
  .bk-list .bk-acts {
    margin-left: var(--sp-8);
  }
}
.btn.bk-keep {
  padding: 0 var(--sp-10);
  gap: 7px;
  font-size: 12.5px;
}
.btn.bk-keep.is-kept,
.btn.bk-keep.is-kept:hover {
  background: var(--color-accent-bg);
  color: var(--color-accent-fg);
}
.bk-pin {
  width: 7px;
  height: 7px;
  border: 1.5px solid currentColor;
  border-radius: 1px;
  transform: rotate(45deg);
}
.btn.btn-link.bk-act {
  height: var(--ctl);
  padding: 0 var(--sp-10);
}
.btn.btn-link.bk-del,
.btn.btn-link.bk-del:hover {
  color: var(--color-danger-fg);
}
.bk-foot {
  margin: var(--sp-10) 0 0;
  font-size: 12.5px;
  color: var(--color-text-2);
}
.bk-page > .ulist {
  margin-top: var(--sp-16);
}
.bk-job {
  display: grid;
  grid-template-columns: auto auto auto minmax(0, 1fr);
  gap: var(--sp-12);
  align-items: center;
  font-size: 13px;
}
.bk-job-detail {
  color: var(--color-text-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.bk-status:empty {
  display: none;
}
.bk-status {
  margin-top: var(--sp-10);
}

/* comparison: pickers in one row, the footer with the restore button */
.cmp-controls {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-10);
  align-items: flex-end;
  margin-bottom: var(--sp-12);
}
.cmp-pick {
  flex: 1 1 220px;
  max-width: 330px;
}
.cmp-pick select {
  font-size: 13.5px;
}
.cmp-all {
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  height: var(--ctl);
  font-size: 13px;
  cursor: pointer;
}
.cmp-all input {
  width: 16px;
  height: 16px;
  margin: 0;
  accent-color: var(--color-accent);
}
.cmp-note {
  margin: 0 0 var(--sp-10);
  font-size: 12.5px;
  color: var(--color-text-2);
}
.cmp-none {
  padding: 24px;
  text-align: center;
  color: var(--color-text-2);
  font-size: 13px;
}
.cmp-foot {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-10);
  flex-wrap: wrap;
  align-items: center;
  margin-top: var(--sp-14);
}
.cmp-foot > span {
  font-size: 12.5px;
  color: var(--color-text-2);
}

/* restore: the confirmation and the progress, one 820 px column */
.rs-page {
  max-width: 820px;
  display: flex;
  flex-direction: column;
  gap: var(--sp-14);
}
.rs-page > .pghead {
  margin-bottom: 0;
}
.rs-page .banner {
  margin: 0;
}
.rs-changes {
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  overflow: hidden;
}
.rs-changes > h2 {
  margin: 0;
  padding: var(--sp-12) var(--sp-16);
  border-bottom: var(--hair-w) solid var(--color-border);
  font: 600 14px var(--font-sans);
  letter-spacing: normal;
}
.rs-grid {
  display: grid;
  grid-template-columns: minmax(120px, 0.6fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--sp-12);
  padding: var(--sp-8) var(--sp-16);
}
.rs-headrow {
  background: var(--color-surface-2);
  font: 500 12px var(--font-sans);
  color: var(--color-text-2);
}
.rs-row {
  border-top: var(--hair-w) solid var(--color-border);
  font: 400 12.5px var(--font-mono);
  overflow-wrap: anywhere;
}
.rs-key {
  font-weight: 500;
}
.rs-now {
  color: var(--color-text-2);
}
.rs-none {
  margin: 0;
  padding: var(--sp-12) var(--sp-16);
  font-size: 13px;
  color: var(--color-text-2);
}
.rs-steps-text {
  margin: 0;
  padding-left: 18px;
  font-size: 13px;
  color: var(--color-text-2);
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.rs-cred {
  margin: 0;
  font-size: 12.5px;
  color: var(--color-text-2);
}
.rs-form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-10);
}
.rs-ack {
  align-items: flex-start;
}
.rs-ack input {
  margin-top: 2px;
  flex: none;
}
.ucheck.is-invalid input {
  outline: 2px solid var(--color-danger);
  outline-offset: 1px;
}
.rs-acts {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: var(--sp-8);
  flex-wrap: wrap;
}
.rs-leave {
  font-size: 12.5px;
  color: var(--color-text-2);
}
.rs-status {
  display: flex;
  flex-direction: column;
  gap: var(--sp-14);
}
.rs-progress {
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  padding: 6px var(--sp-16);
}
.rs-step {
  display: flex;
  gap: var(--sp-12);
  align-items: flex-start;
  padding: var(--sp-10) 0;
  border-bottom: var(--hair-w) solid var(--color-border);
}
.rs-mark {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  flex: none;
  background: var(--color-surface-3);
  color: var(--color-text-2);
  font: 600 12px var(--font-sans);
}
.rs-step.is-done .rs-mark {
  background: var(--color-ok-bg);
  color: var(--color-ok-fg);
}
.rs-step.is-active .rs-mark {
  background: var(--color-accent-bg);
  color: var(--color-accent-fg);
}
.rs-step.is-failed .rs-mark {
  background: var(--color-danger-bg);
  color: var(--color-danger-fg);
}
.rs-step-text {
  min-width: 0;
  padding-top: 2px;
}
.rs-step-label {
  display: block;
  font-weight: 500;
  font-size: 13.5px;
}
.rs-step.is-todo .rs-step-label {
  color: var(--color-text-2);
}
.rs-step-detail {
  display: block;
  margin-top: 1px;
  font-size: 12.5px;
  color: var(--color-text-2);
}

/* Replace device: one 820 px card */
.rp-card {
  max-width: 820px;
  display: flex;
  flex-direction: column;
  gap: var(--sp-16);
  padding: 18px;
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
}
.rp-card h2 {
  margin: 0 0 4px;
  font: 600 15px var(--font-sans);
  letter-spacing: normal;
}
.rp-lead {
  margin: 0;
  font-size: 13px;
  color: var(--color-text-2);
  text-wrap: pretty;
}
.rp-card .banner {
  margin: 0;
}
.rp-pick,
.rp-start {
  display: flex;
  flex-direction: column;
  gap: var(--sp-16);
}
.rp-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  gap: var(--sp-12);
  align-items: stretch;
}
.rp-old {
  padding: var(--sp-12);
  border: var(--hair-w) solid var(--color-border);
  border-radius: 9px;
  background: var(--color-surface-2);
}
.rp-old-k {
  margin-bottom: 4px;
  font-size: 12px;
  color: var(--color-text-2);
}
.rp-old-name {
  font-weight: 600;
  overflow-wrap: anywhere;
}
.rp-old-line {
  font: 400 12px var(--font-mono);
  color: var(--color-text-2);
}
.rp-grid select {
  padding: 0 8px;
}
.rp-addr {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 90px;
  gap: var(--sp-8);
  align-content: start;
}
.rp-checks {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.rp-checks .ucheck input {
  accent-color: var(--color-accent);
}
.rp-acts {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: var(--sp-8);
  flex-wrap: wrap;
}
.rp-backup {
  margin-right: auto;
  font-size: 13px;
}
.rp-backup summary {
  cursor: pointer;
  color: var(--color-accent-fg);
}
.rp-backup[open] .ufield {
  margin-top: var(--sp-8);
}
.rp-preview {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: var(--sp-12);
}
.rp-box {
  border: var(--hair-w) solid var(--color-border);
  border-radius: 9px;
  overflow: hidden;
}
.rp-box-h {
  padding: var(--sp-10) var(--sp-14);
  background: var(--color-surface-2);
  font: 600 13px var(--font-sans);
}
.rp-kv {
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr);
  gap: var(--sp-10);
  padding: 7px var(--sp-14);
  border-top: var(--hair-w) solid var(--color-border);
  font-size: 13px;
}
.rp-kv > span:first-child {
  color: var(--color-text-2);
}
.rp-kv .mono {
  font-family: var(--font-mono);
  font-size: 12.5px;
  overflow-wrap: anywhere;
}
.rp-skip {
  padding: 7px var(--sp-14);
  border-top: var(--hair-w) solid var(--color-border);
  font-size: 13px;
}
.rp-skip > span {
  display: block;
}
.rp-skip > span + span {
  font-size: 12px;
  color: var(--color-text-2);
}
.rp-new {
  display: flex;
  flex-direction: column;
  gap: var(--sp-8);
}
.rp-other {
  font-size: 13px;
}
.rp-other summary {
  cursor: pointer;
  color: var(--color-accent-fg);
}
.rp-other[open] .rp-addr {
  margin-top: var(--sp-8);
}

/* ==== page: Policy (/policy, /policy/io, /policy/fix; design v2 N3 + N21): status line,
   conflicts, rule cards, editor, live preview, version history, import / export ==== */
.pol-inline {
  display: contents;
}
.pol-line {
  display: flex;
  align-items: center;
  gap: 6px var(--sp-12);
  flex-wrap: wrap;
  min-height: 46px;
  padding: 6px 6px 6px var(--sp-14);
  margin: -4px 0 var(--sp-14);
  border-radius: 9px;
  border: var(--hair-w) solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text-2);
  font-size: 13px;
}
.pol-line-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
  background: var(--color-ok);
  animation: tf-pulse 2.4s ease-in-out infinite;
}
.pol-line-text {
  flex: 1;
  min-width: 220px;
}
.pol-line-acts {
  display: flex;
  gap: 6px;
}
.pol-line .pol-line-btn {
  height: 32px;
}
.pol-line .pol-line-ghost {
  background: transparent;
}
.pol-line-paused {
  background: var(--color-neutral-bg);
  border-color: var(--color-border-strong);
  color: var(--color-neutral-fg);
}
.pol-line-paused .pol-line-dot {
  background: var(--color-neutral);
  animation: none;
}
.pol-line-failed {
  background: var(--color-danger-bg);
  border-color: var(--color-danger);
  color: var(--color-danger-fg);
}
.pol-line-failed .pol-line-dot {
  background: var(--color-danger);
  animation: none;
}
.pol-confs {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: var(--sp-12);
}
.pol-conf {
  display: flex;
  gap: var(--sp-10);
  align-items: center;
  flex-wrap: wrap;
  padding: var(--sp-10) var(--sp-12);
  border-radius: 8px;
  border: var(--hair-w) solid var(--color-accent);
  background: var(--color-accent-bg);
  color: var(--color-accent-fg);
  font-size: 13px;
}
.pol-conf > span:last-child {
  flex: 1;
  min-width: 200px;
}
.pol-conf-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
  background: var(--color-accent);
}
/* the empty state: a dashed frame with the four templates */
.pol-empty {
  display: flex;
  flex-direction: column;
  gap: var(--sp-10);
  padding: var(--sp-24);
  border: var(--hair-w) dashed var(--color-border-strong);
  border-radius: 12px;
  background: var(--color-surface);
}
.pol-empty h2 {
  margin: 0 0 4px;
  font: 600 16px var(--font-sans);
}
.pol-empty p {
  margin: 0;
  color: var(--color-text-2);
  font-size: 13.5px;
}
.pol-tpls {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr));
  gap: var(--sp-10);
}
.pol-tpls form {
  display: flex;
}
.pol-tpl {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: var(--sp-14);
  border-radius: var(--r-card);
  border: var(--hair-w) solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.pol-tpl:hover {
  border-color: var(--color-accent);
}
.pol-tpl-name {
  font-weight: 600;
}
.pol-tpl-kv {
  font: 400 12.5px var(--font-mono);
}
.pol-tpl-text {
  font-size: 12.5px;
  color: var(--color-text-2);
}
.pol-tpl-use {
  margin-top: 2px;
  font: 500 13px var(--font-sans);
  color: var(--color-accent-fg);
}
/* three columns (cards, editor, preview); the history spans them */
.pol-grid {
  display: grid;
  grid-template-columns: repeat(
    auto-fit,
    minmax(min(100%, max(320px, calc((100% - 28px) / 3))), 1fr)
  );
  gap: var(--sp-14);
  align-items: start;
}
.pol-cards,
.pol-list {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-8);
}
.pol-card {
  display: flex;
  align-items: stretch;
  border-radius: var(--r-card);
  border: var(--hair-w) solid var(--color-border);
  background: var(--color-surface);
}
.pol-card.is-sel {
  border-color: var(--color-accent);
  background: var(--color-accent-bg);
}
.pol-card.is-off {
  background: var(--color-surface-2);
}
.pol-card.is-drag {
  opacity: 0.45;
}
.pol-grip {
  width: 24px;
  flex: none;
  display: grid;
  place-items: center;
  color: var(--color-text-3);
  cursor: grab;
  letter-spacing: -2px;
  font-size: 12px;
}
.pol-card-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: var(--sp-12) 4px var(--sp-12) 0;
  color: var(--color-text);
  text-decoration: none;
}
.pol-card.is-off .pol-card-main {
  color: var(--color-text-2);
}
.pol-card-head {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.pol-card-name {
  font-weight: 600;
}
.pol-card-kv {
  font: 400 12.5px var(--font-mono);
  color: var(--color-text);
}
.pol-card-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 3px var(--sp-12);
  font-size: 12px;
  color: var(--color-text-2);
}
.pol-sev {
  font-weight: 500;
  color: var(--color-neutral-fg);
}
.pol-sev.is-req {
  color: var(--color-accent-fg);
}
.pol-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.pol-chip {
  display: inline-block;
  max-width: 220px;
  height: 22px;
  padding: 0 8px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  line-height: 22px;
  border-radius: 11px;
  background: var(--color-surface-3);
  color: var(--color-text);
  font-size: 12px;
}
.pol-card-note {
  font-size: 12px;
  color: var(--color-text-2);
}
/* the rule menu: the card's full-height "⋯" column */
.pol-card > details.pol-menu {
  display: flex;
  flex: none;
}
.pol-card > details.pol-menu > summary {
  width: 40px;
  height: auto;
  border: 0;
  border-radius: 0 9px 9px 0;
  background: none;
  color: var(--color-text-2);
  font: 600 16px var(--font-sans);
}
.pol-card > details.pol-menu > summary:hover,
.pol-card > details.pol-menu[open] > summary {
  background: var(--color-surface-3);
  color: var(--color-text-2);
}
.pol-menu .menu-panel form {
  display: contents;
}
.pol-card > details.pol-menu > .rowmenu-body {
  top: calc(100% + 4px);
}
.pol-card > details.pol-menu.up > .rowmenu-body {
  top: auto;
  bottom: calc(100% + 4px);
}
/* the editor */
.pol-editor {
  gap: var(--sp-12);
}
.pol-form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-12);
}
.pol-ed-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--sp-8);
}
.pol-ed-head h2 {
  margin: 0;
  font: 600 14px var(--font-sans);
}
.pol-form label.ufield-label {
  font: 500 12.5px var(--font-sans);
  color: var(--color-text-2);
}
.pol-pv-unk > summary {
  min-height: 44px;
  padding: 12px var(--sp-16);
  font-size: 13px;
  color: var(--color-text-2);
  cursor: pointer;
}
.pol-pv-unk[open] > summary {
  border-bottom: var(--hair-w) solid var(--color-border);
}
.pol-enabled {
  font-weight: 400;
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  min-height: 36px;
  font-size: 13px;
  cursor: pointer;
}
.pol-enabled input {
  width: 16px;
  height: 16px;
  accent-color: var(--color-accent);
}
.pol-two {
  /* one column: the editor is ~360 px wide, two halves cut "Choose a setting…" and the value */
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-10);
}
.pol-form select.mono,
.pol-form input.mono,
#want-control select,
#want-control input {
  font-family: var(--font-mono);
  font-size: 13px;
}
.pol-none {
  font: 400 12.5px var(--font-sans);
  color: var(--color-text-3);
}
/* "Applies to": a select-looking fold with the family, tag and device choices */
.pol-scope > summary {
  display: flex;
  align-items: center;
  height: var(--ctl);
  padding: 0 30px 0 10px;
  border: var(--hair-w) solid var(--color-border-strong);
  border-radius: var(--r-control);
  background-color: var(--color-surface);
  background-image:
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position:
    calc(100% - 15px) 50%,
    calc(100% - 10px) 50%;
  background-size: 5px 5px;
  background-repeat: no-repeat;
  color: var(--color-text);
  font: 400 13.5px var(--font-sans);
  list-style: none;
  cursor: pointer;
}
.pol-scope > summary::-webkit-details-marker {
  display: none;
}
.pol-scope-body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-10);
  margin-top: var(--sp-8);
  padding: var(--sp-10);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-control);
}
.pol-scope-body fieldset {
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}
.pol-scope-body legend {
  padding: 0;
  margin-bottom: 4px;
  font: 500 12.5px var(--font-sans);
  color: var(--color-text-2);
}
.pol-pick {
  display: flex;
  flex-wrap: wrap;
  gap: 4px var(--sp-12);
}
.pol-pick-scroll {
  max-height: 160px;
  overflow: auto;
}
.pol-pickc {
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 28px;
  font: 400 13px var(--font-sans);
  color: var(--color-text);
}
.pol-ed-foot {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-8);
  padding-top: var(--sp-12);
  border-top: var(--hair-w) solid var(--color-border);
}
/* the live preview */
.pol-preview {
  padding: 0;
  gap: 0;
  overflow: hidden;
}
.pol-pv-head {
  padding: var(--sp-14) var(--sp-16);
}
.pol-pv-head h2 {
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  margin: 0;
  font: 600 14px var(--font-sans);
}
.pol-pv-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--color-accent);
  animation: tf-pulse 2.4s infinite;
}
.pol-pv-line {
  margin-top: 6px;
  font-size: 13px;
  color: var(--color-text-2);
}
.pol-pv-line b {
  font-weight: 600;
  color: var(--color-text);
}
.pol-pv-none {
  margin: 0;
  padding: var(--sp-24) var(--sp-16);
  border-top: var(--hair-w) solid var(--color-border);
  text-align: center;
  color: var(--color-text-2);
  font-size: 13px;
}
.pol-pv-list {
  max-height: 380px;
  overflow: auto;
  border-top: var(--hair-w) solid var(--color-border);
}
.pol-pv-row {
  display: flex;
  align-items: center;
  gap: var(--sp-10);
  min-height: 44px;
  padding: 9px var(--sp-16);
  border-bottom: var(--hair-w) solid var(--color-border);
  color: var(--color-text);
  text-decoration: none;
}
.pol-pv-row:last-child {
  border-bottom: 0;
}
.pol-pv-row:hover {
  background: var(--color-surface-2);
}
.pol-pv-rdot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  flex: none;
  background: var(--color-warn);
}
.pol-pv-row.is-hint .pol-pv-rdot,
.pol-pv-row.is-unk .pol-pv-rdot {
  background: var(--color-neutral);
}
.pol-pv-name {
  flex: 1;
  min-width: 0;
  overflow-wrap: anywhere;
  font-size: 13px;
}
.pol-pv-note {
  display: block;
  word-break: normal;
  font-size: 12px;
  color: var(--color-text-3);
}
.pol-pv-val {
  font: 400 12px var(--font-mono);
  color: var(--color-text-2);
  white-space: nowrap;
}
.pol-pv-val b {
  font-weight: 400;
  color: var(--color-text);
}
/* the version history */
.pol-hist {
  grid-column: 1 / -1;
  overflow: hidden;
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  background: var(--color-surface);
}
.pol-hist-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--sp-8);
  flex-wrap: wrap;
  padding: var(--sp-12) var(--sp-16);
  border-bottom: var(--hair-w) solid var(--color-border);
}
.pol-hist-head h2 {
  margin: 0;
  font: 600 14px var(--font-sans);
}
.pol-hist-head span {
  font-size: 12.5px;
  color: var(--color-text-2);
}
.pol-hist-body {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
}
.pol-hist-list {
  flex: 1 1 260px;
  border-right: var(--hair-w) solid var(--color-border);
}
.pol-hv {
  display: flex;
  gap: var(--sp-10);
  align-items: flex-start;
  min-height: 52px;
  padding: var(--sp-10) var(--sp-16);
  border-bottom: var(--hair-w) solid var(--color-border);
  color: var(--color-text);
  text-decoration: none;
}
.pol-hv.is-sel {
  background: var(--color-accent-bg);
  box-shadow: inset 3px 0 0 var(--color-accent);
}
.pol-hv-v {
  width: 26px;
  flex: none;
  font: 600 12.5px var(--font-mono);
}
.pol-hv-main {
  min-width: 0;
}
.pol-hv-what {
  display: flex;
  gap: 6px;
  align-items: center;
  flex-wrap: wrap;
  font-size: 13px;
}
.pol-hv-meta {
  display: block;
  font-size: 12px;
  color: var(--color-text-2);
}
.pol-hist-diff {
  flex: 2 1 360px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-10);
  padding: var(--sp-12) var(--sp-16);
}
.pol-hist-diff .pol-none {
  font-size: 13px;
  color: var(--color-text-2);
}
.pol-diff-h {
  font: 600 13px var(--font-sans);
}
.pol-diff {
  align-self: stretch;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: var(--hair-w) solid var(--color-border);
  border-radius: 8px;
}
.pol-diff-row {
  display: grid;
  grid-template-columns: 120px minmax(0, 1fr);
  gap: 4px var(--sp-12);
  padding: var(--sp-8) var(--sp-12);
  border-bottom: var(--hair-w) solid var(--color-border);
  font-size: 12.5px;
}
.pol-diff-row:last-child {
  border-bottom: 0;
}
.pol-diff-l {
  color: var(--color-text-2);
  word-break: break-word;
}
.pol-diff-v {
  font-family: var(--font-mono);
  overflow-wrap: anywhere;
}
/* import / export */
.pio-export {
  display: flex;
  flex-direction: column;
  gap: var(--sp-10);
  max-width: 860px;
  margin-top: var(--sp-16);
}
.pio-acts {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-8);
}
.pio-json {
  margin: 0;
  max-height: 520px;
  overflow: auto;
  padding: var(--sp-16);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  background: var(--color-surface);
  font: 400 12.5px / 1.55 var(--font-mono);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.pio-import {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr));
  gap: var(--sp-14);
  align-items: start;
  margin-top: var(--sp-16);
}
.pio-form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-10);
}
.pio-form textarea {
  min-height: 290px;
  font: 400 12.5px / 1.55 var(--font-mono);
}
.pio-preview {
  overflow: hidden;
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  background: var(--color-surface);
}
.pio-pv-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--sp-8);
  flex-wrap: wrap;
  padding: var(--sp-12) var(--sp-16);
  border-bottom: var(--hair-w) solid var(--color-border);
}
.pio-pv-head h2 {
  margin: 0;
  font: 600 14px var(--font-sans);
}
.pio-counts {
  display: flex;
  gap: 6px;
}
.pio-none {
  margin: 0;
  padding: var(--sp-16);
  font-size: 13px;
  color: var(--color-text-2);
}
.pio-row {
  display: flex;
  gap: var(--sp-12);
  align-items: flex-start;
  padding: var(--sp-10) var(--sp-16);
  border-bottom: var(--hair-w) solid var(--color-border);
  font-size: 13px;
}
.pio-row .bdg {
  flex: none;
  width: 56px;
  justify-content: center;
}
.pio-row-t {
  min-width: 0;
}
.pio-row-d {
  display: block;
  font: 400 12px var(--font-mono);
  color: var(--color-text-2);
  word-break: break-word;
}
.pio-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--sp-12);
  flex-wrap: wrap;
  padding: var(--sp-12) var(--sp-16);
  font-size: 12.5px;
  color: var(--color-text-2);
}
/* Make compliant as a page (no JavaScript) and the started page */
.pol-fix-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 380px), 1fr));
  gap: var(--sp-14);
}
.pol-fix-card h2 a {
  color: inherit;
}
.pol-fix-cmd {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 13px;
}
.pol-fix-note,
.pol-fix-skip {
  margin: 0;
  font-size: 12px;
  color: var(--color-text-2);
}
.pol-fix-foot {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-8);
  margin-top: var(--sp-16);
}
.pol-fix-left {
  margin: 0;
  padding-left: var(--sp-18);
  font-size: 13px;
}
@media (max-width: 44.99rem) {
  /* the status line's 32 px buttons get a 40 px touch target (e2e smallTargets) */
  .pol-line .pol-line-btn {
    position: relative;
  }
  .pol-line .pol-line-btn::after {
    content: "";
    position: absolute;
    inset: -4px 0;
  }
  .pol-two {
    grid-template-columns: minmax(0, 1fr);
  }
  .pol-hist-list {
    border-right: 0;
    border-bottom: var(--hair-w) solid var(--color-border);
  }
}

/* ==== page: user detail, one-time password, setup step 1 (design v2 N4 + N12, WP W2) ==== */
/* user detail: avatar, name with badges and the "username · method" line */
.ud-head {
  display: flex;
  align-items: center;
  gap: var(--sp-12);
  margin-bottom: var(--sp-16);
}
.ud-head .uavatar {
  width: 44px;
  height: 44px;
  font-size: 14px;
  background: var(--color-surface-3);
  color: var(--color-text-2);
}
.ud-who {
  min-width: 0;
}
.ud-who h1 {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-8);
  margin: 0;
  font: 600 22px/1.2 var(--font-sans);
  letter-spacing: -0.015em;
  overflow-wrap: anywhere;
}
.ud-who h1 .bdg {
  letter-spacing: normal;
}
.ud-sub {
  margin: 4px 0 0;
  font-size: 13px;
  color: var(--color-text-2);
  overflow-wrap: anywhere;
}
.ud-acts {
  gap: var(--sp-6);
  margin-bottom: var(--sp-8);
}
.ud-acts .btn:disabled {
  color: var(--color-text-3);
}
.ud-acts .btn.ud-danger:not(:disabled) {
  color: var(--color-danger-fg);
}
.ud-why {
  margin: 0 0 var(--sp-14);
  font-size: 12.5px;
  color: var(--color-text-2);
}
.ud-acts + .banner,
.ud-acts + .ud-grid {
  margin-top: var(--sp-6);
}
.banner.tone-neutral {
  --banner-line: var(--color-border-strong);
  --banner-bg: var(--color-surface-3);
  --banner-fg: var(--color-text-2);
}
.banner.ud-off b {
  color: var(--color-text-2);
}
.banner.ud-off .banner-text {
  flex: 1;
}
/* three cards side by side, stacked on a phone */
.ud-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-14);
  align-items: start;
}
.ud-details {
  gap: var(--sp-6);
}
.ud-details > h2 {
  margin: 0;
}
.ud-activity .ulist-head {
  padding-block: var(--sp-6);
}
.ud-details .ukv-row {
  grid-template-columns: 120px minmax(0, 1fr);
  padding: var(--sp-6) 0;
}
.ud-details details.fold {
  margin: 0;
}
.ud-details details.fold > summary {
  font-weight: 500;
  font-size: 13px;
}
.ud-edit .acct-form {
  margin: var(--sp-6) 0 var(--sp-10);
}
.ud-edit .acct-form .btn {
  align-self: flex-end;
}
.ud-none {
  margin: 0;
  padding: var(--sp-14);
  font-size: 13px;
  color: var(--color-text-2);
}
.ud-row {
  display: flex;
  align-items: center;
  gap: var(--sp-10);
  padding: var(--sp-8) var(--sp-8) var(--sp-8) var(--sp-16);
  border-top: var(--hair-w) solid var(--color-border);
}
.ulist-head + .ud-row {
  border-top: 0;
}
.ud-row-t {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.ud-row-main {
  font-size: 13px;
  font-weight: 500;
}
.ud-row-sub {
  font: 400 12px var(--font-mono);
  color: var(--color-text-2);
  overflow-wrap: anywhere;
}
.ud-end {
  margin: 0;
  flex: none;
}
.ud-act {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-6) var(--sp-12);
  padding: var(--sp-10) var(--sp-16);
  border-top: var(--hair-w) solid var(--color-border);
  font-size: 12.5px;
}
.ulist-head + .ud-act {
  border-top: 0;
}
.ud-act-when {
  font: 400 12.5px var(--font-mono);
  color: var(--color-text-2);
  white-space: nowrap;
}
.ud-act-what {
  font: 500 12.5px var(--font-mono);
}
.ud-act-sum {
  flex: 1 1 auto;
  min-width: 0;
  color: var(--color-text-2);
  overflow-wrap: anywhere;
}
@media (max-width: 44.99rem) {
  .ud-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}
/* one-time password: the value with Copy, username and expiry, the warning, Done */
.otp-card {
  max-width: 560px;
  gap: var(--sp-12);
  padding: var(--sp-18);
}
.otp-value {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-8);
}
.otp-value output {
  flex: 1 1 260px;
  min-width: 0;
  display: flex;
  align-items: center;
  min-height: 48px;
  padding: 0 var(--sp-14);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-control);
  background: var(--color-surface-2);
  font: 500 18px var(--font-mono);
  letter-spacing: 0.02em;
  overflow-wrap: anywhere;
}
.otp-value .btn {
  min-height: 48px;
  padding: 0 var(--sp-24);
}
.otp-card .ukv-row {
  border-top: 0;
  padding: var(--sp-2) 0;
}
.otp-foot {
  display: flex;
  justify-content: flex-end;
  max-width: 560px;
  margin-top: var(--sp-14);
}
/* setup step 1: the card as wide as the wizard's, the log example */
.page-auth .auth-card:has(.setup-steps) {
  width: min(480px, 100%);
}
.setup-log {
  margin: 0;
  padding: var(--sp-10) var(--sp-12);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-control);
  background: var(--color-surface-2);
  font: 400 12px/1.6 var(--font-mono);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.setup-log + .banner {
  margin: 0;
}

/* ==== page: What's new (/whats-new, N5) and the avatar's news dot (W3) ==== */
.avatar-dot {
  position: absolute;
  top: -2px;
  right: -2px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-accent);
  border: 1.5px solid var(--color-surface);
}
.um-menu .um-news {
  justify-content: space-between;
  gap: var(--sp-8);
}
.wn-list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-12);
  max-width: 820px;
}
.wn-rel {
  background: var(--color-surface);
  border: var(--hair-w) solid var(--color-border);
  border-radius: var(--r-card);
  padding: var(--sp-16) var(--sp-18) var(--sp-10);
  min-width: 0;
}
.wn-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px var(--sp-10);
  padding-bottom: var(--sp-10);
}
.wn-v {
  margin: 0;
  font: 700 16px var(--font-mono);
  letter-spacing: normal;
}
.wn-d {
  font-size: 12.5px;
  color: var(--color-text-2);
}
.wn-intro p {
  margin: 0 0 var(--sp-8);
  font-size: 13.5px;
}
.wn-sec {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-10);
  padding: var(--sp-8) 0;
  border-top: var(--hair-w) solid var(--color-border);
  font-size: 13.5px;
  line-height: 22px;
}
.wn-lbl {
  flex: none;
  width: 72px;
  padding-top: 2px;
}
.wn-lbl .bdg {
  width: 72px;
  justify-content: center;
  height: 18px;
}
.wn-sec ul {
  margin: 0;
  padding-left: var(--sp-18);
  min-width: 0;
  overflow-wrap: anywhere;
}
.wn-sec ul ul {
  padding-left: var(--sp-16);
}

/* ==== page: release (/firmware/releases/{version}, N6): notes, files aside, "Changes since" ==== */
.rel-title {
  display: flex;
  align-items: center;
  gap: var(--sp-10);
}
.page-release .pghead {
  align-items: flex-end;
}
.rel-grid {
  display: grid;
  grid-template-columns: minmax(0, 740px) minmax(0, 1fr);
  gap: var(--sp-16);
  align-items: start;
}
.rel-notes {
  padding: var(--sp-20) var(--sp-22);
  display: flex;
  flex-direction: column;
  gap: var(--sp-12);
  font-size: 14px;
  line-height: 1.6;
  min-width: 0;
  overflow-wrap: anywhere;
}
.rel-notes p,
.rel-notes ul,
.rel-notes ol,
.rel-notes blockquote {
  margin: 0;
}
.rel-notes ul,
.rel-notes ol {
  padding-left: var(--sp-20);
}
.rel-notes h4 {
  margin: var(--sp-4) 0 -6px;
  font: 600 15px var(--font-sans);
}
.rel-notes pre {
  margin: 0;
  padding: var(--sp-12) var(--sp-14);
  border-radius: var(--r-code);
  font: 400 12.5px/1.6 var(--font-mono);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.rel-breaking h4 {
  display: none;
}
.rel-aside {
  display: flex;
  flex-direction: column;
  gap: var(--sp-14);
  min-width: 0;
}
.rel-aside .ulist {
  padding: 0 var(--sp-16) var(--sp-14);
}
.rel-aside .ulist-head {
  padding: var(--sp-14) 0 var(--sp-6);
}
.rel-aside .ulist-head form {
  margin: 0;
}
.rel-aside .ulist-head .btn-link {
  min-height: 0;
  font-size: 12.5px;
}
.rel-file {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-10);
  padding: var(--sp-10) 0;
  border-top: var(--hair-w) solid var(--color-border);
}
.rel-file:first-of-type {
  border-top: 0;
}
.rel-file-t {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.rel-file-n {
  font: 500 12.5px var(--font-mono);
  overflow-wrap: anywhere;
}
.rel-file-m {
  font-size: 11.5px;
  color: var(--color-text-2);
}
.rel-orow {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-10);
  padding: var(--sp-6) 0;
  border-top: var(--hair-w) solid var(--color-border);
  font-size: 12.5px;
  color: var(--color-text-2);
}
.rel-orow .mono {
  color: var(--color-text);
  font-size: 12.5px;
}
.rel-start {
  margin-top: var(--sp-8);
}
.rel-start .btn {
  width: 100%;
  justify-content: center;
}
.rel-empty {
  margin: var(--sp-8) 0 0;
  font-size: 12.5px;
  color: var(--color-text-2);
}
.rel-since-lead {
  margin: 0 0 var(--sp-12);
  font-size: 13px;
  color: var(--color-text-2);
}
.rel-since-lead b {
  color: var(--color-text);
}
.rel-since {
  display: flex;
  flex-direction: column;
  gap: var(--sp-10);
  max-width: 900px;
}
.rel-srel {
  padding: var(--sp-14) var(--sp-16);
  gap: 0;
}
.rel-shead {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-10);
  margin-bottom: 6px;
}
.rel-sv {
  font: 700 14px var(--font-mono);
}
.rel-sd {
  font-size: 12.5px;
  color: var(--color-text-2);
}
.rel-srow {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-10);
  padding: 2px 0;
  font-size: 13px;
  line-height: 21px;
}
.rel-slbl {
  flex: none;
  width: 68px;
  padding-top: 2px;
}
.rel-slbl .bdg {
  display: block;
  width: 68px;
  height: 17px;
  line-height: 17px;
  text-align: center;
  font-size: 11px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rel-stxt {
  min-width: 0;
  overflow-wrap: anywhere;
}
.fw-rel-links a {
  color: inherit;
  white-space: nowrap;
}
@media (max-width: 44.99rem) {
  /* a 40 px touch target without moving the line, like the crumbs */
  .fw-rel-links a {
    display: inline-block;
    padding: 11px 0;
    margin: -11px 0;
  }
  .rel-grid {
    grid-template-columns: minmax(0, 1fr);
  }
  .rel-notes {
    padding: var(--sp-18) var(--sp-22);
  }
  .wn-rel {
    padding: var(--sp-14) var(--sp-18) var(--sp-8);
  }
}
