/* webcore — THE LUCKY WHEEL's own sheet.
 * ===========================================================================
 * Owner-neutral, and TOKEN-ONLY. theme.css is the one sheet in an assembled
 * site allowed to decide a colour; every colour below is a role name, so a
 * palette change is one edit there and none here. `wheel.js` reads the same
 * roles through getComputedStyle, which is what keeps the canvas and the page
 * wearing one palette instead of two.
 *
 * WHY A SHEET OF ITS OWN. The dial is a stage — a bezel, a pawl, a hub, a
 * reveal card — and expressing that in site.css would push wheel-only rules
 * onto every page that loads it.
 *
 * ★ A DECLARATION OUTSIDE A RULE IS SILENT. A dropped selector leaves its
 * declarations at the top level, where a CSS parser discards them without a
 * word (memory law, 2026-08-09 — a background that was never DRAWN, not one
 * that was dimmed). Every block below opens and closes in one place, and
 * tests/frontend/test_wheel_page.py fails on a declaration outside a rule.
 *
 * REDUCED MOTION IS THE FINISHED PICTURE, never a shorter one: the transitions
 * here are removed rather than shortened, and the script lands the dial at its
 * final angle instead of walking to it.
 * ===========================================================================
 */

.iw-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  gap: clamp(1rem, 3vw, 2.5rem);
  align-items: start;
}

@media (max-width: 860px) {
  .iw-grid { grid-template-columns: minmax(0, 1fr); }
}

/* ---------------------------------------------------------------- the dial */

.iw-stage { min-width: 0; }

.iw-dial {
  position: relative;
  width: 100%;
  max-width: 34rem;
  margin-inline: auto;
  aspect-ratio: 1 / 1;
}

.iw-dial canvas {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: var(--r-round, 50%);
  /* The disc paints its OWN ground: a translucent page background showing
     through the machined cuts turns them into gaps. */
  background: var(--bg-deep);
  box-shadow: var(--shadow-panel);
}

.iw-dial.is-loading canvas { opacity: .55; }

/* The pawl. Its transform is written by the script every frame, so this rule
   must NOT also transition transform: two animations on one property is not a
   layering, it is a race, and the picture loses. */
.iw-pointer {
  position: absolute;
  top: -1.6%;
  left: 50%;
  width: 8%;
  min-width: 1.75rem;
  margin-left: -4%;
  z-index: 2;
  transform-origin: 50% 12%;
  color: var(--accent);
}

.iw-pointer svg { display: block; width: 100%; height: auto; }

/* The hub: the wheel's own plate, and where the result lands. */
.iw-hub {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 26%;
  height: 26%;
  margin: -13% 0 0 -13%;
  border-radius: var(--r-round, 50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .15rem;
  text-align: center;
  padding: .4rem;
  background: var(--surface-2);
  box-shadow: inset 0 0 0 1px var(--border), var(--shadow);
  color: var(--fg);
  z-index: 1;
}

.iw-hub .hk {
  font-size: clamp(.55rem, 1.4vw, .7rem);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--fg-mute);
  line-height: 1.1;
}

.iw-hub .hv {
  font-family: var(--font-display);
  font-size: clamp(.9rem, 2.6vw, 1.35rem);
  line-height: 1.05;
  overflow-wrap: anywhere;
}

.iw-hub.is-won {
  box-shadow: inset 0 0 0 1px var(--accent), var(--accent-glow);
}

.iw-hub.is-won .hv { color: var(--accent-hi); }

/* ------------------------------------------------------------- the console */

.iw-console {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.iw-bank {
  display: flex;
  align-items: center;
  gap: .65rem;
  padding: .7rem .9rem;
  border-radius: var(--r-s);
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--border);
}

.iw-bank-k {
  font-size: .74rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--fg-mute);
}

.iw-bank-v {
  font-family: var(--font-display);
  font-size: 1.35rem;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.iw-mute {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 0;
  border-radius: var(--r-round, 50%);
  cursor: pointer;
  color: var(--fg-dim);
  background: var(--surface-2);
}

.iw-mute:hover { color: var(--fg); }
.iw-mute svg { width: 1.1rem; height: 1.1rem; }
/* One icon, two states: the slash and the waves are the same drawing with one
   of the two hidden, so there is no second SVG to keep in step. */
.iw-mute .iw-mute-off { display: none; }
.iw-mute[data-off="1"] .iw-mute-on { display: none; }
.iw-mute[data-off="1"] .iw-mute-off { display: inline; }
.iw-mute[data-off="1"] { color: var(--fg-mute); }

.iw-state {
  margin: 0;
  min-height: 3.2em;
  line-height: 1.5;
}

.iw-state.calm { color: var(--fg-dim); }
.iw-state.bad { color: var(--bad); }
.iw-cd { font-variant-numeric: tabular-nums; font-weight: 700; }

.iw-actions { display: flex; flex-wrap: wrap; gap: .6rem; }
.iw-spin { min-width: 12rem; font-variant-numeric: tabular-nums; }

/* ★ `hidden` LOSES TO A CLASS THAT SETS display. `.btn` is `inline-flex`, and
   a class selector outranks the `[hidden]` UA rule, so every button this
   console hides was drawn anyway - all three states on screen at once, which
   is exactly the "which one am I looking at" confusion rule 5 of wheel.js
   exists to prevent. Caught in a rendered shot, not by any static gate. */
.iw-actions [hidden],
.iw-award[hidden] { display: none !important; }

/* ------------------------------------------------------------- the reveal */

.iw-award {
  border-radius: var(--r);
  padding: 1rem 1.1rem;
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--border-2);
  opacity: 0;
  transform: translateY(.4rem);
  transition: opacity .28s ease, transform .28s ease;
}

.iw-award.in { opacity: 1; transform: none; }

.iw-award-k {
  margin: 0 0 .25rem;
  font-size: .74rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--fg-mute);
}

.iw-award-v {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.3rem, 4vw, 1.9rem);
  line-height: 1.1;
  color: var(--accent-hi);
  overflow-wrap: anywhere;
}

.iw-award-s { margin: .35rem 0 0; color: var(--fg-dim); line-height: 1.5; }

/* -------------------------------------------------------------- the board */

.iw-recent {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: .35rem;
}

.iw-recent li {
  display: grid;
  grid-template-columns: minmax(4.5rem, auto) 1fr auto;
  gap: .75rem;
  align-items: baseline;
  padding: .5rem .75rem;
  border-radius: var(--r-xs);
  background: var(--surface);
}

.iw-amt {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--accent-hi);
}

.iw-who { min-width: 0; overflow-wrap: anywhere; }
.iw-when { font-size: .8rem; color: var(--fg-mute); white-space: nowrap; }

@media (max-width: 520px) {
  .iw-recent li { grid-template-columns: minmax(4rem, auto) 1fr; }
  .iw-when { grid-column: 1 / -1; }
}

/* The owner's parked sentences are never drawn; they exist for the script to
   read. `hidden` already does this — the rule is here so a stylesheet reset
   that drops the attribute's default cannot put a wall of copy on the page. */
.iw-copy { display: none !important; }

@media (prefers-reduced-motion: reduce) {
  .iw-award { transition: none; opacity: 1; transform: none; }
}
