/* The page around the game: the playfield, and the few controls laid over it.
   Colours and faces are the game's own, set from its theme's `chrome` palette
   by web/host.js; the values here are only a fallback. */
:root {
  /* The page claims dark support, and its dark look is its light look (the
     block at the end). "only light" did not stop Samsung Internet darkening
     the controls on a real phone in the runner games; its dark mode is
     documented as standing down for pages that declare dark. The control discs
     are painted into a canvas anyway (web/host.js paintFaces), which no
     dark-mode algorithm repaints. Each game's head meta tag says the same for
     the first paint. */
  color-scheme: light dark;
  --page: #1b1633;
  --plate: #fff6e2; /* the controls' disc */
  --glyph: #1b1633; /* the controls' ink */
  --line: 2.9px;
  --edge: #1b1633; /* the controls' rim */
  --focus: #ffd166; /* keyboard focus over the playfield */
  --accent: #ffd166; /* the Resume button */
  --accentGlyph: #1b1633;
  --sheet: #fff6e2; /* the settings sheet */
  --sheetEdge: #1b1633;
  --ink: #1b1633;
  --dim: #8a7a6b;
  --on: #ff3d6e; /* a switch that is on */
  --sheetFocus: #ff3d6e;
  --scrim: rgba(27, 22, 51, 0.6);
  --ui: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --title: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --labelWeight: 700;
  --field-left: 0px;
  --field-right: 0px;
  --field-top: 0px;
}
* { box-sizing: border-box; }
[hidden] { display: none !important; }
html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: var(--page);
  color: var(--ink);
  font: 16px/1.3 var(--ui);
  overscroll-behavior: none;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}
body {
  /* Pinned to the viewport: no scrolling either way, no rubber-band bounce and
     no pull-to-refresh mid-run. touch-action: none also stops pinch and
     double-tap zoom everywhere, including on the controls. */
  position: fixed;
  inset: 0;
  touch-action: none;
}

.stage {
  position: absolute;
  inset: 0;
  display: flex;
  justify-content: center;
  overflow: hidden;
  background: var(--page);
  outline: none; /* focused only to hand Space back to the game; the canvas is the focus */
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  cursor: pointer;
  /* Stated here as well as on body. touch-action does not inherit; Chrome
     intersects it along the ancestor chain, but the element a touch actually
     lands on is the one a browser is most likely to honour, and Samsung
     Internet is the browser this catalogue has already been surprised by.
     Without it a tap can be held back for a double-tap-zoom gesture. */
  touch-action: none;
}
.stage::before {
  /* dims the page colour either side of the playfield on wide screens */
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.18);
  pointer-events: none;
}
canvas {
  position: relative;
  display: block;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25), 0 0 30px rgba(0, 0, 0, 0.25);
}

/* ---- icon controls -------------------------------------------------------
   A glyph on a filled disc in the game's own colours, opaque so it reads over
   any sky and any wall. The disc, rim and glyph are pixels in the button's own
   canvas (.face, drawn by web/host.js paintFaces from --plate, --edge, --glyph
   and --line), not CSS colours, so a browser's dark mode has nothing to
   rewrite. The button itself stays a real button for focus, keys and screen
   readers. */
.icon-btn {
  --rim: 2.5px;
  --mark: 28px; /* the glyph's box, read by paintFaces */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  /* Transparent, but it keeps the box and tells paintFaces the rim width as the
     browser snaps it (Chrome draws 2.5px as 2px). */
  border: var(--rim) solid transparent;
  border-radius: 50%;
  background: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  -webkit-user-select: none;
}
/* Over the whole button, border included; paintFaces sets its size and margin. */
.icon-btn .face { flex: none; display: block; box-shadow: none; }
.icon-btn:focus { outline: none; }
.icon-btn:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; }
/* TV only (web/host.js adds .tv, from the Android TV app's ?tv): focus is read
   from across the room, so the focused control grows and its ring is thicker,
   with a halo in the disc's own colour so it shows over any art. */
.tv .icon-btn:focus-visible {
  outline-width: 5px;
  outline-offset: 5px;
  box-shadow: 0 0 0 5px var(--plate);
  transform: scale(1.12);
}
.tv .row:focus-visible { outline-width: 5px; }
/* Resume and Home are sized to the card they sit on, with words just above:
   they keep their size, and a closer ring. */
.tv .on-card:focus-visible { transform: none; box-shadow: none; outline-offset: 3px; }
.icon-btn:active { transform: scale(0.92); }

/* Limbs are strokes, heads are filled. Units are the 24-unit box. */
.glyph { overflow: visible; }
.glyph path,
.glyph circle { stroke: currentColor; stroke-width: var(--line, 2.9px); stroke-linecap: round; stroke-linejoin: round; }
.glyph path { fill: none; }
/* A gear: flat-ended teeth, and a head without the stroke so it stays clear of the ring. */
.glyph .teeth { stroke-linecap: butt; stroke-width: calc(var(--line, 2.9px) * 1.12); }
.glyph .teeth ~ circle { stroke: none; }
.glyph circle { fill: currentColor; }

/* The controls sit in the TOP-RIGHT corner of the playfield, where the
   artboards put them and where a thumb batting a balloon never goes. Settings
   is always there; Pause joins it while a run is live. The gaps between them,
   and every other pixel of the screen, are play surface. */
.controls {
  position: fixed;
  top: max(calc(var(--field-top) + 14px), calc(env(safe-area-inset-top) + 14px));
  right: max(calc(var(--field-right) + 14px), calc(env(safe-area-inset-right) + 14px));
  display: flex;
  gap: 10px;
  pointer-events: none;
}
.controls > * { pointer-events: auto; }

/* Resume, on the theme's pause card; Home, on the game-over card beside PLAY
   AGAIN. web/host.js sets left and top for both from the card's own units. */
.on-card {
  position: fixed;
  width: 72px;
  height: 72px;
  margin: -36px 0 0 -36px;
}
.resume { --rim: 3px; --mark: 44px; }
.home { --rim: 2.5px; --mark: 26px; width: 54px; height: 54px; margin: -27px 0 0 -27px; }
.on-card:active { transform: scale(0.92); }

/* On the settings sheet, a lighter line. */
.row-icon { --line: 2.4px; }

/* ---- the settings sheet ------------------------------------------------ */
.scrim {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px max(16px, env(safe-area-inset-right)) 24px max(16px, env(safe-area-inset-left));
  background: var(--scrim);
}
.sheet {
  width: 100%;
  max-width: 420px;
  padding: 16px 20px 20px;
  border: 3px solid var(--sheetEdge, var(--edge));
  border-radius: 20px;
  background: var(--sheet);
  color: var(--ink);
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.35);
}
.sheet-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 8px;
}
.sheet h2 {
  margin: 0;
  font: var(--labelWeight, 700) 26px/1.1 var(--title);
}
.sheet .icon-btn:focus-visible { outline-color: var(--sheetFocus); }
.row {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  min-height: 68px;
  margin: 0;
  padding: 10px 6px;
  border: 0;
  border-top: 2px solid color-mix(in srgb, var(--ink) 16%, transparent);
  border-radius: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  text-decoration: none; /* the Privacy row is a link */
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.row:focus { outline: none; }
.row:focus-visible { outline: 3px solid var(--sheetFocus); outline-offset: -3px; border-radius: 10px; }
.row-icon svg { display: block; width: 28px; height: 28px; }
.row-end { flex: 0 0 auto; color: var(--dim); }
.row-text { flex: 1 1 auto; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.row-label { font-size: 19px; font-weight: var(--labelWeight, 700); }
.row-hint { font-size: 14.5px; color: var(--dim); }
.nowrap { white-space: nowrap; } /* TV: the privacy address breaks only after a '/' */
/* On and off read from the thumb's side as well as its colour. */
.switch {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  width: 56px;
  height: 32px;
  padding: 0 4px;
  border: 2.5px solid var(--dim);
  border-radius: 16px;
}
.thumb { width: 20px; height: 20px; border-radius: 50%; background: var(--dim); }
.row[aria-checked='true'] .switch { justify-content: flex-end; background: var(--on); border-color: var(--on); }
.row[aria-checked='true'] .thumb { background: var(--sheet); }

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.noscript {
  position: absolute;
  inset: 0;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  text-align: center;
  background: var(--page);
  color: var(--plate);
  font-size: 16px;
}

/* ---- dark mode ---------------------------------------------------------
   These games are printed artwork with no dark palette: in a dark-mode browser
   they look exactly as they do in light. The page declares color-scheme:
   light dark (above, and in each game's meta tag) and restates its own colours
   here, so a browser that looks for a page's dark styles finds them and leaves
   the page alone. No second palette: every value is still the theme's chrome
   token. */
@media (prefers-color-scheme: dark) {
  html, body, .stage { background: var(--page); color: var(--ink); }
  .noscript { background: var(--page); color: var(--plate); }
  .sheet { background: var(--sheet); color: var(--ink); }
}
