/* ============================================================
   SPORTSOFT RUN V5 — approved design system
   All metrics are expressed against the 1672 x 941 master frame.
   --s is the live master-pixel -> screen-pixel scale (set in JS).
   ============================================================ */

@font-face {
  font-family: 'BOWLER';
  src: url('../assets/fonts/BOWLER-Regular.woff2') format('woff2');
  font-weight: 400;
  font-display: block;
}
@font-face {
  font-family: 'Sofia Sans';
  src: url('../assets/fonts/SofiaSans-Variable.ttf') format('truetype-variations');
  font-weight: 100 900;
  font-display: swap;
}

:root {
  /* --- Style Guide (Figma) ---------------------------------------------
     Colours and type ramps transcribed from the style-guide page. The guide
     calls #14100E "black", but --black here has always been the page ground
     (#000000), so the ink colour keeps its own name.
     letter-spacing is a property of the family, not of the step: every
     BOWLER step is -4% (72px renders as -2.88px), every text step is 0 —
     hence one em-based token instead of one per ramp entry.
     The `u` suffix marks steps the guide sets
     in uppercase; text-transform is not part of the `font` shorthand, so
     apply it at the call site. */
  --ink: #14100e;

  --font-display: 'BOWLER', 'Sofia Sans', sans-serif;
  --font-text: 'Sofia Sans', system-ui, sans-serif;
  --tracking-display: -.04em;

  --text-d-72: 400 72px/78px var(--font-display);
  --text-d-32u: 600 32px/48px var(--font-text);
  --text-d-26: 400 24px/26px var(--font-display);
  --text-d-18: 600 18px/28px var(--font-text);
  --text-d-16u: 700 16px/23px var(--font-text);
  --text-d-12u: 600 12px/16px var(--font-text);

  --text-t-48: 400 48px/52px var(--font-display);
  --text-t-18: 600 18px/20px var(--font-text);
  --text-t-12: 700 12px/16px var(--font-text);

  --text-m-36: 400 36px/36px var(--font-display);
  --text-m-28: 400 28px/30px var(--font-display);
  --text-m-16: 600 16px/26px var(--font-text);
  --text-m-14: 600 14px/18px var(--font-text);
  --text-m-12: 600 12px/10px var(--font-text);
  --text-m-10u: 700 10px/10px var(--font-text);
  --text-m-10su: 600 10px/10px var(--font-text);

  --black: #000000;
  --white: #ffffff;
  --orange: #ff4e00;
  --orange-light: #ff8a33;
  --graphite: #222222;
  --grey: #666666;
  --grey-label: #9a9a9a;
  --danger: #e01b00;
  --panel: #101010;
  --panel-edge: #2b2b2b;
  --s: 1;
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: var(--black);
  color: var(--white);
  font-family: 'Sofia Sans', system-ui, sans-serif;
  letter-spacing: 0;
  overflow: hidden;
}

body.scroll { overflow: auto; }

img { display: block; }

button { font-family: inherit; letter-spacing: 0; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

:focus-visible {
  outline: 2px solid var(--orange-light);
  outline-offset: 2px;
}

/* ---------------- buttons ---------------- */

/* Button module (Figma). Three sizes — Large 174x56, Medium 140x46,
   Small 110x36 — and the mockups pick one per screen, not per call site:
   320 is Small, 390 and 768 are Medium, 1024 and up are Large. So the size
   rides on breakpoints, mobile-first, and --btn-* modifiers below stay
   available for the odd place that needs to opt out.
   Hover and press cross-fade over 140ms ease-out. Metrics sit in custom
   properties so master-pixel contexts (.panel) can restate them through
   --s instead of redeclaring every rule. */

.btn {
  --btn-w: 110px;
  --btn-h: 36px;
  --btn-fs: 10px;
  --btn-lh: 10px;
  --cut: 9px;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--btn-w);
  height: var(--btn-h);
  padding: 0;
  border: 0;
  cursor: pointer;
  font-family: var(--font-text);
  font-weight: 700;
  font-size: var(--btn-fs);
  line-height: var(--btn-lh);
  text-transform: uppercase;
  letter-spacing: 0;
  text-decoration: none;
  background: var(--orange);
  color: var(--ink);
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%);
  transition: background-color .14s ease-out, color .14s ease-out, box-shadow .14s ease-out;
}
.btn > span {
  display: block;
  line-height: var(--btn-lh);
}

@media (min-width: 360px) {
  .btn { --btn-w: 140px; --btn-h: 46px; --btn-fs: 12px; --btn-lh: 16px; --cut: 12px; }
}
@media (min-width: 1024px) {
  .btn { --btn-w: 174px; --btn-h: 56px; --btn-fs: 16px; --btn-lh: 23px; --cut: 15px; }
}

/* explicit size, for the rare spot that must ignore the breakpoint */
.btn--sm { --btn-w: 110px; --btn-h: 36px; --btn-fs: 10px; --btn-lh: 10px; --cut: 9px; }
.btn--md { --btn-w: 140px; --btn-h: 46px; --btn-fs: 12px; --btn-lh: 16px; --cut: 12px; }
.btn--lg { --btn-w: 174px; --btn-h: 56px; --btn-fs: 16px; --btn-lh: 23px; --cut: 15px; }

.btn:not([disabled]):hover { background: var(--orange-light); }
.btn:not([disabled]):active { background: var(--white); color: var(--orange); }
.btn[disabled] { opacity: .5; cursor: not-allowed; }

.btn--secondary {
  background: #0d0d0d;
  color: var(--white);
  box-shadow: inset 0 0 0 2px rgba(255,255,255,.85);
}
.btn--secondary:not([disabled]):hover { background: #1c1c1c; }
.btn--secondary:not([disabled]):active { background: var(--white); color: var(--orange); box-shadow: none; }

.btn--ghost {
  background: transparent;
  color: var(--white);
  clip-path: none;
  width: auto;
  height: auto;
  min-height: 44px;
  padding: 0 4px;
  border-bottom: 1px solid rgba(255,255,255,.55);
}
.btn--ghost:not([disabled]):hover { color: var(--orange-light); background: transparent; border-bottom-color: var(--orange-light); }
.btn--ghost:not([disabled]):active { background: transparent; }

/* ---------------- generic screen ---------------- */

.screen { display: none; position: fixed; inset: 0; }
.screen.is-active { display: block; }

/* ============================================================
   LANDING
   ============================================================ */

#landing {
  overflow-y: auto;
  overflow-x: hidden;
  background: #000;
}

.landing-hero {
  position: relative;
  width: 100%;
  min-height: 100vh;
  /* the strip is reserved only while the cookie notice is up; the app measures
     the bar and writes its height here */
  padding-bottom: var(--cookie-h, 0px);
  display: flex;
  flex-direction: column;
  isolation: isolate;
}

.landing-hero__art {
  position: absolute;
  inset: 0;
  z-index: 0;
  /* xs (320x568) is the base; wider viewports swap in the matching crop below */
  background-image: url('../assets/art/landing-bg-xs.webp');
  background-size: cover;
  /* anchored to the bottom: the track and the dog live along the lower edge,
     so a taller viewport must crop off the sky, never the ground */
  background-position: center bottom;
  background-repeat: no-repeat;
}

/* Each cover is authored per aspect ratio in Figma, so only the crop changes
   per breakpoint — the anchor above stays put. */
@media (min-width: 360px) {
  .landing-hero__art { background-image: url('../assets/art/landing-bg-s.webp'); }
}
@media (min-width: 768px) {
  .landing-hero__art { background-image: url('../assets/art/landing-bg-m.webp'); }
}
@media (orientation: landscape) and (min-width: 480px) {
  .landing-hero__art { background-image: url('../assets/art/landing-bg-l.webp'); }
}
@media (min-width: 1600px) {
  .landing-hero__art { background-image: url('../assets/art/landing-bg-xl.webp'); }
}

/* The hero is laid out straight off the mockups. Every step below restates
   the same six numbers for its breakpoint, so the whole screen moves from
   one block instead of from rules scattered through the file:
     --pad         side gutter
     --topbar-top  where the top row sits (it floats over the art, because
                   at 768 and 1024 the Tech Week mark starts *below* the
                   copy block rather than above it)
     --body-top    top of the copy block
     --gap-title   between eyebrow / headline / paragraph
     --gap-block   title -> slogans -> button (the mockups use one value)
     --copy-w      the copy column
     --text-w      paragraph measure inside it */
.landing-hero {
  --pad: 16px;
  --topbar-top: 16px;
  --body-top: 64px;
  --gap-title: 8px;
  --gap-block: 24px;
  --copy-w: 100%;
  --text-w: 100%;
}

.topbar {
  position: absolute;
  z-index: 2;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: flex-start;
  padding: var(--topbar-top) var(--pad) 0;
}
.topbar__logo { display: none; width: auto; height: 26px; }
.topbar__techweek { width: 68px; height: 16px; margin-right: auto; }

.landing-hero__body {
  position: relative;
  z-index: 2;
  padding: var(--body-top) var(--pad) 0;
}

.hero-copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: var(--copy-w);
}

.eyebrow {
  font: var(--text-m-10su);
  color: var(--orange);
  text-transform: uppercase;
  margin: 0 0 var(--gap-title);
}

.hero-title {
  font: var(--text-m-28);
  letter-spacing: var(--tracking-display);
  text-transform: uppercase;
  color: var(--white);
  white-space: nowrap;
  margin: 0 0 var(--gap-title);
}
.hero-title .run { color: var(--orange); }

.hero-text {
  font: var(--text-m-14);
  color: var(--white);
  width: var(--text-w);
  margin: 0 0 var(--gap-block);
}

/* --- Slogan module (Figma) ---------------------------------------------
   A bordered icon cell butted against a bordered label. The shared edge is
   drawn once, as the icon cell's right border, so it never doubles up. */
.slogans {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--slogan-gap, 12px);
  list-style: none;
  margin: 0 0 var(--gap-block);
  padding: 0;
}
.slogan {
  --sl-pad: 6px;
  --sl-icon: 14px;
  --sl-text-pad: 12px;
  --sl-text-gap: 4px;
  --sl-text-w: 120px;
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--white);
  font: var(--text-m-12);
  text-transform: uppercase;
  color: var(--white);
}
.slogan__icon {
  display: flex;
  padding: var(--sl-pad);
  border-right: 1px solid var(--white);
}
.slogan__icon img { width: var(--sl-icon); height: var(--sl-icon); }
.slogan__text {
  display: flex;
  gap: var(--sl-text-gap);
  width: var(--sl-text-w);
  padding: 8px var(--sl-text-pad);
  white-space: nowrap;
}
.slogan__text b { color: var(--orange); font-weight: inherit; }
/* the third slogan loses a word below 1440, where the row would not fit */
.slogan__long { display: none; }

.hero-actions { display: flex; flex-wrap: wrap; gap: 14px; }

/* Promo fine print. Not in the mockups, but required by the client: it is
   pushed to the foot of the hero (auto margin against the column) and keeps
   the copy gutter, so it stays aligned with the eyebrow at every step. */
.landing-hero__fine {
  position: relative;
  z-index: 2;
  margin: auto 0 0;
  padding: 40px var(--pad) 26px;
  max-width: 62ch;
  font: 400 12px/1.5 var(--font-text);
  /* the foot of the hero can land on the lit track, so the line keeps its own
     shadow instead of relying on the art staying dark */
  color: #c2c2c2;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .9);
}

.linklike {
  background: none; border: 0; padding: 0;
  color: var(--orange-light); cursor: pointer;
  font-size: inherit; text-decoration: underline;
}

/* ============================================================
   GAME STAGE  (1672 x 941 master, scaled by --s)
   ============================================================ */

/* A tap anywhere on the play area is a jump, so nothing inside the game screen
   may behave like text: holding the finger a moment longer used to select the
   HUD readouts and the overlay copy, and the selection then sat over the run.
   Same treatment the JUMP button already gets — the modals stay outside #game,
   so registration input is unaffected. */
#game {
  background: #000;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.stage-wrap {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 16px;
}

.stage {
  position: relative;
  /* высота держит мастер-кадр, ширину задаёт fitStage: на широком экране она
     больше мастерной, и движок дорисовывает мир в получившееся место */
  width: var(--stage-w, calc(var(--s) * 1672px));
  height: calc(var(--s) * 941px);
  background: #000;
  border: calc(var(--s) * 2px) solid var(--orange);
  overflow: hidden;
}

/* ---------------- HUD ---------------- */

/* полоса собрана флексом: блоки по верхней линии, а промежутки между ними
   растягиваются поровну, поэтому отступы слева и справа от каждого
   разделителя всегда одинаковы */
.hud {
  position: absolute;
  left: 0; top: 0; right: 0;
  height: calc(var(--s) * 108px);
  background: #050505;
  border-bottom: calc(var(--s) * 3px) solid var(--orange);
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  padding: calc(var(--s) * 11px) calc(var(--s) * 34px) calc(var(--s) * 11px) calc(var(--s) * 47px);
}

.hud__cell {
  flex: 0 0 auto;
  padding: calc(var(--s) * 8px) 0;
  text-align: center;
}

/* один отступ под всеми заголовками — держится здесь, а не в каждом блоке */
.hud__label {
  display: block;
  font-family: 'BOWLER', 'Sofia Sans', sans-serif;
  color: var(--grey-label);
  /* the HUD is a fixed master-pixel band, so its floors stay modest — every
     cell still has to fit inside the 108px strip at any --s */
  font-size: max(10px, calc(var(--s) * 15px));
  line-height: 1;
  white-space: nowrap;
  margin-bottom: calc(var(--s) * 8px);
}

.hud__value {
  display: block;
  font-family: 'BOWLER', 'Sofia Sans', sans-serif;
  line-height: 1;
  white-space: nowrap;
}
/* BOWLER ships no tabular figures — `tabular-nums` does nothing here and its
   "1" is barely half the width of the other digits. A counting readout then
   changes width and shoves the neighbouring HUD blocks sideways, so every digit
   is boxed to the width of the widest one (.801em, measured off the font). */
.hud__value i {
  display: inline-block;
  width: .801em;
  font-style: normal;
  text-align: center;
}

/* разделитель — линия во всю высоту контентной полосы, так что ни один блок
   её не перерастает; равные промежутки вокруг даёт space-between */
.hud__sep {
  flex: 0 0 auto;
  align-self: stretch;
  width: calc(var(--s) * 1px);
  background: #3a3a3a;
}

/* brand — logo asset is tight-cropped, so its left edge IS the S of SPORTSOFT
   and DATA STREAM sits on exactly the same vertical line */
/* бренд центрирован по вертикали полосы; единственная ячейка с левой выключкой */
.hud-brand { align-self: center; text-align: left; --logo-w: calc(var(--s) * 196px); }
/* логотип и подпись — один блок: подпись равняется по левому краю лого, а сам
   блок можно центрировать в ячейке целиком */
.hud-brand__box { display: inline-block; text-align: left; }
.hud-brand__row {
  display: flex;
  align-items: flex-start;                /* верх RUN на одном уровне с верхом лого */
  gap: calc(var(--s) * 14px);
  height: calc(var(--s) * 42px);
}
.hud-brand img { width: var(--logo-w); height: auto; display: block; }
/* the logo asset is cropped to the cap height of SPORTSOFT, so RUN is sized by
   cap height too and both wordmarks read as one line of type. The asset is
   418x90, BOWLER caps are .7em, hence font-size = width * 90/418 / .7, and the
   .05em of empty space above the caps is pulled back up to align the tops. */
.hud-brand .run {
  font-family: 'BOWLER', 'Sofia Sans', sans-serif;
  color: var(--orange);
  font-size: calc(var(--logo-w) * .3076);
  line-height: 1;
  display: block;
  transform: translateY(-.05em);
}
.hud-brand__sub {
  display: block;
  margin-top: calc(var(--s) * 8px);
  font-family: 'BOWLER', 'Sofia Sans', sans-serif;
  color: #cfcfcf;
  font-size: calc(var(--s) * 13px);
  line-height: 1;
}

/* velocity */
.hud-vel { width: calc(var(--s) * 176px); }
.hud-vel .hud__value {
  color: var(--white);
  font-size: max(13px, calc(var(--s) * 28px));
}
.hud-bar {
  display: block;
  margin: calc(var(--s) * 9px) auto 0;
  width: calc(var(--s) * 176px);
  height: calc(var(--s) * 7px);
  background: #3a3a3a;
}
.hud-bar i { display: block; height: 100%; width: 12%; background: var(--orange); }

/* distance */
.hud-dist .hud__value {
  color: var(--orange);
  font-size: max(20px, calc(var(--s) * 46px));
}

/* modules */
.hud-mod .hud__value {
  color: var(--orange);
  font-size: max(20px, calc(var(--s) * 46px));
}

/* life core — sprite box is 60px wide around a 50px core, so the box is drawn at
   59px to land the core itself on the approved 49px, pitch 57px */
.hud-life .hud__label { margin-bottom: 0; }
.hud-life__icons {
  display: flex;
  justify-content: center;
}
.hud-life__icons img {
  width: max(22px, calc(var(--s) * 59px));
  height: max(22px, calc(var(--s) * 59px));
  transition: opacity .18s ease, filter .18s ease;
}
.hud-life__icons img + img { margin-left: calc(var(--s) * -2px); }
.hud-life__icons img.is-empty { opacity: .3; filter: grayscale(1) brightness(.75); }

/* fullscreen */
.hud-fs {
  position: relative;
  flex: 0 0 auto;
  align-self: center;
  width: max(34px, calc(var(--s) * 78px));
  height: max(34px, calc(var(--s) * 78px));
  min-height: 0;
  min-width: 0;
  background: #0a0a0a;
  border: 0;
  cursor: pointer;
  padding: 0;
}
.hud-fs span {
  position: absolute;
  width: calc(var(--s) * 17px);
  height: calc(var(--s) * 17px);
  border: calc(var(--s) * 3px) solid var(--white);
}
.hud-fs span:nth-child(1) { left: calc(var(--s)*17px); top: calc(var(--s)*17px); border-right: 0; border-bottom: 0; }
.hud-fs span:nth-child(2) { right: calc(var(--s)*17px); top: calc(var(--s)*17px); border-left: 0; border-bottom: 0; }
.hud-fs span:nth-child(3) { left: calc(var(--s)*17px); bottom: calc(var(--s)*17px); border-right: 0; border-top: 0; }
.hud-fs span:nth-child(4) { right: calc(var(--s)*17px); bottom: calc(var(--s)*17px); border-left: 0; border-top: 0; }
.hud-fs:hover span { border-color: var(--orange-light); }

/* при наведении уголки расходятся по диагонали на 10 и возвращаются, зациклено */
@keyframes fs-corner-tl { 50% { transform: translate(calc(var(--s) * -10px), calc(var(--s) * -10px)); } }
@keyframes fs-corner-tr { 50% { transform: translate(calc(var(--s) * 10px), calc(var(--s) * -10px)); } }
@keyframes fs-corner-bl { 50% { transform: translate(calc(var(--s) * -10px), calc(var(--s) * 10px)); } }
@keyframes fs-corner-br { 50% { transform: translate(calc(var(--s) * 10px), calc(var(--s) * 10px)); } }

.hud-fs:hover span {
  animation-duration: 1.1s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}
.hud-fs:hover span:nth-child(1) { animation-name: fs-corner-tl; }
.hud-fs:hover span:nth-child(2) { animation-name: fs-corner-tr; }
.hud-fs:hover span:nth-child(3) { animation-name: fs-corner-bl; }
.hud-fs:hover span:nth-child(4) { animation-name: fs-corner-br; }

@media (prefers-reduced-motion: reduce) {
  .hud-fs:hover span { animation: none; }
}

/* ---------------- play area ---------------- */

.play {
  position: absolute;
  left: 0; right: 0;
  top: calc(var(--s) * 111px);
  bottom: 0;
}
.play canvas { display: block; width: 100%; height: 100%; }

.touch-jump {
  position: absolute;
  right: calc(var(--s) * 34px);
  bottom: calc(var(--s) * 26px);
  width: max(60px, calc(var(--s) * 108px));
  height: max(60px, calc(var(--s) * 108px));
  border-radius: 50%;
  border: 2px solid rgba(255,78,0,.75);
  background: rgba(255,78,0,.1);
  color: var(--white);
  font-family: 'BOWLER', 'Sofia Sans', sans-serif;
  font-size: max(12px, calc(var(--s) * 18px));
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 6;
  /* iOS reads a burst of taps as a double-tap on the word inside the button and
     pops the selection menu over the game — the label has to be untouchable */
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
/* BOWLER caps sit high in their line box — nudge to the optical centre of the circle */
.touch-jump span { display: block; line-height: 1; transform: translateY(.1em); }
body.is-touch .touch-jump.is-on { display: flex; }

/* ---------------- overlays ---------------- */

.overlay {
  position: absolute;
  inset: 0;
  display: none;
  z-index: 8;
}
.overlay.is-active { display: block; }
.overlay::before {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(0,0,0,.42);
}

.panel {
  position: absolute;
  background: #0c0c0c;
  border-top: calc(var(--s) * 4px) solid var(--orange);
  padding: calc(var(--s) * 26px) calc(var(--s) * 34px) calc(var(--s) * 34px);
}

.panel__meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  border-bottom: calc(var(--s) * 1px) solid #333;
  padding-bottom: calc(var(--s) * 14px);
}
/* the floors below follow the button rule: master pixels everywhere, with a
   readable minimum so a short landscape viewport cannot shrink copy to 6px */
.panel__meta span {
  font-weight: 700;
  font-size: max(10px, calc(var(--s) * 15px));
  text-transform: uppercase;
  color: #cfcfcf;
}

.panel__eyebrow {
  color: var(--orange);
  font-weight: 700;
  text-transform: uppercase;
  font-size: max(11px, calc(var(--s) * 16px));
  margin: calc(var(--s) * 22px) 0 calc(var(--s) * 10px);
}
.panel__title {
  font-family: 'BOWLER', 'Sofia Sans', sans-serif;
  font-size: calc(var(--s) * 54px);
  line-height: 1;
  margin: 0 0 calc(var(--s) * 22px);
}
.panel__title .run { color: var(--orange); }
.panel__title img {
  display: inline-block;
  height: calc(var(--s) * 40px);
  width: auto;
  vertical-align: baseline;
  margin-right: calc(var(--s) * 12px);
}
/* headings that pair the logo image with the RUN wordmark — the asset is
   cropped to the cap height of SPORTSOFT and BOWLER caps are .7em, so RUN is
   sized from the logo and both words share one height. The .1em nudge centres
   the caps, not the line box, against the picture. */
.panel__title--logo {
  display: flex;
  align-items: center;
  gap: calc(var(--s) * 14px);
  --logo-h: calc(var(--s) * 40px);
}
.panel__title--logo img { margin-right: 0; height: var(--logo-h); }
.panel__title--logo .run {
  font-size: calc(var(--logo-h) / .7);
  line-height: 1;
  transform: translateY(.1em);
}
.panel__text {
  font-size: max(12px, calc(var(--s) * 19px));
  line-height: 1.45;
  color: #dcdcdc;
  margin: 0;
}

/* Same module, restated in master pixels so it scales with the stage — but a
   landscape phone drives --s down to ~0.41, which would leave a 72x23 button
   with 6.6px type. Every value below therefore carries a floor: a touch target
   never drops under 44px and its label never under 12px. At --s ~ 1 the master
   value always wins, so the approved frame is untouched. */
.panel .btn {
  /* 112 keeps LEADERBOARD + TRY AGAIN on one line inside the result panel;
     wider floors wrap them into a column on a landscape phone */
  --btn-w: max(112px, calc(var(--s) * 174px));
  --btn-h: max(44px, calc(var(--s) * 56px));
  --btn-fs: max(12px, calc(var(--s) * 16px));
  --btn-lh: max(16px, calc(var(--s) * 23px));
  --cut: max(12px, calc(var(--s) * 15px));
}

/* start overlay */
#ovStart .panel {
  left: calc(var(--s) * 78px);
  top: calc(var(--s) * 62px);
  width: calc(var(--s) * 690px);
}
.keys {
  display: flex;
  align-items: center;
  gap: calc(var(--s) * 10px);
  margin: calc(var(--s) * 24px) 0;
  padding: calc(var(--s) * 18px) 0;
  border-top: calc(var(--s) * 1px) solid #333;
  border-bottom: calc(var(--s) * 1px) solid #333;
}
.keys__lbl {
  color: var(--orange);
  font-weight: 700;
  font-size: max(10px, calc(var(--s) * 15px));
  margin-right: calc(var(--s) * 6px);
}
.keycap {
  min-width: max(34px, calc(var(--s) * 62px));
  height: max(24px, calc(var(--s) * 40px));
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 calc(var(--s) * 12px);
  background: #1a1a1a;
  border: calc(var(--s) * 1px) solid #4a4a4a;
  font-size: max(10px, calc(var(--s) * 14px));
  font-weight: 700;
}
.keys .or { color: #8a8a8a; font-size: max(9px, calc(var(--s) * 13px)); }

/* result overlay */
#ovResult .panel {
  left: calc(var(--s) * 150px);
  right: calc(var(--s) * 150px);
  top: calc(var(--s) * 62px);
  display: grid;
  grid-template-columns: 1fr calc(var(--s) * 640px);
  gap: calc(var(--s) * 34px);
  align-items: start;
}
#ovResult .panel__meta { grid-column: 1 / -1; }
.result-left { min-width: 0; }
.result-big {
  font-family: 'BOWLER', 'Sofia Sans', sans-serif;
  color: var(--white);
  font-size: calc(var(--s) * 58px);
  line-height: 1;
  margin: 0 0 calc(var(--s) * 4px);
}
.result-value {
  font-family: 'BOWLER', 'Sofia Sans', sans-serif;
  color: var(--orange);
  font-size: calc(var(--s) * 90px);
  line-height: 1;
  margin: 0;
  display: flex;
  align-items: flex-end;
  gap: calc(var(--s) * 12px);
}
.result-value em {
  font-style: normal;
  font-size: max(11px, calc(var(--s) * 20px));
  color: #cfcfcf;
  padding-bottom: calc(var(--s) * 10px);
}
.result-stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: calc(var(--s) * 20px);
  margin: calc(var(--s) * 26px) 0;
  padding: calc(var(--s) * 18px) 0;
  border-top: calc(var(--s) * 1px) solid #333;
  border-bottom: calc(var(--s) * 1px) solid #333;
}
.result-stats div + div { border-left: calc(var(--s) * 1px) solid #333; padding-left: calc(var(--s) * 20px); }
.result-stats dt {
  font-weight: 700;
  font-size: max(10px, calc(var(--s) * 14px));
  color: #9a9a9a;
  text-transform: uppercase;
  margin: 0 0 calc(var(--s) * 8px);
}
.result-stats dd {
  margin: 0;
  font-family: 'BOWLER', 'Sofia Sans', sans-serif;
  font-size: max(15px, calc(var(--s) * 26px));
}
.result-art {
  position: relative;
  border: calc(var(--s) * 1px) solid #3a3a3a;
  overflow: hidden;
  height: calc(var(--s) * 420px);
  margin: 0;
  background: #000;
}
.result-art img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 64% 46%;
}

.btn-row { display: flex; gap: max(10px, calc(var(--s) * 16px)); flex-wrap: wrap; }

/* leaderboard overlay */
/* панель и призыв с Instagram идут одной колонкой: высота таблицы плавает,
   поэтому блок призыва не прибит к низу, а следует за панелью */
#ovBoard .board-stack {
  position: absolute;
  left: calc(var(--s) * 160px);
  right: calc(var(--s) * 160px);
  top: calc(var(--s) * 26px);
  display: flex;
  flex-direction: column;
  gap: calc(var(--s) * 18px);
  /* ceiling, not a height: on the master frame the stack is shorter than this
     and nothing changes, but on a landscape phone the enlarged rows would push
     the Instagram call-out past the play area — there the table gives way */
  max-height: calc(100% - var(--s) * 52px);
}
#ovBoard .panel { position: static; display: flex; flex-direction: column; min-height: 0; }
/* призыв над заголовком уехал в блок под панелью — отступ держит сама мета */
#ovBoard .panel__meta { margin-bottom: calc(var(--s) * 26px); }

/* Шапка лидерборда собрана одной сеткой: те же три элемента переставляются в
   строку на низком экране без правки разметки. */
.board-head {
  display: grid;
  grid-template-areas:
    'meta  meta'
    'title live';
  grid-template-columns: 1fr auto;
  align-items: end;
  column-gap: calc(var(--s) * 24px);
}
.board-head .panel__meta { grid-area: meta; }
.board-head .panel__title { grid-area: title; margin-bottom: 0; }
.board-head .live-flag { grid-area: live; }

.insta-cta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: calc(var(--s) * 24px);
  border-top: calc(var(--s) * 4px) solid var(--orange);
  background: #0c0c0c;
  padding: calc(var(--s) * 18px) calc(var(--s) * 34px);
  flex-wrap: wrap;
}
.insta-cta__text {
  font-family: 'BOWLER', 'Sofia Sans', sans-serif;
  font-size: max(15px, calc(var(--s) * 30px));
  line-height: 1;
  color: var(--orange);
  text-transform: uppercase;
  margin: 0;
}
/* видимы пять строк, остальные — прокруткой; шапка держится липкой */
.board-scroll {
  margin-top: calc(var(--s) * 12px);
  /* шапка 41 + пять строк по 47.7. На низком экране строка держит собственный
     минимум, поэтому окно отдаёт высоту первым: сжимается до трёх-четырёх
     строк, остальные уходят в прокрутку */
  flex: 1 1 auto;
  min-height: 0;
  max-height: max(170px, calc(var(--s) * 279px));
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--orange) #191919;
}
.board-scroll::-webkit-scrollbar { width: calc(var(--s) * 8px); }
.board-scroll::-webkit-scrollbar-track { background: #191919; }
.board-scroll::-webkit-scrollbar-thumb { background: var(--orange); }

.board { width: 100%; border-collapse: collapse; }
.board caption { text-align: left; }
.board th {
  position: sticky;
  top: 0;
  z-index: 1;
  text-align: left;
  background: #191919;
  color: var(--orange);
  font-size: max(11px, calc(var(--s) * 14px));
  font-weight: 700;
  text-transform: uppercase;
  padding: max(6px, calc(var(--s) * 12px)) max(8px, calc(var(--s) * 18px));
}
.board th:first-child { color: #9a9a9a; }
.board th:last-child, .board td:last-child { text-align: right; }
.board td {
  padding: max(7px, calc(var(--s) * 13px)) max(8px, calc(var(--s) * 18px));
  font-size: max(12px, calc(var(--s) * 18px));
  font-weight: 700;
  border-bottom: calc(var(--s) * 1px) solid #242424;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.board td:first-child { color: #cfcfcf; font-weight: 400; width: max(34px, calc(var(--s) * 70px)); }
.board td.company { color: #d0d0d0; font-weight: 400; }
.board td.meters { color: var(--orange); }
.board tr.is-you td { background: linear-gradient(90deg, rgba(255,78,0,.28), rgba(255,78,0,.05)); }
.board tr.is-you td:first-child { box-shadow: inset calc(var(--s) * 4px) 0 0 var(--orange); }
.board__empty { color: #8a8a8a; font-weight: 400; text-align: center; }

.board-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: calc(var(--s) * 20px);
  margin-top: calc(var(--s) * 22px);
  flex-wrap: wrap;
}
.your-rank { display: flex; align-items: baseline; gap: calc(var(--s) * 12px); }
.your-rank span { font-size: max(10px, calc(var(--s) * 14px)); font-weight: 700; color: #9a9a9a; text-transform: uppercase; }
.your-rank b { font-family: 'BOWLER','Sofia Sans',sans-serif; font-size: max(16px, calc(var(--s) * 26px)); }
.your-rank em { font-style: normal; font-family: 'BOWLER','Sofia Sans',sans-serif; font-size: max(14px, calc(var(--s) * 22px)); color: var(--orange); }

.live-flag {
  display: inline-flex; align-items: center; gap: calc(var(--s) * 8px);
  font-size: max(10px, calc(var(--s) * 14px)); font-weight: 700; color: #cfcfcf;
}
.live-flag i { width: calc(var(--s) * 12px); height: calc(var(--s) * 12px); background: var(--orange); display: block; }

/* A landscape phone leaves the leaderboard ~343px of play area, and the
   enlarged rows need every pixel of it. The chrome around the table — panel
   padding, meta margin, the gap under it — gives up its master-pixel spacing
   here so the table itself keeps three to four visible rows. */
@media (max-height: 520px) {
  /* The master band is only ~34px tall on a 300px viewport, and the enlarged
     readouts need 32 of them — they ended up touching the orange rule. So the
     band gets a floor of its own and the play area starts below it by the same
     amount; the engine re-derives its scale from the remaining height, so the
     picture stays square, just slightly shorter. */
  /* по центру, а не от верха: полоса здесь выше мастерной, и при выравнивании
     по верху весь запас уходил вниз одной щелью */
  .hud {
    height: max(42px, calc(var(--s) * 108px));
    align-items: center;
    padding-top: 4px;
    padding-bottom: 4px;
  }
  .play { top: max(43px, calc(var(--s) * 111px)); }
  .hud__cell { padding-top: 0; padding-bottom: 0; }
  .hud__label { margin-bottom: 2px; }

  /* Все ячейки делят полосу поровну и центрируют своё содержимое: при
     space-between крайние прижимались к краям, и логотип с Life Core стояли
     не по центру своих секций. */
  .hud__cell {
    flex: 1 1 0;
    width: auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
  }
  /* на низкой полосе мастерный бренд наезжает на SPEED — уменьшаем весь блок
     одной переменной, лого и RUN остаются одной высоты */
  .hud-brand { align-self: stretch; --logo-w: calc(var(--s) * 160px); }
  .hud-brand__row {
    justify-content: center;
    gap: calc(var(--s) * 10px);
    height: calc(var(--s) * 35px);
  }
  .hud-bar { margin-left: 0; margin-right: 0; }


  /* Панель брифинга на телефоне узкая: текст разбивается на шесть строк и
     панель перерастает игровое поле. Отдаём ей почти половину ширины —
     тот же текст укладывается вдвое короче. Мастерная ширина остаётся полом,
     чтобы на широком экране ничего не сузилось. */
  #ovStart .panel { width: max(calc(var(--s) * 690px), 45%); }
  /* на совсем низком экране 45% всё ещё оставляют четыре строки и панель
     перерастает поле — добавляем ширины, чтобы текст сложился в три */
  @media (max-height: 360px) {
    #ovStart .panel { width: max(calc(var(--s) * 690px), 55%); }
  }

  /* прижимаем стек к полосе HUD: мастерный отступ на телефоне съедает строку */
  #ovBoard .board-stack { top: 4px; max-height: calc(100% - 8px); }
  #ovBoard .panel { padding-bottom: 10px; }
  #ovBoard .panel__meta { margin-bottom: 8px; }

  /* заголовок, подпись и LIVE встают в одну строку — освободившаяся строка
     уходит таблице, где на телефоне помещается ещё один игрок */
  .board-head {
    grid-template-areas: 'title meta live';
    grid-template-columns: auto 1fr auto;
    align-items: start;
    column-gap: 12px;
    border-bottom: 1px solid #333;
    padding-bottom: 6px;
  }
  .board-head .panel__meta {
    justify-content: flex-end;
    border-bottom: 0;
    padding-bottom: 0;
    margin-bottom: 0;
  }
  #ovBoard .board-foot { margin-top: 8px; }
  .insta-cta { padding-top: 6px; padding-bottom: 6px; }
}

/* На экране ниже 360px каждая строка таблицы на счету, поэтому призыв под
   лидербордом ужимается: его кнопка второстепенная, играть она не мешает. */
@media (max-height: 360px) {
  .insta-cta { padding-top: 4px; padding-bottom: 4px; }
  .insta-cta .btn { --btn-w: 110px; --btn-h: 36px; --btn-fs: 10px; --btn-lh: 10px; --cut: 9px; }
}

/* on the narrowest landscape phones the call-out wraps onto a second line and
   takes the room away from the table — the line stays on one row instead */
@media (max-height: 520px) and (max-width: 760px) {
  .insta-cta__text { font-size: 12px; }
}

/* rotate hint */
.rotate-hint {
  position: fixed;
  inset: 0;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  background: #000;
  z-index: 60;
  text-align: center;
  padding: 24px;
}
.rotate-hint p { max-width: 30ch; color: #cfcfcf; margin: 0; font-size: 16px; }
.rotate-hint b { font-family: 'BOWLER','Sofia Sans',sans-serif; font-size: 24px; }
.rotate-hint svg { width: 64px; height: 64px; }
body.needs-rotate .rotate-hint { display: flex; }

/* ============================================================
   MODALS (registration / complete / legal)
   ============================================================ */

.modal {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(0,0,0,.9);
  overflow-y: auto;
}
.modal.is-active { display: flex; }

.modal__box {
  position: relative;
  width: min(760px, 100%);
  background: #0d0d0d;
  border-top: 4px solid var(--orange);
  padding: 24px 30px 32px;
}
.modal__box--narrow { width: min(560px, 100%); }

/* «REGISTRATION» — самое длинное слово в игре, и на узком экране оно уезжало
   за край модалки. Кегль привязан к ширине окна и упирается в макетные 40px,
   так что на обычных экранах заголовок не меняется. */
.modal__title { font-size: min(40px, 8.2vw); }

.modal__close {
  position: absolute;
  right: 22px;
  top: 74px;
  width: 48px; height: 48px;
  background: #1c1c1c;
  border: 1px solid #3a3a3a;
  color: var(--white);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
}
.modal__close:hover { background: #2a2a2a; }

.field { display: block; margin-bottom: 4px; }
.field__label {
  display: block;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0;
  text-transform: uppercase;
  color: #9a9a9a;
  margin-bottom: 7px;
}
.field input[type=text],
.field input[type=email] {
  width: 100%;
  height: 52px;
  padding: 0 16px;
  background: #1b1b1b;
  border: 1px solid #333;
  color: var(--white);
  font-family: inherit;
  font-size: 16px;
  font-weight: 600;
}
.field input:focus { border-color: var(--orange); outline: none; }
.field input[aria-invalid="true"] { border-color: var(--danger); }
.field__error {
  display: block;
  min-height: 18px;
  color: #ff7a5e;
  font-size: 12px;
  font-weight: 600;
  margin-top: 4px;
}

.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 24px; }

.consent {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin: 14px 0 6px;
  font-size: 14px;
  line-height: 1.4;
}
.consent input { width: 22px; height: 22px; accent-color: var(--orange); margin: 1px 0 0; flex: none; }
.consent .linklike { font-size: 14px; }

.modal .btn-row { display: flex; align-items: center; gap: 22px; margin-top: 20px; flex-wrap: wrap; }

.countdown {
  font-family: 'BOWLER','Sofia Sans',sans-serif;
  font-size: 56px;
  color: var(--orange);
  line-height: 1;
  margin: 12px 0 20px;
}

/* the fallback line and its button are one block, so the button needs the
   breathing room the panel text does not carry */
#mDone .btn { margin-top: 24px; }

.legal-body { max-height: 46vh; overflow-y: auto; padding-right: 8px; color: #c6c6c6; font-size: 14px; line-height: 1.55; }

/* The bar picks up the orange edge of the modal, so the long documents read as
   part of the same frame. Standard properties on purpose: they keep the system
   behaviour — the bar appears while scrolling and fades at rest — and they are
   the only ones iOS Safari listens to, where ::-webkit-scrollbar does nothing
   and the default bar was black on a black panel. `color-scheme` is the
   fallback for browsers that predate scrollbar-color: no colour of ours, but a
   light system bar instead of an invisible one. */
.legal-body {
  color-scheme: dark;
  scrollbar-width: thin;
  scrollbar-color: var(--orange) transparent;
}
.legal-body h3 { color: var(--white); font-size: 15px; margin: 18px 0 6px; }
.legal-body h4 { color: var(--white); font-size: 14px; margin: 12px 0 4px; }
.legal-body p { margin: 0 0 10px; }
.legal-body ul { margin: 0 0 10px; padding-left: 20px; }
.legal-body li { margin: 0 0 6px; }
.legal-body a { color: var(--orange); text-decoration: underline; }
.legal-body a:hover { text-decoration: none; }
/* the first line of the cookie policy carries its revision date, not body copy */
.legal-body .legal-date { color: #8f8f8f; font-size: 13px; }


/* ============================================================
   COOKIES
   ============================================================ */

/* Fixed to the bottom of the viewport, so the hero reserves the same height as
   padding (border-box) and the fine print never ends up underneath it. */
.cookiebar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 40;
  display: none;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  flex-wrap: wrap;
  padding: 14px clamp(16px, 3vw, 40px);
  background: #0b0b0b;
  border-top: 1px solid rgba(255, 78, 0, .6);
}

.cookiebar.is-active { display: flex; }
.cookiebar p { margin: 0; max-width: 76ch; font: 400 13px/1.5 var(--font-text); color: #c2c2c2; }
.cookiebar .btn { min-height: 44px; font-size: 13px; padding: 0 22px; }


/* ============================================================
   RESPONSIVE
   ============================================================ */

/* --- Landing steps, one block per mockup frame ------------------------- */

@media (min-width: 360px) {
  .landing-hero { --topbar-top: 32px; --body-top: 102px; --gap-title: 12px; --gap-block: 32px; }
  .eyebrow { font: var(--text-m-10su); }
  .hero-title { font: var(--text-m-36); }
  .hero-text { font: var(--text-m-16); }
  .slogans { --slogan-gap: 12px; }
  .slogan { --sl-icon: 24px; --sl-text-pad: 18px; --sl-text-gap: 8px; --sl-text-w: 180px; font: var(--text-t-18); }
}

@media (min-width: 768px) {
  .landing-hero { --pad: 42px; --topbar-top: 88px; --body-top: 56px; --gap-block: 42px; --copy-w: 444px; }
  .topbar__techweek { width: 110px; height: 26px; margin-right: 0; margin-left: auto; }
  .eyebrow { font: var(--text-d-12u); }
  .hero-title { font: var(--text-t-48); }
  .hero-text { font: var(--text-d-18); }
  .slogans { --slogan-gap: 16px; }
}

@media (min-width: 1024px) {
  .landing-hero { --pad: 56px; --topbar-top: 118px; --body-top: 82px; --gap-block: 64px; --copy-w: 661px; --text-w: 485px; }
  .hero-title { font: var(--text-d-72); }
  .slogan { --sl-pad: 12px; --sl-icon: 40px; --sl-text-pad: 28px; --sl-text-w: auto; font: var(--text-d-32u); }
}

@media (min-width: 1440px) {
  .landing-hero { --pad: 28px; --topbar-top: 12px; --body-top: 147px; --gap-title: 8px; --gap-block: 42px; --text-w: 546px; }
  /* from here up the top row becomes a real bar: fixed height, full-bleed
     orange rule underneath */
  .topbar { height: 55px; border-bottom: 1px solid var(--orange); }
  .topbar__logo { display: block; }
  .slogans { --slogan-gap: 28px; }
  /* only here is the row wide enough for the longer wording */
  .slogan__long { display: inline; }
  .slogan__short { display: none; }
}

@media (min-width: 1920px) {
  .landing-hero { --pad: 48px; --topbar-top: 32px; --body-top: 183px; }
  .topbar { height: 91px; }
}

@media (max-width: 900px) {
  #landing { overflow-x: hidden; }
  .grid2 { grid-template-columns: 1fr; }
  .modal__box { padding: 20px 18px 26px; }
  .modal__close { top: 16px; right: 14px; width: 44px; height: 44px; }
  .hero-actions { flex-direction: column; align-items: flex-start; }
  .cookiebar { flex-direction: column; align-items: stretch; }
  .cookiebar .btn { align-self: flex-start; }
}

@media (max-height: 460px) and (orientation: landscape) {
  .landing-hero { min-height: 150vh; }
}

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