/*
 * style.css — Geometry Pong's cards and corner, cut from the board itself.
 *
 * The board is neon line on black, so the cards are smoked glass over it:
 * the bots' rally keeps moving behind the start screen, and the panels take
 * their light from the eight player colours rather than a palette of their
 * own. The wordmark spells PONG in the first four of them. The corner plates
 * are hexagons, because everything here is a polygon.
 *
 * No web fonts (hub §1): the system's rounded face where there is one,
 * falling back to the system sans.
 *
 * Layout: each card is one grid, centred with top/left 50% and translate
 * (hub §2, the iPad lesson — never inset:0 + margin:auto). On a sideways
 * phone each card becomes two columns laid over the same markup by grid
 * area, maxgear's shape, so no menu scrolls there.
 */

:root {
  --void: #06070c;
  --glass: rgba(9, 11, 20, 0.82);
  --edge: rgba(120, 140, 210, 0.22);
  --ink: #e9edf7;
  --dim: #8f98b3;
  --cyan: #3be8ff;
  --pink: #ff4fd8;
  --yellow: #ffd23f;
  --green: #7dff6a;
  --font: ui-rounded, "SF Pro Rounded", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --tap: 48px;
  --corner-gap: 8px;
  --corner-room: calc(3 * var(--tap) + 2 * var(--corner-gap) + 24px);
  color-scheme: dark;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: var(--void);
  color: var(--ink);
  font-family: var(--font);
  font-size: 15px;
  -webkit-text-size-adjust: 100%;
}

[hidden] {
  display: none !important;
}

/* A game, not a document (hub §2): js/touch-guard.js is the other half. */
html,
body {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
input,
textarea,
[contenteditable="true"] {
  -webkit-user-select: text;
  user-select: text;
  -webkit-touch-callout: default;
}

/* The board. Every finger on it is a paddle, so nothing may scroll or zoom. */
#view {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  touch-action: none;
}

#ui {
  position: fixed;
  inset: 0;
  pointer-events: none;
}

/* ---- the corner ---- */

#corner {
  position: absolute;
  z-index: 2;
  top: calc(env(safe-area-inset-top, 0px) + 10px);
  right: calc(env(safe-area-inset-right, 0px) + 12px);
  display: flex;
  gap: var(--corner-gap);
  pointer-events: auto;
}

.icon-button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--tap);
  height: var(--tap);
  flex: none;
  padding: 0;
  border: 0;
  color: var(--cyan);
  background: rgba(59, 232, 255, 0.28);
  clip-path: polygon(25% 4%, 75% 4%, 100% 50%, 75% 96%, 25% 96%, 0 50%);
  cursor: pointer;
  position: relative;
}
/* The hexagon's face, inset one pixel so the lighter plate behind reads as
   its edge (a border would be clipped away at the corners). */
.icon-button::before {
  content: "";
  position: absolute;
  inset: 1.5px;
  background: rgba(8, 10, 18, 0.9);
  clip-path: inherit;
}
.icon-button svg {
  position: relative;
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* [hidden] loses to display:flex without this (hub §2, hit three times). */
.icon-button[hidden] {
  display: none;
}
#sound-btn[aria-pressed="true"] .icon-waves,
#sound-btn:not([aria-pressed="true"]) .icon-slash,
#screen-toggle[aria-pressed="true"] .icon-expand,
#screen-toggle:not([aria-pressed="true"]) .icon-contract {
  display: none;
}
/* clip-path eats an outline, so focus lights the whole plate instead. */
.icon-button:focus-visible {
  outline: none;
  background: var(--ink);
}
.icon-button:focus-visible svg {
  color: var(--ink);
}

/* ---- cards ---- */

.card {
  position: absolute;
  top: 50%;
  left: 50%;
  translate: -50% -50%;
  width: min(440px, calc(100% - 32px));
  max-height: calc(100% - 2 * (var(--tap) + 24px) - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px));
  overflow: auto; /* a safety net on very short screens, not the plan */
  padding: 22px 22px 18px;
  display: grid;
  gap: 16px;
  align-content: start;
  background: var(--glass);
  border: 1px solid var(--edge);
  border-radius: 6px;
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.4), 0 20px 60px rgba(0, 0, 0, 0.55);
  pointer-events: auto;
}

h1,
h2 {
  margin: 0;
  text-wrap: balance;
}
h2 {
  font-size: 1.5rem;
  letter-spacing: 0.02em;
}

.wordmark {
  display: grid;
  line-height: 1;
  font-weight: 800;
}
.wordmark {
  font-size: 0.95rem;
  letter-spacing: 0.5em;
  text-transform: uppercase;
  color: var(--dim);
}
.wordmark span {
  /* Shrink to the letters, or the four colour stops spread over the card. */
  justify-self: start;
  margin-top: 6px;
  font-size: 3.6rem;
  letter-spacing: 0.06em;
  /* PONG in the first four player colours. */
  background: linear-gradient(90deg, var(--cyan) 0 25%, var(--pink) 25% 50%, var(--yellow) 50% 75%, var(--green) 75%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 0 14px rgba(59, 232, 255, 0.35));
}

.tag {
  margin: 0;
  color: var(--dim);
  line-height: 1.45;
}
.title-block {
  display: grid;
  gap: 10px;
}

.setup {
  display: grid;
  gap: 10px;
}
.row {
  display: grid;
  grid-template-columns: 84px 1fr;
  align-items: center;
  gap: 10px;
}
.lang-row {
  display: grid;
  grid-template-columns: 84px 1fr;
  align-items: center;
  gap: 10px;
}
.cap {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim);
}
/* The Kaos slider shares the setup rows' caption gutter; its words
   ("Maks", "A bit") get a column of their own on the right. */
.slider-row {
  grid-template-columns: 84px 1fr 5ch;
}
.slider-row output {
  text-align: right;
  font-weight: 700;
  color: var(--cyan);
}
.how {
  margin: 4px 0 0;
  font-size: 0.85rem;
  line-height: 1.45;
  color: var(--dim);
}

/* Segmented rows: alternatives, so one size each (flex: 1 1 0). */
.seg {
  display: flex;
  gap: 6px;
}
.seg-btn {
  flex: 1 1 0;
  min-width: 0;
  height: 42px;
  padding: 0 6px;
  border-radius: 4px;
  border: 1px solid var(--edge);
  background: transparent;
  color: var(--ink);
  font: 700 0.95rem var(--font);
  font-variant-numeric: tabular-nums;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  cursor: pointer;
}
.seg-btn[aria-pressed="true"] {
  border-color: var(--cyan);
  color: var(--cyan);
  background: rgba(59, 232, 255, 0.08);
  box-shadow: inset 0 0 0 1px var(--cyan), 0 0 14px rgba(59, 232, 255, 0.25);
}
.flag {
  width: 22px;
  height: 16px;
  flex: none;
  border-radius: 2px;
}

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

.doors,
.actions {
  display: grid;
  gap: 10px;
  justify-items: stretch;
}
.go {
  min-height: var(--tap);
  padding: 0 16px;
  border-radius: 4px;
  border: 1px solid transparent;
  font: 700 1.05rem var(--font);
  letter-spacing: 0.02em;
  cursor: pointer;
  background: var(--cyan);
  color: #021216;
  box-shadow: 0 0 22px rgba(59, 232, 255, 0.35);
}
.go.alt {
  background: transparent;
  color: var(--ink);
  border-color: var(--edge);
  box-shadow: none;
}
/* The way back to the arcade: secondary, last, a little apart. */
.go.exit {
  margin-top: 8px;
  background: transparent;
  color: var(--dim);
  border-color: var(--edge);
  box-shadow: none;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
}
.go.exit svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.go:disabled {
  opacity: 0.5;
  cursor: default;
}
button:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

#update {
  display: grid;
  gap: 2px;
  padding: 8px 16px;
  border-color: var(--yellow);
  color: var(--yellow);
}
#update .update-sub {
  font-size: 0.8rem;
  font-weight: 600;
  opacity: 0.8;
}
#update[hidden] {
  display: none;
}
#build {
  margin: 0;
  text-align: center;
  font-size: 0.75rem;
  color: var(--dim);
  font-variant-numeric: tabular-nums;
}

/* ---- the menu panel ---- */

.menu {
  grid-template-areas: "head" "actions" "settings" "exit";
}
.menu-head {
  grid-area: head;
  display: grid;
  gap: 6px;
}
.menu-actions {
  grid-area: actions;
}
.menu-settings {
  grid-area: settings;
  display: grid;
  gap: 10px;
}
#menu-exit {
  grid-area: exit;
}
.vol-row {
  display: grid;
  grid-template-columns: 84px 1fr 3ch;
  align-items: center;
  gap: 10px;
}
.vol-row label {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim);
}
.vol-row output {
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.vol-hint {
  margin: 0;
  font-size: 0.8rem;
  color: var(--dim);
  line-height: 1.4;
}

/* A styled range: a bare OS slider belongs to no game. */
input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 32px;
  background: transparent;
  cursor: pointer;
}
input[type="range"]::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--cyan), var(--pink));
}
input[type="range"]::-moz-range-track {
  height: 4px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--cyan), var(--pink));
}
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 22px;
  height: 22px;
  margin-top: -9px;
  border-radius: 50%;
  background: var(--void);
  border: 2px solid var(--ink);
  box-shadow: 0 0 10px rgba(59, 232, 255, 0.5);
}
input[type="range"]::-moz-range-thumb {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--void);
  border: 2px solid var(--ink);
}
input[type="range"]:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

/* ---- match over ---- */

.over {
  --c: var(--cyan);
  justify-items: center;
  text-align: center;
}
.winner-mark {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 4px solid var(--c);
  box-shadow: 0 0 24px var(--c);
}
#over-title {
  color: var(--c);
}
.actions.pair {
  grid-template-columns: 1fr 1fr;
  width: 100%;
}

/* ---- online: the lobby card ---- */

/* The same smoked glass and the same buttons as every other card; the three
   things it has that no other card does — a code field, a big code and a row
   of seats — take their light from the board: the code glows cyan like a
   paddle, and each seat is its player's colour and polygon. */
.online-head {
  display: grid;
  gap: 6px;
}
.online-step {
  display: grid;
  gap: 12px;
  margin: 0;
}
.rules {
  margin: 0;
  color: var(--ink);
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
}
.status {
  margin: 0;
  min-height: 1.4em;
  font-size: 0.85rem;
  line-height: 1.4;
  color: var(--dim);
}
.status.warn {
  color: var(--yellow);
}
/* The picture code (hub §8): three slots that fill as the keypad is
   tapped, and the same three, big, in the room — what a host reads out and
   a guest checks they got right. Emoji from the system font: no download. */
.code-row {
  display: flex;
  gap: 10px;
  justify-content: center;
}
.code-slot {
  width: 56px;
  height: 56px;
  display: grid;
  place-items: center;
  font-size: 30px;
  line-height: 1;
  border-radius: 6px;
  border: 1px solid var(--edge);
  background: rgba(59, 232, 255, 0.07);
}
.code-slot.empty {
  color: var(--dim);
  font-size: 20px;
  font-weight: 700;
}
.code-row.hero {
  gap: 12px;
}
.code-row.hero .code-slot {
  width: 84px;
  height: 84px;
  font-size: 46px;
  border-color: rgba(59, 232, 255, 0.45);
  background: rgba(59, 232, 255, 0.1);
  box-shadow: 0 0 26px rgba(59, 232, 255, 0.18);
}
.code-words {
  margin: 0;
  min-height: 1.3em;
  text-align: center;
  font-size: 0.9rem;
  color: var(--dim);
}
/* Twelve keys, six by two: alternatives, so one size each (hub §2). */
.pad {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 6px;
}
.pad-key {
  min-height: var(--tap);
  font-size: 26px;
  line-height: 1;
  border-radius: 6px;
  border: 1px solid var(--edge);
  background: rgba(130, 170, 255, 0.08);
  cursor: pointer;
}
.pad-key:active {
  background: rgba(59, 232, 255, 0.2);
}
.room-code-block {
  display: grid;
  gap: 4px;
  justify-items: center;
  text-align: center;
}
/* The seats: one group, so one grid with a shared swatch gutter (hub §2). */
.seats {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 6px;
}
.seat {
  --c: var(--cyan);
  display: grid;
  grid-template-columns: 16px 1fr;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  border-radius: 4px;
  border: 1px solid var(--edge);
  font-size: 0.85rem;
}
.seat::before {
  content: "";
  width: 14px;
  height: 14px;
  background: var(--c);
  clip-path: polygon(25% 4%, 75% 4%, 100% 50%, 75% 96%, 25% 96%, 0 50%);
}
.seat.bot {
  color: var(--dim);
}
.seat.bot::before {
  opacity: 0.45;
}
.seat.me {
  border-color: var(--c);
  box-shadow: inset 0 0 0 1px var(--c);
}
#online-back {
  margin-top: 4px;
}

/* ---- a sideways phone: two columns, nothing scrolls ---- */

@media (orientation: landscape) and (max-height: 500px) {
  /* The corner takes the top right only, so the card keeps clear of it on
     that side alone and centres in what is left. Keeping clear on both
     sides, as this once did, left a 740px phone a 370px card and cut the
     setup column off. */
  .card {
    left: calc(env(safe-area-inset-left, 0px) + 16px);
    right: calc(env(safe-area-inset-right, 0px) + var(--corner-room));
    margin-inline: auto;
    translate: 0 -50%;
    width: min(760px, calc(100% - var(--corner-room) - 16px - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px)));
    max-height: calc(100% - 24px);
    padding: 14px 18px;
    gap: 10px 22px;
  }
  .start {
    grid-template-columns: 1fr 1fr;
    grid-template-areas: "title setup" "doors setup";
  }
  .title-block {
    grid-area: title;
  }
  .setup {
    grid-area: setup;
    align-content: center;
  }
  .doors {
    grid-area: doors;
    align-content: end;
  }
  .wordmark span {
    font-size: 2.6rem;
  }
  .menu {
    grid-template-columns: 1fr 1fr;
    grid-template-areas: "head settings" "actions settings" "exit settings";
  }
  .menu-settings {
    align-content: center;
  }
  /* The lobby: the heading, the status and Back down the left, whichever
     step is showing down the right — the code and the seats side by side
     when the room is open, since that is the tallest step. */
  .online {
    grid-template-columns: 1fr 1fr;
    grid-template-areas: "head step" "status step" "back step";
    align-items: center;
  }
  .online-head {
    grid-area: head;
  }
  .online-step {
    grid-area: step;
  }
  #online-status {
    grid-area: status;
  }
  #online-back {
    grid-area: back;
  }
  .code-row.hero .code-slot {
    width: 62px;
    height: 62px;
    font-size: 34px;
  }
  .code-slot {
    width: 44px;
    height: 44px;
    font-size: 24px;
  }
  .pad-key {
    min-height: 40px;
    font-size: 22px;
  }
  .seats {
    grid-template-columns: 1fr 1fr;
  }
  .seat {
    padding: 4px 8px;
  }
  .go,
  .seg-btn {
    min-height: 40px;
    height: auto;
  }
  .seg-btn {
    height: 38px;
  }
}

/* ---- the opening sting ---- */

/*
 * js/intro.js, a canvas the script creates and removes. Over everything in
 * the game, the corner plates and the cards included, because it is a
 * curtain: for its three seconds nothing under it is meant to be reachable,
 * and a tap anywhere on it is the skip. The crash bar is raised above it, so
 * a boot failure is still read rather than hidden behind the void.
 */
#intro {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 20;
  touch-action: none;
  cursor: pointer;
}

/* ---- failure ---- */

#crash {
  position: fixed;
  left: 12px;
  right: 12px;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 12px);
  /* Above the opening sting (20), so a failure is read even mid-sting. */
  z-index: 30;
  padding: 10px 14px;
  border-radius: 4px;
  background: #3a0d16;
  border: 1px solid #ff5266;
  color: #ffd9de;
  font-size: 0.85rem;
  pointer-events: auto;
}
.noscript {
  position: fixed;
  top: 50%;
  left: 50%;
  translate: -50% -50%;
  margin: 0;
  color: var(--ink);
}

@media (prefers-reduced-motion: reduce) {
  .wordmark span {
    filter: none;
  }
}
