/* Motion: CSS only. Content is always visible unless the browser supports
   scroll-driven animations (hidden "from" state lives inside @supports). */

/* ===== Hero load animation (all browsers) ===== */
@keyframes hero-rise {
  from { opacity: 0; transform: translateY(24px); }
  to   { opacity: 1; transform: none; }
}
@keyframes hero-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
/* the visitor's dot: a slow ripple, quiet enough to be noticed only on a second look */
@keyframes hero-pin-wave {
  from { transform: scale(.4); opacity: .9; }
  to   { transform: scale(2.2); opacity: 0; }
}

/* .hero-kicker / .hero-sub also carry .reveal; these selectors are more
   specific than .reveal, so the hero load animation wins everywhere. */
.hero .hero-kicker { animation: hero-rise 900ms cubic-bezier(.2, .7, .2, 1) both; }
.hero h1           { animation: hero-rise 900ms cubic-bezier(.2, .7, .2, 1) 150ms both; }
.hero .hero-sub    { animation: hero-rise 900ms cubic-bezier(.2, .7, .2, 1) 300ms both; }
.hero-actions      { animation: hero-rise 900ms cubic-bezier(.2, .7, .2, 1) 450ms both; }
.hero-map          { animation: hero-fade 1.6s ease-out both; }
.pin-wave {
  transform-box: fill-box; transform-origin: center;
  animation: hero-pin-wave 3.2s ease-out 1.2s infinite both;
}

/* ===== Scroll-driven motion (Chromium / Safari 26+) ===== */
@supports (animation-timeline: view()) {
  @keyframes reveal {
    from { opacity: 0; transform: translateY(48px); }
    to   { opacity: 1; transform: none; }
  }
  @keyframes reveal-left {
    from { opacity: 0; transform: translateX(-64px); }
    to   { opacity: 1; transform: none; }
  }
  @keyframes reveal-right {
    from { opacity: 0; transform: translateX(64px); }
    to   { opacity: 1; transform: none; }
  }
  @keyframes reveal-zoom {
    from { opacity: 0; transform: scale(.92); }
    to   { opacity: 1; transform: none; }
  }
  @keyframes map-parallax {
    from { translate: 0 0; }
    to   { translate: 0 60px; }
  }
  @keyframes progress-grow {
    from { transform: scaleX(0); }
    to   { transform: scaleX(1); }
  }

  .reveal {
    animation: reveal linear backwards;
    animation-timeline: view();
    /* Absolute lengths: tall wrappers must not stretch the fade over ~1000px. */
    animation-range:
      entry calc(var(--d, 0) * 20px)
      entry calc(80px + var(--d, 0) * 20px);
  }
  /* Stagger (sitegen/pages.py _reveal_delay): classes, since the CSP allows no inline styles. */
  .reveal--d1 { --d: 1; }
  .reveal--d2 { --d: 2; }
  .reveal--d3 { --d: 3; }
  .reveal.reveal--left  { animation-name: reveal-left; }
  .reveal.reveal--right { animation-name: reveal-right; }
  .reveal.reveal--zoom  { animation-name: reveal-zoom; }

  /* Hero copy (.hero .hero-kicker/.hero-sub) out-specifies .reveal above, so
     it keeps its load animation and ends visible. */

  /* Map: load fade (opacity) + scroll parallax (translate) together. */
  .hero-map {
    animation:
      hero-fade 1.6s ease-out both,
      map-parallax linear both;
    animation-timeline: auto, scroll(root);
    animation-range: normal, 0px 100vh;
  }

  /* Reading progress bar under the header */
  .site-header::after {
    content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 3px;
    background: var(--red);
    transform: scaleX(0); transform-origin: left;
    animation: progress-grow linear both;
    animation-timeline: scroll(root);
    pointer-events: none;
  }
}

/* ===== Reduced motion ===== */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto !important; }
  *, *::before, *::after {
    animation: none !important;
    transition: none !important;
  }
  .reveal { opacity: 1 !important; transform: none !important; }
}
