/* Each moving illustration lives inside a stationary, feathered viewport.
   Mask the viewport, not the image: parallax must never move the seam. */
#gabby-world {
  --scene-feather: clamp(100px, 12vw, 190px);
  --scenery-travel: 44px;
  --device-travel: 48px;
  /* Do not create an unscrolled overflow container above the view timelines. */
  overflow: clip;
}

#gabby-world .scene {
  overflow: clip;
}

#gabby-world .scene::after {
  background: none;
}

#gabby-world .arrival {
  background: linear-gradient(#d0edf9 0%, #d0edf9 35%, #c2dfa0 80%, #b6d97e);
}

#gabby-world .picnic {
  background: linear-gradient(#b6d97e, #b9dd91);
}

#gabby-world .pond {
  background: linear-gradient(#b9dd91, #74d2c4 42%, #92dfe0 75%, #d8eff2);
}

#gabby-world .try-scene {
  background: linear-gradient(#d8eff2, #e0f3f4 30%, #e5edd6 75%, #f9f5e9);
}

/* Keep an opaque reading surface behind this copy at every scroll position.
   The soft outer edge blends into the sky without masking the demo below. */
#gabby-world .try-heading {
  position: relative;
  isolation: isolate;
  padding: 24px 20px;
}

#gabby-world .try-heading::before {
  content: '';
  position: absolute;
  inset: -12px -24px;
  z-index: -1;
  pointer-events: none;
  border-radius: 48px;
  background: #d8eff2;
  box-shadow: 0 0 28px 28px #d8eff2;
}

#gabby-world .try-heading > p {
  color: #514866;
}

#gabby-world .closing {
  background: linear-gradient(#f9f5e9, #f9f5e9 65%, #e3edcb);
}

#gabby-world .scenery {
  position: absolute;
  inset: 0;
  z-index: -2;
  overflow: hidden;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 var(--scene-feather), #000 calc(100% - var(--scene-feather)), transparent);
  mask-image: linear-gradient(to bottom, transparent, #000 var(--scene-feather), #000 calc(100% - var(--scene-feather)), transparent);
}

#gabby-world .arrival .scenery {
  top: 25%;
}

/* Previous artwork remains below the incoming scene during its dissolve.
   Both layers share the stationary edge mask, so no hard image edge travels. */
#gabby-world .picnic { --previous-scene: url('/assets/picnic.webp'); }
#gabby-world .pond { --previous-scene: url('/assets/meadow.webp'); }
#gabby-world .try-scene { --previous-scene: url('/assets/pond.webp'); }

#gabby-world .picnic .scenery::before,
#gabby-world .pond .scenery::before,
#gabby-world .try-scene .scenery::before {
  content: '';
  position: absolute;
  inset: calc(-1 * var(--scenery-travel)) -3%;
  background-image: var(--previous-scene);
  background-size: cover;
  background-position: center;
  opacity: 0;
}

#gabby-world .hero-devices {
  perspective: 1200px;
  --device-travel: 22px;
}

/* Overscan covers the viewport at both extremes of the animation. */
#gabby-world .scenery .landscape {
  inset: calc(-1 * var(--scenery-travel)) -3%;
  width: 106%;
  height: calc(100% + 2 * var(--scenery-travel));
  max-width: none;
  z-index: 0;
  object-fit: cover;
  transform: translateY(0);
}

/* CSS view timelines track normal scrolling, with no wheel interception,
   scroll locks, timers or layout-shifting reveals. Static is the fallback. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    #gabby-world .arrival,
    #gabby-world .picnic,
    #gabby-world .pond,
    #gabby-world .try-scene {
      view-timeline-name: --landscape-scene;
      view-timeline-axis: block;
    }

    #gabby-world .scenery .landscape {
      animation: scenery-pass linear both;
      animation-timeline: --landscape-scene;
      animation-range: entry 0% exit 100%;
    }

    #gabby-world .picnic .scenery .landscape,
    #gabby-world .pond .scenery .landscape,
    #gabby-world .try-scene .scenery .landscape {
      animation-name: scenery-pass, scene-arrive;
      animation-duration: auto, auto;
      animation-timing-function: linear, ease-in-out;
      animation-fill-mode: both, both;
      animation-timeline: --landscape-scene, --landscape-scene;
      animation-range: entry 0% exit 100%, entry 5% entry 95%;
    }

    #gabby-world .scenery::before {
      animation: scene-depart ease-in-out both;
      animation-timeline: --landscape-scene;
      animation-range: entry 5% entry 95%;
    }

    #gabby-world .hero-devices {
      view-timeline-name: --device-reveal;
      view-timeline-axis: block;
    }

    #gabby-world .hero-devices .ipad {
      transform-origin: 50% 65%;
      animation: ipad-settle linear both;
      animation-timeline: --device-reveal;
      animation-range: entry 0% entry 100%;
    }

    #gabby-world .hero-devices .iphone {
      animation: iphone-settle linear both;
      animation-timeline: --device-reveal;
      animation-range: entry 10% entry 100%;
    }

    #gabby-world .hero-devices,
    #gabby-world .screen-on-scene {
      animation: device-pass linear both;
      animation-timeline: --landscape-scene;
      animation-range: entry 0% exit 100%;
    }

    #gabby-world .fish {
      animation: pond-swim linear both;
      animation-timeline: --landscape-scene;
      animation-range: entry 0% exit 100%;
    }

    #gabby-world .fish-two {
      animation-direction: reverse;
    }
  }
}

@keyframes scenery-pass {
  from { transform: translateY(calc(-1 * var(--scenery-travel))); }
  to { transform: translateY(var(--scenery-travel)); }
}

@keyframes device-pass {
  from { translate: 0 var(--device-travel); }
  to { translate: 0 calc(-1 * var(--device-travel)); }
}

@keyframes ipad-settle {
  from { transform: translateY(28px) rotateX(10deg) rotateY(-8deg) rotateZ(-5deg) scale(0.92); }
  to { transform: translateY(0) rotateX(0) rotateY(0) rotateZ(0) scale(1); }
}

@keyframes iphone-settle {
  from { transform: translateY(44px) rotate(8deg) scale(0.94); }
  to { transform: translateY(0) rotate(3deg) scale(1); }
}

@keyframes scene-arrive {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes scene-depart {
  from { opacity: 1; }
  to { opacity: 0; }
}

@keyframes pond-swim {
  from { translate: 48px -8px; }
  to { translate: -48px 8px; }
}

@media (max-width: 650px) {
  #gabby-world { --scenery-travel: 24px; --device-travel: 24px; }
  #gabby-world .arrival .scenery { top: 40%; }
  #gabby-world .try-heading { padding: 18px 8px; }
  #gabby-world .try-heading::before {
    inset: -10px -8px;
    box-shadow: 0 0 20px 16px #d8eff2;
  }
}

@media (prefers-reduced-motion: reduce) {
  #gabby-world .scenery .landscape { transform: none; opacity: 1; }
  #gabby-world .scenery::before { opacity: 0; }
  #gabby-world .hero-devices,
  #gabby-world .screen-on-scene,
  #gabby-world .fish { translate: none; }
}
