:root {
  --ink: #EDE6D6;
  --ink-dim: #A9A392;
  --stone-900: #14161D;
  --stone-800: #1C1F29;
  --stone-700: #262A38;
  --stone-600: #343A4C;
  --gold: #C9A227;
  --gold-dim: #8A7328;
  --alliance: #3E7CB1;
  --alliance-dim: #274F70;
  --horde: #B23A2E;
  --horde-dim: #742620;
  --danger: #E08585;
  --ok: #7DBE8C;
  /* Guaranteed tank (story 17): a steel blue-grey, its own colour rather than
     any class's, the way --ok is the healer's. */
  --steel: #8FA7C2;

  /* Classic class colors — the values raid frames and addons use. Shaman's
     #0070DE only manages 3.8:1 against --stone-900, so it's lightened to
     #3D95FF (6.0:1) while still reading as "Shaman blue". */
  --class-warrior: #C79C6E;
  --class-paladin: #F58CBA;
  --class-hunter:  #ABD473;
  --class-rogue:   #FFF569;
  --class-priest:  #FFFFFF;
  --class-shaman:  #3D95FF;
  --class-mage:    #69CCF0;
  --class-warlock: #9482C9;
  --class-druid:   #FF7D0A;
}

/* A data-cls attribute picks the class color; everything downstream reads
   --cls-color, so JS never has to know a hex value. */
[data-cls="Warrior"] { --cls-color: var(--class-warrior); }
[data-cls="Paladin"] { --cls-color: var(--class-paladin); }
[data-cls="Hunter"]  { --cls-color: var(--class-hunter); }
[data-cls="Rogue"]   { --cls-color: var(--class-rogue); }
[data-cls="Priest"]  { --cls-color: var(--class-priest); }
[data-cls="Shaman"]  { --cls-color: var(--class-shaman); }
[data-cls="Mage"]    { --cls-color: var(--class-mage); }
[data-cls="Warlock"] { --cls-color: var(--class-warlock); }
[data-cls="Druid"]   { --cls-color: var(--class-druid); }

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  min-height: 100vh;
  background: var(--stone-900);
  color: var(--ink);
  font-family: 'Work Sans', sans-serif;
  overflow-x: hidden;
  transition: background 1.4s ease;
}

body.theme-alliance {
  background: linear-gradient(150deg, #05101c 0%, #0f2c4d 32%, #1f6bb0 60%, #0a1f33 100%);
}

body.theme-horde {
  background: linear-gradient(150deg, #140505 0%, #3d0d0d 32%, #a01818 60%, #240707 100%);
}

canvas#embers {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
}

.bg-wash {
  position: fixed;
  inset: 0;
  z-index: -1;
  opacity: 0;
  background: radial-gradient(ellipse at 50% 15%, rgba(201,162,39,0.22) 0%, rgba(20,22,29,0) 62%);
  transition: opacity 1.4s ease, background 1.4s ease;
}

.bg-wash.active.alliance {
  opacity: 1;
  background:
    radial-gradient(ellipse at 50% 10%, rgba(30,144,255,0.75) 0%, rgba(30,144,255,0.25) 45%, rgba(20,22,29,0) 85%),
    linear-gradient(180deg, rgba(20,80,160,0.35) 0%, rgba(20,22,29,0) 55%);
  animation: washPulse 3.2s ease-in-out infinite;
}

.bg-wash.active.horde {
  opacity: 1;
  background:
    radial-gradient(ellipse at 50% 10%, rgba(230,25,25,0.75) 0%, rgba(230,25,25,0.25) 45%, rgba(20,22,29,0) 85%),
    linear-gradient(180deg, rgba(160,20,20,0.35) 0%, rgba(20,22,29,0) 55%);
  animation: washPulse 3.2s ease-in-out infinite;
}

@keyframes washPulse {
  0%, 100% { opacity: 0.85; }
  50% { opacity: 1; }
}

.vignette {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: radial-gradient(ellipse at 50% 0%, transparent 0%, transparent 40%, rgba(0,0,0,0.55) 100%);
}

main {
  position: relative;
  z-index: 2;
  max-width: 880px;
  margin: 0 auto;
  padding: 4rem 1.5rem 5rem;
}

header {
  text-align: center;
  margin-bottom: 2.5rem;
}

h1 {
  font-family: 'Cinzel', serif;
  font-weight: 700;
  font-size: clamp(2rem, 5vw, 3rem);
  margin: 0 0 0.5rem;
  letter-spacing: 0.02em;
  color: var(--gold);
  text-shadow: 0 2px 12px rgba(201,162,39,0.25);
}

header p {
  color: var(--ink-dim);
  font-size: 1rem;
  margin: 0;
  max-width: 480px;
  margin-inline: auto;
  line-height: 1.6;
}

/* position: relative anchors the absolutely-positioned .mode-badge and
   .version-badge that sit in the board's top padding, left and right. */
.board {
  position: relative;
  background: linear-gradient(180deg, var(--stone-800), var(--stone-700));
  border: 1px solid var(--stone-600);
  border-radius: 4px;
  box-shadow: 0 20px 60px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.03);
  padding: 2rem;
}

.stage-label {
  text-align: center;
  font-family: 'Cinzel', serif;
  font-size: 0.85rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gold-dim);
  margin-bottom: 1.5rem;
}

.options-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 1.5rem;
  padding-bottom: 1.2rem;
  margin-bottom: 1.2rem;
  border-bottom: 1px solid var(--stone-600);
}

.field { display: flex; align-items: center; gap: 0.5rem; }
.field label { font-size: 0.85rem; color: var(--ink-dim); white-space: nowrap; }

.option-help {
  flex-basis: 100%;
  font-size: 0.78rem;
  color: var(--ink-dim);
  line-height: 1.5;
  margin: 0;
}

select {
  background: var(--stone-900);
  color: var(--ink);
  border: 1px solid var(--stone-600);
  border-radius: 4px;
  padding: 0.45rem 0.7rem;
  font-family: 'Work Sans', sans-serif;
  font-size: 0.9rem;
}

input[type="checkbox"] { accent-color: var(--gold); width: 16px; height: 16px; }

.setup-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 0.7rem;
}

.setup-row .num {
  width: 22px;
  text-align: right;
  color: var(--ink-dim);
  font-size: 0.85rem;
  flex-shrink: 0;
}

.setup-row input[type="text"] {
  flex: 1;
  background: var(--stone-900);
  color: var(--ink);
  border: 1px solid var(--stone-600);
  border-radius: 4px;
  padding: 0.5rem 0.7rem;
  font-family: 'Work Sans', sans-serif;
  font-size: 0.9rem;
}

.suggest-btn {
  background: var(--stone-700);
  border: 1px solid var(--stone-600);
  color: var(--ink-dim);
  border-radius: 4px;
  padding: 0.45rem 0.6rem;
  font-size: 0.8rem;
  cursor: pointer;
  white-space: nowrap;
  flex-shrink: 0;
}
.suggest-btn:hover { color: var(--ink); background: var(--stone-600); }

details.exclude { margin-bottom: 1.2rem; }
details.exclude summary { font-size: 0.85rem; color: var(--ink-dim); cursor: pointer; user-select: none; }
.exclude-grid { display: flex; flex-wrap: wrap; gap: 0.5rem 1.2rem; margin-top: 0.75rem; }
.exclude-grid label { display: flex; align-items: center; gap: 0.4rem; font-size: 0.82rem; color: var(--ink-dim); }

.big-btn {
  display: block;
  width: 100%;
  background: linear-gradient(180deg, var(--gold), var(--gold-dim));
  color: var(--stone-900);
  border: none;
  border-radius: 4px;
  padding: 0.85rem;
  font-family: 'Cinzel', serif;
  font-weight: 700;
  font-size: 1.05rem;
  letter-spacing: 0.04em;
  cursor: pointer;
  transition: transform 0.1s ease, box-shadow 0.15s ease;
  box-shadow: 0 4px 14px rgba(201,162,39,0.25);
  margin-top: 0.5rem;
}
.big-btn:hover { box-shadow: 0 6px 20px rgba(201,162,39,0.4); }
.big-btn:active { transform: scale(0.98); }
.big-btn:disabled { opacity: 0.35; cursor: not-allowed; box-shadow: none; }

.ghost-btn {
  display: block;
  width: 100%;
  background: transparent;
  color: var(--ink-dim);
  border: 1px solid var(--stone-600);
  border-radius: 4px;
  padding: 0.6rem;
  font-family: 'Work Sans', sans-serif;
  font-size: 0.85rem;
  cursor: pointer;
  margin-top: 0.6rem;
}
.ghost-btn:hover { color: var(--ink); border-color: var(--ink-dim); }

/* The roll button stays right-aligned; the reroll counter is pushed to the
   other end of the same row rather than taking a row of its own. */
.lazy-row {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.75rem;
  margin-bottom: 1rem;
}

.reroll-pool {
  margin-right: auto;
  font-size: 0.82rem;
  color: var(--gold);
  letter-spacing: 0.02em;
}

/* ---------- Run modes ---------- */
.mode-choice {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem;
  margin-bottom: 1.4rem;
}

.mode-card {
  flex: 1 1 220px;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  text-align: left;
  background: var(--stone-900);
  border: 1px solid var(--stone-600);
  border-radius: 4px;
  padding: 0.9rem 1rem;
  cursor: pointer;
  font-family: 'Work Sans', sans-serif;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.mode-card:hover { border-color: var(--ink-dim); }
.mode-card:focus-visible { outline: 1px solid var(--gold-dim); outline-offset: 2px; }

.mode-card .mode-name {
  font-family: 'Cinzel', serif;
  font-weight: 700;
  font-size: 1rem;
  letter-spacing: 0.04em;
  color: var(--ink-dim);
}

.mode-card .mode-desc {
  font-size: 0.78rem;
  line-height: 1.5;
  color: var(--ink-dim);
}

.mode-card.selected { background: rgba(201,162,39,0.08); border-color: var(--gold-dim); }
.mode-card.selected .mode-name { color: var(--gold); }
.mode-card.selected .mode-desc { color: var(--ink); }

.mode-card[data-mode="brutal"].selected {
  background: rgba(178,58,46,0.1);
  border-color: var(--horde);
}
.mode-card[data-mode="brutal"].selected .mode-name { color: #E8A79C; }

/* Rides in the board's top padding, so the mode shows on every stage without
   costing a row. It has to stay shorter than that 2rem of padding, or it clips
   the stage label once the label wraps on a phone. */
.mode-badge {
  position: absolute;
  top: 0.3rem;
  left: 0.5rem;
  z-index: 3;
  font-family: 'Cinzel', serif;
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 0.15rem 0.45rem;
  border: 1px solid var(--gold-dim);
  border-radius: 3px;
  color: var(--gold);
  line-height: 1.4;
}
.mode-badge.brutal { border-color: var(--horde); color: #E8A79C; }

/* ---------- Game version ---------- */
/* The landing screen. Deliberately heavier than the mode cards: this is the
   question that decides what everything later is drawn from. */
.version-choice {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
  margin-bottom: 1.2rem;
}

.version-card {
  flex: 1 1 240px;
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  text-align: left;
  background: var(--stone-900);
  border: 1px solid var(--stone-600);
  border-radius: 4px;
  padding: 1.3rem 1.2rem;
  cursor: pointer;
  font-family: 'Work Sans', sans-serif;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.version-card:hover { border-color: var(--ink-dim); }
.version-card:focus-visible { outline: 1px solid var(--gold-dim); outline-offset: 2px; }

.version-card .version-name {
  font-family: 'Cinzel', serif;
  font-weight: 700;
  font-size: 1.35rem;
  letter-spacing: 0.04em;
  color: var(--ink-dim);
}

.version-card .version-tag {
  font-family: 'Cinzel', serif;
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold-dim);
}

.version-card .version-desc {
  font-size: 0.8rem;
  line-height: 1.55;
  color: var(--ink-dim);
}

.version-card.selected { background: rgba(201,162,39,0.08); border-color: var(--gold-dim); }
.version-card.selected .version-name { color: var(--gold); }
.version-card.selected .version-desc { color: var(--ink); }

.version-stage-note {
  font-size: 0.78rem;
  color: var(--ink-dim);
  line-height: 1.5;
  margin: 0;
  text-align: center;
}

/* The misclick escape hatch at the top of setup. Compact on purpose — the
   choice was already made a screen ago; this only has to be findable. */
.version-switch {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.6rem;
  margin-bottom: 1.2rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--stone-600);
}

.version-switch-label {
  font-family: 'Cinzel', serif;
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold-dim);
}

.version-switch button {
  font-family: 'Cinzel', serif;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  padding: 0.25rem 0.7rem;
  background: var(--stone-900);
  border: 1px solid var(--stone-600);
  border-radius: 3px;
  color: var(--ink-dim);
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
}
.version-switch button:hover:not(:disabled) { border-color: var(--ink-dim); }
.version-switch button:focus-visible { outline: 1px solid var(--gold-dim); outline-offset: 2px; }
.version-switch button.selected {
  background: rgba(201,162,39,0.1);
  border-color: var(--gold-dim);
  color: var(--gold);
}
.version-switch button:disabled { cursor: default; opacity: 0.55; }

.version-switch-note {
  font-size: 0.75rem;
  color: var(--ink-dim);
  /* Pushed to its own end of the row so it never crowds the two buttons when
     the row wraps on a phone. */
  margin-left: auto;
}

/* Rides in the board's top padding opposite .mode-badge — the corner story 11
   freed up when the sound toggle was deleted. Same height budget: it has to
   stay shorter than that 2rem of padding or it clips a wrapped stage label. */
.version-badge {
  position: absolute;
  top: 0.3rem;
  right: 0.5rem;
  z-index: 3;
  font-family: 'Cinzel', serif;
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 0.15rem 0.45rem;
  border: 1px solid var(--gold-dim);
  border-radius: 3px;
  color: var(--gold);
  line-height: 1.4;
}

.names-later {
  font-size: 0.8rem;
  color: var(--ink-dim);
  line-height: 1.5;
  margin: 0 0 1.2rem;
}

.stage-note {
  font-size: 0.85rem;
  color: var(--ink-dim);
  text-align: center;
  line-height: 1.6;
  max-width: 480px;
  margin: 0 auto 1.2rem;
}

/* ---------- Pick order + claiming ---------- */
.drum.settled.gold { color: var(--gold); text-shadow: 0 0 24px rgba(201,162,39,0.45); }

.pick-order-list {
  list-style: none;
  counter-reset: pick;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
  margin: 0 0 1.2rem;
  padding: 0;
}

.pick-order-list li {
  counter-increment: pick;
  font-size: 0.82rem;
  color: var(--ink-dim);
  border: 1px solid var(--stone-600);
  border-radius: 3px;
  padding: 0.3rem 0.6rem;
}

.pick-order-list li::before {
  content: counter(pick) ". ";
  color: var(--gold-dim);
}

.pick-order-list li.current {
  color: var(--ink);
  border-color: var(--gold-dim);
  background: rgba(201,162,39,0.1);
}

.claim-turn {
  text-align: center;
  font-family: 'Cinzel', serif;
  font-size: 1rem;
  color: var(--gold);
  margin: 0 0 1.2rem;
}

/* A claimed hero stops competing for attention. */
.claim-card.claimed { opacity: 0.7; }
.claim-card.claimed .card-roll-btn { color: var(--ok); border-color: rgba(125,190,140,0.4); }

.result-mode {
  text-align: center;
  font-size: 0.8rem;
  color: var(--ink-dim);
  margin: 0 0 0.4rem;
}

.healer-panel {
  background: rgba(125,190,140,0.08);
  border: 1px solid rgba(125,190,140,0.3);
  border-radius: 4px;
  padding: 1rem;
  margin-bottom: 1.2rem;
  text-align: center;
}

.healer-toggle-label {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.9rem;
  color: var(--ink);
  cursor: pointer;
}

.healer-toggle-label input[type="checkbox"] {
  accent-color: #7DBE8C;
  width: 16px;
  height: 16px;
}

/* Two toggles now (story 17), one per line. */
/* Checkboxes in one column, the block centred in the panel. */
.healer-panel .healer-toggle-label {
  display: flex;
  justify-content: flex-start;
  text-align: left;
  width: fit-content;
  max-width: 100%;
  margin-left: auto;
  margin-right: auto;
}
.healer-panel .healer-toggle-label input[type="checkbox"] { flex: none; }
.healer-panel .healer-toggle-label + .healer-toggle-label { margin-top: 0.45rem; }
.tank-toggle-label input[type="checkbox"] { accent-color: var(--steel); }

.healer-note {
  font-size: 0.78rem;
  color: var(--ink-dim);
  line-height: 1.5;
  margin: 0.5rem 0 0;
}

/* ---------- Heroic Pack ---------- */
/* The same panel shape as the healer and profession options, in stone rather
   than green or gold: this one isn't a promise about a role or a choice about
   the roll, it's a fact about what the table owns. Hidden entirely on Classic. */
.pack-panel {
  background: rgba(255,255,255,0.03);
  border: 1px solid var(--stone-600);
  border-radius: 4px;
  padding: 1rem;
  margin-bottom: 1.2rem;
  text-align: center;
}

.pack-toggle-label {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.9rem;
  color: var(--ink);
  cursor: pointer;
}

.pack-toggle-label input[type="checkbox"] {
  accent-color: var(--gold);
  width: 16px;
  height: 16px;
}

.pack-note {
  font-size: 0.78rem;
  color: var(--ink-dim);
  line-height: 1.5;
  margin: 0.5rem 0 0;
}

/* ---------- Professions ---------- */
/* Same shape as the healer panel, in gold rather than healer green — it's an
   option about the roll, not a promise about a role. */
.prof-panel {
  background: rgba(201,162,39,0.06);
  border: 1px solid rgba(201,162,39,0.28);
  border-radius: 4px;
  padding: 1rem;
  margin-bottom: 1.2rem;
  text-align: center;
}

.prof-toggle-label {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.9rem;
  color: var(--ink);
  cursor: pointer;
}

.prof-suboptions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4rem 1.4rem;
  margin-top: 0.8rem;
}

.prof-check {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.82rem;
  color: var(--ink-dim);
  cursor: pointer;
}

.prof-note-setup {
  font-size: 0.78rem;
  color: var(--ink-dim);
  line-height: 1.5;
  margin: 0.6rem 0 0;
}

/* Two profession names on one line don't fit a 190px card at the value line's
   usual size, so this one stage runs smaller and is allowed to wrap. */
#professionGrid .card .value {
  font-size: 1rem;
  line-height: 1.35;
  min-height: 2.7em;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* The stage's own status line: what the options are doing, and what gathering
   still owes while the cards are being rolled. */
.prof-note {
  font-size: 0.82rem;
  color: var(--ink-dim);
  text-align: center;
  line-height: 1.6;
  max-width: 520px;
  margin: 0 auto 1rem;
}

/* Professions on a result or claim card: under the spec/class line, quieter
   than it, and never class-colored. */
.card .professions {
  font-size: 0.78rem;
  color: var(--gold-dim);
  letter-spacing: 0.02em;
  line-height: 1.4;
  margin: 0 0 0.2rem;
}

/* The healer designation picker went away with story 07 — Normal picks the
   slot at random and Brutal has no guarantee at all, so there is nobody left
   to designate. */
.healer-warning {
  font-size: 0.82rem;
  color: var(--danger);
  text-align: center;
  line-height: 1.5;
  margin: 0 0 1rem;
}

.lazy-btn {
  background: transparent;
  border: 1px solid var(--gold-dim);
  color: var(--gold);
  border-radius: 4px;
  padding: 0.4rem 0.8rem;
  font-size: 0.8rem;
  cursor: pointer;
  font-family: 'Work Sans', sans-serif;
}
.lazy-btn:hover { background: rgba(201,162,39,0.1); }

.faction-stage { text-align: center; padding: 1.5rem 0; position: relative; }

.faction-flash {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  transform: translate(-50%, -50%) scale(1);
  background: radial-gradient(circle, rgba(255,255,255,0.9) 0%, rgba(201,162,39,0.5) 35%, rgba(201,162,39,0) 70%);
  opacity: 0;
  pointer-events: none;
  z-index: 0;
}

.faction-flash.bang.alliance {
  background: radial-gradient(circle, rgba(255,255,255,0.95) 0%, rgba(62,124,177,0.6) 35%, rgba(62,124,177,0) 70%);
}
.faction-flash.bang.horde {
  background: radial-gradient(circle, rgba(255,255,255,0.95) 0%, rgba(178,58,46,0.6) 35%, rgba(178,58,46,0) 70%);
}

.faction-flash.bang {
  animation: flashBurst 0.6s ease-out forwards;
}

@keyframes flashBurst {
  0% { opacity: 0; transform: translate(-50%, -50%) scale(1); }
  15% { opacity: 1; }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(38); }
}

.drum {
  position: relative;
  z-index: 1;
  font-family: 'Cinzel', serif;
  font-size: clamp(1.8rem, 6vw, 2.6rem);
  font-weight: 700;
  color: var(--ink-dim);
  min-height: 3.2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  letter-spacing: 0.03em;
  transition: color 0.2s ease, text-shadow 0.3s ease;
}
.drum.settled.alliance { color: #9CC5E8; text-shadow: 0 0 24px rgba(62,124,177,0.5); }
.drum.settled.horde { color: #E8A79C; text-shadow: 0 0 24px rgba(178,58,46,0.5); }
.drum.spinning { animation: shake 0.08s infinite; }
.drum.bang { animation: bangPop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); }

@keyframes bangPop {
  0% { transform: scale(1); }
  35% { transform: scale(1.5); }
  60% { transform: scale(0.92); }
  100% { transform: scale(1); }
}

@keyframes shake {
  0% { transform: translateX(0); }
  50% { transform: translateX(2px); }
  100% { transform: translateX(-2px); }
}

.faction-caption {
  color: var(--ink-dim);
  font-size: 0.9rem;
  margin-top: 0.5rem;
  min-height: 1.3em;
}

.faction-choice-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem;
  margin-top: 0.5rem;
}

.faction-choice-row .big-btn { margin-top: 0; }

.choice-btn {
  flex: 1;
  min-width: 140px;
  border: 1px solid var(--stone-600);
  background: var(--stone-700);
  color: var(--ink);
  border-radius: 4px;
  padding: 0.85rem;
  font-family: 'Cinzel', serif;
  font-weight: 700;
  font-size: 0.95rem;
  letter-spacing: 0.03em;
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease, transform 0.1s ease;
}
.choice-btn:active:not(:disabled) { transform: scale(0.98); }

.choice-btn.alliance:hover:not(:disabled) { border-color: #3E7CB1; background: rgba(62,124,177,0.15); color: #9CC5E8; }
.choice-btn.horde:hover:not(:disabled) { border-color: #B23A2E; background: rgba(178,58,46,0.15); color: #E8A79C; }

.choice-btn:disabled { opacity: 0.45; cursor: not-allowed; }

.choice-reason {
  display: block;
  margin-top: 0.3rem;
  font-family: 'Work Sans', sans-serif;
  font-weight: 500;
  font-size: 0.75rem;
  letter-spacing: 0;
  color: var(--ink-dim);
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 1rem;
  margin-bottom: 1.2rem;
}

.card {
  background: var(--stone-900);
  border: 1px solid var(--stone-600);
  border-radius: 4px;
  padding: 1.1rem;
  position: relative;
  text-align: center;
  min-height: 128px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  transition: border-color 0.2s ease;
}

.card.done { border-color: var(--gold-dim); }

/* Rolled class cards and result cards take a muted tint of the class color
   instead of the gold border. Race cards keep the gold. Browsers without
   color-mix() just fall through to the rules above. */
.card.done[data-cls] {
  border-color: color-mix(in srgb, var(--cls-color) 42%, var(--stone-600));
  box-shadow: 0 0 18px -6px color-mix(in srgb, var(--cls-color) 55%, transparent);
}

.result-card[data-cls] {
  border-color: color-mix(in srgb, var(--cls-color) 32%, var(--stone-600));
}

/* ---------- Card landings ---------- */
/* Every card carries a --glow: gold by default, the class color once story
   03's data-cls is on it, healer green on the guaranteed healer's spec. One
   pair of keyframes then covers every color. */
.card { --glow: var(--gold); }
.card[data-cls] { --glow: var(--cls-color); }
.card.healer-slot { --glow: var(--ok); }
.card.tank-slot { --glow: var(--steel); }
/* A landing that spent the character's one reroll glows ash instead. Must
   stay after the two rules above so it wins the cascade. */
.card.landed-reroll { --glow: var(--ink-dim); }

/* The pulse rides on a pseudo-element so it can scale past the card's own
   border without disturbing layout or the border-color rules above. */
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 4px;
  border: 1px solid var(--glow);
  opacity: 0;
  pointer-events: none;
}

.card.landed::after,
.card.landed-reroll::after { animation: cardGlow 0.6s ease-out; }

@keyframes cardGlow {
  0%   { opacity: 0; transform: scale(1); box-shadow: 0 0 0 0 var(--glow); }
  18%  { opacity: 0.9; }
  100% { opacity: 0; transform: scale(1.07); box-shadow: 0 0 26px 6px transparent; }
}

.card .value.landed { animation: valuePop 0.45s cubic-bezier(0.34, 1.56, 0.64, 1); }
.card .value.landed-reroll { animation: valuePopSpent 0.55s cubic-bezier(0.34, 1.56, 0.64, 1); }

/* Smaller than the faction drum's bangPop — a card landing is a beat, not
   the headline. */
@keyframes valuePop {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.25); }
  62%  { transform: scale(0.96); }
  100% { transform: scale(1); }
}

/* Same beat, but the value drains to grey and snaps back, so the table sees
   the reroll was spent. */
@keyframes valuePopSpent {
  0%   { transform: scale(1); filter: saturate(0.15) brightness(0.7); }
  35%  { transform: scale(1.18); filter: saturate(0.15) brightness(0.7); }
  62%  { transform: scale(0.97); filter: saturate(0.15) brightness(0.7); }
  78%  { filter: saturate(0.15) brightness(0.7); }
  100% { transform: scale(1); filter: saturate(1) brightness(1); }
}

.card .name {
  font-size: 0.78rem;
  color: var(--ink-dim);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin: 0 0 0.5rem;
}

.healer-badge,
.tank-badge {
  display: inline-block;
  color: #7DBE8C;
  font-size: 0.9rem;
  text-transform: none;
  letter-spacing: normal;
}
.tank-badge { color: var(--steel); font-size: 0.8rem; }

.card .value {
  font-family: 'Cinzel', serif;
  font-size: 1.2rem;
  color: var(--ink);
  margin: 0;
  min-height: 1.5em;
  transition: color 0.2s ease;
}

.card .value.spinning { color: var(--ink-dim); }

/* A landed class name wears its class color. */
.card .value[data-cls] { color: var(--cls-color); }

/* The class spin flickers in class colors too, dimmed so it still reads as
   "still rolling". The color transition is dropped mid-spin — at ~100ms per
   tick it would otherwise smear one class color into the next. */
.card .value.spinning[data-cls] {
  color: var(--cls-color);
  opacity: 0.68;
  transition: none;
}

.card .sub {
  font-size: 0.82rem;
  color: var(--ink-dim);
  margin: 0.2rem 0 0.7rem;
}

/* Only the class word in a sub-line ("Holy Paladin", "Troll Shaman") is
   colored; the spec and race stay dim ink. */
.card .sub [data-cls] { color: var(--cls-color); }

.card-roll-btn {
  background: var(--stone-700);
  color: var(--ink);
  border: 1px solid var(--stone-600);
  border-radius: 4px;
  padding: 0.4rem;
  font-size: 0.82rem;
  cursor: pointer;
  font-family: 'Work Sans', sans-serif;
  margin-top: 0.6rem;
}
.card-roll-btn:hover { background: var(--stone-600); }
.card-roll-btn:disabled { opacity: 0.4; cursor: not-allowed; }

.result-card .value { color: var(--gold); }

/* ---------- Character names ---------- */
/* Directly editable, but wearing none of the browser's form chrome — it reads
   as the card's own text until you focus it.
   Deliberately NOT inside a flex row. The first version of this feature put
   the input and its die button in `display: flex` without `min-width: 0` on
   the input; a bare text input's intrinsic width is about 20 characters, wider
   than a 190px card's content box, and `flex: 1` grows but never shrinks, so
   the button was shoved clean outside the card. A block-level input with
   box-sizing: border-box cannot do that. min-width: 0 is here anyway, because
   the next person to wrap this in a flex row will need it. */
.card .charname-input {
  display: block;
  width: 100%;
  min-width: 0;
  box-sizing: border-box;
  background: transparent;
  border: none;
  border-bottom: 1px solid transparent;
  border-radius: 0;
  padding: 0.1rem 0.2rem;
  margin: 0 0 0.5rem;
  font-family: 'Cinzel', serif;
  font-size: 1rem;
  color: var(--ink);
  text-align: center;
  -webkit-appearance: none;
  appearance: none;
}

.card .charname-input::placeholder {
  color: var(--ink-dim);
  font-style: italic;
}

/* The underline is the only affordance, and only when you go looking for it. */
.card .charname-input:hover { border-bottom-color: var(--stone-600); }
.card .charname-input:focus {
  outline: none;
  border-bottom-color: var(--gold-dim);
}

/* Rerolled names pop like any other landing (story 05's playLanding). */
.card .charname-input.landed {
  animation: valuePop 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* Same background, border, radius and family as every other button on the
   board — just smaller, because a result card is read more than it is
   operated. Never an emoji glyph: the old 🎲 inherited none of this and the
   emoji font substituted a color glyph that fought the gold/ash palette. */
.charname-btn {
  margin-top: 0.5rem;
  padding: 0.28rem 0.4rem;
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  color: var(--ink-dim);
}
.charname-btn:hover { color: var(--ink); }

/* ---------- Party reveal ---------- */
/* Cards are dealt in one at a time. animation-fill-mode: both holds the
   "from" frame through the delay, so a card that hasn't been dealt yet stays
   invisible instead of flashing into place first. */
.result-card.deal-in {
  animation: dealIn 0.42s cubic-bezier(0.22, 0.61, 0.36, 1) both;
  animation-delay: var(--deal-delay, 0ms);
}

@keyframes dealIn {
  from { opacity: 0; transform: translateY(16px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* The flash is sized against the cards it is flashing behind, not against the
   whole stage — story 09 put a rating panel under the grid, and without this
   wrapper the ellipse would grow to cover that too. */
.result-reveal { position: relative; }
#resultGrid { position: relative; z-index: 1; }

/* The flash sits behind the grid — same idea as the faction flashBurst, but
   sized to the party rather than exploding from a point. */
.result-flash {
  position: absolute;
  top: 45%;
  left: 50%;
  width: 100%;
  height: 85%;
  border-radius: 50%;
  transform: translate(-50%, -50%) scale(0.4);
  background: radial-gradient(ellipse, rgba(255,255,255,0.55) 0%, rgba(201,162,39,0.5) 35%, rgba(201,162,39,0) 72%);
  opacity: 0;
  z-index: 0;
  pointer-events: none;
}

.result-flash.alliance {
  background: radial-gradient(ellipse, rgba(255,255,255,0.6) 0%, rgba(62,124,177,0.6) 35%, rgba(62,124,177,0) 72%);
}
.result-flash.horde {
  background: radial-gradient(ellipse, rgba(255,255,255,0.6) 0%, rgba(178,58,46,0.6) 35%, rgba(178,58,46,0) 72%);
}

.result-flash.bang { animation: revealFlash 0.5s ease-out forwards; }

@keyframes revealFlash {
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(0.4); }
  22%  { opacity: 1; }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(2.2); }
}

/* ---------- Party comp rating ---------- */
/* Bars stay gold, the way the fairness panel's do — story 03 deliberately kept
   class color off anything that isn't a class. */
.rating-panel {
  margin-top: 1.6rem;
  border: 1px solid var(--stone-600);
  border-top-color: var(--gold-dim);
  border-radius: 6px;
  background: rgba(0,0,0,0.18);
  padding: 1rem 1.1rem;
}

.rating-panel.rating-in {
  animation: ratingIn 0.5s cubic-bezier(0.22, 0.61, 0.36, 1) both;
  animation-delay: var(--rating-delay, 0ms);
}

@keyframes ratingIn {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}

.rating-head {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 0.8rem;
  /* Three items now, and the narrowest phone is 360px — wrapping is what
     keeps the version label inside the panel instead of beside it. */
  flex-wrap: wrap;
}

.rating-grade {
  font-family: 'Cinzel', serif;
  font-size: 2.6rem;
  line-height: 1;
  font-weight: 700;
  color: var(--ink);
}

/* A grade is not a class, so this is its own small scale: gold at the top,
   ash in the middle, danger red at the bottom. */
.rating-grade[data-grade="S"] { color: var(--gold); text-shadow: 0 0 22px rgba(201,162,39,0.55); }
.rating-grade[data-grade="A"] { color: var(--gold); }
.rating-grade[data-grade="B"] { color: var(--ink); }
.rating-grade[data-grade="C"] { color: var(--ink-dim); }
.rating-grade[data-grade="D"] { color: #C98A72; }
.rating-grade[data-grade="F"] { color: var(--danger); }

.rating-score {
  font-size: 0.9rem;
  color: var(--ink-dim);
  letter-spacing: 0.04em;
}

/* Which curve cut this letter. Sits with the score rather than under the
   verdict because it qualifies the grade, not the sentence about it — and a
   screenshot of the head alone should still say which game it is. */
.rating-version {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ink-dim);
  border: 1px solid var(--stone-600);
  border-radius: 3px;
  padding: 0.14rem 0.42rem;
  white-space: nowrap;
}

.rating-verdict {
  text-align: center;
  color: var(--ink);
  font-size: 0.92rem;
  line-height: 1.5;
  margin: 0.6rem auto 0;
  max-width: 44ch;
}

.rating-breakdown { margin-top: 0.9rem; }

.rating-breakdown summary {
  font-size: 0.78rem;
  color: var(--ink-dim);
  cursor: pointer;
  user-select: none;
  text-align: center;
}
.rating-breakdown summary:hover { color: var(--ink); }

.rating-axis { margin-top: 1rem; }

.rating-axis-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 0.8rem;
  margin-bottom: 0.35rem;
}

.rating-axis-head .label {
  font-family: 'Cinzel', serif;
  color: var(--gold-dim);
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.rating-axis-head .stat { color: var(--ink-dim); }

.rating-bar-track {
  position: relative;
  height: 10px;
  background: var(--stone-900);
  border: 1px solid var(--stone-600);
  border-radius: 3px;
  overflow: hidden;
}

.rating-bar-fill {
  position: absolute;
  top: 0; left: 0; bottom: 0;
  background: linear-gradient(90deg, var(--gold-dim), var(--gold));
}

.rating-notes {
  list-style: none;
  margin: 0.45rem 0 0;
  padding: 0;
}

.rating-notes li {
  font-size: 0.78rem;
  color: var(--ink-dim);
  line-height: 1.5;
  padding-left: 0.9rem;
  position: relative;
}

.rating-notes li::before {
  content: '\2022';
  position: absolute;
  left: 0;
  color: var(--gold-dim);
}

.rating-scale-note {
  font-size: 0.75rem;
  color: var(--ink-dim);
  text-align: center;
  margin: 1rem 0 0;
  font-style: italic;
}

.error {
  color: var(--danger);
  font-size: 0.85rem;
  margin-top: 1rem;
  min-height: 1.2em;
  text-align: center;
}

footer {
  text-align: center;
  margin-top: 2rem;
  color: var(--ink-dim);
  font-size: 0.8rem;
}

.debug-panel {
  margin-top: 2rem;
  border-top: 1px solid var(--stone-700);
  padding-top: 1rem;
}

.debug-panel summary {
  font-size: 0.8rem;
  color: var(--ink-dim);
  cursor: pointer;
  user-select: none;
  text-align: center;
}

.debug-note {
  font-size: 0.78rem;
  color: var(--ink-dim);
  text-align: center;
  max-width: 520px;
  margin: 0.8rem auto 1rem;
  line-height: 1.5;
}

.debug-settings {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.5rem;
  justify-content: center;
  align-items: center;
  margin-bottom: 1rem;
}

.debug-check {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.82rem;
  color: var(--ink-dim);
  cursor: pointer;
}

.debug-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  justify-content: center;
  margin-bottom: 1.2rem;
}

.debug-controls .ghost-btn {
  width: auto;
  padding: 0.5rem 1.2rem;
}

.debug-section {
  margin-bottom: 1.2rem;
}

.debug-section h4 {
  font-family: 'Cinzel', serif;
  font-size: 0.85rem;
  color: var(--gold-dim);
  text-align: center;
  margin: 0 0 0.7rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.debug-bar-row {
  display: grid;
  grid-template-columns: 90px 1fr 130px;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.8rem;
  margin-bottom: 0.4rem;
}

.debug-bar-row .label { color: var(--ink); text-align: right; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.debug-bar-track {
  position: relative;
  height: 14px;
  background: var(--stone-900);
  border: 1px solid var(--stone-600);
  border-radius: 3px;
  overflow: hidden;
}

.debug-bar-fill {
  position: absolute;
  top: 0; left: 0; bottom: 0;
  background: linear-gradient(90deg, var(--gold-dim), var(--gold));
}

.debug-bar-target {
  position: absolute;
  top: -2px; bottom: -2px;
  width: 2px;
  background: var(--ink);
  opacity: 0.7;
}

.debug-bar-row .stat { color: var(--ink-dim); white-space: nowrap; }

.debug-legend {
  font-size: 0.75rem;
  color: var(--ink-dim);
  text-align: center;
  margin-top: 0.5rem;
}

/* ---------- Reduced motion ---------- */
/* Everything that pops, bursts, shakes or deals becomes a plain fade. The
   drum's shake is in here too — it predates this rule and used to ignore the
   setting entirely. The ember burst is skipped in script.js, which reads the
   same media query. */
@media (prefers-reduced-motion: reduce) {
  .drum.spinning { animation: none; }
  .drum.bang { animation: softFade 0.4s ease-out; }
  .bg-wash.active.alliance,
  .bg-wash.active.horde { animation: none; }
  .faction-flash.bang { animation: staticFlash 0.5s ease-out forwards; }

  .card .value.landed,
  .card .value.landed-reroll { animation: softFade 0.4s ease-out; }
  .card.landed::after,
  .card.landed-reroll::after { animation: softGlow 0.5s ease-out; }
  .card .charname-input.landed { animation: softFade 0.4s ease-out; }

  .result-card.deal-in {
    animation: softFade 0.35s ease-out both;
    animation-delay: var(--deal-delay, 0ms);
  }
  .result-flash.bang { animation: softAreaFlash 0.5s ease-out forwards; }

  .rating-panel.rating-in {
    animation: softFade 0.4s ease-out both;
    animation-delay: var(--rating-delay, 0ms);
  }

  .big-btn:active { transform: none; }
  .choice-btn:active:not(:disabled) { transform: none; }
}

@keyframes softFade {
  from { opacity: 0.25; }
  to   { opacity: 1; }
}

@keyframes softGlow {
  0%   { opacity: 0; }
  30%  { opacity: 0.5; }
  100% { opacity: 0; }
}

/* The faction flash is a 10px dot that normally scales to fill the stage;
   held at a fixed size it can fade without ever moving. */
@keyframes staticFlash {
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(22); }
  25%  { opacity: 0.5; transform: translate(-50%, -50%) scale(22); }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(22); }
}

@keyframes softAreaFlash {
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(1.3); }
  25%  { opacity: 0.55; transform: translate(-50%, -50%) scale(1.3); }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(1.3); }
}

.hidden { display: none !important; }
