/* Mono Air — phone build.
   The tokens mirror src/theme.ts so the site and the seat-back tablet read as
   one product: same palette, same glass pills, same corner radii. */

:root {
  --bg: #000000;
  --panel: #101012;
  --panel-alt: #141418;
  --text: #ffffff;
  --dim: rgba(255, 255, 255, 0.68);
  --faint: rgba(255, 255, 255, 0.5);
  --border: rgba(255, 255, 255, 0.1);
  --chip-bg: rgba(255, 255, 255, 0.08);
  --chip-text: rgba(255, 255, 255, 0.7);
  --chip-active-bg: #ffffff;
  --chip-active-text: #000000;
  --ok: #6fdc8c;
  --accent: #8aa4ff;
  --glass: rgba(16, 20, 26, 0.55);
  --glass-border: rgba(255, 255, 255, 0.12);
  --pill-ink: rgba(255, 255, 255, 0.78);
  /* The hero copy is always white, so its wash stays dark in both themes —
     the tablet's dashboard does the same. */
  --hero-fade: #000000;
  --nav-bg: rgba(8, 9, 12, 0.9);
  --tile: rgba(125, 155, 255, 0.12);

  --radius-card: 18px;
  --radius-panel: 22px;
  --pad: 18px;
  /* In landscape the notch eats one side, so the content margin has to clear
     it — the artwork still bleeds edge to edge behind it. */
  --pad-l: max(var(--pad), env(safe-area-inset-left, 0px));
  --pad-r: max(var(--pad), env(safe-area-inset-right, 0px));
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  /* The page is phone-shaped; on a laptop it stays a centred column. */
  --column: 760px;

  color-scheme: dark;
}

[data-theme='light'] {
  --bg: #f2f2f5;
  --panel: #ffffff;
  --panel-alt: #e9e9ee;
  --text: #1a1a20;
  --dim: rgba(0, 0, 0, 0.65);
  --faint: rgba(0, 0, 0, 0.48);
  --border: rgba(0, 0, 0, 0.08);
  --chip-bg: rgba(0, 0, 0, 0.06);
  --chip-text: rgba(0, 0, 0, 0.6);
  --chip-active-bg: #1a1a20;
  --chip-active-text: #ffffff;
  --ok: #188a4b;
  --accent: #1a3ec6;
  --nav-bg: rgba(255, 255, 255, 0.92);
  --tile: rgba(26, 62, 198, 0.06);
  /* The switches float over dark key art on the home screen but over paper on
     the inner ones, so in this theme the glass turns light and its ink dark. */
  --glass: rgba(255, 255, 255, 0.68);
  --glass-border: rgba(0, 0, 0, 0.12);
  --pill-ink: rgba(0, 0, 0, 0.7);
  --hero-fade: #0a0b18;
  color-scheme: light;
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* A class that sets `display` outbids the UA rule behind the hidden attribute,
   which is how the player's error card ended up painted over a running game.
   One global rule keeps every hidden element hidden. */
[hidden] { display: none !important; }

html, body {
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  overscroll-behavior-y: none;
}

/* the floating circles hover over the page, so the last row needs room */
/* was + 86px while the bottom dock existed; now only the safe area */
body { min-height: 100dvh; padding-bottom: calc(var(--safe-bottom) + 28px); }
/* the install bar floats over the page, so the last row needs room under it */
body.has-install { padding-bottom: calc(var(--safe-bottom) + 96px); }
/* set while a game or the airline card is up */
body.locked { overflow: hidden; }

img { display: block; max-width: 100%; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
h1, h2, h3 { font-weight: 800; letter-spacing: -0.4px; }

/* ── boot splash ──────────────────────────────────────────────────────────
   The mono wordmark draws itself with a stroke, fills, and the whole sheet
   lifts away. Lifted from mono-games so arriving here feels like arriving
   there. It covers the page until app.js retires it, which also hides the
   catalogue's first paint. */
/* Two beats in one place: mono draws itself, holds, then dissolves upward as
   the partner's mark rises into the same spot. Both live in the centre of a
   grid cell, so neither shifts the other. */
.splash {
  position: fixed;
  inset: 0;
  z-index: 999;
  display: grid;
  place-items: center;
  /* Flat black, not var(--bg): the same colour the inline rule in index.html
     paints before this file arrives, so the two never disagree mid-load. */
  background: #000;
  transition: opacity 0.46s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.46s cubic-bezier(0.22, 1, 0.36, 1);
}
.splash > * { grid-area: 1 / 1; }
.splash-mark {
  width: min(56vw, 220px);
  height: auto;
  overflow: visible;
  animation: splash-mono-out 0.5s cubic-bezier(0.65, 0, 0.35, 1) 1.75s forwards;
}
/* Held at zero until app.js adds .in — the animation used to fire on a timer,
   which could land before the logo had loaded and showed as a flicker. */
.splash-partner {
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transform: translateY(14px) scale(0.96);
}
.splash-partner.in {
  animation: splash-partner-in 0.62s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}
.splash-partner img { height: 44px; width: auto; }
.splash-partner b {
  font-size: 34px;
  font-weight: 800;
  letter-spacing: 4px;
  opacity: 0.95;
}
@keyframes splash-mono-out {
  to { opacity: 0; transform: translateY(-14px) scale(0.97) }
}
@keyframes splash-partner-in {
  to { opacity: 1; transform: translateY(0) scale(1) }
}
@media (prefers-reduced-motion: reduce) {
  .splash-mark { animation-delay: 1.2s }
  .splash-partner.in { animation-duration: 0.3s; animation-timing-function: linear }
}
/* The sheet and its marks leave together: the partner's mark keeps the pose
   its entrance ended on (animation-fill-mode: forwards), so cancelling the
   animation here would snap it back — it simply rides the sheet out. */
.splash.leaving { opacity: 0; transform: scale(1.06); pointer-events: none; }
.splash.leaving .splash-mark { animation-play-state: paused; }
.splash .stroke {
  fill: var(--text);
  fill-opacity: 0;
  stroke: var(--text);
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: splash-draw 0.95s cubic-bezier(0.65, 0, 0.35, 1) forwards,
    splash-fill 0.45s ease-out forwards;
}
/* Left-to-right cadence: the m leads, the ono follows a beat later. */
.splash .stroke-m { animation-delay: 0.05s, 1s; }
.splash .stroke-ono { animation-delay: 0.28s, 1.15s; }
@keyframes splash-draw { to { stroke-dashoffset: 0 } }
@keyframes splash-fill {
  to { fill-opacity: 1; stroke-opacity: 0 }
}
@media (prefers-reduced-motion: reduce) {
  .splash .stroke { animation: none; stroke: none; fill-opacity: 1 }
}

/* ── top chrome ───────────────────────────────────────────────────────────
   Pinned to the top: the brand and the language switch stay reachable however
   far down the catalogue you are. Over the hero it is only a soft wash, and it
   turns into frosted glass once the artwork has scrolled past (.solid, set
   from app.js). */
.topbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: calc(var(--safe-top) + 10px) var(--pad-r) 10px var(--pad-l);
}
/* A soft wash behind the bar so the logo and the pills keep their contrast over
   a bright hero — a shadow on the chrome itself would ring around the letters,
   so the gradient sits behind everything instead and fades into the artwork. */
.topbar::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.55) 0%,
    rgba(0, 0, 0, 0.34) 45%,
    rgba(0, 0, 0, 0) 100%
  );
  transition: opacity 0.25s ease;
}
/* Past the hero the page behind the bar is plain black, where a fading gradient
   reads as a smudge — so it hands over to a flat pane of frosted glass. */
.topbar::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0;
  background: rgba(8, 9, 12, 0.62);
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
  backdrop-filter: blur(18px) saturate(1.2);
  -webkit-backdrop-filter: blur(18px) saturate(1.2);
  transition: opacity 0.25s ease;
}
.topbar.solid::before { opacity: 0; }
.topbar.solid::after { opacity: 1; }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .topbar::after { background: rgba(8, 9, 12, 0.94); }
}
.topbar-row { display: flex; align-items: center; gap: 8px; width: 100%; }
/* MONO and the airline's own lockup, in white, with the hairline between them
   that keeps the pair reading as one line. Both are sized by height and left to
   find their own width — the airline mark is far wider than it is tall, so it
   runs a little taller to match MONO's optical weight. */
.topbar .brand { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
/* The airline mark hangs its bird below the wordmark, so centring the two boxes
   leaves MONO sitting low against CENTRUM's type. Both are nudged against the
   rule instead, which stands on its own so its height answers to neither. */
.topbar .brand .mono { height: 20px; width: auto; transform: translateY(-2px); }
.topbar .brand .rule {
  flex: 0 0 auto;
  width: 1px;
  height: 22px;
  background: currentColor;
  opacity: 0.45;
}
.topbar .brand .airline {
  height: 18px;
  width: auto;
  transform: translateY(-1px);
  opacity: 0.95;
}
/* The house version has no airline mark — just a word set to match MONO. */
.topbar .brand .wordmark {
  font-size: 16px;
  font-weight: 800;
  letter-spacing: 1.6px;
  line-height: 20px;
  opacity: 0.92;
}
#brandMark { display: flex; align-items: center; }
.topbar .spacer { flex: 1; }

/* Nothing to show yet — say so with something to look at, not two sentences
   running into each other. */
.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 8px;
  margin: 34px auto;
  max-width: 320px;
  color: var(--faint);
  font-size: 14px;
  line-height: 20px;
}
.empty b { font-size: 17px; color: var(--text); }
.radar {
  position: relative;
  width: 96px;
  height: 96px;
  margin-bottom: 6px;
  display: block;
}
.radar::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 12px;
  height: 12px;
  margin: -6px 0 0 -6px;
  border-radius: 50%;
  background: var(--ok);
  box-shadow: 0 0 14px var(--ok);
}
.radar i {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 1.5px solid var(--ok);
  animation: radar 2.6s ease-out infinite;
}
.radar i:nth-child(2) { animation-delay: 0.85s; }
.radar i:nth-child(3) { animation-delay: 1.7s; }
@keyframes radar {
  0% { transform: scale(0.2); opacity: 0 }
  20% { opacity: 0.65 }
  100% { transform: scale(1); opacity: 0 }
}

/* Inner screens start below the header, which floats over the page. */
.screen-head { padding: calc(var(--safe-top) + 78px) var(--pad-r) 0 var(--pad-l); }
.screen-head h1 { font-size: 26px; letter-spacing: -0.7px; }
.screen-head p { margin-top: 6px; font-size: 14px; line-height: 20px; color: var(--dim); }
.screen-body { padding: 14px var(--pad-r) 0 var(--pad-l); }

/* The glass language switch in the header. Slim on purpose: it shares the bar
   with the lockup and should read as a quiet control, not a second brand. */
.pill {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 2px;
  border-radius: 999px;
  background: var(--glass);
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}
.pill button {
  height: 26px;
  min-width: 30px;
  padding: 0 9px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.3px;
  color: var(--pill-ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
}
/* Emoji flags render in colour whatever the text colour is, and they sit a
   hair high in most faces — nudged back onto the baseline of the code. */
.pill .flag {
  font-size: 12.5px;
  font-style: normal;
  line-height: 1;
  transform: translateY(0.5px);
}
.pill button[aria-pressed='true'] { background: #efeff2; color: #1a1a20; }
[data-theme='light'] .pill button[aria-pressed='true'] { background: #1a1a20; color: #fff; }
/* Closed, only the language in use shows; the other two are folded away to
   zero width and unroll on a tap. Collapsing rather than hiding keeps the
   animation on width alone, which the compositor can carry. */
/* Closed, the gap between the pills would still be drawn around buttons that
   have collapsed to nothing, leaving a lopsided sliver of glass beside the
   one language on show. The gap opens with them. */
#langPill { gap: 0; transition: gap 0.24s ease; }
#langPill.open { gap: 2px; }
#langPill button:not([aria-pressed='true']) {
  min-width: 0;
  max-width: 0;
  padding: 0;
  opacity: 0;
  overflow: hidden;
  pointer-events: none;
  transition: max-width 0.24s cubic-bezier(0.2, 0.8, 0.3, 1), opacity 0.18s ease,
    padding 0.24s ease, min-width 0.24s ease;
}
#langPill.open button:not([aria-pressed='true']) {
  min-width: 30px;
  max-width: 70px;
  padding: 0 9px;
  opacity: 1;
  pointer-events: auto;
}
.icon-btn { width: 40px; height: 38px; justify-content: center; }
.icon-btn svg { width: 19px; height: 19px; color: var(--pill-ink); }

/* The Centrum Air badge — the tablet keeps the airline behind exactly this
   round logo button in the header, and so does the phone. */
.badge-btn {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: 20px;
  overflow: hidden;
  border: 1px solid var(--glass-border);
  background: var(--glass);
}
.badge-btn img { width: 100%; height: 100%; object-fit: cover; }
.badge-btn:active { opacity: 0.8; }

/* ── nearby: the tablet's screen (src/NearbyScreen.tsx) on a phone — the same
   gradient hero, the same profile card, the same radar. ─────────────────── */
.near-hero {
  position: relative;
  height: 240px;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  background: linear-gradient(115deg, #1a2a7e 0%, #6e2ab4 35%, #d43b8a 68%, #ff8a5a 100%);
}
.near-hero::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(1.5px 1.5px at 14% 26%, rgba(255,255,255,0.9), transparent),
    radial-gradient(1px 1px at 30% 66%, rgba(255,255,255,0.6), transparent),
    radial-gradient(1.5px 1.5px at 48% 20%, rgba(255,255,255,0.8), transparent),
    radial-gradient(1px 1px at 62% 52%, rgba(255,255,255,0.55), transparent),
    radial-gradient(1.5px 1.5px at 76% 30%, rgba(255,255,255,0.85), transparent),
    radial-gradient(1px 1px at 88% 70%, rgba(255,255,255,0.6), transparent);
}
.near-hero::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 30%, var(--bg) 100%);
}
.near-hero div { position: relative; z-index: 1; padding: 0 var(--pad-r) 24px var(--pad-l); }
.near-hero h1 { font-size: clamp(30px, 9vw, 40px); line-height: 1.06; color: #fff; letter-spacing: -0.6px; }
.near-hero p { margin-top: 8px; font-size: 14.5px; line-height: 20px; color: rgba(255, 255, 255, 0.78); }

.near-body { padding: 16px var(--pad-r) 0 var(--pad-l); display: flex; flex-direction: column; gap: 12px; }
.me-card {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 16px;
  border-radius: 22px;
  background: var(--panel);
}
.me-card .peer-av { width: 50px; height: 50px; border-radius: 25px; font-size: 15px; }
.me-copy { flex: 1; min-width: 0; }
.me-copy .eyebrow { display: block; font-size: 10px; font-weight: 700; letter-spacing: 1.3px; color: var(--faint); }
.me-copy b {
  display: block;
  margin-top: 3px;
  font-size: 17px;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.me-copy small { display: block; font-size: 12.5px; line-height: 16px; color: var(--faint); }
.conn-chip {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 6px;
  height: 28px;
  padding: 0 10px;
  white-space: nowrap;
  border-radius: 15px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.5px;
  background: rgba(111, 220, 140, 0.12);
  color: var(--ok);
}
.conn-chip.off { background: var(--chip-bg); color: var(--faint); }
.conn-chip i { width: 8px; height: 8px; border-radius: 4px; background: currentColor; }

.near-card { padding: 18px 16px; border-radius: 22px; background: var(--panel); }
/* the relay is not answering — say so instead of spinning "connecting" */
.notice {
  margin: 10px 0 2px;
  padding: 12px 14px;
  border-radius: 14px;
  background: rgba(255, 184, 77, 0.09);
  border: 1px solid rgba(255, 184, 77, 0.2);
  color: #c98a28;
  font-size: 12.5px;
  line-height: 18px;
  font-weight: 500;
}
.near-card > header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
.near-card > header h2 { font-size: 18px; }
.near-card > header span { display: flex; align-items: center; gap: 6px; font-size: 12.5px; font-weight: 700; color: var(--ok); }
.near-card > header span i { width: 8px; height: 8px; border-radius: 4px; background: currentColor; }
.near-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 30px 8px 10px;
  border-top: 1px solid var(--border);
  margin-top: 10px;
}
.near-empty b { margin-top: 16px; font-size: 16px; }
.near-empty small { max-width: 300px; margin-top: 6px; font-size: 13px; line-height: 19px; color: var(--faint); }
/* the tablet's radar: one ring with a live dot in it */
.radar {
  position: relative;
  width: 70px;
  height: 70px;
  border-radius: 35px;
  border: 1px solid rgba(111, 220, 140, 0.3);
  background: rgba(111, 220, 140, 0.07);
}
.radar i:first-child {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 13px;
  height: 13px;
  margin: -6.5px 0 0 -6.5px;
  border-radius: 7px;
  background: var(--ok);
  border: 0;
  animation: none;
}
/* the two others sweep outwards */
.radar i:nth-child(2), .radar i:nth-child(3) {
  position: absolute;
  inset: -1px;
  border-radius: 50%;
  border: 1px solid rgba(111, 220, 140, 0.45);
  animation: radar 2.6s ease-out infinite;
}
.radar i:nth-child(3) { animation-delay: 1.3s; }
.radar::after { content: none; }

/* the game picker, the tablet's row list rather than a grid */
.pick-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 9px 6px;
  border-top: 1px solid var(--border);
  text-align: left;
}
.pick-row:first-of-type { border-top: 0; }
.pick-row img { width: 44px; height: 44px; border-radius: 13px; object-fit: cover; flex: 0 0 auto; }
.pick-row b { flex: 1; min-width: 0; font-size: 14.5px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pick-row small { font-size: 12px; color: var(--faint); }

/* ── leaderboard: the tablet's screen (src/LeaderboardScreen.tsx), narrowed
   to a phone — same gradient hero, same podium, same list card. ─────────── */
.rank-hero {
  position: relative;
  height: 260px;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  background: linear-gradient(115deg, #0a2a6e 0%, #2a6ab4 30%, #18a88e 62%, #f5c542 100%);
}
/* the tablet sprinkles a starfield over it */
.rank-hero::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(1.5px 1.5px at 12% 22%, rgba(255,255,255,0.9), transparent),
    radial-gradient(1px 1px at 28% 62%, rgba(255,255,255,0.7), transparent),
    radial-gradient(1.5px 1.5px at 44% 18%, rgba(255,255,255,0.8), transparent),
    radial-gradient(1px 1px at 58% 48%, rgba(255,255,255,0.6), transparent),
    radial-gradient(1.5px 1.5px at 72% 28%, rgba(255,255,255,0.85), transparent),
    radial-gradient(1px 1px at 86% 66%, rgba(255,255,255,0.7), transparent),
    radial-gradient(1px 1px at 34% 84%, rgba(255,255,255,0.5), transparent),
    radial-gradient(1.5px 1.5px at 66% 78%, rgba(255,255,255,0.6), transparent);
}
.rank-hero::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 30%, var(--bg) 100%);
}
.rank-hero div {
  position: relative;
  z-index: 1;
  padding: 0 var(--pad-r) 26px var(--pad-l);
}
.rank-hero h1 { font-size: clamp(30px, 9vw, 40px); line-height: 1.06; color: #fff; letter-spacing: -0.6px; }
.rank-hero p { margin-top: 8px; font-size: 14.5px; line-height: 20px; color: rgba(255, 255, 255, 0.8); }

.rank-body { padding: 18px var(--pad-r) 0 var(--pad-l); }
.podium { display: flex; align-items: flex-end; gap: 10px; margin: 22px 0 26px; }
.podium { justify-content: center; }
.podium-slot { flex: 0 1 33%; min-width: 0; display: flex; flex-direction: column; align-items: center; }
.podium-slot .crown { font-size: 22px; line-height: 24px; margin-bottom: 6px; }
.podium-av {
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.22);
}
.podium-slot b {
  margin-top: 8px;
  max-width: 100%;
  font-size: 13px;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.podium-slot small { font-size: 16px; font-weight: 700; color: #f5c542; margin-top: 1px; }
.pedestal {
  align-self: stretch;
  margin-top: 10px;
  border: 1px solid var(--border);
  border-bottom: 0;
  border-radius: 14px 14px 0 0;
  background: var(--panel-alt);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 21px;
  font-weight: 700;
  color: var(--faint);
}
.pedestal.first {
  background: rgba(245, 197, 66, 0.12);
  border-color: rgba(245, 197, 66, 0.32);
  color: #f5c542;
}

.rank-list { border-radius: 22px; overflow: hidden; background: var(--panel); }
.rank-cols { display: flex; align-items: center; padding: 14px 16px 6px; }
.rank-cols span:first-child { flex: 1; }
.rank-cols span { width: 62px; text-align: right; font-size: 9.5px; font-weight: 700; letter-spacing: 1.1px; color: var(--faint); }
.rank-row {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 62px;
  padding: 8px 16px;
  border-top: 1px solid var(--border);
}
.rank-row.me { background: var(--rowHighlight, rgba(255,255,255,0.065)); }
.rank-row .n { width: 20px; font-size: 15px; font-weight: 700; color: var(--faint); }
.rank-row .who { flex: 1; min-width: 0; }
.rank-row .who b { display: block; font-size: 14.5px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rank-row .who small { font-size: 11.5px; color: var(--faint); }
.rank-row .h { width: 62px; text-align: right; font-size: 13.5px; color: var(--dim); }
.rank-row .p { width: 62px; text-align: right; font-size: 16px; font-weight: 700; }

/* ── the dock ──────────────────────────────────────────────────────────────
   Lifted from mono-main (frontend/src/components/mono/BottomDock.vue) so the
   cabin site and the Mono app carry the same navigation: one nearly clear
   glass pill, and an active tab that is only ever a brighter icon — no plate,
   no glow. The blur is on the pill itself rather than on a layer beneath it;
   iOS composites a backdrop-filter layer on the GPU and lets it cover its
   siblings, which made the icons disappear mid-scroll in their app. */
.tabbar {
  position: fixed;
  left: 50%;
  bottom: calc(var(--safe-bottom) + 14px);
  z-index: 30;
  isolation: isolate;
  width: min(calc(100% - 44px), 330px);
  height: 50px;
  padding: 3px 10px;
  border-radius: 999px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  align-items: center;
  overflow: hidden;
  /* the scroll content supplies the colour; this only dims and blurs it */
  background: rgba(8, 12, 22, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.07);
  box-shadow:
    0 14px 32px -20px rgba(0, 0, 0, 0.56),
    0 2px 6px -5px rgba(0, 0, 0, 0.48);
  backdrop-filter: blur(14px) brightness(0.66);
  -webkit-backdrop-filter: blur(14px) brightness(0.66);
  transform: translateX(-50%);
  transform-origin: 50% 100%;
  transition: transform 280ms cubic-bezier(0.2, 0.8, 0.3, 1), opacity 280ms ease;
}
/* Scrolling down tucks the dock away; scrolling up or reaching the top brings
   it back. Scaling the whole pill keeps the work on the compositor. */
.tabbar.compact { transform: translateX(-50%) scale(0.88) translateY(5px); opacity: 0.94; }
/* Without a working blur it would be an almost invisible outline over a light
   page, so fall back to a flat dark pill. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .tabbar { background: rgba(12, 14, 20, 0.86); }
}
[data-theme='light'] .tabbar {
  background: rgba(255, 255, 255, 0.06);
  border-color: rgba(0, 0, 0, 0.06);
  backdrop-filter: blur(14px) brightness(1.25);
  -webkit-backdrop-filter: blur(14px) brightness(1.25);
}
.tabbar button {
  position: relative;
  z-index: 2;
  width: 100%;
  height: 44px;
  border-radius: 22px;
  display: grid;
  place-items: center;
  /* Opaque, not rgba: a translucent glyph lets the blurred page tint it from
     the inside, and around thin strokes that bleed reads as a halo. */
  color: #c7cbd3;
  background: transparent;
  transition: transform 0.18s ease, color 0.18s ease;
}
[data-theme='light'] .tabbar button { color: #4a4f59; }
.tabbar button svg { width: 22px; height: 22px; }
.tabbar button:active { transform: scale(0.92); }
/* No selected-tab plate: the active state is the icon colour, nothing else. */
.tabbar button[aria-selected='true'] { color: #fff; }
[data-theme='light'] .tabbar button[aria-selected='true'] { color: #10131a; }
/* how many passengers are on this Wi-Fi */
.tabbar .count {
  position: absolute;
  top: 3px;
  right: 50%;
  margin-right: -19px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 8px;
  background: #6fdc8c;
  color: #05060c;
  font-size: 9.5px;
  font-weight: 800;
  font-style: normal;
  line-height: 16px;
  text-align: center;
}

/* ── hero carousel ────────────────────────────────────────────────────── */
.hero { position: relative; }
.hero-track {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.hero-track::-webkit-scrollbar { display: none; }
.hero-slide {
  position: relative;
  flex: 0 0 100%;
  scroll-snap-align: start;
  /* Short enough that the first row of games shows under the fold — the hero
     invites, the catalogue is what the passenger came for. */
  height: clamp(400px, 64dvh, 560px);
  overflow: hidden;
  background: #0a0b18;
}
.hero-slide .art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* one wash from the top for the chrome, one from the bottom for the copy */
.hero-slide::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to bottom, rgba(4, 6, 18, 0.55) 0%, rgba(4, 6, 18, 0) 32%),
    linear-gradient(to bottom, rgba(0, 0, 0, 0) 38%, var(--hero-fade) 99%);
}
.hero-copy {
  position: absolute;
  inset: auto 0 0 0;
  z-index: 2;
  /* The dot strip used to sit under the Play button and this cleared it; with
     the dots gone the copy sits closer to the fold. */
  padding: 0 var(--pad-r) 22px var(--pad-l);
}
.hero-copy .icon {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  object-fit: cover;
  border: 1px solid rgba(255, 255, 255, 0.4);
  margin-bottom: 12px;
}
.hero-copy h1 {
  font-size: clamp(34px, 10vw, 46px);
  line-height: 1.04;
  letter-spacing: -1.4px;
  color: #fff;
}
.hero-copy p {
  margin-top: 8px;
  max-width: 30ch;
  font-size: 15px;
  line-height: 21px;
  color: rgba(255, 255, 255, 0.72);
}
.play-btn {
  margin-top: 18px;
  height: 50px;
  padding: 0 40px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.2);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  font-size: 16px;
  font-weight: 700;
  color: #fff;
}
.play-btn:active { transform: scale(0.97); }

/* ── sections ─────────────────────────────────────────────────────────── */
.section-title {
  margin: 14px var(--pad-r) 12px var(--pad-l);
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -0.3px;
}
.section-sub { margin: -6px var(--pad-r) 14px var(--pad-l); font-size: 13.5px; color: var(--dim); }

.rail {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  padding: 0 var(--pad-r) 2px var(--pad-l);
  scrollbar-width: none;
  scroll-snap-type: x proximity;
  /* Without this the first tile snaps to the bare scroll port and the row
     starts flush against the screen edge, out of line with everything else. */
  scroll-padding-left: var(--pad-l);
}
.rail::-webkit-scrollbar { display: none; }

.tile { flex: 0 0 auto; width: 104px; scroll-snap-align: start; }
.tile .art {
  width: 104px;
  height: 104px;
  border-radius: 24px;
  object-fit: cover;
  background: var(--panel-alt);
}
.tile span {
  display: block;
  margin-top: 7px;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--dim);
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tile:active { opacity: 0.75; }

.chips { margin: 18px 0 14px; }
.chip {
  flex: 0 0 auto;
  height: 36px;
  padding: 0 16px;
  border-radius: 999px;
  background: var(--chip-bg);
  color: var(--chip-text);
  font-size: 13.5px;
  font-weight: 700;
  white-space: nowrap;
}
.chip[aria-pressed='true'] { background: var(--chip-active-bg); color: var(--chip-active-text); }

/* ── "add to home screen" ─────────────────────────────────────────────────
   One glass bar across the bottom, above the safe area. It is an offer, not a
   gate: an × closes it, and it never appears once the app is installed. */
.install {
  position: fixed;
  left: 12px;
  right: 12px;
  bottom: calc(var(--safe-bottom) + 12px);
  z-index: 40;
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: 18px;
  background: rgba(18, 19, 25, 0.82);
  border: 1px solid rgba(255, 255, 255, 0.1);
  box-shadow: 0 18px 40px -20px rgba(0, 0, 0, 0.9);
  backdrop-filter: blur(20px) saturate(1.2);
  -webkit-backdrop-filter: blur(20px) saturate(1.2);
  animation: install-in 0.32s cubic-bezier(0.2, 0.8, 0.3, 1);
}
@keyframes install-in {
  from { transform: translateY(18px); opacity: 0 }
  to { transform: translateY(0); opacity: 1 }
}
.install-icon { width: 38px; height: 38px; border-radius: 10px; flex: 0 0 auto; }
.install-copy { min-width: 0; display: block; }
.install-copy b { display: block; font-size: 14px; font-weight: 700; }
.install-copy small {
  display: block;
  margin-top: 2px;
  font-size: 11.5px;
  line-height: 15px;
  color: var(--dim);
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.install-cta {
  height: 34px;
  padding: 0 14px;
  border-radius: 999px;
  background: #fff;
  color: #10131a;
  font-size: 13px;
  font-weight: 700;
  white-space: nowrap;
}
.install-cta:active { transform: scale(0.96); }
.install-x { width: 26px; height: 26px; border-radius: 13px; color: var(--faint); font-size: 13px; }
/* The steps only ever open on iOS, where there is no install API to call. */
.install-steps {
  grid-column: 1 / -1;
  margin-top: 4px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 8px;
  list-style: none;
}
.install-steps li { display: flex; align-items: center; gap: 9px; font-size: 13px; color: var(--dim); }
.install-steps i {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.12);
  color: var(--text);
  font-size: 11px;
  font-weight: 700;
  font-style: normal;
  display: grid;
  place-items: center;
}

/* ── the filter strip: "All" and one genre dropdown ───────────────────────
   Fifteen genres will not fit across a phone, so only the picked one shows
   and the rest live behind the chevron. */
.filters {
  position: relative;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 18px 0 14px;
  padding: 0 var(--pad-r) 0 var(--pad-l);
}
.genre { position: relative; }
.genre-btn { display: inline-flex; align-items: center; gap: 6px; padding-right: 12px; }
.genre-btn svg { width: 16px; height: 16px; flex: 0 0 auto; transition: transform 0.18s ease; }
.genre-btn[aria-expanded='true'] svg { transform: rotate(180deg); }
.genre-menu {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 40;
  min-width: 190px;
  max-height: min(58vh, 420px);
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: 6px;
  border-radius: 16px;
  background: rgba(20, 20, 26, 0.92);
  border: 1px solid var(--border);
  box-shadow: 0 18px 40px -18px rgba(0, 0, 0, 0.9), 0 2px 10px -6px rgba(0, 0, 0, 0.7);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
}
.genre-item {
  display: block;
  width: 100%;
  padding: 10px 12px;
  border-radius: 10px;
  text-align: left;
  font-size: 14px;
  font-weight: 600;
  color: var(--dim);
  white-space: nowrap;
}
.genre-item:active { background: rgba(255, 255, 255, 0.07); }
.genre-item[aria-selected='true'] { color: var(--text); background: rgba(255, 255, 255, 0.1); }

/* Shorts-style catalogue: two columns of tall 9:16 poster cards. */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 12px;
  padding: 0 var(--pad-r) 0 var(--pad-l);
}
.card {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 9 / 16;
  border-radius: var(--radius-card);
  overflow: hidden;
  background: var(--panel-alt);
  text-align: left;
}
.card:active { transform: scale(0.98); }
.card .art { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* the 5-second clip sits over the poster and fades in once it is the one playing */
.card video.preview { opacity: 0; transition: opacity 0.3s ease; }
.card video.preview.on { opacity: 1; }
.card::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 45%, rgba(0, 0, 0, 0.76) 100%);
}
.card .info {
  position: absolute;
  inset: auto 10px 10px 10px;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 8px;
}
.card .info img { width: 26px; height: 26px; border-radius: 8px; object-fit: cover; flex: 0 0 auto; }
.card .info b,
.card .info small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.card .info b { font-size: 14px; font-weight: 700; color: #fff; }
.card .info small { font-size: 11.5px; color: rgba(255, 255, 255, 0.66); }
.card .best {
  position: absolute;
  top: 9px;
  right: 9px;
  z-index: 2;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  color: #fff;
  background: rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

/* ── inner screens (scores, airline) ──────────────────────────────────── */
.stat-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; padding: 4px var(--pad-r) 4px var(--pad-l); }
.stat {
  background: var(--tile);
  border-radius: 16px;
  padding: 14px 10px;
  text-align: center;
}
.stat b { display: block; font-size: 20px; font-weight: 800; color: var(--accent); }
.stat span { display: block; margin-top: 3px; font-size: 11.5px; line-height: 15px; color: var(--dim); }

.list { padding: 14px var(--pad-r) 0 var(--pad-l); display: flex; flex-direction: column; gap: 8px; }
.row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 10px 12px;
  border-radius: 16px;
  background: var(--panel);
  border: 1px solid var(--border);
  text-align: left;
}
.row:active { opacity: 0.8; }
.row .rank { width: 22px; font-size: 13px; font-weight: 800; color: var(--faint); text-align: center; }
.row img { width: 42px; height: 42px; border-radius: 12px; object-fit: cover; flex: 0 0 auto; }
.row .meta { flex: 1; min-width: 0; }
.row .meta b { display: block; font-size: 15px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row .meta small { font-size: 12px; color: var(--faint); }
.row .score { font-size: 15px; font-weight: 800; color: var(--ok); white-space: nowrap; }

.airline-head { display: flex; align-items: center; gap: 14px; padding-right: 34px; }
.airline-head img { width: 52px; height: 52px; border-radius: 26px; object-fit: cover; flex: 0 0 auto; }
.airline-head h1 { font-size: 23px; }
.airline-head small { display: block; margin-top: 2px; font-size: 12.5px; color: var(--dim); }
.airline-about { margin-top: 16px; font-size: 14.5px; line-height: 22px; color: var(--dim); }
.airline-mission { margin-top: 10px; font-size: 14px; line-height: 21px; color: var(--dim); }
.airline-mission b { color: var(--accent); }
.stat-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin-top: 18px; }
.fleet-label { margin: 22px 0 10px; font-size: 11px; font-weight: 700; letter-spacing: 1.4px; color: var(--faint); }
.fleet { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
.plane { border: 1px solid var(--border); border-radius: 16px; padding: 14px; }
.plane b { display: block; font-size: 15px; margin-bottom: 6px; }
.plane span { display: block; font-size: 13px; line-height: 20px; color: var(--dim); }

/* ── Centrum Air sheet ────────────────────────────────────────────────── */
.sheet { position: fixed; inset: 0; z-index: 50; display: flex; align-items: flex-end; justify-content: center; }
.sheet-backdrop { position: absolute; inset: 0; background: rgba(0, 0, 0, 0.62); }
.sheet-panel {
  position: relative;
  width: 100%;
  max-width: 560px;
  max-height: 90dvh;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 26px 26px 0 0;
  padding: 18px var(--pad-r) calc(var(--safe-bottom) + 26px) var(--pad-l);
  animation: sheet-up 0.28s ease;
}
.sheet-panel::before {
  content: '';
  display: block;
  width: 38px;
  height: 4px;
  border-radius: 2px;
  background: var(--chip-bg);
  margin: 0 auto 16px;
}
@keyframes sheet-up { from { transform: translateY(24px); opacity: 0; } }
.sheet-close {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 32px;
  height: 32px;
  border-radius: 16px;
  background: var(--chip-bg);
  color: var(--text);
  font-size: 13px;
  font-weight: 700;
}
@media (min-width: 620px) {
  .sheet { align-items: center; padding: 24px; }
  .sheet-panel { border-radius: 26px; max-height: 84dvh; }
  .sheet-panel::before { display: none; }
}

/* ── player ───────────────────────────────────────────────────────────── */
.player { position: fixed; inset: 0; z-index: 60; background: #05060c; }
.player iframe { width: 100%; height: 100%; border: 0; display: block; }

.round-btn {
  position: absolute;
  z-index: 3;
  width: 42px;
  height: 42px;
  border-radius: 21px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  background: rgba(10, 14, 18, 0.72);
  border: 1px solid rgba(255, 255, 255, 0.16);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.round-btn svg { width: 22px; height: 22px; }
.back { top: calc(var(--safe-top) + 10px); left: 12px; }

/* Docked: the small badge above a running game. */
.game-badge {
  position: absolute;
  top: calc(var(--safe-top) + 10px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 12;
  width: 42px;
  height: 42px;
  border-radius: 13px;
  padding: 2px;
  background: rgba(255, 255, 255, 0.22);
  border: 1px solid rgba(255, 255, 255, 0.3);
  pointer-events: none;
  transition:
    top 0.62s cubic-bezier(0.22, 1, 0.36, 1),
    width 0.62s cubic-bezier(0.22, 1, 0.36, 1),
    height 0.62s cubic-bezier(0.22, 1, 0.36, 1),
    border-radius 0.62s cubic-bezier(0.22, 1, 0.36, 1),
    box-shadow 0.62s ease,
    background-color 0.5s ease,
    border-color 0.5s ease;
}
.game-badge img {
  width: 100%;
  height: 100%;
  border-radius: 11px;
  object-fit: cover;
  transition: border-radius 0.62s cubic-bezier(0.22, 1, 0.36, 1);
}
/* Launching: the same badge, blown up to the middle of the screen, breathing
   while it waits. Dropping .launching is what makes it fly home. */
.game-badge.launching {
  /* Sits over the spacer .launch::before reserves for it; app.js measures that
     spacer and writes the offset here, so the two never drift apart. */
  top: var(--launch-mark-top, calc(50% - 96px));
  width: 96px;
  height: 96px;
  border-radius: 26px;
  padding: 3px;
  background: rgba(255, 255, 255, 0.1);
  border-color: rgba(255, 255, 255, 0.16);
  box-shadow: 0 26px 54px -26px rgba(0, 0, 0, 0.9);
  /* The breathe keyframes carry translateX(-50%) themselves: an animation
     replaces the element's transform outright, so leaving the centring to the
     base rule would let the mark drift half its width to the right. */
  animation: launch-breathe 2.6s ease-in-out infinite;
}
.game-badge.launching img { border-radius: 23px; }

.player-overlay {
  position: absolute;
  inset: 0;
  z-index: 4;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  background: #05060c;
  transition: opacity 0.32s ease;
}
.player-overlay.solid { background: #05060c; }
.player-overlay.gone { opacity: 0; pointer-events: none; }
.player-poster { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0.35; }
/* The launch screen, as mono-games does it: the game's mark breathing over a
   wash of its own artwork, then its name and an indeterminate bar. */
/* The mark floats over this overlay on its own — it is .game-badge.launching,
   positioned against the frame so it can fly up into the badge afterwards. A
   spacer the same size holds its place in this column, so mark, title and bar
   centre as one group however tall the text turns out to be. */
.launch {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 0 32px;
  text-align: center;
}
.launch::before {
  content: '';
  display: block;
  width: 96px;
  height: 96px;
  margin-bottom: 16px;
}
.launch strong { font-size: 21px; font-weight: 800; letter-spacing: -0.4px; color: #fff; }
.launch small { margin-top: -4px; font-size: 14px; color: rgba(255, 255, 255, 0.62); }
.launch-progress {
  width: 66px;
  height: 2px;
  border-radius: 999px;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.16);
}
.launch-progress i {
  display: block;
  width: 48%;
  height: 100%;
  border-radius: inherit;
  background: #fff;
  animation: launch-progress 1.05s ease-in-out infinite;
}
@keyframes launch-breathe {
  0%, 100% { transform: translateX(-50%) scale(1) }
  50% { transform: translateX(-50%) translateY(-3px) scale(1.025) }
}
@keyframes launch-progress {
  0% { transform: translateX(-115%) }
  55% { transform: translateX(55%) }
  100% { transform: translateX(215%) }
}
@media (prefers-reduced-motion: reduce) {
  .game-badge.launching { animation: none }
}

.card-panel {
  position: relative;
  width: min(360px, calc(100% - 48px));
  padding: 26px 22px;
  border-radius: var(--radius-panel);
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.1);
  text-align: center;
  color: #fff;
}
.card-panel h2 { font-size: 19px; }
.card-panel p { margin-top: 8px; font-size: 14.5px; line-height: 21px; color: rgba(255, 255, 255, 0.68); }
.row-btns { display: flex; gap: 10px; justify-content: center; margin-top: 20px; }
.btn {
  height: 44px;
  padding: 0 22px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  font-size: 14.5px;
  font-weight: 600;
  color: #fff;
}
.btn.primary { background: #fff; border-color: #fff; color: #000; font-weight: 700; }

.toast {
  position: absolute;
  left: 50%;
  bottom: calc(var(--safe-bottom) + 26px);
  transform: translateX(-50%);
  z-index: 5;
  padding: 10px 18px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 700;
  color: #05060c;
  background: #fff;
  animation: toast-in 0.25s ease;
}
@keyframes toast-in { from { opacity: 0; transform: translate(-50%, 8px); } }

/* ── wider phones / small tablets ─────────────────────────────────────── */
@media (min-width: 620px) {
  :root { --pad: 26px; }
  .hero-copy { padding-bottom: 54px; }
  .grid { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
}

/* Landscape phone: 430px of hero is taller than the screen, which hides the
   catalogue behind a single slide. */
@media (orientation: landscape) and (max-height: 560px) {
  .hero-slide { height: 86dvh; }
  .hero-copy { padding-bottom: 30px; }
  .hero-copy h1 { font-size: clamp(28px, 5vw, 38px); }
  .hero-copy p { font-size: 14px; line-height: 19px; margin-top: 6px; max-width: 46ch; }
  .hero-copy .icon { width: 36px; height: 36px; margin-bottom: 8px; }
  .play-btn { margin-top: 12px; height: 44px; }
}

/* Only a real desktop gets the centred column; a phone held sideways is still
   a phone and fills its screen. */
@media (min-width: 900px) and (min-height: 700px) {
  #view { max-width: var(--column); margin: 0 auto; }
  .topbar {
    padding-left: max(var(--pad-l), calc((100% - var(--column)) / 2));
    padding-right: max(var(--pad-r), calc((100% - var(--column)) / 2));
  }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* ── duel: the rival bar over a running game ───────────────────────────────
   The tablet animates this with React Native Animated; on the phone the same
   beats are CSS keyframes, restarted by swapping a class. */
.bhud {
  position: absolute;
  top: calc(var(--safe-top) + 8px);
  left: 62px;
  right: 12px;
  z-index: 4;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  --tone: #6fdc8c;
}
.bhud[data-tone='bad'] { --tone: #ff6b6b; }

.bhud-glow {
  position: absolute;
  top: -70px;
  left: -80px;
  right: -20px;
  height: 150px;
  background: linear-gradient(to bottom, var(--tone), rgba(0, 0, 0, 0));
  opacity: 0;
}
.bhud-glow.beat { animation: bhud-glow 0.75s ease-out; }
.bhud-glow.chase { animation: bhud-glow-twice 1s ease-out; }
@keyframes bhud-glow { 0% { opacity: 0 } 15% { opacity: 0.75 } 100% { opacity: 0 } }
@keyframes bhud-glow-twice {
  0% { opacity: 0 } 12% { opacity: 0.6 } 40% { opacity: 0 } 60% { opacity: 0.5 } 100% { opacity: 0 }
}

.bhud-bar {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 6px;
  width: 100%;
  padding: 8px 12px 9px;
  border-radius: 22px;
  background: rgba(8, 11, 16, 0.82);
  border: 1px solid rgba(255, 255, 255, 0.16);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  overflow: hidden;
}
.bhud-bar.leading { border-color: rgba(111, 220, 140, 0.5); }
.bhud-bar.beat { animation: bhud-beat 0.72s ease-out; }
.bhud-bar.chase { animation: bhud-chase 0.9s ease-out; }
@keyframes bhud-beat {
  0% { box-shadow: inset 0 0 0 60px transparent; transform: translateX(0) rotate(0) }
  8% { box-shadow: inset 0 0 0 60px color-mix(in srgb, var(--tone) 30%, transparent); border-color: var(--tone); transform: translateX(7px) rotate(0.7deg) }
  20% { transform: translateX(-6px) rotate(-0.6deg) }
  32% { transform: translateX(3px) rotate(0.3deg) }
  100% { box-shadow: inset 0 0 0 60px transparent; transform: translateX(0) rotate(0) }
}
@keyframes bhud-chase {
  0%, 100% { box-shadow: inset 0 0 0 60px transparent }
  12% { box-shadow: inset 0 0 0 60px color-mix(in srgb, var(--tone) 22%, transparent) }
  40% { box-shadow: inset 0 0 0 60px transparent }
  60% { box-shadow: inset 0 0 0 60px color-mix(in srgb, var(--tone) 18%, transparent) }
}

/* the glint that flies across the bar — translucent, so digits stay readable */
.bhud-sweep {
  position: absolute;
  top: -30px;
  bottom: -30px;
  width: 70px;
  opacity: 0;
  background: linear-gradient(90deg, transparent, var(--tone), rgba(255, 255, 255, 0.75), var(--tone), transparent);
  transform: rotate(16deg);
}
.bhud-sweep.run { animation: bhud-sweep 0.62s cubic-bezier(0.2, 0.6, 0.3, 1); }
@keyframes bhud-sweep {
  0% { opacity: 0; transform: translateX(-160px) rotate(16deg) }
  15%, 85% { opacity: 0.55 }
  100% { opacity: 0; transform: translateX(320px) rotate(16deg) }
}

.bhud-top { display: flex; align-items: center; gap: 8px; width: 100%; }
.bhud-side { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1 1 0; }
.bhud-side.gone { opacity: 0.4; }
.bhud-right { justify-content: flex-end; }
/* "he is right behind you": the rival's side leans in for a beat */
.bhud-right.chase-in { animation: bhud-chase-in 0.9s ease-out; }
@keyframes bhud-chase-in {
  0%, 100% { transform: translateX(0) scale(1) }
  18% { transform: translateX(-8px) scale(1.12) }
  45% { transform: translateX(0) scale(1) }
  62% { transform: translateX(-6px) scale(1.09) }
}
.bhud-av {
  flex: 0 0 auto;
  width: 32px;
  height: 32px;
  border-radius: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
  font-style: normal;
  color: #fff;
  border: 2px solid rgba(255, 255, 255, 0.28);
}
.bhud-bar.leading .bhud-side:first-child .bhud-av,
.bhud-bar:not(.leading) .bhud-right .bhud-av { border-color: #fff; box-shadow: 0 0 10px rgba(255, 255, 255, 0.8); }
.bhud-copy { min-width: 0; }
.bhud-copy-right { text-align: right; }
.bhud-copy b {
  display: block;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.9px;
  color: rgba(255, 255, 255, 0.55);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.bhud-scorerow { position: relative; display: flex; align-items: center; gap: 5px; }
.bhud-copy-right .bhud-scorerow { justify-content: flex-end; }
.bhud-scorerow em {
  font-style: normal;
  font-size: 20px;
  font-weight: 800;
  letter-spacing: -0.5px;
  color: #fff;
}
.bhud-scorerow em.pop { animation: bhud-pop 0.36s ease-out; }
@keyframes bhud-pop { 0% { transform: scale(1) } 25% { transform: scale(1.3) } 100% { transform: scale(1) } }
.bhud-live {
  width: 6px;
  height: 6px;
  border-radius: 4px;
  background: #6fdc8c;
  animation: bhud-live 1.24s ease-in-out infinite;
}
.bhud-right .bhud-live { background: #ff6b6b; }
@keyframes bhud-live {
  0%, 100% { opacity: 0.45; transform: scale(0.75) }
  50% { opacity: 1; transform: scale(1.35) }
}

.bhud-gap {
  flex: 0 0 auto;
  font-size: 11.5px;
  font-weight: 800;
  color: rgba(255, 255, 255, 0.8);
  white-space: nowrap;
  max-width: 40%;
  overflow: hidden;
  text-overflow: ellipsis;
}
.bhud-gap[data-tone='good'] { color: #6fdc8c; }
.bhud-gap[data-tone='bad'] { color: #ff8a8a; }
.bhud-tug {
  position: relative;
  width: 100%;
  height: 6px;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.22);
  overflow: visible;
}
.bhud-mine {
  position: absolute;
  inset: 0;
  border-radius: 4px;
  background: #6fdc8c;
  transform-origin: left center;
  transition: transform 0.35s cubic-bezier(0.2, 0.8, 0.3, 1);
}
.bhud-knot {
  position: absolute;
  top: -3px;
  width: 3px;
  height: 13px;
  margin-left: -1.5px;
  border-radius: 2px;
  background: #fff;
  transition: left 0.35s cubic-bezier(0.2, 0.8, 0.3, 1);
}
.bhud-knot.knock { animation: bhud-knock 0.7s ease-out; }
@keyframes bhud-knock { 0% { transform: scale(2.4); box-shadow: 0 0 12px #fff } 100% { transform: scale(1) } }

.bhud-sparks { position: absolute; left: 50%; top: 50%; }
.bhud-sparks i {
  position: absolute;
  width: 5px;
  height: 5px;
  border-radius: 3px;
  background: var(--tone);
  opacity: 0;
}
.bhud-sparks i:nth-child(1) { --dx: -42px; --dy: -20px }
.bhud-sparks i:nth-child(2) { --dx: -28px; --dy: 16px }
.bhud-sparks i:nth-child(3) { --dx: -16px; --dy: -18px }
.bhud-sparks i:nth-child(4) { --dx: -6px; --dy: 14px }
.bhud-sparks i:nth-child(5) { --dx: 6px; --dy: -18px }
.bhud-sparks i:nth-child(6) { --dx: 16px; --dy: 16px }
.bhud-sparks i:nth-child(7) { --dx: 28px; --dy: -20px }
.bhud-sparks i:nth-child(8) { --dx: 42px; --dy: 14px }
.bhud-sparks.burst i { animation: bhud-spark 0.62s ease-out; }
@keyframes bhud-spark {
  0% { opacity: 0; transform: translate(0, 0) scale(0.4) }
  20% { opacity: 1 }
  100% { opacity: 0; transform: translate(var(--dx), var(--dy)) scale(0.2) }
}

.bhud-bannerwrap { position: relative; display: flex; align-items: center; justify-content: center; }
/* the ring that blows out of the middle when the lead changes hands */
.bhud-shock {
  position: absolute;
  width: 130px;
  height: 130px;
  border-radius: 50%;
  border: 4px solid var(--tone);
  opacity: 0;
  pointer-events: none;
}
.bhud-shock.blow { animation: bhud-shock 0.76s ease-out; }
@keyframes bhud-shock {
  0% { opacity: 0; transform: scale(0.25) }
  8% { opacity: 0.9 }
  100% { opacity: 0; transform: scale(3.2) }
}

/* the gain that flies off a score */
.bhud-gain {
  position: absolute;
  top: -4px;
  font-style: normal;
  font-size: 13px;
  font-weight: 800;
  color: #6fdc8c;
  pointer-events: none;
  animation: bhud-gain 0.9s cubic-bezier(0.2, 0.7, 0.3, 1) forwards;
}
.bhud-copy-right .bhud-gain { right: 0; }
@keyframes bhud-gain {
  0% { opacity: 0; transform: translateY(0) scale(0.7) }
  20% { opacity: 1; transform: translateY(-6px) scale(1.15) }
  100% { opacity: 0; transform: translateY(-26px) scale(1) }
}

.bhud-banner {
  display: flex;
  margin-top: 9px;
  padding: 7px 20px;
  border-radius: 20px;
  background: rgba(8, 11, 16, 0.9);
  border: 1.5px solid var(--tone);
}
.bhud-banner[data-tone='bad'] { --tone: #ff6b6b; }
.bhud-banner[data-tone='good'] { --tone: #6fdc8c; }
.bhud-banner.show { animation: bhud-banner 1.8s ease-out forwards; }
@keyframes bhud-banner {
  0% { opacity: 0; transform: scale(1.35) }
  20% { opacity: 1; transform: scale(1) }
  85% { opacity: 1 }
  100% { opacity: 0 }
}
.bhud-banner i {
  font-style: normal;
  font-size: 17px;
  font-weight: 800;
  letter-spacing: 0.4px;
  color: var(--tone);
  animation: bhud-letter 0.5s cubic-bezier(0.2, 1.4, 0.4, 1) backwards;
  animation-delay: calc(var(--i) * 22ms);
}
@keyframes bhud-letter {
  0% { opacity: 0; transform: translateY(16px) scale(1.8) }
  100% { opacity: 1; transform: translateY(0) scale(1) }
}

.bhud-feed { display: flex; flex-direction: column; align-items: center; gap: 5px; margin-top: 7px; }
.bhud-line {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 6px 13px;
  border-radius: 16px;
  font-size: 12.5px;
  font-weight: 800;
  color: #fff;
  background: rgba(8, 11, 16, 0.86);
  border: 1px solid rgba(255, 255, 255, 0.16);
  animation: bhud-line 0.3s ease-out;
}
.bhud-line i { font-style: normal; font-size: 11px; opacity: 0.9; }
.bhud-line.good { border-color: rgba(111, 220, 140, 0.55); background: rgba(12, 52, 28, 0.88); }
.bhud-line.bad { border-color: rgba(255, 107, 107, 0.6); background: rgba(72, 14, 14, 0.88); }
@keyframes bhud-line { from { opacity: 0; transform: translateY(-8px) scale(0.9) } }

.bhud-intro {
  position: absolute;
  top: 74px;
  display: flex;
  align-items: center;
  gap: 20px;
}
.bhud-intro span { font-size: 34px; font-weight: 800; color: #fff; text-shadow: 0 2px 10px rgba(0, 0, 0, 0.6); }
.bhud-av-big { width: 56px; height: 56px; border-radius: 28px; font-size: 19px; border-width: 3px; }
.bhud-intro.play { animation: bhud-intro 2s ease-out forwards; }
.bhud-intro.play .bhud-av-big:first-child { animation: bhud-in-left 2s ease-out forwards; }
.bhud-intro.play .bhud-av-big:last-child { animation: bhud-in-right 2s ease-out forwards; }
@keyframes bhud-intro { 0% { opacity: 0 } 10% { opacity: 1 } 80% { opacity: 1 } 100% { opacity: 0 } }
@keyframes bhud-in-left { 0% { transform: translateX(-90px) } 20%, 100% { transform: translateX(0) } }
@keyframes bhud-in-right { 0% { transform: translateX(90px) } 20%, 100% { transform: translateX(0) } }

/* ── nearby: passengers on this Wi-Fi ──────────────────────────────────── */
.nearby-btn { position: relative; }
.nearby-btn .count {
  position: absolute;
  top: -2px;
  right: -2px;
  min-width: 17px;
  height: 17px;
  padding: 0 4px;
  border-radius: 9px;
  background: #6fdc8c;
  color: #05060c;
  font-size: 10.5px;
  font-weight: 800;
  line-height: 17px;
  text-align: center;
}
.peer-row { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-top: 1px solid var(--border); }
.peer-row:first-child { border-top: 0; }
.peer-av {
  width: 42px;
  height: 42px;
  border-radius: 21px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  font-weight: 700;
  color: #fff;
  flex: 0 0 auto;
}
.peer-meta { flex: 1; min-width: 0; }
.peer-meta b { display: block; font-size: 15px; }
.peer-meta small { font-size: 12px; color: var(--faint); }
.peer-btn {
  height: 38px;
  padding: 0 16px;
  border-radius: 19px;
  font-size: 13px;
  font-weight: 700;
  background: var(--chip-active-bg);
  color: var(--chip-active-text);
  white-space: nowrap;
}
.peer-btn[data-state='sent'] { background: var(--chip-bg); color: var(--dim); }
.peer-btn[data-state='accepted'] { background: var(--okChipBg, rgba(111,220,140,0.14)); color: var(--ok); }
.pick-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 10px; margin-top: 14px; }
.pick-game { border-radius: 14px; overflow: hidden; background: var(--panel-alt); }
.pick-game img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.pick-game span {
  display: block;
  padding: 6px 8px 8px;
  font-size: 11.5px;
  font-weight: 700;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
