/* Operator admin console (EPIC 9) layout. Consumes the LIVE neon-noir tokens (tokens-neon-noir.css,
   linked in admin.html after tokens.css); only console-specific structure lives here (tabs, KPI grid,
   subcards, promo columns). No new color values - everything resolves through the shared theme tokens. */

/* ---- tabs (the console section switcher) ----
   The rail is split into three labelled groups (Moderation / Administrative / Backend). Each .tab-group
   is its own block with a heading above its buttons; the groups sit side by side and wrap on narrow
   screens. Grouping is purely visual - every .tab keeps its id + handler. */
.tabs {
  display: flex;
  gap: var(--sp-4);
  flex-wrap: wrap;
  align-items: flex-start;
  margin: var(--sp-3) 0 var(--sp-4);
  border-bottom: 1px solid var(--line);
  padding-bottom: var(--sp-3);
}
.tab-group {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  flex: 1 1 240px;
  min-width: 0;
  padding: var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-2, 10px);
  background: var(--surface-2);
}
.tab-group-head {
  flex: 1 1 100%;
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-bottom: var(--sp-1);
}
.tab-group-title {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: .08em;
  font-weight: var(--fw-bold);
  color: var(--brand);
}
.tab-group-sub {
  font-size: var(--fs-xs);
  line-height: 1.35;
  color: var(--muted);
}
/* Plain-English "what this does / when to use it" intro at the top of each panel. */
.tool-help {
  margin: 0 0 var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--line);
  border-left: 3px solid var(--brand);
  border-radius: var(--radius-2, 10px);
  background: var(--surface-2);
  color: var(--fg-dim, var(--fg));
  font-size: var(--fs-sm);
  line-height: 1.4;
}
.tabs .tab {
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--muted);
  font-weight: var(--fw-semi);
  letter-spacing: .02em;
  padding: var(--sp-2) var(--sp-4);
  border-radius: var(--r-md);
  cursor: pointer;
  transition: color var(--dur-2), border-color var(--dur-2), box-shadow var(--dur-2);
}
.tabs .tab:hover { color: var(--fg); }
.tabs .tab[aria-selected="true"] {
  color: var(--fg);
  border-color: var(--violet);
  box-shadow: var(--neon-glow);
  background: var(--violet-soft);
}
.tabs .tab:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }

/* ---- work-queue COUNT BADGES on actionable tabs ----
   A tab whose queue has open work shows a small count chip so the rail reads as a live work queue
   (the operator can see a tab needs attention without opening it). The badge text + color are set by
   admin.js from the existing KPI counts; '.has-work' makes it red, otherwise it's a muted count. */
.tabs .tab { display: inline-flex; align-items: center; gap: var(--sp-2); }
.tab-badge {
  display: none; min-width: 18px; height: 18px; padding: 0 5px;
  align-items: center; justify-content: center;
  font-size: var(--fs-xs); font-weight: var(--fw-bold); font-variant-numeric: tabular-nums;
  line-height: 1; border-radius: var(--r-pill);
  background: var(--surface-3); color: var(--muted); border: 1px solid var(--line-2);
}
.tab-badge.show { display: inline-flex; }
.tab-badge.has-work { background: var(--lose-soft); color: var(--lose); border-color: var(--lose); }
.tabs .tab[aria-selected="true"] .tab-badge.has-work { box-shadow: 0 0 8px var(--lose-glow); }

/* ---- per-group color accenting (scannability: differentiate the three rail groups) ----
   A 2px top accent + a tinted title so Moderation / Administrative / Backend read as distinct zones
   rather than one undifferentiated block. Tokens only. */
.tab-group { border-top-width: 2px; }
.tab-group.grp-moderation     { border-top-color: var(--warn); }
.tab-group.grp-administrative { border-top-color: var(--violet); }
.tab-group.grp-backend        { border-top-color: var(--cyan); }
.tab-group.grp-moderation     .tab-group-title { color: var(--warn); }
.tab-group.grp-administrative .tab-group-title { color: var(--violet); }
.tab-group.grp-backend        .tab-group-title { color: var(--cyan); }

.tabpanel { animation: fade-in var(--dur-2) var(--ease-out, ease); }
@keyframes fade-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* ---- KPI dashboard grid ---- */
.kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--sp-3);
  margin: var(--sp-3) 0;
}
.kpi-tile {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: var(--sp-4);
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}
.kpi-tile .lbl {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--muted);
  font-weight: var(--fw-semi);
}
.kpi-tile b {
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
  line-height: 1.15;
  /* Keep big money figures (e.g. the devnet-seeded bankroll, now abbreviated to "$1.00Q") on ONE line
     so they never wrap mid-number; clamp with an ellipsis if an exact figure is still too wide. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.kpi-tile .sub { font-size: var(--fs-xs); color: var(--muted); }
.kpi-tile.good b { color: var(--win); }
.kpi-tile.bad  b { color: var(--lose); }
.kpi-tile.accent b { color: var(--violet); text-shadow: var(--neon-glow-text); }

/* ---- ACTIONABLE KPI tiles: a tile that jumps to the tab where you fix it (button, keyboard-reachable).
   The dashboard diagnoses AND takes you to the fix. A small "Open ->" affordance appears on hover/focus. */
.kpi-tile.tile-link {
  cursor: pointer; text-align: left; width: 100%; font: inherit;
  transition: border-color var(--dur-2), box-shadow var(--dur-2), transform var(--dur-1);
}
.kpi-tile.tile-link:hover { border-color: var(--violet); box-shadow: var(--neon-glow); transform: translateY(-1px); }
.kpi-tile.tile-link:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
.kpi-tile.tile-link.bad:hover { border-color: var(--lose); box-shadow: 0 0 14px var(--lose-glow); }
.kpi-tile .go {
  font-size: var(--fs-xs); color: var(--violet); font-weight: var(--fw-semi);
  opacity: 0; transition: opacity var(--dur-2); margin-top: 2px;
}
.kpi-tile.tile-link:hover .go, .kpi-tile.tile-link:focus-visible .go { opacity: 1; }
/* non-destructive KPI error banner (keeps the last tiles visible, dimmed, with a Retry) */
.kpi-error {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  margin: 0 0 var(--sp-3); padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--lose); border-radius: var(--r-md); background: var(--lose-soft); color: var(--lose);
  font-size: var(--fs-sm);
}
.kpi-grid.stale, .balgrid.stale { opacity: .45; }

/* ---- subcards (nested cards inside a tab panel) ---- */
.subcard { margin-top: var(--sp-4); }
#userDetail.subcard { border-color: var(--violet); }

.promo-cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--sp-4);
  align-items: start;
}
.promo-cols .subcard { margin-top: 0; }

/* ---- user-detail key/value rows ---- */
.kv { display: grid; grid-template-columns: max-content 1fr; gap: var(--sp-1) var(--sp-4); margin: var(--sp-2) 0; }
.kv dt { color: var(--muted); font-size: var(--fs-sm); }
.kv dd { margin: 0; font-variant-numeric: tabular-nums; font-size: var(--fs-sm); word-break: break-word; }

/* ---- status pills in tables ---- */
.pill { display: inline-block; padding: 1px 8px; border-radius: 999px; font-size: var(--fs-xs); font-weight: var(--fw-semi); border: 1px solid var(--line); }
.pill.ok    { color: var(--win);  border-color: var(--win); }
.pill.held  { color: var(--lose); border-color: var(--lose); }
.pill.flagged { color: var(--warn); border-color: var(--warn); }

.data td, .data th { white-space: nowrap; }
.data td.wrap { white-space: normal; word-break: break-word; max-width: 32ch; }
tr.clickable { cursor: pointer; }
tr.clickable:hover td { background: var(--surface-3); }

/* ---- money / RTP cells: positive (house take) vs negative (house bled) ---- */
.data td.good { color: var(--win); font-variant-numeric: tabular-nums; }
.data td.bad  { color: var(--lose); font-variant-numeric: tabular-nums; }
/* A money-OUT (debit) row in the investigator fund-flow transactions table. */
.data td.neg  { color: var(--lose); font-variant-numeric: tabular-nums; }

/* ---- investigator sub-panels (fund flow / user status / tip counterparties in the player drill-down) ---- */
#userDetail .subcard h4 { margin: 0 0 var(--sp-2); font-size: var(--fs-md); }
#userDetail .subcard .row.spread { margin-top: var(--sp-4); }
#userDetail .subcard .row.spread strong { font-size: var(--fs-sm); color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
/* A flagged row (a game paying above edge, a quarantined swap, a blocked withdrawal) gets a left accent. */
tr.row-alert td { background: var(--lose-soft); }
tr.row-alert td:first-child { box-shadow: inset 3px 0 0 var(--lose); }
/* The blended TOTAL footer row in the per-game RTP table. */
tr.row-total td { border-top: 1px solid var(--line); font-weight: var(--fw-semi); }

@media (max-width: 560px) {
  .data { font-size: var(--fs-xs); }
  .tabs { gap: var(--sp-2); }
  .tab-group { flex-basis: 100%; }
  .tabs .tab { padding: var(--sp-2) var(--sp-3); }
}

/* ---- Roles & permissions (custom staff roles + SAFE palette) ----
   The matrix is roles (rows) x permissions (columns). Built-in rows are read-only (every box disabled);
   custom rows are editable only for SAFE columns. DANGEROUS columns are locked for every row + carry a
   "code-only" lock marker. No new colors - all through the shared neon-noir tokens. */
/* A scroll container for any wide table. Capped height + sticky header so the column titles stay in view
   while the operator scrolls a long body; horizontal scroll keeps a wide table from breaking the page. */
.table-scroll { overflow: auto; max-height: 70vh; }
.table-scroll thead th { position: sticky; top: 0; z-index: 2; background: var(--surface-2); }
.role-matrix th, .role-matrix td { text-align: center; }
.role-matrix th:first-child, .role-matrix td:first-child { text-align: left; }
/* Keep the ROLE column (first cell of every row + the corner header) pinned while scrolling sideways, so
   a checkbox never loses which role it belongs to. The corner needs a higher z so it stays above both. */
.role-matrix th:first-child, .role-matrix td:first-child {
  position: sticky; left: 0; z-index: 1; background: var(--surface-2);
}
.role-matrix thead th:first-child { z-index: 3; }
.role-matrix tbody tr:hover td:first-child { background: var(--surface-3); }
.role-matrix th.col-locked { color: var(--muted); }
.role-matrix .lock-mark { color: var(--muted); font-size: var(--fs-xs); }
.role-matrix tr.role-builtin td:first-child { color: var(--muted); }
.role-matrix tr.role-custom  td:first-child { color: var(--fg); font-weight: var(--fw-semi); }
.role-matrix .role-kind { display: block; font-size: var(--fs-xs); color: var(--muted); font-weight: var(--fw-reg); text-transform: uppercase; letter-spacing: .06em; }
/* A disabled (read-only / code-only) checkbox is dimmed so the lock is visually obvious. */
.role-matrix input[type="checkbox"]:disabled { opacity: .35; cursor: not-allowed; }
.role-matrix td.cell-locked { background: var(--surface-2); }
.role-matrix .del-role { color: var(--lose); border-color: var(--lose); }

/* The safe-permission palette in the create-role form (a labelled checkbox per SAFE permission). */
.role-palette { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4); margin: var(--sp-3) 0; }
.role-palette label { display: inline-flex; align-items: center; gap: var(--sp-1); font-size: var(--fs-sm); }

/* User-roles chips (the roles a looked-up user holds; each removable). */
.role-chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-2) 0; }
.role-chip { display: inline-flex; align-items: center; gap: var(--sp-1); padding: 2px 8px; border-radius: 999px; border: 1px solid var(--line); font-size: var(--fs-xs); }
.role-chip button { background: none; border: 0; color: var(--lose); cursor: pointer; font-size: var(--fs-sm); line-height: 1; padding: 0 2px; }
.role-chip button:hover { color: var(--fg); }

/* =============================================================================
   UX OVERHAUL additions (operator console). Tokens only — no new color values.
   ========================================================================== */

/* ---- dense investigator tables: a horizontal-scroll wrapper with a sticky header ----
   The 8-column directory + fund-flow tables are white-space:nowrap; wrapping each in .data-scroll keeps
   the page from scrolling sideways and pins the header row while the operator scans a long body. */
.data-scroll { overflow: auto; max-height: 70vh; border: 1px solid var(--line); border-radius: var(--r-md); }
.data-scroll > .data { margin: 0; }
.data-scroll thead th { position: sticky; top: 0; z-index: 2; background: var(--surface-2); box-shadow: inset 0 -1px 0 var(--line); }

/* ---- environment chip (devnet vs mainnet) — the most important context on a real-funds console ---- */
.env-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 2px 10px; border-radius: var(--r-pill);
  font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: .06em; text-transform: uppercase;
  border: 1px solid var(--line-2); color: var(--muted); background: var(--surface-2); white-space: nowrap;
}
.env-chip::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: currentColor; flex: none; }
.env-chip.env-mainnet { color: var(--lose); border-color: var(--lose); background: var(--lose-soft); }
.env-chip.env-dev { color: var(--warn); border-color: var(--warn); background: var(--warn-soft); }
#signin .env-chip { margin-bottom: var(--sp-3); }
/* The bootstrap (dev-only register+grant) control is demoted: only shown on a dev host, visually quiet. */
#bootstrapWrap { margin-top: var(--sp-2); }
#bootstrapWrap.hidden { display: none; }
#bootstrap { font-size: var(--fs-xs); opacity: .8; }

/* ---- confirm-modal REASON / step-up fields (money-adjacent gates) ----
   Rendered inside the shared confirmModal body (XSS-safe DOM the caller builds). A vertical field stack +
   a plain-English summary line so a freeze / credit always captures WHY and shows WHAT before the POST. */
.modal-field { display: flex; flex-direction: column; gap: 4px; margin: 0 0 var(--sp-3); text-align: left; }
.modal-field > label { font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .05em; color: var(--muted); font-weight: var(--fw-semi); }
.modal-field input, .modal-field textarea { width: 100%; }
.modal-summary {
  margin: 0 0 var(--sp-3); padding: var(--sp-3); text-align: left;
  border: 1px solid var(--line); border-left: 3px solid var(--violet); border-radius: var(--r-md);
  background: var(--surface-2); font-size: var(--fs-sm); line-height: 1.45;
}
.modal-summary dl { display: grid; grid-template-columns: max-content 1fr; gap: 2px var(--sp-3); margin: 0; }
.modal-summary dt { color: var(--muted); }
.modal-summary dd { margin: 0; font-variant-numeric: tabular-nums; word-break: break-word; }
.modal-summary .amt { font-family: var(--font-display); font-weight: var(--fw-bold); font-size: var(--fs-lg); color: var(--violet); }
.modal-hint { font-size: var(--fs-xs); color: var(--muted); margin: -2px 0 var(--sp-2); text-align: left; }

/* ---- withdrawal-limits editor: group sub-headings + dual (human + raw) helper + policy preview ---- */
.cfg-group { margin: var(--sp-4) 0 var(--sp-2); }
.cfg-group-title { font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .06em; font-weight: var(--fw-bold); color: var(--cyan); margin: 0 0 var(--sp-1); }
.field .conv {
  display: block; margin-top: 3px; font-size: var(--fs-xs); color: var(--muted); font-variant-numeric: tabular-nums; min-height: 1em;
}
.field .conv.bad { color: var(--lose); }
/* Read-only "fixed by the coin" scale chip — decimals are a hard invariant, shown not typed (see admin.js). */
.field .fixed-scale {
  display: inline-block; padding: 6px 10px; border-radius: var(--radius-sm, 6px);
  background: color-mix(in oklab, var(--cyan) 10%, transparent);
  border: 1px dashed color-mix(in oklab, var(--cyan) 35%, transparent);
  font-size: var(--fs-sm); font-variant-numeric: tabular-nums; color: var(--text);
}
.field .hint { display: block; margin-top: 4px; font-size: var(--fs-xs); color: var(--muted); line-height: 1.4; }
/* Explicit "No limit / off" toggle + its warning — uncapping is never a blank box (see admin.js capFrom). */
.field .cap-none {
  display: inline-flex; align-items: center; gap: 6px; margin-top: 6px;
  font-size: var(--fs-sm); color: var(--muted); cursor: pointer;
}
.field .cap-none input { width: auto; margin: 0; }
.field .cap-warn {
  display: block; margin-top: 4px; font-size: var(--fs-xs); font-weight: var(--fw-bold);
  color: var(--lose); line-height: 1.4;
}
.field input:disabled { opacity: .5; cursor: not-allowed; }
/* Mystery-box structured prize rows (Label · $ value · Chance %) — replaces the raw base-unit JSON textarea. */
.bx-rows { display: flex; flex-direction: column; gap: 6px; }
.bx-row { display: grid; grid-template-columns: 1fr 90px 90px auto; gap: 6px; align-items: center; }
.bx-row input { margin: 0; }
.bx-usd-wrap { position: relative; display: block; }
.bx-usd-wrap::before { content: "$"; position: absolute; left: 8px; top: 50%; transform: translateY(-50%); color: var(--muted); pointer-events: none; }
.bx-row .bx-usd { padding-left: 18px; }
.bx-row .bx-rm { padding: 4px 8px; line-height: 1; }
#bxTotalPct.bad { color: var(--lose); font-weight: var(--fw-bold); }
/* Progressive disclosure: rare/advanced controls collapse behind a native <details> (no JS). */
.adv-section { margin-top: var(--sp-5); border-top: 1px dashed var(--border, rgba(255,255,255,.12)); padding-top: var(--sp-3); }
.adv-section > .adv-summary {
  cursor: pointer; font-weight: var(--fw-bold); color: var(--cyan); list-style: none;
  padding: var(--sp-2) 0; display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
}
.adv-section > .adv-summary::-webkit-details-marker { display: none; }
.adv-section > .adv-summary::before { content: "▸"; display: inline-block; transition: transform .15s ease; }
.adv-section[open] > .adv-summary::before { transform: rotate(90deg); }
.adv-section > .adv-summary .hint { font-weight: var(--fw-normal); }
.cfg-preview {
  margin: var(--sp-3) 0; padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--line); border-left: 3px solid var(--cyan); border-radius: var(--r-md);
  background: var(--surface-2); font-size: var(--fs-sm); line-height: 1.5;
}
.cfg-preview b { color: var(--fg); font-variant-numeric: tabular-nums; }
.cfg-unit-toggle { display: inline-flex; gap: var(--sp-2); align-items: center; font-size: var(--fs-sm); color: var(--muted); }

/* ---- risk queue inline-triage: a row marked reviewed is dimmed + struck so the queue visibly shrinks ---- */
tr.is-reviewed td { opacity: .5; }
tr.is-reviewed .pill { text-decoration: line-through; }

/* ---- copy-to-clipboard affordance (e.g. a full withdrawal destination address) ---- */
.copy-btn {
  background: none; border: 1px solid var(--line); color: var(--muted); cursor: pointer;
  font-size: var(--fs-xs); line-height: 1; padding: 2px 6px; border-radius: var(--r-sm); margin-left: 6px;
}
.copy-btn:hover { color: var(--fg); border-color: var(--violet); }
.copy-btn.copied { color: var(--win); border-color: var(--win); }

/* ---- withdrawal-review row enrichment (KYC tier + standing pill + view-player link) ---- */
.wd-meta { display: inline-flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.link-btn {
  background: none; border: 0; color: var(--violet); cursor: pointer; padding: 0;
  font: inherit; text-decoration: underline; text-underline-offset: 2px;
}
.link-btn:hover { color: var(--cyan); }

/* ---- sticky context header on the Credit form when it's prefilled for a specific player ---- */
.credit-context {
  display: none; position: sticky; top: 0; z-index: 1;
  margin: 0 0 var(--sp-3); padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--violet); border-radius: var(--r-md); background: var(--violet-soft);
  font-size: var(--fs-sm); color: var(--fg);
}
.credit-context.show { display: block; }
.credit-context b { color: var(--violet); }
/* live "applies now vs escalates" hint as the operator types a credit amount */
#creditApplyHint { font-size: var(--fs-xs); min-height: 1em; margin: -2px 0 var(--sp-2); }
#creditApplyHint.now { color: var(--win); }
#creditApplyHint.escalate { color: var(--warn); }
/* per-row credit-ceiling inline validation warning (display-only; server stays authoritative) */
.cl-warn { display: none; margin-top: 3px; font-size: var(--fs-xs); color: var(--warn); }
.cl-warn.show { display: block; }
/* Flags catalog: the dot-key demoted to a small muted subline under the friendly description. */
.data .flag-key { display: block; margin-top: 2px; font-size: var(--fs-xs); opacity: .7; }
/* Sortable column headers (sortableTable in admin.js): click a header to sort; ↕ idle, ↑/↓ active. */
.data th.th-sort { cursor: pointer; user-select: none; white-space: nowrap; }
.data th.th-sort:hover { color: var(--fg); }
.data th.th-sort::after { content: '\2195'; opacity: .35; margin-left: 4px; font-size: .85em; }
.data th[aria-sort="ascending"]::after  { content: '\2191'; opacity: 1; }
.data th[aria-sort="descending"]::after { content: '\2193'; opacity: 1; }
.data th.th-sort:focus-visible { outline: 2px solid var(--cyan); outline-offset: -2px; }
