/* Layout: gold-framed board on the left, the duel stage and score ledger on the right; on phones the stage sits on top, the board below, touch buttons last */
:root {
  color-scheme: dark;
  --night: #0d0a1b;
  --stone: #1a1430;
  --slate: #231b3f;
  --rule: #3b2f63;
  --edge: #140c24;
  --ink: #f3ecff;
  --muted: #a99cd0;
  --gold: #f2c14b;
  --lumi: #8aa6ff;
  --sable: #ff8a9b;
  --danger: #ff5a78;
  --font-title: "Jacquard 12", "Old English Text MT", Georgia, serif;
  --font-ui: "Pixelify Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-num: "Silkscreen", "Courier New", monospace;
}
* { box-sizing: border-box; }
[hidden] { display: none !important; }
html, body { height: 100%; }
body {
  margin: 0;
  background:
    radial-gradient(ellipse at 50% -10%, rgba(120, 90, 220, 0.22), transparent 60%),
    var(--night);
  color: var(--ink);
  font: 400 16px/1.45 var(--font-ui);
}
canvas { display: block; image-rendering: pixelated; image-rendering: crisp-edges; }
button { font: inherit; color: inherit; }
:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }

/* Spells flying from board to board, over everything but the menus. */
.flight { position: fixed; inset: 0; z-index: 5; width: 100%; height: 100%; pointer-events: none; image-rendering: auto; }

/* Phones: stage on top, board(s) below, touch buttons last. Wide screens: boards on the outside, the
   stage window and the ledger in a center column between them, as in Tetris Attack. */
.game {
  position: relative;
  z-index: 1;
  min-height: 100%;
  display: grid;
  justify-content: center;
  align-content: start;
  justify-items: center;
  gap: 14px;
  padding-block: 16px 28px;
  padding-inline: 16px;
  grid-template-areas: "stage" "ledger" "side" "p1" "ctrl";
}
/* The wide hall spans the top; boards (and the score ledger) sit below it. */
body.is-versus .game { grid-template-columns: auto auto; grid-template-areas: "stage stage" "p1 p2" "side side" "ctrl ctrl"; column-gap: 12px; }
body.is-wide .game {
  height: 100%;
  align-content: center;
  align-items: start;
  column-gap: 28px;
  row-gap: 14px;
  padding-block: 12px;
  grid-template-columns: auto auto;
  grid-template-areas: "p1 center" "ctrl ctrl";
}
body.is-wide.is-versus .game { grid-template-columns: auto auto auto; grid-template-areas: "p1 center p2" "ctrl ctrl ctrl"; }
body.is-wide .board-col { align-self: center; }
body.is-wide .board-tag { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
/* Phones: the center column dissolves and its parts stack in the page grid. */
.center-col { display: contents; }
/* Wide screens: the column is exactly as tall as the boards (its own content never stretches the
   row), and the stage window sits in its middle, level with the middle of the boards: the ledger
   above it, the stop bar, sound and keys below. The top padding skips the name tag over each board. */
body.is-wide .center-col {
  grid-area: center;
  align-self: stretch;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto minmax(0, 1fr);
  gap: 14px;
  padding-top: 22px;
  contain: size;
}
/* Short wide screens: the keyboard help steps aside so the center column fits. */
@media (max-height: 720px) { body.is-wide .help { display: none; } }
.stage-col { grid-area: stage; display: grid; justify-items: center; }
.p1 { grid-area: p1; }
.p2 { grid-area: p2; }
.ledger { grid-area: ledger; display: grid; width: 100%; max-width: 560px; }
.side-col { grid-area: side; display: grid; gap: 14px; width: 100%; max-width: 560px; justify-items: center; }
body.is-wide .ledger, body.is-wide .stage-col, body.is-wide .side-col { grid-area: auto; max-width: none; }
body.is-wide .ledger { align-self: end; }
body.is-wide .side-col { justify-items: stretch; align-self: start; }
/* Phones in Versus: the stage carries both gauges, so the ledger steps aside to fit both boards. */
body.is-versus:not(.is-wide) .ledger, body.is-versus:not(.is-wide) .hud, body.is-versus:not(.is-wide) .stop { display: none; }
/* Short wide screens: tighter tiles and spacing so the window keeps its full width. */
@media (max-height: 760px) {
  body.is-wide .center-col, body.is-wide .side-col { gap: 8px; }
  body.is-wide .hud { gap: 6px; }
  body.is-wide .tile { padding: 4px 8px; gap: 0; }
  body.is-wide .tile .lbl { font-size: 11px; }
  body.is-wide .tile b { font-size: 16px; }
  body.is-wide .tile.score b { font-size: 22px; }
  body.is-wide .tile .lbl { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
}
body.is-wide .tile { padding-inline: 8px; }
/* In the narrow center column the volume slider speaks for itself, keeping the sound row on one line. */
body.is-wide .side-col .vol .lbl { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.board-col { display: grid; justify-items: center; align-content: end; gap: 8px; }
/* The two boards line up even when one name wraps onto two lines. */
body.is-versus .board-col { align-self: end; }
.board-tag { margin: 0; font: 400 14px/1 var(--font-num); letter-spacing: 0.04em; }
.board-tag.lumi { color: var(--lumi); }
.board-tag.sable { color: var(--sable); }
.board-frame.rival { border-color: #c9d0e0; }

/* Each board sits in a row with its ultimate gauge on the outer side: left of yours, right of the rival's. */
.board-row { display: flex; align-items: stretch; gap: var(--gauge-gap); }
:root { --gauge-w: 30px; --gauge-gap: 10px; }
body:not(.is-wide) { --gauge-w: 20px; --gauge-gap: 6px; }

/* Ultimate gauge: a tall bar the height of the board, filling from the bottom in the mage's colors
   (set from the element palette), with quarter marks and the ultimate's name running up it. */
.ult-gauge {
  --g: #9457e2; --gd: #3b2160; --gl: #f1e2ff;
  position: relative;
  flex: none;
  width: var(--gauge-w);
  background: var(--edge);
  border: 3px solid var(--rule);
  box-shadow: 0 0 0 2px var(--edge), inset 0 0 8px rgba(0, 0, 0, 0.6);
  overflow: hidden;
}
.ult-gauge i { position: absolute; inset: auto 0 0 0; height: 0; background: linear-gradient(0deg, var(--gd), var(--g)); transition: height 0.12s linear; }
.ult-gauge i::after { content: ""; position: absolute; inset: 0 0 auto 0; height: 3px; background: var(--gl); opacity: 0.8; }
/* quarter marks over the fill */
.ult-gauge::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(0deg, transparent calc(25% - 1px), rgba(20, 12, 36, 0.75) calc(25% - 1px), rgba(20, 12, 36, 0.75) 25%, transparent 25%) 0 0 / 100% 100%,
    linear-gradient(0deg, transparent calc(50% - 1px), rgba(20, 12, 36, 0.75) calc(50% - 1px), rgba(20, 12, 36, 0.75) 50%, transparent 50%) 0 0 / 100% 100%,
    linear-gradient(0deg, transparent calc(75% - 1px), rgba(20, 12, 36, 0.75) calc(75% - 1px), rgba(20, 12, 36, 0.75) 75%, transparent 75%) 0 0 / 100% 100%;
  pointer-events: none;
}
.ult-gauge span {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  writing-mode: vertical-rl;
  transform: rotate(180deg); /* reads bottom to top */
  font: 400 12px/1 var(--font-num);
  letter-spacing: 0.14em;
  white-space: nowrap;
  overflow: hidden;
  color: var(--ink);
  text-shadow: 1px 0 0 var(--edge), -1px 0 0 var(--edge), 0 1px 0 var(--edge), 0 -1px 0 var(--edge);
}
body:not(.is-wide) .ult-gauge span { font-size: 10px; letter-spacing: 0.08em; }
.ult-gauge.is-ready { border-color: var(--gl); animation: ult-glow 0.9s ease-in-out infinite alternate; }
.ult-gauge.is-ready i { background: linear-gradient(0deg, var(--g), var(--gl), var(--g)); background-size: 100% 200%; animation: ult-shine 1.2s linear infinite; }
@keyframes ult-glow {
  from { box-shadow: 0 0 0 2px var(--edge), 0 0 8px 2px var(--g); }
  to { box-shadow: 0 0 0 2px var(--edge), 0 0 24px 8px var(--gl); }
}
@keyframes ult-shine { to { background-position: 0 -200%; } }
/* A quick flash when Attunement charges the gauge. */
.ult-gauge.is-charged i { filter: brightness(1.8); }
.ult-gauge.is-charged { border-color: var(--gl); }
@media (prefers-reduced-motion: reduce) {
  .ult-gauge.is-ready, .ult-gauge.is-ready i { animation: none; }
  .ult-gauge.is-ready { box-shadow: 0 0 0 2px var(--edge), 0 0 12px 4px var(--gl); }
}

/* Ornate frames around the boards; the mages' stage has none (they stand on the page itself). */
.board-frame {
  background: linear-gradient(180deg, #3b2f63, #1d1638);
  border: 3px solid var(--gold);
  box-shadow: 0 0 0 3px var(--edge), 0 0 0 5px #6b5a8e, 0 24px 60px rgba(0, 0, 0, 0.55);
}
.board-frame { padding: 5px; touch-action: none; }
.stage-frame { justify-self: center; }
#board { cursor: grab; outline: none; }
body.is-danger .board-frame { border-color: var(--danger); animation: alarm 0.5s steps(2) infinite; }
@keyframes alarm { 50% { box-shadow: 0 0 0 3px var(--edge), 0 0 0 5px var(--danger), 0 0 40px rgba(255, 90, 120, 0.5); } }
@media (prefers-reduced-motion: reduce) { body.is-danger .board-frame { animation: none; } }

/* Score ledger */
.hud { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; width: 100%; }
.tile {
  display: grid;
  gap: 2px;
  padding: 8px 12px;
  background: var(--stone);
  border: 2px solid var(--rule);
}
.tile.score { grid-column: 1 / -1; grid-template-columns: auto 1fr; align-items: baseline; gap: 12px; border-color: #5b4a8e; }
.lbl { font-size: 13px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
.tile b { font: 400 18px/1.2 var(--font-num); font-variant-numeric: tabular-nums; color: var(--ink); }
.tile.score b { justify-self: end; font-size: 28px; color: var(--gold); }
.stop { display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 12px; width: 100%; opacity: 0.45; transition: opacity 0.2s; }
.stop.is-on { opacity: 1; }
.stop-track { height: 8px; background: var(--edge); border: 2px solid var(--rule); }
.stop-track i { display: block; height: 100%; width: 0; background: linear-gradient(90deg, #7fe9ff, #c9b4ff); }

.sound-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 8px 10px; }
.chip {
  padding: 6px 12px;
  font-size: 14px;
  color: var(--muted);
  background: var(--edge);
  border: 2px solid var(--rule);
  cursor: pointer;
}
.chip[aria-pressed="true"] { color: var(--ink); background: var(--rule); border-color: #5b4a8e; }
.chip[aria-pressed="false"] { text-decoration: line-through; }
.vol { display: inline-flex; align-items: center; gap: 8px; }
.vol input { width: 110px; accent-color: var(--gold); }
.help { margin: 0; font-size: 14px; color: var(--muted); }
.help kbd {
  font: 400 12px var(--font-num);
  color: var(--ink);
  padding: 1px 6px;
  border: 2px solid var(--rule);
  background: var(--stone);
}
body:not(.is-wide) .help { display: none; }

/* Touch controls */
.touch-controls { grid-area: ctrl; display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; }
#btn-ult.is-ready { background: var(--gold); color: #1a1022; border-color: var(--gold); animation: ready 0.8s steps(2) infinite; }
@keyframes ready { 50% { background: #fff1b8; } }
@media (prefers-reduced-motion: reduce) { #btn-ult.is-ready { animation: none; } }
body.is-wide .touch-controls { display: none; }
@media (pointer: coarse) { body.is-wide .touch-controls { display: flex; } }
.touch-controls button {
  min-width: 120px;
  padding: 14px 20px;
  font-size: 18px;
  background: var(--slate);
  border: 2px solid var(--rule);
  box-shadow: inset 0 -4px 0 rgba(0, 0, 0, 0.3);
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}
.touch-controls button:active { transform: translateY(2px); box-shadow: inset 0 -2px 0 rgba(0, 0, 0, 0.3); }

/* Screens */
.screen {
  position: fixed;
  inset: 0;
  z-index: 10;
  display: grid;
  place-items: center;
  padding: 16px;
  background: rgba(8, 5, 18, 0.7);
  backdrop-filter: blur(3px);
}
.card {
  width: min(100%, 440px);
  max-height: 100%;
  overflow-y: auto;
  display: grid;
  gap: 18px;
  padding: 26px 24px;
  text-align: center;
  background: var(--stone);
  border: 3px solid var(--gold);
  box-shadow: 0 0 0 3px var(--edge), 0 0 0 5px #6b5a8e, 0 30px 80px rgba(0, 0, 0, 0.6);
}
.card p { margin: 0; }
.title {
  margin: 0;
  font: 400 clamp(46px, 11vw, 64px)/0.9 var(--font-title);
  color: var(--gold);
  text-shadow: 3px 3px 0 var(--edge);
  text-wrap: balance;
}
.subtitle { color: var(--muted); }
.card h2 { margin: 0; font: 400 40px/1 var(--font-title); color: var(--gold); text-shadow: 2px 2px 0 var(--edge); }
.field { display: grid; gap: 8px; justify-items: center; }
.seg { display: inline-flex; border: 2px solid var(--rule); background: var(--edge); }
.seg button {
  padding: 10px 16px;
  border: 0;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.seg button[aria-pressed="true"] { background: var(--rule); color: var(--ink); }
.stepper { display: inline-flex; align-items: center; border: 2px solid var(--rule); background: var(--edge); }
.stepper button { width: 44px; height: 40px; border: 0; background: transparent; font: 400 20px var(--font-num); cursor: pointer; }
.stepper button:disabled { color: var(--rule); cursor: default; }
.stepper output { min-width: 3ch; font: 400 20px var(--font-num); }
.btn {
  justify-self: center;
  min-width: 200px;
  padding: 13px 26px;
  font-size: 20px;
  font-weight: 600;
  color: #1a1022;
  background: var(--gold);
  border: 0;
  box-shadow: inset 0 -4px 0 rgba(0, 0, 0, 0.25), 0 0 0 2px var(--edge);
  cursor: pointer;
}
.btn:hover { background: #ffd56e; }
.btn:active { transform: translateY(2px); box-shadow: inset 0 -2px 0 rgba(0, 0, 0, 0.25), 0 0 0 2px var(--edge); }
.btn.ghost { color: var(--ink); background: transparent; box-shadow: inset 0 0 0 2px var(--rule); }
.btn.ghost:hover { background: var(--slate); }
.btn-row { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }
.keys { display: grid; grid-template-columns: auto auto; justify-content: center; gap: 6px 14px; font-size: 14px; color: var(--muted); text-align: left; }
.keys dt { color: var(--ink); font: 400 12px/1.8 var(--font-num); }
.keys dd { margin: 0; }
.results { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.results .tile b { font-size: 16px; }
.results .tile.score b { font-size: 30px; }
.note { color: var(--gold); font-size: 15px; }

/* Title: mode choice */
.mode-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 10px; }
.mode {
  display: grid;
  gap: 6px;
  padding: 16px;
  text-align: left;
  background: var(--slate);
  border: 2px solid var(--rule);
  box-shadow: inset 0 -4px 0 rgba(0, 0, 0, 0.3);
  cursor: pointer;
}
.mode b { font: 400 34px/1 var(--font-title); color: var(--gold); }
.mode span { font-size: 14px; color: var(--muted); }
.mode:hover { border-color: var(--gold); }

/* Versus setup: element cards */
.card.wide { width: min(100%, 940px); }
.elements { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 10px; }
.element {
  display: grid;
  align-content: start;
  justify-items: start;
  gap: 6px;
  padding: 12px;
  text-align: left;
  background: var(--slate);
  border: 2px solid var(--rule);
  cursor: pointer;
}
.element img { width: 32px; height: 32px; image-rendering: pixelated; }
.element img.portrait { width: auto; height: 84px; image-rendering: auto; }
#stage { image-rendering: auto; } /* drawn at screen resolution; no stretching needed */
.element b { font: 400 30px/1 var(--font-title); color: var(--ink); }
.element .pas, .element .ult { font-size: 13px; line-height: 1.35; color: var(--muted); }
.element .ult { color: var(--ink); }
.element[aria-pressed="true"] { border-color: var(--gold); box-shadow: 0 0 0 2px var(--gold); background: #2c2250; }
.element[aria-pressed="true"] b { color: var(--gold); }
.hint { margin: 0; font-size: 14px; color: var(--muted); }
.hint kbd { font: 400 12px var(--font-num); color: var(--ink); padding: 1px 6px; border: 2px solid var(--rule); background: var(--edge); }
.setup-row { display: flex; flex-wrap: wrap; justify-content: center; gap: 16px 24px; }
.seg { flex-wrap: wrap; justify-content: center; }
.sr { position: absolute; top: 0; left: 0; width: 1px; height: 1px; margin: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* After a duel: hide the result panel to look at the boards, then bring it back. */
.card { position: relative; }
.card:has(> .peek) { padding-top: 46px; }
.peek {
  position: absolute;
  top: 10px;
  right: 10px;
  padding: 4px 10px;
  font-size: 13px;
  color: var(--muted);
  background: var(--edge);
  border: 2px solid var(--rule);
  cursor: pointer;
}
.peek:hover, .peek:focus-visible { color: var(--ink); border-color: var(--gold); }
.screen.is-peeking { background: transparent; backdrop-filter: none; pointer-events: none; }
.screen.is-peeking > .card { visibility: hidden; }
.peek-back {
  position: fixed;
  left: 50%;
  bottom: max(16px, env(safe-area-inset-bottom));
  z-index: 11;
  min-width: 0;
  transform: translateX(-50%);
}
.peek-back:active { transform: translate(-50%, 2px); }

/* Online: title card's third mode spans the row */
#screen-title .mode-row > :nth-child(3) { grid-column: 1 / -1; }
#room-ready[aria-pressed="true"] { color: var(--ink); background: transparent; box-shadow: inset 0 0 0 2px #8fe0a8; }

/* Online: create or join */
.mode.join { cursor: default; align-content: start; }
.mode.join:hover { border-color: var(--rule); }
.mode.join:focus-within { border-color: var(--gold); }
.join-row { display: flex; gap: 8px; align-items: stretch; }
.join-row input {
  width: 0;
  flex: 1;
  min-width: 0;
  padding: 6px 10px;
  font: 400 22px var(--font-num);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink);
  background: var(--edge);
  border: 2px solid var(--rule);
}
.join-row input:focus { outline: none; border-color: var(--gold); }
.join-row .chip { color: var(--ink); }

/* The player's name (title screen): shown to online rivals and on the stats page. */
.name-field { display: flex; align-items: center; justify-content: center; gap: 10px; margin: 0 0 14px; }
.name-field input {
  width: min(220px, 60vw);
  padding: 5px 10px;
  font: 400 16px var(--font-num);
  color: var(--ink);
  background: var(--edge);
  border: 2px solid var(--rule);
}
.name-field input:focus { outline: none; border-color: var(--gold); }

/* Online: the room */
.room-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 10px 16px; }
.code { font: 400 32px/1 var(--font-num); letter-spacing: 0.15em; color: var(--ink); text-shadow: none; }
.players { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr)); gap: 10px; }
.player {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 92px;
  padding: 10px 14px;
  text-align: left;
  background: var(--slate);
  border: 2px solid var(--rule);
}
.player img { height: 72px; width: auto; image-rendering: auto; }
.player-text { display: grid; gap: 4px; }
.player .who { font: 400 26px/1 var(--font-title); color: var(--ink); overflow-wrap: anywhere; }
.player .mage { font-size: 14px; color: var(--muted); }
.player.is-empty { border-style: dashed; }
.badge { justify-self: start; padding: 2px 8px; font: 400 12px/1.6 var(--font-num); color: var(--muted); border: 2px solid var(--rule); background: var(--edge); }
.badge.is-ready { color: #1a1022; background: #8fe0a8; border-color: #8fe0a8; }
#room-elements .element .pas, #room-elements .element .ult { font-size: 12px; }
