/* --- Panel (island) --- */
.panel {
  background: var(--bg-elev);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-island);
  padding: var(--s-4);
}

/* Canonical floating-island surface. .panel / .card share this look. */
/* Unified floating-island skin — the one definition every floating surface
   composes. Elevated depth: layered drop shadow + lit top edge. */
.island {
  background: color-mix(in oklch, var(--bg-elev) 88%, transparent);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-xl);
  box-shadow: var(--island-edge), var(--island-shadow);
}
.island--pill { border-radius: var(--r-pill); }
.island--flush { backdrop-filter: none; -webkit-backdrop-filter: none; }
.panel__head { display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--s-3); gap: var(--s-3); flex-wrap: wrap; }
.panel__head h2, .panel__head h3 { margin: 0; }

/* --- Button (Phase 1.3 — state-complete; see DESIGN.md → Components → Button)
 *
 * Variants: --primary, --secondary (default), --danger, --ghost.
 * Sizes:    --sm (28px), --md (32px, default), --lg (40px).
 * States:   default / hover / focus-visible / active / disabled / loading.
 *
 * focus-visible (not :focus) so mouse clicks don't strobe the ring on every
 * press. The :active translate is gated to (hover: hover) and (pointer: fine)
 * so touch users don't get a confusing 1px jump.
 *
 * Loading state: callers add aria-busy="true" + disabled; the .is-loading
 * class swaps the label for .btn__spinner (a borrowed-border spinner). The
 * @keyframes is auto-suppressed by the prefers-reduced-motion rule in
 * tokens.css, so no per-component override is needed.
 */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  height: 32px;
  padding: 0 var(--s-3);
  background: transparent;
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  line-height: 1;
  cursor: pointer;
  user-select: none;
  transition:
    background-color var(--dur-fast) var(--ease-standard),
    border-color var(--dur-fast) var(--ease-standard),
    color var(--dur-fast) var(--ease-standard),
    transform var(--dur-fast) var(--ease-standard);
}
.btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Sizes */
.btn--sm { height: 28px; padding: 0 var(--s-2); font-size: var(--fs-xs); }
.btn--md { height: 32px; padding: 0 var(--s-3); font-size: var(--fs-sm); }
.btn--lg { height: 40px; padding: 0 var(--s-4); font-size: var(--fs-md); }

/* Primary — accent-filled, the page's strongest affordance. */
.btn--primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--bg-base);
}
.btn--primary:hover:not(:disabled) {
  background: var(--accent-strong);
  border-color: var(--accent-strong);
}
.btn--primary:active:not(:disabled) {
  background: var(--accent-soft);
  border-color: var(--accent-soft);
  color: var(--text-primary);
}

/* Secondary — neutral chrome on transparent bg. */
.btn--secondary {
  background: transparent;
  border-color: var(--border);
  color: var(--text-primary);
}
.btn--secondary:hover:not(:disabled) {
  background: var(--bg-soft);
  border-color: var(--border-strong);
}
.btn--secondary:active:not(:disabled) {
  background: var(--bg-soft);
  border-color: var(--border-strong);
}

/* Danger — destructive actions. */
.btn--danger {
  background: var(--danger);
  border-color: var(--danger);
  color: var(--bg-base);
}
.btn--danger:hover:not(:disabled) {
  /* Brighter danger by mixing toward white in oklch — keeps the same hue. */
  background: color-mix(in oklch, var(--danger) 85%, white);
  border-color: color-mix(in oklch, var(--danger) 85%, white);
}
.btn--danger:active:not(:disabled) {
  background: var(--danger-soft);
  border-color: var(--danger);
  color: var(--danger);
}

/* Ghost — quiet, becomes a button only on hover. */
.btn--ghost {
  background: transparent;
  border-color: transparent;
  color: var(--text-secondary);
}
.btn--ghost:hover:not(:disabled) {
  background: var(--bg-soft);
  color: var(--text-primary);
}
.btn--ghost:active:not(:disabled) {
  background: var(--bg-soft);
}

/* Tactile press — pointer-only so touch users don't see a jump. */
@media (hover: hover) and (pointer: fine) {
  .btn:active:not(:disabled) { transform: translateY(1px); }
}

/* Disabled — applies to attribute, .is-loading falls under here too. */
.btn:disabled,
.btn[aria-busy="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}
.btn[aria-busy="true"] { opacity: 0.85; cursor: progress; }

/* Loading — preserve width by keeping the hidden label in-flow.
 * visibility:hidden (not display:none) means the label still occupies its
 * natural space so the button doesn't collapse to spinner width. The
 * position:absolute that was here was wrong — it took the label out of flow
 * and defeated the whole point. */
.btn__label--hidden {
  visibility: hidden;
  pointer-events: none;
}
.btn.is-loading {
  position: relative;
}
.btn__spinner {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-top-color: transparent;
  animation: btn-spin 0.6s linear infinite;
  display: inline-block;
}
@keyframes btn-spin {
  to { transform: rotate(360deg); }
}

/* --- Input --- */
.input, .input--search {
  height: 32px; padding: 0 var(--s-3);
  background: var(--bg-base);
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  transition: border-color 0.1s;
}
.input:focus, .input--search:focus { border-color: var(--accent); outline: none; }
.input--search { padding-left: var(--s-8); background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%238a93a0' stroke-width='2'><circle cx='11' cy='11' r='7'/><path d='M21 21l-4.35-4.35'/></svg>"); background-repeat: no-repeat; background-position: 10px center; }

/* --- Table --- */
.table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.table th, .table td { text-align: left; padding: var(--s-2) var(--s-3); border-bottom: 1px dashed var(--border); }
.table th { color: var(--text-muted); font-weight: 500; text-transform: uppercase; font-size: var(--fs-xs); letter-spacing: 0.04em; }
.table--dense th, .table--dense td { padding: var(--s-1) var(--s-2); font-size: var(--fs-xs); }

/* --- Tag (legacy single-element label) --- */
.tag { display: inline-block; padding: 1px 6px; border-radius: var(--r-sm); font-size: var(--fs-xs); background: var(--bg-soft); color: var(--text-muted); }

/* --- StatusPill (Phase 1.3 — see DESIGN.md → Components → StatusPill)
 *
 * Renders color + glyph + text label so colorblind users get the same signal.
 * Background is the low-chroma <status>-soft tint, foreground is <status>,
 * border is <status> at 30% alpha — color-mix() composes that without a
 * separate token.
 *
 * Radius is --r-sm (4px), NOT --r-pill — DESIGN.md reserves full-pill radius
 * for the .tag class.
 *
 * Legacy single-element usage like <span class="pill pill--accent"> from
 * the pre-Phase 1 surfaces is preserved further down for back-compat; the
 * new macro emits the structural `.pill__glyph` + `.pill__label` children.
 */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: var(--r-sm);
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  line-height: 1.4;
  font-variant-numeric: tabular-nums;
  background: var(--bg-soft);
  color: var(--text-muted);
  border: 1px solid transparent;
}
.pill--sm { padding: 1px 6px; font-size: var(--fs-xs); }
.pill--md { padding: 2px 8px; font-size: var(--fs-sm); }
.pill__glyph { display: inline-flex; align-items: center; line-height: 1; }
.pill__label { display: inline-flex; align-items: center; line-height: 1; }

.pill--ok {
  background: var(--success-soft);
  color: var(--success);
  border-color: color-mix(in oklch, var(--success) 30%, transparent);
}
.pill--warn {
  background: var(--warning-soft);
  color: var(--warning);
  border-color: color-mix(in oklch, var(--warning) 30%, transparent);
}
.pill--danger {
  background: var(--danger-soft);
  color: var(--danger);
  border-color: color-mix(in oklch, var(--danger) 30%, transparent);
}
.pill--info {
  background: var(--info-soft);
  color: var(--info);
  border-color: color-mix(in oklch, var(--info) 30%, transparent);
}
.pill--muted {
  background: var(--muted-soft);
  color: var(--muted);
  border-color: color-mix(in oklch, var(--muted) 30%, transparent);
}

/* Legacy --accent variant retained for pre-Phase-1 surfaces. New code should
 * use the macro (which emits ok/warn/danger/info/muted). */
.pill--accent {
  background: var(--accent-soft);
  color: var(--accent);
  border-color: color-mix(in oklch, var(--accent) 30%, transparent);
}

/* --- ActorChip (Phase 1.3 — see DESIGN.md → Components → ActorChip)
 *
 * Non-interactive identity chip. Variant-by-prefix logic lives in the
 * actor_chip macro; CSS just renders the four visual treatments.
 */
.actor {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 1px 6px;
  border-radius: var(--r-sm);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  line-height: 1.4;
  /* Identity is information, not an affordance — no hover. */
}
.actor--user    { background: var(--bg-soft);     color: var(--text-secondary); }
.actor--automod { background: var(--accent-soft); color: var(--accent-strong); }
.actor--webhook { background: var(--info-soft);   color: var(--info); }
.actor--chat    { background: var(--bg-soft);     color: var(--text-muted); }
.actor__icon { font-style: normal; opacity: 0.8; }
.actor__label { display: inline-flex; align-items: center; line-height: 1; }

/* --- Modal --- */
.modal-backdrop {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.5);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  z-index: 100;
  display: flex; align-items: center; justify-content: center;
  padding: var(--s-5);
  animation: modal-backdrop-in var(--dur-base) var(--ease-standard);
}
@keyframes modal-backdrop-in { from { opacity: 0; } to { opacity: 1; } }
.modal {
  background: var(--bg-elev);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-xl);
  min-width: 360px; max-width: 640px; max-height: 85vh;
  overflow-y: auto;
  box-shadow: var(--island-edge), var(--island-shadow);
  animation: modal-in var(--dur-slow) var(--ease-decelerate);
}
@keyframes modal-in {
  from { opacity: 0; transform: translateY(8px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.modal--action { max-width: 540px; width: min(540px, 100%); }
.modal__head { padding: var(--s-4) var(--s-5); border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; }
.modal__body { padding: var(--s-5); }

/* --- Menu --- */
.menu {
  background: color-mix(in oklch, var(--bg-elev) 92%, transparent);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-lg);
  padding: var(--s-1);
  min-width: 180px;
  box-shadow: var(--island-edge), var(--island-shadow);
}
.menu__item {
  display: block; width: 100%;
  padding: var(--s-2) var(--s-3);
  background: transparent; border: none;
  color: var(--text-secondary); text-align: left;
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  transition: background var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard);
}
.menu__item:hover { background: var(--bg-soft); color: var(--text-primary); }

/* --- Card (Phase 1.4 — see DESIGN.md → Components → Card)
 *
 * Generic container; "sparingly used". The macro emits the wrapper and the
 * caller composes the slots (.card__header / .card__body / .card__footer)
 * inside, so we ship CSS for the slots even though the macro itself is
 * slot-agnostic.
 */
.card {
  background: var(--bg-elev);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-island);
  padding: var(--s-5);
}
.card__header { margin-bottom: var(--s-4); }
.card__body { /* default flow */ }
.card__footer {
  margin-top: var(--s-4);
  padding-top: var(--s-4);
  border-top: 1px solid var(--border-subtle);
  display: flex;
  gap: var(--s-2);
  justify-content: flex-end;
}
/* Info-tinted card variant — same -soft palette as .pill--info / .toast--info.
 * Used for inline summary cards (e.g. the auto-mod "Selected rule" card). */
.card--info {
  background: var(--info-soft);
  border-color: color-mix(in oklch, var(--info) 30%, transparent);
}

/* --- FormField (Phase 1.4 — see DESIGN.md → Components → FormField)
 *
 * Vertical stack: label + control + (hint OR error). The required asterisk
 * is rendered via ::after on labels carrying [data-required] so we never
 * have to thread an extra <span> into the markup.
 */
.field { display: flex; flex-direction: column; gap: var(--s-1); }
.field + .field { margin-top: var(--s-3); }
.field__label {
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--text-secondary);
}
.field__label[data-required]::after {
  content: " *";
  color: var(--danger);
}
.field__control { /* inherits sizing/border from .input */ }
.field__hint { font-size: var(--fs-xs); color: var(--text-muted); }
.field__error { font-size: var(--fs-xs); color: var(--danger); }
.input[aria-invalid="true"],
.field--invalid .field__control { border-color: var(--danger); }
.input[aria-invalid="true"]:focus,
.field--invalid .field__control:focus {
  outline: none;
  box-shadow: 0 0 0 2px var(--danger-soft, rgba(200, 68, 60, 0.35));
}

/* --- EmptyState (Phase 1.4 — see DESIGN.md → Components → EmptyState)
 *
 * Replaces the old single-element .empty block. Always title + 1–2 sentence
 * body; the actions row is conditional on a primary CTA being provided.
 */
.empty {
  text-align: center;
  padding: var(--s-6) var(--s-4);
  color: var(--text-muted);
}
.empty__title {
  font-size: var(--fs-lg);
  font-weight: var(--fw-semibold);
  color: var(--text-secondary);
  margin: 0 0 var(--s-2) 0;
}
.empty__body {
  font-size: var(--fs-md);
  margin: 0 auto var(--s-4) auto;
  max-width: 48ch;
}
.empty__actions {
  display: flex;
  gap: var(--s-2);
  justify-content: center;
}

/* --- Toast (Phase 1.4 — refreshed; see DESIGN.md → Components → Toast)
 *
 * Status-paired colors using the same -soft palette as StatusPill. The
 * .toast-stack container is preserved as the fixed-position dock for the
 * runtime-injected toasts in static/js/live.js.
 *
 * Levels: ok / warn / err / info. live.js normalises inbound level names
 * (success→ok, error/danger→err) so server-side macros and JS share classes.
 */
.toast-stack {
  position: fixed;
  top: calc(44px + var(--s-4));   /* drop from just below the topbar island row */
  right: var(--s-2);              /* aligned with the topbar islands (where the bell lives) */
  display: flex;
  flex-direction: column;
  align-items: flex-end;         /* islands hug the right edge as they stack down */
  gap: var(--s-2);
  z-index: 200;
  pointer-events: none;
}
.toast {
  display: flex;
  align-items: flex-start;
  gap: var(--s-2);
  width: max-content;
  max-width: min(360px, calc(100vw - 2 * var(--s-2)));
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-xl);    /* island radius — matches topbar/bell panel */
  border: 1px solid var(--border);
  background: var(--bg-elev);
  color: var(--text-primary);
  font-size: var(--fs-sm);
  line-height: 1.35;
  text-align: left;
  box-shadow: var(--island-edge), var(--island-shadow);
  border-left: 3px solid currentColor;
  pointer-events: auto;
  transform-origin: top right;
  animation: toast-in var(--dur-base) var(--ease-decelerate);
}
@keyframes toast-in {
  from { opacity: 0; transform: translateY(-10px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.toast--ok    { background: var(--success-soft); border-color: color-mix(in oklch, var(--success) 30%, transparent); border-left-color: var(--success); border-left-width: 3px; color: var(--success); }
.toast--warn  { background: var(--warning-soft); border-color: color-mix(in oklch, var(--warning) 30%, transparent); border-left-color: var(--warning); border-left-width: 3px; color: var(--warning); }
.toast--err   { background: var(--danger-soft);  border-color: color-mix(in oklch, var(--danger)  30%, transparent); border-left-color: var(--danger);  border-left-width: 3px; color: var(--danger); }
.toast--info  { background: var(--info-soft);    border-color: color-mix(in oklch, var(--info)    30%, transparent); border-left-color: var(--info);    border-left-width: 3px; color: var(--info); }

/* --- Kbd --- */
.kbd { display: inline-block; padding: 1px 6px; background: var(--bg-soft); border: 1px solid var(--border); border-bottom-width: 2px; border-radius: var(--r-sm); font-family: "JetBrains Mono", monospace; font-size: 10px; color: var(--text-muted); }

/* --- Form messages / settings --- */
.form-note { margin: 0 0 var(--s-3); padding: var(--s-3); border: 1px solid var(--border); border-radius: var(--r-sm); }
.form-note--error { border-color: var(--danger); color: var(--danger); }
.form-note--success { border-color: var(--success); color: var(--success); }
.settings-users,
.settings-account { display: grid; gap: var(--s-4); }
.settings-users__create { display: grid; gap: var(--s-3); max-width: 420px; }
.settings-users__create h3 { margin: 0; }
.settings-users__table-wrap { overflow-x: auto; }
.settings-users__table { min-width: 880px; }
.settings-users__actions { display: grid; gap: var(--s-2); min-width: 240px; }
.settings-users__actions form { display: flex; gap: var(--s-2); align-items: center; margin: 0; }
.settings-users__actions .input { min-width: 160px; }


/* --- Editor drawer (right slide-over for auto-mod new/edit forms)
 *
 * The drawer sits on top of the page but below modals (z-index: 60 vs 100).
 * .drawer-backdrop--editor is a self-contained dim overlay (full-viewport,
 * positioned flush-right so the aside fills the right edge). The base
 * .editor-drawer is translate(0) — the "open" state;
 * Alpine toggles the class `.editor-drawer--closed` on enter-start/leave-end
 * to drive the slide animation.
 */
.drawer-backdrop--editor {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  z-index: 60;
  display: flex;
  justify-content: flex-end;
}

.editor-drawer {
  position: fixed;
  top: var(--s-2);
  right: var(--s-2);
  bottom: var(--s-2);
  height: auto;                          /* top + bottom define height — floats clear of edges */
  width: min(640px, calc(100vw - 2 * var(--s-2)));
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);            /* island corners — matches topbar / panels / toasts */
  box-shadow: var(--island-edge), var(--island-shadow);
  display: flex;
  flex-direction: column;
  overflow: hidden;                      /* clip body scroll to the rounded corners */
  z-index: 61;
  transition: transform var(--dur-slow) var(--ease-decelerate);
}

.editor-drawer--closed {
  transform: translateX(calc(100% + var(--s-2)));   /* slide fully off, clearing the right gap */
}

.editor-drawer__head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: var(--s-3) var(--s-4);
  border-bottom: 1px solid var(--border);
  background: var(--bg-elev);
  flex-shrink: 0;
}

.editor-drawer__body {
  flex: 1;
  overflow-y: auto;
  padding: var(--s-4);
}

@media (prefers-reduced-motion: reduce) {
  .editor-drawer { transition: none; }
}




/* ---------------------------------------------------------------------------
 * Auth pages — login + first-owner.
 *
 * Centered card, restrained. Uses the shared field() / button() / pill()
 * macros so the look matches the rest of the panel. Error messages render as
 * a danger pill above the form; password-strength hint copy lives on the
 * .field__hint inside the field() macro.
 * --------------------------------------------------------------------------- */
.auth-body {
  background: var(--bg-base);
  min-height: 100vh;
  display: flex;
}
.auth-shell {
  width: min(380px, 100%);
  margin: 10vh auto;
  padding: 0 var(--s-4);
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
}
.auth-shell--wide { width: min(440px, 100%); }
.auth-shell__brand {
  font-family: var(--font-sans);
  font-size: var(--fs-lg);
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
  letter-spacing: -0.01em;
}
.auth-card { padding: var(--s-5); }
.auth-card__head { margin-bottom: var(--s-4); }
.auth-card__title {
  margin: 0 0 var(--s-1);
  font-size: var(--fs-xl);
  font-weight: var(--fw-semibold);
}
.auth-card__sub {
  margin: 0;
  font-size: var(--fs-sm);
  line-height: 1.5;
}
.auth-card__error {
  margin-bottom: var(--s-3);
}
.auth-form {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}
.auth-form__footer { margin-top: var(--s-2); }
.auth-form__submit { width: 100%; justify-content: center; }

/* ---------------------------------------------------------------------------
 * Error pages — calm monospace error code + single CTA back. Matches the
 * auth-shell layout for visual consistency across "you're outside the app"
 * surfaces.
 * --------------------------------------------------------------------------- */
.error-shell {
  width: min(440px, 100%);
  margin: 12vh auto;
  padding: 0 var(--s-4);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s-4);
}
.error-shell__code {
  font-family: var(--font-mono);
  font-size: 64px;
  line-height: 1;
  color: var(--text-dim);
  letter-spacing: 0.02em;
  margin: 0;
}
.error-shell__title {
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
}
.error-shell__body {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--fs-md);
  line-height: 1.5;
  max-width: 48ch;
}

/* ---- In-app notifications: bell + badge + dropdown ---- */
.notif-bell { position: relative; display: inline-flex; }
.notif-bell__panel {
  position: absolute; top: calc(100% + var(--s-2)); right: 0;
  width: min(22rem, 90vw); max-height: 24rem; overflow-y: auto;
  background: var(--bg-elev, var(--bg-2, #1b1f27));
  box-shadow: var(--shadow-island, 0 8px 24px rgba(0,0,0,.4));
  border-radius: var(--r-lg, 8px);
  padding: var(--s-2); z-index: 60;
}
/* Badge is a sibling of the bell button, absolutely pinned to its top-right.
   Empty (count 0) -> no dot rendered -> invisible. */
.notif-badge { position: absolute; top: -3px; right: -3px; pointer-events: none; }
.notif-badge__dot {
  display: inline-block; min-width: 1.05em; padding: 0 .3em;
  font-size: .66rem; line-height: 1.5; font-weight: 700; text-align: center;
  color: #fff; background: var(--danger, #c8443c);
  border-radius: 999px; box-shadow: 0 0 0 2px var(--bg-elev, #1b1f27);
}
/* Center the inline SVG glyphs in the topbar bell / send buttons. */
.notif-bell #notif-bell svg, .topbar__notif-send svg { display: block; }
.notif-list__head { display: flex; justify-content: space-between; align-items: center; padding: var(--s-1) var(--s-2); }
.notif-list { list-style: none; margin: 0; padding: 0; }
.notif-row { display: flex; gap: var(--s-2); align-items: flex-start; padding: var(--s-2); border-radius: var(--r-md, 6px); }
.notif-row--unread { background: var(--bg-soft, rgba(255,255,255,.04)); }
.notif-row__main { flex: 1 1 auto; min-width: 0; }
.notif-row__title { display: block; }
.notif-row__body { margin: .15rem 0 0; font-size: .85rem; }
.notif-row__time { display: block; margin-top: .2rem; font-size: .7rem; }
.notif-row--warn .notif-row__title { color: var(--warning, #d8a33b); }
.notif-row--error .notif-row__title { color: var(--danger, #c8443c); }
.notify-compose { display: flex; flex-direction: column; gap: var(--s-3); }
.notify-compose__actions { display: flex; justify-content: flex-end; }


/* ---- RCON console (F3) -------------------------------------------------- */
.console-page { display: flex; flex-direction: column; gap: var(--s-4, 1rem); }
.console-form {
  display: flex; align-items: center; gap: var(--s-2, 0.5rem);
  background: var(--bg-elev, #161616); border: 1px solid var(--border, #333);
  border-radius: var(--r-sm, 6px); padding: var(--s-2, 0.5rem) var(--s-3, 0.75rem);
  position: sticky; top: 0; z-index: 1;
}
.console-form__prompt { font-family: var(--font-mono, monospace); color: var(--accent, #6ab0f3); font-weight: 700; }
.console-form__input {
  flex: 1; background: transparent; border: none; outline: none;
  font-family: var(--font-mono, monospace); font-size: var(--fs-sm, 0.9rem);
  color: var(--text-primary, #eee);
}
.console-transcript {
  display: flex; flex-direction: column; gap: var(--s-2, 0.5rem);
  max-height: 32rem; overflow-y: auto;
  font-family: var(--font-mono, monospace); font-size: var(--fs-sm, 0.9rem);
}
.console-line {
  border: 1px solid var(--border-subtle, #2a2a2a); border-left-width: 3px;
  border-radius: var(--r-sm, 6px); padding: var(--s-2, 0.5rem) var(--s-3, 0.75rem);
  background: var(--bg-soft, #1b1b1b);
}
.console-line--ok { border-left-color: var(--success, #4f9d5a); }
.console-line--error { border-left-color: var(--danger, #c8443c); }
.console-line--confirm { border-left-color: var(--warning, #d8a33b); display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2, 0.5rem); }
.console-line__meta { display: flex; gap: var(--s-3, 0.75rem); font-size: var(--fs-xs, 0.75rem); color: var(--text-muted, #888); margin-bottom: var(--s-1, 0.25rem); }
.console-line__cmd { color: var(--text-primary, #eee); font-weight: 600; }
.console-line__resp { margin: var(--s-1, 0.25rem) 0 0; white-space: pre-wrap; word-break: break-word; color: var(--text-secondary, #bbb); }
.console-line__resp--error { color: var(--danger, #c8443c); }
.console-line__confirm-cmd { color: var(--warning, #d8a33b); }
.console-empty { padding: var(--s-4, 1rem); text-align: center; }

/* ---- Map vote (F6) ----------------------------------------------------- */
.mapvote-page { display: flex; flex-direction: column; gap: var(--s-4, 1rem); }
.mapvote-status__head { display: flex; align-items: center; gap: var(--s-3, 0.75rem); margin-bottom: var(--s-2, 0.5rem); }
.mapvote-tally { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--s-1, 0.25rem); }
.mapvote-tally__row { display: flex; align-items: center; gap: var(--s-2, 0.5rem); padding: var(--s-1, 0.25rem) var(--s-2, 0.5rem); border: 1px solid var(--border-subtle, #2a2a2a); border-radius: var(--r-sm, 6px); }
.mapvote-tally__opt { font-family: var(--font-mono, monospace); color: var(--accent, #6ab0f3); font-weight: 700; }
.mapvote-tally__layer { flex: 1; }
.mapvote-tally__count { color: var(--text-muted, #888); font-size: var(--fs-sm, 0.9rem); }
.mapvote-history { margin: 0; padding-left: var(--s-5, 1.25rem); color: var(--text-secondary, #bbb); }
.mapvote-history li { padding: var(--s-1, 0.25rem) 0; }

/* ---- Admin requests inbox (F4) ----------------------------------------- */
.adminreq-page { display: flex; flex-direction: column; gap: var(--s-4, 1rem); }
.adminreq { border: 1px solid var(--border-subtle, #2a2a2a); border-left-width: 3px; border-radius: var(--r-sm, 6px); padding: var(--s-2, 0.5rem) var(--s-3, 0.75rem); margin-bottom: var(--s-2, 0.5rem); background: var(--bg-soft, #1b1b1b); }
.adminreq--open { border-left-color: var(--success, #4f9d5a); }
.adminreq--claimed { border-left-color: var(--warning, #d8a33b); }
.adminreq--resolved { border-left-color: var(--border, #444); opacity: 0.8; }
.adminreq__head { display: flex; align-items: center; gap: var(--s-2, 0.5rem); flex-wrap: wrap; }
.adminreq__who { font-weight: 600; }
.adminreq__steam { font-family: var(--font-mono, monospace); font-size: var(--fs-xs, 0.75rem); color: var(--text-muted, #888); }
.adminreq__time { margin-left: auto; font-size: var(--fs-xs, 0.75rem); }
.adminreq__msg { margin: var(--s-2, 0.5rem) 0; }
.adminreq__meta { font-size: var(--fs-sm, 0.9rem); margin: var(--s-1, 0.25rem) 0 0; }
.adminreq__actions { display: flex; align-items: center; gap: var(--s-2, 0.5rem); flex-wrap: wrap; }
.adminreq__resolve { display: flex; gap: var(--s-2, 0.5rem); align-items: center; flex: 1; }
.adminreq__resolve .input { flex: 1; }

/* ---- CBL card (F1) ----------------------------------------------------- */
.cbl-card { border: 1px solid var(--border-subtle, #2a2a2a); border-radius: var(--r-sm, 6px); padding: var(--s-2, 0.5rem) var(--s-3, 0.75rem); margin-top: var(--s-3, 0.75rem); background: var(--bg-soft, #1b1b1b); }
.cbl-card__head { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2, 0.5rem); }
.cbl-card__title { margin: 0; font-size: var(--fs-sm, 0.9rem); }
.cbl-card__stats { display: flex; flex-wrap: wrap; gap: var(--s-2, 0.5rem); margin: var(--s-2, 0.5rem) 0; }
.cbl-stat { font-size: var(--fs-sm, 0.9rem); color: var(--text-secondary, #bbb); }
.cbl-stat--danger { color: var(--danger, #c8443c); }
.cbl-card__link { font-size: var(--fs-sm, 0.9rem); }
.cbl-card__meta { font-size: var(--fs-xs, 0.75rem); margin: var(--s-1, 0.25rem) 0 0; }

/* ---- RCON console autocomplete (F3 enhancement) ------------------------ */
.console-form__field { position: relative; flex: 1; display: flex; }
.console-form__field .console-form__input { flex: 1; }
.console-suggest {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 20;
  margin: 0; padding: var(--s-1, 0.25rem); list-style: none;
  background: var(--bg-elev, #161616); border: 1px solid var(--border, #333);
  border-radius: var(--r-sm, 6px); max-height: 18rem; overflow-y: auto;
  box-shadow: 0 8px 24px rgba(0,0,0,0.4);
}
.console-suggest__item {
  display: grid; grid-template-columns: auto 1fr auto; gap: 0 var(--s-2, 0.5rem);
  align-items: baseline; padding: var(--s-1, 0.25rem) var(--s-2, 0.5rem);
  border-radius: var(--r-sm, 6px); cursor: pointer; font-family: var(--font-mono, monospace);
}
.console-suggest__item.is-active,
.console-suggest__item:hover { background: var(--accent-soft, rgba(106,176,243,0.15)); }
.console-suggest__name { color: var(--accent, #6ab0f3); font-weight: 700; }
.console-suggest__params { color: var(--text-secondary, #bbb); font-size: var(--fs-sm, 0.9rem); }
.console-suggest__warn { color: var(--danger, #c8443c); }
.console-suggest__desc { grid-column: 1 / -1; color: var(--text-muted, #888); font-size: var(--fs-xs, 0.75rem); font-family: inherit; }
.console-hint { margin: var(--s-1, 0.25rem) 0 0; font-size: var(--fs-sm, 0.9rem); }
.console-hint code { color: var(--accent, #6ab0f3); margin-right: var(--s-2, 0.5rem); }

/* ---- Chat command action chain editor ---------------------------------- */
.chat-cmd-chain__step { border: 1px solid var(--border-subtle, #2a2a2a); border-radius: var(--r-sm, 6px); padding: var(--s-2, 0.5rem); margin-bottom: var(--s-2, 0.5rem); display: flex; flex-direction: column; gap: var(--s-2, 0.5rem); background: var(--bg-soft, #1b1b1b); }
.chat-cmd-chain__step-head { display: flex; align-items: center; gap: var(--s-2, 0.5rem); }
.chat-cmd-chain__num { font-family: var(--font-mono, monospace); color: var(--accent, #6ab0f3); font-weight: 700; }
.chat-cmd-chain__type { flex: 1; }
.chat-cmd-chain__tmpl { width: 100%; font-family: var(--font-mono, monospace); }

/* --- info tooltip (data-tip) + freshness pill ------------------------- */
[data-tip] { position: relative; cursor: help; border-bottom: 1px dotted var(--muted, #8a93a0); }
[data-tip]:hover::after, [data-tip]:focus-visible::after {
  content: attr(data-tip);
  position: absolute; left: 0; bottom: calc(100% + 6px); z-index: 80;
  width: max-content; max-width: 18rem; padding: .4rem .6rem;
  background: var(--surface-2, #1b2027); color: var(--text, #e6e9ee);
  border: 1px solid var(--island-edge, rgba(255,255,255,.14)); border-radius: var(--r-sm, 6px);
  font-size: .8rem; line-height: 1.3; white-space: normal;
  box-shadow: 0 6px 18px rgba(0,0,0,.35);
}
.tac-info { display: inline-flex; align-items: center; justify-content: center;
  width: 1.1em; height: 1.1em; border-radius: 50%; font-size: .75em; font-weight: 700;
  background: var(--surface-2, #1b2027); border: 1px solid var(--island-edge, rgba(255,255,255,.18)); cursor: help; }
.tac-pill { display: inline-block; padding: .15rem .5rem; border-radius: 999px;
  font-size: .78rem; font-weight: 600; background: var(--surface-2, #1b2027);
  border: 1px solid var(--island-edge, rgba(255,255,255,.14)); }
.tac-pill--ok    { color: #7ee0a6; }
.tac-pill--warn  { color: #e9c46a; }
.tac-pill--stale { color: #e07a7a; }
.tac-head { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin-bottom: .5rem; }
.tac-about { margin-left: auto; }
.empty-state { padding: 1rem; color: var(--muted, #8a93a0); }

/* --- Error pages (standalone; reuse .auth-shell / .auth-card) --- */
.error-card { text-align: center; }
.error-card__glyph { font-size: 2.5rem; line-height: 1; margin-bottom: var(--s-2); }
.error-card__code { font-size: var(--fs-xl, 2rem); margin: 0; }
.error-card__title { font-weight: var(--fw-medium); margin: var(--s-1) 0 var(--s-3); }
.error-card .btn { margin-top: var(--s-4); }
