/* MK Pro Games — site styles.
   One stylesheet, no framework. Dark neon arcade: the games are bright, so the furniture
   around them stays quiet and lets them be the loudest thing on the page. */

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* The browser's own [hidden] rule is the weakest thing in the cascade, so any author
   `display:` further down silently defeats it. The shell toggles panels and the name form
   with the hidden attribute, so it has to actually win. */
[hidden] { display: none !important; }

:root {
  --bg:        #0b1026;
  --bg-2:      #0f1533;
  --panel:     rgba(255, 255, 255, 0.045);
  --line:      rgba(255, 255, 255, 0.11);
  --text:      #eaf0ff;
  --muted:     #98a6d4;
  --neon:      #00e5ff;
  --neon-2:    #ff2e97;
  --gold:      #ffd60a;
  --green:     #7cff6b;
  --radius:    16px;
  --wrap:      1120px;
  --font: "Trebuchet MS", "Segoe UI", system-ui, -apple-system, sans-serif;
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}

html { -webkit-text-size-adjust: 100%; }

body {
  font-family: var(--font);
  color: var(--text);
  background:
    radial-gradient(ellipse at 12% -5%, #2d0b4e 0%, transparent 55%),
    radial-gradient(ellipse at 92% 8%, #16225e 0%, transparent 50%),
    var(--bg);
  background-attachment: fixed;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  line-height: 1.6;
}

a { color: var(--neon); text-decoration: none; }
a:hover { text-decoration: underline; }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--neon); color: #04101a; padding: 10px 16px; border-radius: 0 0 8px 0;
}
.skip:focus { left: 0; }

/* ── header ─────────────────────────────────────────────────────────────────────────── */

.site-head {
  display: flex; align-items: center; gap: 24px;
  max-width: var(--wrap); width: 100%; margin: 0 auto;
  padding: 18px 24px;
  flex-wrap: wrap;
}

.brand { display: flex; align-items: baseline; gap: 7px; font-weight: 900; letter-spacing: -0.02em; }
.brand:hover { text-decoration: none; }
.brand-mk {
  font-size: 1.32rem;
  background: linear-gradient(100deg, var(--neon), var(--gold) 48%, var(--neon-2));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.brand-games { font-size: 0.78rem; letter-spacing: 0.28em; color: var(--text); }

.site-nav { display: flex; gap: 20px; margin-left: auto; }
.site-nav a { color: var(--muted); font-size: 0.92rem; }
.site-nav a:hover { color: var(--text); text-decoration: none; }

.site-account { display: flex; align-items: center; gap: 14px; }
.site-account .who { font-weight: 700; color: var(--gold); font-size: 0.92rem; }
.link {
  background: none; border: 0; color: var(--muted); font: inherit; font-size: 0.92rem;
  cursor: pointer; padding: 0;
}
.link:hover { color: var(--text); }

/* ── buttons ────────────────────────────────────────────────────────────────────────── */

.btn {
  display: inline-block; border: 0; cursor: pointer;
  font: inherit; font-weight: 800; letter-spacing: 0.02em;
  padding: 13px 26px; border-radius: 999px;
  color: #04101a;
  background: linear-gradient(100deg, var(--neon), #7cf6ff);
  box-shadow: 0 6px 24px rgba(0, 229, 255, 0.28);
  transition: transform 0.14s ease, box-shadow 0.14s ease;
}
.btn:hover { text-decoration: none; transform: translateY(-2px); box-shadow: 0 10px 30px rgba(0, 229, 255, 0.38); }
.btn:active { transform: translateY(0); }
.btn-sm { padding: 8px 16px; font-size: 0.85rem; }
.btn-ghost {
  background: transparent; color: var(--text);
  border: 1px solid var(--line); box-shadow: none;
}
.btn-ghost:hover { border-color: var(--neon); box-shadow: none; }

/* ── generic page furniture ─────────────────────────────────────────────────────────── */

main { flex: 1; }
.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 24px; }
.narrow { max-width: 560px; }

.page-title { font-size: clamp(1.8rem, 4.5vw, 2.6rem); font-weight: 900; letter-spacing: -0.02em; }
.lede { color: var(--muted); font-size: 1.05rem; max-width: 62ch; }

.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 24px;
}

/* ── home: hero ─────────────────────────────────────────────────────────────────────── */

.hero { max-width: var(--wrap); margin: 0 auto; padding: 48px 24px 20px; text-align: center; }
.hero h1 {
  font-size: clamp(2.2rem, 7vw, 4rem); font-weight: 900; line-height: 1.03;
  letter-spacing: -0.03em;
}
.hero h1 em {
  font-style: normal;
  background: linear-gradient(100deg, var(--neon), var(--gold) 50%, var(--neon-2));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.hero p { color: var(--muted); font-size: 1.1rem; margin: 16px auto 0; max-width: 56ch; }
.hero-by { margin-top: 18px; font-size: 0.95rem; color: var(--muted); }
.hero-by strong { color: var(--gold); }

.counters { display: flex; gap: 32px; justify-content: center; margin-top: 30px; flex-wrap: wrap; }
.counter { text-align: center; }
.counter b { display: block; font-family: var(--mono); font-size: 1.5rem; color: var(--text); }
.counter span { font-size: 0.72rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--muted); }

/* ── home: game grid ────────────────────────────────────────────────────────────────── */

.grid {
  display: grid; gap: 22px;
  grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  max-width: var(--wrap); margin: 0 auto; padding: 36px 24px 12px;
}

.game-card {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 26px;
  transition: transform 0.18s ease, border-color 0.18s ease;
}
.game-card::before {
  content: ""; position: absolute; inset: -40% 40% 60% -40%;
  background: radial-gradient(circle, var(--card-accent, var(--neon)) 0%, transparent 62%);
  opacity: 0.16; pointer-events: none;
}
.game-card:hover { transform: translateY(-4px); border-color: var(--card-accent, var(--neon)); }
.game-card.soon { opacity: 0.72; }
.game-card.soon:hover { transform: none; }

.game-card h2 { position: relative; font-size: 1.5rem; font-weight: 900; letter-spacing: -0.02em; }
.game-card .tag {
  position: relative;
  /* The card is a flex column, which stretches children to full width — inline-block alone
     isn't enough to keep a pill from becoming a bar. */
  display: inline-block; align-self: flex-start; margin-bottom: 14px;
  font-size: 0.62rem; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--card-accent, var(--neon));
  border: 1px solid currentColor; border-radius: 999px; padding: 3px 11px;
}
.game-card p { position: relative; color: var(--muted); margin: 10px 0 22px; flex: 1; }
.game-card .actions { position: relative; display: flex; gap: 12px; align-items: center; }

/* ── home: recent runs ──────────────────────────────────────────────────────────────── */

.recent { max-width: var(--wrap); margin: 0 auto; padding: 34px 24px 60px; }
.recent h2 { font-size: 1.1rem; letter-spacing: 0.02em; margin-bottom: 14px; }
.recent ul { list-style: none; display: grid; gap: 8px; }
.recent li {
  display: flex; align-items: center; gap: 12px;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: 10px; padding: 10px 16px; font-size: 0.92rem;
}
.recent .who { font-weight: 700; }
.recent .pts { margin-left: auto; font-family: var(--mono); color: var(--gold); }
.recent .when { color: var(--muted); font-size: 0.8rem; min-width: 62px; text-align: right; }

/* ── game page ──────────────────────────────────────────────────────────────────────── */

.game-head {
  max-width: var(--wrap); margin: 0 auto; padding: 22px 24px 14px;
  display: flex; align-items: flex-end; gap: 18px; flex-wrap: wrap;
}
.game-head h1 { font-size: clamp(1.6rem, 4vw, 2.2rem); font-weight: 900; letter-spacing: -0.02em; }
.game-head p { color: var(--muted); }
.game-head .best { margin-left: auto; text-align: right; font-family: var(--mono); }
.game-head .best b { display: block; font-size: 1.3rem; color: var(--gold); }
.game-head .best span { font-size: 0.68rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--muted); }

.stage-wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 24px; }

/* The stage is a fixed 16:9 box. The canvas letterboxes a 960×540 playfield inside it, so
   the game is identical on every screen — see the note at the top of tunnel.js. */
.stage {
  position: relative;
  aspect-ratio: 16 / 9;
  width: 100%;
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--line);
  background: #05060d;
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.55);
}
.stage canvas {
  display: block; width: 100%; height: 100%;
  touch-action: none;          /* stop the browser scrolling/zooming on game touches */
  cursor: crosshair;
}
.stage[data-state="playing"] canvas { cursor: none; }

.stage-tools { position: absolute; top: 12px; right: 12px; z-index: 3; display: flex; gap: 8px; }

/* Full screen, the hard way.
 *
 * Where the browser has a real fullscreen it is used, and the stage simply fills whatever box it
 * is given. Where it does not — iOS Safari refuses `requestFullscreen` on anything but a video —
 * this class pins the stage to the viewport instead. The two paths need the same rules, because
 * both end with the stage no longer being a 16:9 box in a column of page.
 *
 * `dvh` rather than `vh`: on a phone `vh` is the viewport with the address bar hidden, so the
 * bottom of the tunnel sits underneath it until you scroll, which in a game you never do. */
.stage:fullscreen,
html.immersive .stage {
  aspect-ratio: auto;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}
html.immersive { overflow: hidden; }
html.immersive .stage {
  position: fixed;
  inset: 0;
  z-index: 200;
  width: 100vw;
  height: 100dvh;
}

/* The invitation under the game. Hidden by default and revealed by the shell only where the
   pointer is coarse, so it never appears on a desktop that has the room already — and never in
   full screen, where it would be an offer already accepted. */
.go-full {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  width: 100%; margin-top: 12px; padding: 14px 16px;
  border-radius: var(--radius); border: 1px solid var(--line);
  background: linear-gradient(180deg, rgba(34, 230, 255, 0.14), rgba(34, 230, 255, 0.05));
  color: var(--text); font: inherit; font-weight: 600; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.go-full:active { transform: translateY(1px); }
.go-full-icon { font-size: 1.15rem; opacity: 0.85; }
html.immersive .go-full, .stage:fullscreen ~ .go-full { display: none; }

.icon-btn {
  width: 38px; height: 38px; border-radius: 50%;
  background: rgba(4, 8, 20, 0.6); border: 1px solid var(--line);
  color: var(--text); font-size: 1rem; cursor: pointer;
  backdrop-filter: blur(6px);
}
.icon-btn:hover { border-color: var(--neon); }

/* overlay panels */
.panel {
  position: absolute; inset: 0; z-index: 2;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 14px; padding: 24px;
  text-align: center;
  background: rgba(5, 8, 22, 0.82);
  backdrop-filter: blur(7px);
  overflow-y: auto;
}
.panel h2 { font-size: clamp(1.4rem, 4vw, 2rem); font-weight: 900; letter-spacing: -0.02em; }
.panel .hint { color: var(--muted); font-size: 0.9rem; max-width: 46ch; }
.panel kbd {
  font-family: var(--mono); font-size: 0.78rem;
  background: rgba(255, 255, 255, 0.09); border: 1px solid var(--line);
  border-radius: 5px; padding: 2px 7px;
}

/*
  The end-of-run panel.

  Everything here arrives rather than appears: the headline drops in, the score rolls up, and the
  stats come one after another. A run is the only thing the player made, and handing all of it
  over in a single frame reads as a form being filled in rather than as a result.
*/
.over-title {
  font-size: clamp(1.1rem, 4vw, 1.5rem); font-weight: 800;
  letter-spacing: 0.3em; text-transform: uppercase; color: var(--muted);
  animation: over-drop 0.45s cubic-bezier(.2, 1.4, .4, 1) both;
}
.over-title.best {
  color: var(--gold);
  text-shadow: 0 0 26px rgba(255, 200, 60, 0.55);
  animation: over-drop 0.45s cubic-bezier(.2, 1.4, .4, 1) both, over-pulse 1.6s ease-in-out 0.45s infinite;
}
@keyframes over-drop {
  from { opacity: 0; transform: translateY(-0.5em) scale(0.9); }
  to   { opacity: 1; transform: none; }
}
@keyframes over-pulse {
  0%, 100% { text-shadow: 0 0 26px rgba(255, 200, 60, 0.5); }
  50%      { text-shadow: 0 0 40px rgba(255, 200, 60, 0.85); }
}

.final-score {
  font-family: var(--mono); font-size: clamp(2.4rem, 9vw, 3.6rem); font-weight: 800;
  color: var(--gold); line-height: 1;
  /* Tabular figures: without them the counter jitters sideways on every frame as digits change. */
  font-variant-numeric: tabular-nums;
}
.final-label { font-size: 0.68rem; letter-spacing: 0.22em; text-transform: uppercase; color: var(--muted); }

.stat-row { display: flex; gap: 22px; flex-wrap: wrap; justify-content: center; }
.stat-row .stat {
  animation: stat-in 0.34s ease both;   /* delay is set per stat by the shell */
}
.stat-row .stat dt { font-size: 0.62rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--muted); }
.stat-row .stat dd { font-family: var(--mono); font-size: 1.05rem; }
@keyframes stat-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

.again-hint { opacity: 0.6; font-size: 0.78rem; }

/* Nobody who just finished a run wants to watch it be announced. */
@media (prefers-reduced-motion: reduce) {
  .over-title, .over-title.best, .stat-row .stat { animation: none; }
}

.result { font-size: 0.98rem; min-height: 1.5em; }
.result.best { color: var(--gold); font-weight: 800; }
.result.held { color: #ffb020; }
.result.muted { color: var(--muted); }

.name-row { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }
.name-row input {
  font: inherit; padding: 11px 16px; border-radius: 999px;
  background: rgba(255, 255, 255, 0.07); border: 1px solid var(--line); color: var(--text);
  min-width: 200px;
}
.name-row input:focus { outline: 2px solid var(--neon); outline-offset: 1px; }
.field-error { color: #ff6b81; font-size: 0.85rem; min-height: 1.2em; }

.panel-actions { display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; }

/* ── MK Line HUD ────────────────────────────────────────────────────────────────────── */
/* Overlaid DOM rather than canvas text: it stays crisp at any resolution, costs the WebGL
   frame nothing, and scales with the viewport using cqw so one set of sizes fits every screen. */

.mkl-hud {
  position: absolute; inset: 0; z-index: 2;
  pointer-events: none;
  container-type: inline-size;
  font-family: var(--mono);
  color: #fff;
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.55);
  transition: opacity 0.25s ease;
}
.mkl-hud.hidden { opacity: 0; }

.mkl-time { position: absolute; top: 2.2cqw; left: 50%; transform: translateX(-50%); text-align: center; }
.mkl-time b {
  display: block; font-size: 7.2cqw; font-weight: 800; line-height: 1;
  letter-spacing: -0.02em; font-variant-numeric: tabular-nums;
}
.mkl-time b.low { color: #ff3b52; animation: mkl-pulse 0.45s ease-in-out infinite; }
@keyframes mkl-pulse { 50% { transform: scale(1.09); } }
.mkl-time span { font-size: 1.2cqw; letter-spacing: 0.3em; opacity: 0.65; }

.mkl-next {
  position: absolute; top: 11.4cqw; left: 50%; transform: translateX(-50%);
  font-size: 1.5cqw; letter-spacing: 0.16em; opacity: 0.8;
}

.mkl-score { position: absolute; top: 2.6cqw; left: 2.6cqw; }
.mkl-score span { display: block; font-size: 1.15cqw; letter-spacing: 0.26em; opacity: 0.6; }
.mkl-score b { font-size: 3.4cqw; font-weight: 800; font-variant-numeric: tabular-nums; }

/* Gear sits beside the speed, because they are read together. */
.mkl-gear {
  position: absolute; right: 2.6cqw; bottom: 11.6cqw;
  display: flex; align-items: baseline; gap: 0.7cqw;
}
.mkl-gear span { font-size: 1.1cqw; letter-spacing: 0.26em; opacity: 0.6; }
.mkl-gear b {
  font-size: 3.4cqw; font-weight: 800; line-height: 1; min-width: 2.2cqw; text-align: right;
  font-variant-numeric: tabular-nums;
}
.mkl-gear b.shift { color: #ffd60a; }
.mkl-gear .mkl-revs {
  display: block; width: 9cqw; height: 0.7cqw; border-radius: 999px;
  background: rgba(0, 0, 0, 0.42); overflow: hidden; align-self: center;
}
.mkl-gear .mkl-revs u { display: block; height: 100%; background: #9fe8ff; transition: width 0.06s linear; }
.mkl-gear .mkl-revs u.red { background: #ff3b52; }

.mkl-speed { position: absolute; right: 2.6cqw; bottom: 2.4cqw; text-align: right; }
.mkl-speed b {
  display: block; font-size: 6.4cqw; font-weight: 800; line-height: 0.95;
  font-variant-numeric: tabular-nums; color: #ffd60a;
}
.mkl-speed span { font-size: 1.2cqw; letter-spacing: 0.28em; opacity: 0.65; }

.mkl-boost { position: absolute; left: 2.6cqw; bottom: 3.4cqw; width: 22cqw; }
.mkl-boost i {
  display: block; height: 1.1cqw; border-radius: 999px;
  background: linear-gradient(90deg, #ffd60a, #ff5a3c);
  transition: width 0.12s linear;
}
.mkl-boost::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 1.1cqw;
  border-radius: 999px; background: rgba(0, 0, 0, 0.42);
}
.mkl-boost i { position: relative; }
.mkl-boost span { display: block; margin-top: 0.5cqw; font-size: 1.1cqw; letter-spacing: 0.24em; opacity: 0.55; }
.mkl-boost span.ready { opacity: 1; color: #ffd60a; }
.mkl-boost span.on { opacity: 1; color: #ff5a3c; }

.mkl-combo {
  position: absolute; right: 2.6cqw; top: 12cqw; text-align: right;
  font-size: 3cqw; font-weight: 800; opacity: 0; transform: translateX(1.4cqw);
  transition: opacity 0.18s ease, transform 0.18s ease;
  color: #ffd60a;
}
.mkl-combo.show { opacity: 1; transform: none; }
.mkl-combo.hot { color: #ff5a3c; font-size: 3.8cqw; }

/* One call-out at a time, in the middle of the frame where the eye already is. */
.mkl-pop {
  position: absolute; left: 50%; top: 21cqw; transform: translate(-50%, 0) scale(0.86);
  font-size: 3.6cqw; font-weight: 800; letter-spacing: 0.02em;
  opacity: 0; transition: opacity 0.12s ease, transform 0.18s cubic-bezier(.2,1.5,.4,1);
  white-space: nowrap;
}
.mkl-pop.show { opacity: 1; transform: translate(-50%, 0) scale(1); }
.mkl-pop.pass { color: #ffffff; font-size: 2.6cqw; }
.mkl-pop.near { color: #ffd60a; }
.mkl-pop.insane { color: #ff5a3c; font-size: 4.6cqw; }
.mkl-pop.checkpoint { color: #18f0a0; }
.mkl-pop.clutch { color: #18f0a0; font-size: 4.6cqw; }
.mkl-pop.unreal { color: #ff2e97; font-size: 5.4cqw; }
.mkl-pop.boost { color: #ff5a3c; }
.mkl-pop.crash { color: #ff3b52; font-size: 4.2cqw; }

/*
  Slipstream. Low and central, under the car rather than out at the edges — it reports on where
  you are right now, so it belongs where you are already looking.
*/
.mkl-draft {
  position: absolute; left: 50%; bottom: 7.5cqw; transform: translate(-50%, 0.6cqw);
  font-size: 1.5cqw; font-weight: 800; letter-spacing: 0.3em;
  padding: 0.5cqw 1.4cqw; border-radius: 999px;
  color: #9fe8ff; border: 1px solid rgba(159, 232, 255, 0.5); background: rgba(8, 24, 38, 0.5);
  opacity: 0; transition: opacity 0.14s ease, transform 0.14s ease;
}
.mkl-draft.show { opacity: 1; transform: translate(-50%, 0); }
.mkl-draft.hot {
  color: #08131c; background: #9fe8ff; border-color: #ffffff;
  box-shadow: 0 0 2.4cqw rgba(159, 232, 255, 0.55);
}

/*
  The zone banner sits above the pop line and is deliberately the largest thing the HUD ever
  shows. It fires once every three checkpoints; the pop line fires several times a minute. The
  hierarchy of the effects should match the rarity of what they are announcing.
*/
.mkl-zone {
  position: absolute; left: 50%; top: 33cqw; transform: translate(-50%, 1.2cqw);
  font-size: 4.4cqw; font-weight: 800; letter-spacing: 0.22em; white-space: nowrap;
  color: #ffffff; text-shadow: 0 0 3cqw rgba(255, 255, 255, 0.45), 0 0.3cqw 1cqw rgba(0, 0, 0, 0.6);
  opacity: 0; transition: opacity 0.4s ease, transform 0.5s cubic-bezier(.2, 1, .3, 1);
}
.mkl-zone.show { opacity: 1; transform: translate(-50%, 0); }

/*
  The record.

  It turns at the music's own tempo and stops when the music stops, which makes the state of the
  soundtrack something you can see out of the corner of an eye. Paused rather than hidden when
  the music dies: a record visibly coming to a halt reads as a warning, and a missing one reads
  as nothing at all.
*/
.mkl-disc {
  position: absolute; left: 2.6cqw; top: 10cqw;
  width: 6.6cqw; height: 6.6cqw; border-radius: 50%;
  background:
    /* The light across the grooves — two soft wedges facing each other, which is what a real
       record does under one lamp. It turns with the disc; at this size nobody's physics minds. */
    conic-gradient(from 210deg,
      rgba(255,255,255,0) 0deg, rgba(255,255,255,0.14) 14deg, rgba(255,255,255,0.02) 38deg,
      rgba(255,255,255,0) 60deg, rgba(255,255,255,0) 178deg, rgba(255,255,255,0.11) 196deg,
      rgba(255,255,255,0.02) 218deg, rgba(255,255,255,0) 240deg),
    /* The grooves: fine and many, not coarse and few. */
    repeating-radial-gradient(circle at 50% 50%,
      rgba(255,255,255,0.055) 0 0.07cqw, rgba(0,0,0,0) 0.07cqw 0.22cqw),
    radial-gradient(circle at 50% 50%, #191a20 0%, #0d0e13 55%, #050607 100%);
  box-shadow: 0 0.3cqw 1.4cqw rgba(0,0,0,0.6), inset 0 0 0 1px rgba(255,255,255,0.08);
  animation: mkl-spin 1.8s linear infinite;
  animation-play-state: paused;
  transition: opacity 0.4s ease;
  opacity: 0.25;
}
.mkl-disc.show { animation-play-state: running; }
/* The label: printed paper, a ring of text-coloured ink, the spindle hole — and a rim of dead
   wax around it, because grooves that run into the label are the tell of a fake. */
.mkl-disc i {
  position: absolute; inset: 33%; border-radius: 50%;
  background:
    radial-gradient(circle at 50% 50%, #0b0c10 0 10%, rgba(0,0,0,0) 10.5%),
    radial-gradient(circle at 50% 50%,
      rgba(0,0,0,0) 0 54%, rgba(0,0,0,0.22) 55% 62%, rgba(0,0,0,0) 63%),
    linear-gradient(135deg, var(--gold), #ff8a3c);
  box-shadow: 0 0 0 0.42cqw #0a0b0e, inset 0 0.1cqw 0.3cqw rgba(0,0,0,0.3);
}
/* One off-centre glint on the wax, so the turning is visible from the corner of an eye. */
.mkl-disc u {
  position: absolute; left: 50%; top: 5%; width: 5%; height: 26%;
  background: linear-gradient(180deg, rgba(255,255,255,0.4), rgba(255,255,255,0));
  border-radius: 999px;
  transform: translateX(-50%) rotate(24deg);
}
@keyframes mkl-spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .mkl-disc { animation: none; }
}

.mkl-flash {
  position: absolute; inset: 0; background: #fff; opacity: 0;
  transition: opacity 0.08s linear; mix-blend-mode: screen;
}

/* ── MK Pulse HUD ───────────────────────────────────────────────────────────────────── */
/* Four numbers and a lot of restraint. Everything on the glass competes with the obstacle the
   player is about to hit, so nothing is here that does not have to be. Sized in container units
   so one set of numbers covers a phone and a monitor. */

.mkp-hud {
  position: absolute; inset: 0; pointer-events: none;
  container-type: inline-size;
  font-family: var(--mono); color: #fff;
}
.mkp-hud.hidden { display: none; }

.mkp-dist { position: absolute; left: 50%; top: 2.2cqw; transform: translateX(-50%); text-align: center; }
.mkp-dist b {
  display: block; font-size: 6.4cqw; font-weight: 800; line-height: 0.92;
  letter-spacing: -0.03em; font-variant-numeric: tabular-nums;
  text-shadow: 0 0 3cqw rgba(255, 255, 255, 0.3), 0 0.2cqw 1cqw rgba(0, 0, 0, 0.8);
}
.mkp-dist span { font-size: 1.1cqw; letter-spacing: 0.4em; opacity: 0.5; }

.mkp-score { position: absolute; left: 2.4cqw; top: 2.4cqw; }
.mkp-score span { display: block; font-size: 1cqw; letter-spacing: 0.3em; opacity: 0.5; }
.mkp-score b { font-size: 2.4cqw; font-weight: 800; font-variant-numeric: tabular-nums; }

.mkp-zoneName {
  position: absolute; left: 2.4cqw; bottom: 2.4cqw;
  font-size: 1.05cqw; letter-spacing: 0.34em; opacity: 0.45;
}

.mkp-flow {
  position: absolute; right: 2.4cqw; top: 2.4cqw; text-align: right;
  font-size: 2.8cqw; font-weight: 800; color: #22e6ff;
  opacity: 0; transform: translateX(1cqw); transition: opacity 0.15s ease, transform 0.15s ease;
}
.mkp-flow.show { opacity: 1; transform: none; }
.mkp-flow.hot { color: #ffc428; font-size: 3.6cqw; text-shadow: 0 0 2.4cqw rgba(255, 196, 40, 0.6); }

/* The feedback hierarchy, in type sizes: an ordinary success is the pop line, a milestone is the
   title, and the crash is the flash. Nothing here strobes — pulses are brightness and colour
   interpolation over a beat, never a fast full-frame flicker. */
/* Only the rare ones land here now, and higher up than they used to.
 *
 * 19cqw put this directly above the tunnel's vanishing point — the exact patch of screen a player
 * is reading obstacles out of. Lifting it to 11 clears the road; shrinking it is the other half,
 * because a word does not need to be large to be noticed when it is the only one. */
.mkp-pop {
  position: absolute; left: 50%; top: 11cqw; transform: translate(-50%, 0) scale(0.88);
  font-size: 1.9cqw; font-weight: 800; white-space: nowrap;
  opacity: 0; transition: opacity 0.1s ease, transform 0.17s cubic-bezier(.2, 1.5, .4, 1);
  text-shadow: 0 0.2cqw 1cqw rgba(0, 0, 0, 0.7);
}
.mkp-pop.show { opacity: 1; transform: translate(-50%, 0) scale(1); }
.mkp-pop.near { color: #22e6ff; }
.mkp-pop.perfect { color: #ffc428; font-size: 2.3cqw; }
/* On the beat. Its own colour, because it is the one thing here you hear before you see. */
.mkp-pop.sync { color: #7cff6b; }

.mkp-title {
  position: absolute; left: 50%; top: 29cqw; transform: translate(-50%, 1.4cqw);
  font-size: 4.2cqw; font-weight: 800; letter-spacing: 0.2em; white-space: nowrap;
  opacity: 0; transition: opacity 0.3s ease, transform 0.5s cubic-bezier(.2, 1, .3, 1);
  text-shadow: 0 0 3.4cqw rgba(255, 255, 255, 0.5), 0 0.3cqw 1cqw rgba(0, 0, 0, 0.75);
}
.mkp-title.show { opacity: 1; transform: translate(-50%, 0); }
.mkp-title.danger { color: #ff2f4e; }
.mkp-title.cleared { color: #22e6ff; }
.mkp-title.speed { color: #ffc428; }

.mkp-count {
  position: absolute; left: 50%; top: 24cqw; transform: translate(-50%, 0) scale(1.4);
  font-size: 9cqw; font-weight: 800; letter-spacing: 0.04em;
  opacity: 0; transition: opacity 0.14s ease, transform 0.34s cubic-bezier(.2, 1, .3, 1);
  text-shadow: 0 0 5cqw rgba(255, 255, 255, 0.55);
}
.mkp-count.show { opacity: 1; transform: translate(-50%, 0) scale(1); }

.mkp-danger {
  position: absolute; left: 50%; bottom: 4.4cqw; transform: translate(-50%, 0.6cqw);
  width: 32cqw; height: 1.3cqw; border-radius: 999px;
  background: rgba(255, 47, 78, 0.16); border: 1px solid rgba(255, 47, 78, 0.55);
  opacity: 0; transition: opacity 0.2s ease, transform 0.2s ease;
}
.mkp-danger.show { opacity: 1; transform: translate(-50%, 0); }
.mkp-danger i { display: block; height: 100%; border-radius: 999px; background: #ff2f4e; transition: width 0.12s linear; }
.mkp-danger span {
  position: absolute; left: 50%; top: 2cqw; transform: translateX(-50%);
  font-size: 1cqw; letter-spacing: 0.34em; color: #ff2f4e; white-space: nowrap;
}

.mkp-flash {
  position: absolute; inset: 0; background: #fff; opacity: 0;
  transition: opacity 0.09s linear; mix-blend-mode: screen;
}
/* Pressure is an edge, not a flash: a red vignette that comes up over a second and sits there.
   It says "this is the hard bit" without anything blinking. */
.mkp-vig {
  position: absolute; inset: 0; opacity: 0;
  transition: opacity 0.4s ease;
  background: radial-gradient(ellipse at center, transparent 42%, rgba(255, 47, 78, 0.5) 100%);
}

@media (prefers-reduced-motion: reduce) {
  .mkp-title, .mkp-count, .mkp-pop { transition: opacity 0.2s linear; }
  .mkp-flash { display: none; }
}

/* ── tables / leaderboards ──────────────────────────────────────────────────────────── */

.board { width: 100%; border-collapse: collapse; font-size: 0.95rem; }
.board th {
  text-align: left; font-size: 0.66rem; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--muted); font-weight: 700; padding: 8px 12px; border-bottom: 1px solid var(--line);
}
.board td { padding: 10px 12px; border-bottom: 1px solid rgba(255, 255, 255, 0.05); }
.board tbody tr:hover { background: rgba(255, 255, 255, 0.03); }
.board .rank { font-family: var(--mono); color: var(--muted); width: 3.2em; }
.board .score { font-family: var(--mono); text-align: right; color: var(--gold); }
.board tr:nth-child(1) .rank { color: var(--gold); font-weight: 800; }
.board tr:nth-child(2) .rank { color: #d6dcf0; font-weight: 800; }
.board tr:nth-child(3) .rank { color: #d08c50; font-weight: 800; }
.board .empty { color: var(--muted); text-align: center; padding: 26px 12px; }

.tabs { display: flex; gap: 8px; margin-bottom: 16px; flex-wrap: wrap; }
.tabs a {
  font-size: 0.85rem; padding: 7px 15px; border-radius: 999px;
  border: 1px solid var(--line); color: var(--muted);
}
.tabs a:hover { color: var(--text); text-decoration: none; }
.tabs a[aria-current="true"] { background: var(--neon); color: #04101a; border-color: var(--neon); font-weight: 800; }

.side-board { margin-top: 26px; }
.side-board h2 { font-size: 1rem; margin-bottom: 10px; }

/* ── forms ──────────────────────────────────────────────────────────────────────────── */

.form-page { max-width: 440px; margin: 0 auto; padding: 48px 24px 70px; }
.form-page h1 { font-size: 1.9rem; font-weight: 900; letter-spacing: -0.02em; margin-bottom: 8px; }
.form-page > p { color: var(--muted); margin-bottom: 22px; }

.field { margin-bottom: 16px; }
.field label { display: block; font-size: 0.8rem; letter-spacing: 0.06em; color: var(--muted); margin-bottom: 6px; }
.field input {
  width: 100%; font: inherit; padding: 12px 15px; border-radius: 11px;
  background: rgba(255, 255, 255, 0.06); border: 1px solid var(--line); color: var(--text);
}
.field input:focus { outline: 2px solid var(--neon); outline-offset: 1px; }
.field .help { font-size: 0.78rem; color: var(--muted); margin-top: 5px; }

.alert {
  background: rgba(255, 46, 151, 0.11); border: 1px solid rgba(255, 46, 151, 0.4);
  color: #ffd0e4; border-radius: 11px; padding: 11px 15px; margin-bottom: 18px; font-size: 0.9rem;
}
.form-page .btn { width: 100%; }
.form-alt { margin-top: 18px; text-align: center; color: var(--muted); font-size: 0.9rem; }

/* ── profile ────────────────────────────────────────────────────────────────────────── */

.profile-head { text-align: center; padding: 46px 24px 8px; }
.profile-head h1 { font-size: 2.2rem; font-weight: 900; letter-spacing: -0.02em; }
.profile-head p { color: var(--muted); }

/* ── about / prose ──────────────────────────────────────────────────────────────────── */

.prose { max-width: 68ch; margin: 0 auto; padding: 48px 24px 70px; }
.prose h1 { font-size: 2.1rem; font-weight: 900; letter-spacing: -0.02em; margin-bottom: 16px; }
.prose h2 { font-size: 1.2rem; margin: 30px 0 8px; }
.prose p { color: #c3ccec; margin-bottom: 14px; }
.prose ul { color: #c3ccec; margin: 0 0 14px 20px; }

/* ── footer ─────────────────────────────────────────────────────────────────────────── */

.site-foot {
  border-top: 1px solid var(--line);
  margin-top: 40px; padding: 26px 24px 34px;
  text-align: center; color: var(--muted); font-size: 0.88rem;
}
.foot-brand strong { color: var(--gold); }
.foot-meta { margin-top: 6px; font-size: 0.82rem; }

/* ── narrow screens ─────────────────────────────────────────────────────────────────── */

@media (max-width: 720px) {
  .site-head { gap: 12px; padding: 14px 16px; }
  .site-nav { order: 3; width: 100%; margin-left: 0; justify-content: center; }
  .site-account { margin-left: auto; }
  .wrap, .stage-wrap, .grid, .recent, .hero, .game-head { padding-left: 16px; padding-right: 16px; }
  .game-head .best { margin-left: 0; text-align: left; }
  .counters { gap: 22px; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* ── MK Arena's HUD ──────────────────────────────────────────────────────────────────
   Kept at the very top of the stage and out of the arena's way. The floor is this game's
   real interface — it says what is about to hurt and how soon — so anything up here that
   competes for the eye is actively harmful, which is why it is three small numbers and a
   call-out that appears only when something has just happened. */
.arena-hud {
  position: absolute; inset: 0; pointer-events: none; z-index: 2;
  /* The stage is the reference for every cqw above. */
  container-type: inline-size;
  font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
}
.arena-hud .ah-row {
  display: flex; justify-content: space-between; align-items: flex-start;
  /* Clear of the mute and full-screen buttons, which live in the same corner. */
  /* The right padding clears the mute and full-screen buttons, which live in the same corner and
     are a fixed 38px each plus their gap and inset — 120px is that, with a little air. Sized as a
     minimum rather than a proportion because the buttons do not shrink with the stage. */
  padding: clamp(6px, 1.6cqw, 14px) clamp(120px, 13cqw, 128px) 0 clamp(10px, 2cqw, 20px);
}
.arena-hud .ah-stat { display: flex; flex-direction: column; gap: 2px; }
.arena-hud .ah-mid { align-items: center; }
.arena-hud .ah-right { align-items: flex-end; }
/* Sized against the stage rather than in fixed rem.
 *
 * On a desktop these were fine and on a phone they ate the arena — a 2.1rem wave counter on a
 * 560px-tall stage is a number standing on the floor it is describing, and the character spent
 * his time behind it. `cqw` is a percentage of the stage's own width, so the HUD is the same
 * fraction of the frame on every screen; the clamps stop it becoming unreadable on a small one or
 * absurd on a large one. */
.arena-hud .ah-key {
  font-size: clamp(0.5rem, 1.1cqw, 0.62rem);
  letter-spacing: 0.18em; color: rgba(255, 255, 255, 0.42);
}
.arena-hud .ah-stat b {
  font-size: clamp(0.95rem, 2.4cqw, 1.5rem);
  line-height: 1; color: #fff; font-variant-numeric: tabular-nums;
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.7);
}
.arena-hud .ah-mid b { font-size: clamp(1.2rem, 3.4cqw, 2.1rem); }

/* The call-out sits above the arena rather than over it: a word printed across the tiles is a
   word printed across the only thing worth looking at. */
.arena-hud .ah-say {
  position: absolute; top: 26%; left: 0; right: 0; text-align: center;
  font-size: clamp(0.8rem, 2cqw, 1.25rem); font-weight: 700; letter-spacing: 0.06em;
  text-shadow: 0 2px 18px rgba(0, 0, 0, 0.8);
}
.arena-hud .ah-close { color: #ffa41e; animation: ah-pop 0.32s ease-out; }
.arena-hud .ah-down { color: #ff2f4e; animation: ah-pop 0.32s ease-out; }
.arena-hud .ah-plain { color: #22e6ff; animation: ah-pop 0.32s ease-out; }
@keyframes ah-pop {
  from { transform: scale(0.82); opacity: 0; }
  to   { transform: scale(1); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .arena-hud .ah-say { animation: none !important; }
}
/* The chain turns amber while a risk streak is live — the one number that changes meaning. */
.arena-hud .ah-hot { color: #ffa41e; }
/* The named shape, under the wave count. Deliberately quiet — it is a vocabulary being taught,
   not an alarm; the floor does the alarming. */
.arena-hud .ah-shape {
  font-size: clamp(0.45rem, 1cqw, 0.6rem); letter-spacing: 0.2em;
  color: rgba(255, 255, 255, 0.5); margin-top: 3px; min-height: 0.8em;
}
/* The record answers a click, so it has to look like it might take one. */
.mkl-disc { transition: transform 0.18s ease-out; }
.mkl-disc:hover { transform: scale(1.08); }
.mkl-disc.flip { animation: mkl-flip 0.42s ease-out; }
@keyframes mkl-flip {
  0%   { transform: rotateY(0deg) scale(1); }
  50%  { transform: rotateY(90deg) scale(1.14); }
  100% { transform: rotateY(0deg) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .mkl-disc.flip { animation: none; }
}

/* ── MK Duel's HUD ───────────────────────────────────────────────────────────────────
   Three things: what is left of the machine, what is left of you, and the charge. No score
   during a duel — a number counting up in the corner competes with the only decision the
   player is being asked to make, and this game has exactly one. */
.duel-hud {
  position: absolute; inset: 0; pointer-events: none; z-index: 2;
  container-type: inline-size;
  font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
}
.duel-hud .dh-top { padding: clamp(8px, 1.8cqw, 16px) clamp(120px, 13cqw, 128px) 0 clamp(12px, 2cqw, 20px); }
.duel-hud .dh-name {
  display: block; font-size: clamp(0.5rem, 1.1cqw, 0.64rem);
  letter-spacing: 0.22em; color: rgba(255, 255, 255, 0.55); margin-bottom: 5px;
}
.duel-hud .dh-bar {
  display: block; height: 6px; border-radius: 3px;
  background: rgba(255, 255, 255, 0.1); overflow: hidden;
}
.duel-hud .dh-bar u {
  display: block; height: 100%; width: 100%; background: #ff2f4e;
  transition: width 0.28s cubic-bezier(0.2, 0.8, 0.3, 1);
}

.duel-hud .dh-bottom {
  position: absolute; left: 0; right: 0; bottom: clamp(10px, 2cqw, 20px);
  display: flex; flex-direction: column; align-items: center; gap: 8px;
}
.duel-hud .dh-life { display: flex; gap: 7px; }
.duel-hud .dh-life i {
  width: clamp(9px, 1.2cqw, 13px); height: clamp(9px, 1.2cqw, 13px);
  border-radius: 50%; background: #22e6ff; box-shadow: 0 0 10px rgba(34, 230, 255, 0.6);
}
.duel-hud .dh-life i.gone { background: rgba(255, 255, 255, 0.16); box-shadow: none; }

/* The charge is the one thing here allowed to shout: it is the entire reward loop made
   visible, and it should move in the corner of the eye at the moment the player dares to wait. */
.duel-hud .dh-charge {
  display: block; width: clamp(150px, 26cqw, 280px); height: 8px; border-radius: 4px;
  background: rgba(255, 255, 255, 0.1); overflow: hidden;
}
.duel-hud .dh-charge u {
  display: block; height: 100%; width: 0%; background: #ffa41e;
  transition: width 0.16s ease-out;
}
.duel-hud .dh-charge.full u { background: #8dff6b; }
.duel-hud .dh-charge.full { box-shadow: 0 0 18px rgba(141, 255, 107, 0.55); }

.duel-hud .dh-say {
  position: absolute; top: 30%; left: 0; right: 0; text-align: center;
  font-size: clamp(0.85rem, 2.1cqw, 1.35rem); font-weight: 700; letter-spacing: 0.08em;
  text-shadow: 0 2px 18px rgba(0, 0, 0, 0.85);
}
.duel-hud .dh-charged { color: #ffa41e; animation: dh-pop 0.3s ease-out; }
.duel-hud .dh-perfect { color: #8dff6b; animation: dh-pop 0.3s ease-out; }
.duel-hud .dh-ready   { color: #8dff6b; animation: dh-pop 0.3s ease-out; }
.duel-hud .dh-hit     { color: #22e6ff; animation: dh-pop 0.3s ease-out; }
.duel-hud .dh-down    { color: #ff2f4e; animation: dh-pop 0.3s ease-out; }
.duel-hud .dh-teach   { color: rgba(255, 255, 255, 0.8); font-weight: 600; }
.duel-hud .dh-plain   { color: #22e6ff; animation: dh-pop 0.3s ease-out; }
@keyframes dh-pop { from { transform: scale(0.84); opacity: 0; } to { transform: scale(1); opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .duel-hud .dh-say { animation: none !important; } }
/* The charge label. Quiet until it is full, then it is the only instruction on screen. */
.duel-hud .dh-hint {
  font-size: clamp(0.45rem, 1cqw, 0.6rem); letter-spacing: 0.22em;
  color: rgba(255, 255, 255, 0.4);
}
.duel-hud .dh-hint.ready { color: #8dff6b; }

/* ── MK Orbit's HUD ──────────────────────────────────────────────────────────────────
   PLANETS gets the room, because "I made 37 planets" is the sentence players say to each
   other; the score is the leaderboard's business. */
.orbit-hud {
  position: absolute; inset: 0; pointer-events: none; z-index: 2;
  container-type: inline-size;
  font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
}
.orbit-hud .oh-row {
  display: flex; justify-content: space-between; align-items: flex-start;
  padding: clamp(8px, 1.7cqw, 15px) clamp(120px, 13cqw, 128px) 0 clamp(12px, 2cqw, 20px);
}
.orbit-hud .oh-stat { display: flex; flex-direction: column; gap: 2px; }
.orbit-hud .oh-mid { align-items: center; }
.orbit-hud .oh-right { align-items: flex-end; }
.orbit-hud .oh-stat span {
  font-size: clamp(0.48rem, 1.05cqw, 0.6rem); letter-spacing: 0.2em;
  color: rgba(255, 255, 255, 0.42);
}
.orbit-hud .oh-stat b {
  font-size: clamp(1rem, 2.3cqw, 1.45rem); line-height: 1; color: #fff;
  font-variant-numeric: tabular-nums; text-shadow: 0 2px 14px rgba(0, 0, 0, 0.7);
}
.orbit-hud .oh-stat:first-child b { font-size: clamp(1.4rem, 3.4cqw, 2.2rem); }
/* Where you are, always. `say` flashes events; this line holds the fact — the current stop on
   the journey, and that the journey ends at Neptune. */
.orbit-hud .oh-where {
  margin-top: clamp(4px, 0.9cqw, 8px); text-align: center;
  display: flex; flex-direction: column; gap: 1px;
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.7);
}
.orbit-hud .oh-where b {
  font-size: clamp(0.7rem, 1.55cqw, 0.95rem); letter-spacing: 0.24em; color: #fff;
}
.orbit-hud .oh-where span {
  font-size: clamp(0.45rem, 1cqw, 0.6rem); letter-spacing: 0.2em;
  color: rgba(255, 255, 255, 0.42);
}
.orbit-hud .oh-chain {
  position: absolute; top: 22%; left: 0; right: 0; text-align: center;
  font-size: clamp(0.6rem, 1.3cqw, 0.8rem); letter-spacing: 0.2em; color: #8dff6b;
}
.orbit-hud .oh-say {
  position: absolute; top: 29%; left: 0; right: 0; text-align: center;
  font-size: clamp(0.85rem, 2cqw, 1.3rem); font-weight: 700; letter-spacing: 0.07em;
  text-shadow: 0 2px 18px rgba(0, 0, 0, 0.85);
}
.orbit-hud .oh-perfect { color: #8dff6b; animation: oh-pop 0.3s ease-out; }
.orbit-hud .oh-plain   { color: #22e6ff; animation: oh-pop 0.3s ease-out; }
.orbit-hud .oh-down    { color: #ff2f4e; animation: oh-pop 0.3s ease-out; }
.orbit-hud .oh-teach   { color: rgba(255, 255, 255, 0.8); font-weight: 600; }
@keyframes oh-pop { from { transform: scale(0.85); opacity: 0; } to { transform: scale(1); opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .orbit-hud .oh-say { animation: none !important; } }

/* ── MK Tempo's HUD ──────────────────────────────────────────────────────────────────
   The disc is the interface; this only keeps the books. The groove bar is the one thing
   that must be readable at a glance, because it is the run's life. */
.tempo-hud {
  position: absolute; inset: 0; pointer-events: none; z-index: 2;
  container-type: inline-size;
  font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
}
.tempo-hud .th-row {
  display: flex; justify-content: space-between; align-items: flex-start;
  padding: clamp(8px, 1.7cqw, 15px) clamp(120px, 13cqw, 128px) 0 clamp(12px, 2cqw, 20px);
}
.tempo-hud .th-stat { display: flex; flex-direction: column; gap: 2px; }
.tempo-hud .th-mid { align-items: center; }
.tempo-hud .th-right { align-items: flex-end; }
.tempo-hud .th-stat span {
  font-size: clamp(0.48rem, 1.05cqw, 0.6rem); letter-spacing: 0.2em;
  color: rgba(255, 255, 255, 0.42);
}
.tempo-hud .th-stat b {
  font-size: clamp(1rem, 2.3cqw, 1.45rem); line-height: 1; color: #fff;
  font-variant-numeric: tabular-nums; text-shadow: 0 2px 14px rgba(0, 0, 0, 0.7);
}
.tempo-hud .th-stat:first-child b { color: #b388ff; }
.tempo-hud .th-where {
  margin-top: clamp(4px, 0.9cqw, 8px); text-align: center;
  display: flex; flex-direction: column; gap: 1px;
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.7);
}
.tempo-hud .th-where b {
  font-size: clamp(0.7rem, 1.55cqw, 0.95rem); letter-spacing: 0.24em; color: #fff;
}
.tempo-hud .th-where span {
  font-size: clamp(0.45rem, 1cqw, 0.6rem); letter-spacing: 0.2em;
  color: rgba(255, 255, 255, 0.42);
}
/* The groove: the run's life, bottom centre where a thumb never covers it. */
.tempo-hud .th-groove {
  position: absolute; left: 50%; bottom: clamp(10px, 2.2cqw, 20px);
  transform: translateX(-50%);
  width: clamp(140px, 26cqw, 300px); height: clamp(5px, 0.8cqw, 8px);
  border-radius: 999px; background: rgba(255, 255, 255, 0.12); overflow: hidden;
}
.tempo-hud .th-groove i {
  display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, #b388ff, #22e6ff);
  transition: width 0.12s linear;
}
.tempo-hud .th-groove i.low { background: #ff2f4e; }
/* Sits in the clear wax between the label and the inner groove, so a judgement does not
   land on top of the very marks the player is reading. */
.tempo-hud .th-say {
  position: absolute; top: 31%; left: 0; right: 0; text-align: center;
  font-size: clamp(0.85rem, 2cqw, 1.3rem); font-weight: 700; letter-spacing: 0.07em;
  text-shadow: 0 2px 18px rgba(0, 0, 0, 0.85);
}
.tempo-hud .th-perfect { color: #8dff6b; animation: th-pop 0.3s ease-out; }
.tempo-hud .th-plain   { color: #22e6ff; animation: th-pop 0.3s ease-out; }
.tempo-hud .th-down    { color: #ff2f4e; animation: th-pop 0.3s ease-out; }
.tempo-hud .th-teach   { color: rgba(255, 255, 255, 0.8); font-weight: 600; }
@keyframes th-pop { from { transform: scale(0.85); opacity: 0; } to { transform: scale(1); opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .tempo-hud .th-say { animation: none !important; } }

/* MK Tempo's side picker, in the shell's own start and game-over panels. Named by piece and
   by composer, because a child should meet the names. */
.tempo-pick { margin: 4px 0 14px; }
.tempo-pick .tp-label {
  display: block; font-size: 0.6rem; letter-spacing: 0.24em;
  color: rgba(255, 255, 255, 0.45); margin-bottom: 8px;
  font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
}
.tempo-pick .tp-row { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; }
.tempo-pick .tp-btn {
  display: flex; flex-direction: column; gap: 2px; align-items: center;
  padding: 7px 11px; border-radius: 9px; cursor: pointer;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.14);
  color: rgba(255, 255, 255, 0.72);
  font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.12s ease;
}
.tempo-pick .tp-btn b { font-size: 0.68rem; letter-spacing: 0.1em; }
.tempo-pick .tp-btn span { font-size: 0.52rem; letter-spacing: 0.18em; opacity: 0.55; }
.tempo-pick .tp-btn:hover { background: rgba(255, 255, 255, 0.1); transform: translateY(-1px); }
.tempo-pick .tp-btn.on {
  background: rgba(179, 136, 255, 0.18);
  border-color: #b388ff;
  color: #fff;
}

/* ── MK Hook's readout ───────────────────────────────────────────────────────────────
   Two numbers, because this build exists to answer one question and a HUD is not it. */
.hook-hud {
  position: absolute; inset: 0; pointer-events: none; z-index: 2;
  container-type: inline-size;
  font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
}
.hook-hud .hh-row {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding-top: clamp(8px, 1.8cqw, 16px);
}
.hook-hud .hh-dist {
  font-size: clamp(1.3rem, 3.2cqw, 2.1rem); color: #fff;
  font-variant-numeric: tabular-nums; text-shadow: 0 2px 16px rgba(0, 0, 0, 0.8);
}
.hook-hud .hh-speed {
  font-size: clamp(0.55rem, 1.2cqw, 0.72rem); letter-spacing: 0.18em;
  color: rgba(255, 255, 255, 0.5);
}
.hook-hud .hh-say {
  position: absolute; top: 30%; left: 0; right: 0; text-align: center;
  font-size: clamp(0.8rem, 1.9cqw, 1.2rem); font-weight: 700; letter-spacing: 0.07em;
  text-shadow: 0 2px 18px rgba(0, 0, 0, 0.85);
}
.hook-hud .hh-perfect { color: #8dff6b; }
.hook-hud .hh-plain   { color: #22e6ff; }
.hook-hud .hh-poor    { color: #ffa41e; }
.hook-hud .hh-teach   { color: rgba(255, 255, 255, 0.8); font-weight: 600; }

/* MK Orbit's chart. Bottom-left, clear of the HUD row and of the corner buttons, and small
   enough that reading it is a glance rather than a decision. */
.orbit-map {
  position: absolute; left: clamp(10px, 2cqw, 18px); bottom: clamp(10px, 2cqw, 18px);
  z-index: 3; pointer-events: none; opacity: 0.92;
}
.orbit-map canvas { display: block; }
@media (max-width: 520px) { .orbit-map { transform: scale(0.78); transform-origin: left bottom; } }

/* MK Pulse's rhythm ticker.
 *
 * Beside the score, small and dim. Near misses and syncs arrive several times a second at full
 * speed; they are the texture of a good run rather than events in it, and their whole job is to be
 * caught out of the corner of an eye. Anything that has to be *read* does not belong here — and
 * nothing at all belongs over the middle of the road, which is where all of this used to go. */
.mkp-tick {
  position: absolute; left: 3.4cqw; top: 9.4cqw;
  font-size: 1.15cqw; font-weight: 700; letter-spacing: 0.12em; white-space: nowrap;
  opacity: 0; transform: translateY(0.4cqw);
  transition: opacity 0.12s ease, transform 0.18s cubic-bezier(.2, 1.4, .4, 1);
  text-shadow: 0 0.2cqw 0.8cqw rgba(0, 0, 0, 0.8);
}
.mkp-tick.show { opacity: 0.95; transform: translateY(0); }
.mkp-tick.near { color: #22e6ff; }
.mkp-tick.sync { color: #7cff6b; }
