/* ============================================================
   Shake to Win — shared design system
   One source of truth. Re-theme from :root.
   ============================================================ */

:root {
  /* Brand — bright Christmas sky (from RBL Q1-HAP Globe-NoSnow.psd render):
     a light cyan→blue→purple gradient, glossy gold star mascot, magenta→gold
     fairy-dust spiral. Much brighter than the old dark-navy theme. */
  --sky-100: #eaf7ff;      /* near-white top of the sky */
  --sky-200: #bfe8ff;
  --sky-300: #7fd0f7;      /* bright cyan */
  --sky-400: #3aa9ec;
  --brand-900: #2a1a6b;    /* deep purple bottom of the gradient */
  --brand-800: #3b2a8f;
  --brand-700: #4b34b0;
  --brand-600: #1266a6;
  --brand-500: #1a86d1;
  --brand-400: #47a6e6;
  --brand-300: #8ccbf2;

  --gold-600: #d99a00;
  --gold-500: #f5b301;
  --gold-400: #ffca2c;
  --gold-300: #ffe08a;

  --accent-500: #ff2ea0;   /* magenta fairy dust */
  --accent-400: #ff6fc0;
  --violet-500: #8a2be2;   /* purple tail of the wordmark/dust */

  /* Neutrals — slightly blue-tinted */
  --ink-900: #0b1b2b;
  --ink-700: #2b3f52;
  --ink-500: #5b6f82;
  --ink-300: #9fb0c0;
  --line: rgba(255,255,255,.14);
  --line-solid: #e3ebf2;

  --paper: #ffffff;
  --paper-muted: #f4f8fb;

  /* Success / danger for status */
  --ok-500: #16a34a;
  --ok-050: #e9f8ee;
  --warn-500: #d97706;

  /* Radii */
  --r-sm: 10px;
  --r-md: 16px;
  --r-lg: 24px;
  --r-xl: 32px;
  --r-full: 999px;

  /* Shadows — brand-tinted, layered */
  --shadow-md: 0 4px 6px -1px rgba(6,42,74,.14), 0 2px 4px -2px rgba(6,42,74,.10);
  --shadow-lg: 0 20px 25px -5px rgba(6,42,74,.30), 0 8px 10px -6px rgba(6,42,74,.22);
  --shadow-gold: 0 14px 40px -10px rgba(245,179,1,.55);
  --shadow-glow: 0 0 60px -8px rgba(71,166,230,.7);

  /* Spacing scale (4/8) */
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px;
  --sp-5: 20px; --sp-6: 24px; --sp-8: 32px; --sp-10: 40px; --sp-12: 48px;

  /* Motion */
  --ease-out: cubic-bezier(.16,1,.3,1);
  --ease-in-out: cubic-bezier(.4,0,.2,1);
  --ease-spring: cubic-bezier(.34,1.56,.64,1);
  --dur-fast: 150ms;
  --dur-base: 250ms;
  --dur-slow: 400ms;

  --maxw: 1120px;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  color: var(--ink-900);
  background: var(--paper-muted);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }

.container { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 clamp(16px, 4vw, 32px); }

/* ---------- Typography ---------- */
h1,h2,h3 { margin: 0; line-height: 1.15; letter-spacing: -.02em; font-weight: 800; }
.eyebrow { text-transform: uppercase; letter-spacing: .1em; font-size: 12px; font-weight: 700; color: var(--brand-500); }
.muted { color: var(--ink-500); }
.tabnum { font-variant-numeric: tabular-nums; }

.gradient-text {
  background: linear-gradient(135deg, var(--gold-400), var(--accent-400) 70%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* ---------- Buttons ---------- */
.btn {
  --bg: var(--brand-600);
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 52px; padding: 0 24px;
  border: 0; border-radius: var(--r-full);
  background: var(--bg); color: #fff;
  font: inherit; font-weight: 700; font-size: 16px;
  cursor: pointer;
  transition: transform 60ms ease, box-shadow var(--dur-base) var(--ease-out), filter var(--dur-fast);
  box-shadow: var(--shadow-md);
}
.btn:hover { filter: brightness(1.06); box-shadow: var(--shadow-lg); }
.btn:active { transform: translateY(1px) scale(.99); }
.btn-gold {
  --bg: linear-gradient(135deg, var(--gold-400), var(--gold-600));
  color: #4a2c00; box-shadow: var(--shadow-gold);
}
.btn-block { display: flex; width: 100%; }
.btn-ghost {
  background: transparent; color: #fff; box-shadow: none;
  border: 1.5px solid var(--line);
}
.btn-ghost:hover { background: rgba(255,255,255,.08); box-shadow: none; }

:focus-visible { outline: 3px solid var(--gold-400); outline-offset: 3px; border-radius: 6px; }

/* ---------- The festive stage (shared background for game screens) ----------
   Bright Christmas sky: light cyan at the top fading through blue into a deep
   purple at the bottom, matching the PSD render. */
.stage {
  /* Fixed-to-viewport, not sized by any vh/svh/dvh unit. iOS Safari settles
     its toolbar (URL bar + tab bar) via an animation AFTER first paint, and
     viewport units can be measured before that settle finishes — which is
     what caused the "looks wrong until you background + resume" bug (resuming
     forces a fresh layout pass after the chrome has already settled, so it
     looked "fixed" by coincidence, not because anything corrected it).
     `position: fixed; inset: 0` sizes against the browser's live rendered
     canvas directly, with no measurement to race and no JS needed. */
  position: fixed;
  inset: 0;
  /* container-size query context: lets children size themselves as a % of
     THIS element's live box (container query units), instead of a vh/svh/dvh
     snapshot of the viewport that can be measured before Safari's chrome
     settles. Same fix rationale as position:fixed above, applied to sizing. */
  container-type: size;
  container-name: stage;
  display: flex; flex-direction: column;
  background:
    radial-gradient(120% 80% at 50% -10%, var(--sky-100), transparent 55%),
    radial-gradient(100% 70% at 50% 120%, var(--brand-900), transparent 60%),
    linear-gradient(180deg, var(--sky-200) 0%, var(--sky-300) 22%, var(--brand-500) 55%, var(--brand-800) 100%);
  color: #fff;
  overflow: hidden;
}
/* Painterly white snow-dust border framing all four edges (per PSD render).
   A soft, uneven vignette of white that's densest at the corners/edges and
   clears toward the center so the globe reads cleanly. */
.stage::before {
  content: "";
  position: absolute; inset: 0;
  background:
    radial-gradient(60% 40% at 50% 0%,   rgba(255,255,255,.9), transparent 70%),
    radial-gradient(60% 40% at 50% 100%, rgba(255,255,255,.85), transparent 70%),
    radial-gradient(30% 60% at 0% 50%,   rgba(255,255,255,.8), transparent 70%),
    radial-gradient(30% 60% at 100% 50%, rgba(255,255,255,.8), transparent 70%);
  filter: blur(8px);
  opacity: .55;
  pointer-events: none;
  z-index: 0;
}
/* Twinkle dust — fine sparkle over the whole stage, on top of the sky */
.stage::after {
  content: "";
  position: absolute; inset: 0;
  background-image:
    radial-gradient(1.5px 1.5px at 12% 22%, #fff, transparent),
    radial-gradient(1.5px 1.5px at 78% 14%, var(--gold-300), transparent),
    radial-gradient(2px 2px at 30% 68%, #fff, transparent),
    radial-gradient(1.5px 1.5px at 64% 78%, #fff, transparent),
    radial-gradient(2px 2px at 88% 52%, var(--accent-400), transparent),
    radial-gradient(1.5px 1.5px at 44% 8%, var(--accent-400), transparent),
    radial-gradient(1.5px 1.5px at 8% 82%, #fff, transparent),
    radial-gradient(2px 2px at 54% 44%, var(--gold-300), transparent);
  animation: twinkle 4s var(--ease-in-out) infinite;
  opacity: .8;
  pointer-events: none;
  z-index: 0;
}
@keyframes twinkle { 0%,100% { opacity: .35; } 50% { opacity: .9; } }

.stage-inner {
  position: relative; z-index: 1;
  flex: 1; min-height: 0; width: 100%; max-width: 460px; margin: 0 auto;
  padding: clamp(12px, 3vw, 24px) 20px calc(16px + env(safe-area-inset-bottom));
  display: flex; flex-direction: column;
}

/* Small brand lockup */
.lockup { display: flex; align-items: center; gap: 10px; justify-content: center; }
.lockup .mark {
  width: 34px; height: 34px; display: grid; place-items: center;
  border-radius: 10px; background: linear-gradient(135deg, var(--gold-400), var(--gold-600));
  color:#4a2c00; font-weight: 900;
}
.lockup .name { font-weight: 800; letter-spacing: .04em; font-size: 14px; }
.lockup .name small { display:block; font-weight:600; font-size:11px; letter-spacing:.16em; color: var(--brand-300); }

/* ---------- Card (light surfaces on white screens) ---------- */
.card {
  background: var(--paper); border-radius: var(--r-lg);
  box-shadow: var(--shadow-md); border: 1px solid var(--line-solid);
}

/* ---------- PIN input ---------- */
.pin-row { display: flex; gap: 10px; justify-content: center; }
.pin-cell {
  width: 46px; height: 58px;
  border-radius: var(--r-sm);
  border: 1.5px solid rgba(255,255,255,.22);
  background: rgba(255,255,255,.06);
  color: #fff; text-align: center;
  font-size: 24px; font-weight: 800; font-variant-numeric: tabular-nums;
  transition: border-color var(--dur-fast), box-shadow var(--dur-fast), background var(--dur-fast);
}
.pin-cell::placeholder { color: rgba(255,255,255,.3); }
.pin-cell:focus { border-color: var(--gold-400); box-shadow: 0 0 0 4px rgba(245,179,1,.2); background: rgba(255,255,255,.12); outline: none; }
.pin-cell.filled { border-color: var(--brand-300); background: rgba(255,255,255,.12); }
.pin-cell.err { border-color: #ff8093; box-shadow: 0 0 0 4px rgba(255,80,120,.18); animation: nudge .4s; }
@keyframes nudge { 0%,100%{transform:translateX(0)} 20%{transform:translateX(-6px)} 60%{transform:translateX(6px)} }

.field-note { font-size: 13px; text-align: center; }
.field-note.err { color: #ffb3c0; }

/* ---------- Globe ----------
   Structure: .globe-wrap is a vertical stack — the round .globe sits on
   top, the .pedestal flows directly beneath it. The globe is a sized
   circular block (NOT an inset:0 absolute fill), so the base can never
   float above it. */
.globe-wrap {
  margin: 8px auto 0;
  /* also bound by viewport height so the whole screen fits without scrolling
     on shorter phones — the globe shrinks before it pushes the CTA off.
     Grown from 34cqh: collapsing the hint/meter/dual-button stack into one
     button + a text-link fallback freed up real vertical space for this. */
  width: min(84vw, 44cqh, 360px);
  position: relative;
  display: flex; flex-direction: column; align-items: center;
}
/* Photoreal globe image (glass sphere + blue/silver base as one asset).
   The glass portion occupies roughly the TOP 64% of this box; the base is the
   lower ~36%. The interactive layers (mascot + prizes + dust) are absolutely
   positioned within .globe-glass, which maps to just the sphere region so
   nothing floats over the base. */
.globe-img {
  width: 100%; display: block;
  filter: drop-shadow(0 26px 30px rgba(42,26,107,.45));
  z-index: 1; position: relative;
}
/* The circular glass region of the globe image — everything inside the sphere
   is placed relative to this box. Values tuned to globe.webp's proportions. */
.globe-glass {
  position: absolute;
  left: 50%; top: 1%;
  width: 88%;              /* hug the visible glass sphere in globe.webp */
  aspect-ratio: 1;
  transform: translateX(-50%);
  border-radius: 50%;
  overflow: hidden;        /* hard clip: nothing inside can cross the glass edge */
  z-index: 2;
  pointer-events: none;
}
/* keep the moving contents within a safe inner circle so tilt/jostle never
   pushes an icon into the transparent corner or across the rim */
.orb {
  position: absolute;
  inset: 0;                /* maps icon --x/--y to the full glass circle */
  border-radius: 50%;
  overflow: hidden;        /* clip contents to the circular glass, not its square box */
  z-index: 2;
}
/* the mascot star, floating in the middle of the sphere. Sits slightly above
   the glass centre so its lower points stay inside the sphere and don't spill
   onto the base. */
.star-img {
  position:absolute; left:50%; top:46%;
  width: 50%;
  transform: translate(-50%,-50%);
  filter: drop-shadow(0 10px 18px rgba(42,26,107,.4));
  z-index: 4;
  animation: mascotFloat 5.5s var(--ease-in-out) infinite;
}
@keyframes mascotFloat {
  0%,100% { transform: translate(-50%,-50%) rotate(-3deg); }
  50%     { transform: translate(-50%,calc(-50% - 8px)) rotate(3deg); }
}
/* magenta → gold fairy-dust spiral wrapping the star (the PSD's hero motion).
   A conic ribbon masked to a ring, spinning slowly. */
.dust {
  position:absolute; inset:2%;
  border-radius:50%;
  /* a single sweeping ribbon (one bright arc, not a full ring) so it reads as
     a spiral wrapping the star rather than a pool of color at the bottom */
  background: conic-gradient(from 150deg,
    transparent 0deg,
    rgba(255,46,160,.0) 30deg,
    rgba(255,46,160,.75) 80deg,
    rgba(255,111,192,.55) 120deg,
    rgba(255,202,44,.7) 165deg,
    rgba(255,202,44,.0) 210deg,
    transparent 360deg);
  /* thin ring band, feathered on both edges */
  -webkit-mask: radial-gradient(closest-side, transparent 58%, #000 68%, #000 80%, transparent 92%);
          mask: radial-gradient(closest-side, transparent 58%, #000 68%, #000 80%, transparent 92%);
  mix-blend-mode: screen;
  opacity:.85; z-index:3;
  animation: spin 14s linear infinite;
  pointer-events:none;
}

/* ---- Floating prize icons inside the orb ----
   Each .orb-item is absolutely positioned via CSS custom props --x/--y
   (its resting % position). A gentle idle float runs by default; JS
   layers a sensor-driven translate on top via the inner .orb-item-inner
   so tilt/shake motion composes with the float without fighting it.
   (.orb positioning + clip is defined above near .globe-glass.)
   JS writes --tiltx / --tilty here (px) from device orientation. */
.orb-item {
  position:absolute;
  left: var(--x); top: var(--y);
  width: var(--size, 34px); height: var(--size, 34px);
  margin-left: calc(var(--size, 34px) / -2);
  margin-top: calc(var(--size, 34px) / -2);
  /* sensor offset applied here, composited on GPU */
  transform: translate3d(var(--tiltx,0), var(--tilty,0), 0);
  transition: transform .12s var(--ease-out);
  will-change: transform;
}
.orb-item .orb-item-inner {
  width:100%; height:100%;
  display:grid; place-items:center;
  animation: floaty var(--float-dur, 5s) var(--ease-in-out) infinite;
  animation-delay: var(--float-delay, 0s);
}
/* decorative prize renders — transparent PNGs, no bubble, soft drop shadow */
.orb-item .orb-item-inner img {
  width:100%; height:100%; object-fit:contain;
  filter: drop-shadow(0 4px 8px rgba(42,26,107,.4));
}

@keyframes floaty {
  0%,100% { transform: translateY(0) rotate(-4deg); }
  50%     { transform: translateY(-10px) rotate(4deg); }
}

@keyframes spin { to { transform: rotate(360deg); } }

/* The base is now part of the photoreal globe image (globe.webp), so there's
   no CSS-drawn pedestal. The globe image stays perfectly still — like a real
   snow globe on a table — and all motion happens to the CONTENTS (mascot +
   prize icons + dust), never the glass or base. */

/* when shaking, the prize icons scatter harder + faster */
.globe.shaking .orb-item .orb-item-inner {
  animation-duration: .4s;
}
.globe.jostle .orb-item .orb-item-inner { animation: jostle .45s var(--ease-in-out); }
/* the mascot also reacts to a shake */
.globe.jostle .star-img { animation: mascotJostle .5s var(--ease-in-out); }
@keyframes mascotJostle {
  0%{transform:translate(-50%,-50%) rotate(0)}
  25%{transform:translate(calc(-50% - 6px),calc(-50% - 4px)) rotate(-8deg)}
  60%{transform:translate(calc(-50% + 6px),calc(-50% + 3px)) rotate(7deg)}
  100%{transform:translate(-50%,-50%) rotate(0)}
}
@keyframes jostle {
  0%{transform:translate(0,0) rotate(0)}
  20%{transform:translate(8px,-11px) rotate(14deg)}
  45%{transform:translate(-10px,7px) rotate(-12deg)}
  70%{transform:translate(6px,9px) rotate(9deg)}
  100%{transform:translate(0,0) rotate(0)}
}

/* hint chip */
.hint {
  display:inline-flex; align-items:center; gap:8px;
  padding: 10px 16px; border-radius: var(--r-full);
  background: rgba(255,255,255,.1); border:1px solid var(--line);
  font-weight:600; font-size:14px;
  animation: pulseHint 2s var(--ease-in-out) infinite;
}
@keyframes pulseHint { 0%,100%{transform:scale(1); opacity:.9} 50%{transform:scale(1.04); opacity:1} }

/* ---------- Reveal / result ---------- */
.result-card {
  text-align:center; border-radius: var(--r-xl); padding: 28px 22px;
  background: rgba(255,255,255,.08); border:1px solid var(--line);
  backdrop-filter: blur(6px);
  animation: rise var(--dur-slow) var(--ease-out) both;
}
.prize-badge {
  display:inline-grid; place-items:center; width: 96px; height:96px; margin: 4px auto 12px;
  border-radius: 50%; font-size: 40px;
  background: radial-gradient(circle at 35% 30%, #fff, var(--gold-300) 45%, var(--gold-500));
  box-shadow: var(--shadow-gold);
  animation: pop .6s var(--ease-spring) both;
}
.prize-value { font-size: clamp(34px, 12vw, 52px); font-weight: 900; letter-spacing:-.03em; line-height: 1.05; }
@keyframes pop { from{transform:scale(.4); opacity:0} to{transform:scale(1); opacity:1} }

/* confetti burst (win only) */
.confetti { position:absolute; inset:0; pointer-events:none; overflow:hidden; z-index:3; }
.confetti i {
  position:absolute; top:-10%; width:9px; height:14px; border-radius:2px;
  animation: fall 2.6s var(--ease-in-out) forwards;
}
@keyframes fall {
  to { transform: translateY(120vh) rotate(540deg); opacity:0; }
}

/* try-again state */
.result-card.tryagain { background: rgba(255,255,255,.06); }
.result-card.tryagain .prize-badge {
  background: radial-gradient(circle at 35% 30%, #cfe0ee, var(--brand-400) 60%, var(--brand-700));
  box-shadow: var(--shadow-glow); color:#fff;
}

/* ---------- Entrance ---------- */
@keyframes rise { from{opacity:0; transform: translateY(16px)} to{opacity:1; transform:none} }
.reveal { animation: rise var(--dur-slow) var(--ease-out) both; }
.reveal:nth-child(1){animation-delay:40ms}
.reveal:nth-child(2){animation-delay:90ms}
.reveal:nth-child(3){animation-delay:140ms}
.reveal:nth-child(4){animation-delay:190ms}
.reveal:nth-child(5){animation-delay:240ms}

/* ---------- Phone frame (for index preview) ---------- */
.phone {
  width: 300px; max-width: 84vw; aspect-ratio: 9/19.5;
  border-radius: 44px; padding: 12px;
  background: linear-gradient(160deg, #1a2836, #060f18);
  box-shadow: var(--shadow-lg), 0 0 0 2px rgba(255,255,255,.05) inset;
}
.phone .screen { width:100%; height:100%; border-radius: 34px; overflow:hidden; position:relative; }
.phone .screen iframe { width:100%; height:100%; border:0; }

/* ---------- Utility ---------- */
.stack { display:flex; flex-direction:column; }
.center { text-align:center; }
.mt-2{margin-top:var(--sp-2)} .mt-3{margin-top:var(--sp-3)} .mt-4{margin-top:var(--sp-4)}
.mt-6{margin-top:var(--sp-6)} .mt-8{margin-top:var(--sp-8)} .mt-auto{margin-top:auto}
.spacer { flex: 1; }

.badge {
  display:inline-flex; align-items:center; gap:6px;
  padding:6px 12px; border-radius: var(--r-full);
  font-size:12px; font-weight:700; letter-spacing:.03em;
}
.badge-line { background: rgba(255,255,255,.1); border:1px solid var(--line); }
.dot { width:7px;height:7px;border-radius:50%; background: var(--gold-400); box-shadow:0 0 8px var(--gold-400); }

/* The [hidden] attribute must always win over any presentational display
   value (.btn, .btn-block, etc.) regardless of class combination or source
   order — hidden is a semantic state, not a style choice, so it gets !important
   rather than relying on cascade position across a large stylesheet. */
[hidden] { display: none !important; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration:.01ms !important; animation-iteration-count:1 !important;
    transition-duration:.01ms !important; scroll-behavior:auto !important;
  }
}
