/* Fox-island background visual — the homepage hero scene. It began as
   experiments/fox-island, which has since been folded into the site, so this is
   the only copy of the scene: the page markup is in index.html.
   Namespaced under fi- so nothing here collides with the site's own classes.
   The sky is rtf6x/css/fox-sky.css; this file styles the falling rocks and leaves, and the mount point of
   the exhaust; the flame itself is drawn by the shared PixiJS module
   rtf6x/js/thruster.js, started on the critical path from rtf6x/js/fox-island-bg.js.
   See rtf6x/pics/fox-island/README.md for how the source art was segmented into
   the layers animated below. */

.bg-module--fox-island {
  background: #050308;
}

/* Seated from the first frame, with no entrance: the scene used to rise the last
   80% of its height into place once the exhaust was ready, and the owner dropped
   that (2026-09-28). The cost is visible and accepted - the flame arrives with
   rtf6x/js/thruster.js a moment after the island is already standing. Anything
   added here again must leave the island in this seat at paint time. */
.fi-scene {
  position: absolute;
  top: 50%;
  right: 15%;
  transform: translateY(-35%);
  width: clamp(400px, 50vw, 700px);
  pointer-events: none;
}
.fi-scene__glow {
  position: absolute;
  inset: -8% -25%;
  z-index: 0;
  background: radial-gradient(45% 40% at 50% 30%, rgba(255, 148, 74, 0.12), transparent 72%);
  filter: blur(14px);
}
.fi-scene__base {
  position: relative;
  z-index: 3;
  width: 100%;
  height: auto;
  display: block;
  filter: drop-shadow(0 26px 50px rgba(0, 0, 0, 0.6));
}
/* Float track: the island, its exhaust and both particle bands all hang from
   .fi-scene__float, so one transform moves the whole scene together and nothing
   can drift out of step.
   ease-in-out softens the turnarounds - the pass eases in and out instead of
   reversing at full speed - and the middle stays steady; alternate supplies the
   way back.
   The travel is a transform on the container, not a margin on the parts: it is
   carried by the compositor, while a layout shift on the parts is re-laid out
   and snapped frame by frame.
   The keyframes hold literal values and no custom property on purpose: the
   animation stays static, which both engines hand to their compositor, and a
   percentage keeps the travel proportional where the scene is smaller. */
@keyframes fi-float {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(0, -3%, 0); }
}
.fi-scene__float {
  /* ease-in-out: the travel eases in and out at both ends of the pass, so the
     turnarounds are soft instead of a hard reversal, and the middle is steady. */
  animation: fi-float 4.5s ease-in-out infinite alternate;
  /* Keep the whole scene on its own composited layer for the whole animation:
     the travel is a fraction of a pixel per frame, and re-rasterising the layer
     each frame is what turns that into visible stepping. */
  will-change: transform;
}

/* Spawn bands: one box per particle kind, each exactly the band its particles
   fly in. The box geometry and every spawn/flight percentage inside it are set
   from rtf6x/js/fox-island-bg.js, so a band and its contents cannot disagree.
   z-index is left at auto on purpose: an absolutely positioned box without a
   z-index does NOT create a stacking context, so a leaf keeps its own z-index
   against the island and can pass behind the trunk and come out in front of the
   rock. A z-index here would flatten the whole group into one level. */
.fi-debris-layer,
.fi-leaf-layer {
  position: absolute;
  pointer-events: none;
}

.fi-debris {
  position: absolute;
  z-index: 1;
  pointer-events: none;
  animation-name: fi-fallDrift;
  animation-timing-function: cubic-bezier(0.5, 0, 0.85, 0.35);
}
.fi-debris img {
  width: 100%;
  height: auto;
  display: block;
}
@keyframes fi-fallDrift {
  0% { top: calc(var(--fi-t0) * 1%); transform: translateX(0) rotate(0deg); opacity: 0; }
  8% { opacity: 0.95; }
  78% { opacity: 0.7; }
  100% {
    top: calc(var(--fi-t1) * 1%);
    transform: translateX(var(--fi-dx, 6%)) rotate(var(--fi-rot, 26deg));
    opacity: 0;
  }
}

.fi-leaf {
  position: absolute;
  z-index: 1;
  pointer-events: none;
  width: 8px;
  animation-name: fi-leafFall;
  animation-timing-function: ease-in;
}
.fi-leaf svg {
  width: 100%;
  height: auto;
  display: block;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.35));
}
@keyframes fi-leafFall {
  0% { top: calc(var(--fi-t0) * 1%); transform: translateX(0) rotate(-10deg); opacity: 0; z-index: 1; }
  18% { opacity: 0; z-index: 1; }
  23% { z-index: 4; }
  30% { opacity: 0.9; }
  50% { transform: translateX(var(--fi-sway1, 7%)) rotate(50deg); }
  74% { transform: translateX(var(--fi-sway2, -6%)) rotate(-30deg); }
  92% { opacity: 0.85; }
  100% {
    top: calc(var(--fi-t1) * 1%);
    transform: translateX(2%) rotate(70deg);
    opacity: 0;
    z-index: 4;
  }
}

.fi-flame {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  /* The PixiJS canvas is laid out inside by rtf6x/js/thruster.js from the
     emitter fractions, so this element is only a mount point -- and it rides the
     island's float track, or the vent would drift out from under the flame. */
}
@media (prefers-reduced-motion: reduce) {
  .fi-scene__float,
  .fi-debris,
  .fi-leaf {
    animation: none;
  }
}

@media (max-width: 900px) {
  .fi-scene {
    right: 50%;
    transform: translate(50%, -50%);
    width: clamp(220px, 70vw, 380px);
    opacity: 0.9;
  }
}
