/* 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. The shape is the
   other one-tap games', so the catalogue's controls are one family. */
: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. The game's head meta tag says the same for
     the first paint. There is ONE look and no dark palette: see the end. */
  color-scheme: light dark;
  --page: #1a1240;
  --plate: #1a1240; /* the controls' disc */
  --glyph: #ffffff; /* the controls' ink */
  --line: 2.9px;
  --edge: #ffffff; /* the controls' rim */
  --focus: #ffffff; /* keyboard focus over the playfield */
  --accent: #b4f03a; /* the Resume button */
  --accentGlyph: #1a1240;
  --sheet: #ffffff; /* the settings sheet */
  --sheetEdge: #1a1240;
  --ink: #1a1240;
  --dim: #5f5690;
  --on: #ff2baa; /* a switch that is on */
  --sheetFocus: #7c4dff;
  --scrim: rgba(26, 18, 64, 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 canopy. 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; }
.icon-btn:active { transform: scale(0.92); }
/* On a TV (web/host.js adds .tv) focus is read from across the room and is the
   only way to know what OK will press: the focused control grows, and its ring
   is thicker, with a halo in the disc's own colour between ring and disc so it
   shows over any sky or canopy. */
.tv .icon-btn:focus-visible {
  outline-width: 5px;
  outline-offset: 5px;
  box-shadow: 0 0 0 5px var(--plate);
  transform: scale(1.15);
}
.tv .row:focus-visible { outline-width: 5px; }
/* On a TV the words and cards in the play column are drawn larger, so the
   corner controls move out of it, to the screen's own top-right corner:
   inside what a TV may crop (overscan: 27 dp top and bottom, 48 dp either
   side in Android TV's layout guidance), with room for a focused, ringed
   control, which reaches 13 px past its disc. */
.tv .controls { top: 30px; right: 48px; }
/* Resume and Home sit on their cards with words close by: they keep their
   size, and a closer ring. */
.tv .on-card:focus-visible { transform: none; outline-offset: 3px; }

/* 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
   artboard puts Pause, beside the score and clear of the road. 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; } /* the TV's 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 ---------------------------------------------------------
   This game is one look - a spring morning - with no dark palette: in a
   dark-mode browser it looks exactly as it does in light. The page declares
   color-scheme: light dark (above, and in the 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); }
}
