:root{
  --deep:#03080f; --cy:#1fd6ff; --tl:#38f0d8; --mg:#ff2a6d; --ink:#7f97ad;
}
*{box-sizing:border-box}
html,body{margin:0;padding:0;height:100%;background:var(--deep);overflow:hidden;
  font-family:"SF Mono",ui-monospace,Menlo,Consolas,monospace;color:#cfe6f5;
  -webkit-font-smoothing:antialiased}
/* iOS Safari collapses its address bar mid-session and `100%`/`100vh` keep reporting the tall
   viewport. `dvh` tracks the bar. On desktop dvh === vh === 100%, so this is a no-op there.
   The CANVAS box is not sized here: index.html sets it in px from the live viewport, which is
   the only way to guarantee it matches the drawing buffer main.js allocates. */
html,body{height:100dvh}
#gl{position:fixed;inset:0;width:100%;height:100%;display:block}

/* ── the boot curtain ─────────────────────────────────────────────────────────────────
   IT IS NOT A CURTAIN THAT RISES ONCE ANY MORE, AND THE TWO DIRECTIONS ARE NOT THE SAME EVENT.
   `main.js` now builds the world when START is pressed rather than before the menu, so it takes
   `.done` OFF again and the overlay comes BACK, once, with the progress bar and the name of what
   is being built. A single symmetric `transition:opacity .7s` served the first direction and was
   wrong for the second: the menu hides inside the click, so for seven tenths of a second the
   player who pressed START looked at a black canvas with a curtain fading up over it, before a
   ten-second build. Splitting the two lets the reveal keep its slow fade — that one is the game
   arriving and should feel like it — while the cover is effectively immediate, which is what an
   acknowledgement of a button press has to be.
   Written as "the transition lives on .done" so that adding the class is a slow fade OUT and
   removing it is a fast fade IN, with no second class for anyone to remember to set. */
#boot{position:fixed;inset:0;z-index:100;display:grid;place-items:center;
  background:radial-gradient(122% 94% at 52% 46%,#0a1e2e 0%,#04121e 44%,#01060c 100%);
  transition:opacity .16s ease,visibility .16s}
#boot.done{opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .7s ease,visibility .7s}
#boot-inner{width:min(560px,74vw);text-align:center;position:relative;z-index:2}
#boot-mark{font-size:clamp(26px,4.6vw,52px);letter-spacing:.30em;font-weight:600;
  text-indent:.30em;line-height:1}
.bm-a{color:#eaf7ff;text-shadow:0 0 26px rgba(31,214,255,.55)}
.bm-b{color:var(--cy);text-shadow:0 0 34px rgba(31,214,255,.8)}
.bm-sep{color:var(--mg);margin:0 .16em;text-shadow:0 0 22px rgba(255,42,109,.9)}
#boot-sub{margin-top:14px;font-size:11px;letter-spacing:.44em;color:#4d7a95}
#boot-track{margin:34px auto 0;height:2px;width:100%;background:rgba(126,182,214,.13);
  position:relative;overflow:hidden}
#boot-bar{position:absolute;inset:0 auto 0 0;width:0%;
  background:linear-gradient(90deg,var(--mg),var(--cy));
  box-shadow:0 0 18px rgba(31,214,255,.75);transition:width .35s cubic-bezier(.2,.8,.2,1)}
#boot-label{margin-top:14px;font-size:10px;letter-spacing:.36em;color:#3f657d;text-transform:uppercase}
#boot-scan{position:absolute;inset:0;z-index:1;pointer-events:none;opacity:.35;
  background:repeating-linear-gradient(0deg,rgba(255,255,255,.028) 0 1px,transparent 1px 3px)}

/* ══════════════════════════════════════════════════════════════════════════════════════
   TOUCH CONTROLS — phone, held in landscape. Owner: agent TOUCH (with src/ui/touch.js).

   Everything below is scoped to `#touch`, `#rotate` or `body[data-touch="on"]`. None of
   those exist unless `ui/touch.js` has decided the device is a phone, so the desktop path
   and every capture parse these rules and match nothing.

   Palette is bible §3.1 and nothing else: deep for the fill, cyan/teal for the cold tier
   (steering, throttle), magenta for the hot tier (brake). Three hue families, no fourth.
   Deliberately NO outer glows: the controls sit on top of a graded, bloomed frame and a soft
   halo on a UI element reads as a bloom artefact. The active state is carried by border
   brightness, an inset wash and a 1 px size change instead.
   ══════════════════════════════════════════════════════════════════════════════════════ */

/* Gesture suppression, gated on the attribute so nothing here can reach a desktop browser.
   Each of these is a specific way iOS Safari breaks a game that is otherwise finished:
   scroll and rubber-band under a steering thumb, double-tap zoom on a pedal, the magnifier
   and the copy/paste callout on a long press, and text selection dragging across the HUD. */
body[data-touch="on"],html:has(body[data-touch="on"]){overscroll-behavior:none}
body[data-touch="on"]{touch-action:none;-webkit-user-select:none;user-select:none;
  -webkit-touch-callout:none;-webkit-tap-highlight-color:transparent}

#touch{position:fixed;left:0;top:0;width:100%;height:100dvh;z-index:30;overflow:hidden;
  touch-action:none;pointer-events:auto;
  -webkit-user-select:none;user-select:none;-webkit-touch-callout:none;
  -webkit-tap-highlight-color:transparent;
  font-family:"SF Mono",ui-monospace,Menlo,Consolas,monospace;text-transform:uppercase;
  transition:opacity .22s ease}
/* Menu, pause and results: the controls go away entirely rather than sitting under a dialog. */
#touch.off{opacity:0;pointer-events:none}
body[data-orient="portrait"] #touch{display:none}

/* The safe-area probe. `env()` is only readable through a computed style, and in landscape
   the Dynamic Island is on the left or the right depending on which way the phone is held —
   so both sides are read on every viewport change rather than assumed. */
#touch .tc-safe{position:absolute;left:0;top:0;width:0;height:0;visibility:hidden;
  padding-left:env(safe-area-inset-left);padding-right:env(safe-area-inset-right);
  padding-top:env(safe-area-inset-top);padding-bottom:env(safe-area-inset-bottom)}

/* ── steering ring ────────────────────────────────────────────────────────────────────
   Drawn where the thumb landed. At rest it is a ghost at the home position — present enough
   to say "put your thumb here", quiet enough not to be furniture. */
/* "Low alpha at rest" has a floor: at opacity .40 over a 1 px border at .20 the ghost was
   INVISIBLE at 1x on mid-grey asphalt (measured — the first state-rest.png showed nothing at
   all in the left corner), and a steering control the player cannot find is not quiet, it is
   missing. This is the quietest it can be and still be locatable at a glance. */
#touch .tc-ring{position:absolute;border-radius:50%;
  border:1.25px solid rgba(31,214,255,.34);
  background:radial-gradient(circle,rgba(2,10,18,.30) 0%,rgba(2,10,18,.20) 66%,rgba(2,10,18,0) 100%);
  opacity:.62;transition:opacity .16s ease,border-color .16s ease}
/* Active: the ring itself stays QUIET and the knob carries the state. The minimap lives in
   this corner and is drawn in the same cyan, so a bright 1.5 px circle over it produced two
   tangled cyan circles (measured — shots/TOUCH/zoom-left.png). The inner scrim is what
   separates them: it dims whatever the ring encloses so the control reads as one object. */
#touch .tc-ring.on{opacity:1;border-color:rgba(31,214,255,.46);
  background:radial-gradient(circle,rgba(2,10,18,.50) 0%,rgba(2,10,18,.40) 66%,rgba(2,10,18,.06) 100%)}
/* A single tick at top dead centre: the only cue that says which way is straight ahead. */
#touch .tc-ring::before{content:'';position:absolute;left:50%;top:-1px;width:1.5px;height:9px;
  margin-left:-.75px;background:rgba(56,240,216,.55)}
#touch .tc-knob{position:absolute;left:50%;top:50%;width:38px;height:38px;
  margin:-19px 0 0 -19px;border-radius:50%;
  border:1.5px solid rgba(31,214,255,.48);background:rgba(31,214,255,.14)}
#touch .tc-ring.on .tc-knob{border-color:var(--cy);background:rgba(31,214,255,.30);
  box-shadow:inset 0 0 14px rgba(31,214,255,.28)}

/* ── A / B pedals ─────────────────────────────────────────────────────────────────────
   Circles, because the thing next to them is a circle. A is cold (go), B is hot (stop) —
   the HUD already reserves magenta for the one thing it is allowed to shout about. */
#touch .tc-pad{position:absolute;border-radius:50%;display:grid;place-content:center;
  border:1.5px solid rgba(31,214,255,.24);background:rgba(4,18,30,.20);
  transition:background-color .08s ease,border-color .08s ease,box-shadow .08s ease}
#touch .tc-gl{font-size:23px;font-weight:600;letter-spacing:.10em;text-indent:.10em;
  line-height:1;color:rgba(207,230,245,.62);text-align:center}
#touch .tc-sub{margin-top:5px;font-size:7.5px;letter-spacing:.30em;text-indent:.30em;
  color:rgba(127,151,173,.62);text-align:center}
#touch .tc-a{border-color:rgba(56,240,216,.30)}
#touch .tc-a.on{border-color:var(--tl);background:rgba(56,240,216,.16);
  box-shadow:inset 0 0 22px rgba(56,240,216,.20)}
#touch .tc-a.on .tc-gl{color:#eafffb;text-shadow:0 0 12px rgba(56,240,216,.55)}
#touch .tc-a.on .tc-sub{color:rgba(150,232,220,.85)}
#touch .tc-b{border-color:rgba(255,42,109,.30)}
#touch .tc-b.on{border-color:var(--mg);background:rgba(255,42,109,.16);
  box-shadow:inset 0 0 22px rgba(255,42,109,.20)}
#touch .tc-b.on .tc-gl{color:#fff0f5;text-shadow:0 0 12px rgba(255,42,109,.55)}
#touch .tc-b.on .tc-sub{color:rgba(255,150,180,.85)}

/* ── handbrake / reset ────────────────────────────────────────────────────────────────
   Minimal and out of the way, as asked. HAND sits up and inboard of the pedals — a thumb
   stretch, not a resting position. RESET is at the bottom centre, the one place on a
   landscape phone neither thumb reaches without meaning it. Chamfered corners are the
   menu's own shape language, so they read as part of the same interface. */
#touch .tc-key{position:absolute;display:grid;place-content:center;
  font-size:8.5px;letter-spacing:.30em;text-indent:.30em;color:rgba(150,178,198,.78);
  border:1px solid rgba(31,214,255,.26);background:rgba(2,10,18,.42);
  clip-path:polygon(7px 0,100% 0,100% calc(100% - 7px),calc(100% - 7px) 100%,0 100%,0 7px);
  transition:background-color .08s ease,border-color .08s ease,color .08s ease}
#touch .tc-key.on{border-color:rgba(31,214,255,.70);background:rgba(31,214,255,.14);
  color:#dff4ff;box-shadow:inset 0 0 18px rgba(31,214,255,.16)}
/* RESET rides the top strip over whatever the city is doing behind it, so unlike HAND it
   needs its own backing to stay readable — at rest it was invisible against the car's tail
   lights when it lived at the bottom centre. Quiet, but never guessing. */
#touch .tc-r{opacity:.72;background:rgba(2,10,18,.52);border-color:rgba(31,214,255,.22)}
#touch .tc-r.on{opacity:1}

/* ── portrait ─────────────────────────────────────────────────────────────────────────
   The track is framed for 2.35 and the car is 4.5 m long; portrait at this aspect is not a
   squashed game, it is an unplayable one. So: a prompt, and the world paused behind it. */
#rotate{display:none;position:fixed;inset:0;z-index:90;place-items:center;
  background:radial-gradient(120% 90% at 50% 46%,#0a1c2b 0%,#04101a 48%,#01060b 100%);
  font-family:"SF Mono",ui-monospace,Menlo,Consolas,monospace;text-transform:uppercase;
  -webkit-user-select:none;user-select:none;touch-action:none}
body[data-touch="on"][data-orient="portrait"] #rotate{display:grid}
#rotate .ro-in{text-align:center;padding:0 26px}
#rotate .ro-ph{width:54px;height:92px;margin:0 auto 26px;border-radius:9px;
  border:1.5px solid rgba(31,214,255,.55);
  animation:ro-turn 2.8s cubic-bezier(.5,0,.3,1) infinite}
#rotate .ro-t{font-size:13px;letter-spacing:.42em;text-indent:.42em;color:var(--cy)}
#rotate .ro-s{margin-top:12px;font-size:8.5px;letter-spacing:.30em;text-indent:.30em;
  color:#4d7a95}
@keyframes ro-turn{0%,26%{transform:rotate(0)}62%,100%{transform:rotate(-90deg)}}
