/* CubeWave — mobile-first, fullscreen, no scrolling.
 * Design tokens: "candy-gel blocks". Rubik is self-hosted (OFL).
 * Theming: 6 presets via html[data-theme] (3 dark, 3 light); default = ink. */

@font-face {
  font-family: 'Rubik';
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
  src: url('../fonts/rubik-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'Rubik';
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
  src: url('../fonts/rubik-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Rubik';
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
  src: url('../fonts/rubik-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---------- Themes ---------- */

:root,
html[data-theme='ink'] {
  --ink: #0b0e1a;
  --glow1: #1b2547;
  --glow2: #1d1533;
  --dot: rgba(238, 241, 255, 0.045);
  --well: #131830;
  --cell: #202743;
  --panel: #171d36;
  --paper: #eef1ff;
  --muted: rgba(238, 241, 255, 0.5);
  --edge: rgba(255, 255, 255, 0.06);
  --inset: rgba(10, 13, 26, 0.55);
  --sheet1: #1e2547;
  --sheet2: #141a33;
  --gold: #f6b73c;
  --accent-hi: #ffd97a;
  --accent-lo: #a87c1d;
  --accent-glow: rgba(246, 183, 60, 0.28);
  --accent-soft: rgba(246, 183, 60, 0.14);
  --accent-mid: rgba(246, 183, 60, 0.45);
  --on-accent: #241a05;
  --jade: #35d07f;
  --coral: #ff5d73;
}

html[data-theme='forest'] {
  --ink: #0a120d;
  --glow1: #14301f;
  --glow2: #0f2418;
  --dot: rgba(236, 255, 244, 0.04);
  --well: #101f16;
  --cell: #1d3527;
  --panel: #15271c;
  --paper: #ecfff4;
  --muted: rgba(236, 255, 244, 0.5);
  --edge: rgba(255, 255, 255, 0.06);
  --inset: rgba(6, 14, 9, 0.55);
  --sheet1: #1a2f22;
  --sheet2: #121f17;
  --gold: #57e389;
  --accent-hi: #9df0bd;
  --accent-lo: #2a7d4e;
  --accent-glow: rgba(87, 227, 137, 0.25);
  --accent-soft: rgba(87, 227, 137, 0.13);
  --accent-mid: rgba(87, 227, 137, 0.45);
  --on-accent: #062012;
}

html[data-theme='wine'] {
  --ink: #160a10;
  --glow1: #33121f;
  --glow2: #1d0f22;
  --dot: rgba(255, 238, 242, 0.045);
  --well: #241019;
  --cell: #3a1a28;
  --panel: #2a1220;
  --paper: #ffeef2;
  --muted: rgba(255, 238, 242, 0.5);
  --edge: rgba(255, 255, 255, 0.07);
  --inset: rgba(20, 5, 12, 0.55);
  --sheet1: #2e1523;
  --sheet2: #1f0e18;
  --gold: #fb7185;
  --accent-hi: #fda4af;
  --accent-lo: #9f1239;
  --accent-glow: rgba(251, 113, 133, 0.25);
  --accent-soft: rgba(251, 113, 133, 0.13);
  --accent-mid: rgba(251, 113, 133, 0.45);
  --on-accent: #2a0812;
}

html[data-theme='porcelain'] {
  --ink: #f2f0ea;
  --glow1: #fff7e8;
  --glow2: #e8e4f2;
  --dot: rgba(38, 36, 30, 0.06);
  --well: #e3dfd4;
  --cell: #cfcabb;
  --panel: #ffffff;
  --paper: #26241e;
  --muted: rgba(38, 36, 30, 0.55);
  --edge: rgba(38, 36, 30, 0.1);
  --inset: rgba(38, 36, 30, 0.07);
  --sheet1: #ffffff;
  --sheet2: #f4f1e9;
  --gold: #d97706;
  --accent-hi: #f6b73c;
  --accent-lo: #a85f00;
  --accent-glow: rgba(217, 119, 6, 0.22);
  --accent-soft: rgba(217, 119, 6, 0.12);
  --accent-mid: rgba(217, 119, 6, 0.4);
  --on-accent: #ffffff;
}

html[data-theme='mint'] {
  --ink: #eaf6ef;
  --glow1: #f2fbf6;
  --glow2: #dff0ea;
  --dot: rgba(23, 53, 42, 0.06);
  --well: #d9ecdf;
  --cell: #c6e0cf;
  --panel: #ffffff;
  --paper: #17352a;
  --muted: rgba(23, 53, 42, 0.55);
  --edge: rgba(23, 53, 42, 0.1);
  --inset: rgba(23, 53, 42, 0.07);
  --sheet1: #ffffff;
  --sheet2: #eef7f1;
  --gold: #0e9f6e;
  --accent-hi: #3fd39a;
  --accent-lo: #047857;
  --accent-glow: rgba(14, 159, 110, 0.22);
  --accent-soft: rgba(14, 159, 110, 0.12);
  --accent-mid: rgba(14, 159, 110, 0.4);
  --on-accent: #ffffff;
}

html[data-theme='sky'] {
  --ink: #e9f0fb;
  --glow1: #f4f9ff;
  --glow2: #e2e9fb;
  --dot: rgba(23, 38, 62, 0.06);
  --well: #d9e4f5;
  --cell: #c5d6ef;
  --panel: #ffffff;
  --paper: #17263e;
  --muted: rgba(23, 38, 62, 0.55);
  --edge: rgba(23, 38, 62, 0.1);
  --inset: rgba(23, 38, 62, 0.07);
  --sheet1: #ffffff;
  --sheet2: #edf2fb;
  --gold: #2563eb;
  --accent-hi: #6aa0ff;
  --accent-lo: #1d4ed8;
  --accent-glow: rgba(37, 99, 235, 0.2);
  --accent-soft: rgba(37, 99, 235, 0.1);
  --accent-mid: rgba(37, 99, 235, 0.4);
  --on-accent: #ffffff;
}

/* ---------- Base ---------- */

:root {
  --gap: 4px;              /* must match GAP in render.js */
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  -webkit-tap-highlight-color: transparent;
}

html, body {
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
}

body {
  font-family: 'Rubik', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background:
    radial-gradient(110% 70% at 50% -10%, var(--glow1) 0%, transparent 55%),
    radial-gradient(90% 60% at 90% 110%, var(--glow2) 0%, transparent 60%),
    var(--ink);
  color: var(--paper);
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  position: fixed;
  inset: 0;
}

/* Subtle dot texture over the ambient glows. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  background-image: radial-gradient(var(--dot) 1px, transparent 1.4px);
  background-size: 22px 22px;
  pointer-events: none;
}

:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

/* The hidden attribute must always win over display rules below. */
[hidden] {
  display: none !important;
}

/* ---------- Store buttons under the board ---------- */
.stores {
  display: flex;
  gap: 8px;
  justify-content: center;
  padding: 8px 0 2px;
}

.store-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  border-radius: 11px;
  background: var(--edge);
  border: 1px solid rgba(255, 255, 255, 0.08);
  color: var(--paper);
  font-size: 12px;
  font-weight: 700;
  text-decoration: none;
  white-space: nowrap;
}

.store-btn svg { width: 15px; height: 15px; flex: none; }

/* The under-board buttons are the fallback for screens too narrow for the side
   columns; on wide screens the columns carry the store links instead. */
@media (min-width: 1081px) {
  .stores { display: none; }
}

/* Short screens need every pixel for the board. */
@media (max-height: 700px) {
  .stores { display: none; }
}

/* Points still to go before the next level, next to the progress bar. */
.level-progress {
  flex: none;
  font-size: 11px;
  font-weight: 700;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  margin-left: 8px;
}

@media (max-width: 340px) {
  .level-progress { display: none; }
}

/* Level-up flash in the middle of the board. */
.level-up {
  position: fixed;
  left: 50%;
  top: 42%;
  transform: translate(-50%, -50%) scale(0.7);
  z-index: 95;
  padding: 10px 22px;
  border-radius: 14px;
  background: var(--accent-soft, rgba(246, 183, 60, 0.18));
  border: 1px solid var(--gold);
  color: var(--gold);
  font-size: 22px;
  font-weight: 900;
  letter-spacing: 0.02em;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
}

.level-up.show {
  animation: levelUpPop 1.4s cubic-bezier(0.2, 0.9, 0.3, 1.2) forwards;
}

@keyframes levelUpPop {
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(0.7); }
  18%  { opacity: 1; transform: translate(-50%, -50%) scale(1.06); }
  30%  { transform: translate(-50%, -50%) scale(1); }
  75%  { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -80%) scale(0.95); }
}

/* The bar itself lights up for a moment when the level ticks over. */
#level-fill.level-flash {
  animation: levelFlash 0.7s ease-out;
}

@keyframes levelFlash {
  0%   { box-shadow: 0 0 0 0 var(--gold); }
  40%  { box-shadow: 0 0 12px 2px var(--gold); }
  100% { box-shadow: 0 0 0 0 transparent; }
}

@media (prefers-reduced-motion: reduce) {
  .level-up.show { animation-duration: 0.01ms; opacity: 1; }
  #level-fill.level-flash { animation: none; }
}

/* ---------- Side promo panels (admin-managed) ---------- */
/* The board is a 520 px column in the middle; the panels take the empty space
   left and right of it and disappear as soon as that space runs out. */
.promo {
  position: fixed;
  top: 0;
  bottom: 0;
  width: min(260px, calc((100vw - 560px) / 2 - 24px));
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  z-index: 40;
  pointer-events: none;
}

.promo-left { left: 0; }
.promo-right { right: 0; }

/* A column holds up to three things: promo, store button, promo. */
.promo-stack {
  pointer-events: auto;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-height: 86vh;
  overflow-y: auto;
}

.store-btn-wide { justify-content: center; }

.promo-card {
  pointer-events: auto;
  width: 100%;
  background: var(--panel, var(--edge));
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 16px;
  padding: 16px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
}

.promo-title {
  font-size: 15px;
  font-weight: 800;
  color: var(--gold);
  margin-bottom: 6px;
}

.promo-title:empty { display: none; }

.promo-text {
  font-size: 14px;
  line-height: 1.55;
  color: var(--muted);
  white-space: pre-wrap;
  word-break: break-word;
}

.promo-btn {
  display: block;
  margin-top: 12px;
  padding: 9px 12px;
  border-radius: 10px;
  background: var(--gold);
  color: #241a00;
  font-size: 13px;
  font-weight: 800;
  text-align: center;
  text-decoration: none;
}

/* No room beside the board — the game always wins. */
@media (max-width: 1080px) {
  .promo { display: none; }
}

#app {
  position: relative;
  height: 100%;
  max-width: 520px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  padding: calc(env(safe-area-inset-top, 0px) + 8px) 14px calc(env(safe-area-inset-bottom, 0px) + 12px);
}

/* ---------- HUD ---------- */

#hud {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 6px 0 12px;
}

.score-hero {
  text-align: center;
  line-height: 1;
}

.score-num {
  font-size: 42px;
  font-weight: 900;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
}

.score-num.bump {
  animation: bump 0.25s ease;
}

@keyframes bump {
  0% { transform: scale(1); }
  40% { transform: scale(1.14); }
  100% { transform: scale(1); }
}

.score-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.22em;
  color: var(--muted);
  margin-top: 3px;
}

.best-chip {
  display: flex;
  align-items: center;
  gap: 7px;
  background: var(--panel);
  border: 1px solid var(--edge);
  border-radius: 14px;
  padding: 7px 12px;
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.18);
}

.crown {
  visibility: hidden;
  width: 17px;
  height: 17px;
  color: var(--gold);
  display: inline-flex;
}

.crown svg {
  width: 100%;
  height: 100%;
}

.best-text {
  display: flex;
  flex-direction: column;
  line-height: 1.05;
}

.best-num {
  font-size: 17px;
  font-weight: 800;
  color: var(--gold);
  font-variant-numeric: tabular-nums;
}

.chip-label {
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: 0.2em;
  color: var(--muted);
}

.hud-buttons {
  display: flex;
  gap: 7px;
}

.icon-btn {
  width: 38px;
  height: 38px;
  border: 1px solid var(--edge);
  border-radius: 13px;
  background: var(--panel);
  color: var(--paper);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 3px 0 rgba(0, 0, 0, 0.2);
  transition: transform 0.06s ease, box-shadow 0.06s ease;
}

.icon-btn:active {
  transform: translateY(2px);
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2);
}

.icon-btn svg {
  width: 19px;
  height: 19px;
}

/* Sound off: dim the icon so the state reads at a glance, not only from the
   slash across the speaker. */
.icon-btn.muted {
  color: var(--muted);
}

/* ---------- Level bar ---------- */

#level-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 2px 12px;
}

.level-label {
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.14em;
  color: var(--muted);
  white-space: nowrap;
}

.level-label #level-num {
  color: var(--gold);
}

.level-track {
  flex: 1;
  height: 7px;
  border-radius: 4px;
  background: var(--inset);
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.25);
  overflow: hidden;
}

#level-fill {
  height: 100%;
  width: 0;
  border-radius: 4px;
  background: linear-gradient(90deg, var(--accent-hi), var(--gold));
  box-shadow: 0 0 8px var(--accent-glow);
  transition: width 0.3s ease;
}

/* Match clock and pause share one chip — see index.html for why they are merged. */
.time-chip {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  border: 1px solid var(--edge);
  border-radius: 999px;
  padding: 4px 10px;
  font: inherit;
  font-size: 11px;
  font-weight: 800;
  color: var(--muted);
  background: var(--inset);
  cursor: pointer;
  white-space: nowrap;
}

.time-chip svg {
  width: 11px;
  height: 11px;
  flex: none;
}

.time-chip:disabled {
  opacity: 0.55;
  cursor: default;
}

.time-chip:not(:disabled):active {
  transform: scale(0.95);
}

.time-chip.paused {
  color: var(--gold);
  border-color: var(--accent-mid);
}

/* Fixed width, so a changing digit never nudges the level bar around. */
.time-num {
  font-variant-numeric: tabular-nums;
  min-width: 4ch;
  text-align: left;
}

.mode-pill {
  flex: 0 0 auto;
  border: 1px solid var(--edge);
  border-radius: 999px;
  padding: 4px 12px;
  font: inherit;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--gold);
  background: var(--inset);
  cursor: pointer;
  white-space: nowrap;
}

.mode-pill:active {
  transform: scale(0.95);
}

/* ---------- Board ---------- */

#board-wrap {
  flex: 0 0 auto;
  display: flex;
  justify-content: center;
}

#board {
  width: 100%;
  max-width: min(100%, 56vh);
  aspect-ratio: 1;
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  grid-template-rows: repeat(8, 1fr);
  gap: var(--gap);
  background: var(--well);
  padding: calc(var(--gap) + 2px);
  border-radius: 18px;
  border: 1px solid var(--edge);
  box-shadow:
    0 14px 34px rgba(0, 0, 0, 0.28),
    inset 0 3px 12px rgba(0, 0, 0, 0.3);
}

.cell {
  border-radius: 22%;
  background: var(--cell);
  box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.25), inset 0 -1px 1px rgba(255, 255, 255, 0.03);
  transition: background 0.08s ease;
  /* The placement sweep rides on ::after and has to be clipped to the cell. */
  position: relative;
  overflow: hidden;
}

/* Candy-gel block: gloss on top, shade below. Color comes from --c (set in JS). */
.cell.filled, .pblock {
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.30) 0%, rgba(255, 255, 255, 0.06) 38%, rgba(0, 0, 0, 0.06) 100%),
    var(--c);
  box-shadow:
    inset 0 2px 0 rgba(255, 255, 255, 0.38),
    inset 0 -3px 0 rgba(0, 0, 0, 0.24),
    inset 2px 0 0 rgba(255, 255, 255, 0.07),
    0 2px 4px rgba(0, 0, 0, 0.25);
}

/* Help mode: an outline around every square the picked piece still fits on. An
   outline and not a fill on purpose — the landing preview right below is a solid
   green block, and the order the eye must read the board in is: landing spot
   first, lines about to burn second, reachable squares last. The cell keeps its
   own background, so a board full of outlines still reads as an empty board. */
.cell.hint {
  box-shadow:
    inset 0 0 0 2px rgba(53, 208, 127, 0.42),
    inset 0 2px 5px rgba(0, 0, 0, 0.25);
}

.cell.ghost-ok {
  background: rgba(53, 208, 127, 0.5) !important;
  box-shadow: inset 0 0 0 2px rgba(160, 255, 205, 0.75);
}

.cell.ghost-bad {
  background: rgba(255, 93, 115, 0.42) !important;
  box-shadow: inset 0 0 0 2px rgba(255, 170, 182, 0.6);
}

.cell.ghost-clear {
  animation: pulse 0.5s ease infinite alternate;
}

@keyframes pulse {
  from { filter: brightness(1); }
  to { filter: brightness(1.65); }
}

.cell.pop {
  animation: pop 0.25s ease;
}

@keyframes pop {
  0% { transform: scale(0.4); }
  60% { transform: scale(1.12); }
  100% { transform: scale(1); }
}

/* One gloss sweep confirming a placement. It lives on ::after on purpose: the
   cell itself is already the stage for pop / clearing / the ghost-clear pulse,
   and two animations on one element would cancel each other out. The per-cell
   delay comes from JS (--shine-delay) and is what makes it a wave rather than a
   flash. */
.cell.shine::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(115deg,
    rgba(255, 255, 255, 0) 30%,
    rgba(255, 255, 255, 0.62) 50%,
    rgba(255, 255, 255, 0) 70%);
  animation: cellShine 0.32s ease-out var(--shine-delay, 0ms) both;
}

@keyframes cellShine {
  from { transform: translateX(-115%); opacity: 0.95; }
  to { transform: translateX(115%); opacity: 0; }
}

.cell.clearing {
  animation: clearPop 0.3s ease forwards;
}

@keyframes clearPop {
  0% { transform: scale(1); opacity: 1; filter: brightness(1.7); }
  40% { transform: scale(1.15); opacity: 1; }
  100% { transform: scale(0); opacity: 0; }
}

/* ---------- Tray ---------- */

#tray {
  flex: 1 1 auto;
  min-height: 100px;
  display: flex;
  gap: 10px;
  padding-top: 16px;
}

.slot {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--inset);
  border: 1px solid var(--edge);
  border-radius: 16px;
  box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.2);
}

.piece {
  display: grid;
  gap: var(--gap);
  touch-action: none;
  cursor: grab;
  filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.28));
}

.pblock {
  border-radius: 22%;
}

.pempty {
  visibility: hidden;
}

/* ---------- Drag layer ---------- */

#drag-layer {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 50;
}

#drag-layer .piece.dragging {
  position: fixed;
  left: 0;
  top: 0;
  transform-origin: center;
  filter: drop-shadow(0 12px 16px rgba(0, 0, 0, 0.4));
  will-change: transform;
}

#drag-layer .piece.flyback {
  transition: transform 0.22s ease-in;
}

.floater {
  position: fixed;
  transform: translate(-50%, -50%);
  font-size: 26px;
  font-weight: 800;
  color: #fff;
  text-shadow: 0 2px 10px rgba(0, 0, 0, 0.65);
  animation: floatUp 0.95s ease-out forwards;
  white-space: nowrap;
}

.floater.big {
  font-size: 34px;
  font-weight: 900;
  color: var(--gold);
}

@keyframes floatUp {
  0% { opacity: 0; transform: translate(-50%, -50%) scale(0.6); }
  15% { opacity: 1; transform: translate(-50%, -60%) scale(1.1); }
  100% { opacity: 0; transform: translate(-50%, -220%) scale(1); }
}

/* ---------- Settings sheet ---------- */

#settings {
  position: fixed;
  inset: 0;
  background: rgba(6, 8, 17, 0.7);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: 110;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}

/* Leaderboard overlay reuses the settings sheet look. */
#leaderboard-sheet {
  position: fixed;
  inset: 0;
  background: rgba(6, 8, 17, 0.7);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: 115;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}

.lb-tabs {
  display: flex;
  gap: 8px;
  padding: 0 18px 10px;
}

.lb-tab {
  flex: 1;
  border: 1px solid var(--edge);
  border-radius: 12px;
  padding: 9px 0;
  font: inherit;
  font-size: 13px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  background: var(--inset);
  cursor: pointer;
}

.lb-tab.active {
  color: var(--gold);
  border-color: var(--gold);
  background: var(--inset);
}

.sheet {
  width: 100%;
  max-width: 520px;
  max-height: 86%;
  display: flex;
  flex-direction: column;
  background: linear-gradient(180deg, var(--sheet1) 0%, var(--sheet2) 100%);
  border: 1px solid var(--edge);
  border-radius: 24px 24px 0 0;
  box-shadow: 0 -12px 48px rgba(0, 0, 0, 0.4);
}

.sheet-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 16px 10px 22px;
}

.sheet-title {
  font-size: 20px;
  font-weight: 900;
}

.sheet-body {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y;
  padding: 0 18px calc(env(safe-area-inset-bottom, 0px) + 22px);
}

.sheet-section {
  padding: 16px 2px;
  border-top: 1px solid var(--edge);
}

.sheet-section:first-child {
  border-top: none;
}

.sheet-section h3 {
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 12px;
}

/* Form */
#account-form input {
  display: block;
  width: 100%;
  margin-bottom: 10px;
  padding: 13px 16px;
  font-family: inherit;
  font-size: 16px; /* ≥16px: no iOS auto-zoom */
  font-weight: 500;
  color: var(--paper);
  background: var(--inset);
  border: 1px solid var(--edge);
  border-radius: 13px;
  outline: none;
}

#account-form input:focus {
  border-color: var(--accent-mid);
}

.form-error {
  color: var(--coral);
  font-size: 13px;
  font-weight: 500;
  margin: -2px 0 10px;
}

.again-btn.wide {
  width: 100%;
}

.again-btn:disabled {
  opacity: 0.6;
}

.profile-line {
  font-size: 15px;
  padding: 5px 0;
  color: var(--paper);
}

.profile-line b {
  color: var(--gold);
}

.signin-btn {
  margin-top: 4px;
}

.danger-btn {
  width: 100%;
  margin-top: 14px;
  border: 1px solid var(--coral);
  border-radius: 14px;
  padding: 12px 20px;
  font-family: inherit;
  font-size: 15px;
  font-weight: 700;
  color: var(--coral);
  background: transparent;
  cursor: pointer;
}

.danger-btn:active {
  opacity: 0.7;
}

.legal-links {
  display: flex;
  gap: 18px;
}

.legal-links a {
  color: var(--gold);
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
}

/* Leaderboard */
.lb-list {
  list-style: none;
  counter-reset: rank;
}

.lb-list li {
  counter-increment: rank;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 9px 12px;
  border-radius: 11px;
  font-size: 15px;
}

.lb-list li:nth-child(odd) {
  background: var(--edge);
}

.lb-list li::before {
  content: counter(rank);
  width: 26px;
  font-weight: 800;
  font-size: 13px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.lb-list li:nth-child(1)::before,
.lb-list li:nth-child(2)::before,
.lb-list li:nth-child(3)::before { color: var(--gold); }

/* When the personal best was set — quiet, between the name and the score. */
.lb-date {
  flex: none;
  margin: 0 10px;
  font-size: 12px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

@media (max-width: 380px) {
  .lb-date { display: none; }
}

.lb-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 500;
}

.lb-score {
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--gold);
}

.lb-list li.me {
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px var(--accent-mid);
}

.lb-note {
  font-size: 14px;
  color: var(--muted);
  padding: 6px 2px;
}

/* Language grid */
.lang-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 7px;
}

.lang-item {
  border: 1px solid var(--edge);
  background: var(--inset);
  color: var(--paper);
  font-family: inherit;
  font-size: 13.5px;
  font-weight: 500;
  padding: 10px 8px;
  border-radius: 11px;
  cursor: pointer;
  text-align: center;
}

.lang-item:active {
  background: var(--edge);
}

.lang-item.active,
.track-item.active,
.theme-item.active {
  background: var(--accent-soft);
  border-color: var(--accent-mid);
  color: var(--gold);
  font-weight: 700;
}

/* Theme picker */
.theme-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 7px;
}

.theme-item {
  display: flex;
  align-items: center;
  gap: 8px;
  border: 1px solid var(--edge);
  background: var(--inset);
  color: var(--paper);
  font-family: inherit;
  font-size: 13px;
  font-weight: 500;
  padding: 9px 10px;
  border-radius: 11px;
  cursor: pointer;
}

.theme-swatch {
  width: 22px;
  height: 22px;
  border-radius: 8px;
  flex: 0 0 auto;
  border: 1px solid rgba(0, 0, 0, 0.25);
}

/* Toggles + tracks */
.toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 2px;
  font-size: 15px;
  font-weight: 500;
}

.toggle {
  width: 52px;
  height: 30px;
  border: none;
  border-radius: 15px;
  background: var(--inset);
  box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.3);
  cursor: pointer;
  position: relative;
  transition: background 0.18s ease;
}

.toggle .knob {
  position: absolute;
  top: 3px;
  inset-inline-start: 3px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--paper);
  opacity: 0.85;
  transition: transform 0.18s ease, background 0.18s ease, opacity 0.18s ease;
}

.toggle.on {
  background: var(--accent-mid);
}

.toggle.on .knob {
  transform: translateX(22px);
  background: var(--gold);
  opacity: 1;
}

[dir="rtl"] .toggle.on .knob {
  transform: translateX(-22px);
}

/* One line of explanation under a toggle whose name alone does not say enough. */
.toggle-hint {
  margin: 0 2px 4px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--muted);
}

.track-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 6px 0 10px;
}

.track-item {
  border: 1px solid var(--edge);
  background: var(--inset);
  color: var(--paper);
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  padding: 11px 14px;
  border-radius: 11px;
  cursor: pointer;
  text-align: start;
}

.credit {
  font-size: 11.5px;
  color: var(--muted);
  padding-top: 10px;
}

.levels-text {
  font-size: 14px;
  line-height: 1.55;
  color: var(--paper);
}

/* ---------- Game-over overlay ---------- */

#overlay {
  position: fixed;
  inset: 0;
  background: rgba(6, 8, 17, 0.78);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease, visibility 0.3s;
}

#overlay.visible {
  opacity: 1;
  visibility: visible;
}

.overlay-card {
  background: linear-gradient(180deg, var(--sheet1) 0%, var(--sheet2) 100%);
  border: 1px solid var(--edge);
  border-radius: 26px;
  padding: 34px 44px;
  text-align: center;
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.5);
  transform: translateY(14px) scale(0.97);
  transition: transform 0.3s cubic-bezier(0.2, 0.9, 0.3, 1.2);
}

#overlay.visible .overlay-card {
  transform: translateY(0) scale(1);
}

.overlay-title {
  font-size: 27px;
  font-weight: 900;
  letter-spacing: 0.01em;
  margin-bottom: 10px;
}

.new-record {
  display: none;
  color: var(--gold);
  font-weight: 800;
  margin-bottom: 8px;
}

.overlay-score-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.22em;
  color: var(--muted);
  margin-top: 12px;
}

.overlay-score {
  font-size: 56px;
  font-weight: 900;
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
}

.overlay-best {
  color: var(--muted);
  font-weight: 500;
  margin-bottom: 24px;
}

.overlay-best span:last-child {
  color: var(--gold);
  font-weight: 800;
}

/* Pause: a solid, blurred cover over the whole game. It sits below the game-over
   overlay (z-index 100) — the two can never be up at the same time anyway. */
.pause-overlay {
  position: fixed;
  inset: 0;
  background: rgba(6, 8, 17, 0.9);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 90;
}

.again-btn {
  border: none;
  border-radius: 16px;
  padding: 15px 36px;
  font-family: inherit;
  font-size: 18px;
  font-weight: 800;
  color: var(--on-accent);
  background: linear-gradient(180deg, var(--accent-hi) 0%, var(--gold) 100%);
  cursor: pointer;
  box-shadow: 0 4px 0 var(--accent-lo), 0 8px 20px var(--accent-glow);
  transition: transform 0.06s ease, box-shadow 0.06s ease;
}

.again-btn:active {
  transform: translateY(3px);
  box-shadow: 0 1px 0 var(--accent-lo), 0 4px 12px var(--accent-glow);
}

/* Small phones */
@media (max-height: 600px) {
  #tray { min-height: 84px; padding-top: 10px; }
  .score-num { font-size: 32px; }
}

/* ---------- Profile edit (nickname + country) ---------- */

.profile-edit {
  margin-top: 10px;
}

.profile-label {
  display: block;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--muted);
  margin: 10px 0 4px;
}

.profile-row input,
.profile-row select {
  width: 100%;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  color: var(--paper);
  background: var(--edge);
  border: 1px solid transparent;
  border-radius: 11px;
  padding: 10px 12px;
  outline: none;
}

.profile-row input:focus,
.profile-row select:focus {
  border-color: var(--accent-mid);
}

#profile-save-btn {
  width: 100%;
  margin-top: 12px;
  padding: 11px 20px;
  font-size: 15px;
  border-radius: 13px;
}

.lb-flag {
  margin-right: 6px;
  font-style: normal;
}

/* ---------- Announcement banner ---------- */

#ann-banner {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 60;
  display: flex;
  justify-content: center;
  /* `top` is set from JS to sit under the HUD — the banner must never cover the
     settings/leaderboard buttons (it used to swallow every tap on them). */
  padding: 8px 12px 0;
  transform: translateY(-110%);
  transition: transform 0.35s cubic-bezier(0.2, 0.9, 0.3, 1.2);
  pointer-events: none;
}

#ann-banner.show {
  transform: translateY(0);
}

.ann-card {
  pointer-events: auto;
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: 520px;
  width: 100%;
  background: var(--panel, var(--edge));
  border: 1px solid var(--accent-mid);
  border-radius: 16px;
  padding: 12px 14px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35);
}

.ann-texts {
  flex: 1;
  min-width: 0;
}

.ann-title {
  font-size: 15px;
  font-weight: 800;
  color: var(--gold);
}

.ann-text {
  font-size: 13px;
  color: var(--paper);
  margin-top: 2px;
  word-wrap: break-word;
}

.ann-link {
  flex-shrink: 0;
  font-family: inherit;
  font-size: 13px;
  font-weight: 700;
  color: var(--on-accent, #fff);
  background: var(--accent-mid);
  border: 0;
  border-radius: 10px;
  padding: 8px 14px;
  cursor: pointer;
}

#ann-close {
  flex-shrink: 0;
  width: 34px;
  height: 34px;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  /* Zeroing the duration is not enough here: a sweep that lasts 0.01ms still
     paints one white frame over the cell. Drop the element instead. JS skips the
     class too — this is the safety net. */
  .cell.shine::after { content: none; }
}

/* Four 38px buttons plus gaps need 173px; on a 320px screen that pushed the last
   one off the edge, and the page cannot scroll (body is overflow:hidden), so the
   restart button was simply unreachable. Shrink the row instead of losing buttons. */
@media (max-width: 359px) {
  #hud { gap: 6px; }
  .hud-buttons { gap: 4px; }
  .icon-btn { width: 32px; height: 32px; }
  .icon-btn svg { width: 17px; height: 17px; }
  .best-chip { padding: 4px 8px; }
  .score-num { font-size: 30px; }
}

/* Same story one row down: with the clock chip the level bar carries four
   controls, and on a phone the progress track was squeezed to a stub. Tighten the
   row instead of dropping a control — the track has to stay readable. */
@media (max-width: 400px) {
  #level-bar { gap: 6px; }
  .time-chip { padding: 4px 8px; gap: 4px; }
  .mode-pill { padding: 4px 9px; letter-spacing: 0.06em; }
}

/* ---------- Install / update (PWA) ---------- */

.install-note {
  margin-top: 10px;
}

/* Bottom edge on purpose: the announcement banner already owns the top, and the
   two must never stack over the HUD buttons.
   The bar does NOT float over the game. Measured at 320x568 it covered three
   tray pieces — which is how the announcement banner once swallowed every tap on
   the header — so the app gives up that height instead, and pwa.js fires a
   resize so the tray re-renders into what is left. */
body.cw-update #app {
  /* Measured by pwa.js: the bar wraps to two lines on a 320px screen and the
     sentence is a different length in each of the 31 languages, so a fixed
     number here would be wrong for someone. */
  padding-bottom: calc(env(safe-area-inset-bottom, 0px) + var(--update-bar-h, 60px) + 24px);
}

.update-bar {
  position: fixed;
  left: 12px;
  right: 12px;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 12px);
  z-index: 70;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  flex-wrap: wrap;
  max-width: 520px;
  margin: 0 auto;
  padding: 11px 14px;
  border-radius: 16px;
  background: var(--panel, var(--edge));
  border: 1px solid var(--accent-mid);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35);
  font-size: 13.5px;
  font-weight: 600;
  color: var(--paper);
}

.update-btn {
  flex-shrink: 0;
  font-family: inherit;
  font-size: 13px;
  font-weight: 800;
  color: var(--on-accent, #fff);
  background: var(--accent-mid);
  border: 0;
  border-radius: 10px;
  padding: 8px 16px;
  cursor: pointer;
}

.update-btn:active {
  transform: translateY(1px);
}

/* On a 320px screen the tray has already been squeezed to its minimum height, so
   there is nothing left to give: keep the bar to a single line there instead.
   Without this the Greek and German sentences wrapped and the bar clipped the
   bottom row of tray pieces by a few pixels. */
@media (max-width: 400px) {
  .update-bar {
    gap: 8px;
    padding: 8px 10px;
    font-size: 12px;
    flex-wrap: nowrap;
  }

  .update-bar span {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .update-btn { padding: 7px 12px; font-size: 12px; }
}
