/* palpanel — foundation stylesheet (F1).

   This is the design's foundation layer only: fonts, the two-tier colour token
   system, and a base reset + element typography. Component styles (cards, pills,
   buttons, the status bar, widgets) are deliberately NOT here — each screen's
   slice (S1–S6) adds its own against these tokens. Hand-compiled from the design
   tokens in claude-design-handoff/; a build step can emit this same file later. */

/* --- fonts (mirror css_sample/fonts.scss; served from the owned di.standof.fish) */

@font-face {
  font-family: "Atkinson Hyperlegible Next";
  src: url("https://di.standof.fish/fonts/AtkinsonHyperlegibleNextVF-Variable.woff2")
    format("woff2");
  font-weight: 200 800;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("https://di.standof.fish/fonts/JetBrainsMono-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("https://di.standof.fish/fonts/JetBrainsMono-Bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("https://di.standof.fish/fonts/JetBrainsMono-Italic.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Atkinson Hyperlegible Next Fallback";
  src: url("https://di.standof.fish/fonts/AtkinsonHyperlegibleNext-Regular.ttf")
    format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Atkinson Hyperlegible Next Fallback";
  src: url("https://di.standof.fish/fonts/AtkinsonHyperlegibleNext-Bold.ttf")
    format("truetype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Atkinson Hyperlegible Next Fallback";
  src: url("https://di.standof.fish/fonts/AtkinsonHyperlegibleNext-Italic.ttf")
    format("truetype");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}

/* --- colour tokens (two-tier) ------------------------------------------------

   Raw palette (--c-*) names each colour by what it IS. The semantic layer below
   names each token by the ROLE it plays, and component CSS references ONLY the
   semantic layer — so renaming what is "accent" touches one alias, and a raw
   name can never lie about its value. */

:root {
  color-scheme: dark;

  /* raw palette: primitives, never referenced by components directly */
  --c-bg-base: #0f0f0e;
  --c-bg-bright: #1e1e1c;
  --c-bg-brighter: #373339;
  --c-line: #262523;

  --c-cream: #efe6cf;
  --c-cream-bright: #f7f3f0;
  --c-muted: #a8a29a;
  --c-faint: #797969;

  --c-purple: #7e58a0;
  --c-purple-dark: #5e3880;
  --c-purple-vibrant: #bb8ee8;
  --c-pink: #fdbbec;

  --c-teal: #60c2b7; /* live / good */
  --c-red: #f27872; /* fault */
  --c-grey: #5a545f; /* idle + offline dots (one grey) */
  --c-badge: #4a4650;

  /* amber: one source hex + lighten-only tints (the 10% fill tracks the base) */
  --c-amber: #cfa03f;
  --c-amber-light: #dcba74; /* recovery banner text / borders */
  --c-amber-hover: #d6ad5c; /* amber button hover */
  --c-amber-ink: #1a1509; /* text on an amber fill */
  --c-amber-badge-bg: #3a2e1a; /* dark amber badge bg */

  /* data series: one teal ramp (magenta dropped) */
  --c-tier-bigger: #236173; /* 16 GB, full/dark teal */
  --c-tier-regular: #9fb2ac; /* 8 GB, desaturated toward grey */

  /* sand secondary button (kept separate — NOT amber) */
  --c-sand: #dbc699;
  --c-sand-hover: #e6d4ab;

  --c-border-input: #675178;
  --c-disabled-bg: #26232a;

  /* semantic aliases: the only tokens components use */
  --bg: var(--c-bg-base);
  --surface: var(--c-bg-bright); /* cards, inputs */
  --surface-raised: var(--c-bg-brighter);
  --hairline: var(--c-line);

  --text: var(--c-cream);
  --text-emphasis: var(--c-cream-bright);
  --text-muted: var(--c-muted);
  --text-faint: var(--c-faint);

  --accent: var(--c-purple); /* primary action border */
  --accent-fill: var(--c-purple-dark); /* primary action fill */
  --accent-bright: var(--c-purple-vibrant); /* totals, # prefix, caret, mem fill */

  --link: var(--c-pink);
  --link-hover: var(--c-purple-vibrant);

  --status-live: var(--c-teal);
  --status-waking: var(--c-purple-vibrant);
  --status-fault: var(--c-red); /* fault / mem-high / banned */
  --status-warn: var(--c-amber); /* past history, not currently active */
  --status-idle: var(--c-grey); /* idle + offline */

  --draft: var(--c-amber); /* unsaved / staged / recovery */
  --draft-text: var(--c-amber-light);
  --draft-hover: var(--c-amber-hover);
  --draft-fill: color-mix(in srgb, var(--c-amber) 10%, transparent);
  --on-draft: var(--c-amber-ink);
  --draft-badge-bg: var(--c-amber-badge-bg);

  --tier-regular: var(--c-tier-regular);
  --tier-bigger: var(--c-tier-bigger);

  --btn-secondary: var(--c-sand);
  --btn-secondary-hover: var(--c-sand-hover);

  --border-input: var(--c-border-input);
  --disabled-bg: var(--c-disabled-bg);
  --disabled-text: var(--c-faint);

  --rule: color-mix(in srgb, var(--text) 22%, transparent); /* standard section left-rule */

  /* Advanced console block (raw palette + semantic aliases; JSON is untinted) */
  --c-console-bg: #161514;
  --c-console-text: #cbc6be;
  --console-bg: var(--c-console-bg);
  --console-text: var(--c-console-text);

  /* fonts */
  --font-body:
    "Atkinson Hyperlegible Next", "Atkinson Hyperlegible Next Fallback",
    system-ui, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, monospace;
}

/* --- base reset + element typography ---------------------------------------- */

* {
  box-sizing: border-box;
}

body {
  margin: 0 auto;
  padding: 2rem 1.25rem;
  max-width: 840px; /* standard app content column (Login narrows its own wrapper) */
  font: 400 18px/1.5 var(--font-body);
  color: var(--text);
  background: var(--bg);
}

h1,
h2,
h3 {
  color: var(--text);
  font-family: var(--font-body);
  font-weight: 700;
  margin: 0 0 0.6rem;
}
h1 {
  font-size: 28px;
}
h2 {
  font-size: 27px;
}
h3 {
  font-size: 20px;
}

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

/* form controls default to mono (numbers/keys/values read as mono per the design) */
input,
select,
textarea,
button {
  font-family: var(--font-mono);
}
::placeholder {
  color: var(--text-faint);
}

/* native <details> disclosure: strip the marker, rotate a .caret glyph when open.
   A shared micro-pattern used by accordions across screens, so it lives in the
   foundation rather than any one component. */
details > summary {
  list-style: none;
  cursor: pointer;
}
details > summary::-webkit-details-marker {
  display: none;
}
.caret {
  display: inline-block;
  transition: transform 0.15s ease;
}
details[open] > summary .caret {
  transform: rotate(90deg);
}

/* --- shell chrome (F2): topbar + tab nav -----------------------------------

   The shared shell every authed page renders into: wordmark + sign-out, then the
   tab nav. Page bodies stay unstyled until their slices add component CSS. */

.topbar {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
}
.wordmark {
  font: 700 19px/1 var(--font-mono);
  letter-spacing: -0.02em;
  color: var(--text-emphasis);
}
.signout {
  font: 500 16px/1 var(--font-body);
  color: var(--text-muted);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
}
.signout:hover {
  color: var(--text);
}
.topbar-user {
  display: flex;
  align-items: baseline;
  gap: 14px;
}
.user-email {
  font: 400 15px/1 var(--font-mono);
  color: var(--text-faint);
}

.tabnav {
  display: flex;
  gap: 2px;
  margin-top: 16px;
  border-bottom: 2px solid var(--surface-raised);
}
.tabnav a {
  font: 600 16px/1 var(--font-body);
  color: var(--text-muted);
  padding: 9px 14px;
  border-bottom: 2px solid transparent;
  margin-bottom: -2px;
}
.tabnav a:hover {
  color: var(--text);
}
.tabnav a.active {
  color: var(--accent-bright);
  border-bottom-color: var(--accent);
}

main {
  margin-top: 26px;
}

/* generic muted-text utility (used by stubs / empty states) */
.muted {
  color: var(--text-muted);
}

/* --- login (S1) ------------------------------------------------------------

   The login page is standalone (no shell): a centered 360px column. Its recovery
   path flips the form into an account reset entirely in CSS, via an open
   <details> — see the reset-mode block at the end. */

body.login-page {
  max-width: none;
  padding: 24px;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}
.login {
  width: 100%;
  max-width: 360px;
}
.login-head {
  text-align: center;
  margin-bottom: 30px;
}
.wordmark-lg {
  font: 700 28px/1 var(--font-mono);
  letter-spacing: -0.02em;
  color: var(--text-emphasis);
}
.login-sub {
  font: 400 16px/1 var(--font-mono);
  color: var(--text-faint);
  margin-top: 9px;
}

/* banners: error (red) and recovery (amber, shown only in reset mode) */
.serr,
.rban {
  align-items: flex-start;
  gap: 9px;
  border-radius: 6px;
  padding: 10px 12px;
  margin-bottom: 20px;
}
.serr {
  display: flex;
  background: color-mix(in srgb, var(--status-fault) 9%, transparent);
  border: 1px solid var(--status-fault);
}
.serr-mark {
  color: var(--status-fault);
  font-weight: 700;
  line-height: 1.3;
}
.serr-text {
  font: 500 16.5px/1.4 var(--font-body);
  color: var(--status-fault);
}
.rban {
  display: none; /* revealed by the reset-mode block */
  background: var(--draft-fill);
  border: 1px solid var(--draft);
}
.rban-mark {
  color: var(--draft);
  font-weight: 700;
  line-height: 1.2;
}
.rban-text {
  font: 500 16.5px/1.4 var(--font-body);
  color: var(--draft-text);
}

/* fields */
.fld-row {
  margin-bottom: 16px;
}
.fld-row:last-of-type {
  margin-bottom: 22px;
}
.lbl {
  display: block;
  font: 700 14px/1 var(--font-body);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin: 0 0 8px;
}
.fld {
  width: 100%;
  box-sizing: border-box;
  font: 400 18px/1 var(--font-mono);
  color: var(--text);
  background: var(--surface);
  border: 2px solid var(--border-input);
  border-radius: 5px;
  padding: 12px;
}
.fld:focus {
  outline: none;
  border-color: var(--accent);
}

/* primary button (full width) */
.btn {
  width: 100%;
  font: 700 19px/1 var(--font-body);
  color: var(--text-emphasis);
  background: var(--accent-fill);
  border: 2px solid var(--accent);
  border-radius: 6px;
  padding: 14px;
  cursor: pointer;
  transition: background 0.15s ease;
}
.btn:hover {
  background: var(--accent);
}

/* recovery disclosure */
.recovery {
  margin-top: 22px;
  border-top: 1px solid var(--hairline);
  padding-top: 6px;
}
.recovery > summary {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 10px 0;
  font: 600 17px/1 var(--font-body);
  color: var(--text);
}
.recovery > summary .caret {
  font: 700 21px/1 var(--font-mono);
  color: var(--accent-bright);
}
.recovery-active {
  color: var(--draft);
  font-weight: 700;
}
.recovery-body {
  padding: 2px 0 4px;
}
.rec {
  font-size: 16px;
}
.recovery-note {
  font: 400 15px/1.5 var(--font-mono);
  color: var(--text-faint);
  margin: 10px 0 0;
}

/* reset mode: an open recovery disclosure turns sign-in into an account reset,
   entirely in CSS — labels flip, the amber banner shows, the error hides, and the
   button goes amber. */
.mr {
  display: none;
}
.login:has(details[open]) .ms {
  display: none;
}
.login:has(details[open]) .mr {
  display: inline;
}
.login:has(details[open]) .serr {
  display: none;
}
.login:has(details[open]) .rban {
  display: flex;
}
.login:has(details[open]) .btn {
  background: var(--draft);
  border-color: var(--draft-text);
  color: var(--on-draft);
}
.login:has(details[open]) .btn:hover {
  background: var(--draft-hover);
}

/* --- dashboard (S2) --------------------------------------------------------

   The hero machine-state card (the one card the design allows — a live status
   readout) plus the #-headed content sections. #dashboard is the htmx-swapped
   fragment container. */

#dashboard {
  display: flex;
  flex-direction: column;
  gap: 22px;
}

/* a control action's error (e.g. a failed raise), swapped in above the card */
.action-error {
  color: var(--status-fault);
  border: 1px solid var(--status-fault);
  border-radius: 8px;
  padding: 10px 12px;
  margin: 0;
  font: 500 17px/1.4 var(--font-body);
}

.card {
  background: var(--surface);
  border: 1px solid var(--surface-raised);
  border-radius: 8px;
  padding: 16px;
}
.card-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}
.card-status {
  display: flex;
  align-items: center;
  gap: 11px;
}
.card-label {
  font: 700 26px/1 var(--font-body);
  color: var(--text-emphasis);
}
.card-size {
  text-align: right;
}
.card-size-lbl {
  font: 700 14px/1 var(--font-body);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.card-size-val {
  font: 700 22px/1 var(--font-mono);
  color: var(--accent-bright);
  margin-top: 6px;
}
.card-identity {
  font: 400 15px/1 var(--font-mono);
  color: var(--text-faint);
  margin: 10px 0 0;
}

/* Provisional control-plane-degraded note — spacing only; the real degraded
   treatment (colour/icon/placement) comes from the F4 design round-trip. */
.card-flynote {
  margin: 8px 0 0;
}

/* status dot */
.dot {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  flex: none;
  background: var(--status-idle);
}
.dot.ok {
  background: var(--status-live);
}
.dot.warn {
  background: var(--status-waking);
}
.dot.idle {
  background: var(--status-idle);
}
.dot.pulse {
  animation: pulse 1.2s ease-in-out infinite;
}
@keyframes pulse {
  50% {
    opacity: 0.32;
  }
}

/* the slot: an enlarged raise button while down, the memory row + bar once live */
.raise {
  width: 100%;
  margin-top: 16px;
  font: 700 19px/1 var(--font-body);
  color: var(--text-emphasis);
  background: var(--accent-fill);
  border: 2px solid var(--accent);
  border-radius: 6px;
  padding: 14px;
  cursor: pointer;
  transition: background 0.15s ease;
}
.raise:hover:not(:disabled) {
  background: var(--accent);
}
.raise:disabled {
  background: var(--disabled-bg);
  border-color: var(--surface-raised);
  color: var(--disabled-text);
  cursor: not-allowed;
}

.card-mem {
  margin-top: 16px;
}
.card-mem-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.card-mem-lbl {
  font: 700 14px/1 var(--font-body);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.card-mem-val {
  font: 400 17px/1 var(--font-mono);
  color: var(--accent-bright);
}
.card-mem-val.high {
  color: var(--status-fault);
}
.mem-track {
  height: 8px;
  border-radius: 4px;
  background: var(--surface-raised);
  overflow: hidden;
  margin-top: 8px;
}
.mem-fill {
  display: block;
  height: 100%;
  border-radius: 4px 0 0 4px;
  background: var(--accent-bright);
}
.mem-fill.high {
  background: var(--status-fault);
}

/* # section header + standard left-rule body (shared across content screens) */
.section-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 13px;
}
.section-head h2 {
  font: 700 27px/1.2 var(--font-body);
  color: var(--text);
  margin: 0;
}
.section-head .hash {
  color: var(--accent-bright);
}
.count-badge {
  font: 400 16px/1 var(--font-mono);
  color: var(--text-muted);
  background: var(--bg);
  border: 1px solid var(--surface-raised);
  border-radius: 999px;
  padding: 3px 9px;
}
.section-body {
  border-left: 1px solid var(--rule);
  padding-left: 15px;
}

.player-list {
  list-style: none;
  margin: 10px 0 0;
  padding: 0;
}
.player-list li {
  padding: 10px 0;
  border-bottom: 1px solid var(--hairline);
  font: 500 18px/1 var(--font-body);
  color: var(--text);
}

/* connect address — inline beside the status in the machine-card top row (shown
   only when public_addr is set). Grouped with the status via .card-headline so it
   sits on the left; fonts/colours match the existing card treatment. */
.card-headline {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
}
.card-connect {
  display: flex;
  align-items: center;
  gap: 10px;
}
.card-connect code {
  font: 700 18px/1 var(--font-mono);
  color: var(--text);
  word-break: break-all;
}
.connect-copy {
  font: 400 14px/1 var(--font-mono);
  color: var(--accent-bright);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}
.connect-copy:hover {
  color: var(--link);
}

/* --- Advanced: the read-only /api/status diagnostics screen ----------------- */

/* header line: the endpoint + a green 200, per-source freshness on the right */
.status-line {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin: 22px 0 12px;
}
.status-req {
  font: 700 17px/1 var(--font-mono);
  color: var(--text);
}
.status-req .ok {
  color: var(--status-live);
}
.status-fresh {
  font: 400 15px/1 var(--font-mono);
  color: var(--text-faint);
}

/* the console block: verbatim snapshot JSON, plain (untinted) monospace */
.status-json {
  margin: 0;
  font: 400 15.5px/1.6 var(--font-mono);
  color: var(--console-text);
  background: var(--console-bg);
  border-left: 2px solid var(--border-input);
  border-radius: 0 6px 6px 0;
  padding: 13px 14px;
  white-space: pre;
  overflow-x: auto;
}

/* copy + open-raw links under the block */
.status-actions {
  display: flex;
  gap: 14px;
  margin-top: 10px;
}
.status-actions button,
.status-actions a {
  font: 400 15px/1 var(--font-mono);
  color: var(--accent-bright);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}
.status-actions button:hover,
.status-actions a:hover {
  color: var(--link);
}

/* raw players[] table */
.raw-table {
  margin-top: 26px;
}
.raw-caption {
  font: 700 15px/1 var(--font-mono);
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 8px;
}
.raw-scroll {
  overflow-x: auto;
}
.raw-table table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--font-mono);
}
.raw-table th {
  font: 700 13px/1 var(--font-mono);
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 7px 8px;
  border-bottom: 1px solid var(--surface-raised);
}
.raw-table td {
  font: 400 15px/1.3 var(--font-mono);
  color: var(--text);
  padding: 8px;
  border-bottom: 1px solid var(--hairline);
}
.raw-table .l {
  text-align: left;
}
.raw-table .r {
  text-align: right;
}
.raw-table td.ip {
  color: var(--text-muted);
}
.raw-table td.uid {
  color: var(--text-faint);
}

.read-only-note {
  font: 400 15px/1.5 var(--font-mono);
  color: var(--text-faint);
  margin: 22px 0 0;
}

/* --- Players roster (read-only; moderation/banlist are S4b) ------------------ */
.activelist {
  margin-top: 4px;
}
.group-divider {
  font: 700 15px/1 var(--font-mono);
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin: 18px 0 6px;
}
.prow {
  border-bottom: 1px solid var(--hairline);
}
.prow > summary {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 2px;
  cursor: pointer;
  list-style: none;
}
.prow > summary::-webkit-details-marker {
  display: none;
}
.pdot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex: none;
}
.pdot.on {
  background: var(--status-live);
}
.pdot.off {
  background: var(--status-idle);
}
.pmeta {
  display: flex;
  flex-direction: column;
  gap: 3px;
  flex: 1;
  min-width: 0;
}
.pmeta .uid {
  font: 400 14px/1 var(--font-mono);
  color: var(--text-faint);
}
.pmeta .pnrow {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
}
.pmeta .pn {
  font: 600 18px/1 var(--font-body);
  color: var(--text);
}
.pmeta .pk {
  font: 400 15px/1 var(--font-mono);
  color: var(--text-muted);
}
.prow .caret {
  color: var(--text-faint);
  font-size: 16px;
  transition: transform 0.12s ease;
}
.prow[open] .caret {
  transform: rotate(90deg);
}
.pdet {
  padding: 4px 2px 14px 21px;
}
.fgrid {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 5px 14px;
  margin: 0;
}
.fgrid dt {
  font: 400 14px/1.4 var(--font-mono);
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.fgrid dd {
  font: 400 15px/1.4 var(--font-mono);
  color: var(--text);
  margin: 0;
  overflow-wrap: anywhere;
}
.fgrid .addr {
  display: block;
}

/* --- Players moderation (S4b): mode toggle, action bar, ban sheet, banlist ---- */

/* the Moderate/Done toggle in the section head */
.section-head .modbtn {
  margin-left: auto;
  font: 600 16px/1 var(--font-body);
  color: var(--accent-bright);
  border: 1px solid var(--surface-raised);
  border-radius: 6px;
  padding: 7px 12px;
  cursor: pointer;
  user-select: none;
}
.lbl-done {
  display: none;
}
#modmode:checked ~ .players .lbl-mod {
  display: none;
}
#modmode:checked ~ .players .lbl-done {
  display: inline;
}
#modmode:checked ~ .players .modbtn {
  color: var(--status-fault);
  border-color: color-mix(in srgb, var(--status-fault) 45%, transparent);
}

/* select-and-act bar, revealed only in moderation mode */
.abar {
  display: none;
  margin: 6px 0 14px;
}
#modmode:checked ~ .players .abar {
  display: block;
}
.abar-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.abar-lbl {
  font: 700 16px/1.3 var(--font-body);
  color: var(--text);
}
.abar-btns {
  display: flex;
  gap: 8px;
}

/* buttons */
.b {
  font: 600 16px/1 var(--font-body);
  border-radius: 6px;
  padding: 8px 12px;
  cursor: pointer;
  border: 1px solid transparent;
  display: inline-flex;
  align-items: center;
}
.b.ghost {
  background: none;
  border-color: var(--surface-raised);
  color: var(--text);
}
.b.ghost:hover {
  border-color: var(--text-muted);
}
.b.red {
  background: none;
  border-color: color-mix(in srgb, var(--status-fault) 45%, transparent);
  color: var(--status-fault);
}
.b.redfill {
  background: var(--status-fault);
  color: var(--bg);
  border: 0;
}
.b:disabled,
.b[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}

/* ban sheet (mocked in S4b — confirm disabled) */
.bandrop {
  display: none;
  margin-top: 12px;
  padding: 13px 14px;
  background: var(--surface);
  border: 1px solid var(--surface-raised);
  border-radius: 8px;
}
#bansheet:checked ~ .players .bandrop {
  display: block;
}
.bandrop .sl {
  font: 700 14px/1 var(--font-mono);
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin: 10px 0 6px;
}
.bandrop .sl:first-child {
  margin-top: 0;
}
.reason {
  width: 100%;
  font: 400 17px/1.3 var(--font-body);
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--surface-raised);
  border-radius: 6px;
  padding: 8px 10px;
}
.chips {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.chip {
  font: 600 15px/1 var(--font-body);
  color: var(--text-muted);
  background: var(--bg);
  border: 1px solid var(--surface-raised);
  border-radius: 6px;
  padding: 7px 11px;
  cursor: pointer;
}
.chip:has(input:checked) {
  color: var(--text);
  border-color: var(--accent);
}
.chip input {
  display: none;
}
.bandrop-foot {
  display: flex;
  gap: 8px;
  margin-top: 16px;
}
.bandrop-foot > * {
  flex: 1;
  justify-content: center;
}
.mod-hint {
  font: 400 15px/1.3 var(--font-mono);
  color: var(--text-faint);
  margin: 10px 0 0;
}

/* search (placeholder, disabled until the active-search enrichment) */
.search {
  width: 100%;
  margin: 4px 0 12px;
  font: 400 17px/1.3 var(--font-body);
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--surface-raised);
  border-radius: 8px;
  padding: 9px 12px;
}
.search:disabled {
  opacity: 0.6;
}

/* row checkboxes appear only in moderation mode; the row carries the hairline */
.row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  border-bottom: 1px solid var(--hairline);
}
.row .prow {
  flex: 1;
  min-width: 0;
  border-bottom: 0;
}
.rowcheck {
  display: none;
  margin-top: 15px;
  flex: none;
}
#modmode:checked ~ .players .rowcheck {
  display: block;
}

/* moderation notice + the per-row ban-history line */
.mod-notice {
  font: 600 16px/1.3 var(--font-body);
  color: var(--status-live);
  margin: 0 0 10px;
}
.banhist {
  margin-top: 12px;
}
.banhist .sl {
  display: block;
  font: 700 14px/1 var(--font-mono);
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 5px;
}

/* banlist section (S4c): active bans, each with an Unban control */
.banlist {
  margin-top: 30px;
}
.banlist-head {
  margin-bottom: 10px;
}
.hash.hash-danger {
  color: var(--status-fault);
}
.banrows {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}
.banrow {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 2px;
  border-bottom: 1px solid var(--hairline);
}
.banrow:last-child {
  border-bottom: none;
}
.ban-lines {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1;
  min-width: 0;
}
.ban-line1 {
  display: flex;
  align-items: baseline;
  gap: 10px;
}
.ban-line2 {
  display: flex;
  align-items: baseline;
  gap: 8px;
}
.banrow .bn {
  font: 600 17px/1.2 var(--font-body);
  color: var(--text);
}
.banrow .buid,
.banrow .bwhen,
.banrow .bdur {
  font: 400 15px/1 var(--font-mono);
  color: var(--text-faint);
}
/* A row PalServer has not been told about yet — a ban that has not landed or a lift
   that has not. Warn rather than danger: nothing is wrong, the decision is simply
   still travelling. The note above the list says why, so the badge stays a word. */
.banrow .bpending {
  font: 600 13px/1 var(--font-body);
  color: var(--status-warn);
  border: 1px solid var(--status-warn);
  border-radius: 4px;
  padding: 2px 6px;
}
.ban-pending-note {
  font: 400 15px/1.4 var(--font-body);
  color: var(--text-muted);
  margin: 0 0 10px;
  max-width: 70ch;
}
.banrow .brs {
  font: 400 16px/1.3 var(--font-body);
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
  min-width: 0;
}
.banrow .bby {
  font: 400 15px/1 var(--font-mono);
  color: var(--text-faint);
  white-space: nowrap;
  flex: none;
}
.banrow .bunban {
  flex: none;
}

/* roster-row status pills: currently banned, or has past ban history */
.pill {
  font: 700 13px/1 var(--font-mono);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 4px 6px 2px;
  border-radius: 4px;
  white-space: nowrap;
}
.pill.banned {
  color: var(--status-fault);
  border: 1px solid color-mix(in srgb, var(--status-fault) 45%, transparent);
}
.pill.warn {
  color: var(--status-warn);
  border: 1px solid color-mix(in srgb, var(--status-warn) 45%, transparent);
}

/* --- Housekeeping (S5a): reused status card + Save control --- */
.housekeeping {
  display: flex;
  flex-direction: column;
  gap: 28px;
}
/* start/raise error banner, shown inside the machine card */
.card-error {
  margin-bottom: 12px;
}
/* Machine controls: one row per control — button (plus its live status) on the
   left, description on the right, thin hairline dividers between rows. */
.ctl-list {
  display: flex;
  flex-direction: column;
}
.ctl-item {
  display: grid;
  grid-template-columns: 172px 1fr;
  column-gap: 22px;
  align-items: start;
  padding: 15px 0;
}
.ctl-item:first-child {
  padding-top: 0;
}
.ctl-item + .ctl-item {
  border-top: 1px solid var(--hairline);
}
.ctl-action {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 7px;
}
@media (max-width: 520px) {
  .ctl-item {
    grid-template-columns: 1fr;
    row-gap: 8px;
  }
}
.b.primary {
  background: var(--accent-fill);
  border-color: var(--accent);
  color: var(--text-emphasis);
  font-weight: 700;
  padding: 10px 16px;
}
.b.primary:hover:not(:disabled) {
  background: var(--accent);
}
.save-result {
  font: 500 16px/1.3 var(--font-mono);
}
.save-ok {
  color: var(--status-live);
}
.save-err {
  color: var(--status-fault);
}
.ctl-note {
  font: 400 15.5px/1.4 var(--font-body);
  margin: 0;
}

/* Read-only game-config view (S5d-2): categories, each a wrapping grid of
   label/value pairs. Most-relevant fields are emphasised; locked keys never render. */
.hk-config .cfg-intro {
  font: 400 16px/1.5 var(--font-body);
  margin: 0 0 4px;
  max-width: 70ch;
}
/* config deploy-status line (S5d): latched pending/live/failed, polled */
.cfg-status:empty {
  display: none;
}
.cfg-status {
  margin: 2px 0 14px;
  font: 500 14px/1.4 var(--font-body);
}
.cfg-status-pending {
  color: var(--text-muted);
}
.cfg-status-live {
  color: var(--status-live);
}
.cfg-status-failed {
  color: var(--status-warn);
}
.cfg-defaults {
  margin-left: auto;
  font: 500 13px/1 var(--font-body);
  color: var(--text-muted);
  background: none;
  border: 1px solid var(--hairline);
  border-radius: 6px;
  padding: 6px 12px;
  cursor: pointer;
  white-space: nowrap;
}
.cfg-defaults:hover {
  color: var(--text);
  border-color: var(--border-input);
}
.cfg-cat {
  margin-top: 22px;
}
.cfg-cat-name {
  font: 600 17px/1.2 var(--font-body);
  color: var(--accent-bright);
  margin: 0 0 4px;
}
.cfg-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
  column-gap: 30px;
}
/* full-width categories: one column, and text inputs get the extra room */
.cfg-grid--full {
  grid-template-columns: 1fr;
}
.cfg-grid--full .cfg-input {
  flex: 1 1 auto;
  justify-content: flex-end;
}
.cfg-grid--full .cfg-input input[type="text"] {
  flex: 1 1 auto;
  max-width: 620px;
}
.cfg-field {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 14px;
  padding: 7px 0;
  border-bottom: 1px solid var(--hairline);
}
/* overridden fields carry a teal "changed" cue: a left tick + emphasised label
   (--status-live is the panel's teal; the amber draft cue stays on the bar) */
.cfg-field.overridden {
  box-shadow: inset 2px 0 0 var(--status-live);
  padding-left: 8px;
}
.cfg-label {
  font: 400 16.5px/1.35 var(--font-body);
  color: var(--text-muted);
}
.cfg-field.rel .cfg-label {
  color: var(--text);
  font-weight: 600;
}
.cfg-field.overridden .cfg-label {
  color: var(--status-live);
}
.cfg-input {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
}
.cfg-input input[type="number"],
.cfg-input input[type="text"],
.cfg-input select {
  font: 500 15px/1.2 var(--font-mono);
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border-input);
  border-radius: 5px;
  padding: 4px 8px;
  max-width: 170px;
}
/* numbers read as compact, right-aligned entries — visually distinct from text */
.cfg-input input[type="number"] {
  width: 88px;
  text-align: right;
}
.cfg-step {
  display: flex;
  align-items: center;
  gap: 2px;
  background: var(--surface);
  border: 1px solid var(--border-input);
  border-radius: 5px;
  padding-right: 4px;
}
.cfg-step:has(input:focus) {
  border-color: var(--accent-bright);
}
.cfg-input .cfg-step input[type="number"] {
  appearance: textfield;
  -moz-appearance: textfield;
  width: 66px;
  border: none;
  background: none;
  padding-right: 4px;
}
.cfg-input .cfg-step input[type="number"]::-webkit-inner-spin-button,
.cfg-input .cfg-step input[type="number"]::-webkit-outer-spin-button {
  appearance: none;
  margin: 0;
}
.cfg-step-btn {
  font: 400 10px/1 var(--font-body);
  color: var(--text-faint);
  background: none;
  border: none;
  border-radius: 3px;
  padding: 4px;
  cursor: pointer;
}
.cfg-step-btn:hover {
  color: var(--text);
  background: var(--surface-raised);
}
.cfg-input input:focus,
.cfg-input select:focus {
  outline: none;
  border-color: var(--accent-bright);
}
.cfg-input input[type="checkbox"] {
  width: 18px;
  height: 18px;
  accent-color: var(--accent);
  cursor: pointer;
}
.cfg-multi {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  justify-content: flex-end;
}
.cfg-check {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font: 400 14px/1.2 var(--font-body);
  color: var(--text-muted);
}
.cfg-check input {
  width: 15px;
  height: 15px;
  accent-color: var(--accent);
}
/* per-field revert: reads "changed" (teal) at rest, morphs to "reset" (amber) on
   hover — the hover reveals the action, so no separate hover-colour rule is needed */
.cfg-reset {
  font: 500 12px/1 var(--font-body);
  background: none;
  border: none;
  cursor: pointer;
  padding: 2px 4px;
}
.cfg-reset-idle {
  color: var(--status-live);
}
.cfg-reset-act {
  display: none;
  color: var(--draft-text);
}
.cfg-reset:hover .cfg-reset-idle {
  display: none;
}
.cfg-reset:hover .cfg-reset-act {
  display: inline;
}
.cfg-err {
  flex-basis: 100%;
  text-align: right;
  font: 400 13px/1.3 var(--font-body);
  color: var(--status-fault);
}

/* Sticky staged-draft bar (S5d-3b): floats at the viewport bottom while the config is
   in view, in the amber "draft" cue. Present but hidden at zero overrides. */
.cfg-draftbar {
  position: sticky;
  bottom: 14px;
  display: none;
  margin-top: 20px;
}
.cfg-draftbar.active {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 12px 18px;
  border: 1px solid var(--status-live);
  border-radius: 8px;
  background: var(--surface);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.45);
}
.draftbar-msg {
  font: 400 15px/1.3 var(--font-body);
  color: var(--status-live);
}
.draftbar-msg strong {
  font-weight: 700;
}
.draftbar-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}
.draftbar-save {
  font: 700 14px/1 var(--font-body);
  color: var(--text-emphasis);
  background: var(--accent-fill);
  border: 1px solid var(--accent);
  border-radius: 6px;
  padding: 8px 16px;
  cursor: pointer;
  white-space: nowrap;
}
.draftbar-save:hover {
  background: var(--accent);
}
.draftbar-saved {
  font: 700 14px/1 var(--font-body);
  color: var(--status-live);
  white-space: nowrap;
}
.draftbar-discard {
  font: 600 14px/1 var(--font-body);
  color: var(--bg);
  background: var(--btn-secondary);
  border: 1px solid var(--btn-secondary);
  border-radius: 6px;
  padding: 8px 14px;
  cursor: pointer;
  white-space: nowrap;
}
.draftbar-discard:hover {
  background: var(--btn-secondary-hover);
  border-color: var(--btn-secondary-hover);
}
