/* AIventure — split-pane dashboard */

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
[hidden] { display: none !important; }

:root {
  --bg:          #0d1117;
  --bg-panel:    #161b22;
  --bg-header:   #21262d;
  --bg-entry:    #1a1f27;
  --border:      #30363d;
  --text:        #c9d1d9;
  --text-muted:  #8b949e;
  --text-dim:    #484f58;
  --accent:      #58a6ff;
  --accent-win:  #3fb950;
  --accent-loss: #f85149;
  --btn-bg:      #238636;
  --btn-hover:   #2ea043;
  --btn-dim:     #21262d;
  --btn-dim-txt: #484f58;
  --btn-txt:     #ffffff;
  --accent-gold: #f0c040;
  --radius:      6px;
  --gap:         16px;
  /* Typography — overridden per-world by the generated theme (app.js). */
  --font-heading: 'Segoe UI', system-ui, sans-serif;
  --font-body:    'Segoe UI', system-ui, sans-serif;
}

html, body { height: 100%; font-family: var(--font-body); background: var(--bg); color: var(--text); font-size: 17px; line-height: 1.55; }

/* Screens */
.screen { width: 100%; min-height: 100vh; }

/* ---- SETUP SCREEN ---- */
#setup-screen {
  display: flex;
  align-items: flex-start;        /* top-align: the multi-step wizard can grow taller than the viewport */
  justify-content: center;
  padding: 3rem 2rem;
}
.setup-inner {
  width: 100%;
  max-width: 760px;
}
#login-screen {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}
.login-inner {
  width: 100%;
  max-width: 360px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 2rem 1.75rem;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
}
.login-form { display: flex; flex-direction: column; gap: 0.7rem; margin-top: 1.2rem; }
.login-input {
  background: var(--bg); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius); padding: 0.7rem 0.8rem; font: inherit;
  width: 100%;
  font-size: 1rem; /* >=16px prevents iOS Safari auto-zoom on focus */
}
.login-form .hub-forge-btn { width: 100%; padding: 0.7rem 0.8rem; }

@media (max-width: 480px) {
  .login-inner { padding: 1.5rem 1.25rem; }
}
.title {
  font-family: var(--font-heading);
  font-size: 2.4rem;
  font-weight: 700;
  color: var(--accent);
  letter-spacing: -0.5px;
  margin-bottom: 0.3rem;
}
.tagline {
  color: var(--text-muted);
  margin-bottom: 1.8rem;
}

/* World-creation wizard — a vertical stack of step cards, each unlocking below. */
.wizard { display: flex; flex-direction: column; gap: 1rem; }

.wizard-step {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.1rem 1.2rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  text-align: left;
  /* Fade-and-rise as each new step is revealed below the last. */
  animation: wizard-reveal 0.35s ease;
}
@keyframes wizard-reveal {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}
.wizard-step.done { border-color: var(--accent); }

.wizard-step-head { display: flex; align-items: baseline; gap: 0.7rem; flex-wrap: wrap; }
.wizard-step-num {
  font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--text-dim); font-weight: 700;
}
.wizard-step-title {
  font-family: var(--font-heading); font-size: 1.25rem; font-weight: 700; color: var(--accent);
}
.wizard-step-blurb { font-size: 0.88rem; line-height: 1.55; color: var(--text-muted); margin: 0; }

.wizard-prompt {
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius);
  color: var(--text); padding: 0.7rem 0.9rem; font-size: 0.95rem; line-height: 1.5;
  resize: vertical; outline: none; transition: border-color 0.15s; font-family: var(--font-body);
}
.wizard-prompt:focus { border-color: var(--accent); }

.wizard-mode-select {
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius);
  color: var(--text); padding: 0.5rem 0.7rem; font-size: 0.9rem; align-self: flex-start;
  outline: none; cursor: pointer; font-family: var(--font-body);
}
.wizard-mode-select:focus { border-color: var(--accent); }

.wizard-preview-btn {
  margin-top: 0.6rem;
  background: transparent; border: 1px solid var(--border); color: var(--text-muted);
  border-radius: var(--radius); padding: 0.45rem 0.9rem; font-size: 0.85rem; font-weight: 600;
  cursor: pointer; transition: border-color 0.15s, color 0.15s;
}
.wizard-preview-btn:hover { border-color: var(--accent); color: var(--accent); }

.wizard-btn-row { display: flex; gap: 0.6rem; align-self: flex-start; flex-wrap: wrap; }

.wizard-gen-btn {
  background: transparent; border: 1px solid var(--accent); color: var(--accent);
  border-radius: var(--radius); padding: 0.5rem 1.1rem; font-size: 0.9rem; font-weight: 600;
  cursor: pointer; transition: background 0.15s, color 0.15s;
}
.wizard-gen-btn:hover:not(:disabled) { background: var(--accent); color: var(--btn-txt); }
.wizard-gen-btn:disabled { opacity: 0.5; cursor: not-allowed; }

/* Refine: a quieter secondary action next to Regenerate — tweaks the current
   result per the guidance box instead of rolling a fresh one. */
.wizard-refine-btn {
  background: transparent; border: 1px solid var(--border); color: var(--text-muted);
  border-radius: var(--radius); padding: 0.5rem 1.1rem; font-size: 0.9rem; font-weight: 600;
  cursor: pointer; transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.wizard-refine-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.wizard-refine-btn:disabled { opacity: 0.4; cursor: not-allowed; }

.wizard-result {
  background: var(--bg-entry); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 0.8rem 1rem; font-size: 0.92rem; line-height: 1.6;
}
.wizard-result h3 { font-family: var(--font-heading); color: var(--accent); font-size: 1.05rem; margin: 0 0 0.4rem; }
.wizard-result .wizard-world-name { font-size: 1.3rem; }
.wizard-result p { margin: 0 0 0.55rem; color: var(--text); }
.wizard-result p:last-child { margin-bottom: 0; }
.wizard-goals, .wizard-stats { margin: 0.3rem 0 0; padding-left: 1.1rem; display: flex; flex-direction: column; gap: 0.3rem; }
.wizard-stats li { list-style: none; }
.wizard-stats strong { color: var(--text); margin-right: 0.4rem; }
.wizard-stats span, .wizard-goals li { color: var(--text-muted); font-size: 0.86rem; }
.wizard-currency { color: var(--accent-gold) !important; font-size: 0.88rem; }
.wizard-extra { color: var(--text-muted) !important; font-size: 0.85rem; }
.wizard-result .wizard-section-head { font-family: var(--font-heading); color: var(--accent); font-size: 0.98rem; margin: 0.8rem 0 0.3rem; }
.wizard-chips { display: flex; flex-wrap: wrap; gap: 0.35rem; margin: 0 0 0.6rem; }
.wizard-chip {
  background: var(--bg-panel, var(--bg)); border: 1px solid var(--border); border-radius: 999px;
  padding: 0.1rem 0.6rem; font-size: 0.74rem; color: var(--text-muted); white-space: nowrap;
}
.wizard-cultures { margin: 0.3rem 0 0; padding-left: 1.1rem; display: flex; flex-direction: column; gap: 0.3rem; }
.wizard-cultures li { list-style: none; }
.wizard-cultures strong { color: var(--text); }
.wizard-cultures span { color: var(--text-muted); font-size: 0.86rem; }
.wizard-swatches { display: flex; gap: 0.5rem; margin-top: 0.6rem; }
.wizard-swatch { width: 28px; height: 28px; border-radius: 50%; border: 1px solid var(--border); display: inline-block; }

.wizard-continue-btn {
  align-self: flex-end;
  background: var(--btn-bg); color: var(--btn-txt); border: none; border-radius: var(--radius);
  padding: 0.6rem 1.4rem; font-size: 0.95rem; font-weight: 600; cursor: pointer; transition: background 0.15s;
}
.wizard-continue-btn:hover:not(:disabled) { background: var(--btn-hover); }
.wizard-continue-btn:disabled { opacity: 0.5; cursor: not-allowed; }

.status-line {
  margin-top: 0.8rem;
  padding: 0.6rem 0.9rem;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 0.88rem;
  color: var(--text-muted);
}
.status-line.error { border-color: var(--accent-loss); color: var(--accent-loss); }

.hint {
  margin-top: 1.5rem;
  font-size: 0.82rem;
  color: var(--text-dim);
  line-height: 1.6;
}

/* ---- GAME SCREEN — SPLIT PANE ---- */
/* #game-screen is a column: a persistent header (stays reachable in both
   modes), then EITHER the adventure split-pane OR the hub board — never
   both (Epic 5.3's mode-driven shell; see [data-mode] below). */
#game-screen { display: flex; flex-direction: column; height: 100vh; }

.split-pane {
  display: flex;
  width: 100%;
  flex: 1;
  min-height: 0;
  gap: 0;
}

/* Panel shared */
.story-panel, .telemetry-panel {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}

.panel-header, .game-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.7rem 1.1rem;
  background: var(--bg-header);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.panel-label {
  font-family: var(--font-heading);
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}

/* The saga rail (Epic 15) — persists across hub AND adventure views, between
   the header and the story/hub content below: "Act II of IV — <title>", the
   act's goal, and a threat meter tracking how close the saga's climax is. */
.saga-rail {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  padding: 0.5rem 1.1rem;
  background: var(--bg-header);
  border-bottom: 1px solid var(--accent-gold);
  flex-shrink: 0;
}
.saga-rail-main {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  font-family: var(--font-heading);
}
.saga-rail-title { font-size: 0.85rem; font-weight: 700; color: var(--accent-gold); letter-spacing: 0.02em; }
.saga-rail-goal { font-size: 0.8rem; color: var(--text-muted); }
.saga-rail-threat {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.saga-rail-threat-label { font-size: 0.7rem; color: var(--text-muted); white-space: nowrap; }
.saga-rail-threat-track {
  flex: 1;
  max-width: 220px;
  height: 5px;
  border-radius: 3px;
  background: var(--bg-panel);
  overflow: hidden;
}
.saga-rail-threat-fill {
  height: 100%;
  background: var(--accent-loss, #c0392b);
  transition: width 0.4s ease;
}
.saga-rail-threat-track.resolved .saga-rail-threat-fill { background: var(--accent-win, #2e8b57); }
/* Epic 20 (Act Clock): numeric N/M readout beside the bar + an optional
   AI-authored escalation caption line beneath it. */
.saga-rail-threat-count { font-size: 0.7rem; color: var(--text-muted); white-space: nowrap; }
.saga-rail-escalation { font-size: 0.78rem; color: var(--text-muted); font-style: italic; }

/* ---- LEFT: Story panel ---- */
.story-panel {
  flex: 2;
  min-width: 0;
  border-right: 1px solid var(--border);
}

.story-log {
  flex: 1;
  overflow-y: auto;
  padding: 1.2rem 1.4rem;
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
}

/* Individual narrative entry */
.story-entry {
  background: var(--bg-entry);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.9rem 1.1rem;
  flex-shrink: 0;
}
.story-entry .entry-timing {
  margin-top: 0.5rem;
  text-align: right;
  font-size: 0.68rem;
  color: var(--text-dim);
  opacity: 0.6;
  letter-spacing: 0.02em;
}
.story-entry .entry-turn {
  font-size: 0.72rem;
  color: var(--text-dim);
  margin-bottom: 0.4rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.story-entry .entry-choice {
  font-size: 0.92rem;
  color: var(--accent);
  margin-bottom: 0.45rem;
  font-style: italic;
}
.story-entry .entry-body {
  display: flex;
  align-items: flex-start;
  gap: 0.8rem;
}
.story-entry .entry-text {
  flex: 1;
  min-width: 0;
  font-size: 1.05rem;
  line-height: 1.65;
  white-space: pre-wrap;
}
.story-entry.game-over-entry {
  border-color: var(--accent-win);
  background: #0d1f11;
  color: #e6e6e6;
}
.story-entry.game-over-entry .entry-turn { color: #9fb0a4; }
.story-entry.game-over-entry .entry-choice { color: #d7c98a; }
.story-entry.game-over-entry.loss {
  border-color: var(--accent-loss);
  background: #200d0d;
}
.story-entry.game-over-entry.loss .entry-turn { color: #b09a9a; }
.story-entry.game-over-entry.loss .entry-choice { color: #e08a7d; }

/* Act dividers — a full-width seam marker so the hub<->adventure rhythm reads
   at a glance in the scrolling story column (Epic 5.1). */
.story-divider {
  margin: 1.4rem 0;
  padding: 0.6rem 0;
  text-align: center;
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 0.85rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
.story-divider.divider-complete { color: var(--accent-gold); }
.story-divider.divider-win {
  color: var(--accent-win);
  border-color: var(--accent-win);
}
.story-divider.divider-loss {
  color: var(--accent-loss);
  border-color: var(--accent-loss);
}
/* Arc/act-transition/saga-victory markers (Epic 15) — a heavier, gold-bordered
   seam so these bigger saga beats read as more than an ordinary adventure. */
.story-divider.divider-arc-begins,
.story-divider.divider-act-transition,
.story-divider.divider-saga-victory {
  color: var(--accent-gold);
  border-color: var(--accent-gold);
  border-width: 2px;
}

/* Choices */
/* Choices flow at the end of the scrollable story column (Disco-Elysium style)
   rather than in a pinned tray, so narrative and the options that follow it read
   as one continuous, scrollable exchange. */
.choices-area {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.choices-area:empty { display: none; }

.choice-btn {
  background: var(--bg-panel);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.6rem 1rem;
  font-size: 1rem;
  text-align: left;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.choice-label {
  flex: 1;
}
.choice-icons {
  display: flex;
  flex-shrink: 0;
  gap: 0.25rem;
}
.choice-icons .art-slot.art-item,
.choice-icons .art-slot.art-character {
  width: 40px;
  height: 40px;
}

.choice-btn:hover:not(:disabled) {
  background: var(--bg-header);
  border-color: var(--accent);
  color: var(--accent);
}
.choice-btn:disabled {
  background: var(--btn-dim);
  color: var(--btn-dim-txt);
  cursor: default;
  border-color: var(--border);
  text-decoration: line-through;
  opacity: 0.5;
}

/* Thinking dots */
.thinking {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.75rem 1.4rem;
  border-top: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 0.85rem;
}
.dot {
  display: inline-block;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--accent);
  animation: bounce 1.1s infinite;
}
.dot:nth-child(2) { animation-delay: 0.18s; }
.dot:nth-child(3) { animation-delay: 0.36s; }
@keyframes bounce {
  0%, 80%, 100% { transform: translateY(0); opacity: 0.4; }
  40%            { transform: translateY(-5px); opacity: 1; }
}
.thinking-label { margin-left: 0.2rem; }

/* ---- RIGHT: Telemetry panel ---- */
/* The right panel is a single scrollable column (character name, portrait,
   quest info, stats, conditions, credits, inventory, background) — no tabs,
   unlike the left story panel. .telemetry-scroll owns the scrollbar since
   .telemetry-panel keeps the shared overflow:hidden from the
   .story-panel, .telemetry-panel rule. */
.telemetry-panel {
  flex: 1;
  min-width: 300px;
  max-width: 560px;
}
.telemetry-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

.telemetry-section {
  border-bottom: 1px solid var(--border);
  padding: 0.9rem 1.1rem;
}
.telemetry-section h3 {
  font-family: var(--font-heading);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  margin-bottom: 0.55rem;
}

.t-location {
  font-size: 0.95rem;
  color: var(--text);
  line-height: 1.55;
}

.t-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}
.t-list li { font-size: 0.95rem; }
.t-list li strong { color: var(--accent); display: block; font-size: 0.92rem; }
.t-list li span  { color: var(--text-muted); font-size: 0.9rem; }
.t-empty { color: var(--text-dim); font-style: italic; }

/* Item/NPC rows with an illustration thumbnail (Epic 13) */
.t-list li.item-row,
.t-list li.npc-row {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
}
.t-list .row-info {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.t-value-badge {
  display: inline-block;
  background: var(--bg-header);
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 0 5px;
  font-size: 0.72rem;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  margin-left: 4px;
  vertical-align: middle;
}

/* Item modification (upgrade/damage/downgrade) indicator on an inventory row —
   see public/app.js's inventory render and server/ledger.js modifyInventory. */
.item-modified {
  cursor: help;
  color: var(--accent, var(--text-muted));
}

/* Epic 11: the pinned vehicle/mount row (the player's traveling base) and its
   badges — a vehicle/mount is just an inventory item, so this is styling
   only, not a separate entity. */
.item-row.item-ride {
  background: var(--bg-header);
  border-radius: 4px;
  padding: 0.2rem 0.3rem;
  margin: -0.2rem -0.3rem 0.3rem;
}
.item-ride-badge {
  color: var(--accent, var(--text-muted));
  font-weight: 700;
}
.item-type-badge {
  text-transform: capitalize;
  opacity: 0.75;
}

/* Epic 19 (Signature items): a collapsed "legend" expander showing an item's
   accrued deed history — see public/app.js's inventory render and
   server/ledger.js addItemLore. Starts collapsed; .open reveals the list. */
.item-lore-toggle {
  cursor: pointer;
  color: var(--accent, var(--text-muted));
  font-size: 0.78rem;
  display: inline-block;
  margin-top: 0.1rem;
}
.item-lore-list {
  display: none;
  margin: 0.2rem 0 0;
  padding-left: 1.1rem;
  font-size: 0.85rem;
  color: var(--text-muted);
}
.item-lore.open .item-lore-list {
  display: block;
}

.t-recap {
  font-size: 0.95rem;
  color: var(--text-muted);
  line-height: 1.6;
}

/* Header action button group */
.header-actions { display: flex; gap: 0.4rem; align-items: center; }

/* Secondary button (New World / Copy State) */
.btn-secondary {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-muted);
  border-radius: var(--radius);
  padding: 0.25rem 0.7rem;
  font-size: 0.78rem;
  cursor: pointer;
  transition: border-color 0.12s, color 0.12s;
}
.btn-secondary:hover {
  border-color: var(--text-muted);
  color: var(--text);
}

/* ---- Odds & Stakes: choice badges ---- */
.choice-btn { flex-wrap: wrap; }
.stakes { display: flex; gap: 0.35rem; flex-shrink: 0; flex-wrap: wrap; }
.badge {
  flex-shrink: 0;
  font-size: 0.64rem;
  letter-spacing: 0.03em;
  font-weight: 700;
  padding: 0.12rem 0.45rem;
  border-radius: 999px;
  border: 1px solid currentColor;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.badge.stat   { color: var(--text-muted, #b9a98f); }
.badge.chance { color: var(--accent); }
.badge.safe   { color: #4caf6b; }
.badge.reward-minor   { color: #6ea8b5; }
.badge.reward-major   { color: #4caf6b; }
.badge.reward-massive { color: var(--accent-gold); }
.badge.cost-trivial { color: #8b949e; }
.badge.cost-painful { color: #d9a521; }
.badge.cost-severe  { color: #e0533d; }
.badge.lethal {
  color: #fff;
  background: var(--accent-loss);
  border-color: var(--accent-loss);
  letter-spacing: 0.06em;
}
.choice-btn:disabled .badge { opacity: 0.4; }

/* A choice the DM flagged as lethal — telegraph the danger up front. */
.choice-btn.lethal {
  border-color: var(--accent-loss);
  box-shadow: inset 0 0 0 1px var(--accent-loss);
}

/* NPC-offered job/arc acquisition (Epic 13, Commit 5; Epic 15 renamed
 * "campaign" to "arc") — these carry no Odds & Stakes check (they hand off to
 * a fresh adventure forge instead of rolling), so they get their own distinct
 * look rather than the dice badges. .action-embark = a one-shot side job;
 * .action-arc = advances the current saga act, offered only by its key NPC. */
.choice-btn.action-embark,
.choice-btn.action-arc {
  flex-direction: column;
  align-items: stretch;
  gap: 0.3rem;
}
.choice-btn.action-embark { border-color: var(--accent-win); box-shadow: inset 0 0 0 1px var(--accent-win); }
.choice-btn.action-arc { border-color: var(--accent-gold); box-shadow: inset 0 0 0 1px var(--accent-gold); }
.choice-btn.action-embark .choice-label { color: var(--accent-win); font-weight: 600; }
.choice-btn.action-arc .choice-label { color: var(--accent-gold); font-weight: 600; }

/* Lethal-confirmation modal */
.lethal-confirm p { margin: 0 0 0.6rem; }
.lethal-confirm-actions,
.game-over-actions { display: flex; gap: 0.6rem; margin-top: 0.8rem; }
.lethal-confirm-actions .choice-btn,
.game-over-actions .choice-btn { flex: 1; }

/* Permanent-death panel */
.game-over-panel { text-align: center; padding: 1rem 0.5rem; }
.game-over-title { color: var(--accent-loss); margin: 0 0 0.5rem; }
.game-over-sub   { color: var(--text-muted, #b9a98f); margin: 0 0 0.4rem; }

/* Saga-victory panel (Epic 15) — reuses .game-over-panel's layout with a WIN
   palette, since it's the same "the story just reached a permanent milestone"
   shape as death, just the opposite outcome. */
.game-over-panel.victory .game-over-title { color: var(--accent-win); }

/* ---- Dice roll line in a story entry ---- */
.entry-roll {
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  margin-bottom: 0.5rem;
  padding: 0.25rem 0.5rem;
  border-radius: 4px;
  display: inline-block;
  border: 1px solid currentColor;
  font-variant-numeric: tabular-nums;
}
.degree-crit-success { color: var(--accent-gold); }
.degree-success      { color: var(--accent-win); }
.degree-setback      { color: #d9a521; }
.degree-failure      { color: #e0533d; }
.degree-crit-fail    { color: var(--accent-loss); }

/* ---- Mechanical change chips (credits/items/conditions/stats/reputation) ----
   Shown after a turn/milestone resolves, so the player doesn't have to
   cross-reference the character sheet to see what just changed. */
.entry-changes {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-top: 0.6rem;
}
.change-chip {
  font-size: 0.72rem;
  font-weight: 700;
  padding: 0.16rem 0.5rem;
  border-radius: 999px;
  border: 1px solid currentColor;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.change-chip.gain    { color: var(--accent-win); }
.change-chip.loss    { color: var(--accent-loss); }
.change-chip.neutral { color: #8b949e; }

/* ---- Character sheet additions ---- */
.stat-list li strong { display: flex; justify-content: space-between; }
.stat-mod { color: var(--text-muted); font-variant-numeric: tabular-nums; font-weight: 700; }
.stat-mod.pos { color: var(--accent-win); }
.stat-mod.neg { color: var(--accent-loss); }
.stat-base-strike { color: var(--text-muted); text-decoration: line-through;
  font-weight: 600; font-size: 0.85em; margin-left: 4px; }
.stat-affect { color: var(--text-muted); font-size: 0.72rem;
  font-variant-numeric: tabular-nums; }
.t-currency { font-size: 1rem; }
.currency-balance {
  display: inline-block; font-weight: 700; color: var(--accent-gold);
  font-variant-numeric: tabular-nums; margin-right: 0.5rem;
}
.currency-worth { display: block; color: var(--text-dim); font-size: 0.76rem; margin-top: 0.2rem; }
.attitude-badge {
  display: inline-block; margin-left: 6px; padding: 0 5px; border-radius: 999px;
  font-size: 0.7rem; font-weight: 700; border: 1px solid currentColor; vertical-align: middle;
}
.attitude-good    { color: var(--accent-win); }
.attitude-bad     { color: var(--accent-loss); }
.attitude-neutral { color: var(--text-muted); }

/* ---- Hub (Epic 5.3 → unified story-log scenes) ----
   The hub is no longer a separate full-board layout swap — it renders into
   the SAME #story-log / #choices-area as an adventure turn, so the character
   sidebar (.telemetry-panel) stays visible and hub interactions get the same
   inline scene-card art (.scene-card). See app.js renderHubMainScene/renderShopScene/etc. */
.hub-sub { color: var(--text-muted); font-size: 0.88rem; margin: 0 0 0.6rem; }
.hub-footer { display: flex; flex-direction: column; gap: 0.6rem; margin-top: 0.8rem; padding-top: 0.8rem; border-top: 1px solid var(--border); }
.seed-input {
  background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius);
  color: var(--text); padding: 0.5rem 0.7rem; font-size: 0.88rem; resize: vertical; outline: none;
}
.seed-input:focus { border-color: var(--accent); }
.hub-forge-btn {
  background: var(--btn-bg); color: var(--btn-txt); border: none; border-radius: var(--radius);
  padding: 0.7rem 1.2rem; font-size: 0.95rem; font-weight: 600; cursor: pointer; align-self: flex-start;
}
.hub-forge-btn:hover { background: var(--btn-hover); }
.past-list { list-style: none; display: flex; flex-direction: column; gap: 0.3rem; }
.past-list li { font-size: 0.84rem; color: var(--text-muted); }

/* ---- Modal ---- */
.modal-overlay {
  position: fixed; inset: 0; background: rgba(0,0,0,0.6);
  display: flex; align-items: center; justify-content: center; z-index: 50; padding: 1.5rem;
}
.modal {
  background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius);
  width: 100%; max-width: 600px; max-height: 85vh; display: flex; flex-direction: column; overflow: hidden;
}
/* Wide modal — for content that needs the room to breathe. */
.modal-overlay.wide .modal { max-width: 1000px; max-height: 92vh; }
.modal-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0.8rem 1.1rem; background: var(--bg-header); border-bottom: 1px solid var(--border);
}
.modal-title { font-family: var(--font-heading); font-size: 0.95rem; font-weight: 700; color: var(--text); }
.modal-body { padding: 1.4rem 1.5rem; overflow-y: auto; }
.muted { color: var(--text-dim); font-style: italic; font-size: 0.85rem; }

/* Milestone / hub / shop / tavern / visit choices — all rendered inline among
   the normal choice buttons (Epic 5.3: every interaction is a story-log
   scene, so they share one look instead of each having its own card/modal). */
.choices-heading { color: var(--text-muted); font-size: 0.9rem; margin: 0 0 0.2rem; }
.milestone-choice, .scene-choice { flex-direction: column; align-items: stretch; gap: 0.3rem; }
.milestone-choice .choice-label, .scene-choice .choice-label { flex: none; color: var(--accent); font-weight: 600; }
.milestone-choice .choice-desc, .scene-choice .choice-desc { color: var(--text-muted); font-size: 0.85rem; }
.milestone-effect { align-self: flex-start; margin-top: 0.15rem; padding: 0.1rem 0.5rem; border-radius: 999px;
  background: var(--accent-soft, rgba(127,127,127,0.15)); color: var(--accent); font-size: 0.8rem; font-weight: 600; }

/* Setup-screen "load existing" link */
.setup-load { margin-top: 1rem; color: var(--text-dim); font-size: 0.85rem; text-align: center; }
.link-btn { background: none; border: none; color: var(--accent); cursor: pointer; font: inherit; padding: 0; text-decoration: underline; }
.link-btn:hover { color: var(--accent-gold); }

/* Load World / Character menu */
.load-menu { display: flex; flex-direction: column; gap: 1rem; }
.load-newworld { align-self: stretch; background: var(--btn-bg); color: var(--btn-txt); border: none; border-radius: var(--radius); padding: 0.55rem 0.9rem; font-size: 0.85rem; font-weight: 600; cursor: pointer; }
.load-newworld:hover { background: var(--btn-hover); }
.load-world { background: var(--bg-entry); border: 1px solid var(--border); border-radius: var(--radius); padding: 1rem 1.1rem; display: flex; flex-direction: column; gap: 0.7rem; }
.load-world-head { display: flex; align-items: center; justify-content: space-between; gap: 0.8rem; }
.load-world-head strong { color: var(--accent); font-size: 0.95rem; }
.load-world-name { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.load-world-pill { background: var(--accent-soft, rgba(127,127,127,0.15)); color: var(--accent); border-radius: 999px; padding: 0.1rem 0.55rem; font-size: 0.7rem; font-weight: 600; }
.load-world-setting { color: var(--text-dim); font-size: 0.78rem; }
.load-directory-heading { color: var(--text-muted); font-size: 0.85rem; margin: 0.3rem 0 0; }
.load-newchar { background: transparent; border: 1px solid var(--accent); color: var(--accent); border-radius: var(--radius); padding: 0.25rem 0.7rem; font-size: 0.75rem; cursor: pointer; flex-shrink: 0; }
.load-newchar:hover { background: var(--bg-header); }
.load-char { display: flex; align-items: center; justify-content: space-between; gap: 0.8rem; background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius); padding: 0.7rem 0.9rem; }
.load-char.current { border-color: var(--accent); }
.load-char strong { font-size: 0.85rem; }
.load-char-meta { display: block; margin-top: 0.15rem; color: var(--text-muted); font-size: 0.75rem; }
.load-char-btn { background: var(--btn-bg); color: var(--btn-txt); border: none; border-radius: var(--radius); padding: 0.35rem 0.85rem; font-size: 0.8rem; font-weight: 600; cursor: pointer; flex-shrink: 0; }
.load-char-btn:hover { background: var(--btn-hover); }
.load-world-actions, .load-char-actions { display: flex; align-items: center; gap: 0.4rem; flex-shrink: 0; }
.load-delete { background: transparent; border: 1px solid var(--border); color: var(--text-muted); border-radius: var(--radius); padding: 0.25rem 0.5rem; font-size: 0.8rem; line-height: 1; cursor: pointer; flex-shrink: 0; }
.load-delete:hover { border-color: var(--danger, #c0392b); color: var(--danger, #c0392b); background: var(--bg-header); }
.load-char-locked { color: var(--text-dim); font-size: 0.78rem; flex-shrink: 0; }

/* Scrollbar (webkit) */
::-webkit-scrollbar        { width: 6px; }
::-webkit-scrollbar-track  { background: transparent; }
::-webkit-scrollbar-thumb  { background: var(--border); border-radius: 3px; }

/* ---- Tab strips (Epic 5.2) ----
   Left: Story / Lore·Log. Right: Location / Inventory / Character Sheet /
   Quests. Each `.tab-strip` is paired with the `.tab-panels` that follows it
   (app.js keys off that DOM adjacency, not an id). Replaces the old
   scroll-jump `#section-rail`. */
.tab-strip {
  display: flex;
  flex-shrink: 0;
  background: var(--bg-header);
  border-bottom: 1px solid var(--border);
}
.tab-strip .tab {
  flex: 1;
  padding: 0.55rem 0.6rem;
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  color: var(--text-muted);
  font-family: var(--font-heading);
  font-size: 0.74rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  cursor: pointer;
  transition: color 0.12s, border-color 0.12s;
}
.tab-strip .tab:hover  { color: var(--text); }
.tab-strip .tab.active { color: var(--accent); border-bottom-color: var(--accent); }

.tab-panels {
  flex: 1;
  min-height: 0;
}
.tab-panel {
  display: none;
  height: 100%;
  overflow-y: auto;
}
.tab-panel.active { display: block; }
/* The Story tab hosts #story-log, which does its own flex-column scrolling
   (so choices stay pinned at the bottom of the column) — let it, rather than
   the tab-panel, own the scrollbar. */
.tab-panel[data-panel="story"] { overflow: hidden; }
.tab-panel[data-panel="story"].active { display: flex; flex-direction: column; }

/* Arrow-key highlight (Epic 5.4) */
.choice-btn.kb-active {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent) inset;
}

/* Quests tab */
.t-quest-act {
  font-size: 0.85rem;
  color: var(--text-muted);
  margin-bottom: 0.6rem;
}
.quest-objectives li {
  display: flex;
  gap: 0.5rem;
  align-items: baseline;
}
.quest-mark { flex-shrink: 0; font-weight: 700; }
.quest-win .quest-mark  { color: var(--accent-win); }
.quest-loss .quest-mark { color: var(--accent-loss); }

/* Group headers ("To succeed" / "Avoid") splitting win vs. loss objectives —
   plain text, not the flex row the objective <li>s use. */
.quest-objectives li.quest-group-header {
  display: block;
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-top: 0.6rem;
  color: var(--text-muted);
}
.quest-objectives li.quest-group-header:first-child { margin-top: 0; }

/* The Saga (Epic 15) — a compact retrospective of the meta-story's acts:
   complete/active/locked, locked acts showing only "?" (never spoiling
   title/goal). Mirrors the quest-objectives list's spacing/typography. */
.saga-acts-list li {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  padding: 0.3rem 0;
}
.saga-acts-list li.saga-act-active strong { color: var(--accent-gold); }
.saga-acts-list li span { font-size: 0.8rem; color: var(--text-muted); }

/* ---- Responsive: collapse split-pane into one scroll ---- */
@media (max-width: 820px) {
  html, body { font-size: 17px; }

  #game-screen { height: auto; min-height: 100vh; display: block; }
  .split-pane { flex-direction: column; height: auto; }

  .story-panel, .telemetry-panel {
    height: auto;
    overflow: visible;
  }
  .story-panel { flex: none; border-right: none; border-bottom: 1px solid var(--border); }
  .telemetry-panel { flex: none; min-width: 0; max-width: none; }

  .story-log { flex: none; overflow: visible; min-height: 40vh; }
  .tab-panels { overflow: visible; height: auto; }
  .tab-panel.active { overflow: visible; height: auto; }

  /* Header / action buttons reflow */
  .panel-header, .game-header { flex-wrap: wrap; gap: 0.5rem; }
  .header-actions { flex-wrap: wrap; }

  .modal-overlay { padding: 0.75rem; }

  /* Odds & Stakes badges: drop to their own full-width row below the choice
     label so the badge group has a width to wrap against instead of pushing
     off the button's right edge — also keeps item-consuming choices (icon +
     short badge set) flowing the same as every other choice. */
  .choice-btn .stakes { flex-basis: 100%; min-width: 0; }

  /* Scene/premise prose reads too small next to the 1.05rem narrative body
     on a phone-width single column — bring it up to match. */
  .scene-card-desc, .goal-card-premise, .goal-card-goal, .chapter-card-blurb { font-size: 1rem; }

  /* NPC portrait: let prose wrap around a floated portrait instead of living
     in a permanently narrow flex column beside a fixed 64px image. */
  .story-entry .entry-body { display: block; }
  .story-entry .entry-body .art-slot.art-character {
    float: left;
    margin: 0 0.8rem 0.4rem 0;
  }
}

/* Release notes — shared by the "Latest updates" panel on the setup screen and
   the standalone release-notes.html page. */
.release-panel {
  margin-top: 2.5rem;
  padding-top: 1.6rem;
  border-top: 1px solid var(--border);
}
.release-panel-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1rem;
}
.release-panel-title {
  font-family: var(--font-heading);
  font-size: 1.3rem;
  font-weight: 700;
  color: var(--text);
  margin: 0;
}
.release-see-all {
  color: var(--accent);
  text-decoration: none;
  font-size: 0.9rem;
  white-space: nowrap;
}
.release-see-all:hover { text-decoration: underline; }

.release-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  margin: 0;
  padding: 0;
}
.release-day {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.9rem 1.1rem;
}
.release-day-date {
  font-family: var(--font-heading);
  font-weight: 700;
  color: var(--accent);
  font-size: 1.05rem;
  margin-bottom: 0.5rem;
}
.release-day-items {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
}
.release-item {
  display: grid;
  grid-template-columns: 8.5rem 1fr;
  align-items: baseline;
  column-gap: 0.6rem;
}
.release-item-title {
  color: var(--text-muted);
  font-size: 0.92rem;
}
.release-tag {
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 0.12rem 0.5rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--text-muted);
  text-align: center;
  white-space: nowrap;
  justify-self: start;
}
.release-tag-new            { color: var(--accent-win);  border-color: var(--accent-win); }
.release-tag-improved       { color: var(--accent);      border-color: var(--accent); }
.release-tag-fixed          { color: var(--accent-loss); border-color: var(--accent-loss); }
.release-tag-under-the-hood { color: var(--text-dim);    border-color: var(--text-dim); }

/* Standalone release-notes.html page shell */
.release-page {
  min-height: 100%;
  display: flex;
  justify-content: center;
  padding: 3rem 2rem;
}
.release-inner {
  width: 100%;
  max-width: 760px;
}
.release-back { margin-bottom: 1.4rem; }
.release-back a { color: var(--text-muted); text-decoration: none; font-size: 0.9rem; }
.release-back a:hover { color: var(--accent); }

/* ---------------------------------------------------------------------------
   Illustrations (Epic 13) — art.slot wraps a single <img>, sized/shaped by
   kind. Generated at fal-valid sizes (512x512 / 2048x512) and scaled down
   here via object-fit, so a missing/still-generating image just leaves an
   empty slot (imgEl() removes it entirely on final failure) — text-only is
   always a valid render.
--------------------------------------------------------------------------- */
.art-slot { display: block; flex-shrink: 0; overflow: hidden; }
.art-slot.loading {
  background: linear-gradient(90deg, var(--bg-header) 25%, var(--border) 50%, var(--bg-header) 75%);
  background-size: 200% 100%;
  animation: art-shimmer 1.4s ease-in-out infinite;
}
.art-slot.loading .art { opacity: 0; }
@keyframes art-shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .art-slot.loading { animation: none; background: var(--bg-header); }
}
.art {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: var(--bg-header);
  border: 1px solid var(--border);
}

.art-slot.art-item {
  width: 88px;
  height: 88px;
  border-radius: var(--radius);
}
.art-slot.art-item .art { border-radius: var(--radius); }

.art-slot.art-character {
  width: 88px;
  height: 88px;
  border-radius: 50%;
}
.art-slot.art-character .art { border-radius: 50%; }

/* Player portrait, pinned atop the character sheet. Rounded square rather than
   a circle — a circle mask clips the corners of the square generated image
   (hat brims, hair, shoulders), which reads as a cut-off avatar. */
.player-portrait { display: flex; flex-direction: column; align-items: center; gap: 0.5rem; margin-bottom: 0.9rem; }
.player-portrait .art-slot.art-character {
  width: 168px;
  height: 168px;
  border-radius: var(--radius);
}
.player-portrait .art-slot.art-character .art { border-radius: var(--radius); }
.player-portrait-name { font-weight: 600; letter-spacing: 0.02em; }

/* NPC portrait beside a story-log entry */
.story-entry .art-slot.art-character {
  width: 88px;
  height: 88px;
}

/* Scene card — an inline story-log entry printed whenever the scene changes
   (replaces the old persistent top banner, which obscured too much of the
   story pane). Same illustration, but it scrolls with the rest of the story
   instead of staying pinned. */
.scene-card {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--bg-entry);
  flex-shrink: 0;
}
.scene-card .art-slot.art-location {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 1;
  max-height: 260px;
}
.scene-card .art-slot.art-location .art { width: 100%; height: 100%; border: none; border-radius: 0; }
.scene-card-title {
  padding: 0.7rem 1.1rem 0.1rem;
  font-weight: 600;
  font-size: 1rem;
  color: var(--text);
}
.scene-card-desc {
  padding: 0.2rem 1.1rem 0.8rem;
  font-size: 0.85rem;
  line-height: 1.4;
  color: var(--text-muted);
}

/* Goal card — printed once right after a freshly-forged adventure's opening
   scene card, so the win objective(s) are visible inline instead of only in
   the Quests tab. Shares the scene-card's bordered-block language. */
.goal-card {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-entry);
  padding: 0.8rem 1.1rem;
  flex-shrink: 0;
}
.goal-card-premise {
  font-size: 0.85rem;
  line-height: 1.4;
  color: var(--text-muted);
  margin-bottom: 0.5rem;
}
.goal-card-goal {
  display: flex;
  gap: 0.5rem;
  align-items: baseline;
  font-size: 0.9rem;
  color: var(--text);
}
.goal-card-goal + .goal-card-goal { margin-top: 0.25rem; }

/* Chapter card (Epic 21, Adventure Chronicle) — the end-of-adventure keepsake:
   a climax illustration + the epilogue prose + a short "deeds" list. Printed
   inline at the adventure→hub transition (shares scene-card's bordered-block
   language) and reused, unstyled-body-only, inside the hub's chapter-detail
   modal (openChapterModal in app.js). */
.chapter-card {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--bg-entry);
  flex-shrink: 0;
}
.chapter-card .art-slot.art-location {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 1;
  max-height: 260px;
}
.chapter-card .art-slot.art-location .art { width: 100%; height: 100%; border: none; border-radius: 0; }
.chapter-card-title {
  padding: 0.7rem 1.1rem 0.1rem;
  font-weight: 600;
  font-size: 1rem;
  color: var(--text);
}
.chapter-card-blurb {
  padding: 0.2rem 1.1rem 0.8rem;
  font-size: 0.85rem;
  line-height: 1.4;
  color: var(--text-muted);
}
.chapter-card-deeds {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0 1.1rem 0.9rem;
  margin: 0;
  font-size: 0.84rem;
  color: var(--text);
}
.chapter-card-deeds li::before { content: '✦ '; color: var(--text-muted); }

/* A completed-adventure row in the hub's "past chapters" footer that has a
   chronicle — clickable to open the full chapter-detail modal (plain rows
   without a chronicle, e.g. pre-Epic-21 saves, stay static text). */
.past-list-chapter {
  cursor: pointer;
  text-decoration: underline;
  text-decoration-style: dotted;
  text-underline-offset: 2px;
}
.past-list-chapter:hover { color: var(--text); }
