/* ===================== PLAYER (mobile) =====================
   Dark EWC mobile layout — brand render behind the join card, GEAR type,
   gold/orange accents. ========================================= */

/* The phone shell is LOCKED to the viewport: iOS Safari happily scrolls the
   document past `overflow:hidden` on body (e.g. after the nickname keyboard
   opens), leaving the page shifted down with dead space below. position:fixed
   is the one reliable lock — inner regions (whodle history, leaderboards)
   still scroll inside their own overflow containers. play.js additionally
   snaps window scroll back to 0 on scene changes + keyboard close. */
html {
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
}
.play-body {
  position: fixed;
  inset: 0;
  width: 100%;
  overflow: hidden;
  height: 100vh;
  height: 100dvh;
  overscroll-behavior: none;
  touch-action: manipulation;
  -webkit-user-select: none;
  user-select: none;
}

/* ---------- Toast ---------- */
.toast {
  position: fixed;
  top: calc(env(safe-area-inset-top) + 14px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 100;
  background: var(--surface-2);
  border: 1px solid var(--line);
  padding: 10px 18px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 600;
  box-shadow: var(--shadow);
  animation: fadeUp 0.3s both;
  max-width: 90vw;
  text-align: center;
}
.toast.error { border-color: var(--danger); color: var(--danger-soft); }
.toast.success { border-color: var(--success); color: #7ee2a0; }

/* Shared recovery layer; the last frame stays visible but cannot take actions. */
.player-connection[hidden] { display:none; }
.player-connection {
  position:fixed; inset:0; z-index:120; display:grid; place-items:center;
  padding:calc(env(safe-area-inset-top) + 24px) 24px calc(env(safe-area-inset-bottom) + 24px);
  background:rgba(var(--tint-ink),.78); overflow:auto;
}
.player-connection-card {
  width:100%; max-width:360px; display:grid; justify-items:center; gap:22px;
  padding:28px 24px; border:1px solid var(--line-strong); border-radius:20px;
  background:var(--surface-2); box-shadow:var(--shadow); text-align:center;
  animation:connectionCardIn 180ms ease-out both;
}
.player-connection-icon { width:36px; height:36px; color:var(--text); }
.player-connection-card h2 { margin:0; font:700 24px/1.2 var(--font-body); overflow-wrap:anywhere; }
.player-connection-card p { margin:12px 0 0; font:400 15px/1.5 var(--font-body); color:var(--text-dim); }
.player-connection-card .btn { width:100%; min-height:48px; white-space:normal; }
.game-screen.connection-paused { pointer-events:none; }
.game-screen.connection-paused * { animation-play-state:paused !important; }
@keyframes connectionCardIn { from { opacity:0; transform:translateY(8px); } to { opacity:1; transform:translateY(0); } }
@media(prefers-reduced-motion:reduce) { .player-connection-card { animation:none; } }

/* ---------- Join screen ---------- */
.join-screen {
  position: relative;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 22px;
  gap: 18px;
}
/* Brand 3D render atmosphere behind the join card. */
.join-screen::before {
  content: '';
  position: fixed; inset: 0; z-index: 0;
  background: var(--brand-bgPhone) center/cover no-repeat;
  opacity: 0.4;
}
.join-screen::after {
  content: '';
  position: fixed; inset: 0; z-index: 0;
  background:
    radial-gradient(700px 500px at 70% 0%, rgba(var(--tint-orange),0.10), transparent 60%),
    linear-gradient(180deg, rgba(var(--tint-ink),0.64), rgba(var(--tint-ink),0.93));
}
.join-screen > * { position: relative; z-index: 1; }

.join-card { width: 100%; max-width: 420px; padding: 30px 24px 26px; }
.join-logo { display: flex; align-items: baseline; gap: 8px; }
.join-logo .ewc-logo { font-size: 38px; color: var(--text); }
.join-logo-img { width: 130px; height: auto; display: block; margin: 0 auto; filter: drop-shadow(0 6px 24px rgba(var(--tint-gold),0.3)); }
.join-logo-sub {
  font-family: var(--font-narrow); font-weight: 700;
  letter-spacing: 0.2em; color: var(--text-dim); font-size: 18px;
}
.join-tag { margin: 10px 0 0; text-align: center; }
.no-token-text { color: var(--text-dim); font-size: 16px; line-height: 1.5; margin: 14px 0 18px; }
.no-token-text b { color: var(--text); }
.no-token-icon { font-size: 56px; text-align: center; }
.join-title { font-size: 38px; margin: 14px 0 22px; text-align: center; text-transform: uppercase; }
.join-title, .join-title .gold-text { background: var(--ewc-grad); -webkit-background-clip: text; background-clip: text; color: transparent; }
/* The one-line brief above the nickname: what this stage is running right now.
   Quieter than the title, louder than the footer — it is information a fan
   should read, not a legal notice they are meant to skim past. */
.join-brief {
  color: var(--text-dim); font-size: 14px; line-height: 1.5;
  margin: 10px 2px 16px; text-align: center;
}
.join-error { color: var(--danger-soft); font-size: 14px; min-height: 18px; margin: 12px 2px 0; font-weight: 500; }
.join-footer { font-size: 13px; color: var(--text-dim); display: flex; align-items: center; gap: 8px; }

.conn-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--warning); transition: background 0.3s; display: inline-block; }
.conn-dot.online { background: var(--success); box-shadow: 0 0 8px var(--success); }
.conn-dot.offline { background: var(--danger); }

/* ---------- Game shell ---------- */
.game-screen { height: 100dvh; display: flex; flex-direction: column; }

/* Top app-bar: EWC logo (leading) · player nickname chip (trailing). No
   connection dot — a spare, native app-bar. */
/* Both ends of the bar sit inset from the screen edge — the logo and the
   nickname chip used to graze the bezel on a phone. */
.game-top {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: calc(env(safe-area-inset-top) + 12px) 26px 12px;
  border-bottom: 1px solid var(--line-soft);
}
.game-logo-img { height: 22px; width: auto; display: block; flex-shrink: 0; opacity: 0.96; margin-left: 8px; }
.me-tag {
  display: inline-flex; align-items: center; max-width: 52%;
  padding: 4px 11px; background: var(--surface-2);
  border: 1px solid var(--line-soft); border-radius: 999px;
  margin-right: 8px;
}
.me-name {
  font-family: var(--font-narrow); font-weight: 700; font-size: 11px;
  letter-spacing: 0.02em; color: var(--text-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.me-tag:has(.me-name:empty) { display: none; } /* no chip until the name is set */

.player-banner {
  background: var(--grad-gold); color: var(--on-accent); font-weight: 700;
  text-align: center; padding: 9px 14px; font-size: 14px;
}

.game-stage {
  flex: 1; display: flex; flex-direction: column;
  /* Centred, not top-packed. Every scene used to sit high with dead space
     under it. "safe center" and not plain "center": when a scene IS taller
     than the stage, centring pushes its top out of view under overflow:hidden,
     and losing the top of a question is worse than an off-centre one. The
     plain value stays first as the fallback for engines without "safe". */
  justify-content: center;
  justify-content: safe center;
  padding: 16px; overflow: hidden; position: relative;
}

/* Bottom stat bar: Score + Rank as two equal, polished stat cards. The gradient
   appears exactly once (the RANK numeral via --grad-num) — 70/20/10 stays calm. */
.game-bottom {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 9px 14px calc(env(safe-area-inset-bottom) + 11px);
  border-top: 1px solid var(--line-soft);
  background: linear-gradient(180deg, transparent, rgba(0, 0, 0, 0.22));
}
.stat-row { display: flex; align-items: stretch; gap: 9px; width: 100%; }
.stat-card {
  flex: 1 1 0; min-width: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  padding: 7px 10px 8px;
  background: var(--surface-2); border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm);
}
.stat-card-label {
  font-family: var(--font-narrow); font-weight: 700; font-size: 9px;
  text-transform: uppercase; letter-spacing: 0.14em; color: var(--text-faint);
}
.stat-card-value {
  font-family: var(--font-display); font-weight: 900; font-size: 22px; line-height: 1;
  color: var(--text); font-variant-numeric: tabular-nums;
}
/* the "Rise Above" sign-off restored under the stats — quiet, centred. */
.game-signoff {
  font-family: var(--font-narrow); font-weight: 700; font-size: 8.5px;
  text-transform: uppercase; letter-spacing: 0.34em; color: var(--text-faint);
}
.stat-card.rank .stat-card-value {
  background: var(--grad-num); -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}

/* ---------- Generic stage states ---------- */
.stage-center { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: 16px; }
.stage-icon { font-size: 54px; }
.stage-headline { font-family: var(--font-display); font-weight: 900; text-transform: uppercase; font-size: 34px; }
.stage-sub { color: var(--text-dim); font-size: 16px; max-width: 300px; }

.waiting-pulse { width: 64px; height: 64px; border-radius: 50%; border: 4px solid var(--surface-3); border-top-color: var(--text); animation: spin 1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- Trivia / poll question ---------- */
.q-prompt {
  font-family: var(--font-display); font-weight: 900; font-size: 24px;
  line-height: 1.1; margin-bottom: 12px; text-align: center; text-transform: uppercase;
}
.q-timer-row { display: flex; align-items: center; justify-content: center; gap: 10px; margin-bottom: 14px; }
.q-timer {
  font-family: var(--font-display); font-weight: 900; font-size: 26px;
  width: 52px; height: 52px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  border: 3px solid var(--text); color: var(--text);
}
.q-timer.urgent { border-color: var(--danger); color: var(--danger-soft); animation: pulseDot 0.7s infinite; }
.q-meta { color: var(--text-dim); font-size: 13px; }

/* Interim standings — my rank + rank movement between questions. */
.st-play-rank { font-family: var(--font-display); font-weight: 900; font-size: 84px; line-height: 1; }
.st-play-move { font-family: var(--font-narrow); font-weight: 700; font-size: 22px; animation: popIn 0.4s both 0.25s; }
.st-play-move.up { color: var(--success); }
.st-play-move.down { color: var(--danger-soft); }
.st-play-gain { font-family: var(--font-display); font-weight: 900; font-size: 26px; background: var(--grad-num); -webkit-background-clip: text; background-clip: text; color: transparent; filter: drop-shadow(0 2px 8px rgba(0,0,0,0.6)); }

/* Points-multiplier badge — warm gradient clipped into the glyphs (brand:
   gold/orange never flat), drop-shadow instead of text-shadow. */
.q-mult-badge { font-family: var(--font-display); font-weight: 900; text-transform: uppercase; text-align: center; font-size: 18px; letter-spacing: 0.06em; margin-bottom: 8px; background: var(--grad-num); -webkit-background-clip: text; background-clip: text; color: transparent; filter: drop-shadow(0 2px 8px rgba(0,0,0,0.6)); animation: multPulsePlay 1.6s ease-in-out infinite; }
@keyframes multPulsePlay { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.05); } }

/* Game logo (white EWC co-brand lockup) on the trivia views. */
.play-game-logo { width: min(78%, 290px); height: auto; max-height: 56px; object-fit: contain; display: block; margin: 0 auto 4px; opacity: 0.95; }
.play-game-logo.sm { max-height: 30px; width: min(60%, 200px); margin-bottom: 10px; opacity: 0.8; }

/* Countdown number on the phone */
.cd-num-play { font-family: var(--font-display); font-weight: 900; font-size: 120px; line-height: 1; color: var(--text); animation: popIn 0.4s both; }

.answers-grid { flex: 1; display: grid; grid-template-columns: 1fr 1fr; gap: 12px; align-content: stretch; }
.answers-grid.single { grid-template-columns: 1fr; }
.answer-tile {
  border: none; border-radius: var(--radius); color: #fff;
  font-family: var(--font-narrow); font-weight: 700; font-size: 18px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px; padding: 14px; cursor: pointer; position: relative;
  transition: transform 0.1s ease, filter 0.15s ease, opacity 0.2s;
  min-height: 84px;
  box-shadow: 0 8px 22px -10px rgba(0,0,0,.6);
}
.answer-tile:active { transform: scale(0.96); }
.answer-tile .shape { font-size: 26px; line-height: 1; }
.answer-tile.dim { opacity: 0.3; filter: grayscale(0.4); }
.answer-tile.chosen { outline: 4px solid #fff; outline-offset: -4px; }
.answer-tile.correct { box-shadow: 0 0 0 4px var(--success), 0 8px 22px -10px rgba(0,0,0,.6); }
.answer-tile.wrong { box-shadow: 0 0 0 4px var(--danger), 0 8px 22px -10px rgba(0,0,0,.6); }
.answer-tile .tile-count { position: absolute; top: 8px; right: 10px; font-size: 13px; opacity: 0.85; font-weight: 700; }

.locked-banner {
  margin-top: 14px; text-align: center; padding: 14px; border-radius: var(--radius);
  background: var(--surface-2); border: 1px solid var(--line-soft); font-weight: 600; color: var(--text-dim);
}
/* Reserved but invisible before the player taps — keeps the answer grid's height
   constant so the tiles never jump/resize when the real banner appears. */
.locked-banner.pending { visibility: hidden; }

/* ---------- Result feedback ---------- */
.result-card { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: 10px; border-radius: var(--radius); }
.result-emoji { font-size: 70px; }
.result-title { font-family: var(--font-display); font-weight: 900; text-transform: uppercase; font-size: 42px; }
.result-correct .result-title { color: var(--success); }
.result-wrong .result-title { color: var(--danger); }
.result-points { font-family: var(--font-display); font-weight: 900; font-size: 32px; background: var(--grad-num); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; color: transparent; }
.result-meta { color: var(--text-dim); font-size: 15px; }

/* ---------- "Starts soon" key visual (waiting for the next game) ---------- */

/* ---------- ON-STAGE host duel (watch mode) ---------- */
.host-mini-vs { display: flex; align-items: center; gap: 14px; margin-top: 10px; }
.host-mini-card {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  background: var(--surface-2); border: 1px solid var(--line-soft); border-radius: var(--radius-sm);
  padding: 12px 20px; min-width: 110px;
}
.host-mini-card b { font-family: var(--font-display); font-weight: 900; text-transform: uppercase; font-size: 16px; }
.host-mini-members { font-size: 10px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.04em; }
.host-mini-score { font-family: var(--font-display); font-weight: 900; font-size: 30px; background: var(--grad-num); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; color: transparent; }
.host-mini-mid { font-family: var(--font-display); font-weight: 900; font-size: 18px; color: var(--text-dim); }

/* ---------- Leaderboard ---------- */
/* overflow-y:auto forces overflow-x:auto (CSS spec), which clipped the rows'
   left border/rounded corner flush against the scroll edge. A little inline
   padding gives every row its full block back. */
.lb-wrap { flex: 1; display: flex; flex-direction: column; gap: 10px; overflow-y: auto; padding: 2px 5px; }
.lb-title { font-family: var(--font-display); font-weight: 900; text-transform: uppercase; font-size: 30px; text-align: center; margin-bottom: 4px; }
.lb-row {
  display: flex; align-items: center; gap: 12px; padding: 11px 14px;
  background: var(--surface-2); border: 1px solid var(--line-soft); border-radius: 11px;
}
.lb-row.me { border-color: rgba(247,247,247,.45); background: rgba(247,247,247,.07); }
.lb-rank { font-family: var(--font-display); font-weight: 900; font-size: 20px; width: 30px; color: var(--text-dim); }
.lb-row:nth-child(1) .lb-rank { color: var(--text); }
.lb-name { flex: 1; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lb-score { font-family: var(--font-display); font-weight: 700; color: var(--text); }

/* ---------- Prize-pool claim card (a code was won) ---------- */
.prize-claim {
  border-radius: 18px; padding: 16px 18px; text-align: center; margin-bottom: 14px;
  background: var(--surface-2); border: 1px solid var(--line-soft);
  box-shadow: 0 0 44px -10px var(--gold-glow, rgba(var(--tint-gold), 0.5));
}
.prize-claim-head {
  font-family: var(--font-display); font-weight: 900; text-transform: uppercase; font-size: 20px;
  background: var(--grad-num); -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
.prize-claim-prize { font-family: var(--font-narrow); font-weight: 700; font-size: 16px; color: var(--text); margin-top: 4px; }
.prize-claim-code {
  font-family: ui-monospace, monospace; font-size: 22px; letter-spacing: 0.06em; color: var(--text);
  background: var(--bg); border: 1px dashed var(--line); border-radius: 10px;
  padding: 10px 12px; margin: 10px 0 6px; word-break: break-all; user-select: all;
}
.prize-claim-sub { color: var(--text-dim); font-size: 12px; }

/* ---------- Podium (player) ---------- */
.podium-player { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: 14px; }
.podium-medal { font-size: 80px; }
.podium-place { font-family: var(--font-display); font-weight: 900; text-transform: uppercase; font-size: 36px; }
.podium-prize { color: var(--text-dim); font-weight: 600; font-size: 18px; }

/* ---------- Arabic stage language (body.lang-ar) ----------
   The layout stays LTR; plaintext bidi lets each text block pick its own
   base direction, so Arabic lines read right-to-left and mixed Arabic/Latin
   strings (game names, scores) order sanely. */
body.lang-ar #stage *,
body.lang-ar #joinScreen * { unicode-bidi: plaintext; }

/* ==================== HOW TO PLAY ====================
   The ten seconds between scanning a code and a game starting. Everything here
   reads from theme tokens, so the card wears whatever the stage is wearing —
   including the unbranded default, where it has no brand colour to borrow. */
.guide-card {
  width: 100%; max-width: 420px; margin: 0 auto;
  /* The stage clips (overflow:hidden), so a card taller than it loses its
     bottom — which is where the steps are. Cap it to the stage and let the
     DEMO give up height first; the steps are the only part that must survive
     at any phone size. Internal scroll is the last resort, not the plan. */
  max-height: 100%; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  display: flex; flex-direction: column; align-items: center; text-align: center;
  padding: 20px 18px 18px;
  border-radius: 18px;
  border: 1px solid var(--line);
  background: linear-gradient(180deg, var(--surface) 0%, var(--bg-2) 100%);
  box-shadow: 0 24px 60px -30px rgba(0, 0, 0, 0.8);
  animation: guideIn 0.42s cubic-bezier(.2, .8, .3, 1) both;
}
@keyframes guideIn { from { opacity: 0; transform: translateY(14px) scale(0.98); } to { opacity: 1; transform: none; } }

.guide-badge {
  flex: 0 0 auto;
  width: 52px; height: 52px; border-radius: 50%;
  display: grid; place-items: center; font-size: 26px; line-height: 1;
  background: var(--grad-num);
  box-shadow: 0 10px 30px -12px var(--gold-glow);
  margin-bottom: 10px;
}
.guide-kicker {
  font-family: var(--font-narrow); font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.22em; font-size: 11px; color: var(--text-faint);
}
.guide-title {
  margin: 5px 0 0; font-family: var(--font-display); font-weight: 900;
  text-transform: uppercase; font-size: 23px; line-height: 1.05; color: var(--text);
}
.guide-goal {
  margin: 7px 0 13px; font-size: 14px; line-height: 1.45;
  color: var(--text-dim); max-width: 30ch;
}

.guide-steps { list-style: none; margin: 0; padding: 0; width: 100%; display: flex; flex-direction: column; gap: 9px; flex: 0 0 auto; }
.guide-step {
  display: flex; align-items: center; gap: 13px; text-align: left;
  padding: 10px 12px; border-radius: 11px;
  background: var(--bg-2); border: 1px solid var(--line-soft);
  animation: guideStep 0.4s cubic-bezier(.2, .8, .3, 1) both;
}
[dir="rtl"] .guide-step { text-align: right; }
@keyframes guideStep { from { opacity: 0; transform: translateX(-10px); } to { opacity: 1; transform: none; } }
.guide-step-n {
  flex: 0 0 auto; width: 21px; height: 21px; border-radius: 50%;
  display: grid; place-items: center;
  font-family: var(--font-display); font-weight: 900; font-size: 11px;
  background: var(--grad-num); color: var(--on-accent);
}
.guide-step-ico { flex: 0 0 auto; font-size: 21px; line-height: 1; }
.guide-step-t { flex: 1 1 auto; font-size: 14.5px; line-height: 1.35; color: var(--text); }

.guide-ok {
  margin-top: 14px; width: 100%; padding: 13px;
  border: none; border-radius: 13px; cursor: pointer;
  font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
  letter-spacing: 0.06em; font-size: 16px;
  background: var(--grad-num); color: var(--on-accent);
}
.guide-ok:active { transform: translateY(1px); }

/* ==================== ANIMATED GUIDE DEMO ====================
   A moving diagram of a gesture words cannot carry. One 4s loop, timed so the
   pull, the release and the hit each get a beat rather than blurring together.
   Tokens only, so it wears the stage's theme. */
.gd {
  width: 100%; margin: 2px 0 14px;
  flex: 0 1 auto; min-height: 0;
  border-radius: 14px; overflow: hidden;
  background: var(--bg-2); border: 1px solid var(--line-soft);
}
.gd-svg { display: block; width: 100%; height: auto; max-height: 22vh; }

/* The target drifts side to side — the reason aiming is not trivial. */
.gd-target { animation: gdTarget 4s ease-in-out infinite; }
.gd-t-ring { fill: none; stroke: var(--gold); stroke-width: 2.5; opacity: 0.9; }
.gd-t-core { fill: var(--gold); }
@keyframes gdTarget {
  0%, 100% { transform: translate(66px, 26px); }
  50%      { transform: translate(134px, 26px); }
}

.gd-anchor { fill: var(--text-faint); }

/* The band stretches with the pull, then vanishes on release. Scaled from the
   anchor rather than re-pointed: x1/x2/y1/y2 are not CSS-animatable in Chrome,
   which is why the band never drew at all in the first cut. */
.gd-band { stroke: var(--gold); stroke-width: 2.5; stroke-linecap: round; }
.gd-band-g {
  transform-origin: 100px 84px;
  opacity: 0;
  animation: gdBand 4s ease-in-out infinite;
}
@keyframes gdBand {
  0%,  8%  { transform: scale(0);    opacity: 0; }
  14%      { transform: scale(0.18); opacity: 0.9; }
  45%      { transform: scale(1);    opacity: 0.9; }
  50%      { transform: scale(1);    opacity: 0; }
  100%     { transform: scale(0);    opacity: 0; }
}

/* The thumb: appears, presses, drags back and down, then lets go. */
.gd-thumb { animation: gdThumb 4s ease-in-out infinite; }
.gd-thumb-halo { fill: var(--gold); opacity: 0.18; }
.gd-thumb-dot  { fill: var(--text); }
@keyframes gdThumb {
  0%,  6%  { transform: translate(100px, 84px);  opacity: 0; }
  12%      { transform: translate(100px, 84px);  opacity: 1; }
  45%      { transform: translate(80px, 106px);  opacity: 1; }
  50%      { transform: translate(80px, 106px);  opacity: 0; }
  100%     { transform: translate(80px, 106px);  opacity: 0; }
}

/* The shot leaves the OPPOSITE way to the drag — the whole point of the loop. */
.gd-shot {
  fill: var(--text); opacity: 0;
  animation: gdShot 4s ease-in-out infinite;
}
@keyframes gdShot {
  0%, 49%  { transform: translate(0, 0); opacity: 0; }
  52%      { transform: translate(0, 0); opacity: 1; }
  74%      { transform: translate(20px, -56px); opacity: 1; }
  80%      { transform: translate(25px, -62px); opacity: 0; }
  100%     { transform: translate(25px, -62px); opacity: 0; }
}

.gd-cap {
  display: flex; justify-content: space-between; gap: 8px;
  padding: 0 12px 10px;
  font-family: var(--font-narrow); font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.08em; font-size: 10.5px; color: var(--text-faint);
}
.gd-cap span { animation: gdCap 4s ease-in-out infinite; }
.gd-cap-2 { animation-delay: 2s; }
@keyframes gdCap {
  0%, 4%   { color: var(--text-faint); }
  10%, 44% { color: var(--text); }
  52%,100% { color: var(--text-faint); }
}

@media (prefers-reduced-motion: reduce) {
  .gd-target, .gd-band, .gd-thumb, .gd-shot, .gd-cap span { animation: none; }
  .gd-thumb, .gd-shot, .gd-band { opacity: 1; }
}

/* Optional status footer for full guides. Waiting pages use the launch slot. */
.guide-status {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  margin-top: 14px; padding: 9px 14px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--bg-2);
  font-family: var(--font-narrow); font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.1em; font-size: 11px;
  white-space: nowrap;
}
.guide-status-dot {
  width: 14px; height: 14px; border-radius: 50%; flex: 0 0 auto;
  border: 2px solid var(--line-strong); border-top-color: var(--text);
  animation: spin 1s linear infinite;
}
.guide-status-in { color: var(--text); }
.guide-status-sep { color: var(--text-faint); }
.guide-status-wait { color: var(--text-dim); }
/* The dots tick one at a time — the smallest possible "still going" signal. */
.guide-status-wait i { font-style: normal; opacity: 0; animation: guideEllipsis 1.5s steps(1) infinite; }
.guide-status-wait i:nth-child(2) { animation-delay: 0.5s; }
.guide-status-wait i:nth-child(3) { animation-delay: 1s; }
@keyframes guideEllipsis { 0%, 74% { opacity: 0; } 25%, 73% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .guide-status-dot, .guide-status-wait i { animation: none; }
  .guide-status-wait i { opacity: 1; }
}

/* Short phones: the demo is the first thing that may give up height, never the
   steps. */
@media (max-height: 700px) {
  .guide-badge { width: 42px; height: 42px; font-size: 21px; margin-bottom: 8px; }
  .guide-title { font-size: 20px; }
  .guide-goal { margin: 6px 0 10px; font-size: 13px; }
  .gd { margin-bottom: 8px; }
  /* The demo is the flexible part: on a short phone it gives up height so the
     three steps stay whole. A gesture at 60% scale still reads; a step that
     is not on screen does not. */
  /* The status strip is now the last thing in the card, so on a short phone it
     is the one competing for the bottom edge. The demo keeps paying for it —
     it is the only element here that still reads at any size. */
  .gd-svg { max-height: 11vh; }
  .guide-goal { margin: 5px 0 8px; }
  .guide-step { padding: 8px 11px; }
  .guide-steps { gap: 7px; }
  .guide-ok { margin-top: 10px; padding: 11px; }
  .guide-status { margin-top: 10px; padding: 7px 12px; font-size: 10px; }
}
