:root{
  --ink:#eaf0f8;
  --dim:#94a1b3;
  --accent:#ff5f52;
  --accent2:#3ad2ff;
  --gold:#ffd45e;
  --panel:rgba(8,12,19,.55);
  --stroke:rgba(255,255,255,.11);

  /* The viewport is `viewport-fit=cover`, so the page runs edge to edge and the
     notch / dynamic island / home bar sit ON TOP of it. Every fixed control
     offsets itself by these instead of hard-coding a gutter — in landscape the
     cutout is on the left or right edge, which is exactly where the thumb
     controls and the HUD corners live. The 0px fallback keeps the surrounding
     calc() valid on browsers that do not know env(). */
  --sat:env(safe-area-inset-top,0px);
  --sar:env(safe-area-inset-right,0px);
  --sab:env(safe-area-inset-bottom,0px);
  --sal:env(safe-area-inset-left,0px);

  --gut:clamp(10px,1.6vmin,20px);      /* HUD gutter, before the insets */
}

*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%;overflow:hidden;overscroll-behavior:none}

body{
  background:#05070b;
  color:var(--ink);
  font-family:"Segoe UI",system-ui,-apple-system,Roboto,sans-serif;
  -webkit-user-select:none;user-select:none;
  -webkit-tap-highlight-color:transparent;
  /* NOT `none` — touch-action is intersected down the whole ancestor chain, so
     `none` here would also kill the overlay's own scrolling (a tall options card
     on a landscape phone). The page itself cannot scroll anyway (overflow:hidden
     + overscroll-behavior:none); `manipulation` only drops double-tap zoom. The
     gameplay surfaces below opt back into `none` individually. */
  touch-action:manipulation;
}

#gl{
  position:fixed;inset:0;
  width:100%;height:100%;
  display:block;
  touch-action:none;          /* steering/tap hit-testing lives on the canvas */
}

/* ================= frozen backdrop =================
   Sits directly over the canvas, below everything else. No transition: the
   context is created with preserveDrawingBuffer:false, so the canvas underneath
   may be blanked as soon as the frame is composited and a cross-fade would
   flash black. The still is a downscaled JPEG, so it is already soft — that
   softness reads as depth of field behind the card. */
.freeze{
  position:fixed;inset:0;z-index:1;
  background:#05070b center center / cover no-repeat;
  display:none;pointer-events:none;
}
.freeze.on{display:block}

/* ================= HUD ================= */
.hud{
  position:fixed;inset:0;z-index:3;
  pointer-events:none;
  opacity:0;transition:opacity .3s;
  padding:calc(var(--gut) + var(--sat)) calc(var(--gut) + var(--sar))
          calc(var(--gut) + var(--sab)) calc(var(--gut) + var(--sal));
  font-variant-numeric:tabular-nums;
}
.hud.on{opacity:1}

.hud-tl{position:absolute;top:calc(var(--gut) + var(--sat));left:calc(var(--gut) + var(--sal));display:flex;flex-direction:column;gap:6px;align-items:flex-start}
.hud-tr{position:absolute;top:calc(var(--gut) + var(--sat));right:calc(var(--gut) + var(--sar));display:flex;flex-direction:column;gap:6px;align-items:flex-end}
.hud-br{position:absolute;right:calc(var(--gut) + var(--sar));bottom:calc(var(--gut) + var(--sab));display:flex;flex-direction:column;gap:8px;align-items:flex-end}

.panel{
  background:var(--panel);
  border:1px solid var(--stroke);
  backdrop-filter:blur(8px);
  border-radius:12px;
  padding:6px 13px;
  min-width:132px;
}
.panel.sm{min-width:118px;padding:4px 12px}

.label{display:block;font-size:9px;letter-spacing:.20em;color:var(--dim);text-transform:uppercase}
.value{display:block;font-size:27px;font-weight:800;line-height:1.12}
.value.small{font-size:16px}
.value.dim{color:var(--dim)}

.chip{
  background:var(--panel);border:1px solid var(--stroke);
  backdrop-filter:blur(8px);
  border-radius:999px;padding:5px 13px;
  font-size:10px;font-weight:800;letter-spacing:.16em;
  color:var(--gold);
}
.chip.ghost{color:var(--dim);font-weight:600}
.chip.tiny{font-size:9px;letter-spacing:.10em;opacity:.55}

/* combo */
.combo{
  position:absolute;left:50%;top:14%;
  transform:translateX(-50%) scale(.85);
  text-align:center;
  opacity:0;transition:opacity .18s, transform .18s;
  font-weight:900;
}
.combo.on{opacity:1;transform:translateX(-50%) scale(1)}
.combo .x{font-size:22px;color:var(--accent2);opacity:.75}
.combo span:nth-child(2){font-size:40px;color:var(--accent2);text-shadow:0 0 26px rgba(58,210,255,.8)}
.combo em{display:block;font-style:normal;font-size:9px;letter-spacing:.22em;color:var(--dim);margin-top:-4px}

/* speedo */
.dial{
  background:var(--panel);border:1px solid var(--stroke);
  backdrop-filter:blur(8px);
  border-radius:14px;padding:9px 15px 11px;
  min-width:196px;
}
.rpm-track{
  height:6px;border-radius:4px;overflow:hidden;
  background:rgba(255,255,255,.11);margin-bottom:7px;
}
.rpm-fill{
  height:100%;width:20%;
  background:linear-gradient(90deg,#2c7d4f,#8ad14e 55%,#ffd45e);
  transition:width .05s linear;
}
.rpm-fill.red{background:linear-gradient(90deg,#b8452c,#ff5f52 60%,#fff0a8);box-shadow:0 0 14px rgba(255,95,82,.75)}

.readout{display:flex;align-items:baseline;gap:6px}
.kmh{font-size:40px;font-weight:900;line-height:1;letter-spacing:-.01em}
.unit{font-size:11px;color:var(--dim);letter-spacing:.14em}
.gear{
  margin-left:auto;
  font-size:22px;font-weight:900;color:var(--gold);
  border:1px solid var(--stroke);border-radius:8px;
  padding:1px 11px;background:rgba(255,255,255,.05);
}

.nitro{
  display:flex;align-items:center;gap:9px;
  background:var(--panel);border:1px solid var(--stroke);
  border-radius:12px;padding:6px 13px;
  backdrop-filter:blur(8px);
}
.nitro-label{font-size:9px;letter-spacing:.20em;color:var(--dim)}
.nitro-track{width:156px;height:8px;border-radius:5px;background:rgba(255,255,255,.13);overflow:hidden}
.nitro-fill{
  height:100%;width:100%;
  background:linear-gradient(90deg,#0e7fa8,#3ad2ff 60%,#b6f2ff);
  box-shadow:0 0 12px rgba(58,210,255,.75);
  transition:width .08s linear;
}
.nitro-fill.low{background:linear-gradient(90deg,#7a3510,#ff8a3c);box-shadow:0 0 12px rgba(255,138,60,.7)}
.nitro-fill.boost{animation:pulse .3s infinite alternate}
/* ran dry: greyed until it re-arms, so a held key that does nothing looks deliberate */
.nitro-fill.charging{
  background:linear-gradient(90deg,#3a4450,#5d6b7a);
  box-shadow:none;opacity:.75;animation:none;
}
@keyframes pulse{to{filter:brightness(1.45)}}

/* floating score popups */
.popups{position:fixed;left:50%;top:46%;pointer-events:none;z-index:5}
.pop{
  position:absolute;left:0;top:0;white-space:nowrap;
  font-size:19px;font-weight:900;letter-spacing:.06em;
  transform:translate(-50%,0);
}

/* countdown */
.countdown{
  position:fixed;inset:0;display:none;
  align-items:center;justify-content:center;
  font-size:clamp(90px,22vmin,220px);font-weight:900;
  color:#fff;text-shadow:0 0 60px rgba(58,210,255,.85), 0 10px 40px rgba(0,0,0,.7);
  pointer-events:none;z-index:6;
}
.countdown.on{display:flex}

/* toast */
.toast{
  position:fixed;left:50%;bottom:9%;
  transform:translate(-50%,14px);
  background:rgba(8,12,19,.75);border:1px solid var(--stroke);
  backdrop-filter:blur(8px);
  border-radius:999px;padding:8px 20px;
  font-size:12px;font-weight:700;letter-spacing:.10em;
  opacity:0;transition:opacity .25s, transform .25s;
  pointer-events:none;z-index:6;
}
.toast.on{opacity:1;transform:translate(-50%,0)}

/* ================= touch =================
   The container is inert; only the buttons take pointers, so a press anywhere
   else falls through to the canvas and becomes a steering tap. */
/* Always present: the steer zones double as the mouse control on desktop, only
   the button pads are touch-device-only. Sits *below* the HUD (which is inert)
   so the edge glow washes under the panels instead of tinting them. */
.touch{position:fixed;inset:0;z-index:2;pointer-events:none}

/* edge flash confirming which side is held — the zones never take input */
.zone{
  position:absolute;top:0;bottom:0;width:32%;
  opacity:0;transition:opacity .10s;pointer-events:none;
}
.zone.zl{left:0;background:linear-gradient(90deg,rgba(58,210,255,.22),transparent)}
.zone.zr{right:0;background:linear-gradient(270deg,rgba(58,210,255,.22),transparent)}
.zone.on{opacity:1}

.pad{
  position:absolute;bottom:calc(12px + var(--sab));
  display:none;align-items:flex-end;gap:10px;
}
body.coarse .pad{display:flex}
.pad.l{left:calc(12px + var(--sal))}
.pad.r{right:calc(12px + var(--sar))}

.tbtn{
  pointer-events:auto;
  display:flex;align-items:center;justify-content:center;
  width:74px;height:74px;border-radius:50%;
  font:inherit;font-size:11px;font-weight:800;letter-spacing:.09em;
  color:var(--ink);
  background:rgba(10,16,24,.46);
  border:1px solid var(--stroke);
  backdrop-filter:blur(8px);
  touch-action:none;
  transition:transform .07s, background .07s;
}
.tbtn:active{background:rgba(58,210,255,.26);transform:scale(.93)}
.tbtn.nos{
  width:86px;height:86px;font-size:15px;letter-spacing:.12em;
  color:var(--accent2);border-color:rgba(58,210,255,.34);
}
.tbtn.brake{color:var(--accent);border-color:rgba(255,95,82,.30)}
.tbtn.flash{width:54px;height:54px;font-size:9px;color:var(--gold)}
/* the arrows only exist in button-steering mode; otherwise the halves steer */
.tbtn.arrow{font-size:25px;letter-spacing:0;display:none}
.touch[data-steer="buttons"] .tbtn.arrow{display:flex}

/* pause — no Esc key on a phone. Top centre keeps it clear of both HUD stacks. */
.mbtn{
  position:fixed;z-index:7;display:none;
  top:calc(8px + var(--sat));left:50%;transform:translateX(-50%);
  width:52px;height:36px;border-radius:999px;
  align-items:center;justify-content:center;
  font:inherit;font-size:12px;letter-spacing:.14em;color:var(--dim);
  background:var(--panel);border:1px solid var(--stroke);
  backdrop-filter:blur(8px);touch-action:none;
}
body.coarse .mbtn.on{display:flex}
.mbtn:active{color:var(--ink);background:rgba(58,210,255,.20)}

/* ================= rotate gate ================= */
.rotate{
  position:fixed;inset:0;z-index:30;display:none;
  flex-direction:column;align-items:center;justify-content:center;gap:16px;
  background:#05070b;text-align:center;
  padding:calc(28px + var(--sat)) calc(28px + var(--sar))
          calc(28px + var(--sab)) calc(28px + var(--sal));
  touch-action:none;
}
body.coarse.portrait .rotate{display:flex}
.phone{
  width:52px;height:92px;margin-bottom:6px;
  border:3px solid var(--accent2);border-radius:11px;
  box-shadow:0 0 26px rgba(58,210,255,.45);
  animation:tipover 2.4s ease-in-out infinite;
}
@keyframes tipover{0%,28%{transform:rotate(0)}58%,100%{transform:rotate(-90deg)}}
.rot-title{font-size:17px;font-weight:800;letter-spacing:.04em}
.rot-sub{font-size:12px;color:var(--dim);margin-bottom:10px}
.rotate .btn{width:auto;font-size:11px;padding:10px 16px}

/* ================= overlays ================= */
.overlay{
  position:fixed;inset:0;z-index:10;
  display:flex;
  background:radial-gradient(900px 620px at 50% 44%, rgba(6,10,16,.62), rgba(3,5,9,.92));
  backdrop-filter:blur(5px);
  padding:calc(22px + var(--sat)) calc(22px + var(--sar))
          calc(22px + var(--sab)) calc(22px + var(--sal));
  text-align:center;
  overflow-y:auto;
  touch-action:pan-y;                    /* the one thing that may scroll */
  -webkit-overflow-scrolling:touch;
}
.overlay.hidden{display:none}

/* `margin:auto` centres the card, NOT `align-items:center` on the overlay:
   auto margins absorb only *positive* free space, so a card taller than a short
   landscape screen falls back to top-aligned and stays scrollable. Centring
   would push its first row (Steering) above the scroll origin, out of reach. */
.card{width:100%;max-width:390px;margin:auto;animation:pop .3s ease-out}
.card.hidden{display:none}
@keyframes pop{from{transform:scale(.94);opacity:0}to{transform:scale(1);opacity:1}}

.logo{
  font-size:clamp(32px,9vmin,54px);
  font-weight:900;letter-spacing:.03em;line-height:.95;
  text-shadow:0 0 34px rgba(255,95,82,.45);
}
.logo span{display:block;color:var(--accent)}
.logo i{
  display:block;font-style:normal;
  font-size:.34em;letter-spacing:.6em;margin-top:8px;
  color:var(--accent2);text-shadow:0 0 24px rgba(58,210,255,.7);
}

.tag{color:var(--dim);font-size:13px;line-height:1.6;margin:16px 0 22px}
.title{font-size:32px;font-weight:900;letter-spacing:.05em;margin-bottom:20px}
.title.crash{color:var(--accent);text-shadow:0 0 30px rgba(255,95,82,.55)}

.btn{
  display:block;width:100%;
  margin:9px 0;padding:14px 18px;
  font:inherit;font-size:15px;font-weight:800;letter-spacing:.11em;
  color:#0a0d12;
  background:linear-gradient(180deg,#ff8a7e,var(--accent));
  border:0;border-radius:13px;cursor:pointer;
  box-shadow:0 10px 26px rgba(255,95,82,.30);
  transition:transform .08s, filter .15s;
}
.btn:hover{filter:brightness(1.09)}
.btn:active{transform:translateY(2px)}
.btn.ghost{background:transparent;color:var(--dim);border:1px solid var(--stroke);box-shadow:none}
.btn.ghost:hover{color:var(--ink)}

.keys{list-style:none;margin:22px 0 6px;font-size:12px;color:var(--dim)}
.keys li{margin:9px 0}
kbd{
  display:inline-block;min-width:22px;padding:2px 6px;margin-right:3px;
  font:inherit;font-size:11px;color:var(--ink);
  background:rgba(255,255,255,.08);
  border:1px solid var(--stroke);border-bottom-width:2px;border-radius:5px;
}

.best{margin-top:16px;font-size:12px;color:var(--dim)}
.best b{color:var(--ink)}

.loading{color:var(--dim);font-size:13px;margin-top:20px;animation:blink 1.1s infinite}
.loading a{color:var(--accent2)}
@keyframes blink{50%{opacity:.35}}

.stats{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:18px}
.stats div{
  background:rgba(255,255,255,.05);border:1px solid var(--stroke);
  border-radius:11px;padding:10px 6px;
}
.stats span{display:block;font-size:9px;letter-spacing:.16em;color:var(--dim);text-transform:uppercase}
.stats b{font-size:20px;font-variant-numeric:tabular-nums}

.newbest{
  color:var(--gold);font-weight:800;font-size:13px;letter-spacing:.16em;
  margin-bottom:14px;animation:blink 1s infinite;
}
.newbest.hidden{display:none}

/* options */
.opts{margin-bottom:22px}
.opt{
  display:flex;align-items:center;justify-content:space-between;gap:14px;
  padding:11px 4px;border-bottom:1px solid rgba(255,255,255,.06);
  font-size:13px;color:var(--dim);
}
.pill{
  font:inherit;font-size:12px;font-weight:800;letter-spacing:.08em;
  color:var(--ink);background:rgba(255,255,255,.07);
  border:1px solid var(--stroke);border-radius:999px;
  padding:6px 18px;cursor:pointer;min-width:104px;
}
.pill:hover{background:rgba(58,210,255,.16)}
input[type=range]{
  -webkit-appearance:none;appearance:none;
  width:150px;height:5px;border-radius:4px;
  background:rgba(255,255,255,.15);outline:none;cursor:pointer;
  /* a sideways drag adjusts the slider, a vertical one still scrolls the card */
  touch-action:pan-y;
}
input[type=range]::-webkit-slider-thumb{
  -webkit-appearance:none;width:16px;height:16px;border-radius:50%;
  background:var(--accent2);box-shadow:0 0 10px rgba(58,210,255,.7);
}
input[type=range]::-moz-range-thumb{
  width:16px;height:16px;border:0;border-radius:50%;
  background:var(--accent2);box-shadow:0 0 10px rgba(58,210,255,.7);
}

@media (max-height:640px){
  .key-only{display:none}
  .stats b{font-size:17px}
}
@media (max-width:560px){
  .hud-tl .panel:nth-child(3){display:none}
  .dial{min-width:160px}
  .kmh{font-size:32px}
  .nitro-track{width:118px}
}

/* ================= touch device ==================
   `coarse` is set on <body> at boot (game.js section 7) rather than driven by a
   media query, so the option rows and the key list agree with the input scheme
   the game actually picked. */
.touch-only{display:none}
body.coarse .touch-only{display:block}
body.coarse .opt.touch-only{display:flex}
body.coarse .key-only{display:none}

/* the thumb corners belong to the controls, so the speedo moves to the middle
   of the bottom edge where it blocks the least road */
body.coarse .hud-br{
  right:auto;left:50%;transform:translateX(-50%);
  bottom:calc(9px + var(--sab));
  flex-direction:row;align-items:center;gap:8px;
}
body.coarse .dial{min-width:0;padding:6px 12px 8px}
body.coarse .kmh{font-size:27px}
body.coarse .rpm-track{width:104px;margin-bottom:5px}
body.coarse .nitro{flex-direction:column;gap:4px;padding:6px 11px}
body.coarse .nitro-track{width:86px;height:7px}
body.coarse .combo{top:19%}
body.coarse .hud-tl .value{font-size:21px}
body.coarse .hud-tl .panel{min-width:104px;padding:4px 10px}
body.coarse #fps{display:none}

/* landscape phones are short — claw back vertical space */
@media (pointer:coarse) and (max-height:460px){
  .tbtn{width:64px;height:64px}
  .tbtn.nos{width:74px;height:74px;font-size:13px}
  .tbtn.flash{width:46px;height:46px;font-size:8px}
  .pad{bottom:calc(8px + var(--sab));gap:8px}

  /* the options card is the tallest screen — nine rows on a touch device.
     Tighten it so it mostly fits; what is left over scrolls. */
  .overlay{padding-top:calc(12px + var(--sat));padding-bottom:calc(12px + var(--sab))}
  .title{font-size:23px;margin-bottom:12px}
  .opts{margin-bottom:13px}
  .opt{padding:7px 4px;font-size:12px}
  .pill{padding:5px 16px;min-width:94px}
  .btn{margin:7px 0;padding:11px 16px;font-size:14px}
}

/* the second rule must out-specify `body.coarse .opt.touch-only` above, which
   would otherwise force the tilt rows back on when the scheme is not tilt */
.hidden{display:none}
body.coarse .touch-only.hidden{display:none}
