/* The .NET client's look (bakeoff/spec/visuals.md sections 6.5, 9, 10): flat rounded panels,
   one font (Nunito), big numbers, visible focus, text size / high contrast / reduced motion.
   The colours are tokens.css's (A · Console, #403): no colour is written here. */

@font-face {
  font-family: 'Nunito';
  font-style: normal;
  font-display: swap;
  font-weight: 200 1000;
  src: url('fonts/nunito-latin-wght-normal-ba344451.woff2') format('woff2-variations');
}

/* Arabic (#84, docs/plans/arabic-rtl.md 2.9): Baloo Bhaijaan 2, the rounded Baloo family's Arabic,
   closest to Nunito's round shapes (OFL; @fontsource-variable/baloo-bhaijaan-2's Arabic subset, 38 KB).
   Its unicode-range is the Arabic blocks only, so a browser fetches it only when it draws an Arabic
   letter: an English page never does. Not precached either (js/sw-build.mjs). */
@font-face {
  font-family: 'Baloo Bhaijaan 2';
  font-style: normal;
  font-display: swap;
  font-weight: 400 800;
  src: url('fonts/baloo-bhaijaan-2-arabic-wght-normal-643bd83b.woff2') format('woff2-variations');
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-08FF, U+FB50-FDFF, U+FE70-FEFC;
}

:root {
  --scale: 1;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: var(--bg);
  color: var(--ui-text);
  font-family: 'Nunito', 'Baloo Bhaijaan 2', system-ui, sans-serif;
  font-weight: 700;
  font-size: calc(var(--fs-base) * var(--scale));
  line-height: var(--line);
  -webkit-tap-highlight-color: transparent;
}

button,
input {
  font: inherit;
  color: inherit;
}

#stage {
  position: fixed;
  inset: 0;
}

.stage-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  touch-action: none;
}

#labels {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}

#app {
  position: fixed;
  inset: 0;
  overflow: auto;
}

/* Capture mode (#407, window.__gonfetti.capture; tools/game-media's hero pictures): the 3D world
   alone. No HUD, menu or in-world label (a name or a number would read backwards mirrored). */
[data-capture] body > :not(#stage),
[data-capture] body > :not(#stage) *,
[data-capture] #labels,
[data-capture] #labels * {
  visibility: hidden !important;
}

/* ------------------------------------------------------------ right to left (#84)
   Every rule is written with logical properties (margin-inline-start, inset-inline-end, text-align:
   start…), so a right-to-left page (<html dir="rtl">: Arabic, ?lang=qps-rtl) mirrors by itself and
   the text ratchet allows no left or right. What must not mirror sits in a dir="ltr" layer: the
   arena and its labels (#stage), the touch controls (#touch) and what is placed beside them, the
   player panels of the games whose seats start on their card's side (Game/HudLayout.cs
   PlayersBySide: Siegeometry, Polygone and the floor-ring games, Outlier, Perimeter; and the team
   games, whose scoreboards keep each side where its goal is too). Text a player reads in such a
   layer gets class t. An arrow that means "next" or "back" gets class flip; one that points at the
   arena (Dodecaball's goals), a key cap or a pad's d-pad does not. Nothing here applies left to right. */
:root[dir='rtl'] .t {
  direction: rtl;
}

:root[dir='rtl'] .flip {
  display: inline-block;
  transform: scaleX(-1);
}

/* Key caps, pad badges and the room code read left to right in every language. */
:root[dir='rtl'] :is(kbd, .pb, .code-input) {
  direction: ltr;
  unicode-bidi: isolate;
}

/* Panels that keep their sides are a dir="ltr" layer (Game/HudLayout.cs); their cards and the
   drawer's "Tap to close" read right to left. */
:root[dir='rtl'] .hud-players[dir='ltr'] .pg-card,
:root[dir='rtl'] .hud-players[dir='ltr']::after {
  direction: rtl;
}

/* ------------------------------------------------------------ loader */

#loader {
  position: fixed;
  inset: 0;
  display: grid;
  place-content: safe center;
  justify-items: center;
  gap: 1em;
  padding: 1em;
  overflow: auto;
  background: var(--bg);
  z-index: 50;
}

.loader-title {
  margin: 0;
  font-size: 2.6em;
  font-weight: 900;
}

.loader-about {
  max-width: 38em;
  margin: 0;
  text-align: center;
  font-weight: 600;
  color: var(--ui-dim);
}

.loader-games {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.3em 0.5em;
  max-width: 44em;
  margin: 0;
  padding: 0;
  list-style: none;
}

.loader-games a {
  display: inline-block;
  padding: 0.5em 0.7em;
  border-radius: 0.6em;
  background: var(--ui-key);
  color: inherit;
  text-decoration: none;
  font-size: max(var(--fs-small), 0.8em);
}

.loader-track {
  width: 16em;
  height: 0.5em;
  border-radius: 1em;
  background: var(--ui-key);
  overflow: hidden;
}

#loader-bar {
  width: 0;
  height: 100%;
  background: var(--ui-text);
  transition: width 0.15s;
}

#loader-text {
  color: var(--ui-dim);
}

/* A phone's first screen is on the page before the app is up (#823, index.html #first-screen): the
   loading cover is then only its bar, a thin line along the top, and the page under it is pressed
   through it. A press the app has not answered yet shows as taken. */
:root.first-screen #loader {
  inset: 0 0 auto;
  display: block;
  padding: 0;
  overflow: visible;
  background: none;
  pointer-events: none;
}

:root.first-screen #loader > :not(.loader-track) {
  display: none;
}

/* The developers' corner label is the app's to show (it hides it but for ?dev=1): not before it. */
:root.first-screen #corner {
  display: none;
}

/* Full screen needs the app (and a tap of its own, so it cannot be kept): its button keeps its
   place, so nothing moves, and shows when the app is up. */
:root.first-screen .fs-btn {
  visibility: hidden;
}

/* The app did not start (index.html #first-screen fail): the loading page again, with Reload. */
.loader-reload {
  margin-top: 1em;
}

:root.first-screen #loader .loader-track {
  width: 100%;
  height: 3px;
  border-radius: 0;
}

#app .first-pressed {
  animation: first-pressed 0.7s ease-in-out infinite alternate;
}

@keyframes first-pressed {
  to {
    opacity: 0.5;
  }
}

@media (prefers-reduced-motion: reduce) {
  #app .first-pressed {
    animation: none;
    opacity: 0.6;
  }
}

/* A room's invite (#654, index.html #loader-join): "Joining the room" and the code, big, in place
   of the start page's words; the games' links are for crawlers and visitors, not for a friend
   on their way into a room. */
.loader-join {
  display: grid;
  justify-items: center;
  gap: 0.2em;
  margin: 0;
  font-weight: 700;
  text-align: center;
}

.loader-code {
  font-size: 2.4em;
  font-weight: 900;
  letter-spacing: 0.12em;
  padding-inline-start: 0.12em;
}

#loader.joining .loader-about,
#loader.joining nav,
#loader.joining .loader-privacy {
  display: none;
}

/* Where Home will show a backdrop (#529, index.html #loader-pic): the chosen game's picture at
   once, where Home's is (home.css shares .loader-pic, .loader-art and .loader-shade with Home's
   picture layer), and the loader's words on the start side in the hero's column, so Home takes
   over with no jump. --hero-w as Home's (home.css .hero-home). */
#loader.with-pic {
  --hero-w: min(44vw, 30em);
  justify-content: start;
  justify-items: start;
  padding-inline: max(2em, var(--safe-start)) 1em;
}

#loader.with-pic > :not(.loader-bg) {
  max-width: var(--hero-w);
}

#loader.with-pic .loader-about {
  text-align: start;
}

#loader.with-pic .loader-games {
  justify-content: flex-start;
}

/* Behind the words, over the loader's own background (#loader is a stacking context). */
.loader-bg {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}

/* ------------------------------------------------------------ corner, stats */

.corner {
  position: fixed;
  inset-inline-start: 0.8em;
  bottom: 0.5em;
  font-size: max(var(--fs-small), 0.72em);
  color: var(--ui-dim);
  pointer-events: none;
  z-index: 20;
}

.stats-btn {
  position: fixed;
  inset-inline-start: 0.8em;
  top: 0.6em;
  z-index: 30;
  padding: 0.2em 0.6em;
  border-radius: 0.6em;
  border: 1px solid var(--ui-line);
  background: var(--ui);
  font-size: max(var(--fs-small), 0.72em);
  font-weight: 900;
  cursor: pointer;
}

.stats {
  position: fixed;
  inset-inline-start: 0.8em;
  top: 2.4em;
  z-index: 30;
  padding: 0.6em 0.8em;
  border-radius: 0.8em;
  background: var(--ui);
  border: 1px solid var(--ui-line);
  font-size: max(var(--fs-small), 0.72em);
  font-variant-numeric: tabular-nums;
  pointer-events: none;
  line-height: calc(1.35 * var(--line-k));
}

.stats table {
  border-collapse: collapse;
}

.stats td {
  padding: 0 0.4em;
}

.stats td:first-child {
  color: var(--ui-dim);
}

.stats td:last-child {
  text-align: end;
  font-weight: 900;
}

.hidden {
  display: none !important;
}

/* Read out by screen readers, never seen (#say in index.html). */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ------------------------------------------------------------ focus (always visible) */

/* White, never yellow (A · Console 3.1), off the box by a gap so it shows on the yellow button too. */
[data-nav]:focus,
:is(button, a, input, select, textarea, [tabindex]):focus-visible {
  outline: var(--ring);
  outline-offset: var(--ring-gap);
}

/* ------------------------------------------------------------ menus */

.menu {
  min-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: safe center;
  gap: 0.8em;
  padding: 1.2em 1em 2.2em;
}

.menu h1 {
  margin: 0;
  font-size: 3em;
  font-weight: 900;
}

.menu h2 {
  margin: 0;
  font-size: 1.7em;
  font-weight: 900;
}

.menu .lead {
  margin: -0.6em 0 0;
  color: var(--ui-dim);
}

.big {
  display: flex;
  align-items: center;
  gap: 0.7em;
  padding: 0.8em 1.1em;
  border-radius: 0.8em;
  border: 1px solid var(--ui-line);
  background: var(--ui);
  font-size: 1.15em;
  font-weight: 900;
  text-align: start;
  cursor: pointer;
}

.big small {
  display: block;
  font-size: max(var(--fs-small), 0.65em);
  font-weight: 700;
  color: var(--ui-dim);
}

.big:disabled {
  opacity: 0.5;
  cursor: default;
}

.big svg {
  flex: none;
}

.panel {
  width: min(44em, 94vw);
  padding: 0.6em 1.1em;
  border-radius: 0.8em;
  border: 1px solid var(--ui-line);
  background: var(--ui);
}

.panel h3 {
  margin: 0 0 0.3em;
  font-size: max(var(--fs-small), 0.85em);
  font-weight: 900;
  color: var(--ui-dim);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5em;
  margin: 0.25em 0;
}

.row > .label {
  min-width: 9em;
  color: var(--ui-dim);
}

/* A line under a row's chips saying why they are greyed (the seats in humans vs bots, #603). */
.row-note {
  flex: 1 1 100%;
  padding-inline-start: 9.5em;
  color: var(--ui-dim);
  font-size: max(var(--fs-small), 0.85em);
}

/* Siegeometry's chosen map under its chips (#162): a small picture and one line. */
.sg-map-about {
  display: flex;
  flex: 1 1 100%;
  align-items: center;
  gap: 0.75em;
  /* Under the chips, past the row's label (9em and the row's gap). */
  padding-inline-start: 9.5em;
  color: var(--ui-dim);
}

.sg-map-about p {
  margin: 0;
}

.sg-map-pic {
  flex: none;
  width: 5.5em;
  height: 5.5em;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding: 0.25em 0.75em;
  border-radius: var(--r-pill);
  border: 2px solid var(--ui-line);
  background: transparent;
  font-weight: 800;
  cursor: pointer;
}

.chip[aria-pressed='true'] {
  background: var(--ui-text);
  color: var(--ink);
  border-color: transparent;
}

/* A chip that is a tile (a preset with its line, a game with its picture): rounded, not a pill. */
.chip:is(.preset, .tgame) {
  border-radius: var(--r-l);
}

.chip:disabled {
  opacity: 0.45;
  cursor: default;
}

.chip .check {
  display: inline-block;
  width: 0.9em;
  height: 0.9em;
  border-radius: 0.25em;
  border: 0.14em solid currentColor;
}

.chip[aria-pressed='true'] .check {
  background: currentColor;
}

.count {
  min-width: 2em;
  text-align: center;
  font-size: 1.2em;
  font-weight: 900;
  font-variant-numeric: tabular-nums;
}

.note {
  color: var(--ui-dim);
  font-size: max(var(--fs-small), 0.85em);
}

.seats {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5em;
}

.seat {
  display: flex;
  flex-wrap: wrap;
  max-width: 100%;
  align-items: center;
  gap: 0.35em;
  padding: 0.25em 0.6em;
  border-radius: 0.6em;
  border-inline-start: 0.3em solid var(--c);
  background: var(--ui-raised);
  font-size: max(var(--fs-small), 0.85em);
}

.seat span {
  color: var(--ui-dim);
}

.actions {
  display: flex;
  gap: 0.7em;
  justify-content: center;
  flex-wrap: wrap;
}

/* A quiet button: a see-through white pill. The main one (.primary): the yellow pill, one per screen. */
.btn {
  padding: 0.6em 1.3em;
  border-radius: var(--r-pill);
  border: 2px solid transparent;
  background: var(--ui-quiet);
  font-weight: 900;
  cursor: pointer;
}

.btn.primary {
  background: var(--do);
  color: var(--on-do);
  border-color: transparent;
  box-shadow: var(--do-glow);
}

.high-contrast .btn:not(.primary) {
  border-color: var(--ui-text);
}

.btn:disabled {
  opacity: 0.45;
}

.where {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 12em), 1fr));
  gap: 0.7em;
  width: min(44em, 94vw);
}

.where .big {
  flex-direction: column;
  align-items: flex-start;
}

.where .big[aria-pressed='true'] {
  border: 2px solid var(--ui-text);
}

.code-input {
  width: 6em;
  padding: 0.4em 0.6em;
  border-radius: 0.6em;
  border: 2px solid var(--ui-line);
  background: var(--ui-raised);
  font-size: 1.6em;
  font-weight: 900;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  text-align: center;
}

kbd {
  display: inline-block;
  min-width: 1.4em;
  padding: 0.05em 0.4em;
  margin: 0 0.15em;
  border-radius: 0.35em;
  background: var(--ui-key);
  /* A light outline all round, the bottom thicker like a key's side (#509): the old near-black
     edge on a dark fill, inside a dark button, could hardly be seen. Same size as before: the
     bottom border keeps its 0.12em, the rest is an inset line. */
  border-bottom: 0.12em solid var(--ui-key-edge);
  box-shadow: inset 0 0 0 1px var(--ui-key-edge);
  font: inherit;
  font-size: max(var(--fs-small), 0.78em);
  font-weight: 800;
  text-align: center;
}

.pb {
  display: inline-grid;
  place-items: center;
  min-width: 1.5em;
  height: 1.5em;
  padding: 0 0.35em;
  margin: 0 0.15em;
  border-radius: 1em;
  background: var(--ui-key);
  font-style: normal;
  font-size: max(var(--fs-small), 0.75em);
  font-weight: 900;
  vertical-align: 0.1em;
}

.pb.a {
  background: var(--pad-a);
  color: var(--on-pad-a);
}

.pb.b {
  background: var(--pad-b);
  color: var(--on-pad-b);
}

.pb.x {
  background: var(--pad-x);
  color: var(--on-pad-x);
}

.pb.y {
  background: var(--pad-y);
  color: var(--on-pad-y);
}

/* On the yellow button a badge or key cap is dark with a yellow glyph (A · Console). */
:is(.btn.primary, .start, .gpick-play, .hero-play, .mini.primary) :is(.pb, kbd) {
  background: var(--on-do);
  color: var(--do);
}

/* The dark key cap on yellow needs no light outline: it stands out already. */
:is(.btn.primary, .start, .gpick-play, .mini.primary) kbd {
  border-bottom-color: var(--on-do);
  box-shadow: none;
}
