/* ============ FX LAYER ============
 * Design space: x in [0, 100], y in [0, 133.33] (3:4 aspect page)
 * 1 unit (--u) = 1% of page width, set by JS on each resize.
 * All element sizes/positions use --u so ratio is preserved across screens.
 */

.page-fx {
  position: absolute; top: 0; right: 0; bottom: 0; left: 0;
  pointer-events: none; /* only buttons receive taps */
  z-index: 10;
}

.fx-el {
  position: absolute;
  left:   calc(var(--x) * var(--u));
  top:    calc(var(--y) * var(--u));
  width:  calc(var(--w) * var(--u));
  height: calc(var(--h) * var(--u));
  transform: translate(-50%, -50%); /* anchor: center (fixed) */
  padding: 0; margin: 0; border: 0; background: none;
  cursor: pointer;
  pointer-events: auto;
  -webkit-tap-highlight-color: transparent;
}

/* Inner wrappers: path (translates) + anim (rotates/scales/opacity) */
.fx-path {
  display: block; width: 100%; height: 100%;
  will-change: transform;
}
.fx-anim {
  display: block; width: 100%; height: 100%;
  transform-origin: center;
  will-change: transform, opacity, filter;
}

.fx-img, .fx-video {
  width: 100%; height: 100%;
  object-fit: contain;
  user-select: none;
  -webkit-user-drag: none;
  pointer-events: none;
}
.fx-img {
  filter: drop-shadow(0 2px 4px rgba(0,0,0,0.25));
}
.fx-video {
  display: block;
}

/* Idle state: static, no animation */
.fx-el .fx-anim {
  animation: none;
}

/* When playing, keep idle state (no extra CSS animation — APNG/video handles it) */
.fx-el.playing .fx-anim {
  animation: none;
}

/* ============ PRESETS ============ */

/* sway-lr: rotates left-right, pivoting at bottom (roots of plant) */
.fx-el.playing-sway-lr .fx-anim {
  transform-origin: center bottom;
  animation: sway-lr var(--anim-duration, 1600ms) ease-in-out;
}
@keyframes sway-lr {
  0%   { transform: rotate(0deg);  }
  20%  { transform: rotate(calc(var(--amplitude, 10) * -1deg)); }
  50%  { transform: rotate(calc(var(--amplitude, 10) *  1deg)); }
  80%  { transform: rotate(calc(var(--amplitude, 10) * -0.6deg)); }
  100% { transform: rotate(0deg);  }
}

/* walk-across:
 *   outer .fx-path → translate from start to (dx, dy) and back (round trip)
 *   inner .fx-anim → brief "wings open" scale flash at midpoint
 * dx/dy are in design units (one unit = 1% of page width via --u).
 */
.fx-el.playing-walk-across .fx-path {
  animation: walk-across var(--anim-duration, 2400ms) ease-in-out;
}
.fx-el.playing-walk-across .fx-anim {
  animation: wings-open-flash var(--anim-duration, 2400ms) ease-out;
}
@keyframes walk-across {
  0%   { transform: translate(0, 0); }
  50%  { transform: translate(calc(var(--dx, 30) * var(--u)), calc(var(--dy, 0) * var(--u))); }
  100% { transform: translate(0, 0); }
}
@keyframes wings-open-flash {
  0%, 35%, 65%, 100% { transform: scale(1); }
  50%                { transform: scale(1.35); }
}

/* bounce: simple vertical hop, one cycle. Amplitude is in design units. */
.fx-el.playing-bounce .fx-anim {
  animation: bounce var(--anim-duration, 600ms) ease-out;
}
@keyframes bounce {
  0%, 100% { transform: translateY(0); }
  40%      { transform: translateY(calc(var(--amplitude, 6) * var(--u) * -1)); }
  70%      { transform: translateY(calc(var(--amplitude, 6) * var(--u) * -0.3)); }
}

/* climb-up:
 *   outer .fx-path → translate upward by `distance` design units, hold, return
 *   inner .fx-anim → small body wobble for "legs push" feel
 */
.fx-el.playing-climb-up .fx-path {
  animation: climb-up var(--anim-duration, 2000ms) ease-in-out;
}
.fx-el.playing-climb-up .fx-anim {
  animation: climb-wobble var(--anim-duration, 2000ms) linear;
}
@keyframes climb-up {
  0%   { transform: translate(0, 0); }
  40%  { transform: translateY(calc(var(--distance, 15) * var(--u) * -1)); }
  60%  { transform: translateY(calc(var(--distance, 15) * var(--u) * -1)); }
  100% { transform: translate(0, 0); }
}
@keyframes climb-wobble {
  0%, 100% { transform: rotate(0deg); }
  20% { transform: rotate(-4deg); }
  40% { transform: rotate(4deg); }
  60% { transform: rotate(-3deg); }
  80% { transform: rotate(3deg); }
}

/* jump-between:
 *   2-hop arc — element jumps to (dx, 0) reaching peak height at midpoints, then back.
 *   `dx` = horizontal distance to next stone (design units)
 *   `height` = peak arc height (design units, positive = upward)
 */
.fx-el.playing-jump-between .fx-path {
  animation: jump-path var(--anim-duration, 2400ms) ease-in-out;
}
@keyframes jump-path {
  0%   { transform: translate(0, 0); }
  20%  { transform: translate(calc(var(--dx, 25) * 0.5 * var(--u)), calc(var(--height, 14) * var(--u) * -1)); }
  40%  { transform: translate(calc(var(--dx, 25) * var(--u)), 0); }
  55%  { transform: translate(calc(var(--dx, 25) * var(--u)), 0); }
  75%  { transform: translate(calc(var(--dx, 25) * 0.5 * var(--u)), calc(var(--height, 14) * var(--u) * -1)); }
  100% { transform: translate(0, 0); }
}

/* flow-loop:
 *   inner .fx-anim → subtle horizontal sway of the image
 *   .fx-anim::after → bright shimmer streak sweeping left → right (suggests flowing water)
 *   In the current "tap once" model this plays once per tap. For continuous loops a future
 *   auto-loop behavior would re-trigger automatically.
 */
.fx-el.playing-flow-loop .fx-anim {
  position: relative;
  overflow: hidden;
  animation: flow-sway var(--anim-duration, 2000ms) ease-in-out;
}
.fx-el.playing-flow-loop .fx-anim::after {
  content: '';
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  background: linear-gradient(90deg,
    transparent 0%,
    rgba(255, 255, 255, 0.55) 50%,
    transparent 100%);
  pointer-events: none;
  animation: flow-shimmer var(--anim-duration, 2000ms) linear;
}
@keyframes flow-sway {
  0%, 100% { transform: translateX(0) scale(1); }
  50%      { transform: translateX(2%) scale(1.02); }
}
@keyframes flow-shimmer {
  0%   { transform: translateX(-150%); }
  100% { transform: translateX(150%); }
}

/* petal-drift:
 *   inner .fx-anim → gentle sway (the flower itself)
 *   .fx-particle children → spawned by JS in playElement; each falls outward & down
 *   Particles read --tx (horizontal drift, design units), --ty (fall distance), and animation-delay.
 */
.fx-el.playing-petal-drift .fx-anim {
  animation: petal-sway var(--anim-duration, 2000ms) ease-in-out;
  transform-origin: center bottom;
}
@keyframes petal-sway {
  0%, 100% { transform: rotate(0deg); }
  30%      { transform: rotate(-6deg); }
  70%      { transform: rotate(6deg); }
}

.fx-particle {
  position: absolute;
  left: 50%; top: 50%;
  width:  calc(var(--u) * 3);
  height: calc(var(--u) * 3);
  margin-left: calc(var(--u) * -1.5);
  margin-top:  calc(var(--u) * -1.5);
  background: radial-gradient(circle at 35% 35%, #ffd1e0 30%, #e87aa0 90%);
  border-radius: 60% 40% 60% 40% / 40% 60% 40% 60%;
  pointer-events: none;
  opacity: 0;
  animation: petal-drift 1800ms ease-out forwards;
}
@keyframes petal-drift {
  0%   { transform: translate(0, 0) rotate(0deg) scale(0.4);  opacity: 0; }
  15%  { opacity: 1; }
  100% { transform: translate(var(--tx), var(--ty)) rotate(220deg) scale(0.7); opacity: 0; }
}

/* sparkle: opacity + brightness pulse, slight scale */
.fx-el.playing-sparkle .fx-anim {
  animation: sparkle var(--anim-duration, 1500ms) ease-in-out;
}
@keyframes sparkle {
  0%, 100% { opacity: 0.55; filter: brightness(1) saturate(1);   transform: scale(1);    }
  30%      { opacity: 1;    filter: brightness(1.6) saturate(1.3); transform: scale(1.18); }
  60%      { opacity: 0.85; filter: brightness(1.2) saturate(1.1); transform: scale(1.08); }
}

/* flap-flutter:
 *   outer .fx-path → circular flight path
 *   inner .fx-anim → wing flap (scaleX oscillation)
 */
.fx-el.playing-flap-flutter .fx-path {
  animation: flutter-path var(--anim-duration, 2500ms) ease-in-out;
}
.fx-el.playing-flap-flutter .fx-anim {
  animation: flutter-flap 180ms linear infinite;
}
@keyframes flutter-flap {
  0%, 100% { transform: scaleX(1);    }
  50%      { transform: scaleX(0.55); }
}
@keyframes flutter-path {
  0%   { transform: translate(0, 0); }
  25%  { transform: translate(18%, -14%); }
  50%  { transform: translate(0, -24%); }
  75%  { transform: translate(-18%, -14%); }
  100% { transform: translate(0, 0); }
}

/* ============ MOVEMENT TYPES (GIF-based elements) ============
 * These handle ONLY page-level translate on .fx-path.
 * Visual animation comes from the GIF itself.
 * Reuse existing keyframes where possible.
 */

/* circle: circular flight path (from flap-flutter) */
.fx-el.moving-circle .fx-path {
  animation: flutter-path var(--anim-duration, 2500ms) ease-in-out;
}

/* linear: round-trip translate (from walk-across) */
.fx-el.moving-linear .fx-path {
  animation: walk-across var(--anim-duration, 2400ms) ease-in-out;
}

/* climb: vertical translate up, hold, return (from climb-up) */
.fx-el.moving-climb .fx-path {
  animation: climb-up var(--anim-duration, 2000ms) ease-in-out;
}

/* hop: two-hop arc path (from jump-between) */
.fx-el.moving-hop .fx-path {
  animation: jump-path var(--anim-duration, 2400ms) ease-in-out;
}

/* bounce: vertical hop in-place */
.fx-el.moving-bounce .fx-anim {
  animation: bounce var(--anim-duration, 600ms) ease-out !important;
}

/* ============ FULLSCREEN VIDEO OVERLAY ============ */
.fx-fullscreen-video {
  position: absolute;
  top: 0; left: 0; width: 100%; height: 100%;
  object-fit: cover;
  z-index: 20;
  display: none;
}

/* Hide bg image when fullscreen video is active */
.page-slot.fx-fullscreen-active > div:first-child {
  visibility: hidden;
}

/* ============ HOTSPOT WORD BUBBLE ============
 * Rendered inside .page-slot (sibling of fullscreen video) so it can
 * layer above the video via z-index. Positioned from copied --x/--y/--h
 * vars of the hotspot button.
 */
.fx-word {
  position: absolute;
  left: calc(var(--x, 50) * var(--u));
  top:  calc((var(--y, 50) - var(--h, 10) / 2) * var(--u));
  transform: translate(-50%, -100%);
  z-index: 30;
  padding: calc(var(--u) * 1.2) calc(var(--u) * 2.4);
  background: white;
  color: #2a1f3d;
  font-family: 'Nunito', sans-serif;
  font-weight: 800;
  font-size: calc(var(--u) * 3.2);
  border-radius: calc(var(--u) * 2);
  box-shadow: 0 6px 20px rgba(0,0,0,0.25);
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  animation: word-pop 1800ms ease-out;
}
.fx-word::after {
  content: '';
  position: absolute;
  left: 50%; bottom: -6px;
  width: 12px; height: 12px;
  background: white;
  transform: translateX(-50%) rotate(45deg);
  box-shadow: 3px 3px 6px rgba(0,0,0,0.1);
}
@keyframes word-pop {
  0%   { opacity: 0; transform: translate(-50%, -80%) scale(0.6); }
  15%  { opacity: 1; transform: translate(-50%, -100%) scale(1.1); }
  30%  { transform: translate(-50%, -100%) scale(1); }
  80%  { opacity: 1; }
  100% { opacity: 0; transform: translate(-50%, -110%) scale(0.9); }
}

/* ============ DEV HOTSPOT DEBUG (?debug) ============
 * Activated when body has .debug-hotspots (set by ?debug URL param).
 * Draws a dashed outline + tinted fill over every .fx-el tap region
 * and labels each with its aria-label (element id).
 */
body.debug-hotspots .fx-el {
  outline: 2px dashed #ff00c8;
  outline-offset: -2px;
  background: rgba(255, 0, 200, 0.18);
}
body.debug-hotspots .fx-el::after {
  content: attr(aria-label);
  position: absolute;
  left: 0;
  top: 0;
  padding: 2px 6px;
  background: #ff00c8;
  color: #fff;
  font: 700 10px/1.2 'Nunito', sans-serif;
  white-space: nowrap;
  pointer-events: none;
  z-index: 1;
}
