:root {
  --bg: #f4f6f9;
  --ink: #1b2430;
  --muted: #6b7786;
  --blue: #1e70d8;
  --line: #d8dde5;
  --panel: #ffffff;
}
:root[data-theme="dark"] { --bg:#12161b; --ink:#e8edf4; --muted:#a1adbd; --blue:#6da9ff; --line:#2a323d; --panel:#1a2029; }
* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 15px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  display: flex; align-items: center; justify-content: center;
  padding: 24px 16px;
}
.shell { width: 100%; max-width: 1040px; }

.err { display: flex; gap: 20px; align-items: center; margin-bottom: 22px; }
.err__code {
  font: 700 46px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--blue); letter-spacing: -2px;
  padding-right: 20px; border-right: 2px solid var(--line);
}
.err__text h1 { margin: 0 0 2px; font-size: 21px; font-weight: 650; letter-spacing: -0.2px; }
.err__text p { margin: 0; color: var(--muted); font-size: 14px; }

/* ------------------------------------------------------------- skin rail */

/* Where the rail lives. By default it is a scrolling strip under the stage —
   the stage is the page, and nothing about it moves to make room.

   Given a window wide enough, the rail lifts out of the flow entirely and hangs
   in the margin to the left of the page column. It is absolute at that point,
   so the stage, the legend and the board sit at exactly the width and height
   they had before the rail existed. */
.play { position: relative; display: flex; flex-direction: column-reverse; gap: 10px; }

.skins {
  display: flex; gap: 8px;
  overflow-x: auto;
  padding-bottom: 4px;
  scrollbar-width: thin;
}
/* 1040 of page plus a 74 rail and its gutters on both sides — the shell is
   centred, so the margin the rail needs has to exist on the right as well or
   the page would shift sideways to make room. */
@media (min-width: 1240px) {
  .play { display: block; }
  .skins {
    position: absolute; top: 0; right: 100%;
    margin-right: 14px;
    flex-direction: column;
    overflow: visible; padding-bottom: 0;
  }
}
/* The rail's own square. Everything inside it is centred, and the label rides
   under the art in the smallest type on the page. */
.skin {
  position: relative;
  width: 74px; height: 86px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; padding: 4px 3px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  cursor: pointer;
  color: var(--muted);
  transition: border-color .15s, transform .15s;
}
.skin:hover:not(:disabled) { border-color: var(--blue); transform: translateY(-1px); }
.skin.is-on { border-color: var(--blue); box-shadow: 0 0 0 2px color-mix(in srgb, var(--blue) 30%, transparent); }
.skin.is-on .skin__name { color: var(--blue); font-weight: 650; }
.skin:disabled { cursor: not-allowed; }
.skin__art {
  position: relative;
  width: 56px; height: 56px;
  display: flex; align-items: center; justify-content: center;
  color: var(--blue);
}
.skin__thumb { display: block; width: 56px; height: 56px; image-rendering: pixelated; }
.skin__icon { width: 30px; height: 30px; }
/* Two lines at most, and the tier names are long — so the label is clipped
   rather than allowed to shove the square out of shape. */
.skin__name {
  max-width: 100%;
  font-size: 9.5px; line-height: 1.15; text-align: center;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Locked: the art greys out and goes quiet, and the lock sits on top of it in
   the one red on the page that means "not yet". */
.skin__lock { display: none; }
.skin.is-locked .skin__thumb { filter: grayscale(1) brightness(.75); opacity: .45; }
.skin.is-locked .skin__lock {
  display: block;
  position: absolute; left: 50%; top: 50%;
  width: 30px; height: 30px; margin: -15px 0 0 -15px;
  color: #e2382f;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,.35));
}

/* The moment a tier is first reached. */
.skin.is-fresh { animation: skin-pop .45s ease-out 2; }
@keyframes skin-pop {
  0%, 100% { box-shadow: 0 0 0 0 transparent; }
  50% { box-shadow: 0 0 0 4px color-mix(in srgb, var(--blue) 45%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .skin, .skin.is-fresh { transition: none; animation: none; }
}

.stage {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 10px;
  position: relative;
  box-shadow: 0 1px 2px rgba(0,0,0,.05), 0 12px 32px -18px rgba(0,0,0,.35);
}
canvas {
  display: block; width: 100%; height: auto;
  image-rendering: pixelated;
  border-radius: 8px;
  touch-action: manipulation;
}
.hint {
  position: absolute; left: 0; right: 0; bottom: 18px;
  text-align: center; color: var(--muted); font-size: 13px;
  pointer-events: none; transition: opacity .25s;
}
.hint.is-hidden { opacity: 0; }

.legend {
  margin-top: 14px; display: flex; flex-wrap: wrap; gap: 8px 22px;
  color: var(--muted); font-size: 12.5px;
}
.legend em { color: var(--blue); font-style: normal; font-weight: 600; }
kbd {
  font: 11px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  border: 1px solid var(--line); border-bottom-width: 2px;
  border-radius: 4px; padding: 3px 5px; background: var(--panel); color: var(--ink);
}

@media (max-width: 560px) {
  .err { gap: 14px; }
  .err__code { font-size: 34px; padding-right: 14px; }
}

/* ------------------------------------------------------------ name gate */

/* Over the page, not inside the stage: on a phone the stage is shorter than
   the card, and an ask that hangs out of its own box reads as a second thing
   broken. The share card is laid out the same way. */
.gate {
  position: fixed; inset: 0;
  display: flex; align-items: center; justify-content: center;
  padding: 24px 16px;
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  backdrop-filter: blur(3px);
  z-index: 9;
}
.gate.is-hidden { display: none; }
.gate__card {
  width: min(360px, 100%);
  max-height: 100%;
  overflow: auto;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 22px 22px 18px;
  text-align: center;
  box-shadow: 0 18px 40px -22px rgba(0,0,0,.5);
}
.gate__label { display: block; font-size: 17px; font-weight: 650; letter-spacing: -0.2px; }
.gate__sub { margin: 4px 0 14px; color: var(--muted); font-size: 13px; }
.gate__label--sub { margin-top: 12px; font-size: 13px; font-weight: 600; color: var(--muted); }
.gate__input {
  width: 100%; padding: 9px 11px;
  font: 15px ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--ink); background: var(--bg);
  border: 1px solid var(--line); border-radius: 8px;
}
.gate__input:focus { outline: 2px solid var(--blue); outline-offset: 1px; border-color: var(--blue); }
.gate__go {
  width: 100%; margin-top: 10px; padding: 9px 12px;
  font: 600 14px/1.2 inherit; color: #fff; background: var(--blue);
  border: 0; border-radius: 8px; cursor: pointer;
}
.gate__go:hover { filter: brightness(1.07); }
/* The way out of an ask that is now optional: quiet, but not hidden. */
.gate__skip {
  width: 100%; margin-top: 6px; padding: 6px 12px;
  font: 500 12.5px/1.2 inherit; color: var(--muted);
  background: none; border: 0; border-radius: 8px; cursor: pointer;
}
.gate__skip:hover { color: var(--ink); }
.gate__skip.is-hidden { display: none; }
.gate__note { margin: 10px 0 0; min-height: 16px; color: var(--muted); font-size: 12.5px; }

.who.is-hidden { display: none; }
.who em { color: var(--blue); font-style: normal; font-weight: 600; }
.who a { color: var(--muted); margin-left: 6px; }

/* ----------------------------------------------------------- leaderboard */

.board {
  margin-top: 18px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 14px 16px 12px;
}
.board__title {
  margin: 0 0 8px; font-size: 12px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .09em; color: var(--muted);
}
.board__list { margin: 0; padding: 0; list-style: none; }
.board__row {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr) auto 62px;
  gap: 10px; align-items: baseline;
  padding: 5px 0;
  border-top: 1px solid var(--line);
}
.board__row:first-child { border-top: 0; }
.board__row.is-me { color: var(--blue); font-weight: 600; }

/* The top three carry their medal on the rank, not on the whole row: a gold
   row would out-shout the score next to it, and the board is read by score. */
.board__row.is-gold   .board__rank { color: #d4a017; }
.board__row.is-silver .board__rank { color: #9aa4b0; }
.board__row.is-bronze .board__rank { color: #b5713a; }
.board__row.is-gold   .board__rank,
.board__row.is-silver .board__rank,
.board__row.is-bronze .board__rank { font-weight: 700; }
.board__row.is-gold   { background: linear-gradient(90deg, rgba(212,160,23,.12), transparent 62%); }
.board__row.is-silver { background: linear-gradient(90deg, rgba(154,164,176,.12), transparent 62%); }
.board__row.is-bronze { background: linear-gradient(90deg, rgba(181,113,58,.12), transparent 62%); }
.board__rank, .board__score {
  font: 13px ui-monospace, SFMono-Regular, Menlo, monospace;
}
.board__rank { color: var(--muted); }
.board__row.is-me .board__rank { color: inherit; }
.board__name { font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.board__org { color: var(--muted); font-size: 12.5px; font-weight: 400; }
.board__org::before { content: "· "; }
.board__row.is-me .board__org { color: inherit; opacity: .8; }
.board__tier { font-size: 12px; color: var(--muted); }
.board__score { text-align: right; }
.board__empty, .board__note { color: var(--muted); font-size: 13px; }
.board__note { margin: 8px 0 0; min-height: 17px; }

/* ------------------------------------------------------------- share card */

/* The call to action sits where the hint does — by the time a run has ended
   the hint is gone, and that strip is the one place on the stage the game
   over band does not cover. */
/* The canvas has already said the score is a best, so the button only has to
   say what it does. It is also the one piece of page chrome that sits over the
   canvas, which is white in day mode and white again under night mode's
   inverted sky — hence the filled pill rather than text in the page's ink. */
.cta {
  position: absolute; left: 0; right: 0; bottom: 14px;
  display: flex; justify-content: center;
}
.cta.is-hidden { display: none; }
.cta__go {
  padding: 7px 16px;
  font: 600 13px/1.2 inherit; color: #fff; background: var(--blue);
  border: 0; border-radius: 999px; cursor: pointer;
}
.cta__go:hover { filter: brightness(1.07); }

/* Over the page rather than inside the stage, as the name gate is: the card is
   a 1200x630 picture with text and buttons under it, which is taller than the
   stage however narrow it is made. */
.share {
  position: fixed; inset: 0;
  display: flex; align-items: center; justify-content: center;
  padding: 24px 16px;
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  backdrop-filter: blur(3px);
  z-index: 10;
}
.share.is-hidden { display: none; }
.share__card {
  position: relative;
  width: min(520px, 100%);
  max-height: 100%;
  overflow: auto;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 16px;
  text-align: center;
  box-shadow: 0 18px 40px -22px rgba(0,0,0,.5);
}
/* It takes focus when it opens, which is what makes Escape and Tab work from
   the moment it appears — but it is a panel, not a control, so it does not
   draw a focus ring. */
.share__card:focus { outline: none; }
/* The card is drawn at 1200x630 and only ever shown scaled down, so the
   preview is the shared image itself rather than a description of it. */
.share__preview {
  display: block; width: 100%; height: auto;
  border: 1px solid var(--line); border-radius: 8px;
  background: #fff;
}
.share__text {
  margin: 12px 0 0; padding: 8px 10px;
  text-align: left; font-size: 12.5px; line-height: 1.45;
  color: var(--muted); background: var(--bg);
  border: 1px solid var(--line); border-radius: 8px;
  word-break: break-word;
}
.share__actions { display: flex; gap: 8px; margin-top: 10px; }
.share__go, .share__alt {
  flex: 1; padding: 9px 12px;
  font: 600 13px/1.2 inherit; border-radius: 8px; cursor: pointer;
}
.share__go { color: #fff; background: var(--blue); border: 0; }
.share__go:hover { filter: brightness(1.07); }
.share__go.is-hidden, .share__alt.is-hidden, .share__preview.is-hidden { display: none; }
.share__alt {
  color: var(--ink); background: var(--panel);
  border: 1px solid var(--line);
}
.share__alt:hover { border-color: var(--blue); color: var(--blue); }
/* The networks: text labels rather than borrowed logos, in one wrapping row so
   a fifth one later costs nothing. */
.share__social {
  display: flex; flex-wrap: wrap; gap: 8px;
  margin-top: 10px;
}
.share__net {
  flex: 1 1 auto; min-width: 88px;
  padding: 8px 10px;
  font: 600 13px/1.2 inherit; text-align: center; text-decoration: none;
  color: var(--ink); background: var(--panel);
  border: 1px solid var(--line); border-radius: 8px;
  cursor: pointer;
}
.share__net:hover { border-color: var(--blue); color: var(--blue); }
.share__note { margin: 8px 0 0; min-height: 16px; color: var(--muted); font-size: 12.5px; }
/* Inside the card, not hanging off its corner: the card scrolls on a short
   window, and anything outside it would be clipped away. */
.share__close {
  position: absolute; top: 9px; right: 9px;
  width: 28px; height: 28px; padding: 0;
  font: 16px/1 inherit; color: var(--muted);
  background: var(--panel); border: 1px solid var(--line);
  border-radius: 50%; cursor: pointer;
}
.share__close:hover { color: var(--ink); }

@media (max-width: 560px) {
  .share__card { padding: 12px; }
  .share__actions { flex-wrap: wrap; }
  /* Where Web Share exists — which is most phones — it is the whole answer,
     so it gets a row of its own and the clipboard sits under it. */
  .share__go { flex-basis: 100%; }
}

.game-nav { display: flex; justify-content: space-between; align-items: center; margin-bottom: 32px; color: var(--muted); font-size: 13px; }
.game-nav a { color: var(--blue); text-decoration: none; font-weight: 650; }
.game-nav a:hover { text-decoration: underline; }
.game-nav a:focus-visible { outline: 3px solid var(--blue); outline-offset: 5px; }
body { height: auto; min-height: 100%; }

.mode-nav { display:flex; gap:8px; margin-bottom:20px; }
.mode-nav a { padding:8px 16px; border:1px solid var(--line); border-radius:8px; color:var(--muted); text-decoration:none; font-weight:650; }
.mode-nav a[aria-current="page"] { color:var(--blue); border-color:var(--blue); background:var(--panel); }
.mode-nav a:focus-visible, .arena-intro summary:focus-visible { outline:3px solid var(--blue); outline-offset:4px; }
.arena-intro { padding:20px; margin-bottom:24px; background:var(--panel); border:1px solid var(--line); border-radius:12px; }
.arena-intro h2 { font-size:18px; margin:0 0 8px; }
.arena-intro p { margin:8px 0; }
.arena-intro summary { color:var(--blue); cursor:pointer; font-weight:650; }
.arena-intro details { margin:16px 0; }
.arena-intro a { color:var(--blue); }
.arena-note { color:var(--muted); font-size:12px; }
.arena-status { font:12px/1.6 ui-monospace,monospace; color:var(--muted); }
