/* Story effects (see js/storyfx.js). Only transform and opacity animate, so the Fire stays smooth. */
.sp-fx { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }
.sp-fx.back { z-index: 0; }
.sp-item { z-index: 1; }
.sp-fx.front { z-index: 2; }
.sp-fx > i { position: absolute; inset: 0; display: block; }
.sp-fx b { position: absolute; display: block; }

/* Night: a blue tint, a moon and twinkling stars */
.fx-night { background: linear-gradient(rgba(12, 20, 60, .62), rgba(20, 30, 80, .4)); }
.fx-moon { inset: auto !important; right: 8%; top: 8%; width: 13cqh; height: 13cqh; border-radius: 50%; box-shadow: inset -3.5cqh -1.5cqh 0 0 #f6efc4; }
.fx-stars b { width: 1.2cqh; height: 1.2cqh; border-radius: 50%; background: #fff; animation: fx-twinkle 2.4s ease-in-out infinite; }
@keyframes fx-twinkle { 50% { opacity: .2; transform: scale(.5); } }

/* Sun with slowly turning rays */
.fx-sun { inset: auto !important; right: 6%; top: 4%; width: 20cqh; height: 20cqh; }
.fx-sun::before { content: ""; position: absolute; inset: 22%; border-radius: 50%; background: radial-gradient(#fff6b0, #ffd426 60%, #ffb800); box-shadow: 0 0 6cqh #ffe27a; }
.fx-sun b { inset: 0; border-radius: 50%; background: repeating-conic-gradient(rgba(255, 214, 40, .75) 0 10deg, transparent 10deg 30deg);
  -webkit-mask: radial-gradient(circle, transparent 34%, #000 36%, #000 62%, transparent 64%); mask: radial-gradient(circle, transparent 34%, #000 36%, #000 62%, transparent 64%);
  animation: fx-spin 14s linear infinite; }
@keyframes fx-spin { to { transform: rotate(360deg); } }

.fx-rainbow { inset: auto !important; left: 22%; bottom: 22%; width: 56%; height: 70%; border-radius: 50% 50% 0 0 / 100% 100% 0 0;
  background: radial-gradient(ellipse at 50% 100%, transparent 52%, #e2392c 52% 57%, #f28c28 57% 62%, #ffd426 62% 67%, #23a050 67% 72%, #2878e0 72% 77%, #7b4fd0 77% 82%, transparent 82%);
  opacity: .8; animation: fx-fadein 1.6s ease-out both; }
@keyframes fx-fadein { from { opacity: 0; transform: scale(.9); transform-origin: 50% 100%; } }

/* Drifting clouds (grey ones when it rains) */
.fx-clouds b { left: -30%; width: 26cqw; height: 9cqh; border-radius: 99px; background: #fff; opacity: .9;
  box-shadow: 5cqw -3cqh 0 1cqh #fff, -4cqw -1.5cqh 0 .5cqh #fff; animation: fx-drift 24s linear infinite; }
.fx-clouds.grey b { background: #7d889c; box-shadow: 5cqw -3cqh 0 1cqh #7d889c, -4cqw -1.5cqh 0 .5cqh #7d889c; }
@keyframes fx-drift { to { transform: translateX(170cqw); } }
.fx-dim { background: rgba(60, 72, 96, .28); }

/* Rain: streaks falling at a slant, rings on the road */
.fx-rain b { top: -12%; width: .45cqw; height: 9cqh; border-radius: 99px; background: linear-gradient(rgba(235, 244, 255, 0), rgba(235, 244, 255, .95));
  transform: rotate(14deg); animation: fx-fall .7s linear infinite; }
@keyframes fx-fall { to { transform: translate(-8cqh, 125cqh) rotate(14deg); } }
.fx-ripples b { width: 6cqw; height: 2cqh; border: .35cqh solid rgba(220, 235, 255, .8); border-radius: 50%; animation: fx-ripple 1.6s ease-out infinite; }
@keyframes fx-ripple { 0% { transform: scale(.2); opacity: 1; } 100% { transform: scale(1.4); opacity: 0; } }
.fx-flash { background: #fff; opacity: 0; animation: fx-flash 4.5s linear infinite; }
@keyframes fx-flash { 0%, 88%, 100% { opacity: 0; } 90% { opacity: .75; } 92% { opacity: .1; } 94% { opacity: .6; } }

/* Snow: soft flakes that drift as they fall, and a white ground */
.fx-snow b { top: -6%; width: 1.8cqh; height: 1.8cqh; border-radius: 50%; background: #fff; transform: scale(var(--s, 1)); animation: fx-flake 5s linear infinite; }
@keyframes fx-flake { 25% { translate: 2cqw 28cqh; } 50% { translate: -1cqw 55cqh; } 75% { translate: 2cqw 82cqh; } 100% { translate: 0 112cqh; } }
.fx-snowground { inset: auto 0 0 0 !important; height: 12%; background: linear-gradient(rgba(255, 255, 255, .5), #f4f8ff); }

/* Wind: leaves tumbling across */
.fx-wind b { left: -8%; width: 2.6cqh; height: 1.4cqh; border-radius: 0 100% 0 100%; background: #6fb35f; animation: fx-gust 3s linear infinite; }
.fx-wind b:nth-child(3n) { background: #e8a33a; }
@keyframes fx-gust { 0% { transform: translate(0, 0) rotate(0); } 50% { transform: translate(60cqw, -8cqh) rotate(300deg); } 100% { transform: translate(120cqw, 4cqh) rotate(640deg); } }
.fx-fog b { left: -40%; width: 70%; height: 22%; border-radius: 50%; background: rgba(240, 244, 250, .7); filter: blur(2cqh); animation: fx-drift 16s linear infinite; }

/* Speed: white lines rushing past */
.fx-speed b { right: -30%; height: .7cqh; border-radius: 99px; background: rgba(255, 255, 255, .85); animation: fx-whoosh .7s linear infinite; }
@keyframes fx-whoosh { from { transform: translateX(0); opacity: 0; } 20% { opacity: 1; } to { transform: translateX(-150cqw); opacity: 0; } }

/* A win: confetti */
.fx-confetti b { top: -8%; width: 1.4cqh; height: 2.2cqh; border-radius: .3cqh; animation: fx-confetti 3s linear infinite; }
@keyframes fx-confetti { 0% { transform: translateY(0) rotate(0); } 100% { transform: translateY(118cqh) rotate(720deg); } }

/* Splashing water: rolling waves and drops */
.fx-waves { inset: auto 0 0 0 !important; height: 12%; background: repeating-radial-gradient(circle at 50% 0, transparent 0 3cqh, rgba(255, 255, 255, .55) 3cqh 3.8cqh, transparent 3.8cqh 6cqh);
  background-size: 12cqh 6cqh; animation: fx-waves 2.4s linear infinite; opacity: .8; }
@keyframes fx-waves { to { background-position: 12cqh 0; } }
.fx-drops b { bottom: 8%; width: 1.4cqh; height: 1.4cqh; border-radius: 50% 50% 50% 0; background: #9fd8ff; animation: fx-hopdrop 1.4s ease-out infinite; }
@keyframes fx-hopdrop { 0% { transform: translateY(0) scale(.4); opacity: 0; } 30% { opacity: 1; } 60% { transform: translateY(-22cqh) scale(1); } 100% { transform: translateY(0) scale(.5); opacity: 0; } }

.fx-sparkle b { width: 3cqh; height: 3cqh; background: #fff6b0; clip-path: polygon(50% 0, 62% 38%, 100% 50%, 62% 62%, 50% 100%, 38% 62%, 0 50%, 38% 38%); animation: fx-twinkle 1.8s ease-in-out infinite; }
.fx-notes b { bottom: 30%; font: 700 8cqh/1 var(--read); color: #2b2f3a; animation: fx-float 3s ease-in infinite; }
@keyframes fx-float { 0% { transform: translateY(0); opacity: 0; } 20% { opacity: 1; } 100% { transform: translate(4cqw, -40cqh); opacity: 0; } }

/* What things on the ground do */
.sp-item > i { position: absolute; pointer-events: none; }
.act-hop .sp-in img { animation: fx-hop 1.3s ease-in-out infinite; }
@keyframes fx-hop { 0%, 60%, 100% { transform: translateY(0); } 30% { transform: translateY(-18%); } }
.act-fly .sp-in img { animation: fx-fly 3.2s ease-in-out infinite; }
@keyframes fx-fly { 0%, 100% { transform: translate(0, -40%) rotate(-4deg); } 50% { transform: translate(12%, -70%) rotate(5deg); } }
.act-spin .sp-in img { animation: fx-spin 2.4s linear infinite; }
.act-bob .sp-in img { animation: fx-bobwater 2.6s ease-in-out infinite; }
@keyframes fx-bobwater { 50% { transform: translateY(-8%) rotate(4deg); } }
.act-flutter .sp-in img { transform-origin: 10% 100%; animation: fx-flutter 1.4s ease-in-out infinite; }
@keyframes fx-flutter { 50% { transform: skewY(-6deg) scaleX(.92); } }
.act-cheer .sp-in > * { animation: fx-cheer 1s ease-in-out infinite; transform-origin: 50% 100%; }
@keyframes fx-cheer { 0%, 100% { transform: translateY(0) scale(1); } 40% { transform: translateY(-12%) scale(1.06); } }
.act-pulse .sp-in img { animation: fx-pulse 1.4s ease-in-out infinite; }
@keyframes fx-pulse { 50% { transform: scale(1.14); filter: drop-shadow(0 0 2cqh #ffe27a); } }
.act-float .sp-in img { animation: fx-cheer 1.6s ease-in-out infinite; }
.act-wobble .sp-in img { animation: fx-wobble 1.8s ease-in-out infinite; }
@keyframes fx-wobble { 25% { transform: rotate(-7deg); } 75% { transform: rotate(7deg); } }
.act-sway .sp-in img { transform-origin: 50% 100%; animation: fx-sway 1.2s ease-in-out infinite; }
.act-sway.soft .sp-in img { animation-duration: 3.4s; }
@keyframes fx-sway { 50% { transform: rotate(-6deg); } }
.act-burst .sp-in img { animation: fx-burst .9s ease-out infinite; }
@keyframes fx-burst { 0% { transform: scale(.6) rotate(-10deg); } 40% { transform: scale(1.25) rotate(8deg); } 100% { transform: scale(.9); } }
.act-roll .sp-in img { animation: fx-roll 2.4s ease-in-out infinite; }
@keyframes fx-roll { 50% { transform: translateX(6%) translateY(-2%); } }

/* Cars */
.act-zoom .sp-in svg { animation: fx-zoom .5s ease-in-out infinite !important; }
@keyframes fx-zoom { 0%, 100% { transform: translateX(0) rotate(0); } 50% { transform: translateX(3%) rotate(-1.2deg) translateY(-1%); } }
.act-zoom .sp-in { animation: sp-pop .5s cubic-bezier(.2, .9, .3, 1.4) both, fx-surge 2.4s ease-in-out .6s infinite; }
@keyframes fx-surge { 50% { translate: 8cqw 0; } }
.act-climb .sp-in svg { animation: fx-climb 2.6s ease-in-out infinite !important; transform-origin: 30% 100%; }
@keyframes fx-climb { 0%, 100% { transform: rotate(-7deg) translateY(-6%); } 50% { transform: rotate(-9deg) translate(4%, -10%); } }
.act-shake .sp-in svg { animation: fx-shake .5s linear infinite !important; }
@keyframes fx-shake { 25% { transform: translate(-1.5%, -1%) rotate(-1.5deg); } 50% { transform: translate(1.5%, 0) rotate(1deg); } 75% { transform: translate(-1%, -1.5%) rotate(-1deg); } }
.act-skid .sp-in svg { animation: fx-skid 2.4s ease-out infinite !important; transform-origin: 80% 100%; }
@keyframes fx-skid { 0% { transform: translateX(-8%); } 30% { transform: translateX(2%) rotate(2deg); } 45%, 100% { transform: none; } }
.act-cheer.sparky .sp-in svg, .act-sleepy .sp-in svg { transform-origin: 50% 100%; }
.act-sleepy .sp-in svg { animation: fx-breathe 3s ease-in-out infinite; }
@keyframes fx-breathe { 50% { transform: scaleY(.96); } }

.fx-beam { left: 92%; bottom: 18%; width: 80%; height: 46%; background: linear-gradient(90deg, rgba(255, 246, 196, .75), rgba(255, 246, 196, 0)); clip-path: polygon(0 40%, 100% 0, 100% 100%, 0 60%); }
.fx-mud { inset: 30% 10% 18% 10%; }
.fx-mud b { position: absolute; width: 14%; aspect-ratio: 1.3; border-radius: 50%; background: #7a4a24; opacity: .85; }
.fx-mud b:nth-child(1) { left: 6%; top: 40%; } .fx-mud b:nth-child(2) { left: 30%; top: 60%; width: 9%; } .fx-mud b:nth-child(3) { left: 58%; top: 35%; width: 11%; } .fx-mud b:nth-child(4) { left: 80%; top: 62%; width: 8%; }
.fx-spray { left: -22%; bottom: 0; width: 30%; height: 40%; background: radial-gradient(ellipse at 100% 100%, rgba(220, 235, 255, .85), rgba(220, 235, 255, 0) 70%); animation: fx-puff .5s ease-out infinite; }
.fx-dust { left: -26%; bottom: 0; width: 34%; height: 40%; }
.fx-dust b { position: absolute; bottom: 0; width: 34%; aspect-ratio: 1; border-radius: 50%; background: rgba(214, 190, 150, .7); animation: fx-puff 1s ease-out infinite; }
.fx-dust b:nth-child(2) { left: 30%; animation-delay: -.33s; } .fx-dust b:nth-child(3) { left: 60%; animation-delay: -.66s; }
@keyframes fx-puff { 0% { transform: scale(.3) translateX(0); opacity: .9; } 100% { transform: scale(1.3) translateX(-40%); opacity: 0; } }
.fx-skid { left: -30%; bottom: 2%; width: 40%; height: 5%; border-radius: 99px; background: linear-gradient(90deg, rgba(40, 40, 50, 0), rgba(40, 40, 50, .55)); }
.fx-pow { left: 55%; top: -45%; font: 400 9cqh/1 var(--display); color: #e2392c; -webkit-text-stroke: .5cqh #fff; paint-order: stroke; animation: fx-burst .9s ease-out infinite; white-space: nowrap; }
.fx-zzz { left: 60%; top: -30%; }
.fx-zzz b { position: absolute; font: 700 6cqh/1 var(--read); color: #2b2f3a; animation: fx-float 2.6s ease-in infinite; }
.fx-zzz b:nth-child(2) { animation-delay: -.9s; font-size: 7.5cqh; } .fx-zzz b:nth-child(3) { animation-delay: -1.8s; font-size: 9cqh; }

/* Calm mode and reduced motion: everything still shows, nothing moves */
body.calm .sp-fx *, body.calm .sp-item * { animation: none !important; }
@media (prefers-reduced-motion: reduce) { .sp-fx *, .sp-item * { animation: none !important; } }
body.calm .fx-rain b, body.calm .fx-snow b, body.calm .fx-confetti b { top: calc(var(--y, 40) * 1%); }
body.calm .fx-wind b { left: calc(var(--y, 40) * 1%); }
@media (prefers-reduced-motion: reduce) { .fx-rain b, .fx-snow b, .fx-confetti b { top: calc(var(--y, 40) * 1%); } }

/* The beach scene's sea (between 50% and 70% down the strip) shimmers */
.fx-sea { inset: 50% 0 30% 0 !important; background: repeating-linear-gradient(90deg, transparent 0 6cqw, rgba(255, 255, 255, .45) 6cqw 8cqw, transparent 8cqw 14cqw);
  -webkit-mask: linear-gradient(transparent, #000 40%, #000 60%, transparent); mask: linear-gradient(transparent, #000 40%, #000 60%, transparent); animation: fx-sea 5s linear infinite; }
@keyframes fx-sea { to { background-position: 14cqw 0; } }
