/* ==========================================================================
   Digital Unicorn: motion
   ==========================================================================
   Every animation on the site. There is no animation library: this is all of
   it, plus one IntersectionObserver in js/reveal.js that does nothing but
   set data-visible.

   Ported unchanged from the Next.js build. Read the reduced-motion blocks
   before editing anything here. Each one is deliberate and each one is
   paired with the animation above it. An animation added without its reset
   is a defect, not an omission.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Marquee. Used by the logo band and the cover strip.

   Duration is set per instance via --marquee-duration on the element, so one
   keyframe serves a fast cover strip and a slower, reversed logo band.
   Custom properties resolve in the element's own scope, not where they are
   declared, which is what makes that work.

   The -50% translate is the seam: the track holds the tile set twice, so
   moving exactly half the track puts tile 1 of the second set where tile 1
   of the first set began. Any other value and the loop visibly jumps.
   -------------------------------------------------------------------------- */
@keyframes marquee {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(-50%, 0, 0); }
}

.marquee-track {
  animation: marquee var(--marquee-duration, 44s) linear infinite;
}

/* WCAG 2.2.2 asks for a real control on motion that runs longer than five
   seconds, so hover alone is not enough: touch and keyboard users never
   hover. The checkbox in the markup is the control, these rules are the
   wiring. This costs zero JavaScript. */
.marquee:hover .marquee-track,
.marquee:focus-within .marquee-track,
.marquee:has(.marquee-pause:checked) .marquee-track {
  animation-play-state: paused;
}

@media (prefers-reduced-motion: reduce) {
  .marquee-track { animation: none; }

  /* With the animation off the rail becomes a static wrapped wall, so
     full-size tiles would stack taller than the screen and push the headline
     out of view. Capped at the tile's own base height rather than something
     smaller, because the metric plate carries a 48px numeral and clips below
     this. Set here rather than as a responsive override so it cannot lose an
     ordering race with the large-breakpoint height it overrides. */
  .marquee-tile { height: 14rem; }
}

/* --------------------------------------------------------------------------
   Mega-menu and popover open. Fades and slides in without pushing layout.
   -------------------------------------------------------------------------- */
@keyframes overlay-in {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 1; transform: translateY(0); }
}

.animate-overlay-in {
  animation: overlay-in 0.16s ease-out;
  transform-origin: top;
}

@media (prefers-reduced-motion: reduce) {
  .animate-overlay-in { animation: none; }
}

/* --------------------------------------------------------------------------
   Reveal. Two flavours of the same movement.
   -------------------------------------------------------------------------- */
@keyframes reveal-up {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: translateY(0); }
}

/* On-load, for a short list of known length: the hero proof numbers.
   `both` holds the from-state through the delay so nothing flashes in early,
   which is also why the reduced-motion reset drops the whole shorthand.
   Killing only animation-name would keep the fill and leave the numbers
   permanently invisible. */
.reveal-stagger > * {
  animation: reveal-up 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.reveal-stagger > *:nth-child(2) { animation-delay: 90ms; }
.reveal-stagger > *:nth-child(3) { animation-delay: 180ms; }
.reveal-stagger > *:nth-child(4) { animation-delay: 270ms; }

@media (prefers-reduced-motion: reduce) {
  .reveal-stagger > * { animation: none; }
}

/* Same movement, held until the list is scrolled into view and stepped 200ms
   apart. js/reveal.js sets data-visible. Sections this far down the page
   would otherwise finish animating long before anyone reached them.

   The from-state lives on the container, not the children, so a page that
   never runs the observer (JS disabled, script failed) never hides them. */
.reveal-on-view[data-visible="false"] > * { opacity: 0; }
.reveal-on-view[data-visible="true"] > * {
  animation: reveal-up 0.6s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.reveal-on-view[data-visible="true"] > *:nth-child(2) { animation-delay: 200ms; }
.reveal-on-view[data-visible="true"] > *:nth-child(3) { animation-delay: 400ms; }
.reveal-on-view[data-visible="true"] > *:nth-child(4) { animation-delay: 600ms; }

@media (prefers-reduced-motion: reduce) {
  .reveal-on-view[data-visible="false"] > * { opacity: 1; }
  .reveal-on-view[data-visible="true"] > * { animation: none; }
}
