/* Servo -- overlay chrome. The play field itself is canvas; everything here
   is the screens layered on top of it. Palette is shared with the art
   direction so DOM and canvas cannot drift apart. */

:root {
  --bg-deep: #06090f;
  --bg-warm: #141326;
  --dirt: #3b2a1b;
  --hole: #150c07;
  --rim: #8a5a34;
  --amber: #ff9a3c;
  --cream: #f7f1e4;
  --ink: #160d0a;
  --pink: #f06fa8;
  /* Points green. Bright enough to carry on the dark panel; the grass greens
     from the play field are far too dark to read as text. */
  --green: #7dc95a;
  --danger: #e0452b;
  --display: Impact, "Arial Black", "Haettenschweiler", system-ui, sans-serif;
  --body: "Trebuchet MS", "Segoe UI", system-ui, -apple-system, sans-serif;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden;
  background: linear-gradient(180deg, var(--bg-deep) 0%, var(--bg-warm) 100%);
  color: var(--cream);
  font-family: var(--body);
  /* The whole point is tapping fast; none of the browser's touch gestures help. */
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
  overscroll-behavior: none;
}

#game-root { position: fixed; inset: 0; }

.game-canvas { display: block; width: 100%; height: 100%; }

/* Hide the native cursor over the play field -- the mallet sprite is the cursor. */
body[data-state="playing"] .game-canvas,
body[data-state="countdown"] .game-canvas { cursor: none; }

#overlay {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  pointer-events: none;
  padding: max(16px, env(safe-area-inset-top)) 16px max(16px, env(safe-area-inset-bottom));
}

.screen {
  pointer-events: auto;
  width: min(560px, 92vw);
  max-height: 92vh;
  overflow-y: auto;
  text-align: center;
  padding: clamp(18px, 4vw, 32px);
  border-radius: 20px;
  background: rgba(21, 12, 7, 0.88);
  border: 3px solid var(--rim);
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.65), inset 0 1px 0 rgba(255, 154, 60, 0.18);
  backdrop-filter: blur(6px);
  animation: rise 220ms ease-out;
}

.screen[hidden] { display: none; }

@keyframes rise {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: none; }
}

/* The logo is drawn on the canvas, in the upper half of the play field. The
   menu therefore anchors to the BOTTOM of the viewport instead of centring,
   or the panel lands straight on top of it. Every other screen still centres. */
body[data-screen="menu"] #overlay { align-items: end; }

/* The level pill and its reset control sit on one row: the button undoes
   exactly the number beside it, and putting them together says so without
   needing a label. */
.menu-level-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

/* Quiet by default -- destructive, and used once in a hundred visits, so it
   must not compete with JOUER. It only turns red once armed. */
.btn-reset {
  font-family: var(--body);
  font-size: 12px;
  letter-spacing: 1px;
  padding: 7px 12px;
  min-height: 34px;
  border-radius: 999px;
  border: 1px solid rgba(247, 241, 228, 0.28);
  background: transparent;
  color: #c8b49b;
  cursor: pointer;
  transition: color 120ms ease, border-color 120ms ease, background 120ms ease;
}
.btn-reset:hover { color: var(--cream); border-color: rgba(247, 241, 228, 0.55); }
.btn-reset:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }

.btn-reset.is-armed {
  color: #fff;
  background: var(--danger);
  border-color: var(--danger);
  font-weight: bold;
}

/* Current level, on the menu. Reads from the stored value, so it is correct
   the instant the player returns from a game that promoted them. */
.menu-level {
  display: inline-block;
  margin: 0;
  padding: 7px 16px;
  border-radius: 999px;
  font-size: 13px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--cream);
  background: rgba(255, 154, 60, 0.12);
  border: 2px solid rgba(255, 154, 60, 0.4);
}

.menu-level strong {
  font-family: var(--display);
  font-size: 26px;
  letter-spacing: 1px;
  color: var(--amber);
  vertical-align: -3px;
  margin-left: 6px;
}

.wordmark {
  font-family: var(--display);
  font-size: clamp(52px, 12vw, 96px);
  letter-spacing: 4px;
  margin: 0 0 20px;
  color: var(--amber);
  text-shadow: 0 4px 0 var(--ink), 0 0 34px rgba(255, 154, 60, 0.4);
}

.screen-title {
  font-family: var(--display);
  font-size: clamp(30px, 7vw, 46px);
  letter-spacing: 3px;
  margin: 0 0 12px;
  color: var(--amber);
  text-shadow: 0 3px 0 var(--ink);
}

.tagline { font-size: clamp(15px, 3.6vw, 19px); margin: 0 0 22px; color: var(--cream); }
.muted { color: #c8b49b; font-size: 14px; margin: 8px 0; }

/* --- buttons ---------------------------------------------------------- */

.btn-row { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin: 18px 0 6px; }

.btn {
  font-family: var(--display);
  font-size: clamp(17px, 3.6vw, 21px);
  letter-spacing: 2px;
  padding: 14px 26px;
  min-height: 52px; /* comfortable touch target on a 375px phone */
  border-radius: 12px;
  border: 3px solid var(--ink);
  background: #4a2c17;
  color: var(--cream);
  cursor: pointer;
  transition: transform 90ms ease, filter 120ms ease;
}
.btn:hover { filter: brightness(1.16); }
.btn:active { transform: translateY(2px); }
.btn:focus-visible { outline: 3px solid var(--amber); outline-offset: 3px; }
.btn:disabled { opacity: 0.6; cursor: progress; }

.btn-primary {
  background: linear-gradient(180deg, #ff9a3c 0%, #d4661a 100%);
  color: var(--ink);
  box-shadow: 0 5px 0 #8a3d0c;
}
.btn-primary:active { box-shadow: 0 2px 0 #8a3d0c; }

/* In-game controls: only exist while a round is running, and sit in the
   bottom-left corner opposite the mute toggle so none of them can be hit by
   accident while aiming at the back row. */
#ingame-controls {
  position: fixed;
  left: max(12px, env(safe-area-inset-left));
  bottom: max(12px, env(safe-area-inset-bottom));
  z-index: 10;
  display: none;
  gap: 8px;
  pointer-events: auto;
}

body[data-state="playing"] #ingame-controls,
body[data-state="countdown"] #ingame-controls { display: flex; }

.btn-ingame {
  font-size: 13px;
  letter-spacing: 1px;
  padding: 9px 14px;
  min-height: 44px;
  opacity: 0.82;
}

.btn-mute {
  position: fixed;
  right: max(12px, env(safe-area-inset-right));
  bottom: max(12px, env(safe-area-inset-bottom));
  z-index: 10;
  pointer-events: auto;
  font-size: 13px;
  letter-spacing: 1px;
  padding: 9px 14px;
  min-height: 44px;
  opacity: 0.82;
}

/* --- menu rules ------------------------------------------------------- */

.rules {
  list-style: none;
  margin: 18px 0 0;
  padding: 16px;
  text-align: left;
  font-size: 14px;
  line-height: 1.55;
  border-radius: 12px;
  background: rgba(255, 154, 60, 0.07);
  border: 1px solid rgba(255, 154, 60, 0.22);
}
.rules li + li { margin-top: 8px; }
/* Pink is Agent Gabriel's colour -- it matches his shirt, and using it for
   emphasis generally would dilute the one signal the player must not miss.
   Anything that is not about him gets its own colour. */
.rules strong { color: var(--pink); }
.rules strong.pts { color: var(--green); }
/* Reuses --danger, the red already used for the timer under ten seconds, so
   the interface has one red rather than two that nearly match. */
.rules strong.lvl { color: var(--danger); }

/* Inline SVG rather than CSS shapes: an octagon needs clip-path, which would
   take the border away with the corners, and neither an octagon nor an
   hourglass reads correctly as a styled box at 18px. */
.rule-icon {
  width: 18px;
  height: 18px;
  vertical-align: -4px;
  margin-right: 2px;
}

/* --- loading ---------------------------------------------------------- */

.loading-track {
  width: 100%; height: 14px;
  background: rgba(0, 0, 0, 0.5);
  border: 2px solid var(--rim);
  border-radius: 8px;
  overflow: hidden;
}
.loading-bar {
  height: 100%; width: 0%;
  background: linear-gradient(90deg, #d4661a, var(--amber));
  transition: width 180ms ease;
}

/* --- game over -------------------------------------------------------- */

.final-score-label { font-size: 13px; letter-spacing: 3px; color: var(--amber); margin: 6px 0 0; }
.final-score {
  font-family: var(--display);
  font-size: clamp(56px, 15vw, 90px);
  margin: 0;
  line-height: 1;
  text-shadow: 0 4px 0 var(--ink);
}

.stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  margin: 20px 0 4px;
}
.stats > div {
  padding: 10px 4px;
  border-radius: 10px;
  background: rgba(255, 154, 60, 0.08);
  border: 1px solid rgba(255, 154, 60, 0.2);
}
.stats dt { font-size: 11px; letter-spacing: 1px; color: #c8b49b; text-transform: uppercase; }
.stats dd { margin: 4px 0 0; font-family: var(--display); font-size: 22px; }

.levelup-banner {
  margin: 10px 0 0;
  padding: 9px 12px;
  border-radius: 9px;
  font-size: 14px;
  font-weight: bold;
  color: var(--amber);
  background: rgba(255, 154, 60, 0.13);
  border: 1px solid rgba(255, 154, 60, 0.34);
}

/* --- name entry ------------------------------------------------------- */

.name-slots { display: flex; gap: 10px; justify-content: center; margin: 20px 0 14px; }

.name-slot {
  width: clamp(52px, 15vw, 68px);
  height: clamp(64px, 18vw, 84px);
  font-family: var(--display);
  font-size: clamp(30px, 8vw, 42px);
  color: var(--cream);
  background: #2a180d;
  border: 3px solid var(--rim);
  border-radius: 10px;
  cursor: pointer;
  transition: border-color 120ms ease, transform 90ms ease;
}
.name-slot:hover { border-color: var(--amber); }
.name-slot:active { transform: translateY(2px); }
.name-slot:focus-visible { outline: 3px solid var(--amber); outline-offset: 2px; }
.name-slot.is-empty { color: #6a5340; }

.name-input {
  width: min(280px, 80%);
  padding: 12px;
  font-family: var(--display);
  font-size: 30px;
  letter-spacing: 10px;
  text-align: center;
  text-transform: uppercase;
  color: var(--cream);
  background: #2a180d;
  border: 3px solid var(--rim);
  border-radius: 10px;
}
.name-input:focus { outline: none; border-color: var(--amber); }

.name-error { color: var(--danger); font-size: 14px; margin: 12px 0 0; font-weight: bold; }

.lb-hint {
  margin: 10px 0 0;
  font-size: 12px;
  color: #a89076;
}
.lb-hint a { color: var(--amber); }

/* Level tabs. Built from the levels that actually have scores, so a tab never
   opens an empty board. */
.lb-levels {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  justify-content: center;
  margin: 0 0 12px;
}

.lb-tab {
  font-family: var(--display);
  font-size: 13px;
  letter-spacing: 1px;
  padding: 6px 11px;
  min-height: 32px;
  border-radius: 999px;
  border: 1px solid rgba(255, 154, 60, 0.3);
  background: transparent;
  color: #c8b49b;
  cursor: pointer;
}
.lb-tab:hover { color: var(--cream); border-color: rgba(255, 154, 60, 0.6); }
.lb-tab:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }
.lb-tab.is-active {
  background: rgba(255, 154, 60, 0.22);
  border-color: var(--amber);
  color: var(--amber);
}
/* Pill, not bare digits: "N1" followed by a loose "2" reads as level 12. The
   enclosed background is what separates the count from the level number. */
.lb-tab-count {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.42);
  font-family: var(--body);
  font-size: 10px;
  line-height: 1.5;
  opacity: 0.9;
}

/* Per-row delete. Quiet until hovered -- it sits next to every row, so it must
   not read as the primary thing on the line. */
.lb-delete {
  width: 26px;
  height: 26px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid rgba(247, 241, 228, 0.22);
  background: transparent;
  color: #a89076;
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
}
.lb-delete:hover { color: #fff; background: var(--danger); border-color: var(--danger); }
.lb-delete:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }
.lb-delete:disabled { opacity: 0.4; cursor: progress; }
.lb-delete.is-failed { color: #fff; background: var(--danger); border-color: var(--danger); }

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

.leaderboard { list-style: none; margin: 14px 0; padding: 0; }

.lb-row {
  display: grid;
  grid-template-columns: 44px 1fr auto auto 92px auto;
  gap: 8px;
  align-items: center;
  padding: 10px 12px;
  border-radius: 9px;
  font-size: 15px;
  background: rgba(255, 255, 255, 0.03);
}
.lb-row + .lb-row { margin-top: 5px; }
.lb-row.is-you {
  background: rgba(255, 154, 60, 0.2);
  border: 2px solid var(--amber);
  box-shadow: 0 0 18px rgba(255, 154, 60, 0.3);
}
.lb-rank { font-family: var(--display); color: var(--amber); font-size: 18px; }
.lb-name { font-family: var(--display); letter-spacing: 3px; font-size: 19px; text-align: left; }
.lb-points { font-family: var(--display); font-size: 19px; }
/* The level a score was set at. Amber pill so it reads as context for the
   score rather than as part of it. */
.lb-level {
  font-family: var(--display);
  font-size: 13px;
  letter-spacing: 1px;
  padding: 3px 9px;
  border-radius: 999px;
  color: var(--amber);
  background: rgba(255, 154, 60, 0.14);
  border: 1px solid rgba(255, 154, 60, 0.32);
}
.lb-date { font-size: 11px; color: #a89076; text-align: right; }
.lb-empty { padding: 22px; color: #c8b49b; }

.offline-note {
  font-size: 12.5px;
  color: #ffcf9a;
  background: rgba(255, 154, 60, 0.13);
  border: 1px solid rgba(255, 154, 60, 0.32);
  border-radius: 8px;
  padding: 8px 12px;
  margin: 0 0 10px;
}

.your-score { font-size: 14px; color: var(--amber); margin: 10px 0 0; font-weight: bold; }

/* --- misc ------------------------------------------------------------- */

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Hitting PIP flashes the whole frame pink -- unmissable even mid-wave. */
body.penalty-flash::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  background: rgba(240, 111, 168, 0.28);
  animation: penaltyFade 220ms ease-out forwards;
  z-index: 5;
}
@keyframes penaltyFade { from { opacity: 1; } to { opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  .screen { animation: none; }
  body.penalty-flash::after { animation: none; opacity: 0.28; }
  .btn { transition: none; }
}

/* Phones: the play field needs the room, so the chrome tightens up. */
@media (max-width: 420px) {
  .screen { width: 94vw; padding: 16px 14px; border-width: 2px; }
  .stats { grid-template-columns: repeat(2, 1fr); }
  /* Phone: the date is the first thing to go, but the level stays -- it is
     what makes two scores comparable. */
  .lb-row { grid-template-columns: 30px 1fr auto auto auto; font-size: 14px; }
  .lb-date { display: none; }
  .lb-level { font-size: 11px; padding: 2px 7px; }
}

/* Short landscape (a phone turned sideways) -- vertical space is the constraint. */
@media (max-height: 520px) {
  .rules { display: none; }
  .screen { padding: 12px 14px; }
}
