/* ================================================================
   LEADERBOARD — ADVANCE CSS  (deferred, async)
   Place at: origin/static/cdn/leaderboard_advance.css
   All 3D card flips, spring physics, ambient motion, glassmorphism.
   Touch devices get auto-playing ambient animations.
   Fine-pointer devices get full 3D hover escalation.
   ================================================================ */

/* ---- Google Fonts upgrade (same stack as demo_weekly) --------- */
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;600;700&display=swap');

h1,h2,h3,h4,.card-streak,.ss-num,.yr-rank-num,.yr-streak,
.week-label-text,.card-rank-badge {
  font-family: 'Space Grotesk', var(--font);
}

/* ---- Spring easings reference --------------------------------
   --spring:   cubic-bezier(0.34,1.56,0.64,1)   — overshoot
   --spring-s: cubic-bezier(0.22,1,0.36,1)       — fast decel
   Elastic:    cubic-bezier(0.68,-0.55,0.265,1.55)
   ---------------------------------------------------------------- */

/* ================================================================
   BACKGROUND ATMOSPHERE
   ================================================================ */
body {
  background:
    radial-gradient(ellipse 900px 600px at 10% 0%,   rgba(59,130,246,.1), transparent 60%),
    radial-gradient(ellipse 700px 500px at 92% 20%,  rgba(96,165,250,.07), transparent 55%),
    radial-gradient(ellipse 500px 400px at 50% 80%,  rgba(245,158,11,.04), transparent 55%),
    var(--bg);
}

/* Scroll progress shimmer */
.scroll-progress {
  background: linear-gradient(90deg, var(--acc), var(--gold));
  box-shadow: 0 0 10px var(--glow);
}

/* ================================================================
   NEON PALETTE — for the reveal sequence only
   ================================================================ */
:root {
  --neon-cyan:    #00f7ff;
  --neon-magenta: #ff2fd0;
  --neon-red:     #ff2b4d;
}

/* ================================================================
   FLOATING TOP CONTROLS — back button + theme toggle
   ================================================================ */
.back-btn, .theme-toggle {
  backdrop-filter: blur(16px) saturate(150%);
  -webkit-backdrop-filter: blur(16px) saturate(150%);
  background: rgba(17,24,39,0.65);
  transition: transform 0.28s var(--spring), box-shadow 0.28s ease, border-color 0.2s ease;
}
body.light-mode .back-btn, body.light-mode .theme-toggle {
  background: rgba(255,255,255,0.7);
}
.back-btn:hover {
  transform: translateY(-2px) translateX(-2px);
  border-color: var(--acc);
  box-shadow: 0 8px 24px var(--glow);
}
.back-btn:active { transform: scale(0.96); }
.back-btn i { transition: transform 0.25s var(--spring); }
.back-btn:hover i { transform: translateX(-3px); }

.theme-toggle:hover {
  transform: rotate(-14deg) scale(1.08);
  border-color: var(--acc);
  box-shadow: 0 8px 24px var(--glow);
}
.theme-toggle:active { transform: scale(0.9); }

/* ================================================================
   REVEAL FLASH — "TOP 10 REVEALED" cinematic title card
   ================================================================ */
.reveal-flash {
  background: radial-gradient(circle at 50% 50%, rgba(0,0,0,0.55), rgba(0,0,0,0.15) 70%);
  transition: opacity 0.3s ease;
}
.reveal-flash-text {
  background: linear-gradient(90deg, var(--neon-cyan), var(--accL), var(--gold), var(--neon-magenta));
  background-size: 300% 100%;
  -webkit-background-clip: text; background-clip: text; color: transparent;
  text-shadow: none;
}
.reveal-flash.show {
  opacity: 1;
  animation: flashPulse 1.3s ease forwards;
}
.reveal-flash.show .reveal-flash-text {
  animation: flashTextIn 1.3s cubic-bezier(0.16,1,0.3,1) both, flashGradientSweep 1.3s linear both;
}
@keyframes flashPulse {
  0%   { opacity: 0; }
  12%  { opacity: 1; }
  75%  { opacity: 1; }
  100% { opacity: 0; }
}
@keyframes flashTextIn {
  0%   { transform: scale(0.6); filter: blur(6px); letter-spacing: 0.4em; }
  35%  { transform: scale(1.06); filter: blur(0); letter-spacing: 0.06em; }
  45%  { transform: scale(1) skewX(6deg); text-shadow: -3px 0 var(--neon-cyan), 3px 0 var(--neon-magenta); }
  50%  { transform: scale(1) skewX(-4deg); text-shadow: 3px 0 var(--neon-cyan), -3px 0 var(--neon-magenta); }
  55%  { transform: scale(1) skewX(0); text-shadow: none; }
  100% { transform: scale(1); }
}
@keyframes flashGradientSweep {
  from { background-position: 0% 0; }
  to   { background-position: 200% 0; }
}

/* ================================================================
   FOCUS-MODE ATMOSPHERE — grid floor + scanline + vignette
   Only visible while body.lb-focus-mode is active (reveal in progress)
   ================================================================ */
.focus-overlay { transition: opacity 0.5s ease; }
body.lb-focus-mode .focus-overlay { opacity: 1; }

.focus-grid {
  position: absolute; inset: 0;
  background-image:
    linear-gradient(rgba(59,130,246,0.14) 1px, transparent 1px),
    linear-gradient(90deg, rgba(59,130,246,0.14) 1px, transparent 1px);
  background-size: 46px 46px;
  -webkit-mask-image: radial-gradient(ellipse 90% 70% at 50% 100%, #000 40%, transparent 78%);
  mask-image: radial-gradient(ellipse 90% 70% at 50% 100%, #000 40%, transparent 78%);
  transform: perspective(400px) rotateX(58deg) scale(1.6);
  transform-origin: 50% 100%;
  animation: gridDrift 6s linear infinite;
}
@keyframes gridDrift {
  from { background-position: 0 0, 0 0; }
  to   { background-position: 0 46px, 46px 0; }
}

.focus-scanline {
  position: absolute; left: 0; right: 0; height: 140px; top: -140px;
  background: linear-gradient(180deg, transparent, rgba(59,130,246,0.16), transparent);
  animation: scanlineSweep 3.4s ease-in-out infinite;
}
@keyframes scanlineSweep {
  0%   { top: -140px; }
  100% { top: 100%; }
}

.focus-vignette {
  position: absolute; inset: 0;
  background: radial-gradient(ellipse 70% 60% at 50% 42%, transparent 40%, rgba(0,0,0,0.55) 100%);
}

/* Dim + blur everything except the stage while focus mode is active */
body.lb-focus-mode #lbMain > .container > .lb-section:not(#stageSection),
body.lb-focus-mode .site-footer {
  filter: blur(6px) brightness(0.4) saturate(0.6);
  opacity: 0.55;
  pointer-events: none;
  transition: filter 0.6s ease, opacity 0.6s ease;
}
@media (max-width: 640px) {
  body.lb-focus-mode #lbMain > .container > .lb-section:not(#stageSection),
  body.lb-focus-mode .site-footer {
    filter: blur(2px) brightness(0.45) saturate(0.7);
  }
}

/* Auto-focus the stage: lift, center, glow */
#stageSection {
  transition: transform 0.6s var(--spring-s), filter 0.6s ease;
  position: relative; z-index: 30;
}
body.lb-focus-mode #stageSection {
  transform: scale(1.015);
}
body.lb-focus-mode .lb-stage-wrap::before {
  content: '';
  position: absolute; inset: -24px;
  border-radius: var(--rXL);
  box-shadow: 0 0 0 1px rgba(59,130,246,0.25), 0 0 80px rgba(59,130,246,0.18);
  pointer-events: none;
  animation: stageAuraPulse 2.4s ease-in-out infinite;
  z-index: -1;
}
@keyframes stageAuraPulse {
  0%,100% { box-shadow: 0 0 0 1px rgba(59,130,246,0.25), 0 0 60px rgba(59,130,246,0.14); }
  50%      { box-shadow: 0 0 0 1px rgba(96,165,250,0.4), 0 0 100px rgba(59,130,246,0.26); }
}
.lb-stage-wrap { position: relative; }

/* Lighter ambient afterglow once reveal has settled */
body.lb-revealed-glow #stageSection { transform: none; }
body.lb-revealed-glow .lb-stage-wrap::after {
  content: '';
  position: absolute; inset: -16px;
  border-radius: var(--rXL);
  box-shadow: 0 0 60px rgba(59,130,246,0.08);
  pointer-events: none; z-index: -1;
  transition: opacity 1s ease;
}

/* ================================================================
   CARD DISORIENTATION SHUFFLE — plays only during focus mode, on
   cards that haven't flipped yet. Colour-shifts, jitters position,
   fades — then snaps cleanly into the final ranked order the instant
   JS adds .flipped (the running animation simply stops matching and
   the existing flip transition takes over from wherever it was).
   ================================================================ */
@keyframes cardShuffle {
  0%   { transform: translate(0,0) rotate(0deg) scale(1);        filter: hue-rotate(0deg) brightness(1) saturate(1); }
  14%  { transform: translate(-13px, 9px) rotate(-7deg) scale(0.95);  filter: hue-rotate(70deg) brightness(1.35) saturate(1.4); }
  28%  { transform: translate(11px, -13px) rotate(6deg) scale(1.05);  filter: hue-rotate(150deg) brightness(0.7) saturate(1.2); }
  42%  { transform: translate(-9px, -7px) rotate(-4deg) scale(0.97);  filter: hue-rotate(220deg) brightness(1.25) saturate(1.5); }
  56%  { transform: translate(12px, 8px) rotate(5deg) scale(1.03);    filter: hue-rotate(300deg) brightness(0.85) saturate(1.3); }
  70%  { transform: translate(-7px, 12px) rotate(-3deg) scale(0.96);  filter: hue-rotate(20deg) brightness(1.15) saturate(1.1); }
  85%  { transform: translate(6px, -5px) rotate(2deg) scale(1.01);    filter: hue-rotate(340deg) brightness(0.95) saturate(1.2); }
  100% { transform: translate(0,0) rotate(0deg) scale(1);        filter: hue-rotate(360deg) brightness(1) saturate(1); }
}
body.lb-focus-mode .lb-card:not(.flipped) {
  animation: cardShuffle 1.7s ease-in-out infinite;
}
body.lb-focus-mode .lb-card:not(.flipped):nth-child(2n) { animation-duration: 2s; animation-direction: reverse; }
body.lb-focus-mode .lb-card:not(.flipped):nth-child(3n) { animation-duration: 1.35s; }
body.lb-focus-mode .lb-card:not(.flipped):nth-child(5n) { animation-duration: 2.2s; animation-direction: reverse; }

/* Chromatic-aberration edge flicker on the still-hidden card backs */
body.lb-focus-mode .lb-card:not(.flipped) .lb-back {
  animation: backGlitch 1.7s ease-in-out infinite;
}
@keyframes backGlitch {
  0%,100% { box-shadow: 0 6px 24px rgba(0,0,0,0.3); }
  50%      { box-shadow: -3px 0 0 rgba(0,247,255,0.35), 3px 0 0 rgba(255,47,208,0.35), 0 6px 24px rgba(0,0,0,0.3); }
}

/* Landing impact glow: fires once each card locks into .flipped, timed
   to line up with JS's own stagger (--fi is set per-card by JS) */
.lb-card.flipped .lb-front {
  animation: cardLanding 0.7s calc(var(--fi, 0) * 90ms + 0.75s) var(--spring-s);
}
@keyframes cardLanding {
  0%   { box-shadow: 0 0 0 2px rgba(59,130,246,0.9), 0 0 50px rgba(59,130,246,0.5); }
  100% { box-shadow: 0 6px 24px rgba(0,0,0,0.3); }
}

/* ================================================================
   SEQUENTIAL SPOTLIGHT REVEAL
   Each rank is zoomed to screen-centre one at a time (JS computes the
   --zoom-x/--zoom-y offset + --zoom-scale, this file owns every curve,
   duration and glow). The wrap (not the card) carries the zoom, so it
   never fights with the card's own rotateY flip.
   ================================================================ */
body.lb-sequence-active .lb-card-wrap {
  transition: opacity 0.4s ease, filter 0.4s ease;
}
body.lb-sequence-active .lb-card-wrap:not(.is-spotlighted) {
  opacity: 0.22;
  filter: blur(2px) saturate(0.5);
}
body.light-mode.lb-sequence-active .lb-card-wrap:not(.is-spotlighted) {
  opacity: 0.3;
  filter: blur(2px) saturate(0.6) brightness(1.04);
}

.lb-card-wrap.is-spotlighted {
  position: relative;
  z-index: 500;
  transform: translate(var(--zoom-x, 0), var(--zoom-y, 0)) scale(var(--zoom-scale, 1.6));
  transition: transform 0.42s cubic-bezier(0.16,1,0.3,1);
}
.lb-card-wrap.settling {
  transform: translate(0, 0) scale(1);
  transition: transform 0.38s cubic-bezier(0.4,0,0.2,1);
}

/* Tier variety — strip (8–10), grid (4–7) and podium (2–3) each get a
   slightly different flavour of motion so the countdown doesn't feel
   like the same beat repeated nine times. */
.lb-card-wrap.tier-c.is-spotlighted {
  transition-timing-function: cubic-bezier(0.16,1,0.3,1);
}
.lb-card-wrap.tier-b.is-spotlighted {
  transform: translate(var(--zoom-x, 0), var(--zoom-y, 0)) scale(var(--zoom-scale, 1.6)) rotate(-1.6deg);
  transition-timing-function: cubic-bezier(0.34,1.56,0.64,1);
}
.lb-card-wrap.tier-a.is-spotlighted {
  transform: translate(var(--zoom-x, 0), var(--zoom-y, 0)) scale(var(--zoom-scale, 1.6)) rotate(1.1deg);
  transition-timing-function: cubic-bezier(0.22,1,0.36,1);
}

/* Spotlight ring — reads clearly on both light and dark backgrounds
   because it's a coloured glow rather than a dark scrim */
.lb-card-wrap.is-spotlighted::before {
  content: '';
  position: absolute; inset: -14px;
  border-radius: calc(var(--rXL) + 10px);
  box-shadow: 0 0 0 1px rgba(59,130,246,0.4), 0 24px 70px rgba(0,0,0,0.45), 0 0 90px rgba(59,130,246,0.28);
  animation: spotlightRingPulse 1.1s ease-in-out infinite;
  pointer-events: none;
  z-index: -1;
}
body.light-mode .lb-card-wrap.is-spotlighted::before {
  box-shadow: 0 0 0 1px rgba(59,130,246,0.35), 0 24px 60px rgba(15,23,42,0.18), 0 0 70px rgba(59,130,246,0.22);
}
@keyframes spotlightRingPulse {
  0%,100% { box-shadow: 0 0 0 1px rgba(59,130,246,0.4), 0 24px 70px rgba(0,0,0,0.45), 0 0 70px rgba(59,130,246,0.22); }
  50%      { box-shadow: 0 0 0 1px rgba(96,165,250,0.55), 0 24px 70px rgba(0,0,0,0.45), 0 0 110px rgba(59,130,246,0.34); }
}

/* ================================================================
   MYSTERY CHARGE — rank 1 pulses harder and harder in place before
   it ever moves, so the audience knows something bigger is coming
   ================================================================ */
.lb-card-wrap.is-charging .lb-card { animation: none; }
.lb-card-wrap.is-charging .lb-back {
  animation: mysteryCharge 1.45s ease-in-out infinite;
}
@keyframes mysteryCharge {
  0%   { box-shadow: 0 0 0 1px rgba(245,158,11,0.3), 0 0 24px rgba(245,158,11,0.18); transform: scale(1); }
  50%  { box-shadow: 0 0 0 2px rgba(251,191,36,0.6), 0 0 55px rgba(245,158,11,0.4); transform: scale(1.035); }
  100% { box-shadow: 0 0 0 1px rgba(245,158,11,0.3), 0 0 24px rgba(245,158,11,0.18); transform: scale(1); }
}
body.lb-mystery-charge .focus-vignette {
  animation: mysteryVignette 1.45s ease-in-out infinite;
}
@keyframes mysteryVignette {
  0%,100% { background: radial-gradient(ellipse 70% 60% at 50% 42%, transparent 40%, rgba(0,0,0,0.55) 100%); }
  50%      { background: radial-gradient(ellipse 70% 60% at 50% 42%, rgba(245,158,11,0.06) 20%, rgba(0,0,0,0.6) 100%); }
}

/* Champion spotlight — the podium ring gets a gold cast instead of blue */
.lb-card-wrap.is-champion-spotlight::before {
  box-shadow: 0 0 0 1px rgba(245,158,11,0.55), 0 30px 80px rgba(0,0,0,0.5), 0 0 120px rgba(245,158,11,0.4);
  animation: championRingPulse 0.85s ease-in-out infinite;
}
body.light-mode .lb-card-wrap.is-champion-spotlight::before {
  box-shadow: 0 0 0 1px rgba(245,158,11,0.5), 0 30px 70px rgba(15,23,42,0.2), 0 0 100px rgba(245,158,11,0.32);
}
@keyframes championRingPulse {
  0%,100% { filter: brightness(1); }
  50%      { filter: brightness(1.18); }
}

/* ================================================================
   CONFETTI BURST — fired once, at the champion reveal only
   ================================================================ */
.celebration-burst.show { opacity: 1; }
.confetti-piece {
  position: absolute;
  top: -6%;
  left: var(--left, 50%);
  border-radius: 2px;
  opacity: 0.95;
  transform: translate3d(0,0,0) rotate(0deg);
  animation: confettiFall var(--dur, 2s) var(--delay, 0s) cubic-bezier(0.36,0.06,0.6,0.98) forwards;
}
@keyframes confettiFall {
  0%   { transform: translate3d(0, 0, 0) rotate(0deg); opacity: 1; }
  85%  { opacity: 1; }
  100% { transform: translate3d(var(--drift, 0), 108vh, 0) rotate(var(--rot, 360deg)); opacity: 0; }
}

/* Champion flash gets a gold-weighted sweep instead of the full rainbow */
.reveal-flash.champion-flash .reveal-flash-text {
  background: linear-gradient(90deg, var(--gold), var(--goldL), #fff, var(--gold));
  background-size: 300% 100%;
}

/* ================================================================
   OUTRO — "this could be you next week"
   ================================================================ */
.reveal-outro {
  transition: opacity 0.45s ease, visibility 0.45s ease;
}
.reveal-outro.show .outro-card {
  animation: outroCardIn 0.55s cubic-bezier(0.16,1,0.3,1) both;
}
@keyframes outroCardIn {
  from { opacity: 0; transform: translateY(24px) scale(0.94); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.outro-card {
  box-shadow: 0 24px 70px rgba(0,0,0,0.45), 0 0 0 1px rgba(59,130,246,0.18);
}
body.light-mode .outro-card {
  box-shadow: 0 20px 50px rgba(15,23,42,0.16), 0 0 0 1px rgba(59,130,246,0.14);
}
.outro-eyebrow i {
  animation: outroSparklePulse 1.6s ease-in-out infinite;
}
@keyframes outroSparklePulse {
  0%,100% { opacity: 0.6; transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.18); }
}
.outro-cta {
  transition: transform 0.28s var(--spring), box-shadow 0.28s ease;
  box-shadow: 0 4px 16px var(--glow);
}
.outro-cta:hover {
  transform: translateY(-2px) scale(1.03);
  box-shadow: 0 8px 24px rgba(59,130,246,0.35);
}
.outro-cta:active { transform: scale(0.96); }
.outro-cta i { transition: transform 0.25s var(--spring); }
.outro-cta:hover i { transform: translateX(3px); }

/* ================================================================
   MEDAL BADGE — vector award icon replacing the emoji medals, tinted
   by the existing .text-gold/.text-silver/.text-bronze classes
   ================================================================ */
.card-medal-icon {
  filter: drop-shadow(0 2px 6px rgba(0,0,0,0.25));
  animation: medalGleam 2.6s ease-in-out infinite;
}
body.light-mode .card-medal-icon {
  filter: drop-shadow(0 2px 5px rgba(15,23,42,0.15));
}
@keyframes medalGleam {
  0%,100% { filter: drop-shadow(0 2px 6px rgba(0,0,0,0.25)) brightness(1); }
  50%      { filter: drop-shadow(0 2px 10px rgba(0,0,0,0.3)) brightness(1.15); }
}

/* ================================================================
   HERO ENTRANCE
   ================================================================ */
@keyframes heroTitleIn {
  from { opacity:0; transform: translateY(32px); clip-path: inset(0 0 100% 0); }
  to   { opacity:1; transform: translateY(0);    clip-path: inset(0 0 0% 0); }
}
@keyframes fadeSlideUp {
  from { opacity:0; transform: translateY(20px); }
  to   { opacity:1; transform: translateY(0); }
}

.lb-hero-title     { animation: heroTitleIn 0.7s 0.15s var(--spring-s) both; }
.lb-hero-sub       { animation: fadeSlideUp 0.5s 0.4s ease both; }
.hero-meta         { animation: fadeSlideUp 0.5s 0.55s ease both; }
.week-switcher     { animation: fadeSlideUp 0.5s 0.65s var(--spring) both; }

/* Title ink highlight */
.ink-highlight {
  position: relative; color: var(--accL);
  background: linear-gradient(120deg, rgba(59,130,246,.2), rgba(59,130,246,0) 90%);
  padding: 0 .15em; border-radius: 4px;
}

/* Week switcher spring hover */
.week-nav-btn {
  transition: transform 0.3s var(--spring), background 0.2s ease, color 0.2s ease, box-shadow 0.3s ease;
}
.week-nav-btn:not(:disabled):hover {
  transform: scale(1.14) rotate(-6deg);
  box-shadow: 0 4px 14px var(--glow);
}

.week-switcher {
  box-shadow: 0 8px 28px rgba(0,0,0,0.3);
  transition: box-shadow 0.3s ease, transform 0.3s var(--spring);
}
.week-switcher:hover {
  box-shadow: 0 12px 36px rgba(0,0,0,0.4);
  transform: translateY(-2px);
}

/* ================================================================
   CARD FLIP ENGINE
   Full 3D. Cards start showing their BACK.
   JS adds .flipped class — card rotates, back hides, front shows.
   ================================================================ */
.lb-card-wrap { perspective: 1000px; }

.lb-card {
  transform-style: preserve-3d;
  transition: transform 0.85s var(--spring-s);
  cursor: default;
}

.lb-face {
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  box-shadow: 0 6px 24px rgba(0,0,0,0.3);
  transition: box-shadow 0.4s ease;
}

/* BACK: faces viewer by default */
.lb-back {
  transform: rotateY(0deg);
  background: linear-gradient(145deg, var(--surf), var(--surf2));
  border: 1px solid rgba(255,255,255,0.06);
}

/* FRONT: starts hidden (180deg away) */
.lb-front { transform: rotateY(180deg); }

/* When .flipped is added, card rotates to show front */
.lb-card.flipped { transform: rotateY(180deg); }

/* ---- Rank-specific front face colours ----------------------- */
.lb-front.rank-1 {
  background: linear-gradient(145deg, rgba(245,158,11,0.12), rgba(251,191,36,0.06), var(--surf));
  border-color: rgba(245,158,11,0.4);
  box-shadow: 0 0 0 1px rgba(245,158,11,0.25), 0 12px 40px rgba(245,158,11,0.15);
}
.lb-front.rank-2 {
  background: linear-gradient(145deg, rgba(148,163,184,0.1), var(--surf));
  border-color: rgba(148,163,184,0.35);
}
.lb-front.rank-3 {
  background: linear-gradient(145deg, rgba(180,83,9,0.1), var(--surf));
  border-color: rgba(180,83,9,0.3);
}

/* ---- Hover physics on revealed cards ----------------------- */
html[data-input="fine"] .lb-card.flipped {
  cursor: pointer;
}
html[data-input="fine"] .lb-card.flipped:hover {
  box-shadow: none; /* handled by .lb-face */
}
html[data-input="fine"] .lb-card.flipped:hover .lb-front {
  box-shadow: 0 22px 60px rgba(0,0,0,0.5), 0 0 40px var(--glow);
}
html[data-input="fine"] .lb-card.flipped {
  transition: transform 0.85s var(--spring-s);
}
html[data-input="fine"] .lb-card.flipped:hover {
  transform: rotateY(180deg) translateY(-8px) scale(1.03);
}

/* Rank 1 card extra glow on hover */
html[data-input="fine"] .lb-card.flipped.card-rank-1:hover .lb-front {
  box-shadow: 0 24px 64px rgba(245,158,11,0.3), 0 0 40px rgba(245,158,11,0.2);
}

/* ---- Touch: ambient float for back cards (pre-reveal) ------- */
html[data-input="touch"] .lb-card:not(.flipped) {
  animation: cardFloat 5s var(--spring-s) infinite;
}
html[data-input="touch"] .lb-card:not(.flipped):nth-child(2n) {
  animation-delay: -1.5s; animation-duration: 6s;
}
html[data-input="touch"] .lb-card:not(.flipped):nth-child(3n) {
  animation-delay: -3s; animation-duration: 4.5s;
}
@keyframes cardFloat {
  0%,100% { transform: translateY(0) rotateZ(0deg); }
  33%      { transform: translateY(-6px) rotateZ(0.5deg); }
  66%      { transform: translateY(-3px) rotateZ(-0.4deg); }
}

/* ---- Card back shimmer pattern ------------------------------ */
.lb-back::after {
  content: '';
  position: absolute; inset: 0; border-radius: inherit;
  background: repeating-linear-gradient(
    45deg,
    transparent,
    transparent 8px,
    rgba(59,130,246,0.025) 8px,
    rgba(59,130,246,0.025) 9px
  );
  pointer-events: none;
}

/* ---- Card stagger entrance (JS sets --fi var) --------------- */
@keyframes flipIn {
  from { transform: rotateY(90deg) scale(0.85); opacity:0; }
  50%  { opacity:1; }
  to   { transform: rotateY(180deg) scale(1); }
}


/* ================================================================
   PODIUM PLATFORM STYLING
   ================================================================ */
.podium-base {
  background: linear-gradient(180deg, var(--surf3), var(--surf2));
  border: 1px solid var(--border);
  border-top: none;
  box-shadow: 0 8px 24px rgba(0,0,0,0.25) inset;
  position: relative;
  transition: box-shadow 0.4s ease;
}

.podium-slot.rank1 .podium-base {
  background: linear-gradient(180deg, rgba(245,158,11,0.08), var(--surf2));
  border-color: rgba(245,158,11,0.2);
}
.podium-slot.rank2 .podium-base {
  background: linear-gradient(180deg, rgba(148,163,184,0.06), var(--surf2));
  border-color: rgba(148,163,184,0.15);
}

.podium-rank-num {
  background: linear-gradient(180deg, var(--surf3), transparent);
}

/* Podium entrance animation */
@keyframes podiumRise {
  from { transform: scaleY(0); transform-origin: bottom; }
  to   { transform: scaleY(1); }
}
.podium-slot.rank1 .podium-base { animation: podiumRise 0.5s 2.2s ease both; }
.podium-slot.rank2 .podium-base { animation: podiumRise 0.45s 2.1s ease both; }
.podium-slot.rank3 .podium-base { animation: podiumRise 0.4s 2s ease both; }

/* Rank 1 crown glow */
.card-crown {
  animation: crownGlow 2.5s ease-in-out infinite;
}
@keyframes crownGlow {
  0%,100% { text-shadow: 0 0 6px rgba(245,158,11,0.4); transform: translateY(0); }
  50%      { text-shadow: 0 0 18px rgba(245,158,11,0.7), 0 0 30px rgba(245,158,11,0.3); transform: translateY(-3px); }
}

/* ================================================================
   STAT CARDS (this week in numbers)
   ================================================================ */
.strip-stat {
  transition: transform 0.32s var(--spring), box-shadow 0.32s var(--spring-s);
  box-shadow: 0 2px 14px rgba(0,0,0,0.15);
  position: relative; overflow: hidden;
}

.strip-stat::before {
  content: '';
  position: absolute; top:0; left:0; right:0; height:2px;
  background: var(--acc); transform: scaleX(0); transform-origin: left;
  transition: transform 0.35s var(--spring); border-radius: 2px 2px 0 0;
}

html[data-input="fine"] .strip-stat:hover {
  transform: translateY(-6px) scale(1.02);
  box-shadow: 0 16px 40px rgba(0,0,0,0.3);
}
html[data-input="fine"] .strip-stat:hover::before { transform: scaleX(1); }

html[data-input="touch"] .strip-stat {
  animation: cardDrift 6s ease-in-out infinite;
}
html[data-input="touch"] .strip-stat:nth-child(2){animation-delay:-2s}
html[data-input="touch"] .strip-stat:nth-child(3){animation-delay:-4s}
html[data-input="touch"] .strip-stat:nth-child(4){animation-delay:-1s}
@keyframes cardDrift {
  0%,100% { transform: translateY(0); }
  50%      { transform: translateY(-5px); }
}

/* Stats counter entrance */
@keyframes statCountIn {
  from { opacity:0; transform: translateY(24px) scale(0.9); }
  60%  { opacity:1; transform: translateY(-3px) scale(1.01); }
  100% { transform: translateY(0) scale(1); }
}
.strip-stat:nth-child(1){ animation: statCountIn 0.5s 0.1s var(--spring-s) both; }
.strip-stat:nth-child(2){ animation: statCountIn 0.5s 0.22s var(--spring-s) both; }
.strip-stat:nth-child(3){ animation: statCountIn 0.5s 0.34s var(--spring-s) both; }
.strip-stat:nth-child(4){ animation: statCountIn 0.5s 0.46s var(--spring-s) both; }

/* ================================================================
   YOUR RANK STRIP
   ================================================================ */
.your-rank-strip {
  box-shadow: 0 4px 20px rgba(59,130,246,0.12);
  transition: transform 0.3s var(--spring), box-shadow 0.3s ease;
}
html[data-input="fine"] .your-rank-strip:hover {
  transform: translateX(4px);
  box-shadow: 0 8px 28px rgba(59,130,246,0.2);
}
.your-rank-strip::before {
  animation: leftBarPulse 3s ease-in-out infinite;
}
@keyframes leftBarPulse {
  0%,100% { opacity:1; }
  50%      { opacity:0.5; box-shadow: 2px 0 12px var(--glow); }
}

/* ================================================================
   ABOUT CARDS
   ================================================================ */
.about-card {
  transition: transform 0.32s var(--spring), box-shadow 0.32s ease,
              border-color 0.2s ease;
  box-shadow: 0 2px 14px rgba(0,0,0,0.12);
}
html[data-input="fine"] .about-card:hover {
  transform: translateY(-5px) rotateX(2deg);
  box-shadow: 0 16px 40px rgba(0,0,0,0.28);
  border-color: var(--borderL);
}
.about-card {
  background: linear-gradient(145deg, var(--surf), var(--surf2));
}

/* ================================================================
   REVEAL BUTTON — compact pill, not a slab. A quiet ambient pulse
   instead of a big spreading glow ring, so it reads as a normal-sized
   CTA that happens to breathe a little, rather than dominating the layout.
   ================================================================ */
.btn-reveal {
  background: var(--acc);
  color: #fff;
  font-size: 0.84rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  padding: 0.62rem 1.4rem;
  border-radius: 50px;
  border: none;
  position: relative;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  transition: transform 0.28s var(--spring), box-shadow 0.28s ease;
  box-shadow: 0 2px 12px var(--glow);
  animation: revealBtnPulse 2.6s ease-in-out infinite;
}
.btn-reveal i { font-size: 0.78rem; }
@keyframes revealBtnPulse {
  0%,100% { box-shadow: 0 2px 12px var(--glow), 0 0 0 0 rgba(59,130,246,0.26); }
  50%      { box-shadow: 0 2px 12px var(--glow), 0 0 0 6px rgba(59,130,246,0); }
}
.btn-reveal:hover {
  transform: scale(1.035) translateY(-2px);
  box-shadow: 0 6px 20px rgba(59,130,246,0.35);
  animation: none;
}
.btn-reveal:active {
  transform: scale(0.96);
  transition-duration: 0.08s;
  animation: none;
}

/* Reveal button shimmer sweep — subtler, narrower band */
.btn-reveal::after {
  content: '';
  position: absolute; top:-50%; left:-60%;
  width:26%; height:200%;
  background: linear-gradient(100deg, transparent, rgba(255,255,255,0.14), transparent);
  transform: skewX(-20deg);
  animation: btnShimmer 3.4s ease-in-out infinite;
}
@keyframes btnShimmer {
  0%,100% { left:-60%; opacity:0; }
  50%      { left:120%; opacity:0.9; }
}

/* ================================================================
   CARD AVATAR — smooth fade-in once the real image loads, plus a
   subtle rank-tinted ring so podium avatars feel a bit more alive.
   ================================================================ */
.card-avatar {
  transition: border-color 0.3s ease, box-shadow 0.3s ease;
}
.card-avatar img {
  transition: opacity 0.45s ease;
}
.card-avatar .avatar-placeholder svg {
  transition: opacity 0.3s ease;
}
.card-avatar img.is-loaded ~ .avatar-placeholder {
  opacity: 0;
}
.lb-card.card-rank-1 .card-avatar {
  border-color: rgba(245,158,11,0.55);
  box-shadow: 0 0 0 3px rgba(245,158,11,0.12);
}
.rank-2 .card-avatar, .podium-slot.rank2 .card-avatar {
  border-color: rgba(148,163,184,0.55);
}
.rank-3 .card-avatar, .podium-slot.rank3 .card-avatar {
  border-color: rgba(180,120,60,0.55);
}

/* Week-toggle button */
.btn-last-week {
  transition: transform 0.28s var(--spring), color 0.18s, border-color 0.18s;
}
.btn-last-week:hover { transform: translateY(-2px); }

/* ================================================================
   "ALMOST THERE" LOADING DRAMA — compact radar HUD, not a big spinner.
   Small enough to sit beside the message text instead of dominating
   the screen while the real show (card shuffle) happens behind it.
   ================================================================ */
.at-hud { animation: fadeSlideUp 0.3s ease both; }

.at-ring-wrap {
  position: relative;
  border-radius: 50%;
  background:
    conic-gradient(from 0deg, var(--acc) 0deg, transparent 70deg,
      transparent 290deg, var(--accL) 360deg);
  animation: atRingSpin 1.1s linear infinite;
  box-shadow: 0 0 10px var(--glow), inset 0 0 0 1px rgba(255,255,255,0.06);
}
.at-ring-wrap::before {
  content: '';
  position: absolute; inset: 4px; border-radius: 50%;
  background: var(--bg);
}
body.light-mode .at-ring-wrap::before { background: var(--surf); }
.at-ring-dot {
  box-shadow: 0 0 8px 2px var(--acc);
  animation: atDotPulse 1.1s ease-in-out infinite;
}
@keyframes atRingSpin { to { transform: rotate(360deg); } }
@keyframes atDotPulse {
  0%,100% { opacity: 0.5; transform: translate(-50%,-50%) scale(0.85); }
  50%      { opacity: 1;   transform: translate(-50%,-50%) scale(1.25); }
}

.at-bar-fill {
  background: linear-gradient(90deg, var(--acc), var(--accL), var(--gold));
  background-size: 200% 100%;
  animation: fillShimmer 1.5s linear infinite;
  box-shadow: 0 0 8px var(--glow);
}
@keyframes fillShimmer {
  0%   { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}

/* HUD text: quick chromatic-aberration glitch flicker on entry, then settles */
.at-msg { position: relative; }
.at-msg.active { animation: hudTextGlitchIn 0.45s ease both; }
@keyframes hudTextGlitchIn {
  0%   { opacity: 0; transform: translateY(16px); text-shadow: -2px 0 var(--acc), 2px 0 var(--gold); }
  40%  { text-shadow: 2px 0 var(--acc), -2px 0 var(--gold); }
  100% { opacity: 1; transform: translateY(0); text-shadow: none; }
}

/* ================================================================
   SKELETON SHIMMER
   ================================================================ */
@keyframes skShimmer {
  0%   { background-position: -500px 0; }
  100% { background-position:  500px 0; }
}
.sk {
  background: linear-gradient(
    90deg, var(--surf) 0%, var(--surf3) 40%, var(--borderL) 50%, var(--surf3) 60%, var(--surf) 100%
  );
  background-size: 1000px 100%;
  animation: skShimmer 1.8s ease-in-out infinite;
}

/* ================================================================
   BUTTONS (global spring upgrade)
   ================================================================ */
.btn {
  transition: transform 0.28s var(--spring), box-shadow 0.28s ease,
              background 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}
.btn-primary:hover {
  transform: translateY(-3px) scale(1.02);
  box-shadow: 0 8px 24px var(--glow);
}
.btn-primary:active { transform: scale(0.96); transition-duration: 0.08s; }
.btn-outline:hover  { transform: translateY(-2px); box-shadow: 0 4px 14px rgba(0,0,0,0.2); }

/* ================================================================
   SCROLL REVEAL  (JS adds .lb-revealed)
   ================================================================ */
.lb-reveal-target {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 0.55s ease, transform 0.55s var(--spring-s);
}
.lb-reveal-target.lb-revealed {
  opacity: 1;
  transform: translateY(0);
}

/* ================================================================
   SOCIAL LINKS SPRING
   ================================================================ */
.social-links a {
  transition: transform 0.3s var(--spring), color 0.2s ease,
              border-color 0.2s ease, box-shadow 0.3s ease;
}
.social-links a:hover {
  transform: translateY(-3px) rotate(-4deg);
  box-shadow: 0 6px 16px rgba(0,0,0,0.25);
}

/* ================================================================
   FOOTER
   ================================================================ */
.footer-links a {
  transition: color 0.2s ease, transform 0.25s var(--spring);
}
.footer-links a:hover { transform: translateX(3px); }

/* ================================================================
   TENSION PHASE — the wait gets tenser the longer it runs: shuffle
   speeds up, the stage 'heartbeat' quickens, grid/scanline accelerate,
   and a false near-reveal flicker teases the payoff.
   ================================================================ */
@keyframes stageHeartbeat {
  0%,100% { transform: scale(1); }
  20%     { transform: scale(1.012); }
  35%     { transform: scale(0.998); }
  50%     { transform: scale(1.016); }
  70%     { transform: scale(1); }
}
body.lb-focus-mode .lb-stage-wrap { animation: stageHeartbeat 1.8s ease-in-out infinite; }

body.lb-tension .lb-card:not(.flipped)            { animation-duration: 0.65s; }
body.lb-tension .lb-card:not(.flipped) .lb-back    { animation-duration: 0.65s; }
body.lb-tension .lb-card:not(.flipped):nth-child(2n) { animation-duration: 0.75s; }
body.lb-tension .lb-card:not(.flipped):nth-child(3n) { animation-duration: 0.55s; }
body.lb-tension .lb-card:not(.flipped):nth-child(5n) { animation-duration: 0.85s; }
body.lb-tension .focus-grid                        { animation-duration: 2.1s; }
body.lb-tension .focus-scanline                     { animation-duration: 1.05s; }
body.lb-tension .lb-stage-wrap::before              { animation-duration: 0.9s; }
body.lb-tension .lb-stage-wrap                      { animation-duration: 0.85s; }

.focus-vignette::after {
  content: ''; position: absolute; inset: 0;
  background: rgba(255,255,255,0.07);
  opacity: 0;
}
body.lb-tension .focus-vignette::after {
  animation: teaseFlicker 2.4s steps(1) infinite;
}
@keyframes teaseFlicker {
  0%, 87%, 100% { opacity: 0; }
  89%  { opacity: 0.55; }
  90%  { opacity: 0; }
  93%  { opacity: 0.3; }
  94%  { opacity: 0; }
}

/* ================================================================
   CLIMAX COUNTDOWN — "3…2…1" right before the flash. Guaranteed
   suspense beat regardless of how long the fetch actually took.
   ================================================================ */
.climax-overlay {
  background: radial-gradient(circle at 50% 50%, rgba(0,0,0,0.8), rgba(0,0,0,0.4) 60%, rgba(0,0,0,0.85));
  transition: opacity 0.25s ease;
}
.climax-digit {
  display: inline-block;
  background: linear-gradient(180deg, var(--neon-cyan), var(--accL) 45%, var(--neon-magenta));
  -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 0 34px rgba(59,130,246,0.55));
  opacity: 0;
}
.climax-digit.tick { animation: climaxTick 0.43s cubic-bezier(0.16,1,0.3,1); }
@keyframes climaxTick {
  0%   { transform: scale(2.4); opacity: 0; filter: blur(12px) drop-shadow(0 0 0 transparent); }
  10%  { opacity: 1; text-shadow: -5px 0 var(--neon-cyan), 5px 0 var(--neon-magenta); }
  20%  { text-shadow: 5px 0 var(--neon-cyan), -5px 0 var(--neon-magenta); }
  30%  { text-shadow: none; }
  45%  { transform: scale(1); opacity: 1; filter: blur(0) drop-shadow(0 0 34px rgba(59,130,246,0.55)); }
  82%  { transform: scale(1); opacity: 1; }
  100% { transform: scale(0.68); opacity: 0; }
}

/* Screen shake on each countdown tick — beats the stage like a pulse */
body.lb-focus-mode .lb-stage-wrap.shake {
  animation: climaxShake 0.42s cubic-bezier(0.36,0.07,0.19,0.97);
}
@keyframes climaxShake {
  10%,90%     { transform: translate3d(-1px,0,0); }
  20%,80%     { transform: translate3d(2px,-1px,0); }
  30%,50%,70% { transform: translate3d(-4px,1px,0); }
  40%,60%     { transform: translate3d(4px,-1px,0); }
}

/* ================================================================
   MOBILE TUNING — lighter atmosphere, same motion language
   ================================================================ */
@media (max-width: 640px) {
  .focus-grid { background-size: 34px 34px; opacity: 0.8; }
  .focus-scanline { height: 90px; top: -90px; }
  body.lb-focus-mode .lb-stage-wrap::before { inset: -12px; }
  @keyframes cardShuffle {
    0%   { transform: translate(0,0) rotate(0deg) scale(1);       filter: hue-rotate(0deg) brightness(1); }
    30%  { transform: translate(-6px, 5px) rotate(-3deg) scale(0.97); filter: hue-rotate(140deg) brightness(1.2); }
    60%  { transform: translate(6px, -5px) rotate(3deg) scale(1.02);  filter: hue-rotate(280deg) brightness(0.9); }
    100% { transform: translate(0,0) rotate(0deg) scale(1);       filter: hue-rotate(360deg) brightness(1); }
  }
}

/* ================================================================
   LIGHT MODE OVERRIDES
   ================================================================ */
body.light-mode { background: var(--bg); }
body.light-mode .lb-back {
  background: linear-gradient(145deg, #e8eef6, #f1f5fb);
  border-color: rgba(0,0,0,0.06);
}
body.light-mode .lb-front {
  box-shadow: 0 4px 20px rgba(0,0,0,0.07);
}

/* ================================================================
   REDUCED MOTION
   ================================================================ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0ms !important;
    transition-duration: 0.1s !important;
  }
}
html.reduced-motion *, html.reduced-motion *::before, html.reduced-motion *::after {
  animation-duration: 0.01ms !important;
  transition-duration: 0.1s !important;
}