/* ============================================================================
   HAPPINESS CITY — مدينة السعادة
   UI stylesheet, built from the "Game logo UI theme" design canvas.

   Two temperature families taken straight off the logo:
     FIRE (gold → red)  = action, money, urgency, rewards
     ICE  (pale → blue) = navigation, panels, info, calm
   Every raised thing has a heavy black outline and a solid bottom face that
   collapses when pressed. Nothing is soft — no blur, no drop shadows that
   fade; the depth is all flat extrusion, the way the logo's letters are.

   ── The unit system ────────────────────────────────────────────────────────
   The whole game lives inside #stage, a fixed 16:9 landscape box (HD,
   rendered at up to 1920x1080). `html` sets 1rem = 1 "design pixel" of a
   640x360 design canvas, so the entire UI scales as one piece with the
   stage. (On a landscape phone 1rem stays about the physical size the old
   352px-wide portrait mockup gave it.) Never use px for UI sizes here.

   ── Landscape layout ───────────────────────────────────────────────────────
   Height is the scarce axis (332rem inside the padding), width is not. The
   middle third belongs to the runner and the street: in a run the hazards
   appear at the vanishing point (~38% down) and the runner's feet sit at
   ~80%, so the HUD keeps to the top edge and the four corners. On the menu
   the runner stands in the clear middle third and the panels take side
   columns. Sheets lay out in two columns rather
   than one long scroll, and dialogs are capped in width and centred.

   ── Direction ──────────────────────────────────────────────────────────────
   Arabic and English share one layout. Every row is flex and the handful of
   directional rules key off :root[dir], so switching `dir` on <html> mirrors
   the whole UI with no second stylesheet.
   ========================================================================== */

@import url('./fonts.css');

*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

:root {
  /* fire ramp — action / money (warm painted amber, not neon) */
  --fire-1: #FFC44E;
  --fire-2: #F5952F;
  --fire-3: #E2672A;
  --fire-4: #B5361B;
  --fire-deep: #5A1E08;
  --fire-ink: #2A1206;

  /* ice ramp — toggles, best (pulled toward the teal of the panels) */
  --ice-1: #C2F0F0;
  --ice-2: #5FC7D1;
  --ice-3: #2A8FA6;
  --ice-deep: #1B6478;
  --ice-ink: #082A33;

  /* night ramp — ground: deep slate-teal ink */
  --night: #0A1418;
  --night-2: #1A303A;
  --night-3: #284753;
  --slab: #2F5562;
  --slab-2: #1D3641;
  --well: #0B161B;

  --outline: #160A04;
  --outline-drop: #0A0E10;

  --text: #F4E6C8;
  --text-ice: #E6D7B8;
  --text-mute: rgba(226, 210, 178, .62);
  --danger: #FF8A72;

  /* ---- the painted bronze plaque (Arcane-style frames) ------------------
     Every framed thing is three background layers in one box: a neutral
     brush-stroke tile, the fill (clipped to the padding box) and a bronze
     gradient showing through a transparent 3rem border (the rim, lit from
     above so it reads bevelled). Box-shadows add a dark ink line outside the
     rim and another inside it. All flat layers: nothing blurs, nothing
     filters, so a repaint of the live score costs next to nothing. The
     generator for paint.webp and the orn-*.svg scrolls is
     assets/ui/make_ui_paint.py. */
  --ink: #160A04;
  --teal-hi: #406B7A;
  --teal: #2A4A58;
  --teal-lo: #172E39;
  --rim: linear-gradient(#FBDDAE, #DC9A5C 15%, #B26B35 38%, #7B3E1A 62%, #BC763F 82%, #4A240E) border-box;
  --paint: url(../assets/ui/paint.webp) 0 0 / 128rem repeat padding-box;
  --teal-fill: radial-gradient(140% 120% at 36% 26%, var(--teal-hi), var(--teal) 46%, var(--teal-lo)) padding-box;
  --amber-fill: linear-gradient(#FFD27A, var(--fire-2) 52%, var(--fire-3) 80%, #C24A1E) padding-box;
  --frame: 0 0 0 1.5rem var(--ink), inset 0 0 0 1.5rem rgba(18, 8, 2, .85);
  --drop: rgba(8, 8, 8, .5);
  --cream: #F7E9CB;
  --orn: url(../assets/ui/orn-tl.svg) left top / 22rem 22rem no-repeat padding-box,
         url(../assets/ui/orn-tr.svg) right top / 22rem 22rem no-repeat padding-box,
         url(../assets/ui/orn-bl.svg) left bottom / 22rem 22rem no-repeat padding-box,
         url(../assets/ui/orn-br.svg) right bottom / 22rem 22rem no-repeat padding-box;
  --orn-sm: url(../assets/ui/orn-tl.svg) left top / 13rem 13rem no-repeat padding-box,
         url(../assets/ui/orn-tr.svg) right top / 13rem 13rem no-repeat padding-box,
         url(../assets/ui/orn-bl.svg) left bottom / 13rem 13rem no-repeat padding-box,
         url(../assets/ui/orn-br.svg) right bottom / 13rem 13rem no-repeat padding-box;

  --ar: 'Baloo Bhaijaan 2', 'Cairo', system-ui, sans-serif;
  --ui: 'Cairo', system-ui, -apple-system, sans-serif;
  --display: 'Bungee', 'Cairo', system-ui, sans-serif;
  --mono: ui-monospace, 'Cascadia Mono', Consolas, monospace;
}

/* ---------------------------------------------------------------- the stage
   Width is the smaller of "as wide as the window" and "as wide as a 16:9 box
   that still fits the window's height", so the frame is always HD-shaped:
   edge to edge on a 16:9 monitor or a landscape phone, pillarboxed in a wider
   window and letterboxed in a taller one. The canvas inside is drawn at a
   fixed HD resolution per tier (js/main.js, renderSize), not at this CSS size
   times the device ratio. */
html {
  --stage-w: min(100vw, calc(100vh * 16 / 9));
  font-size: calc(var(--stage-w) / 640);   /* 1rem = 1 design px of 640x360 */
}
@supports (height: 100dvh) {
  html { --stage-w: min(100vw, calc(100dvh * 16 / 9)); }
}

html, body {
  width: 100%; height: 100%;
  overflow: hidden;
  background:
    radial-gradient(60% 50% at 50% 42%, #101A36 0%, transparent 70%),
    #04060D;
  font-family: var(--ui);
  color: var(--text);
  touch-action: none;
  -webkit-user-select: none; user-select: none;
  -webkit-tap-highlight-color: transparent;
}

button, input { font-family: inherit; color: inherit; border: none; background: none; }
button { cursor: pointer; }

#stage {
  position: fixed;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: var(--stage-w);
  height: calc(var(--stage-w) * 9 / 16);
  overflow: hidden;
  background: var(--night);
  box-shadow: 0 0 0 3rem var(--outline), 0 24rem 70rem rgba(0, 0, 0, .75);
}
/* Only round the corners when the frame is actually a frame (a clear bar on
   two sides). A 16:9 monitor or a landscape phone that the stage fills edge to
   edge keeps square corners: rounding there would just clip the render. */
@media (min-aspect-ratio: 17/9) and (min-width: 480px), (max-aspect-ratio: 15/9) and (min-width: 480px) {
  #stage { border-radius: 12rem; }
}
/* A 16:9 stage on a phone held upright is a sliver across the middle of the
   screen: ask for landscape instead (a plain web page cannot lock the
   orientation, it takes fullscreen on Android and is not possible on iOS).
   Phones only: a tablet held upright (768 px and up) letterboxes to a
   playable band. The query matches main.js rotateMq. One pseudo-element:
   the bronze-rimmed teal plaque of the dialogs, centred, with a spread shadow
   for the dark backdrop. Sized in px: the rem follows the sliver stage here. */
@media (orientation: portrait) and (hover: none) and (pointer: coarse) and (max-width: 600px) {
  body::after {
    content: '\21BB\A Rotate your device';
    white-space: pre-line;
    position: fixed; left: 50%; top: 50%; z-index: 1000;
    transform: translate(-50%, -50%);
    width: min(78vw, 300px); box-sizing: border-box;
    padding: 18px 20px 20px; text-align: center;
    background: url(../assets/ui/paint.webp) 0 0 / 96px repeat padding-box,
      radial-gradient(140% 120% at 36% 26%, var(--teal-hi), var(--teal) 46%, var(--teal-lo)) padding-box,
      var(--rim);
    border: 4px solid transparent; border-radius: 14px;
    box-shadow: 0 0 0 2px var(--ink), inset 0 0 0 2px rgba(18, 8, 2, .85), 0 0 0 100vmax #04060D;
    color: var(--cream); text-shadow: 0 2px 0 var(--ink);
    font: 600 22px/1.45 var(--ui);
  }
  html[lang="ar"] body::after { content: '\21BB\A أدر جهازك أفقيًا'; font-family: var(--ar); font-weight: 700; }
}

#app, #app canvas { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }

.hidden { display: none !important; }

/* Any full-frame layer. Safe-area insets keep the rows clear of the home
   indicator. The notch sits on the left or right of a landscape phone, but a
   notched phone is longer than 16:9, so the stage is pillarboxed and the notch
   already falls in the side bar: only the part of the side inset that reaches
   past the bar (env() is measured against the viewport, not the stage) is
   added, which is 0 on every current phone. */
.screen {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  --bar-x: calc((100vw - var(--stage-w)) / 2);
  padding: calc(14rem + env(safe-area-inset-top, 0px))
           calc(14rem + max(0px, env(safe-area-inset-right, 0px) - var(--bar-x)))
           calc(14rem + env(safe-area-inset-bottom, 0px))
           calc(14rem + max(0px, env(safe-area-inset-left, 0px) - var(--bar-x)));
  z-index: 10;
}

/* ============================================================== keyframes */
@keyframes hcShine  { 0% { transform: translateX(-140%) skewX(-18deg); }
                     55%,100% { transform: translateX(420%) skewX(-18deg); } }
@keyframes hcFloat  { 0%, 100% { transform: translateY(0); }
                      50% { transform: translateY(-7rem); } }
@keyframes hcPulse  { 0%, 100% { opacity: .5; transform: scale(1); }
                      50% { opacity: .95; transform: scale(1.07); } }
@keyframes hcBar    { 0% { background-position: 0 0; }
                      100% { background-position: 28rem 0; } }
@keyframes hcSpin   { to { transform: rotate(360deg); } }
@keyframes hcPop    { from { transform: scale(.86) translateY(10rem); opacity: 0; } }
@keyframes hcBadge  { 0%, 100% { transform: scale(1); }
                      50% { transform: scale(1.06); } }
@keyframes hcToast  { 0% { transform: translate(-50%, -16rem); opacity: 0; }
                      12%, 82% { transform: translate(-50%, 0); opacity: 1; }
                      100% { transform: translate(-50%, -10rem); opacity: 0; } }
@keyframes hcToastSide { 0% { transform: translateY(-12rem); opacity: 0; }
                         12%, 82% { transform: translateY(0); opacity: 1; }
                         100% { transform: translateY(-8rem); opacity: 0; } }

/* ============================================================== primitives */

.hc-slab {
  background: var(--paint), var(--teal-fill), var(--rim);
  border: 3rem solid transparent;
  border-radius: 8rem;
  box-shadow: var(--frame);
}

/* The pills: the plaque recipe without corner scrolls (too tight for them). */
.hc-chip {
  display: flex; align-items: center; gap: 6rem;
  padding: 4rem 9rem;
  background: var(--paint), var(--teal-fill), var(--rim);
  border: 3rem solid transparent;
  border-radius: 24rem;
  box-shadow: var(--frame), 0 3rem 0 1.5rem var(--drop);
  font: 400 12rem/1 var(--display);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  text-shadow: 0 1.5rem 0 rgba(10, 6, 2, .85);
}
.hc-chip.fire { color: var(--fire-1); }
.hc-chip.ice  { color: #A6ECEF; }
/* the HUD best readout is cream, like the score (the reference), not gem blue */
#high-chip:not(.beat) { color: var(--cream); }
.hc-chip .k {
  font: 700 9rem/1 var(--ar); letter-spacing: 0;
  color: rgba(226, 210, 178, .72);
  text-shadow: none;
}
/* The HUD best chip once this run's score has passed it: an amber badge that
   pops once, then keeps counting with the score (ui.setScore). */
.hc-chip.beat {
  color: var(--fire-ink);
  background: var(--paint), var(--amber-fill), var(--rim);
  text-shadow: 0 1rem 0 rgba(255, 230, 170, .5);
  animation: hcBadge .5s ease-out 1;
}
.hc-chip.beat .k { color: rgba(42, 18, 6, .75); }

/* The little geometric currency marks. The coin is a minted piece: gold face,
   a struck inner ring, a dark bronze edge. */
.pip { display: block; flex: none; }
.pip-coin {
  width: 16rem; height: 16rem; border-radius: 50%;
  background:
    radial-gradient(circle at 38% 32%, #FFF0B8 0 12%, transparent 30%),
    radial-gradient(circle, #FFE58A 0 9%, #A8571A 11% 18%, transparent 21%),
    radial-gradient(circle, transparent 0 52%, rgba(122, 56, 10, .55) 56% 62%, transparent 66%),
    radial-gradient(circle at 50% 40%, #FFD45E, #F0A02A 60%, #B9631A);
  border: 2rem solid #5A2A0C;
  box-shadow: 0 0 0 1rem #C98446;
}

/* Square icon buttons (pause, back, char arrows): a small ornate plaque with
   the corner scrolls; the bottom face collapses when pressed. */
.hc-icon {
  position: relative;
  width: 44rem; height: 44rem; flex: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--orn-sm), var(--paint), var(--teal-fill), var(--rim);
  border: 3rem solid transparent;
  border-radius: 9rem;
  box-shadow: var(--frame), 0 5rem 0 1.5rem var(--drop);
  color: var(--cream);
  font: 700 18rem/1 var(--ui);
  text-shadow: 0 1.5rem 0 var(--ink);
  transition: transform .06s, box-shadow .06s, filter .12s;
}
.hc-icon:hover { filter: brightness(1.15); }
.hc-icon:active, .hc-icon.is-down {
  transform: translateY(4rem);
  box-shadow: var(--frame), 0 1rem 0 1.5rem var(--drop);
}
/* The pause bars are cast bronze, inked like the scrolls. */
.ic-pause { display: flex; gap: 4rem; }
.ic-pause i {
  width: 5rem; height: 16rem; border-radius: 1.5rem;
  background: linear-gradient(90deg, #FCE0B2, #DE9C5E 45%, #A9602C);
  box-shadow: 0 0 0 1.2rem var(--ink), 0 2rem 0 1.2rem rgba(10, 6, 2, .45);
}

/* The primary action block: amber paint in the bronze rim, 9rem bottom face,
   sweeping shine. */
.hc-play {
  position: relative; overflow: hidden;
  display: flex; align-items: center; justify-content: center; gap: 10rem;
  width: 100%; padding: 16rem;
  background: var(--orn), var(--paint), var(--amber-fill), var(--rim);
  border: 3rem solid transparent;
  border-radius: 10rem;
  box-shadow:
    var(--frame),
    inset 0 5rem 0 rgba(255, 240, 200, .35),
    0 9rem 0 #4A1F09,
    0 9rem 0 1.5rem var(--ink);
  transition: transform .06s, box-shadow .06s, filter .12s;
}
.hc-play .ar { font: 800 25rem/1 var(--ar); color: var(--fire-ink); text-shadow: 0 1.5rem 0 rgba(255, 228, 170, .55); }
.hc-play .en { font: 400 12rem/1 var(--display); color: rgba(42, 18, 6, .62); letter-spacing: .08em; }
.hc-play .shine {
  position: absolute; top: 0; bottom: 0; width: 38rem;
  background: linear-gradient(90deg, transparent, rgba(255, 246, 220, .45), transparent);
  animation: hcShine 3s ease-in-out infinite;
}
.hc-play:hover { filter: brightness(1.05); }
.hc-play:active, .hc-play.is-down {
  transform: translateY(7rem);
  box-shadow: var(--frame), inset 0 5rem 0 rgba(255, 240, 200, .35),
              0 2rem 0 #4A1F09, 0 2rem 0 1.5rem var(--ink);
}
.hc-play[disabled] { filter: grayscale(.85) brightness(.6); pointer-events: none; }

.hc-btn {
  flex: 1; padding: 12rem 8rem;
  display: flex; flex-direction: column; align-items: center; gap: 2rem;
  border: 3rem solid transparent;
  border-radius: 8rem;
  transition: transform .06s, box-shadow .06s, filter .12s;
}
.hc-btn.wide { flex: 1 1 100%; }
.hc-btn b     { font: 800 15rem/1.15 var(--ar); }
.hc-btn small { font: 600 9rem/1 var(--mono); letter-spacing: .1em; }
.hc-btn.fire {
  background: var(--paint), var(--amber-fill), var(--rim);
  box-shadow: var(--frame), inset 0 4rem 0 rgba(255, 240, 200, .32),
              0 6rem 0 #4A1F09, 0 6rem 0 1.5rem var(--ink);
}
.hc-btn.fire b     { color: var(--fire-ink); }
.hc-btn.fire small { color: rgba(42, 18, 6, .62); }
.hc-btn.fire:active, .hc-btn.fire.is-down {
  transform: translateY(4rem);
  box-shadow: var(--frame), inset 0 4rem 0 rgba(255, 240, 200, .32),
              0 2rem 0 #4A1F09, 0 2rem 0 1.5rem var(--ink);
}
.hc-btn.dark {
  background: var(--paint), var(--teal-fill), var(--rim);
  box-shadow: var(--frame), 0 6rem 0 1.5rem var(--drop);
}
.hc-btn.dark b     { color: var(--cream); text-shadow: 0 1.5rem 0 var(--ink); }
.hc-btn.dark small { color: rgba(226, 210, 178, .55); }
.hc-btn.dark.danger b { color: var(--danger); }
.hc-btn.dark:active, .hc-btn.dark.is-down {
  transform: translateY(4rem);
  box-shadow: var(--frame), 0 2rem 0 1.5rem var(--drop);
}
.hc-btn:hover { filter: brightness(1.12); }
.hc-btn[disabled] { filter: grayscale(.8) brightness(.6); pointer-events: none; }
/* A tap leaves :hover stuck on a touch screen, so the hover lift would keep a
   button lit until the next tap somewhere else. Disabled ones keep their grey. */
@media (hover: none) {
  .hc-icon:hover, .hc-play:hover:not([disabled]), .hc-btn:hover:not([disabled]) { filter: none; }
}

/* A thin progress rail, used inside chips, rows and rails. */
.mini-bar {
  height: 7rem; padding: 1rem;
  background: var(--well); border: 1.5rem solid #9A5A2C; border-radius: 5rem;
  box-shadow: 0 0 0 1rem var(--ink), inset 0 1.5rem 0 rgba(0, 0, 0, .5);
}
.mini-bar > i {
  display: block; height: 100%; width: 0%;
  background: linear-gradient(var(--fire-1), var(--fire-3));
  border-radius: 3rem;
  transition: width .35s ease-out;
}

/* ================================================================== FX layers */
#vignette {
  position: absolute; inset: 0; pointer-events: none; z-index: 4;
  background: radial-gradient(ellipse at center, transparent 72%, rgba(4, 6, 13, .4) 100%);
}
#flash {
  position: absolute; inset: 0; pointer-events: none; z-index: 9;
  background: radial-gradient(ellipse at center, rgba(224, 27, 18, .25), rgba(224, 27, 18, .6));
  opacity: 0; transition: opacity .1s;
}
#flash.on { opacity: 1; }

/* ====================================================================== HUD */
#hud { pointer-events: none; z-index: 5; }
#hud button { pointer-events: auto; }

/* Top edge: pause in the inline-start corner, the score plaque dead centre
   over the sky (a grid, so the uneven corners never push it off-centre), the
   coin and best chips in the inline-end corner. */
.hud-top { display: grid; grid-template-columns: 1fr auto 1fr; align-items: start; gap: 8rem; }
.hud-left  { display: flex; gap: 8rem; justify-self: start; }
.hud-right { display: flex; flex-direction: column; gap: 6rem; align-items: flex-end; justify-self: end; }
.hud-gap { flex: 1; }

/* The city behind the HUD is a pale, hazy daylight street, not the mockup's
   night sky — bare text vanished into it, so the readout sits on its own chip. */
.hud-score {
  position: relative;               /* anchors the "+N" floats */
  /* Holds a 7-character score ("999,999": ~96rem of Bungee at 22rem, plus
     the padding and border) so the chip never resizes mid-run below 1M. */
  /* The ornate plaque of the reference: teal paint, bronze rim, a filigree
     scroll in each corner. Sized for the landscape top edge: it ends ~62rem
     down, well above the vanishing point at ~137rem. */
  text-align: center; min-width: 136rem;
  padding: 5rem 16rem 7rem;
  background: var(--orn), var(--paint), var(--teal-fill), var(--rim);
  border: 3rem solid transparent;
  border-radius: 12rem;
  box-shadow: var(--frame), 0 5rem 0 1.5rem var(--drop);
}
.hud-score-label {
  font: 400 8.5rem/1 var(--display);
  letter-spacing: .1em; color: rgba(222, 214, 198, .78);
  text-shadow: 0 1.5rem 0 rgba(10, 6, 2, .7);
  white-space: nowrap;
}
.hud-score-label .ar { font: 700 8.5rem/1 var(--ar); letter-spacing: 0; }
/* Bungee, the logo's blocky digits, in cream with an inked edge; the drop
   shadow is the extrusion. */
.hud-score-val {
  margin-top: 4rem;
  font: 400 22rem/1 var(--display); font-variant-numeric: tabular-nums;
  color: var(--cream);
  -webkit-text-stroke: 1.5rem var(--ink); paint-order: stroke fill;
  text-shadow: 0 2.5rem 0 rgba(12, 22, 28, .9);
  /* its own small layer: the per-frame score text re-rasters only the
     digits, never the plaque, scrolls and paint tile under them */
  will-change: transform;
}
/* "+N" per coin, drifting down beside the score plaque on its inline-end
   side (ui.floatText). Not under it: the combo pill sits under the plaque for
   most of a run and would cover it. LTR and isolated so "+30" never reads
   "30+" in Arabic; that makes its own logical sides LTR too, so the side is
   set physically, with an RTL twin. Starts invisible; the WAAPI fade leaves
   it at opacity 0. */
.score-float {
  position: absolute; left: 100%; top: 50%; margin-left: 6rem;
  z-index: 1;
  direction: ltr; unicode-bidi: isolate;
  pointer-events: none; opacity: 0;
  font: 400 12rem/1 var(--display); color: var(--fire-1);
  white-space: nowrap;
  -webkit-text-stroke: 1.2rem var(--ink); paint-order: stroke fill;
  text-shadow: 0 2rem 0 var(--outline);
}
:root[dir='rtl'] .score-float { left: auto; right: 100%; margin-left: 0; margin-right: 6rem; }
/* 40rem is about 43 CSS px on a landscape phone; the apron below takes the
   hit area to 56rem. */
#hud .hc-icon { width: 40rem; height: 40rem; font-size: 15rem; }
#hud .ic-pause i { height: 15rem; width: 5rem; }
/* The pause button is smaller than a fingertip; an invisible 8rem apron
   around it takes the near misses. */
#hud .hc-icon::after { content: ''; position: absolute; inset: -8rem; }

/* Under the score, centred: it still ends above the vanishing point (~112rem
   down against ~137rem), so the streak reads without covering what is coming. */
.combo {
  align-self: center; margin-top: 8rem;
  display: flex; align-items: center; gap: 7rem;
  padding: 5rem 13rem;
  background: var(--paint), linear-gradient(#F08A3A, var(--fire-3) 50%, #A8331A) padding-box, var(--rim);
  border: 3rem solid transparent;
  border-radius: 24rem;
  /* Solid: the old opacity pulse dipped to 50% and the pill went unread. It
     pops on a step up instead (.pop, set by ui.setCombo). */
  box-shadow: var(--frame), inset 0 4rem 0 rgba(255, 220, 160, .25), 0 4rem 0 1.5rem var(--drop);
  animation: none;
}
.combo #combo-x {
  font: 400 14rem/1 var(--display); color: var(--cream);
  -webkit-text-stroke: 1.2rem var(--ink); paint-order: stroke fill;
}
@keyframes hcComboPop { 0% { transform: scale(1.6) rotate(-6deg); }
                        60% { transform: scale(.92); }
                        100% { transform: scale(1); } }
.combo.pop { animation: hcComboPop .35s cubic-bezier(.2, 1.6, .4, 1); }
/* Coins toward the next step, five per step; hidden at the x5 cap. */
.combo-pips { display: flex; gap: 3rem; }
.combo-pips i { width: 6rem; height: 6rem; border-radius: 2rem; background: rgba(40, 12, 2, .4); }
.combo-pips i.on { background: var(--cream); box-shadow: 0 0 0 1rem var(--ink); }
.combo-pips.hidden { display: none !important; }

/* Near-miss pop under the score. White, not a hazard colour: amber and coral
   stay the only saturated things in the frame. Animated by ui.nearMiss(),
   which lifts it at most 4rem. The combo pill occupies ~74-112rem while a
   streak is live, so the pop drops below it then (122rem, so the lift never
   tucks it under the pill) and sits right under the score otherwise. */
.near-pop {
  position: absolute; inset-inline: 0;
  /* #hud's padding-top carries the safe-area inset and the score and combo
     pill flow below it, so this absolute offset has to carry it too. */
  top: calc(122rem + env(safe-area-inset-top, 0px));
  text-align: center; pointer-events: none;
  font: 400 14rem/1 var(--display); color: var(--cream);
  -webkit-text-stroke: 1.5rem var(--ink); paint-order: stroke fill;
  text-shadow: 0 2rem 0 var(--outline);
}
.combo.hidden + .near-pop { top: calc(76rem + env(safe-area-inset-top, 0px)); }

/* A green door close ahead (main.js: under 60 m, and through the flash) owns
   the top centre: the score plaque and the combo pill dim so the whole lit
   rectangle and its bright lintel read, as in the film. The corners (pause,
   coins, mission) stay. Opacity only, so reduced motion keeps it. */
.hud-score, .combo, .near-pop { transition: opacity .25s ease-out; }
#hud.door-near .hud-score, #hud.door-near .combo, #hud.door-near .near-pop { opacity: .3; }
/* the world's name takes that band while it shows */
#hud.wn-on .combo, #hud.wn-on .near-pop { opacity: 0; }

/* The world a green door opens onto (ui.worldName): the Arabic name in cream
   over a small bronze-ruled English line. The flash is its title card: it
   lands on the opaque peak and is gone ~1.1 s later, before the first hazard
   row after a door comes up the road. It sits in the combo band under the
   (dimmed) score plaque, ending ~112rem down, above the vanishing point
   (~137rem). No plaque: a caption, not a dialog. */
.world-name {
  position: absolute; inset-inline: 0; top: calc(66rem + env(safe-area-inset-top, 0px));
  display: flex; flex-direction: column; align-items: center; gap: 4rem;
  text-align: center; pointer-events: none; opacity: 0;
}
.world-name.show { animation: hcWorldName 1.1s ease-out both; }
.world-name .wn-ar {
  font: 800 28rem/1.15 var(--ar); color: var(--cream);
  -webkit-text-stroke: 1.5rem var(--ink); paint-order: stroke fill;
  text-shadow: 0 2rem 0 var(--outline), 0 0 18rem rgba(6, 40, 26, .55);
}
.world-name .wn-en {
  display: flex; align-items: center; gap: 7rem;
  font: 400 10rem/1 var(--display); letter-spacing: .2em; color: #F2C48A;
  -webkit-text-stroke: 1.2rem var(--ink); paint-order: stroke fill;
  text-shadow: 0 1.5rem 0 var(--ink), 0 0 10rem rgba(6, 40, 26, .6);
}
.world-name .wn-en::before, .world-name .wn-en::after {
  content: ''; width: 30rem; height: 2rem; border-radius: 1rem;
  background: linear-gradient(90deg, transparent, #DC9A5C 40%, #FBDDAE 50%, #DC9A5C 60%, transparent);
}
@keyframes hcWorldName { 0% { opacity: 0; transform: translateY(6rem) scale(.96); }
                         15% { opacity: 1; transform: none; }
                         60% { opacity: 1; transform: none; }
                         100% { opacity: 0; transform: translateY(-4rem); } }

/* First-run hint pill (ui.showHint): neutral ink, not a hazard colour, so
   amber and coral stay the only saturated things in the frame. Bottom centre,
   under the runner's feet (~80% down) and between the mission and magnet
   corners, so it never sits on the road the hazard is coming down. */
#run-hint {
  position: absolute; inset-inline: 0;
  bottom: calc(16rem + env(safe-area-inset-bottom, 0px));
  margin: auto; width: fit-content; max-width: 200rem;
  padding: 6rem 14rem; border-radius: 20rem;
  border: 2.5rem solid transparent;
  background: var(--paint), var(--teal-fill), var(--rim);
  box-shadow: var(--frame);
  color: var(--cream); font: 700 11.5rem/1.2 var(--ui); text-align: center;
  text-shadow: 0 1.5rem 0 var(--ink);
  pointer-events: none;
  animation: hcNudge 1s ease-in-out infinite;
}
#run-hint[lang="ar"] { font-family: var(--ar); }
@keyframes hcNudge { 50% { transform: translateY(-4rem); } }

/* The 3-2-1 resume count (ui.showCountdown), over the frozen frame. Each
   number punches in and settles; the JS replays the animation per step. */
.countdown {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  pointer-events: none;
  font: 400 84rem/1 var(--display); color: var(--cream);
  -webkit-text-stroke: 5rem var(--outline); paint-order: stroke fill;
  text-shadow: 0 6rem 0 var(--outline);
  animation: hcCount .7s cubic-bezier(.2, 1.5, .4, 1) both;
}
@keyframes hcCount {
  0%   { transform: scale(1.6); opacity: 0; }
  25%  { transform: scale(1);   opacity: 1; }
  100% { transform: scale(.9);  opacity: .85; }
}
.combo .combo-label { font: 700 10rem/1 var(--ar); color: #FFF2DA; text-shadow: 0 1.5rem 0 rgba(60, 14, 2, .8); }

/* The bottom corners: the mission at the inline start, the magnet timer at
   the inline end, the runner in the clear middle between. */
.hud-bottom { display: flex; align-items: flex-end; gap: 12rem; }
.hud-boosts { display: flex; gap: 8rem; margin-inline-start: auto; }
.boost-slot {
  width: 46rem; height: 46rem;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3rem;
  background: var(--orn-sm), var(--paint), var(--teal-fill), var(--rim);
  border: 3rem solid transparent; border-radius: 9rem;
  box-shadow: var(--frame), 0 4rem 0 1.5rem var(--drop);
}
.boost-slot .mark.magnet { width: 30rem; height: 15rem; border: 0; border-radius: 0; background: url(../assets/logo_token.png) center / contain no-repeat; }
.boost-slot em { font: 600 9rem/1 var(--mono); font-style: normal; color: var(--fire-1); }

/* A compact two-line card, fixed width so a new label never resizes it: the
   label on top, then the bar and the live count. */
.hud-mission {
  width: 190rem; flex: none;
  display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 5rem 8rem;
  padding: 7rem 11rem 8rem;
  background: var(--paint), var(--teal-fill), var(--rim);
  border: 3rem solid transparent; border-radius: 10rem;
  box-shadow: var(--frame), 0 4rem 0 1.5rem var(--drop);
}
.hud-mission-text {
  grid-column: 1 / -1;
  font: 700 9.5rem/1.3 var(--ui); color: rgba(240, 228, 204, .9);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.hud-mission .mini-bar { grid-row: 2; grid-column: 1; }
/* Live "cur/goal", always LTR so the slash never flips. */
.mission-n {
  flex: none;
  font: 600 9.5rem/1 var(--mono); font-variant-numeric: tabular-nums;
  color: var(--text-mute);
}
.hud-mission .mission-n { grid-row: 2; grid-column: 2; }
/* Goal reached mid-run: fire outline and count, and one double pop. It pays
   out when the run is banked. */
.hud-mission.is-done { background: var(--paint), var(--teal-fill), linear-gradient(#FFE6A8, var(--fire-1) 40%, #C7701E) border-box; }
.hud-mission.is-done .mission-n { color: var(--fire-1); }
.hud-mission.pop { animation: hcBadge .5s ease-in-out 2; }
/* On a landscape phone 1rem is only ~1.08 CSS px, which left the small HUD
   labels at 9-10 px: floor them at 11 px there. Desktop and cabinet sizes
   (1rem = 1.5-3 CSS px) are already above the floor and do not change. */
@media (hover: none) and (pointer: coarse) {
  .hud-score-label, .hud-score-label .ar { font-size: max(8.5rem, 11px); }
  .hud-mission-text, .hud-mission .mission-n { font-size: max(9.5rem, 11px); }
  #hud .hc-chip .k { font-size: max(9rem, 11px); }
}

/* ===================================================================== MENU */
#menu { z-index: 10; flex-direction: row; justify-content: space-between; gap: 16rem; }
/* Scrim only where type sits on the render: the two side columns. The logo
   and the stat line ride over a bright daylight sky, and the middle third
   has to stay clear, because dimming the runner is the one thing this
   screen must not do. Symmetric, so it needs no RTL twin. */
#menu::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(90deg,
    rgba(6, 12, 16, .88) 0,
    rgba(8, 15, 20, .62) 20%,
    rgba(9, 18, 23, .16) 31%,
    rgba(9, 18, 23, 0) 37%,
    rgba(9, 18, 23, 0) 63%,
    rgba(9, 18, 23, .16) 69%,
    rgba(8, 15, 20, .62) 80%,
    rgba(6, 12, 16, .88) 100%);
}

/* The two side columns. ~200rem each leaves the middle ~210rem for the
   runner, which the menu camera stands dead centre (js/main.js MENU_CAM). */
.menu-col {
  width: 200rem; max-width: 36%; min-height: 0;
  display: flex; flex-direction: column; gap: 9rem;
}

/* The coin readout in the inline-end corner. Taken out of the column's flow
   (the column is the containing block) so the runner pick, PLAY and settings
   centre on the same line as the logo and stats opposite. */
.menu-end { position: relative; }
.menu-end .wallet { position: absolute; top: 0; inset-inline-end: 0; display: flex; }

.menu-logo {
  display: block;
  width: 100%;
  margin: 2rem auto 0;
  filter: drop-shadow(0 6rem 0 rgba(0, 0, 0, .55)) drop-shadow(0 0 24rem rgba(255, 160, 70, .32));
  animation: hcFloat 6s ease-in-out infinite;
}

/* Flexible space: centres each column's cluster in the height left over. */
.menu-gap { flex: 1; min-height: 0; }

#char-select {
  display: flex; align-items: center; gap: 8rem;
  padding: 6rem 7rem;
  background: var(--orn-sm), var(--paint), var(--teal-fill), var(--rim);
  border: 3rem solid transparent; border-radius: 10rem;
  box-shadow: var(--frame), 0 5rem 0 1.5rem var(--drop);
}
.char-arrow {
  width: 34rem; height: 34rem; font-size: 19rem;
  background: var(--paint), var(--teal-fill), var(--rim);   /* too small for scrolls */
  box-shadow: var(--frame), 0 4rem 0 1.5rem var(--drop);
}
/* 34rem is ~37 CSS px on a landscape phone: an apron takes it past 44. */
.char-arrow::after { content: ''; position: absolute; inset: -5rem; }
.char-arrow:active, .char-arrow.is-down {
  box-shadow: var(--frame), 0 1rem 0 1.5rem var(--drop);
}
#char-preview { flex: 1; text-align: center; min-width: 0; }
#char-name {
  font: 900 15rem/1.15 var(--ui); color: var(--cream);
  text-shadow: 0 2rem 0 var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
#char-sub {
  margin-top: 2rem;
  font: 400 8.5rem/1 var(--display); letter-spacing: .14em;
  color: rgba(226, 210, 178, .5);
}

/* PLAY is the menu's one shout: the full block, with the runner pick above
   it and settings, the quiet way out, under it. */
.menu-end #start-btn { margin-top: 4rem; }

/* Settings: a teal plaque one step down from PLAY, its mark and the two
   labels on one centred line. */
.nav-tile {
  min-height: 42rem;   /* 45 CSS px on a landscape phone */
  padding: 6rem 12rem;
  display: flex; align-items: center; justify-content: center; gap: 8rem;
  background: var(--paint), var(--teal-fill), var(--rim);
  border: 3rem solid transparent; border-radius: 9rem;
  box-shadow: var(--frame), 0 5rem 0 1.5rem var(--drop);
  transition: transform .06s, box-shadow .06s;
}
.nav-tile:active, .nav-tile.is-down {
  transform: translateY(4rem);
  box-shadow: var(--frame), 0 1rem 0 1.5rem var(--drop);
}
/* Narrower than the two full-width blocks above it, centred under PLAY. */
.menu-end .menu-settings { margin-top: 6rem; align-self: center; min-width: 64%; }
.nav-tile > span { font: 700 12rem/1 var(--ui); color: var(--cream); text-shadow: 0 1.5rem 0 var(--ink); white-space: nowrap; }
.nav-tile em {
  font: 600 8rem/1 var(--mono); font-style: normal;
  letter-spacing: .08em; color: rgba(226, 210, 178, .55);
}

/* Keyboard wording vs. swipe wording. The query matches IS_TOUCH in ui.js. */
.only-touch { display: none; }
@media (hover: none) and (pointer: coarse) {
  .only-key { display: none; }
  .only-touch { display: block; }
}

/* ---- arcade cabinet (?arcade, html.arcade) -------------------------------
   What the old wide-screen side panels said, now inside the stage: the
   stick and button map under the logo and stats, and a blinking PRESS START
   under settings. */
.arcade-ctrls, .arcade-start { display: none; }
html.arcade .menu-logo { width: 74%; }
html.arcade .arcade-ctrls {
  display: grid; grid-template-columns: 1fr 1fr; gap: 5rem 8rem;
  list-style: none;
  padding: 7rem 9rem;
  background: var(--orn-sm), var(--paint), var(--teal-fill), var(--rim);
  border: 3rem solid transparent; border-radius: 9rem;
  box-shadow: var(--frame), 0 4rem 0 1.5rem var(--drop);
}
.arcade-ctrls li { display: flex; align-items: center; gap: 5rem; min-width: 0; }
.arcade-ctrls li.wide { grid-column: 1 / -1; }
.arcade-ctrls i {
  flex: none; min-width: 30rem; padding: 3rem 4rem; text-align: center;
  font: 400 7.5rem/1 var(--display); font-style: normal; color: var(--ice-1);
  background: var(--slab-2); border: 1.5rem solid #8A4E26; border-bottom-width: 3rem;
  border-radius: 4rem; box-shadow: 0 0 0 1rem var(--ink);
}
.arcade-ctrls i.btn { color: var(--fire-ink); background: linear-gradient(#FFE07A, var(--fire-2)); border-color: #5A2A0C; }
.arcade-ctrls i.logo-mark { height: 16rem; background: url(../assets/logo_token.png) center / 90% no-repeat, var(--slab-2); }
.arcade-ctrls b { font: 700 9rem/1 var(--ar); color: var(--cream); white-space: nowrap; }
.arcade-ctrls span { font: 400 6.5rem/1 var(--display); letter-spacing: .06em; color: rgba(226, 210, 178, .55); white-space: nowrap; }
html.arcade .arcade-start {
  display: flex; flex-direction: column; align-items: center; gap: 3rem;
  align-self: center; width: fit-content;
  padding: 5rem 16rem;
  background: var(--paint), var(--teal-fill), var(--rim);
  border: 2.5rem solid transparent; border-radius: 14rem;
  box-shadow: var(--frame);
}
/* Two lines, not one: an Arabic run and a Latin run on one RTL line read
   back to front. Only the words blink, never the plaque. */
.arcade-start b, .arcade-start span { animation: hcBlink 1.2s steps(2, jump-none) infinite; }
.arcade-start b { font: 700 11rem/1 var(--ar); color: var(--fire-1); }
.arcade-start span { font: 400 8.5rem/1 var(--display); letter-spacing: .1em; color: var(--cream); }
@keyframes hcBlink { 50% { opacity: .25; } }

/* ============================================================ sheet screens */
.sheet {
  z-index: 12; gap: 10rem;
  background:
    radial-gradient(90% 70% at 50% 0%, rgba(52, 88, 102, .55), transparent 70%),
    linear-gradient(rgba(16, 32, 40, .97), rgba(9, 18, 23, .99) 40%),
    var(--night);
}
.sheet-head { display: flex; align-items: center; gap: 9rem; flex: none; }
/* 36rem is ~39 CSS px on a landscape phone: an apron takes it past 44. */
.back-btn { width: 36rem; height: 36rem; font-size: 20rem; }
.back-btn::after { content: ''; position: absolute; inset: -5rem; }
/* The glyph is U+2039, which the browser mirrors on its own inside an RTL run,
   so it points back in both directions with no CSS help. */
.sheet-title { flex: 1; min-width: 0; text-align: start; }
.sheet-title > div { font: 900 15rem/1.15 var(--ui); color: var(--cream); text-shadow: 0 2rem 0 var(--ink); }
.sheet-title em {
  /* its own line, clear of the Arabic title's descenders (the hamza under
     الإعدادات touched it), and inked */
  display: block; margin-top: 3rem;
  font: 400 8rem/1 var(--display); font-style: normal;
  letter-spacing: .12em; color: rgba(226, 210, 178, .62);
  text-shadow: 0 1.2rem 0 var(--ink), 0 0 5rem rgba(4, 8, 10, .85);
}

.sheet-body {
  flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  display: flex; flex-direction: column; gap: 8rem;
  padding-bottom: 6rem;
  touch-action: pan-y;
  scrollbar-width: none;
}
.sheet-body::-webkit-scrollbar { display: none; }
/* Landscape sheets: two columns side by side, scrolling together. With only
   ~280rem of height under the head, one long column wasted the width. */
.sheet-body.cols {
  display: grid; grid-template-columns: 1fr 1fr; align-items: start; gap: 0 18rem;
  padding: 2rem 2rem 6rem;   /* room for the 1.5rem ink line outside each rim */
}
.sheet-col { display: flex; flex-direction: column; gap: 8rem; min-width: 0; }

.sec-label {
  margin-top: 4rem;
  font: 700 9rem/1 var(--ui); letter-spacing: .1em; text-transform: uppercase;
  color: #E8B27A;
  text-shadow: 0 1.5rem 0 rgba(10, 6, 2, .8);
}
.sheet-col > .sec-label:first-child { margin-top: 2rem; }

/* =============================================================== settings */
.set-group { padding: 4rem 12rem; display: flex; flex-direction: column; }
.set-row {
  display: flex; align-items: center; gap: 10rem; flex-wrap: wrap;
  padding: 6rem 0;
  border-bottom: 2rem solid rgba(246, 200, 140, .08);
}
.set-row:last-child { border-bottom: none; }
.set-k { flex: 1; font: 700 11rem/1 var(--ui); color: var(--cream); }
.set-v { order: 2; font: 600 11rem/1 var(--mono); color: var(--fire-1); min-width: 26rem; text-align: end; }

/* Settings fits its two columns without scrolling at 640x360; nothing at
   the foot of either column casts a bottom face, so no scroll apron. */
#screen-settings .sheet-body { padding-bottom: 2rem; }
#set-reset { flex: none; padding-block: 10rem; }
/* rows holding a 41rem segmented control need little padding of their own */
.set-row:has(.seg) { padding-block: 2rem; }
/* Landscape: label, slider, value on one line. Height is the scarce axis,
   and a slider on its own line cost each row ~30rem. */
.set-row:has(.slider) { padding-block: 0; }
.set-row:has(.slider) .set-k { flex: none; min-width: 60rem; }
/* 41rem tall (44 CSS px on a landscape phone) for the finger; the track and
   thumb still draw at their own size in the middle. */
.slider {
  order: 1; flex: 1 1 100rem; height: 41rem; margin: 0;
  -webkit-appearance: none; appearance: none; background: transparent;
  touch-action: pan-x;
}
.slider::-webkit-slider-runnable-track {
  height: 12rem; border-radius: 7rem;
  background: var(--well); border: 2rem solid #9A5A2C;
  box-shadow: inset 0 2rem 0 rgba(0, 0, 0, .6);
}
.slider::-moz-range-track {
  height: 12rem; border-radius: 7rem;
  background: var(--well); border: 2rem solid var(--outline);
}
.slider::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 20rem; height: 20rem; margin-top: -6rem; border-radius: 5rem;
  background: linear-gradient(#FFE6A8, var(--fire-1) 40%, var(--fire-3));
  border: 2rem solid var(--ink);
  box-shadow: 0 2rem 0 #4A1F09;
}
.slider::-moz-range-thumb {
  width: 20rem; height: 20rem; border-radius: 5rem;
  background: linear-gradient(var(--fire-1), var(--fire-3));
  border: 2rem solid var(--fire-ink);
}

.toggle {
  position: relative;
  width: 48rem; height: 26rem; flex: none; padding: 2rem;
  background: var(--well); border: 2.5rem solid #9A5A2C; border-radius: 16rem;
  box-shadow: 0 0 0 1.2rem var(--ink), inset 0 2rem 0 rgba(0, 0, 0, .5);
  display: flex; align-items: center;
  transition: background .15s;
}
.toggle > i {
  display: block; width: 18rem; height: 18rem; border-radius: 5rem;
  background: linear-gradient(#F3C38C, #B06A35 60%, #7B3E1A);
  border: 1.5rem solid var(--ink);
  transition: transform .15s, background .15s;
}
/* the switch is 26rem tall: an apron takes its hit area past 44 px */
.toggle::after { content: ''; position: absolute; inset: -10rem -8rem; }
.toggle.is-on { background: linear-gradient(var(--ice-3), var(--ice-deep)); }
.toggle.is-on > i { background: linear-gradient(#FFF0C4, var(--fire-1) 50%, #C7701E); transform: translateX(20rem); }
:root[dir='rtl'] .toggle.is-on > i { transform: translateX(-20rem); }

.seg { display: flex; flex: none; border: 2.5rem solid #A9622F; border-radius: 8rem; overflow: hidden; box-shadow: 0 0 0 1.2rem var(--ink); }
.seg button { min-height: 41rem; min-width: 44rem; padding: 6rem 13rem; background: var(--slab-2); font: 700 10rem/1 var(--ui); color: rgba(226, 210, 178, .65); }
.seg button + button { border-inline-start: 1.5rem solid var(--ink); }
.seg button.is-on { background: var(--amber-fill); color: var(--fire-ink); }
/* A shade, not a translate: the segments sit flush inside overflow:hidden. */
.seg button:active, .seg button.is-down { filter: brightness(.8); }
/* Keyboard focus drawn inside the segment (the default ring is outside and
   overflow:hidden clips it), in cream so it shows on the amber selected
   segment too; inset from the edge so the rounded ends cannot eat it. */
.seg button:focus-visible { outline: 2rem solid var(--cream); outline-offset: -4rem; }
.set-note { padding: 3rem 0 3rem; font: 400 9rem/1.4 var(--ui); color: rgba(226, 210, 178, .4); }

.ctrl-row {
  display: flex; align-items: center; gap: 10rem;
  padding: 3rem 0; border-bottom: 2rem solid rgba(246, 200, 140, .08);
}
.ctrl-row:last-child { border-bottom: none; }
.ctrl-row b { font: 700 10.5rem/1 var(--ui); color: var(--cream); }
.key {
  min-width: 58rem; padding: 4rem 8rem; text-align: center;
  background: var(--slab-2); border: 2rem solid #8A4E26;
  border-bottom-width: 4rem; border-radius: 5rem;
  box-shadow: 0 0 0 1rem var(--ink);
  font: 600 9rem/1 var(--mono); color: var(--text);
}
.set-version { padding: 0 4rem; text-align: center; font: 600 8rem/1 var(--mono); color: rgba(226, 210, 178, .3); }

/* =================================================== LEADERBOARD + SIGN-IN */
/* js/board.js: the sign-in sheet (gate and rename), the menu plaque, the
   full board sheet, the game-over rank and the settings player row. Same
   painted plaque recipe as everything else; names are any script, so every
   name cell is one line with an ellipsis and overflow:hidden (a fallback font
   for Cyrillic or CJK must never grow a row). */

/* ---- the menu plaque (replaces the old stats line) ----------------------
   A button with a FIXED height: the column is centred by flexible gaps, so a
   plaque that grew with its content would make the column jump. Rows: head,
   five names, the player's own row, the lifetime distance. */
.menu-board {
  position: relative; flex: none;
  width: 184rem; height: 133rem; margin: 0 auto;
  display: grid; grid-template-columns: minmax(0, 1fr);
  grid-template-rows: 15rem 65rem 1fr 11rem;
  padding: 6rem 11rem 7rem;
  background: var(--paint), var(--teal-fill), var(--rim);
  border: 2.5rem solid transparent; border-radius: 12rem;
  box-shadow: var(--frame), 0 5rem 0 1.5rem var(--drop);
  text-align: start; color: var(--cream);
  transition: transform .06s, box-shadow .06s, filter .12s;
}
.menu-board:active, .menu-board.is-down {
  transform: translateY(3rem);
  box-shadow: var(--frame), 0 1rem 0 1.5rem var(--drop);
}
@media (hover: hover) { .menu-board:hover { filter: brightness(1.08); } }
.menu-board > * { grid-column: 1; min-width: 0; }
.lb-head { grid-row: 1; display: flex; align-items: baseline; gap: 5rem; white-space: nowrap; }
.lb-head .lb-t { font: 700 9rem/1 var(--ui); color: #E8B27A; text-shadow: 0 1.5rem 0 rgba(10, 6, 2, .8); }
.lb-head em { font: 400 7rem/1 var(--display); font-style: normal; letter-spacing: .1em; color: rgba(226, 210, 178, .5); }
/* a small cast-bronze pill: the plaque is the button, this says so */
.lb-all {
  margin-inline-start: auto; align-self: center;
  padding: 2rem 6rem 2.5rem; border-radius: 7rem;
  background: var(--paint), linear-gradient(#FBDDAE, #D99657 35%, #A75F2C) padding-box;
  box-shadow: 0 0 0 1rem var(--ink);
  font: 700 7.5rem/1 var(--ui); color: var(--fire-ink);
}
.lb-rows { grid-row: 2; display: grid; grid-template-rows: repeat(5, 13rem); }
.lb-rows.is-dim { opacity: .45; }
.lb-row { display: grid; grid-template-columns: 14rem minmax(0, 1fr) auto; align-items: center; gap: 6rem; }
.lb-rows .lb-row .r { text-align: center; font: 600 9rem/1 var(--mono); color: rgba(226, 210, 178, .55); }
.lb-row .n {
  min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
  font: 700 10rem/1.25 var(--ui); color: var(--cream);
}
/* The name truncates inside its own direction (the bdi), so a Latin name in
   the Arabic UI (or an Arabic one in English) loses its end, not its start;
   the column keeps the page's side. Not text-align: match-parent, which
   Chrome resolves against the dir=auto bdi itself. */
.lb-row .n > bdi { display: block; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; text-align: right; }
:root[dir='ltr'] .lb-row .n > bdi { text-align: left; }
.lb-row .s { font: 700 10rem/1 var(--mono); font-variant-numeric: tabular-nums; color: var(--cream); }
.lb-rows .lb-row.is-me .n, .lb-rows .lb-row.is-me .s, .lb-rows .lb-row.is-me .r { color: var(--fire-1); }
/* the offline / empty line sits over the rows (they keep their space) */
.lb-msg {
  grid-row: 2; align-self: center; text-align: center;
  font: 700 9.5rem/1.35 var(--ui); color: var(--cream);
}
.lb-msg.is-off { font-weight: 600; color: var(--text-mute); }
/* the player's own row: rank, YOU (or PLAY TO GET RANKED), best */
.lb-you {
  grid-row: 3; display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 6rem;
  margin-top: 3rem; border-top: 2rem solid rgba(246, 200, 140, .12);
  color: var(--fire-1);
}
.lb-you .r { font: 700 9.5rem/1 var(--mono); }
.lb-you .n { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: 800 10rem/1.25 var(--ui); }
.lb-you .s { font: 700 10.5rem/1 var(--mono); font-variant-numeric: tabular-nums; }
.lb-foot {
  grid-row: 4; align-self: center; text-align: center; white-space: nowrap; overflow: hidden;
  font: 600 8.5rem/1 var(--ui); color: rgba(226, 210, 178, .6);
}
.lb-foot b { font: 700 9rem/1 var(--mono); color: var(--cream); }
/* An arcade cabinet: the top five only, read-only (board.js drops data-goto). */
html.arcade .menu-board { height: auto; grid-template-rows: 15rem 65rem; pointer-events: none; }
html.arcade .lb-all, html.arcade .lb-you, html.arcade .lb-foot { display: none; }
/* landscape phone: 1rem is ~1.08 CSS px, so the 9-10rem labels get an 11 px floor */
@media (hover: none) and (pointer: coarse) {
  .lb-row .n, .lb-row .s, .lb-you .n, .lb-you .s, .lb-msg { font-size: max(10rem, 11px); }
  .lb-rows .lb-row .r, .lb-you .r { font-size: max(9rem, 10.5px); }
}

/* ---- the board sheet ------------------------------------------------------
   One centred list, 22rem a row; the player's row amber, the podium in
   medallions. The pinned row under it is the player when they rank outside
   the top 100 (or the "play to get ranked" line). */
#screen-leaderboard .sheet-body { position: relative; align-items: center; padding: 2rem 2rem 8rem; }
.lb-list { flex: none; width: min(100%, 470rem); padding: 4rem 10rem; list-style: none; }
.lb-big {
  height: 22rem; padding-inline: 6rem; border-radius: 4rem;
  grid-template-columns: 34rem minmax(0, 1fr) 64rem 72rem; gap: 8rem;
}
/* :not(.is-me): the stripe (0,3,0) would beat the own row's amber (0,2,0)
   and leave its ink text on the dark slab at every even rank */
.lb-list .lb-big:nth-child(even):not(.is-me) { background: rgba(255, 255, 255, .03); }
.lb-big .r { text-align: center; }
.lb-big .r i {
  display: inline-grid; place-items: center; min-width: 18rem; height: 18rem; padding: 0 3rem; border-radius: 9rem;
  font: 600 9.5rem/1 var(--mono); font-style: normal; color: var(--text-mute);
}
.lb-big.m1 .r i, .lb-big.m2 .r i, .lb-big.m3 .r i { font-weight: 700; color: var(--fire-ink); box-shadow: 0 0 0 1.2rem var(--ink), inset 0 1.5rem 0 rgba(255, 255, 255, .45); }
.lb-big.m1 .r i { background: #FFD27A; }
.lb-big.m2 .r i { background: #D9E4E8; }
.lb-big.m3 .r i { background: #C98446; }
.lb-big .n { font: 700 11.5rem/1.3 var(--ui); }
.lb-big .d { text-align: right; font: 600 9.5rem/1 var(--mono); color: var(--text-mute); white-space: nowrap; }
.lb-big .s { text-align: right; font: 700 11.5rem/1 var(--mono); color: var(--fire-1); }
.lb-big.is-me { background: var(--amber-fill); box-shadow: 0 0 0 1.2rem var(--ink); }
.lb-big.is-me .n, .lb-big.is-me .d, .lb-big.is-me .s, .lb-big.is-me .r i { color: var(--fire-ink); }
#lb-pin {
  flex: none; width: min(100%, 470rem); height: 28rem; margin: 0 auto;
  padding-inline: 14rem;
  background: var(--paint), var(--amber-fill), var(--rim);
  border: 2.5rem solid transparent; border-radius: 8rem;
  box-shadow: var(--frame), 0 4rem 0 1.5rem var(--drop);
  /* the rank column grows for "#12,345" (past 10,000 players) instead of
     spilling into the name; the 34rem floor keeps it lined up with the list */
  grid-template-columns: minmax(34rem, max-content) minmax(0, 1fr) 64rem 72rem;
}
/* Unranked: "PLAY TO GET RANKED" is a hint, not a control (the pin has no
   handler), so it drops the raised amber button look for the menu plaque's
   flat fire text. The cells are recoloured directly: .is-me sets them to ink. */
#lb-pin.is-cta { background: none; border-color: transparent; box-shadow: none; }
#lb-pin.is-cta .n, #lb-pin.is-cta .r i { color: var(--fire-1); font-weight: 800; }
.lb-state { padding: 40rem 0; text-align: center; font: 600 11rem/1.4 var(--ui); color: var(--text-mute); }
#lb-me-chip { font-size: 11rem; }
#lb-me-chip[lang="ar"] { font: 700 11rem/1 var(--ar); }

/* ---- the sign-in sheet ----------------------------------------------------
   Over the loading screen at first launch (z 21 > 20), opaque, so the city
   idles behind it. Everything a finger must touch ends by ~125rem down: a
   landscape phone's keyboard leaves about the top 130-175rem of the stage
   visible (board.js freezes the stage while a field has focus). */
#screen-signin { z-index: 21; gap: 8rem; }
.signin[data-mode="gate"] .back-btn { display: none; }
/* the sub-title is dir=auto (its "?" must end the line in either script), so
   its side follows the page, not its own direction */
#signin-title-sub { text-align: right; }
:root[dir='ltr'] #signin-title-sub { text-align: left; }
/* an empty dir=auto input resolves LTR, which put the Arabic placeholder and
   the caret on the left; until something is typed it follows the page */
:root[dir='rtl'] #signin-name:placeholder-shown { direction: rtl; }
.signin .sheet-head { min-height: 36rem; }
/* 36rem with the seg's rim: the head stays 36rem tall (y 14-50) */
.signin .seg button { min-height: 31rem; padding: 4rem 12rem; }
.signin-form { display: flex; flex-direction: column; }
.signin-row { display: grid; grid-template-columns: 1fr 1.3fr auto; gap: 9rem; align-items: end; }
.signin[data-mode="rename"] .signin-row { grid-template-columns: minmax(0, 300rem) auto; justify-content: center; }
.signin[data-mode="rename"] #signin-email-f { display: none; }
.field { display: flex; flex-direction: column; gap: 2rem; min-width: 0; }
.field-k {
  font: 700 8.5rem/1 var(--ui); color: #E8B27A;
  text-shadow: 0 1.5rem 0 rgba(10, 6, 2, .8);
}
/* The wells of the settings controls, at finger height (41rem is 44 CSS px
   on a landscape phone). 16 px text at least: iOS zooms into anything less. */
.field input {
  width: 100%; height: 41rem; padding: 0 10rem;
  background: var(--well); border: 2.5rem solid #9A5A2C; border-radius: 8rem;
  box-shadow: 0 0 0 1.2rem var(--ink), inset 0 2rem 0 rgba(0, 0, 0, .5);
  color: var(--cream); font: 700 max(13rem, 16px)/1 var(--ui);
  -webkit-user-select: text; user-select: text; touch-action: manipulation;
  outline: none; transition: border-color .12s;
}
.field input:focus { border-color: var(--fire-1); }
.field input.is-bad, .field input[aria-invalid="true"] { border-color: var(--danger); }
/* the placeholder may be smaller than the 16 px text (only the text size
   decides iOS zoom): the long name hint fits the phone's narrower field */
.field input { text-overflow: ellipsis; }
.field input::placeholder { color: rgba(226, 210, 178, .4); font-weight: 600; font-size: 11.5rem; }
/* the browser's autofill paint would be a pale yellow box in a dark well */
.field input:-webkit-autofill, .field input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--cream);
  box-shadow: 0 0 0 1.2rem var(--ink), inset 0 0 0 100rem var(--well);
  caret-color: var(--cream);
}
#signin-go { flex: none; min-width: 128rem; padding: 4rem 18rem; justify-content: center; }
.signin-err {
  height: 12rem; margin-top: 3rem; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
  font: 700 10rem/1.2 var(--ui); color: var(--danger);
}
.signin-note {
  margin-top: 4rem; text-align: center;
  font: 400 10.5rem/1.5 var(--ui); color: rgba(240, 228, 204, .6);
}
.signin-logo {
  align-self: center; width: 210rem; margin-top: 12rem;
  filter: drop-shadow(0 6rem 0 rgba(0, 0, 0, .55)) drop-shadow(0 0 24rem rgba(255, 160, 70, .32));
  animation: hcFloat 6s ease-in-out infinite;
  pointer-events: none;
}
.signin-load {
  margin-top: auto; margin-bottom: 16rem; text-align: center;
  font: 600 9rem/1 var(--ui); color: var(--text-mute);
}
.signin-load b { font: 700 9rem/1 var(--mono); }

/* ---- settings: who is playing (in the head) ------------------------------ */
.set-player { display: flex; align-items: center; gap: 7rem; min-width: 0; flex: none; }
.set-player-k { font: 700 9rem/1 var(--ui); color: #E8B27A; text-shadow: 0 1.5rem 0 rgba(10, 6, 2, .8); }
.set-player-n {
  display: block; max-width: 110rem; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
  font: 700 11rem/1.3 var(--ui); color: var(--cream); text-shadow: 0 1.5rem 0 var(--ink);
}
/* 36rem tall with the seg's rim, like the back button: a taller head pushed
   the two columns below into a scroll */
.set-player-acts button { min-height: 31rem; min-width: 0; padding: 4rem 9rem; font-size: 9.5rem; white-space: nowrap; }
/* Those 31rem buttons (here and in the sign-in head) are 34 CSS px on the
   phone; a vertical apron takes the finger target to ~44 px without growing
   either head. Only these two segs overflow, so their outer buttons take
   the rim's rounding (8rem - 2.5rem) themselves. */
.signin .seg, .set-player-acts { overflow: visible; }
.signin .seg button, .set-player-acts button { position: relative; }
.signin .seg button::after, .set-player-acts button::after { content: ''; position: absolute; inset: -5rem 0; }
.signin .seg button:first-child, .set-player-acts button:first-child { border-start-start-radius: 5.5rem; border-end-start-radius: 5.5rem; }
.signin .seg button:last-child, .set-player-acts button:last-child { border-start-end-radius: 5.5rem; border-end-end-radius: 5.5rem; }

/* ---- game over: "GLOBAL #12 OF 340" on the distance line ----------------- */
.go-rank { white-space: nowrap; color: var(--fire-1); }
.go-rank b { font: 700 11rem var(--mono); }
.go-rank.is-dim { opacity: .55; }
.go-rank.is-best #go-rank-t::before { content: '★ '; }

/* ============================================================ dialogs / popups */
.overlay-dim { justify-content: center; align-items: center; background: rgba(5, 11, 14, .72); z-index: 16; }

.hc-dialog {
  position: relative;
  padding: 22rem 14rem 14rem;
  background: var(--orn), var(--paint),
    radial-gradient(120% 80% at 50% 18%, #3A6271, #24414E 55%, #142731) padding-box, var(--rim);
  border: 3.5rem solid transparent;
  border-radius: 12rem;
  box-shadow: var(--frame), 0 8rem 0 1.5rem var(--drop),
              0 0 40rem rgba(255, 150, 60, .16);
  animation: hcPop .28s cubic-bezier(.2, 1.5, .4, 1);
  /* centred and capped: a full-width dialog on a 640rem stage stretched
     every button into a bar */
  width: min(100%, 340rem);
}
/* Game over: the run's numbers at the inline start, the way out (run
   again, back) in a column at the inline end. Side by side it is
   ~175rem tall, where stacked it would not fit the 332rem of height.
   Hung high, just under the score plaque, with the dim easing off below it:
   the runner lies at ~75-85% of the frame height and the death camera's
   push-in onto him stays in view under the dialog. */
#gameover {
  justify-content: flex-start;
  background: linear-gradient(rgba(5, 11, 14, .76) 0, rgba(5, 11, 14, .7) 58%, rgba(5, 11, 14, .3) 74%, rgba(5, 11, 14, .2));
}
.hc-dialog.go {
  margin-top: 66rem;
  width: min(100%, 492rem);
  display: grid; grid-template-columns: 1fr 196rem; align-items: center; gap: 0 16rem;
  padding: 22rem 16rem 14rem;
}
.hc-dialog.go .dialog-tip { margin-top: 8rem; min-height: 0; }
.hc-dialog.go .dialog-row { margin-top: 8rem; }
.hc-dialog.go .dialog-hint { margin-top: 8rem; }
.go-main { min-width: 0; }
.go-actions > .dialog-row:first-child { margin-top: 0; }
.dialog-tab {
  position: absolute; top: -13rem; left: 50%; transform: translateX(-50%);
  padding: 5rem 18rem; white-space: nowrap;
  /* a cast-bronze name plate riveted over the top rim */
  background: var(--paint), linear-gradient(#FBDDAE, #D99657 30%, #A75F2C 70%, #6E3616) padding-box,
              linear-gradient(#5A2C10, #2A1206) border-box;
  border: 2rem solid transparent; border-radius: 7rem;
  box-shadow: 0 0 0 1.5rem var(--ink), inset 0 2rem 0 rgba(255, 245, 220, .45), 0 3rem 0 1.5rem var(--drop);
  font: 400 12rem/1 var(--display); color: #2A1206; letter-spacing: .06em;
  text-shadow: 0 1.2rem 0 rgba(255, 236, 200, .5);
}
.dialog-tab.ice {
  background: var(--paint), var(--teal-fill), var(--rim);
  color: var(--cream); text-shadow: 0 1.5rem 0 var(--ink);
}
.dialog-tab.danger {
  background: var(--paint), linear-gradient(#E0623A, #A8301A) padding-box, var(--rim);
  color: #FFE9CC; text-shadow: 0 1.5rem 0 var(--ink);
}
.dialog-title { text-align: center; font: 900 20rem/1.2 var(--ui); color: var(--cream); text-shadow: 0 2rem 0 var(--ink); }
.dialog-sub { margin-top: 6rem; text-align: center; font: 400 11rem/1.6 var(--ui); color: rgba(240, 228, 204, .6); }
.dialog-row { margin-top: 11rem; display: flex; gap: 9rem; flex-wrap: wrap; }
.dialog-tip { margin-top: 11rem; min-height: 30rem; text-align: center; font: 700 10.5rem/1.5 var(--ui); color: var(--fire-1); }
.dialog-hint { margin-top: 10rem; text-align: center; font: 400 9.5rem/1 var(--ui); color: rgba(226, 210, 178, .7); }
.dialog-hint b { color: var(--text-ice); }

.stat-row { display: flex; gap: 9rem; }
.stat {
  flex: 1; padding: 9rem 4rem; text-align: center;
  background: var(--paint), linear-gradient(#142630, #0E1C24) padding-box, linear-gradient(#C27C45, #6A3416) border-box;
  border: 2rem solid transparent; border-radius: 7rem;
  box-shadow: 0 0 0 1.2rem var(--ink), inset 0 2rem 0 rgba(0, 0, 0, .35);
}
.stat span { display: block; font: 600 9rem/1 var(--ui); color: var(--text-mute); }
.stat b {
  display: block; margin-top: 4rem;
  font: 400 16rem/1 var(--display); font-variant-numeric: tabular-nums; color: var(--cream);
  text-shadow: 0 2rem 0 var(--ink);
}
.stat b.fire { color: var(--fire-1); }
.stat b.ice  { color: #A6ECEF; }
/* The game-over boxes pop in one after another while ui.countUp() runs. */
.stat-row .stat { animation: hcPop .3s both; }
.stat-row .stat:nth-child(2) { animation-delay: .08s; }
.stat-row .stat:nth-child(3) { animation-delay: .16s; }
.go-dist { margin: 6rem 0 0; text-align: center; font: 600 10rem/1.3 var(--ui); color: var(--text-ice); }
.go-dist b { font: 700 11rem var(--mono); }

#new-best {
  margin: 0 auto 9rem; width: fit-content; padding: 5rem 14rem;
  background: var(--paint), radial-gradient(140% 120% at 30% 20%, #5A3220, #3A1E14 50%, #22121A) padding-box, linear-gradient(#FFF0C4, var(--fire-1) 35%, #C7701E 70%, #7A3A10) border-box;
  border: 3rem solid transparent; border-radius: 8rem;
  box-shadow: var(--frame), 0 0 26rem rgba(255, 150, 50, .4);
  font: 900 11rem/1 var(--ui); color: #FFE3C0;
  animation: hcBadge 1.1s ease-in-out infinite;
}

/* ================================================================== toast */
/* Top centre: on the menu that is the free sky between the two columns, on
   a sheet the space beside its title. Lower down it would sit on the runner. */
.toast {
  position: absolute; z-index: 24;
  left: 50%; top: calc(16rem + env(safe-area-inset-top, 0px));
  transform: translateX(-50%);
  max-width: 300rem;
  padding: 9rem 16rem;
  background: var(--paint), var(--teal-fill), linear-gradient(#FFF0C4, var(--fire-1) 35%, #C7701E 70%, #7A3A10) border-box;
  border: 3rem solid transparent; border-radius: 24rem;
  box-shadow: var(--frame), 0 4rem 0 1.5rem var(--drop);
  font: 900 11rem/1.3 var(--ui); color: var(--cream);
  text-shadow: 0 1.5rem 0 var(--ink);
  text-align: center;
  animation: hcToast 2.2s ease-out forwards;
  pointer-events: none;
}
.toast.bad { background: var(--paint), var(--teal-fill), linear-gradient(#FFC2A8, var(--danger) 40%, #8A2A16) border-box; }
/* In a run the top centre is the score and the combo, so a milestone toast
   drops in under the coin and best chips in the inline-end corner instead. */
#hud:not(.hidden) ~ .toast {
  left: auto; inset-inline-end: 14rem;
  top: calc(90rem + env(safe-area-inset-top, 0px));
  max-width: 190rem;
  transform: none;
  animation-name: hcToastSide;
}
/* Over the game-over panel the side slot lands on RUN AGAIN: a mission
   completed by that run drops in at the top centre instead, above the panel
   (it hangs from 66rem; the score plaque behind it is repeated in the panel). */
#gameover:not(.hidden) ~ .toast {
  right: auto; left: 50%;   /* physical: the side rule's inset-inline-end is left in RTL */
  top: calc(8rem + env(safe-area-inset-top, 0px));
  max-width: 300rem;
  transform: translateX(-50%);
  animation-name: hcToast;
}

/* ================================================================== LOADING */
.loading-screen {
  z-index: 20; align-items: center;
  padding: calc(18rem + env(safe-area-inset-top, 0px)) 24rem
           calc(18rem + env(safe-area-inset-bottom, 0px));
  background:
    linear-gradient(#1E4250, #08121A 60%),
    radial-gradient(80% 40% at 50% 74%, rgba(255, 130, 50, .3), transparent 70%),
    #08121A;
}
/* Flat city skyline cut out of a striped block — same trick as the mockup. */
.city-silhouette {
  position: absolute; left: 0; right: 0; bottom: 0; height: 150rem;
  background: repeating-linear-gradient(90deg, #1C3440 0 40rem, #142731 40rem 80rem);
  border-top: 3rem solid var(--outline);
  clip-path: polygon(0 46%, 10% 46%, 10% 18%, 22% 18%, 22% 60%, 34% 60%, 34% 26%,
                     46% 26%, 46% 52%, 58% 52%, 58% 12%, 72% 12%, 72% 40%,
                     86% 40%, 86% 22%, 100% 22%, 100% 100%, 0 100%);
}
.loading-screen > :not(.city-silhouette) { position: relative; }

.load-logo {
  margin-top: 14rem; width: 236rem; max-width: 100%;
  filter: drop-shadow(0 0 34rem rgba(255, 106, 24, .45));
  animation: hcFloat 5.5s ease-in-out infinite;
}
.load-spin { margin-top: 12rem; display: flex; align-items: center; gap: 9rem; }
.load-spin i {
  width: 14rem; height: 14rem;
  background: linear-gradient(var(--ice-1), var(--ice-3));
  border: 2rem solid var(--ice-ink);
  animation: hcSpin 1.6s linear infinite;
}
.load-spin span { font: 400 11rem/1 var(--display); letter-spacing: .14em; color: rgba(226, 210, 178, .7); }

/* Capped and centred: a 612rem-wide tip line was too long to read. */
.load-bottom { margin-top: auto; width: min(100%, 460rem); display: flex; flex-direction: column; gap: 10rem; }
.tip-slab { padding: 9rem 14rem; background: var(--orn-sm), var(--paint), var(--teal-fill), var(--rim); }
.tip-k { font: 400 9rem/1 var(--display); letter-spacing: .12em; color: var(--fire-1); margin-bottom: 5rem; }
.tip-v { font: 400 10.5rem/1.55 var(--ui); color: rgba(240, 228, 204, .74); }

.bar-head {
  display: flex; justify-content: space-between; gap: 10rem; margin-bottom: 6rem;
  font: 600 10rem/1.3 var(--mono); color: var(--text-mute);
}
.bar-head .status { font-family: var(--ui); font-weight: 600; text-align: start; }
.bar {
  height: 22rem; padding: 3rem;
  background: var(--well); border: 3rem solid #A9622F; border-radius: 12rem;
  box-shadow: 0 0 0 1.5rem var(--ink), inset 0 3rem 0 rgba(0, 0, 0, .6);
}
.bar-fill {
  width: 0%; height: 100%; border-radius: 8rem;
  background-color: var(--fire-2);
  background-image:
    repeating-linear-gradient(115deg, rgba(255, 255, 255, .28) 0 6rem, transparent 6rem 14rem),
    linear-gradient(var(--fire-1), var(--fire-3));
  background-size: 28rem 100%, 100% 100%;
  box-shadow: 0 0 16rem rgba(255, 138, 15, .75);
  animation: hcBar .7s linear infinite;
  transition: width .3s ease-out;
}

/* ============================================================ failure panels */
.fail-screen { justify-content: center; align-items: center; background: rgba(5, 11, 14, .95); z-index: 30; }
.fail-screen .hc-dialog { width: min(100%, 480rem); }
.boot-msg {
  max-width: 100%; margin: 12rem 0; padding: 12rem;
  text-align: left; direction: ltr;
  white-space: pre-wrap; word-break: break-word;
  font: 11rem/1.6 var(--mono); color: rgba(240, 228, 204, .78);
  background: #0A0F1E; border: 2rem solid var(--outline); border-radius: 6rem;
  max-height: 170rem; overflow: auto;
}

/* ======================================================= Arabic sub-lines */
/* applyLang (i18n.js) tags every filled element with the language it holds.
   In English mode the Arabic sub-lines sit in Latin slots (mono or Bungee,
   tracked out, sometimes uppercased), and tracking alone pulls the joins of
   Arabic letters apart. Attribute selectors, not :lang(): <html lang=ar> would
   make :lang(ar) match every element and strip the English tracking too.
   Sizes are explicit rem because the parents set none for em to scale from. */
[lang="ar"]:not(html) { letter-spacing: 0 !important; text-transform: none !important; }
.hc-btn small[lang="ar"]   { font: 700 10rem/1.1 var(--ar); }
.nav-tile em[lang="ar"]    { font: 700 8rem/1.1 var(--ar); }
.hc-play .en[lang="ar"]    { font: 700 14rem/1.1 var(--ar); }
.sheet-title em[lang="ar"], #char-sub[lang="ar"] { font: 700 10rem/1.1 var(--ar); }
.lb-head em[lang="ar"]     { font: 700 7.5rem/1 var(--ar); }
.dialog-tab[lang="ar"], .load-spin span[lang="ar"], .tip-k span[lang="ar"],
.hud-score-label span[lang="ar"]:not(.ar) { font-family: var(--ar); font-weight: 700; }

/* ===================================================== screen-enter motion */
/* Every screen is shown by dropping .hidden (display:none), which restarts
   these, so each entry plays with no JS. */
@keyframes hcDrop { from { transform: translateY(-40rem); opacity: 0; } }
@keyframes hcRise { from { transform: translateY(40rem); opacity: 0; } }
@keyframes hcFade { from { opacity: 0; } }
#hud .hud-top { animation: hcDrop .32s cubic-bezier(.2, 1.4, .4, 1) both; }
#hud .hud-mission { animation: hcRise .32s .08s cubic-bezier(.2, 1.4, .4, 1) both; }
#menu .menu-start { animation: hcDrop .3s ease-out both; }
#menu .menu-end { animation: hcRise .3s cubic-bezier(.2, 1.3, .4, 1) both; }
.sheet { animation: hcFade .16s ease-out both; }
.sheet .sheet-head { animation: hcDrop .26s ease-out both; }
.overlay-dim { animation: hcFade .18s ease-out both; }
/* The goal-reached pop (ui.setMission) has to beat the entry rise above,
   which outranks the plain .hud-mission.pop rule in the HUD section. */
#hud .hud-mission.pop { animation: hcBadge .5s ease-in-out 2; }

/* --------------------------------------------------------------- reduced motion */
@media (prefers-reduced-motion: reduce) {
  .menu-logo, .load-logo, .signin-logo, .load-spin i, .hc-play .shine, .bar-fill,
  #new-best, .hc-dialog, .combo,
  .near-pop, .hc-chip.beat, .world-name.show, .hud-mission.pop, .combo-pips,
  #hud .hud-top, #hud .hud-mission, #menu .menu-start, #menu .menu-end,
  .sheet, .sheet .sheet-head, .overlay-dim, .countdown, .stat, #run-hint,
  .arcade-start b, .arcade-start span {
    animation: none !important;
  }
  .world-name.show { opacity: 1; }
}

/* arcade kiosk (?arcade): no pointer on screen */
html.arcade, html.arcade * { cursor: none !important; }
