/* The night-valley scene: the landing page hero and the game's loading screen.
   Source of truth: apps/web/tools/scene.css. `apps/web/tools/scene.py` copies it to /scene/scene.css of both apps.
   The scene is a 480x270 pixel picture. --u is one scene pixel in CSS pixels; the stage covers its box like
   `object-fit: cover`, anchored to the bottom so the fire is always in view. */
.scene { position: absolute; inset: 0; overflow: hidden; container-type: size; background: #0b0918; pointer-events: none; }
.sc-stage { --w: max(100cqw, 177.78cqh); --u: calc(var(--w) / 480); position: absolute; left: 50%; bottom: 0; width: var(--w); aspect-ratio: 16 / 9;
  /* on a narrow screen look a little left of the middle, so the hero and the fire are both in view */
  transform: translateX(calc(-50% + min(var(--u) * 36, (var(--w) - 100cqw) / 2))); image-rendering: pixelated; }
.sc-stage i { position: absolute; display: block; background-repeat: no-repeat; background-size: 100% 100%; }
.sc-l { inset: 0; transform: translate(calc(var(--px, 0) * var(--d, 0) * var(--u)), calc(var(--py, 0) * var(--d, 0) * var(--u))); transition: transform 0.6s ease-out; }
.sc-sky { background-image: url(sky.png); }
.sc-far { background-image: url(far.png); --d: 1; }
.sc-mid { background-image: url(mid.png); --d: 2; }
.sc-near { background-image: url(near.png); --d: 3; }
.sc-clearing { background-image: url(clearing.png); --d: 4; }
.sc-front { background-image: url(front.png); --d: 9; inset: 0 -3%; }

/* a few stars that breathe */
.sc-star { width: var(--u); height: var(--u); background: #f2ece0; animation: sc-twinkle 4s ease-in-out infinite; }
.sc-star.b { width: calc(var(--u) * 3); height: calc(var(--u) * 3); background:
  linear-gradient(#fff8d8, #fff8d8) center / var(--u) 100% no-repeat, linear-gradient(#fff8d8, #fff8d8) center / 100% var(--u) no-repeat; }
@keyframes sc-twinkle { 0%, 100% { opacity: 0.25; } 50% { opacity: 1; } }

/* slow clouds across the moon */
.sc-cloud { width: calc(var(--u) * 96); height: calc(var(--u) * 30); background-image: url(cloud.png); opacity: 0.9; animation: sc-drift 140s linear infinite; }
.sc-cloud.p { width: calc(var(--u) * 48); height: calc(var(--u) * 24); background-image: url(cloud_puff.png); }
@keyframes sc-drift { from { transform: translateX(calc(var(--u) * -140)); } to { transform: translateX(calc(var(--u) * 620)); } }

/* the Rift breathes, slowly */
.sc-rift { left: calc(var(--u) * 205); top: calc(var(--u) * 120); width: calc(var(--u) * 80); height: calc(var(--u) * 80);
  background: radial-gradient(closest-side, rgba(255, 140, 50, 0.45), rgba(200, 60, 40, 0.18) 55%, transparent); mix-blend-mode: screen;
  animation: sc-breathe 7s ease-in-out infinite; }
@keyframes sc-breathe { 0%, 100% { opacity: 0.45; transform: scale(0.9); } 50% { opacity: 1; transform: scale(1.08); } }

/* the bonfire: stone ring sprite, four-frame flame, warm light on the grass */
.sc-fireset { position: absolute; inset: 0; transform: translate(calc(var(--px, 0) * 4 * var(--u)), calc(var(--py, 0) * 4 * var(--u))); transition: transform 0.6s ease-out; }
.sc-light { left: calc(var(--u) * 140); top: calc(var(--u) * 160); width: calc(var(--u) * 200); height: calc(var(--u) * 140);
  background: radial-gradient(closest-side, rgba(255, 190, 90, 0.42), rgba(255, 120, 40, 0.16) 50%, transparent); mix-blend-mode: screen;
  animation: sc-flicker 2.3s steps(1) infinite; }
@keyframes sc-flicker { 0% { opacity: 0.9; } 13% { opacity: 1; } 29% { opacity: 0.82; } 41% { opacity: 0.97; } 58% { opacity: 0.86; } 72% { opacity: 1; } 86% { opacity: 0.9; } }
.sc-base { left: calc(var(--u) * 190); top: calc(var(--u) * 168); width: calc(var(--u) * 96); height: calc(var(--u) * 96); background-image: url(bonfire_base.png); }
.sc-fire { left: calc(var(--u) * 226); top: calc(var(--u) * 196); width: calc(var(--u) * 28); height: calc(var(--u) * 44);
  background-image: url(fire.png); background-size: 400% 100% !important; animation: sc-frames 0.5s steps(4) infinite; }
@keyframes sc-frames { from { background-position: 0 0; } to { background-position: 133.333% 0; } }

/* sparks: square embers that rise and fade */
.sc-ember { left: calc(var(--u) * 240); top: calc(var(--u) * 206); width: var(--u); height: var(--u); background: #ffe066;
  animation: sc-rise 3.2s linear infinite; opacity: 0; }
.sc-ember:nth-of-type(2n) { background: #ffa030; animation-duration: 4.1s; }
.sc-ember:nth-of-type(3n) { background: #fffbe0; animation-duration: 2.7s; }
@keyframes sc-rise {
  0% { opacity: 0; transform: translate(0, 0); }
  10% { opacity: 1; }
  50% { transform: translate(calc(var(--u) * var(--dx, 3)), calc(var(--u) * -34)); }
  100% { opacity: 0; transform: translate(calc(var(--u) * var(--dx, 3) * -0.6), calc(var(--u) * -78)); } }
.sc-smoke { left: calc(var(--u) * 228); top: calc(var(--u) * 180); width: calc(var(--u) * 24); height: calc(var(--u) * 12); background-image: url(smoke.png); opacity: 0; animation: sc-smoke 9s linear infinite; }
@keyframes sc-smoke { 0% { opacity: 0; transform: translate(0, 0) scale(0.6); } 15% { opacity: 0.32; }
  100% { opacity: 0; transform: translate(calc(var(--u) * 22), calc(var(--u) * -90)) scale(2.2); } }

/* the hero, hood up, by the fire; the Spark keeps the tools turning around them */
.sc-hero { left: calc(var(--u) * 158); top: calc(var(--u) * 206); width: calc(var(--u) * 24); height: calc(var(--u) * 32); }
.sc-body { inset: 0; background-image: url(hero.png); background-size: 200% 100% !important; animation: sc-cast 9s steps(1) infinite, sc-breath 2.8s ease-in-out infinite; }
@keyframes sc-cast { 0%, 64% { background-position: 0 0; } 65%, 82% { background-position: 100% 0; } 83% { background-position: 0 0; } }
@keyframes sc-breath { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(calc(var(--u) * -0.5)); } }
.sc-ring { position: absolute; left: 50%; top: 52%; width: 0; height: 0; transform: scaleY(0.38); }
.sc-spin { position: absolute; inset: 0; animation: sc-spin 7s linear infinite; animation-delay: var(--t, 0s); }
.sc-tool { position: absolute; left: 0; top: 0; width: calc(var(--u) * 13); height: calc(var(--u) * 13); margin: calc(var(--u) * -6.5);
  transform: translateX(calc(var(--u) * 22)) rotate(0deg); animation: sc-unspin 7s linear infinite; animation-delay: var(--t, 0s); }
.sc-tool::after { content: ''; position: absolute; inset: 0; background: var(--img) center / 100% 100% no-repeat; animation: sc-bob 1.3s ease-in-out infinite alternate; }
@keyframes sc-spin { to { transform: rotate(360deg); } }
/* undo the turn and the squash so each tool stays upright on its ellipse */
@keyframes sc-unspin { from { transform: translateX(calc(var(--u) * 22)) rotate(0deg) scaleY(2.6316); } to { transform: translateX(calc(var(--u) * 22)) rotate(-360deg) scaleY(2.6316); } }
@keyframes sc-bob { to { transform: translateY(calc(var(--u) * -1.5)) rotate(-8deg); } }
.sc-spark { left: calc(var(--u) * 176); top: calc(var(--u) * 200); width: calc(var(--u) * 9); height: calc(var(--u) * 9); background-image: url(spark.png);
  animation: sc-pulse 1.8s ease-in-out infinite alternate; }
@keyframes sc-pulse { from { opacity: 0.55; transform: scale(0.8) translateY(0); } to { opacity: 1; transform: scale(1.1) translateY(calc(var(--u) * -2)); } }

/* fireflies over the grass */
.sc-fly { width: var(--u); height: var(--u); background: #fff0a8; box-shadow: 0 0 calc(var(--u) * 3) calc(var(--u) * 1) rgba(255, 224, 120, 0.55);
  animation: sc-wander 11s ease-in-out infinite, sc-blink 2.6s steps(2) infinite; }
@keyframes sc-wander { 0%, 100% { transform: translate(0, 0); } 25% { transform: translate(calc(var(--u) * 9), calc(var(--u) * -6)); }
  50% { transform: translate(calc(var(--u) * 3), calc(var(--u) * -12)); } 75% { transform: translate(calc(var(--u) * -7), calc(var(--u) * -4)); } }
@keyframes sc-blink { 0% { opacity: 1; } 50% { opacity: 0.25; } }

@media (prefers-reduced-motion: reduce) {
  .scene *, .scene *::after { animation: none !important; transition: none !important; }
  .sc-ember, .sc-smoke { display: none !important; }
}
