/* Bounce Puzzle site. The ground and glows come from the live site
   (website/styles.css); the accent, game pieces and the play screen come from the game
   (src/utils/constants.js, src/screens/GameScreen.js). */
:root {
  --sc-canvas:     #0f0f1a;
  --sc-surface:    #16162a;
  --sc-ink:        #ffffff;
  --sc-ink-soft:   rgba(255, 255, 255, 0.7);
  --sc-accent:     #7c3aed;
  --sc-accent-ink: #ffffff;
  --sc-font-display: "Unbounded", system-ui, sans-serif;
  --sc-font-text:    "Geist", system-ui, sans-serif;

  --indigo: #7c3aed;
  --indigo-light: #a78bfa;
  --purple: #a855f7;
  --ball: #ff6b6b;
  --teal: #4ecdc4;
  --goal: #95e77e;
  --gold: #fbbf24;
  --sticky: #fbbf24;
  --super: #8b5cf6;
  --win: #22c55e;
  --line: rgba(255, 255, 255, 0.08);

  /* The game screen's own values, from GameScreen.js styles. */
  --gs-bg: #1a1a2e;
  --gs-head: rgba(0, 0, 0, 0.4);
  --gs-panel: rgba(255, 255, 255, 0.1);
  --gs-drop: #7f00ff;
  --gs-field: #0a0a18;
  --gs-border: #333;
  --gs-font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, system-ui, sans-serif;
}

html { background: var(--sc-canvas); overflow-x: clip; }
body { background: var(--sc-canvas); color: var(--sc-ink); font-family: var(--sc-font-text); overflow-x: clip; }
main { position: relative; z-index: 1; }

/* ------------------------------------------------------------- ground ---- */
.bg { position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.orb { position: absolute; border-radius: 50%; filter: blur(110px); opacity: 0.22; will-change: transform; }
.orb--indigo { width: 640px; height: 640px; background: var(--indigo); top: -220px; right: -200px; animation: drift-a 22s ease-in-out infinite; }
.orb--teal   { width: 460px; height: 460px; background: var(--teal); bottom: 60px; left: -170px; animation: drift-b 17s ease-in-out infinite; opacity: 0.16; }
.orb--purple { width: 380px; height: 380px; background: var(--purple); bottom: -140px; right: 18%; animation: drift-a 19s ease-in-out infinite reverse; }
.orb--coral  { width: 260px; height: 260px; background: var(--ball); top: 38%; left: 34%; animation: drift-b 25s ease-in-out infinite reverse; opacity: 0.09; }
@keyframes drift-a { 0%, 100% { transform: translate(0, 0); } 50% { transform: translate(40px, -36px); } }
@keyframes drift-b { 0%, 100% { transform: translate(0, 0); } 50% { transform: translate(-30px, 34px) scale(1.06); } }
/* A faint grid of dots, like an empty board, fading out toward the edges. */
.dots {
  position: absolute; inset: 0;
  background-image: radial-gradient(rgba(255, 255, 255, 0.07) 1px, transparent 1.4px);
  background-size: 28px 28px;
  -webkit-mask-image: radial-gradient(ellipse 70% 60% at 50% 40%, #000 30%, transparent 80%);
          mask-image: radial-gradient(ellipse 70% 60% at 50% 40%, #000 30%, transparent 80%);
}

/* --------------------------------------------------------------- top bar -- */
/* The live site's bar: full width, a hairline under it, content held to the
   live site's 1112px. */
.bar {
  position: fixed; z-index: var(--sc-z-chrome); top: 0; left: 0; right: 0;
  padding-top: env(safe-area-inset-top);
  background: rgba(15, 15, 26, 0.72); border-bottom: 1px solid var(--line);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
}
.bar__inner { display: flex; align-items: center; gap: 28px; width: min(100% - 48px, 1112px); height: 64px; margin: 0 auto; }
.bar__title {
  margin-right: auto; display: flex; align-items: center; gap: 10px; text-decoration: none; color: var(--sc-ink);
  font: 700 1rem/1 var(--sc-font-display); letter-spacing: -0.01em;
}
.bar__ball { width: 22px; height: 22px; border-radius: 50%; background: radial-gradient(circle at 35% 32%, #ffb3b3 0 18%, var(--ball) 20%); box-shadow: 0 0 14px rgba(255, 107, 107, 0.6); }
.bar__modes { display: flex; gap: 28px; }
.bar__modes a {
  text-decoration: none; font: 500 0.95rem/1 var(--sc-font-text); color: var(--sc-ink-soft);
  transition: color 150ms var(--sc-ease-out);
}
.bar__modes a:hover { color: var(--sc-ink); }
.bar__cta {
  display: flex; align-items: center; min-height: 40px; padding: 0 18px; border-radius: 999px;
  background: var(--indigo); color: #fff; text-decoration: none; font: 600 0.95rem/1 var(--sc-font-text);
  transition: background-color 150ms var(--sc-ease-out), transform 150ms var(--sc-ease-out);
}
@media (hover: hover) and (pointer: fine) { .bar__cta:hover { background: var(--indigo-light); } }
.bar__cta:active { transform: scale(0.97); }

/* Apple's App Store badge, used as supplied: at least 40px tall, with clear
   space around it. */
.badge { display: inline-block; border-radius: 9px; line-height: 0; transition: transform 150ms var(--sc-ease-out); }
.badge img { height: 54px; width: auto; }
@media (hover: hover) and (pointer: fine) { .badge:hover { transform: translateY(-2px); } }
.badge:active { transform: scale(0.97); }

/* -------------------------------------------------------------- shared -- */
.eyebrow {
  margin: 0; font: 600 0.78rem/1 var(--sc-font-text); letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--indigo-light);
}
.h2 { font: 800 var(--sc-t-2xl)/1.08 var(--sc-font-display); letter-spacing: -0.035em; margin: 0; text-wrap: balance; }
.num { color: var(--teal); }
.num--gold { color: var(--gold); }
.body { font: 400 var(--sc-t-base)/1.62 var(--sc-font-text); color: var(--sc-ink-soft); margin: 0; max-width: 38ch; text-wrap: pretty; }

.cta {
  display: inline-flex; align-items: center; gap: 10px;
  min-height: 54px; padding: 0 28px; border-radius: 999px;
  background: var(--indigo); color: #fff; text-decoration: none;
  font: 700 1rem/1 var(--sc-font-text); white-space: nowrap;
  box-shadow: 0 6px 24px rgba(124, 58, 237, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.2);
  transition: background-color 150ms var(--sc-ease-out), transform 150ms var(--sc-ease-out), box-shadow 150ms var(--sc-ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .cta:hover { background: var(--indigo-light); transform: translateY(-2px); box-shadow: 0 10px 30px rgba(124, 58, 237, 0.55), inset 0 1px 0 rgba(255, 255, 255, 0.2); }
}
.cta:active { transform: scale(0.97); }
.cta__apple { width: 20px; height: 20px; margin-top: -2px; }

/* No double-tap zoom on controls a player taps repeatedly. */
:where(a, button) { touch-action: manipulation; }
:where(a, button, canvas):focus-visible { outline: 2px solid var(--indigo-light); outline-offset: 3px; }

/* The board: the game's darker field. */
.field, .gs-wrap { position: relative; background: var(--gs-field); overflow: hidden; }
.board { display: block; width: 100%; aspect-ratio: 340 / 520; }
.angle {
  position: absolute; left: 0; top: 0; pointer-events: none;
  padding: 3px 7px; border-radius: 6px; background: rgba(15, 15, 26, 0.92);
  font: 600 0.8rem/1 var(--sc-font-text); color: var(--sc-ink);
  transform: translate(-50%, -100%); font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------- the game screen --- */
/* GameScreen.js and DraggableBankItem.js, value for value. The game sizes its
   chrome as s(n) = n * screen width / 375, capped at 1.4 (utils/scale.js);
   here the screen is the .gs or .phone box, so --s is one game point. Text is
   the system font, as React Native draws it. */
.gs, .phone { container-type: inline-size; }
.gs { background: var(--gs-bg); border-radius: 22px; overflow: hidden; box-shadow: 0 0 0 1px var(--line), 0 30px 60px -20px rgba(0, 0, 0, 0.8); }
.gs-head {
  --s: min(calc(100cqw / 375), 1.4px);
  /* Text never drops below the game on a standard 375pt phone, so the small
     showcase frames stay readable; the panels around it still scale. */
  --t: max(var(--s), 1px);
  display: flex; align-items: center; padding: calc(8 * var(--s));
  background: var(--gs-head); color: #fff; font-family: var(--gs-font);
}
.gs-mid { flex: 1; min-width: 0; padding: 0 calc(8 * var(--s)); }
.gs-row { display: flex; align-items: center; justify-content: center; }
.gs-row + .gs-row { margin-top: calc(8 * var(--s)); }
.gs-panel {
  display: flex; align-items: center; justify-content: center; min-width: 0;
  height: calc(28 * var(--s)); background: var(--gs-panel); color: #fff;
}
.gs-name {
  display: block; flex: 0 1 calc(216 * var(--s)); margin-right: calc(6 * var(--s)); padding: 0 calc(8 * var(--s));
  border-radius: calc(6 * var(--s)); text-align: center;
  font-size: calc(12 * var(--t)); font-weight: 600; line-height: calc(28 * var(--s));
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.gs-name--score { font-size: calc(16 * var(--t)); }
.gs-stars { flex: 0 0 calc(64 * var(--s)); border-radius: calc(6 * var(--s)); }
.gs-stars i { font-style: normal; font-size: calc(16 * var(--s)); line-height: 1; color: #374151; transition: color 300ms var(--sc-ease-out); }
.gs-stars i.is-on { color: var(--gold); }
.gs-att { padding: 0 calc(4 * var(--s)); font-size: calc(12 * var(--t)); font-weight: 700; font-variant-numeric: tabular-nums; }
.gs-time { font-size: calc(13 * var(--t)); font-weight: 700; font-variant-numeric: tabular-nums; }
.gs-time.is-low { color: #ef4444; }
.gs-hearts { display: flex; }
.gs-hearts svg { width: calc(14 * var(--s)); height: calc(14 * var(--s)); }
.gs-bank {
  flex: 0 1 calc(216 * var(--s)); flex-wrap: wrap; margin-right: calc(6 * var(--s)); padding: 0 calc(4 * var(--s));
  border-radius: calc(8 * var(--s));
}
.gs-chip {
  display: inline-flex; align-items: center; margin: calc(2 * var(--s)) calc(3 * var(--s));
  padding: calc(4 * var(--s)) calc(8 * var(--s)); border: 0; border-radius: calc(6 * var(--s));
  background: rgba(255, 255, 255, 0.1); color: #fff;
  font-family: var(--gs-font); font-size: calc(10 * var(--t)); font-weight: 700; line-height: 1.2;
}
.gs-chip.is-empty, button.gs-chip:disabled { opacity: 0.3; }
/* The Challenge and Endless showcase phones always show every platform
   placed, so their chips are always empty; lifted from the game's 0.3 so the
   bank still reads at a glance. Level 102 keeps the game's value. */
.phone .gs-chip.is-empty { opacity: 0.55; }
button.gs-chip { cursor: grab; touch-action: none; }
button.gs-chip:disabled { cursor: default; }
/* The bank bar: 24x8 with a 1px rim in its own colour, and PlatformMark's
   chevron, up for super and down for sticky. */
.pill {
  position: relative; box-sizing: border-box; width: calc(24 * var(--s)); height: calc(8 * var(--s));
  margin-right: calc(4 * var(--s)); border: 1px solid var(--teal); border-radius: calc(4 * var(--s)); background: var(--teal);
}
.pill--sticky { background: var(--sticky); border-color: var(--sticky); }
.pill--super { background: var(--super); border-color: var(--super); }
.pill--sticky::after, .pill--super::after {
  content: ''; position: absolute; left: 50%; top: 50%; box-sizing: border-box; height: 58%; aspect-ratio: 1;
  border-top: calc(2 * var(--s)) solid rgba(255, 255, 255, 0.9); border-right: calc(2 * var(--s)) solid rgba(255, 255, 255, 0.9);
}
.pill--super::after { transform: translate(-50%, -50%) translateY(12%) rotate(-45deg); }
.pill--sticky::after { transform: translate(-50%, -50%) translateY(-12%) rotate(135deg); }
.gs-drop {
  flex-shrink: 0; padding: calc(6 * var(--s)) calc(12 * var(--s)); border: 0; border-radius: calc(8 * var(--s));
  background: var(--gs-drop); color: #fff;
  font-family: var(--gs-font); font-size: calc(14 * var(--t)); font-weight: 700; line-height: 1.2;
  transition: opacity 150ms var(--sc-ease-out), background-color 150ms var(--sc-ease-out);
}
/* Greyed while the ball is in play, as the game does outside setup. */
.gs-drop:disabled, .gs-drop.is-off { opacity: 0.4; background: #666; }
/* TouchableOpacity's press: the control fades to 0.2. */
.gs-drop.is-pressed, .gs-drop--live:active:not(:disabled), .gs-circle:active:not(:disabled) { opacity: 0.2; }
.gs-drop--live { cursor: pointer; }
.gs-drop--live:disabled { cursor: default; }
.gs-circle {
  flex-shrink: 0; display: grid; place-items: center; width: calc(32 * var(--s)); height: calc(32 * var(--s));
  padding: 0; border: 0; border-radius: 50%; background: var(--gs-panel); color: #fff; cursor: pointer; text-decoration: none;
  font-family: var(--gs-font); font-size: calc(18 * var(--s)); line-height: 1;
  transition: opacity 150ms var(--sc-ease-out);
}
.gs-circle--retry { font-size: calc(20 * var(--s)); }
span.gs-circle { cursor: default; }
.gs-circle:disabled { opacity: 0.4; cursor: default; }
.gs-wrap { margin: 8px; border: 1px solid var(--gs-border); border-radius: 8px; }

/* ------------------------------------------------------------- 1 · hero -- */
/* One copy block (title, pitch, Apple's badge) and the phone, which is the
   focal point, playing a real level. Behind them a quiet scene from the
   game's world (lab/hero-art.mjs draws it): sky and a few gold stars, large
   faint spikes on the horizon, two darker spikes at the edges, then low
   hills that overlap the phone's foot. Each plane drifts at its own rate as
   the hero scrolls away (data-sc-parallax). Phones stack copy over the
   phone; wide screens put them side by side. */
.hero {
  --gx: 50%;
  position: relative; min-height: max(100svh, 700px); overflow: clip; isolation: isolate;
  display: flex; flex-direction: column; align-items: center; text-align: center;
  padding: calc(64px + env(safe-area-inset-top) + clamp(8px, 1.6svh, 24px)) 16px 24px;
}
/* The bottom fades out so the hills dissolve into the page's ground and
   glows below, with no seam. The back fades first and higher, so nothing
   behind the hills shows through while they fade. */
.scene {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  -webkit-mask-image: linear-gradient(#000 calc(100% - 170px), transparent calc(100% - 70px));
          mask-image: linear-gradient(#000 calc(100% - 170px), transparent calc(100% - 70px));
}
.scene--front {
  z-index: 3;
  -webkit-mask-image: linear-gradient(#000 calc(100% - 90px), transparent);
          mask-image: linear-gradient(#000 calc(100% - 90px), transparent);
}
.sky {
  position: absolute; inset: 0;
  background:
    radial-gradient(ellipse 46% 34% at var(--gx) 80%, rgba(124, 58, 237, 0.42), transparent 72%),
    linear-gradient(180deg, #0f0f1a 0%, #13132a 46%, #1a1a2e 78%, #0f0f1a 100%);
}
.plane { position: absolute; left: 0; right: 0; }
.plane svg { display: block; width: 100%; height: 100%; }
/* Each plane holds two drawings: narrow (phones, tablets) and wide. */
.layer--wide { display: none !important; }
.plane--sky { top: 0; height: 100%; }
.plane--far { bottom: 0; height: 71%; }
.plane--mid { bottom: 0; height: 50%; }
/* The near hills run 40px past the bottom so rising with the scroll never
   opens a gap; that strip is the page's own ground colour. */
.plane--near { bottom: -60px; height: calc(26% + 60px); border-bottom: 60px solid var(--sc-canvas); box-sizing: border-box; }
@media (prefers-reduced-motion: no-preference) {
  .tw { animation: twinkle 3.8s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
  .tw--1 { animation-delay: -1.3s; animation-duration: 4.6s; }
  .tw--2 { animation-delay: -2.4s; animation-duration: 5.4s; }
}
@keyframes twinkle { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.35; transform: scale(0.8); } }

.hero__copy { position: relative; z-index: 4; display: grid; justify-items: center; }
/* The game's own title (MenuScreen and the launch splash): BOUNCE in white
   over PUZZLE in the title violet, the same size, system font at 900 with
   letter spacing 2 at 52pt. The game's -10 top margin on PUZZLE puts the
   lines one font size apart, which line-height 1 reproduces. Real text, so
   the heading reads "Bounce Puzzle". */
.logo {
  --logo: clamp(2.6rem, 1.3rem + 5.6vw, 4.4rem);
  margin: 0; display: grid; justify-items: inherit;
  font: 900 var(--logo)/1 -apple-system, BlinkMacSystemFont, "SF Pro Display", system-ui, sans-serif;
  letter-spacing: 0.04em; text-transform: uppercase;
}
/* The spacing trails the last letter, so pull it back to keep the words centred. */
.logo__a, .logo__b { margin-right: -0.04em; }
.logo__a { color: #ffffff; }
.logo__b { color: #8b5cf6; }
.hero__lede {
  margin: clamp(10px, 1.8svh, 24px) 0 0; max-width: 34ch; text-wrap: balance;
  font: 500 clamp(1rem, 0.94rem + 0.36vw, 1.3rem)/1.45 var(--sc-font-text); color: var(--sc-ink);
}
.hero__lede span { font-weight: 400; color: var(--sc-ink-soft); }
.hero__badge { margin-top: clamp(12px, 2svh, 28px); }
.hero__badge img { height: 52px; }

.hero__stage {
  position: relative; z-index: 2; flex-shrink: 0;
  /* As wide as the screen's height allows, so the whole phone sits above
     the fold on a tall phone and the header reads at a glance. */
  width: clamp(280px, calc((max(100svh, 700px) - 320px) / 1.74), min(90vw, 350px));
  margin-top: clamp(12px, 1.8svh, 24px);
}
.hero__tilt { position: relative; transform-style: preserve-3d; }
/* The phone: the game's own screen, header and board, in the site's phone
   body, with a violet glow under it. */
.device {
  container-type: inline-size; position: relative; padding: 9px; border-radius: 38px;
  background: linear-gradient(135deg, #2a2a4a, #1a1a2e);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.1), 0 40px 90px -20px rgba(124, 58, 237, 0.55), 0 24px 50px -18px rgba(0, 0, 0, 0.95);
}
/* On a phone the device is small, so the header's text keeps a 1.15x floor
   over the game's own size, capped so the title never truncates (the panels still scale with the screen). */
.device > .gs-head { --t: max(1px, min(1.15px, calc(var(--s) * 1.4))); }
.device > .gs-head { border-radius: 29px 29px 0 0; background: linear-gradient(var(--gs-head), var(--gs-head)), var(--gs-bg); padding-top: 12px; }
.device > .field { border-radius: 0 0 29px 29px; }
/* On a phone the text floor makes the bank's chips wider than the game's, so
   a third chip used to wrap out of sight. Tighter chip spacing keeps every
   counter the level hands out on one line, as in the game. */
@container (max-width: 360px) {
  .device .gs-bank { flex-wrap: nowrap; padding: 0 calc(2 * var(--s)); }
  .device .gs-chip { margin: calc(2 * var(--s)) calc(1.5 * var(--s)); padding: calc(4 * var(--s)) calc(5 * var(--s)); }
  .device .gs-drop { padding: calc(6 * var(--s)) calc(10 * var(--s)); }
}
/* A still of the hero board's first frame, shown while the game code loads
   on a slow connection; the live board paints over it. Regenerate it if the
   hero level changes. */
[data-hero] { background: var(--gs-field) url("assets/poster-hero.webp") center / 100% 100% no-repeat; }

/* Wide screens: copy and phone side by side, the phone at full height. */
@media (min-width: 1024px) and (min-height: 640px) {
  .hero {
    --gx: 64%;
    flex-direction: row; justify-content: center; align-items: center; gap: clamp(48px, 7vw, 132px);
    text-align: left; height: 100svh; min-height: 680px; padding: 64px 48px 0;
  }
  .hero__copy { justify-items: start; flex: 0 1 560px; margin-top: -2svh; }
  .logo { --logo: clamp(4rem, 1rem + 4.6vw, 6rem); }
  .hero__lede { max-width: 30ch; text-wrap: pretty; }
  .hero__badge img { height: 56px; }
  .hero__stage { width: clamp(300px, calc((100svh - 150px) / 1.78), 430px); margin-top: 0; }
  .layer--wide { display: block !important; }
  .layer--narrow { display: none !important; }
  .plane--far { height: 52%; }
  .plane--mid { height: 46%; }
  .plane--near { height: calc(30% + 60px); }
}

/* ---------------------------------------------------------- 2 · how ----- */
.how__stage {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, clamp(360px, 25vw, 520px));
  align-items: center; gap: var(--sc-8);
  padding: 80px var(--sc-gutter) 24px; max-width: 72rem; margin: 0 auto;
}
.how__steps { position: relative; min-height: 13rem; }
.step {
  position: absolute; inset: 0 auto auto 0; margin: 0;
  font: 500 var(--sc-t-xl)/1.3 var(--sc-font-text); color: var(--sc-ink-soft); max-width: 18ch;
}
.step__k { display: block; font: 900 var(--sc-t-3xl)/1 var(--sc-font-display); letter-spacing: -0.05em; margin-bottom: 12px; }
.step--teal .step__k { color: var(--teal); }
.step--indigo .step__k { color: var(--indigo-light); }
.step--violet .step__k { color: #a78bfa; }
.step--green .step__k { color: var(--goal); }
.how__game { width: 100%; position: relative; }
.how__game .field--how { width: min(100% - 16px, calc((100svh - 300px) * 340 / 520)); margin: 8px auto 0; }
/* Four bars that fill as the steps pass. */
.how__prog { position: absolute; left: 0; bottom: 0; display: flex; gap: 6px; margin: 0; padding: 0; list-style: none; }
.how__prog li { width: 34px; height: 5px; border-radius: 3px; background: rgba(255, 255, 255, 0.14); transition: background-color 200ms var(--sc-ease-out); }
.how__prog li.is-on { background: var(--teal); }
.how__prog li.is-now { background: var(--sc-ink); }
/* What the pieces are: one line under the board. */
.legend {
  display: flex; justify-content: center; flex-wrap: wrap; gap: 6px 18px; margin: 0; padding: 10px 8px 12px; list-style: none;
  font: 500 0.88rem/1.2 var(--sc-font-text); color: var(--sc-ink-soft);
}
.legend li { display: inline-flex; align-items: center; gap: 7px; }
.legend i { flex-shrink: 0; display: inline-block; font-style: normal; }
.legend__ball { width: 12px; height: 12px; border-radius: 50%; background: var(--ball); box-shadow: 0 0 8px rgba(255, 107, 107, 0.6); }
.legend__goal { width: 13px; height: 13px; border-radius: 4px; background: var(--goal); }
.legend__star { color: var(--gold); font-size: 1rem; line-height: 1; }
/* The ghost finger: a soft touch mark that does each step. site.js moves it
   with transform; its centre is the touch point. */
.finger {
  position: absolute; left: -22px; top: -22px; width: 44px; height: 44px; border-radius: 50%; pointer-events: none; opacity: 0;
  background: radial-gradient(circle, rgba(255, 255, 255, 0.55) 0 30%, rgba(255, 255, 255, 0.18) 32% 62%, transparent 64%);
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.7);
  transition: box-shadow 120ms var(--sc-ease-out);
}
.finger.is-press { box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.95), 0 0 0 8px rgba(255, 255, 255, 0.12); }

/* --------------------------------------------------------- 3 · worlds --- */
.worlds__stage { display: flex; align-items: center; }
.rail { display: flex; align-items: center; gap: clamp(20px, 3vw, 40px); padding: 0 var(--sc-gutter); width: max-content; }
.rail__lead { width: clamp(16rem, 28vw, 25rem); display: grid; gap: var(--sc-4); }
.rail__end { width: clamp(12rem, 20vw, 17rem); }
.rail__then { margin: 0; font: 800 var(--sc-t-xl)/1.2 var(--sc-font-display); letter-spacing: -0.03em; }
/* Cards sized by the screen height (Cheng, 2026-10-14): the board fills all
   but 230px of it, up to 520px wide and 80% of the width on phones. */
.world { width: min(80vw, 520px, calc((100svh - 230px) * 340 / 520)); display: grid; gap: 12px; }
.world .field { border-radius: 14px; box-shadow: 0 0 0 1px var(--world, var(--line)), 0 18px 40px -16px var(--world-glow, transparent); }
.world__label { display: flex; align-items: baseline; gap: 10px; }
.world__n { margin: 0; font: 800 1.2rem/1 var(--sc-font-display); letter-spacing: -0.03em; }
.world__theme { font: 600 0.92rem/1 var(--sc-font-text); color: var(--world, var(--sc-ink-soft)); }
.world__swatch { display: none; }
/* Which world is in the middle: a dot per world in its colour, and "3 / 8". */
.rail__count {
  position: absolute; left: 50%; bottom: max(18px, 3svh); transform: translateX(-50%);
  display: flex; align-items: center; gap: 7px; margin: 0; padding: 8px 14px; border-radius: 999px;
  background: var(--card-bg); box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08);
  font: 600 0.9rem/1 var(--sc-font-text); color: var(--sc-ink); font-variant-numeric: tabular-nums;
  transition: opacity 200ms var(--sc-ease-out);
}
.rail__count.is-hidden { opacity: 0; }
.rail__count i { width: 7px; height: 7px; border-radius: 50%; background: var(--world); opacity: 0.35; transition: opacity 150ms var(--sc-ease-out), transform 150ms var(--sc-ease-out); }
.rail__count i.is-on { opacity: 1; transform: scale(1.35); }
.rail__count span { min-width: 3.2em; margin-left: 4px; text-align: right; }

/* ---------------------------------------------------------- 4 · modes --- */
.modes { padding: clamp(3rem, 6vw, 6rem) var(--sc-gutter) var(--sc-7); }
/* Two even columns: the text cards share one row height and the phones line
   up beneath them (subgrid). */
.modes__grid { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: auto auto; column-gap: clamp(2rem, 5vw, 5rem); row-gap: var(--sc-5); max-width: 66rem; margin: 0 auto; }
.mode { display: grid; grid-row: span 2; grid-template-rows: subgrid; gap: var(--sc-5); scroll-margin-top: 90px; }
.mode .phone { justify-self: center; }
.mode__text { display: grid; gap: var(--sc-4); align-content: start; }
.switch__hint { margin: 0; font: 500 var(--sc-t-sm)/1.3 var(--sc-font-text); color: var(--sc-ink-soft); }
.modes__get { display: grid; justify-items: center; gap: var(--sc-4); margin-top: var(--sc-8); text-align: center; }
.phone {
  width: min(100%, clamp(300px, 23vw, 430px), max(300px, calc((100svh - 330px) * 0.58))); padding: 10px; border-radius: 40px;
  background: linear-gradient(135deg, #2a2a4a, #1a1a2e);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08), 0 36px 70px -26px rgba(168, 85, 247, 0.4), 0 20px 40px -20px rgba(0, 0, 0, 0.9);
}
.phone > .gs-head { border-radius: 30px 30px 0 0; background: linear-gradient(var(--gs-head), var(--gs-head)), var(--gs-bg); padding-top: 14px; }
.phone > .gs-wrap { margin: 0; border-radius: 0 0 30px 30px; border: 0; }
.switch { display: inline-flex; gap: 4px; padding: 4px; background: rgba(255, 255, 255, 0.06); border: 1px solid var(--line); border-radius: 999px; justify-self: start; }
.switch button {
  min-height: 44px; padding: 0 16px; border: 0; border-radius: 999px; background: transparent;
  font: 600 0.9rem/1 var(--sc-font-text); color: var(--sc-ink-soft); cursor: pointer;
  transition: background-color 150ms var(--sc-ease-out), color 150ms var(--sc-ease-out);
}
.switch button:hover { color: var(--sc-ink); }
.switch button[aria-checked="true"] { background: var(--indigo); color: #fff; box-shadow: 0 4px 14px rgba(124, 58, 237, 0.45); }
.switch button:active { transform: scale(0.97); }

/* ----------------------------------------------------------- 6 · play --- */
/* Follows Endless closely: a short lead-in, then the board. */
.play { display: grid; place-items: center; align-content: center; gap: 14px; padding: var(--sc-7) 16px 32px; scroll-margin-top: 64px; }
/* Says the board is playable, above it so it never covers the board. */
.play__lead { display: grid; justify-items: center; gap: 4px; text-align: center; }
.play__title { margin: 0; font: 800 var(--sc-t-lg)/1.2 var(--sc-font-display); letter-spacing: -0.02em; color: var(--teal); }
.play__hint { margin: 0; max-width: 34ch; text-wrap: balance; font: 400 1rem/1.4 var(--sc-font-text); color: var(--sc-ink-soft); }
/* Focusing a control here scrolls it clear of the fixed top bar. */
.play :where(a, button, canvas) { scroll-margin-top: 80px; }
.play__inner { width: min(100%, clamp(460px, 30vw, 580px), calc((100svh - 270px) * 340 / 520 + 16px)); min-width: min(100%, 300px); }
.field--play { touch-action: none; }
.board--play { cursor: grab; }
.board--play.is-dragging { cursor: grabbing; }
.toast {
  position: absolute; left: 50%; top: 14px; transform: translateX(-50%);
  padding: 8px 14px; border-radius: 8px; background: rgba(15, 15, 26, 0.94);
  font: 500 0.88rem/1.2 var(--sc-font-text); color: var(--sc-ink); white-space: nowrap;
  opacity: 0; transition: opacity 200ms var(--sc-ease-out); pointer-events: none;
}
.toast.is-on { opacity: 1; }

/* The game's Level Complete popup. */
.win {
  position: absolute; left: 7%; right: 7%; top: 50%; transform: translateY(-50%);
  padding: 26px 18px 20px; border-radius: 22px;
  background: #0a1f12; border: 1.5px solid var(--win);
  display: grid; justify-items: center; gap: 12px; text-align: center;
  box-shadow: 0 24px 48px -12px rgba(0, 0, 0, 0.7);
}
.win[hidden] { display: none; }
.win__stars { display: flex; gap: 14px; }
.win__stars span { width: 46px; height: 46px; background: #374151; clip-path: polygon(50% 0, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%); }
.win__stars span.is-on { background: var(--gold); }
.win__title { margin: 4px 0 0; font: 800 1.7rem/1.1 var(--sc-font-text); letter-spacing: -0.02em; }
.win__note { margin: 0; font: 400 0.95rem/1.45 var(--sc-font-text); color: #c5d6ca; max-width: 24ch; }
.win__actions { display: flex; gap: 10px; margin-top: 6px; }
.win__btn {
  min-height: 48px; padding: 0 24px; border-radius: 16px; border: 0;
  display: inline-flex; align-items: center; text-decoration: none;
  background: #34483b; color: #fff; font: 700 1.05rem/1 var(--sc-font-text); cursor: pointer;
  transition: background-color 150ms var(--sc-ease-out), transform 120ms var(--sc-ease-out);
}
.win__btn:hover { background: #3f5747; }
.win__btn--next { background: var(--win); }
.win__btn--next:hover { background: #2fd567; }
.win__btn:active { transform: scale(0.97); }
@media (prefers-reduced-motion: no-preference) {
  .win:not([hidden]) { animation: win-in 320ms var(--sc-ease-out); }
  .win__stars span.is-on { animation: star-in 360ms var(--sc-ease-out) backwards; }
  .win__stars span:nth-child(2).is-on { animation-delay: 120ms; }
  .win__stars span:nth-child(3).is-on { animation-delay: 240ms; }
}
@keyframes win-in { from { opacity: 0; transform: translateY(-50%) scale(0.95); } }
@keyframes star-in { from { opacity: 0; transform: scale(0.95) rotate(-12deg); } }

/* ---------------------------------------------------------- 7 · close --- */
/* The close follows the level closely and the footer follows the close. */
.close { display: grid; gap: var(--sc-9); padding: var(--sc-8) var(--sc-gutter) 0; }
.close__inner { display: grid; justify-items: center; align-content: center; gap: var(--sc-5); text-align: center; }
.close__icon { width: 128px; height: 128px; border-radius: 29px; box-shadow: 0 0 48px rgba(124, 58, 237, 0.4), var(--sc-e2); }
.close__line { margin: 0; font: 800 clamp(2.1rem, 1.5rem + 1.8vw, 3rem)/1.1 var(--sc-font-display); letter-spacing: -0.04em; }
.close .badge { margin-top: calc(var(--sc-5) * 0.3); }
.close .badge img { height: 64px; }
.close__note { margin: calc(var(--sc-5) * -0.4) 0 0; font: 400 0.95rem/1.4 var(--sc-font-text); color: var(--sc-ink-soft); }

/* A product footer: name, maker, contact, legal links. */
.foot {
  display: grid; grid-template-columns: 1fr auto; align-items: center; gap: var(--sc-5) var(--sc-7);
  width: 100%; max-width: 66rem; margin: 0 auto; padding: var(--sc-6) 0 calc(var(--sc-6) + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line); font: 400 0.95rem/1.4 var(--sc-font-text); color: var(--sc-ink-soft);
}
.foot p { margin: 0; }
.foot__brand { display: flex; align-items: center; gap: 14px; }
.foot__icon { width: 44px; height: 44px; border-radius: 10px; }
.foot__name { font: 800 1.05rem/1.2 var(--sc-font-display); letter-spacing: -0.02em; color: var(--sc-ink); }
.foot__links { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 0 22px; }
.foot__links a { display: inline-flex; align-items: center; min-height: 44px; color: var(--sc-ink); text-decoration: underline; text-decoration-color: rgba(255, 255, 255, 0.3); text-underline-offset: 4px; }
@media (hover: hover) and (pointer: fine) { .foot__links a:hover { text-decoration-color: currentColor; } }
.foot__legal { grid-column: 1 / -1; font-size: 0.85rem; }
/* "Support" names the address; inline-block keeps the link underline off it. */
.foot__label { display: inline-block; margin-right: 8px; color: var(--sc-ink-soft); }
/* The game's accounts, where most visitors arrive from. */
.foot__social { grid-column: 2; display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 0 22px; }
.foot__social a { display: inline-flex; align-items: center; min-height: 44px; color: var(--sc-ink-soft); text-decoration: underline; text-decoration-color: rgba(255, 255, 255, 0.25); text-underline-offset: 4px; }
@media (hover: hover) and (pointer: fine) { .foot__social a:hover { color: var(--sc-ink); text-decoration-color: currentColor; } }
/* The download action right after the playable level. */
.play__badge { margin-top: 8px; }

/* -------------------------------------------------------- gaps: drift -- */
/* Drifting levels, picked from style-design set bp-gaps on 2026-10-12.
   Solved levels from the other worlds float in the margins of the gaps below
   Endless and level 102, tilted and at three depths. Cheng dropped the loose
   platforms between them on 2026-10-14. Parallax is the page's own data-sc-parallax, so tilts use
   the rotate and scale properties rather than transform. */
:root {
  --drift-opacity: 0.28;
  --drift-w: clamp(120px, 13vw, 210px);
  --drift-blur: 1px;
}
.gap { position: relative; height: 0; z-index: 0; pointer-events: none; }
.drift { position: absolute; width: var(--drift-w); aspect-ratio: 340 / 520; border-radius: 12px; opacity: var(--drift-opacity); filter: blur(var(--drift-blur)) saturate(0.9); box-shadow: 0 30px 60px -24px rgba(0, 0, 0, 0.9); }
.drift--near { width: calc(var(--drift-w) * 1.2); opacity: calc(var(--drift-opacity) * 1.4); filter: none; }
.drift--far { width: calc(var(--drift-w) * 0.7); opacity: calc(var(--drift-opacity) * 0.7); filter: blur(calc(var(--drift-blur) * 2.5)); }

/* ------------------------------------------------- text: game panels -- */
/* Game panels, picked from style-design set bp-text on 2026-10-12. Words sit
   on the game's own surfaces: dark cards like the game screen, headings in a
   translucent title panel like the level name, and each step's key word as a
   chip in its colour, DROP set as the game's DROP button. */
:root {
  --card-bg: rgba(26, 26, 46, 0.78);
  --card-radius: 22px;
  --card-pad: 1.6rem;
  --panel-bg: rgba(255, 255, 255, 0.1);
}
.mode__text, .rail__lead {
  padding: var(--card-pad); border-radius: var(--card-radius); background: var(--card-bg);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08), 0 24px 50px -24px rgba(0, 0, 0, 0.9);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
}
.mode__text .h2, .rail__lead .h2 { justify-self: start; padding: 0.18em 0.45em 0.22em; border-radius: 0.28em; background: var(--panel-bg); }
.rail__then { padding: var(--card-pad); border-radius: var(--card-radius); background: var(--card-bg); box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08); }
.step__k {
  width: fit-content; padding: 0.12em 0.32em 0.16em; border-radius: 0.22em; color: #0a0a18 !important;
  box-shadow: 0 0.12em 0.5em -0.1em var(--chip);
}
.step--teal .step__k { --chip: var(--teal); background: var(--chip); }
.step--indigo .step__k { --chip: var(--indigo-light); background: var(--chip); }
.step--violet .step__k { --chip: var(--gs-drop); background: var(--chip); color: #fff !important; font-family: var(--gs-font); font-weight: 800; letter-spacing: 0; }
.step--green .step__k { --chip: var(--goal); background: var(--chip); }

/* --------------------------------------------------------------- phone -- */
@media (max-width: 860px) {
  /* Around level 102 a phone has no clear spot for the drifting levels:
     every place they fit covers "Try it.", the board or the closing card. */
  .gap--a, .gap--c { display: none; }
  .bar__modes { display: none; }
  .bar__cta { min-height: 44px; }

  .orb--indigo { width: 420px; height: 420px; }

  /* How it plays: the step word big, the progress bars to its right, and
     the board straight under it. */
  .how__stage { grid-template-columns: 1fr; gap: 10px; padding-top: 78px; align-content: start; }
  .how__steps { min-height: 7.4rem; }
  .step { font-size: 1.05rem; max-width: none; }
  .step__k { font-size: 2.5rem; margin-bottom: 6px; }
  .how__prog { left: auto; right: 0; top: 2px; bottom: auto; }
  .how__prog li { width: 22px; }
  .how__game { max-width: 340px; margin: 0 auto; }
  .how__game .field--how { width: min(100% - 16px, calc((100svh - 400px) * 340 / 520)); }
  .legend { font-size: 0.82rem; gap: 4px 14px; padding: 8px 6px 10px; }

  /* Worlds: the intro, every world and the last card each get the screen to
     themselves, centred, as large as the height allows. */
  .rail { gap: 16px; }
  .rail__lead, .rail__end { width: calc(100vw - 2 * var(--sc-gutter)); box-sizing: border-box; }
  .world { width: min(100vw - 2 * var(--sc-gutter), calc((100svh - 250px) * 340 / 520)); }
  .worlds__stage { padding: calc(64px + env(safe-area-inset-top)) 0 60px; box-sizing: border-box; }
  .world__label { flex-wrap: wrap; row-gap: 4px; }
  .world__n { font-size: 1.45rem; }
  .world__theme { font-size: 1.05rem; }

  /* Challenge and Endless: each phone fits the screen with its text. */
  .modes__grid { grid-template-columns: 1fr; grid-template-rows: none; row-gap: var(--sc-8); }
  .mode { grid-row: auto; grid-template-rows: none; }
  .phone { width: min(100%, max(220px, calc((100svh - 360px) * 0.56))); }
  .mode__text { --card-pad: 1.15rem; gap: 12px; }
  .modes__get { margin-top: var(--sc-7); }

  .play { padding: var(--sc-6) 8px 24px; gap: 10px; }
  .play__hint { font-size: 0.95rem; padding: 0 8px; }
  .close { padding-top: var(--sc-6); gap: var(--sc-8); }
  .foot { grid-template-columns: 1fr; }
  .foot__links { justify-content: flex-start; flex-direction: column; }
  .foot__social { grid-column: 1; justify-content: flex-start; }
}

/* Small phones: a world's name and theme wrap inside its card instead of
   running under the next one. */
@media (max-width: 400px) {
  .world__label { flex-wrap: wrap; row-gap: 4px; }
}

@media (prefers-reduced-motion: reduce) {
  .orb { animation: none; }
}

/* Tablets, 600 to 860 wide with the height to pin: still the stacked phone
   layout, but the hero phone, the demo board and the step words grow with the
   width so each meets its desktop size at 861 instead of jumping there. */
@media (min-width: 600px) and (max-width: 860px) and (min-height: 501px) {
  .how__game { max-width: clamp(320px, calc(15vw + 230px), 360px); }
  .step { font-size: clamp(1rem, calc(5.85vw - 18.4px), 2rem); }
  .step__k { font-size: clamp(1.8rem, calc(14.54vw - 58.4px), 4.2rem); }
  .rail__lead { width: 16rem; }
  .rail__end { width: 12rem; }
}

/* Without motion, and on a phone held sideways (Cheng's pick, option C), the
   page reads straight down. The worlds rail becomes a grid, every world at
   once, and how it plays is not pinned: all four steps show and the board
   shows the finished drop (site.js). */
@media (prefers-reduced-motion: reduce), (orientation: landscape) and (max-height: 500px) {
  .worlds { height: auto !important; }
  .worlds [data-sc-stage] { position: static !important; height: auto !important; overflow: visible !important; padding: var(--sc-8) 0; }
  .worlds .rail { width: auto; flex-wrap: wrap; justify-content: center; align-items: start; row-gap: var(--sc-7); }
  .worlds .rail__lead, .worlds .rail__end { width: 100%; max-width: 66rem; }
  .how { height: auto !important; }
  .how [data-sc-stage] { position: static !important; height: auto !important; }
  .how__steps { min-height: 0; display: grid; gap: var(--sc-5); }
  .how .step { position: static; opacity: 1 !important; transform: none !important; }
  .how__prog, .finger, .rail__count { display: none !important; }
  .worlds__stage { padding-top: var(--sc-8) !important; }
  .worlds .rail { transform: none !important; }
}

/* Phone held sideways: too short to play level 102, so the board steps aside
   for a line asking to turn upright, where it fits. The board keeps its state
   underneath. Boards that only need to be seen are sized to the width. */
.turn { display: none; }
@media (orientation: landscape) and (max-height: 500px) {
  .hero { height: auto; min-height: 0; padding-bottom: 72px; }
  .logo { --logo: 3.4rem; }
  .hero__stage { width: 250px; }
  .device > .gs-head { --t: max(var(--s), 1px); }
  .how__game { max-width: 320px; margin: 0 auto; }
  .how__game .field--how { width: calc(100% - 16px); }
  .world { width: min(30vw, 260px); }
  .play__inner, .play__lead, .play__badge { display: none; }
  .phone { width: min(100%, 300px); }
  .turn {
    display: grid; justify-items: center; gap: var(--sc-5); max-width: 32rem; text-align: center;
    padding: calc(var(--card-pad) * 1.2) var(--card-pad); border-radius: var(--card-radius); background: var(--card-bg);
    box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08);
  }
  .turn__line { margin: 0; font: 800 var(--sc-t-xl)/1.15 var(--sc-font-display); letter-spacing: -0.03em; text-wrap: balance; }
}
