/* ═══════════════════════════════════════
   CELEBRATE — shared reward styles  v1
   confetti, milestone bursts, session finale, shared keyframes
   ═══════════════════════════════════════ */

#celebrateLayer{
  position:fixed;inset:0;z-index:9000;
  pointer-events:none;overflow:hidden;
}

/* ── Prize splash (Phase B) — tappable gift, reveals a random prize ── */
#prizeOverlay{
  display:none;position:fixed;inset:0;z-index:9400;
  align-items:center;justify-content:center;
  background:rgba(0,0,0,.45);backdrop-filter:blur(4px);
  opacity:0;transition:opacity .35s ease;
}
#prizeOverlay.show{opacity:1;}
#prizeGift{
  font-size:clamp(5rem,22vw,8rem);line-height:1;cursor:pointer;
  pointer-events:auto;-webkit-tap-highlight-color:transparent;
  filter:drop-shadow(0 8px 20px rgba(0,0,0,.35));
}
.prize-gift-bounce{animation:celHop .7s ease-in-out infinite;}
#prizeReveal{
  flex-direction:column;align-items:center;gap:6px;
}
#prizeReveal .prize-emoji{font-size:clamp(5rem,22vw,8rem);line-height:1;filter:drop-shadow(0 8px 20px rgba(0,0,0,.35));}
#prizeReveal .prize-name{
  font-family:'Baloo 2',cursive;font-size:clamp(1.4rem,6vw,2rem);font-weight:900;
  color:#fff;text-shadow:0 2px 8px rgba(0,0,0,.6);
}
.prize-reveal-pop{animation:celBounceIn .5s cubic-bezier(.34,1.56,.64,1);}
#prizeReveal .prize-sticker{
  width:clamp(160px,52vw,260px);height:auto;
  filter:drop-shadow(0 8px 20px rgba(0,0,0,.35));
}
/* v2: gift shakes with anticipation instead of hopping */
.prize-gift-shake{animation:prizeGiftShake .9s ease-in-out infinite;transform-origin:50% 85%;}
/* After shake, switch to a continuous inviting bounce to demand a tap */
.prize-gift-bounce{
  animation:prizeGiftBounce 0.85s cubic-bezier(.36,.07,.19,.97) infinite;
  transform-origin:50% 85%;
}
@keyframes prizeGiftBounce{
  0%,100%{transform:translateY(0) scale(1) rotate(0deg);}
  20%    {transform:translateY(-18px) scale(1.08) rotate(-3deg);}
  40%    {transform:translateY(-28px) scale(1.12) rotate(3deg);}
  60%    {transform:translateY(-14px) scale(1.06) rotate(-1deg);}
  80%    {transform:translateY(-4px) scale(1.02) rotate(1deg);}
}
@keyframes prizeGiftShake{
  0%,100%{transform:rotate(0) scale(1.15);}
  15%{transform:rotate(-9deg) scale(1.15);}
  30%{transform:rotate(8deg) scale(1.18);}
  45%{transform:rotate(-6deg) scale(1.15);}
  60%{transform:rotate(4deg) scale(1.17);}
  75%{transform:rotate(-2deg) scale(1.15);}
}

/* ── Prize progress meter — filling gift ring on game screens ── */
#prizeMeter{
  display:none;position:fixed;bottom:12px;right:12px;z-index:60;
  width:52px;height:52px;border-radius:50%;
  align-items:center;justify-content:center;
  cursor:pointer;-webkit-tap-highlight-color:transparent;
  box-shadow:0 3px 10px rgba(0,0,0,.25);
  background:rgba(255,255,255,.4);backdrop-filter:blur(3px);
}
/* Vehicles: the switcher bar wraps to two rows of buttons on phones, so lift
   the meter clear of it. */
#prizeMeter.meter-raised{bottom:calc(150px + env(safe-area-inset-bottom));}
#prizeMeterRing{
  position:absolute;inset:0;border-radius:50%;
  background:conic-gradient(#ffb300 0deg, rgba(255,255,255,.35) 0deg);
  -webkit-mask:radial-gradient(circle, transparent 58%, #000 60%);
          mask:radial-gradient(circle, transparent 58%, #000 60%);
}
#prizeMeterIcon{font-size:1.5rem;line-height:1;filter:drop-shadow(0 2px 4px rgba(0,0,0,.25));}
#prizeMeter.prize-meter-pop{animation:prizeMeterPop .35s ease-out;}
@keyframes prizeMeterPop{40%{transform:scale(1.18);}100%{transform:scale(1);}}
#prizeMeter.prize-meter-shake{animation:prizeMeterShake .6s ease-in-out;}
@keyframes prizeMeterShake{
  0%,100%{transform:rotate(0) scale(1);}
  20%{transform:rotate(-12deg) scale(1.25);}
  40%{transform:rotate(10deg) scale(1.25);}
  60%{transform:rotate(-8deg) scale(1.2);}
  80%{transform:rotate(5deg) scale(1.1);}
}

/* ── Hub sticker-book badge ── */
#hubStickersBtn{
  display:none;position:fixed;top:max(14px,env(safe-area-inset-top) + 8px);
  right:max(66px,env(safe-area-inset-right) + 60px);z-index:80;
  width:42px;height:42px;border-radius:50%;
  background:rgba(255,255,255,.88);border:2px solid rgba(0,0,0,.07);
  font-size:1.2rem;cursor:pointer;-webkit-tap-highlight-color:transparent;
  box-shadow:0 2px 10px rgba(0,0,0,.12);
  align-items:center;justify-content:center;transition:transform .15s;
}
#hubStickersBtn:active{transform:scale(.9);}
#hubStickersCount{
  position:absolute;top:-4px;right:-4px;
  min-width:18px;height:18px;border-radius:9px;padding:0 4px;
  background:#ef5350;color:#fff;
  font-family:'Baloo 2',cursive;font-size:.7rem;font-weight:800;
  display:flex;align-items:center;justify-content:center;
}
#hubStickersCount:empty{display:none;}

/* ── Sticker book screen ── */
#stickersScreen{
  display:none;position:fixed;inset:0;z-index:10;
  flex-direction:column;align-items:center;justify-content:center;
  background:transparent;   /* shares the home-screen backdrop (HUB_BG_SCREENS) */
  overflow-y:auto;padding:max(64px,env(safe-area-inset-top) + 54px) 16px 22px;
}
.sticker-header{text-align:center;margin-bottom:10px;flex-shrink:0;}
.sticker-title{
  font-family:'Baloo 2',cursive;font-size:clamp(1.4rem,6vw,2rem);font-weight:900;
  color:#e65100;text-shadow:0 2px 0 rgba(255,255,255,.7);
}
#stickerSub{
  font-family:'Baloo 2',cursive;font-size:1rem;font-weight:800;color:#bf360c;opacity:.7;
}
/* Sized by BOTH width and height (aspect-ratio:1 makes the grid square, so
   bounding it by the shorter of the two axes guarantees it fits the viewport
   without scrolling) — the old width-only sizing (max-width:520px) was fine on
   a tall phone but overflowed on a short one, forcing a scroll. Same fix
   family as the settings-panel-fit pass. overflow-y:auto above stays only as
   an accessibility fallback for extreme zoom, not something that should fire
   in normal use now. */
#stickerGrid{
  display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(6px,2vw,14px);
  width:min(520px,92vw,calc(100dvh - 170px));
  aspect-ratio:1/1;
  flex-shrink:0;
}
@media (max-height:700px){
  #stickersScreen{padding:max(54px,env(safe-area-inset-top) + 44px) 14px 16px;}
  .sticker-header{margin-bottom:6px;}
  .sticker-title{font-size:1.15rem;}
  #stickerSub{font-size:.82rem;}
  #stickerGrid{width:min(520px,92vw,calc(100dvh - 128px));}
}
.sticker-slot{
  position:relative;aspect-ratio:1/1;border-radius:18px;
  background:rgba(255,255,255,.55);border:2px dashed rgba(191,54,12,.25);
  display:flex;align-items:center;justify-content:center;padding:8%;
  -webkit-tap-highlight-color:transparent;
}
.sticker-slot.earned{
  background:#fff;border:2px solid rgba(191,54,12,.15);
  box-shadow:0 3px 10px rgba(0,0,0,.1);cursor:pointer;
}
.sticker-img{width:100%;height:100%;object-fit:contain;}
.sticker-slot:not(.earned) .sticker-img,
.sticker-slot:not(.earned) .sticker-emoji{
  /* True dark silhouette — the value SPRINT_CHANGELOG:118 claimed shipped but
     never did. The old washed grey vanished over the hub's light grass, so
     legibility depended on which row a sticker landed in. */
  filter:brightness(0);opacity:.22;
}
.sticker-emoji{font-size:clamp(2rem,9vw,3.4rem);line-height:1;}
.sticker-count{
  position:absolute;top:4px;right:6px;
  background:#ffb300;color:#fff;border-radius:10px;padding:1px 7px;
  font-family:'Baloo 2',cursive;font-size:.75rem;font-weight:800;
  box-shadow:0 1px 4px rgba(0,0,0,.2);
}
.sticker-slot.sticker-wiggle{animation:celWiggle .5s ease-in-out;}
/* Earned sticker shimmer — hints the sticker is tappable */
.sticker-earned-shimmer{
  animation:stickerShimmer 2.2s ease-in-out infinite;
}
@keyframes stickerShimmer{
  0%,100%{filter:brightness(1);}
  50%    {filter:brightness(1.18) drop-shadow(0 0 6px rgba(255,179,0,0.5));}
}

/* Rain confetti — falls full-height with drift + spin */
.cel-confetti{
  position:absolute;top:-18px;pointer-events:none;
  animation:celConfettiFall linear forwards;
}
@keyframes celConfettiFall{
  0%  {transform:translateY(0)     translateX(0)             rotate(0deg);opacity:1;}
  75% {opacity:1;}
  100%{transform:translateY(108vh) translateX(var(--cdrift)) rotate(var(--cspin));opacity:0;}
}

/* Burst confetti — radiates from a point */
.cel-burst{
  position:absolute;pointer-events:none;
  animation:celBurstFly ease-out forwards;
}
@keyframes celBurstFly{
  0%  {transform:translate(0,0) scale(1);opacity:1;}
  100%{transform:translate(var(--bx),var(--by)) scale(.2);opacity:0;}
}

/* ── Session finale ── */
#finaleOverlay{
  position:fixed;inset:0;z-index:9500;
  display:flex;align-items:center;justify-content:center;
  background:radial-gradient(ellipse at center,rgba(70,40,120,.92) 0%,rgba(20,10,50,.96) 100%);
  animation:finaleIn .4s ease-out;
  transition:background .6s ease;
}
@keyframes finaleIn {from{opacity:0;}to{opacity:1;}}

/* Calm-mode entry: no star, so no purple flash-in — starts fully
   transparent and only ever animates TO black (see .finale-black). */
#finaleOverlay.finale-nospectacle{background:rgba(20,10,50,0);animation:none;}

/* Beat 1 — settle: stop the star's bounce/wave loops and ease it back to a
   resting pose, so the last motion a child sees calms down instead of
   cutting off mid-jiggle. transition lives on the base .finale-star/.fs-hand
   rules (below) so this class swap animates rather than snapping. */
.finale-settle .finale-star{animation:none;transform:scale(1) rotate(0deg) translateY(0);}
.finale-settle .fs-hand{animation:none;transform:rotate(4deg);}

/* Beat 2 — black: the overlay eases to solid black (transition on the base
   rule above) and the star/confetti fade under it. This is also the moment
   endSession() runs (see _finaleSettleToBlack in js/celebrate.js) — fully
   hidden behind opaque black, so the hide-game/build-dashboard DOM swap
   never flashes on screen. */
.finale-black{background:#000!important;}
.finale-black .finale-star{transition:opacity .5s ease;opacity:0;}

/* Beat 3 — reveal: black fades away to show the finished done screen
   underneath, which already opens on "All done! Great job!" — no separate
   text needed on the overlay itself. */
.finale-reveal{transition:opacity .65s ease;opacity:0;}

.finale-star{
  position:relative;
  width:min(64vw,340px);height:min(64vw,340px);
  animation:finaleStarIn .6s cubic-bezier(.34,1.56,.64,1),finaleStarBounce 1.4s ease-in-out .6s infinite;
  /* Lets .finale-settle's explicit transform (below) ease in once the
     bounce loop is removed, instead of snapping straight to it. */
  transition:transform .45s ease-out;
}
@keyframes finaleStarIn{
  0%  {transform:scale(0) rotate(-30deg);}
  70% {transform:scale(1.15) rotate(6deg);}
  100%{transform:scale(1) rotate(0);}
}
@keyframes finaleStarBounce{
  0%,100%{transform:translateY(0) rotate(-3deg);}
  50%    {transform:translateY(-22px) rotate(3deg);}
}

.fs-shape{
  position:absolute;inset:0;
  background:radial-gradient(circle at 38% 32%,#ffe680 0%,#ffd740 45%,#ffab00 100%);
  clip-path:polygon(50% 0%,61% 35%,98% 35%,68% 57%,79% 91%,50% 70%,21% 91%,32% 57%,2% 35%,39% 35%);
  filter:drop-shadow(0 0 40px rgba(255,215,64,.75));
}
.fs-face{
  position:absolute;left:50%;top:50%;
  width:38%;height:26%;
  transform:translate(-50%,-40%);
}
.fs-eye{
  position:absolute;top:0;
  width:16%;height:42%;
  background:#5d3a00;border-radius:50%;
  animation:fsBlink 3.2s infinite;
}
.fs-eye-l{left:16%;} .fs-eye-r{right:16%;}
@keyframes fsBlink{
  0%,92%,100%{transform:scaleY(1);}
  95%        {transform:scaleY(.12);}
}
.fs-mouth{
  position:absolute;left:50%;bottom:0;
  width:52%;height:46%;
  transform:translateX(-50%);
  border:5px solid #5d3a00;border-top:none;
  border-radius:0 0 90px 90px;
  background:rgba(200,60,40,.35);
}
.fs-hand{
  position:absolute;right:-8%;top:26%;
  font-size:clamp(3rem,14vw,5.2rem);line-height:1;
  transform-origin:70% 90%;
  animation:fsWave .55s ease-in-out infinite alternate;
  transition:transform .45s ease-out;
}
@keyframes fsWave{
  0%  {transform:rotate(-14deg);}
  100%{transform:rotate(22deg);}
}

/* ── Fishtank magic mode — dims the tank to a dark neon "laser bowling"
   look for 20s: the tank background/decor goes dark (::before, sits below
   the fish), fish themselves get a pulsing multi-colour glow so they read
   as the light source, and diagonal laser-coloured beams sweep across on
   top (::after, screen blend so they only brighten, never muddy the dark
   background). Previous version just brightened + tinted the whole scene,
   which read as "sunny", not "blacklight" (Jason, 2026-08-16). */
#fishScreen.fish-magic::before{
  content:'';position:absolute;inset:0;z-index:1;pointer-events:none;
  background:rgba(4,7,26,.82);
  animation:fishMagicDimIn .8s ease;
}
@keyframes fishMagicDimIn{
  0%  {background-color:rgba(4,7,26,0);}
  100%{background-color:rgba(4,7,26,.82);}
}
#fishScreen.fish-magic #fishContainer{
  /* Must outrank ::before's z-index:1 explicitly — #fishContainer has no
     z-index of its own, and an explicitly-stacked sibling always paints
     above a z-index:auto one regardless of DOM order. Without this the
     dim layer painted OVER the fish, muting the neon glow it was meant to
     show through (Jason, 2026-08-21: "fish need to neon glow over the
     overlay"). fishScore/fishMagicBtn/abs-back sit at 21-25, still above. */
  position:relative;z-index:2;
  filter:saturate(1.9) brightness(1.2) contrast(1.12);
  transition:filter 1s ease;
}
#fishScreen.fish-magic #fishContainer>div{
  animation:fishNeonGlow 1.7s ease-in-out infinite;
}
@keyframes fishNeonGlow{
  0%,100%{filter:drop-shadow(0 0 8px rgba(255,70,215,.9)) drop-shadow(0 0 18px rgba(70,220,255,.55));}
  50%    {filter:drop-shadow(0 0 15px rgba(70,220,255,.95)) drop-shadow(0 0 24px rgba(255,70,215,.6));}
}
#fishScreen.fish-magic::after{
  content:'';position:absolute;inset:0;pointer-events:none;z-index:15;
  mix-blend-mode:screen;
  background:
    linear-gradient(100deg,transparent 44%,rgba(255,60,210,.4) 48%,rgba(255,60,210,.4) 50%,transparent 54%),
    linear-gradient(100deg,transparent 63%,rgba(60,225,255,.35) 67%,rgba(60,225,255,.35) 69%,transparent 73%),
    linear-gradient(100deg,transparent 20%,rgba(255,220,60,.22) 24%,rgba(255,220,60,.22) 25%,transparent 29%);
  background-size:260% 100%;
  animation:fishLaserSweep 5s linear infinite;
}
@keyframes fishLaserSweep{
  0%  {background-position:130% 0, 150% 0, 170% 0;}
  100%{background-position:-40% 0, -60% 0, -80% 0;}
}
/* Countdown ring on the magic-mode ("star") button itself — drains over
   the same 20s the mode runs, so a child can see at a glance how much
   glowing-tank time is left without reading a number (Jason, 2026-08-21).
   forwards-filling so it holds at fully-drained until JS removes the
   class; can't be re-triggered mid-run since _fishMagic() already no-ops
   while fish-magic is active, so no restart/reflow handling needed. */
.fish-magic-ring{position:absolute;inset:-3px;width:calc(100% + 6px);height:calc(100% + 6px);pointer-events:none;transform:rotate(-90deg);}
.fish-magic-ring circle{fill:none;stroke:#fff4c2;stroke-width:3.4;stroke-linecap:round;
  stroke-dasharray:163.4;stroke-dashoffset:0;opacity:0;
  filter:drop-shadow(0 0 3px rgba(255,220,120,.9));}
#fishMagicBtn.fish-magic-active .fish-magic-ring circle{
  opacity:1;animation:fishMagicRingDrain 20s linear forwards;
}
@keyframes fishMagicRingDrain{
  0%  {stroke-dashoffset:0;}
  100%{stroke-dashoffset:163.4;}
}

.fish-magic-sparkle{
  position:absolute;font-size:1.2rem;line-height:1;pointer-events:none;z-index:16;
  transform:translate(-50%,-50%);animation:fishMagicSparklePop .9s ease-out forwards;
}
@keyframes fishMagicSparklePop{
  0%  {opacity:0;transform:translate(-50%,-50%) scale(.4) rotate(0deg);}
  30% {opacity:1;transform:translate(-50%,-50%) scale(1.15) rotate(20deg);}
  100%{opacity:0;transform:translate(-50%,-60%) scale(.8) rotate(50deg);}
}

/* ── Day/Night magic weather fall ── */
@keyframes dnWxFall{
  0%  {transform:translateY(0);opacity:0;}
  8%  {opacity:.95;}
  85% {opacity:.95;}
  100%{transform:translateY(105vh);opacity:0;}
}

/* ── Shared per-game reward keyframes (used by Phase 4 features) ── */
@keyframes celWiggle{
  0%  {transform:rotate(0) scale(1);}
  25% {transform:rotate(-8deg) scale(1.08);}
  50% {transform:rotate(6deg) scale(1.05);}
  75% {transform:rotate(-4deg) scale(1.02);}
  100%{transform:rotate(0) scale(1);}
}
@keyframes celHop{
  0%,100%{transform:translateY(0) scale(1);}
  40%    {transform:translateY(-26px) scale(1.12);}
  70%    {transform:translateY(0) scale(.94,.88);}
}
@keyframes celBounceIn{
  0%  {transform:scale(0);}
  60% {transform:scale(1.25);}
  100%{transform:scale(1);}
}
@keyframes celFloatUp{
  0%  {transform:translateY(0) scale(.7);opacity:1;}
  100%{transform:translateY(-90px) scale(1.25);opacity:0;}
}
@keyframes celSpinDance{
  0%  {transform:rotate(0) scale(1);}
  30% {transform:rotate(-20deg) scale(1.2);}
  60% {transform:rotate(380deg) scale(1.25);}
  100%{transform:rotate(360deg) scale(1);}
}
