/* Design tokens.
 *
 * Everything colour-related in Cartheca resolves through these. Stylesheets should
 * never contain a raw hex value: if a new colour is needed, it belongs here as a token
 * so both themes stay in step.
 *
 * Theme selection, in order of precedence:
 *   1. data-theme="light" or "dark" on <html>, set server-side from the theme cookie
 *   2. the operating system's prefers-color-scheme
 *   3. light
 *
 * The server injects the attribute while serving the page, so the correct theme is in
 * place before first paint. That avoids the usual flash and needs no inline script,
 * which matters because the Content-Security-Policy only allows scripts from 'self'.
 */

:root {
  color-scheme: light;

  /* Parchment surfaces, lightest to most recessed */
  --paper: #eee6d7;
  --surface: #f8f3e9;
  --surface-raised: #fffaf0;
  --surface-sunken: #e2d6c1;
  --surface-muted: #e9dfcd;
  --topbar-bg: rgba(248, 243, 233, .94);

  /* Ink */
  --ink: #292724;
  --muted: #6c655b;
  --faint: #887f72;
  --on-accent: #fffaf0;

  /* Rules and edges */
  --line: #d2c4ad;
  --line-strong: #b8a98f;

  /* Forest emerald is the fixed brand accent; --deck-accent overrides it per deck. */
  --accent: #174a35;
  --accent-strong: #103827;
  --accent-soft: #d2ddd5;

  --danger: #8b332c;
  --danger-soft: #f5e5e2;
  --positive: #174a35;
  --warning: #89502f;
  --warning-soft: #ead4c3;

  /* Deliberately dark panels that carry light text in either theme — the sign-in
   * splash, feature cards, the landing illustration. */
  --inverse: #292724;
  --inverse-2: #1e201f;
  --on-inverse: #eee6d7;
  --on-inverse-muted: #a1978a;
  --on-inverse-accent: #d18457;

  /* Earth pigments for the five colours, plus colourless and multicolour gold.
   * Deliberately desaturated: these are manuscript pigments, not spot inks. */
  --mana-w: #96844f;
  --mana-u: #42627d;
  --mana-b: #4c4150;
  --mana-r: #8c3a2a;
  --mana-g: #174a35;
  --mana-c: #7c7166;
  --mana-gold: #a6552d;

  /* Semantic aliases used by archival presentation surfaces. */
  --copper: var(--mana-gold);
  --inverse-line: var(--line-strong);

  /* Set per deck at runtime; gold is the multicolour convention and a safe default. */
  --deck-accent: var(--mana-gold);

  --shadow: 0 18px 44px rgba(41, 39, 36, .12);
  --shadow-soft: 0 3px 10px rgba(41, 39, 36, .08);
  /* Bare colours, for rules that compose their own shadow or overlay. */
  --shadow-tint: rgba(41, 39, 36, .18);
  --backdrop: rgba(24, 26, 25, .66);
}

/* Soft charcoal, aged leather, and low candlelight. Dark surfaces stay close enough
 * together to avoid glare, while the pigments remain legible without feeling neon. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --paper: #1e201f;
    --surface: #282b29;
    --surface-raised: #313432;
    --surface-sunken: #181a19;
    --surface-muted: #232624;
    --topbar-bg: rgba(40, 43, 41, .94);

    --ink: #eee5d4;
    --muted: #b8ad9c;
    --faint: #968b7d;
    --on-accent: #fffaf0;

    --line: #464843;
    --line-strong: #5b5d56;

    --accent: #2f6b4f;
    --accent-strong: #79b395;
    --accent-soft: #25362f;

    --danger: #ce8272;
    --danger-soft: #382522;
    --positive: #79b395;
    --warning: #d18457;
    --warning-soft: #493428;
    --inverse: #202321;
    --inverse-2: #181a19;
    --on-inverse: #eee5d4;
    --on-inverse-muted: #a1978a;
    --on-inverse-accent: #d18457;

    --mana-w: #c5b795;
    --mana-u: #7892a8;
    --mana-b: #95869d;
    --mana-r: #c07961;
    --mana-g: #79b395;
    --mana-c: #9c9387;
    --mana-gold: #d18457;

    --shadow: 0 18px 44px rgba(0, 0, 0, .3);
    --shadow-soft: 0 3px 10px rgba(0, 0, 0, .22);
    --shadow-tint: rgba(0, 0, 0, .34);
    --backdrop: rgba(0, 0, 0, .62);
  }
}

/* Explicit choice from the preferences page. Duplicated rather than shared with the
 * media query above because a preference has to win over the system setting. */
:root[data-theme="dark"] {
  color-scheme: dark;

  --paper: #1e201f;
  --surface: #282b29;
  --surface-raised: #313432;
  --surface-sunken: #181a19;
  --surface-muted: #232624;
  --topbar-bg: rgba(40, 43, 41, .94);

  --ink: #eee5d4;
  --muted: #b8ad9c;
  --faint: #968b7d;
  --on-accent: #fffaf0;

  --line: #464843;
  --line-strong: #5b5d56;

  --accent: #2f6b4f;
  --accent-strong: #79b395;
  --accent-soft: #25362f;

  --danger: #ce8272;
  --danger-soft: #382522;
  --positive: #79b395;
  --warning: #d18457;
  --warning-soft: #493428;
  --inverse: #202321;
  --inverse-2: #181a19;
  --on-inverse: #eee5d4;
  --on-inverse-muted: #a1978a;
  --on-inverse-accent: #d18457;

  --mana-w: #c5b795;
  --mana-u: #7892a8;
  --mana-b: #95869d;
  --mana-r: #c07961;
  --mana-g: #79b395;
  --mana-c: #9c9387;
  --mana-gold: #d18457;

  --shadow: 0 18px 44px rgba(0, 0, 0, .3);
  --shadow-soft: 0 3px 10px rgba(0, 0, 0, .22);
  --shadow-tint: rgba(0, 0, 0, .34);
  --backdrop: rgba(0, 0, 0, .62);
}

/* Names kept from the previous palette so existing rules keep working while the
 * stylesheets are migrated. New code should use the semantic tokens above. */
:root {
  --green: var(--accent);
  --green2: var(--accent-strong);
  --gold: var(--mana-gold);

  /* Fixed on purpose, and the only colours here that do not flip with the theme: the
   * preference swatches have to show what each theme looks like while you are sitting
   * in the other one. */
  --preview-light-paper: #eee6d7;
  --preview-light-accent: #174a35;
  --preview-dark-paper: #1e201f;
  --preview-dark-accent: #2f6b4f;
}

/* A deck's colour identity sets --deck-accent on a container; anything inside it that
 * uses the accent follows along. */
[data-identity="W"] { --deck-accent: var(--mana-w); }
[data-identity="U"] { --deck-accent: var(--mana-u); }
[data-identity="B"] { --deck-accent: var(--mana-b); }
[data-identity="R"] { --deck-accent: var(--mana-r); }
[data-identity="G"] { --deck-accent: var(--mana-g); }
[data-identity="C"] { --deck-accent: var(--mana-c); }
[data-identity="M"] { --deck-accent: var(--mana-gold); }

/* These selectors intentionally outrank the legacy header declarations bundled after
 * this token sheet. The translucent surface now follows the selected theme, and the
 * wordmark always resolves to the primary text colour. */
body .topbar { background: var(--topbar-bg); }
.topbar .brand { color: var(--ink); }

/* The assistant review is a modal dialog: it has to be answered, and it is raised by a
   proposal arriving rather than by the reader going to look for it. Width is generous
   because a change summary is a sentence, not a label. */
#assistant-proposals { width: min(720px, calc(100vw - 32px)); max-height: min(80vh, 780px); padding: 0; border: 1px solid var(--line); background: var(--surface); color: inherit; }
#assistant-proposals > form { max-height: inherit; padding: clamp(20px, 2.4vw, 34px); }
#assistant-proposals::backdrop { background: color-mix(in srgb, var(--ink) 55%, transparent); }
#proposal-list { min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
.review-lead { margin: 6px 0 0; color: var(--muted); }
.review-note { margin: 16px 0 0; color: var(--muted); font-size: 11px; line-height: 1.5; }
.review-open { border-color: var(--deck-accent); color: var(--deck-accent); }
.proposal-card { padding: 20px 0; border-top: 1px solid var(--line); }
.proposal-card:first-child { border-top: 0; }
.proposal-card h3 { margin: 0; font: 22px Georgia, serif; }
.proposal-card > p { color: var(--muted); }
/* A deletion cannot be undone, so it reads as a warning rather than a routine edit. */
.proposal-card-destructive h3 { color: var(--danger); }
.proposal-card-destructive .proposal-changes label { background: color-mix(in srgb, var(--danger) 12%, var(--surface-muted)); border-left: 3px solid var(--danger); }
.proposal-changes { display: grid; gap: 8px; margin-top: 16px; }
.proposal-changes label { display: flex; align-items: flex-start; gap: 10px; margin: 0; padding: 10px 12px; background: var(--surface-muted); font-size: 13px; text-transform: none; letter-spacing: 0; }
.proposal-changes input { width: auto; margin: 2px 0 0; }

/* Shared progress, empty, and failure presentation.
 *
 * One visual family for the three resting states a panel can be in. They share a sigil,
 * a serif heading, and a muted line of explanation, so moving between Decks, Cards,
 * Collection, and Community no longer means learning a new vocabulary of blank space.
 *
 * The three are deliberately distinguishable at a glance: the loading sigil breathes in
 * copper, the empty sigil sits still in copper, and the failure sigil is outlined in
 * --danger. Before this, a failed load was written into the empty-state slot, so "you
 * have no decks" and "we could not reach the server" looked the same.
 */

.state-panel {
  display: grid;
  min-height: 300px;
  place-content: center;
  justify-items: center;
  padding: 35px;
  text-align: center;
  color: var(--muted);
}
.state-panel h3 { margin: 20px 0 8px; color: var(--ink); font: 27px Georgia, serif; }
.state-panel p { max-width: 460px; margin: 0; line-height: 1.7; }
.state-panel button { margin-top: 22px; }

.state-sigil {
  display: grid;
  width: 58px;
  height: 58px;
  place-items: center;
  border: 1px solid var(--copper);
  border-radius: 50%;
  color: var(--copper);
  font: italic 27px Georgia, serif;
}
.state-panel-loading .state-sigil { animation: state-pulse 1.4s ease-in-out infinite; }
.state-panel-failure .state-sigil { border-color: var(--danger); color: var(--danger); font-style: normal; }

@keyframes state-pulse { 50% { transform: scale(1.08); opacity: .55; } }
@media (prefers-reduced-motion: reduce) {
  .state-panel-loading .state-sigil { animation: none; }
}

/* Inside a dialog, a sidebar, or a dropdown there is no room for the full panel. */
.state-panel-inline { min-height: 0; padding: 18px 12px; }
.state-panel-inline .state-sigil { width: 34px; height: 34px; font-size: 17px; }
.state-panel-inline h3 { margin: 12px 0 4px; font-size: 17px; }
.state-panel-inline p { font-size: 13px; }
.state-panel-inline button { margin-top: 12px; }

/* A region being rewritten: visibly inert, so a stale value is not mistaken for current.
 * Generalised from the one place that had grown this behaviour by hand. */
[aria-busy="true"].is-busy { opacity: .55; pointer-events: none; }

/* Background synchronisation is behind. One persistent line, not a toast per failed poll. */
.live-updates-notice {
  position: fixed;
  left: 24px;
  bottom: 24px;
  z-index: 40;
  padding: 11px 16px;
  border: 1px solid var(--warning);
  background: var(--warning-soft);
  color: var(--ink);
  box-shadow: var(--shadow-soft);
  font: 600 12px system-ui;
}

/* Status surfaces that are reporting a failure rather than a state. */
.playtest-status-failed { border-left: 3px solid var(--danger); color: var(--danger); }
.stream-loading.stream-failed { color: var(--danger); font-size: 22px; text-align: center; padding: 0 24px; }

/* Supporting data that failed while the rest of the page works. Named and retryable,
 * rather than the four silent `.catch(() => {})` calls this replaces. */
.supporting-failures { display: grid; gap: 8px; margin: 16px 4vw 0; }
.supporting-failure {
  display: flex;
  gap: 14px;
  align-items: center;
  justify-content: space-between;
  padding: 11px 14px;
  border-left: 3px solid var(--warning);
  background: var(--warning-soft);
  color: var(--ink);
  font-size: 13px;
}
.supporting-failure button { flex: 0 0 auto; padding: 7px 12px; font-size: 12px; }

/* The toast, promoted out of styles.css so both outcomes are distinguishable everywhere
 * rather than only in the playtester. The previous global rule painted white text on
 * var(--ink), which in dark mode is cream on cream. */
#toast {
  border: 1px solid var(--line-strong);
  background: var(--inverse-2);
  color: var(--on-inverse);
  box-shadow: var(--shadow);
  max-width: min(420px, calc(100vw - 48px));
  line-height: 1.5;
}
#toast.error { border-left: 3px solid var(--danger); }
#toast.success { border-left: 3px solid var(--on-inverse-accent); }

@media (max-width: 800px) {
  .state-panel { min-height: 220px; padding: 24px 14px; }
  .state-panel h3 { font-size: 22px; }
  .live-updates-notice { left: 12px; right: 12px; bottom: 12px; text-align: center; }
}

/* Admin portal presentation.
 *
 * Served as /admin.css, concatenated after the product's theme.css and feedback.css so the
 * tokens and the shared loading/empty/failure panels are already defined. No raw hex here
 * either: every colour resolves through a theme token, so the portal follows the same
 * light and dark palettes as the product.
 *
 * Deliberately plainer than the deck builder. This is a tool for one person doing careful,
 * occasionally irreversible-feeling work, so it favours density and legibility over
 * atmosphere, and it never uses colour alone to mark a state — a locked account gets a
 * border, a label, and a tint.
 */

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, sans-serif;
}

.admin-bar {
  display: flex;
  gap: 24px;
  align-items: center;
  min-height: 62px;
  padding: 0 max(3vw, 18px);
  border-bottom: 1px solid var(--line);
  background: var(--surface);
  position: sticky;
  top: 0;
  z-index: 10;
}
.admin-brand { display: flex; gap: 10px; align-items: center; font: 18px Georgia, serif; }
.admin-brand small { color: var(--danger); font: 700 9px system-ui; letter-spacing: .18em; text-transform: uppercase; }
/* The mark is a hexagon with its own copper edge, so it needs sizing and nothing else. A
   circular border fought that outline, and the red ring it drew was left over from when
   this was a letter — the "Admin" label beside it carries that warning now.
   28px rather than the product's 39px: the admin bar is shallower than the topbar. */
.admin-sigil { display: block; width: 28px; height: 28px; flex: 0 0 28px; object-fit: contain; }

.admin-nav { display: flex; gap: 4px; }
.admin-tab {
  padding: 9px 14px;
  border: 0;
  background: none;
  color: var(--muted);
  font: 600 12px system-ui;
  cursor: pointer;
}
.admin-tab.active { border-radius: 99px; background: var(--accent-soft); color: var(--accent-strong); }

.admin-identity { display: flex; gap: 12px; align-items: center; margin-left: auto; color: var(--muted); font-size: 12px; }

main { max-width: 1200px; margin: auto; padding: 28px max(3vw, 18px) 70px; }

h1 { margin: 0; font: 34px Georgia, serif; }
.admin-view-head { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; }
.admin-view-head h1 { margin-right: auto; }
.admin-count { margin: 6px 0 18px; color: var(--muted); font-size: 12px; }

.admin-search, .admin-filter select {
  min-width: 240px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  background: var(--surface-raised);
  color: var(--ink);
  font: inherit;
}
.admin-search:focus, .admin-filter select:focus { border-color: var(--accent-strong); outline: none; }
.admin-filter { display: flex; gap: 8px; align-items: center; color: var(--muted); font-size: 12px; }
.admin-filter select { min-width: 180px; }

.admin-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin-top: 22px; }
.admin-stat { padding: 18px; border: 1px solid var(--line); background: var(--surface); }
.admin-stat strong { display: block; font: 30px Georgia, serif; }
.admin-stat span { color: var(--muted); font-size: 10px; letter-spacing: .14em; text-transform: uppercase; }

.admin-list { display: grid; gap: 8px; }
.admin-row {
  display: flex;
  gap: 18px;
  align-items: flex-start;
  justify-content: space-between;
  padding: 15px 17px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--line);
  background: var(--surface);
}
.admin-row-main { display: grid; gap: 4px; min-width: 0; }
.admin-row-main strong { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; font: 16px Georgia, serif; }
.admin-row-main small { color: var(--muted); font-size: 12px; }
.admin-row-actions { display: flex; flex: 0 0 auto; gap: 8px; }

/* State is never carried by colour alone: a tinted left border, plus a text badge. */
.admin-row-locked, .admin-row-hidden { border-left-color: var(--danger); background: var(--danger-soft); }
.admin-row-reason { color: var(--danger) !important; }

.admin-badge {
  padding: 3px 8px;
  border: 1px solid var(--line-strong);
  border-radius: 99px;
  color: var(--muted);
  font: 600 9px system-ui;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.admin-badge-staff { border-color: var(--accent-strong); color: var(--accent-strong); }
.admin-badge-locked { border-color: var(--danger); color: var(--danger); }

.admin-row-tags { display: flex; flex-wrap: wrap; gap: 6px; }
.admin-row-tags span { padding: 2px 7px; background: var(--surface-muted); border-radius: 3px; font-size: 11px; }
.admin-row-primer {
  max-width: 70ch;
  margin: 6px 0 0;
  padding: 9px 11px;
  border-left: 2px solid var(--line);
  background: var(--surface-muted);
  color: var(--muted);
  font-size: 12px;
  line-height: 1.6;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.admin-audit-row {
  display: flex;
  gap: 18px;
  justify-content: space-between;
  padding: 12px 15px;
  border: 1px solid var(--line);
  background: var(--surface);
}
.admin-audit-row strong { display: block; font: 600 13px ui-monospace, SFMono-Regular, Menlo, monospace; }
.admin-audit-row small { display: block; color: var(--muted); font-size: 11px; }
.admin-audit-meta { flex: 0 0 auto; text-align: right; }

button.primary, button.ghost {
  border: 0;
  font: 600 12px system-ui;
  cursor: pointer;
}
button.primary { padding: 11px 17px; background: var(--accent); color: var(--on-accent); }
button.ghost { padding: 8px 13px; border: 1px solid var(--line-strong); background: transparent; color: var(--ink); }
button.ghost:hover { border-color: var(--accent-strong); }
button.ghost.danger, button.primary.danger { border-color: var(--danger); color: var(--danger); }
button.primary.danger { background: var(--danger); color: var(--on-accent); }
button[disabled] { opacity: .55; cursor: default; }

/* Sign-in */
.admin-signin { display: grid; place-items: center; min-height: 68vh; }
.admin-signin-card {
  display: grid;
  gap: 4px;
  width: min(420px, 100%);
  padding: 34px;
  border: 1px solid var(--line);
  border-top: 4px solid var(--danger);
  background: var(--surface);
  box-shadow: var(--shadow);
}
.admin-signin-card .eyebrow { margin: 0; color: var(--danger); font: 700 10px system-ui; letter-spacing: .2em; text-transform: uppercase; }
.admin-signin-card h1 { margin: 6px 0 0; }
.admin-signin-note { margin: 10px 0 18px; color: var(--muted); font-size: 12px; line-height: 1.6; }
.admin-signin-card label { display: block; margin: 12px 0 0; color: var(--muted); font-size: 11px; letter-spacing: .1em; text-transform: uppercase; }
.admin-signin-card input {
  width: 100%;
  margin-top: 6px;
  padding: 11px 12px;
  border: 1px solid var(--line);
  background: var(--surface-raised);
  color: var(--ink);
  font: inherit;
  letter-spacing: 0;
  text-transform: none;
}
.admin-signin-card button { margin-top: 22px; }
.admin-error {
  margin: 16px 0 0;
  padding: 11px 13px;
  border-left: 3px solid var(--danger);
  background: var(--danger-soft);
  color: var(--ink);
  font-size: 13px;
}

/* Reason dialog */
dialog { width: min(520px, 92vw); padding: 0; border: 1px solid var(--line); background: var(--surface); box-shadow: var(--shadow); }
dialog::backdrop { background: var(--backdrop); }
dialog form { padding: 28px; }
dialog h2 { margin: 0 0 12px; font: 26px Georgia, serif; }
.admin-reason-body { margin: 0 0 20px; color: var(--muted); font-size: 13px; line-height: 1.65; }
dialog label { display: block; color: var(--muted); font-size: 11px; letter-spacing: .1em; text-transform: uppercase; }
dialog label small { display: block; margin-top: 4px; font-size: 11px; letter-spacing: 0; text-transform: none; opacity: .85; }
dialog input {
  width: 100%;
  margin-top: 8px;
  padding: 11px 12px;
  border: 1px solid var(--line);
  background: var(--surface-raised);
  color: var(--ink);
  font: inherit;
}
.dialog-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 24px; }

.hidden { display: none !important; }

@media (max-width: 760px) {
  .admin-bar { flex-wrap: wrap; padding: 10px 16px; }
  .admin-identity { margin-left: 0; }
  .admin-row { flex-direction: column; }
  .admin-row-actions { width: 100%; }
  .admin-search, .admin-filter select { min-width: 0; width: 100%; }
}

/* Activity report */
.admin-report-form {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  align-items: flex-end;
  margin: 22px 0 0;
  padding: 20px;
  border: 1px solid var(--line);
  background: var(--surface);
}
.admin-report-form label { display: grid; gap: 6px; color: var(--muted); font-size: 11px; letter-spacing: .1em; text-transform: uppercase; }
.admin-report-form input[type="date"] {
  padding: 10px 12px;
  border: 1px solid var(--line);
  background: var(--surface-raised);
  color: var(--ink);
  font: inherit;
  letter-spacing: 0;
}
.admin-report-toggle { flex-direction: row !important; align-items: center; gap: 8px !important; letter-spacing: 0 !important; text-transform: none !important; font-size: 12px !important; }
.admin-report-toggle input { width: auto; }
.admin-report-form button { margin-left: auto; }

/* Exporting private content is a deliberate act, so the consequence is stated where the
 * choice is made rather than buried in documentation. */
.admin-report-warning {
  margin: 12px 0 0;
  padding: 12px 14px;
  border-left: 3px solid var(--warning);
  background: var(--warning-soft);
  color: var(--ink);
  font-size: 13px;
  line-height: 1.6;
}

.admin-report-summary { margin-top: 18px; }
.admin-report-summary .admin-stats { margin-top: 0; }
.admin-report-summary code { font-size: 12px; }

.admin-report-notes { margin-top: 32px; padding-top: 22px; border-top: 1px solid var(--line); }
.admin-report-notes h2 { margin: 0 0 8px; font: 17px Georgia, serif; }
.admin-report-notes h2 + ul { margin: 0 0 22px; }
.admin-report-notes ul { padding-left: 20px; color: var(--muted); font-size: 13px; line-height: 1.7; }

@media (max-width: 760px) {
  .admin-report-form { flex-direction: column; align-items: stretch; }
  .admin-report-form button { margin-left: 0; }
}

.admin-subsection { margin-top: 36px; padding-top: 24px; border-top: 1px solid var(--line); }
.admin-subsection h2 { margin: 0 0 6px; font: 22px Georgia, serif; }
.admin-subsection .admin-count { max-width: 80ch; line-height: 1.6; }
.admin-note { margin-top: 14px; padding-left: 11px; border-left: 2px solid var(--line); color: var(--faint) !important; }

/* Shown when the portal asks the server for something it does not have, which can only mean
 * the page is newer than the process serving it. Stated once at the top rather than left for
 * each panel to report as an unexplained failure. */
.admin-stale-banner {
  display: grid;
  gap: 6px;
  margin-bottom: 22px;
  padding: 16px 18px;
  border-left: 3px solid var(--warning);
  background: var(--warning-soft);
  color: var(--ink);
  font-size: 13px;
  line-height: 1.65;
}
.admin-stale-banner strong { font-size: 14px; }
.admin-stale-banner code { padding: 1px 5px; background: var(--surface-raised); border: 1px solid var(--line); font-size: 12px; }
.admin-stale-detail { color: var(--muted); font-size: 12px; }
/* A withheld field is not an empty one, and the difference matters when the question is
 * whether somebody wrote something. */
.admin-row-withheld{border-left-color:var(--warning);color:var(--faint);font-style:italic}

/* Appeals: a reply to a decision, which is a conversation rather than a row of buttons. */
.admin-tab-badge{display:inline-grid;place-items:center;min-width:16px;height:16px;margin-left:6px;padding:0 4px;background:var(--danger);color:var(--on-accent);border-radius:9px;font:700 9px/1 system-ui}
.admin-appeal{align-items:start}
/* An unanswered appeal is somebody waiting, so it gets the accent bar. */
.admin-row-open{border-left:3px solid var(--green2);padding-left:13px}
.admin-badge-granted{background:var(--accent-soft);color:var(--accent-strong)}
.admin-appeal-message,.admin-appeal-response{margin:10px 0 0;padding:9px 12px;border-left:2px solid var(--line-strong);background:var(--surface);color:var(--ink);font:13px/1.7 Georgia,serif}
.admin-appeal-response{border-left-color:var(--green2)}

/* The blog editor. The only writing surface in the portal — everything else here is a
 * list of somebody else's content with actions attached. */
.post-editor{display:grid;gap:18px;max-width:820px}
.post-field{display:grid;gap:6px;font-size:13px;font-weight:600;color:var(--ink)}
.post-field input,.post-field textarea{width:100%;padding:10px 12px;border:1px solid var(--line-strong);border-radius:3px;background:var(--surface-raised);color:var(--ink);font:14px/1.6 inherit;font-weight:400}
.post-field textarea{resize:vertical}
#post-body{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;line-height:1.7}
.post-field input:focus-visible,.post-field textarea:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.post-hint{font-weight:400;color:var(--muted);font-size:12px}
.post-help{font-size:12px;color:var(--muted)}
.post-help summary{cursor:pointer;font-weight:600;color:var(--ink)}
.post-help ul{margin:10px 0 0;padding-left:20px;line-height:1.8}
.post-help code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
.post-editor-actions{display:flex;gap:10px;align-items:center}

