/* Tango Logic: game styles (moved out of index.html). Tailwind utilities live in tailwind.css. */
/* =========================================================================
   HALLMARK DESIGN SYSTEM TOKENS (:root & .dark)
   Every color and font goes through CSS custom properties.
   ========================================================================= */
:root {
  --font-display: 'Fredoka', 'Plus Jakarta Sans', system-ui, sans-serif;
  --font-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', monospace;

  --bg-canvas: #E8F5C8;
  --bg-surface: #FFFDF7;
  --bg-surface-elevated: #FFFFFF;
  --bg-glass: rgba(255, 253, 247, 0.90);
  --bg-overlay: rgba(17, 24, 28, 0.76);

  --text-primary: #1D2B1E;
  --text-secondary: #4A5D4C;
  --text-muted: #708272;
  --text-on-accent: #2B1600;
  --text-inverse: #FFFDF7;

  --border-subtle: rgba(29, 43, 30, 0.14);
  --border-strong: rgba(29, 43, 30, 0.26);

  /* Cut the Rope Tactile Candy-Orange & Meadow Gold Palette (Zero Purple-Blue Gradients) */
  --accent-orange-top: #FFB32C;
  --accent-orange-bot: #F26419;
  --accent-orange-lip: #9E3300;
  --accent-orange-ring: #FFF3B0;

  --accent-green-top: #7CE54E;
  --accent-green-bot: #2EB82E;
  --accent-green-lip: #166916;

  --accent-sky-top: #38C6F4;
  --accent-sky-bot: #0E94C7;
  --accent-sky-lip: #07597A;

  --accent-gold: #FACC15;
  --accent-gold-deep: #B45309;
  --accent-moon: #2563EB;
  --accent-danger: #E11D48;
  --accent-emerald: #10B981;

  /* Seamless Biome Map Stop Colors */
  --biome-1: #7BD957;
  --biome-2: #F4B950;
  --biome-3: #D97964;
  --biome-4: #2E7D6B;
  --biome-5: #1B3B36;
}

.dark {
  --bg-canvas: #0F1E19;
  --bg-surface: #172A24;
  --bg-surface-elevated: #1F3730;
  --bg-glass: rgba(23, 42, 36, 0.92);
  --bg-overlay: rgba(8, 14, 12, 0.82);

  --text-primary: #F3F8F5;
  --text-secondary: #B4C7BE;
  --text-muted: #7E998D;
  --text-on-accent: #2B1600;
  --text-inverse: #0F1E19;

  --border-subtle: rgba(243, 248, 245, 0.14);
  --border-strong: rgba(243, 248, 245, 0.28);
}

* {
  box-sizing: border-box;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  -webkit-user-select: none;
}
/* Text fields must stay selectable or iOS blocks caret placement and paste (email, password) */
input, textarea {
  user-select: text;
  -webkit-user-select: text;
}

:root {
  /* Safe clearance so top HUD buttons NEVER hide behind iPhone/Android status bar clock */
  --safe-top: max(env(safe-area-inset-top, 0px), 50px);
  --safe-bottom: max(env(safe-area-inset-bottom, 0px), 14px);
}
html.is-true-fullscreen {
  --safe-top: max(env(safe-area-inset-top, 0px), 14px);
}

html, body {
  position: fixed;
  inset: 0;
  overflow: hidden;
  margin: 0;
  padding: 0;
  width: 100vw;
  height: 100dvh;
  max-height: 100dvh;
  font-family: var(--font-sans);
  background-color: var(--bg-canvas);
  color: var(--text-primary);
  /* Pan and tap only: no pinch zoom and no double-tap zoom (pan-x pan-y leaves out pinch-zoom) */
  touch-action: pan-x pan-y;
  overscroll-behavior: none;
}

.safe-view-shell {
  height: 100dvh;
  max-height: 100dvh;
  padding-top: var(--safe-top);
  padding-bottom: var(--safe-bottom);
  overflow: hidden;
}
/* Shop and Profile are taller than the screen: they scroll (this file loads after Tailwind,
   so the plain overflow: hidden above would otherwise beat their overflow-y-auto class). */
.safe-view-shell.overflow-y-auto {
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

/* The world map and the level maps scroll sideways. Dragged past either end, iPhone's rubber band
   pulled the map away from the edge and showed the page behind it; Android 12+ stretches instead. */
#saga-scroll-container,
#worlds-scroll {
  overscroll-behavior: none;
}

.safe-fixed-top {
  top: var(--safe-top);
}

.safe-fixed-bottom {
  bottom: var(--safe-bottom);
}

/* Responsive Board Frame that ALWAYS fits between Top HUD and Bottom Dock on any phone */
.board-fit-frame {
  width: min(92vw, calc(100dvh - var(--safe-top) - var(--safe-bottom) - 148px), 420px);
}
/* Dark mode for the screens that paint their own background inline */
html.dark #view-home {
  background: linear-gradient(180deg, #0B1633 0%, #13244B 48%, #1B3262 74%, #1E4A2C 74%, #163A22 100%) !important;
}
html.dark #view-home > svg:first-of-type {
  filter: brightness(0.55) saturate(0.8);
}
html.dark #view-shop,
html.dark #view-profile {
  background: linear-gradient(180deg, #0B2C47 0%, #0A1B33 100%) !important;
}
html.dark #modal-victory {
  background: radial-gradient(circle at 50% 35%, #92400E 0%, #451A03 60%, #1C0A02 100%) !important;
}

/* Row/column counters: tiny sun and moon icons with the count beside each */
.quota-line {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1px;
  line-height: 1;
}
.quota-line svg {
  width: 9px;
  height: 9px;
  margin: 0;
}

/* 8x8 and 10x10 boards: use more of the screen so each tile stays tappable */
.board-fit-frame.board-lg {
  width: min(97vw, calc(100dvh - var(--safe-top) - var(--safe-bottom) - 140px), 460px);
}
/* Zoom mode (big boards): the frame grows to ~1.6x and the wrapper scrolls, so tiles reach ~45-50px */
.board-fit-frame.board-lg.board-zoomed {
  width: min(160vw, 720px);
  flex-shrink: 0;
}
#board-scroll-wrap.is-zoomed {
  overflow: auto;
  justify-content: flex-start;
  align-items: flex-start;
  max-height: calc(100dvh - var(--safe-top) - var(--safe-bottom) - 120px);
  overscroll-behavior: contain;
}

/* Cut the Rope 2 Juicy Jelly Button Press & Spring Animation */
@keyframes ctrJellyPop {
  0%   { transform: scale(1, 1); }
  30%  { transform: scale(0.86, 1.12) translateY(3px); }
  65%  { transform: scale(1.08, 0.93) translateY(-2px); }
  85%  { transform: scale(0.97, 1.03); }
  100% { transform: scale(1, 1); }
}
.btn-jelly-anim {
  animation: ctrJellyPop 0.34s cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* Cut the Rope 2 Mascot Squash & Stretch Idle Breathing + Blinking */
@keyframes sunnySquashIdle {
  0%, 100% { transform: translateY(0px) scale(1, 1); }
  50%      { transform: translateY(-7px) scale(1.03, 0.97); }
}
.mascot-idle {
  animation: sunnySquashIdle 2.5s ease-in-out infinite;
  transform-origin: center bottom;
}

@keyframes sunnyBlink {
  0%, 92%, 100% { transform: scaleY(1); }
  96%           { transform: scaleY(0.08); }
}
.sunny-eyes-blink {
  animation: sunnyBlink 3.8s infinite;
  transform-origin: center 106px;
}

@keyframes sunnyWaveLeft {
  0%, 100% { transform: rotate(0deg); }
  50%      { transform: rotate(-16deg); }
}
@keyframes sunnyWaveRight {
  0%, 100% { transform: rotate(0deg); }
  50%      { transform: rotate(16deg); }
}
.sunny-arm-l {
  transform-origin: 48px 118px;
  animation: sunnyWaveLeft 2.2s ease-in-out infinite;
}
.sunny-arm-r {
  transform-origin: 172px 118px;
  animation: sunnyWaveRight 2.2s ease-in-out infinite;
}

/* Post-Victory Single-Sun Cloud Transition Animations (User Request #3 & #4) */
@keyframes sunDipBehindCloud {
  0%   { transform: translateY(0px) scale(1); opacity: 1; }
  35%  { transform: translateY(-4px) scale(1.04); opacity: 1; }
  100% { transform: translateY(28px) scale(0.55); opacity: 0; }
}
@keyframes sunRiseFromCloud {
  0%   { transform: translateY(28px) scale(0.55); opacity: 0; }
  65%  { transform: translateY(-5px) scale(1.06); opacity: 1; }
  85%  { transform: translateY(2px) scale(0.98); opacity: 1; }
  100% { transform: translateY(0px) scale(1); opacity: 1; }
}
@keyframes darkCloudDissolve {
  0%   { opacity: 1; }
  100% { opacity: 0; }
}
.anim-sun-dip {
  transform-origin: 48px 46px;
  animation: sunDipBehindCloud 0.72s cubic-bezier(0.4, 0, 0.2, 1) 0.15s forwards;
}
.anim-cloud-darken-out {
  animation: darkCloudDissolve 0.68s ease-in-out 0.38s forwards;
}
.anim-sun-rise {
  transform-origin: 48px 46px;
  opacity: 0;
  transform: translateY(28px) scale(0.55);
  animation: sunRiseFromCloud 0.78s cubic-bezier(0.34, 1.56, 0.64, 1) 0.88s forwards;
}

/* Dramatic 3D Star Gate Lock Pop & Double Wooden Doors Swinging Open (User Request #5) */
@keyframes gateLockShakeAndPop {
  0%   { transform: translate(0, 0) rotate(0deg) scale(1); opacity: 1; }
  20%  { transform: translate(-3px, 0) rotate(-12deg) scale(1.1); opacity: 1; }
  40%  { transform: translate(3px, 0) rotate(12deg) scale(1.15); opacity: 1; }
  60%  { transform: translate(-3px, -2px) rotate(-10deg) scale(1.2); opacity: 1; }
  100% { transform: translate(0, -24px) rotate(25deg) scale(0); opacity: 0; }
}
@keyframes gateDoorLeftSwing {
  0%   { transform: rotate(0deg) scaleX(1); }
  55%  { transform: rotate(-82deg) scaleX(0.36); }
  78%  { transform: rotate(-66deg) scaleX(0.46); }
  100% { transform: rotate(-74deg) scaleX(0.40); }
}
@keyframes gateDoorRightSwing {
  0%   { transform: rotate(0deg) scaleX(1); }
  55%  { transform: rotate(82deg) scaleX(0.36); }
  78%  { transform: rotate(66deg) scaleX(0.46); }
  100% { transform: rotate(74deg) scaleX(0.40); }
}
@keyframes gateGlowBurst {
  0%   { opacity: 0; transform: scale(0.5); }
  50%  { opacity: 0.95; transform: scale(1.25); }
  100% { opacity: 0; transform: scale(1.6); }
}
.gate-door-l-open {
  transform-origin: 16px 56px;
  transform: rotate(-74deg) scaleX(0.40);
}
.gate-door-r-open {
  transform-origin: 72px 56px;
  transform: rotate(74deg) scaleX(0.40);
}
.gate-door-l-anim {
  transform-origin: 16px 56px;
  animation: gateDoorLeftSwing 1.15s cubic-bezier(0.34, 1.56, 0.64, 1) 0.45s forwards;
}
.gate-door-r-anim {
  transform-origin: 72px 56px;
  animation: gateDoorRightSwing 1.15s cubic-bezier(0.34, 1.56, 0.64, 1) 0.45s forwards;
}
.gate-lock-anim {
  transform-origin: 44px 52px;
  animation: gateLockShakeAndPop 0.55s ease-in-out 0.05s forwards;
}
.gate-burst-anim {
  transform-origin: 44px 52px;
  opacity: 0;
  animation: gateGlowBurst 0.9s ease-out 0.45s forwards;
}

/* Magical Stone & Crystal Portal Vortex Animations (image_cb5bd6.png style!) */
@keyframes portalVortexSpin {
  0%   { transform: rotate(0deg) scale(1); }
  50%  { transform: rotate(180deg) scale(1.05); }
  100% { transform: rotate(360deg) scale(1); }
}
@keyframes portalIgnitePop {
  0%   { transform: scale(0.05) rotate(-90deg); opacity: 0; }
  60%  { transform: scale(1.16) rotate(12deg); opacity: 1; }
  82%  { transform: scale(0.95) rotate(-4deg); opacity: 1; }
  100% { transform: scale(1) rotate(0deg); opacity: 1; }
}
@keyframes portalOuterFlame {
  0%, 100% { transform: scale(1, 1); opacity: 0.9; }
  50%      { transform: scale(1.06, 1.04); opacity: 1; }
}
.portal-vortex-spin {
  transform-origin: 50px 50px;
  animation: portalVortexSpin 5.5s linear infinite;
}
.portal-flame-pulse {
  transform-origin: 50px 50px;
  animation: portalOuterFlame 2.2s ease-in-out infinite;
}
.portal-ignite-anim {
  transform-origin: 50px 50px;
  animation: portalIgnitePop 1.05s cubic-bezier(0.34, 1.56, 0.64, 1) 0.25s both;
}

/* Hide Horizontal Map Scrollbar while keeping smooth touch/drag scrolling */
.no-scrollbar::-webkit-scrollbar {
  display: none;
}
.no-scrollbar {
  -ms-overflow-style: none;
  scrollbar-width: none;
}

.font-display {
  font-family: var(--font-display);
}
.font-mono-num {
  font-family: var(--font-mono);
}

/* Instant accessible focus ring */
button:focus-visible, input:focus-visible {
  outline: 3px solid var(--accent-gold);
  outline-offset: 2px;
}

/* Tactile Cut-the-Rope Circular & Pill 3D Game Buttons */
.ctr-orb-btn {
  background: linear-gradient(180deg, var(--accent-orange-top) 0%, var(--accent-orange-bot) 100%);
  border: 3px solid var(--accent-orange-ring);
  box-shadow: 0 6px 0 var(--accent-orange-lip), 0 10px 20px rgba(0, 0, 0, 0.28), inset 0 3px 4px rgba(255, 255, 255, 0.55);
  /* Fixed white icon with a soft shadow: the theme token turned the icons dark green in dark mode */
  color: #FFFFFF;
  text-shadow: 0 1px 2px rgba(120, 53, 15, 0.45);
  transition: transform 0.08s ease, box-shadow 0.08s ease, filter 0.12s ease;
}
/* Hover styles only where there is a real hover (a mouse). On a phone the last-tapped button
   kept its hover look until the next tap elsewhere, which read as a stuck button. */
@media (hover: hover) {
  .ctr-orb-btn:hover:not(:disabled) {
    filter: brightness(1.05);
  }
}
.ctr-orb-btn:active:not(:disabled) {
  transform: translateY(4px);
  box-shadow: 0 2px 0 var(--accent-orange-lip), 0 4px 10px rgba(0, 0, 0, 0.22), inset 0 2px 3px rgba(255, 255, 255, 0.4);
}

.ctr-green-btn {
  background: linear-gradient(180deg, var(--accent-green-top) 0%, var(--accent-green-bot) 100%);
  border: 3px solid var(--bg-surface-elevated);
  box-shadow: 0 5px 0 var(--accent-green-lip), 0 8px 16px rgba(0, 0, 0, 0.24), inset 0 3px 4px rgba(255, 255, 255, 0.5);
  color: #14532D; /* dark green on light green: readable in both themes */
  transition: transform 0.08s ease, box-shadow 0.08s ease;
}
.ctr-green-btn:active:not(:disabled) {
  transform: translateY(3px);
  box-shadow: 0 2px 0 var(--accent-green-lip), 0 3px 8px rgba(0, 0, 0, 0.2);
}

.btn-3d {
  transition: transform 0.08s ease, box-shadow 0.12s ease, background-color 0.14s ease;
  border-bottom-width: 4px;
}
.btn-3d:active:not(:disabled) {
  transform: translateY(2px);
}
.btn-3d-sm {
  transition: transform 0.08s ease, background-color 0.14s ease;
  border-bottom-width: 3px;
}
.btn-3d-sm:active:not(:disabled) {
  transform: translateY(1.5px);
}

/* Tactile 3D Board Tiles */
.tile-btn {
  touch-action: manipulation;
  transition: background-color 0.14s ease, transform 0.08s ease, box-shadow 0.14s ease, border-color 0.14s ease;
  border-bottom-width: 3.5px;
}
.tile-btn:active:not([data-fixed="true"]) {
  transform: translateY(1.5px);
}

/* Saga Map Node Buttons (No default bottom border so zero grey line ever appears across stars!) */
.saga-node {
  touch-action: manipulation;
  transition: transform 0.08s ease, filter 0.12s ease;
  border: 0;
  background: transparent;
}
@media (hover: hover) {
  .saga-node:hover:not(:disabled) {
    filter: brightness(1.05);
  }
}
.saga-node:active:not(:disabled) {
  transform: translateY(1.5px);
}

/* Store Ribbon Card (Inspired by Cut the Rope Store) */
.store-ribbon {
  background: var(--bg-surface-elevated);
  border: 3px solid var(--border-subtle);
  box-shadow: 0 6px 0 rgba(0, 0, 0, 0.12), 0 10px 20px rgba(0, 0, 0, 0.08);
  transition: transform 0.08s ease, box-shadow 0.12s ease;
}
.store-ribbon:active {
  transform: translateY(2px);
  box-shadow: 0 3px 0 rgba(0, 0, 0, 0.12);
}

@keyframes floatMascot {
  0%, 100% { transform: translateY(0px) rotate(0deg); }
  50% { transform: translateY(-6px) rotate(1.5deg); }
}
.mascot-idle {
  animation: floatMascot 2.8s ease-in-out infinite;
}

@keyframes swingPendant {
  0%, 100% { transform: rotate(-5deg); }
  50% { transform: rotate(5deg); }
}
.pendant-swing {
  transform-origin: top center;
  animation: swingPendant 3.4s ease-in-out infinite;
}

@keyframes floatPointer {
  0%, 100% { transform: translate(-50%, 0px); }
  50% { transform: translate(-50%, -5px); }
}
.pointer-bounce {
  animation: floatPointer 1.4s ease-in-out infinite;
}

@keyframes handTapBounce {
  0%, 100% { transform: translate(-50%, 0px) scale(1); }
  50% { transform: translate(-50%, -7px) scale(1.08); }
}
.tutorial-hand-pointer {
  animation: handTapBounce 1.1s ease-in-out infinite;
  pointer-events: none;
  z-index: 28;
}

@keyframes tutorialRing {
  0%, 100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.75), inset 0 0 0 3.5px var(--accent-emerald); }
  50% { box-shadow: 0 0 0 8px rgba(16, 185, 129, 0), inset 0 0 0 3.5px var(--accent-emerald); }
}
.tutorial-target-tile {
  animation: tutorialRing 1.2s infinite;
  z-index: 18 !important;
}

@keyframes pulseRing {
  0% { box-shadow: 0 0 0 0 rgba(250, 204, 21, 0.65); }
  70% { box-shadow: 0 0 0 11px rgba(250, 204, 21, 0); }
  100% { box-shadow: 0 0 0 0 rgba(250, 204, 21, 0); }
}
.node-current-pulse {
  animation: pulseRing 1.8s infinite;
}

@keyframes popIn {
  0% { transform: scale(0.35) rotate(-12deg); opacity: 0; }
  70% { transform: scale(1.1) rotate(3deg); opacity: 1; }
  100% { transform: scale(1) rotate(0deg); opacity: 1; }
}
.symbol-pop {
  animation: popIn 0.22s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

@keyframes starSparkle {
  0%, 100% { transform: scale(1) rotate(0deg); opacity: 0.9; }
  50% { transform: scale(1.25) rotate(14deg); opacity: 1; }
}
.star-glint {
  transform-origin: center;
  animation: starSparkle 1.6s ease-in-out infinite;
}

@keyframes lineShimmer {
  0% { box-shadow: inset 0 0 0 0 rgba(250, 204, 21, 0); transform: scale(1); }
  40% { box-shadow: inset 0 0 0 3.5px var(--accent-gold), 0 4px 12px rgba(250, 204, 21, 0.35); transform: scale(1.04); }
  100% { box-shadow: inset 0 0 0 0 rgba(250, 204, 21, 0); transform: scale(1); }
}
.tile-shimmer {
  animation: lineShimmer 0.55s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
  z-index: 15 !important;
}

@keyframes pulseHint {
  0%, 100% { box-shadow: 0 0 0 0 rgba(250, 204, 21, 0.7), inset 0 0 0 3px var(--accent-gold); }
  50% { box-shadow: 0 0 0 6px rgba(250, 204, 21, 0), inset 0 0 0 3px var(--accent-gold-deep); }
}
.hint-highlight {
  animation: pulseHint 1.3s infinite;
  z-index: 12 !important;
}
.hint-target {
  box-shadow: inset 0 0 0 3.5px var(--accent-emerald) !important;
  background-color: rgba(16, 185, 129, 0.14) !important;
  z-index: 14 !important;
}
.error-stripes {
  background-image: repeating-linear-gradient(
    -45deg,
    rgba(225, 29, 72, 0.16),
    rgba(225, 29, 72, 0.16) 6px,
    rgba(225, 29, 72, 0.30) 6px,
    rgba(225, 29, 72, 0.30) 12px
  ) !important;
  box-shadow: inset 0 0 0 2.5px var(--accent-danger) !important;
}
@keyframes shakeError {
  0%, 100% { transform: translate(-50%, -50%) rotate(0deg); }
  25% { transform: translate(calc(-50% - 3px), -50%) rotate(-5deg); }
  75% { transform: translate(calc(-50% + 3px), -50%) rotate(5deg); }
}
.badge-error {
  animation: shakeError 0.35s ease-in-out 2;
  background-color: rgba(225, 29, 72, 0.18) !important;
  border-color: var(--accent-danger) !important;
  color: var(--accent-danger) !important;
}

/* Collapsible Brush Drawer (Transform/Opacity only, never width/left) */
.brush-drawer-closed {
  transform: scaleX(0);
  opacity: 0;
  pointer-events: none;
}
.brush-drawer-open {
  transform: scaleX(1);
  opacity: 1;
  pointer-events: auto;
}

/* Hallmark Mandate: Reduced Motion Fallback */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

::-webkit-scrollbar { width: 5px; height: 5px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(112, 130, 114, 0.35); border-radius: 9999px; }

/* White title with a dark outline (matches the TANGO logo) */
.world-title-outline {
  text-shadow: 2px 0 0 #1F2937, -2px 0 0 #1F2937, 0 2px 0 #1F2937, 0 -2px 0 #1F2937,
    2px 2px 0 #1F2937, -2px 2px 0 #1F2937, 2px -2px 0 #1F2937, -2px -2px 0 #1F2937, 0 4px 0 #1F2937;
}

/* A world chest gives a little shake as its reward pops out */
@keyframes chestShake {
  0%, 100% { transform: rotate(0deg) scale(1); }
  20% { transform: rotate(-8deg) scale(1.04); }
  40% { transform: rotate(8deg) scale(1.06); }
  60% { transform: rotate(-6deg) scale(1.08); }
  80% { transform: rotate(6deg) scale(1.1); }
}
.chest-shake { animation: chestShake 0.55s ease-in-out 2; }
@media (prefers-reduced-motion: reduce) { .chest-shake { animation: none; } }

/* Phase F: the road draws itself forward to the next stop after a first solve */
.road-reveal {
  stroke-dasharray: 1 2;
  stroke-dashoffset: 1;
  animation: roadReveal 1s cubic-bezier(0.45, 0, 0.3, 1) 0.35s forwards;
}
@keyframes roadReveal {
  to { stroke-dashoffset: 0; }
}

/* World-to-world wipe: the new sky opens from the centre, clouds drift, the card pops */
.world-wipe {
  animation: worldWipeIn 0.42s cubic-bezier(0.3, 0, 0.2, 1) both;
}
.world-wipe.is-leaving {
  animation: worldWipeOut 0.45s ease-in forwards;
}
.world-wipe-card {
  animation: worldCardPop 0.55s cubic-bezier(0.34, 1.56, 0.64, 1) 0.18s both;
}
.world-wipe-clouds {
  animation: worldCloudDrift 1.8s ease-out both;
}
.world-wipe-clouds.is-low {
  animation-direction: reverse;
}
@keyframes worldWipeIn {
  from { clip-path: circle(0% at 50% 50%); }
  to { clip-path: circle(150% at 50% 50%); }
}
@keyframes worldWipeOut {
  to { opacity: 0; transform: scale(1.06); }
}
@keyframes worldCardPop {
  from { opacity: 0; transform: scale(0.6) translateY(16px); }
  to { opacity: 1; transform: none; }
}
@keyframes worldCloudDrift {
  from { transform: translateX(-24px); }
  to { transform: translateX(24px); }
}

/* Your Sky Crew character sits on the board's corner and reacts to play */
#board-outer-frame {
  position: relative;
}
.board-buddy {
  position: absolute;
  left: -14px;
  top: -30px;
  width: 46px;
  height: 46px;
  z-index: 25;
  pointer-events: none;
  filter: drop-shadow(0 3px 4px rgba(15, 23, 42, 0.25));
}
.board-zoomed .board-buddy {
  display: none;
}
.buddy-hop {
  animation: buddyHop 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.buddy-shake {
  animation: buddyShake 0.5s ease-in-out;
}
@keyframes buddyHop {
  0%, 100% { transform: none; }
  40% { transform: translateY(-12px) scale(1.08); }
}
@keyframes buddyShake {
  0%, 100% { transform: none; }
  20% { transform: translateX(-4px) rotate(-8deg); }
  50% { transform: translateX(4px) rotate(8deg); }
  80% { transform: translateX(-2px) rotate(-4deg); }
}

@media (prefers-reduced-motion: reduce) {
  .road-reveal { animation: none; stroke-dashoffset: 0; }
  .world-wipe, .world-wipe.is-leaving, .world-wipe-card, .world-wipe-clouds { animation: none; }
  .buddy-hop, .buddy-shake { animation: none; }
}

/* Tapping a stop moves the Sun fast enough to finish before the level popup opens */
.sun-move-quick .anim-sun-dip {
  animation-duration: 0.3s;
  animation-delay: 0s;
}
.sun-move-quick .anim-sun-rise {
  animation-duration: 0.48s;
  animation-delay: 0.18s;
}

/* The Sun waits on the bridge once a world's levels are all solved */
.bridge-sun-in {
  animation: bridgeSunIn 0.7s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}
.bridge-sun-out {
  animation: bridgeSunOut 0.3s ease-in forwards;
}
.bridge-sun-bob {
  animation: bridgeSunBob 2.4s ease-in-out infinite;
}
@keyframes bridgeSunIn {
  from { opacity: 0; scale: 0.3; translate: 0 26px; }
  to { opacity: 1; scale: 1; translate: 0 0; }
}
@keyframes bridgeSunOut {
  to { opacity: 0; scale: 0.5; translate: 0 18px; }
}
@keyframes bridgeSunBob {
  0%, 100% { translate: 0 0; }
  50% { translate: 0 -5px; }
}

/* Claiming a chest: the open chest fades off the empty one */
.chest-art-leaving {
  position: absolute;
  animation: chestArtLeave 0.42s ease-out forwards;
}
@keyframes chestArtLeave {
  to { opacity: 0; scale: 1.12; }
}

/* New badge: dim the screen, pop the badge out, let it shine. Sits above the victory card and
   below the confetti, which stays at z-50. */
.badge-shade {
  z-index: 45;
  background: rgba(2, 6, 23, 0.68);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  animation: badgeShadeIn 0.25s ease-out both;
}
.badge-shade.is-leaving {
  animation: badgeShadeOut 0.25s ease-in forwards;
}
.badge-shade.is-leaving .badge-card {
  animation: badgeCardOut 0.25s ease-in forwards;
}
@keyframes badgeShadeIn { from { opacity: 0; } }
@keyframes badgeShadeOut { to { opacity: 0; } }
@keyframes badgeCardOut { to { transform: scale(0.8); } }
.badge-card {
  animation: badgePopOut 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}
@keyframes badgePopOut {
  0% { transform: scale(0.2) rotate(-14deg); opacity: 0; }
  100% { transform: scale(1) rotate(0deg); opacity: 1; }
}
.badge-stage {
  position: relative;
  width: 11rem;
  height: 12.1rem;
}
.badge-rays {
  position: absolute;
  left: 50%;
  top: 40%;
  width: 22rem;
  height: 22rem;
  margin: -11rem 0 0 -11rem;
  pointer-events: none;
  background: repeating-conic-gradient(rgba(255, 244, 190, 0.5) 0deg 11deg, transparent 11deg 30deg);
  -webkit-mask: radial-gradient(closest-side, #000 22%, transparent 100%);
  mask: radial-gradient(closest-side, #000 22%, transparent 100%);
  animation: badgeRaysSpin 14s linear infinite;
}
@keyframes badgeRaysSpin { to { transform: rotate(360deg); } }
.badge-art {
  position: relative;
  width: 100%;
  height: 100%;
  filter: drop-shadow(0 0 22px var(--badge-glow, #FDE68A));
}
/* A band of light crossing the badge's disc (centre 50% 40%, radius 34% of the art's width). */
.badge-sheen {
  position: absolute;
  left: 16%;
  top: 9.1%;
  width: 68%;
  aspect-ratio: 1;
  border-radius: 50%;
  overflow: hidden;
  pointer-events: none;
}
.badge-sheen::before {
  content: '';
  position: absolute;
  top: -20%;
  bottom: -20%;
  left: -60%;
  width: 34%;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.85), transparent);
  transform: rotate(18deg);
  animation: badgeSheen 2.8s ease-in-out 0.55s infinite;
}
@keyframes badgeSheen {
  0% { left: -60%; }
  45%, 100% { left: 125%; }
}
.badge-spark {
  position: absolute;
  width: 18px;
  height: 18px;
  pointer-events: none;
  background: #FFF7C2;
  clip-path: polygon(50% 0, 60% 40%, 100% 50%, 60% 60%, 50% 100%, 40% 60%, 0 50%, 40% 40%);
  animation: badgeSpark 1.6s ease-in-out infinite both;
}
@keyframes badgeSpark {
  0%, 100% { opacity: 0; transform: scale(0.3) rotate(0deg); }
  50% { opacity: 1; transform: scale(1.15) rotate(45deg); }
}
@media (prefers-reduced-motion: reduce) {
  .bridge-sun-bob, .badge-rays, .badge-sheen::before, .badge-spark { animation: none; }
  .badge-spark { opacity: 1; }
}

/* Safari ignores end padding in a scrolling flex row, so keep room for the last card's ring */
#themes-shop-list::after, #profile-frame-row::after {
  content: '';
  flex: 0 0 1px;
}

/* Dark mode for the screens that paint their own scenery. The map and the world select keep their
   colours under a night tint that sits above the ground (z-0) and below the clouds and buttons
   (z-10), so the levels stay bright; the shop and profile swap their daytime blue for night blue. */
html.dark .saga-map-ground::after,
html.dark .worlds-sky::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(8, 13, 38, 0.5) 0%, rgba(8, 13, 38, 0.38) 100%);
}
html.dark #view-shop,
html.dark #view-profile {
  background: linear-gradient(180deg, #102A4C 0%, #0B1633 100%) !important;
}

/* The board and its counters share one set of sizes, so every counter lines up with its row or
   column: the board's inner padding, the gap between tiles, and the row counters' width. */
#board-outer-frame {
  --board-pad: 6px;
  --tile-gap: 6px;
  --rowq-w: 24px;
  --rowq-gap: 6px;
}
@media (min-width: 640px) {
  #board-outer-frame { --board-pad: 8px; --tile-gap: 8px; --rowq-w: 28px; }
}
#board-outer-frame.board-lg { --tile-gap: 4px; }
#board-outer-frame.board-xl { --tile-gap: 3px; }
#board-container { padding: var(--board-pad); }
#grid-tiles { gap: var(--tile-gap); }
#constraint-layer, #tutorial-hand-layer { inset: var(--board-pad); }
.board-row-wrap { gap: var(--rowq-gap); }
.board-row-quotas {
  width: var(--rowq-w);
  row-gap: var(--tile-gap);
  /* the board container's padding plus its 1px border */
  padding: calc(var(--board-pad) + 1px) 0;
}
.board-quota-corner { width: calc(var(--rowq-w) + var(--rowq-gap)); }
.board-col-quotas {
  column-gap: var(--tile-gap);
  padding: 0 calc(var(--board-pad) + 1px);
}
/* Zoomed in, the counters stay on screen while the board scrolls under them */
#board-scroll-wrap.is-zoomed .board-col-row {
  position: sticky;
  top: 0;
  z-index: 32;
  padding: 3px 0;
  margin-bottom: 3px;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.94);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
}
#board-scroll-wrap.is-zoomed .board-quota-corner {
  position: sticky;
  left: 0;
  z-index: 1;
  align-self: stretch;
  border-radius: 12px 0 0 12px;
  background: rgba(255, 255, 255, 0.97);
}
#board-scroll-wrap.is-zoomed .board-row-quotas {
  position: sticky;
  left: 0;
  z-index: 31;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.94);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
}
html.dark #board-scroll-wrap.is-zoomed .board-col-row,
html.dark #board-scroll-wrap.is-zoomed .board-row-quotas {
  background: rgba(15, 23, 42, 0.94);
}
html.dark #board-scroll-wrap.is-zoomed .board-quota-corner {
  background: rgba(15, 23, 42, 0.97);
}

/* First-time guides (js/15-guides.js) and the Level 1 tutorial: the screen goes dark around one
   thing and a hand taps it. The masks catch stray taps; the hole lets the real tap through. */
.coach-mark {
  z-index: 55;
  pointer-events: none;
  animation: badgeShadeIn 0.25s ease-out both;
}
/* Four dark panels around the hole. */
.coach-mask {
  position: fixed;
  pointer-events: auto;
  background: rgba(2, 6, 23, 0.8);
}
.coach-ring {
  position: fixed;
  border-radius: 14px;
  border: 3px solid #FCD34D;
  pointer-events: none;
}
.coach-ring::after {
  content: '';
  position: absolute;
  inset: -3px;
  border-radius: inherit;
  animation: coachRingPulse 1.3s ease-in-out infinite;
}
@keyframes coachRingPulse {
  0%, 100% { box-shadow: 0 0 14px rgba(250, 204, 21, 0.6); }
  50% { box-shadow: 0 0 30px rgba(250, 204, 21, 1); }
}
.coach-bubble {
  position: fixed;
  /* a fixed width, so moving it sideways to stay on screen can't change how it wraps */
  width: max-content;
  max-width: min(300px, calc(100vw - 24px));
  padding: 10px 16px;
  border-radius: 18px;
  text-align: center;
  font-size: 17px;
  line-height: 1.25;
  color: #FFFFFF;
  background: linear-gradient(180deg, #FFB32C, #F26419);
  border: 3px solid #FFFFFF;
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.35);
  pointer-events: none;
}
.coach-skip {
  position: fixed;
  padding: 6px 14px;
  border-radius: 9999px;
  font-size: 12px;
  font-weight: 800;
  color: #0F172A;
  background: rgba(255, 255, 255, 0.92);
  pointer-events: auto;
}
/* The hand's fingertip is at (20px, 4px): it lifts away, comes down on the target and presses. */
.coach-hand {
  position: fixed;
  z-index: 56;
  width: 64px;
  height: 76px;
  pointer-events: none;
  filter: drop-shadow(0 6px 8px rgba(0, 0, 0, 0.35));
  transform-origin: 20px 4px;
  animation: coachHandTap 1.4s ease-in-out infinite;
}
@keyframes coachHandTap {
  0%, 100% { transform: translate(16px, 22px) rotate(-8deg); }
  38% { transform: translate(0, 0) rotate(0deg) scale(1); }
  48% { transform: translate(0, 2px) rotate(0deg) scale(0.92); }
  60% { transform: translate(0, 0) rotate(0deg) scale(1); }
}
.coach-ripple {
  position: fixed;
  z-index: 55;
  width: 54px;
  height: 54px;
  margin: -27px 0 0 -27px;
  border-radius: 50%;
  border: 4px solid #FEF08A;
  pointer-events: none;
  opacity: 0;
  animation: coachRipple 1.4s ease-out infinite;
}
@keyframes coachRipple {
  0%, 44% { opacity: 0; transform: scale(0.3); }
  48% { opacity: 0.95; transform: scale(0.4); }
  100% { opacity: 0; transform: scale(1.5); }
}
@media (prefers-reduced-motion: reduce) {
  .coach-hand { animation: none; transform: translate(6px, 8px); }
  .coach-ring, .coach-ripple { animation: none; }
}

/* Profile: while signed out, the account card is outlined so it reads as something to do */
#profile-account-card.account-card-pending {
  box-shadow: 0 0 0 3px #FBBF24, 0 14px 26px rgba(8, 47, 73, 0.25);
}

/* Home screen Sunny bursting after a long press: sparks fly out and fade */
#btn-mascot-tap {
  touch-action: none;
  -webkit-touch-callout: none;
}
.sunny-burst {
  position: fixed;
  inset: 0;
  z-index: 50;
  pointer-events: none;
}
.sunny-burst span {
  position: fixed;
  animation: sunnyBurstBit 0.8s cubic-bezier(0.2, 0.7, 0.3, 1) forwards;
}
@keyframes sunnyBurstBit {
  0% { transform: translate(0, 0) scale(1) rotate(0deg); opacity: 1; }
  100% { transform: translate(var(--dx), var(--dy)) scale(0.3) rotate(var(--spin)); opacity: 0; }
}
