/*
 * Motion layer.
 *
 * Everything here is gated on `.has-motion`, set by a one-line inline script in
 * <head>. Without JavaScript the class never lands, so the page renders fully
 * visible rather than trusting a script to un-hide it — which is exactly how
 * the team photos ended up invisible before.
 */

/* ------------------------------------------- Pinned "why" section (2) */

/* Only becomes sticky once the script has measured and enabled it */
.why-pin.is-pinned > .why {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-block: 0;
}

/* Logged-in editors: the fixed admin bar sits over the sticky stage's top edge. */
body.admin-bar .why-pin.is-pinned > .why {
  top: var(--wp-admin--admin-bar--height, 32px);
}

.why-pin.is-pinned .why__inner {
  width: 100%;
}

/*
 * Pinned, all three stages share one grid cell so the box is always as tall as
 * the tallest — nothing below it shifts or gets overlapped as they swap.
 */
.why-pin.is-pinned .why__steps {
  display: grid;
  gap: 0;
}

/*
 * Stages cross-fade on a transition, not a keyframe.
 *
 * A keyframe restarts from its own first frame every time it is applied, so
 * reversing direction part-way through — which is exactly what scrolling back
 * up does — snapped the incoming stage to invisible and replayed it. A
 * transition interpolates from wherever the element currently is, so a
 * reversal blends instead of jumping.
 *
 * Direction comes from `data-state` rather than from tracking which way the
 * page is moving: a stage the visitor has already passed sits *above* (prev),
 * one not yet reached sits *below* (next). Scrolling down, the next stage
 * rises into place and the current one drifts up; scrolling back up, the same
 * rule runs in reverse with no extra code. Both directions read as one
 * continuous movement rather than everything always entering from below.
 */
.why-pin.is-pinned .why__step {
  grid-area: 1 / 1;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translateY(28px);
  transition:
    opacity var(--dur-slow) var(--ease-entrance),
    transform var(--dur-slow) var(--ease-entrance),
    /* held until the fade is done, so a leaving stage is not cut mid-fade */
    visibility 0s linear var(--dur-slow);
}

/* Already passed — sits above the frame */
.why-pin.is-pinned .why__step[data-state='prev'] {
  transform: translateY(-28px);
}

/* Not yet reached — waits below the frame */
.why-pin.is-pinned .why__step[data-state='next'] {
  transform: translateY(28px);
}

.why-pin.is-pinned .why__step[data-state='active'] {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: none;
  transition-delay: 0s, 0s, 0s;
}

/* Short desktop viewports: shrink the media so a pinned stage still fits */
@media (min-width: 1024px) and (max-height: 820px) {
  .why-pin.is-pinned .why__media {
    height: 440px;
  }

  .why-pin.is-pinned .why__col {
    gap: 32px;
  }
}

/*
 * Phones tall enough to pin (see ICC_MOTION.why.minHeight) get a compressed
 * version: a shorter photo, tighter rhythm, and the stage counter moved to a
 * horizontal row so it stops fighting the content for width.
 *
 * Height is svh — the *small* viewport height, measured with the browser
 * toolbar showing — so the pinned stage never overflows when the toolbar
 * slides back in mid-scroll.
 */
@media (max-width: 1023px) {
  .why-pin.is-pinned > .why {
    padding-block: 0;
  }

  .why-pin.is-pinned .why__col {
    gap: 24px;
  }

  .why-pin.is-pinned .why__media {
    height: 190px;
    order: 2;
  }

  .why-pin.is-pinned .why__list,
  .why-pin.is-pinned .why__step {
    gap: 14px;
  }

  .why-pin.is-pinned .why__outro {
    font-size: 17px;
    line-height: 24px;
  }

  /* Counter becomes a horizontal row above the scroll hint */
  .why-pin.is-pinned .why__rail {
    position: absolute;
    left: 50%;
    right: auto;
    bottom: 78px;
    top: auto;
    transform: translateX(-50%);
    align-self: auto;
  }

  .why-pin.is-pinned .why__rail-nums {
    flex-direction: row;
    gap: 14px;
    font-size: 14px;
    line-height: 1;
  }

  .why-pin.is-pinned .why__rail-track {
    display: none;
  }

  .why-pin.is-pinned .why__scroll-hint {
    bottom: 20px;
  }

  /* Stacked (short phones): the counter has nothing to count */
  .why-pin:not(.is-pinned) .why__rail {
    display: none;
  }
}

/*
 * Compact tiers for shorter phones.
 *
 * A pinned stage has to fit the viewport outright — there is nowhere for it to
 * overflow to. Most phones showing their browser chrome sit well under the
 * height the full mobile layout needs (measured: 717px of content against a
 * 664px viewport on an iPhone 14), which is why the section quietly stopped
 * animating on real devices and only ever pinned in a chrome-less emulator.
 *
 * These tiers trim the parts that cost the most height and carry the least —
 * the photo, the gaps, the scroll hint whose job the stage counter already
 * does — so the same animation runs on the phones people actually hold. The
 * script measures the result and only pins if it genuinely fits, so anything
 * still too short falls back to the stacked layout rather than clipping.
 */
@media (max-width: 1023px) and (max-height: 820px) {
  .why-pin.is-pinned .why__media {
    height: 150px;
  }

  .why-pin.is-pinned .why__col {
    gap: 18px;
  }

  .why-pin.is-pinned .why__head {
    gap: 8px;
  }

  .why-pin.is-pinned .why__list,
  .why-pin.is-pinned .why__step {
    gap: 12px;
  }

  /* The counter already shows progress; the arrow is the redundant one. */
  .why-pin.is-pinned .why__scroll-hint {
    display: none;
  }

  .why-pin.is-pinned .why__rail {
    bottom: 16px;
  }
}

@media (max-width: 1023px) and (max-height: 700px) {
  .why-pin.is-pinned .why__media {
    height: 118px;
  }

  .why-pin.is-pinned .why__col {
    gap: 14px;
  }

  .why-pin.is-pinned .why__step-title {
    font-size: 20px;
    line-height: 26px;
  }

  .why-pin.is-pinned .why__list,
  .why-pin.is-pinned .why__step {
    gap: 10px;
  }

  .why-pin.is-pinned .why__item p {
    font-size: 14px;
    line-height: 20px;
  }
}

/* ------------------------------------------------- Bouncing arrow (3) */

.why__scroll-hint svg,
.hero__scroll svg {
  animation: icc-bounce 2.4s var(--ease-out) infinite;
}

@keyframes icc-bounce {
  0%,
  55%,
  100% {
    transform: translateY(0);
  }
  70% {
    transform: translateY(7px);
  }
  85% {
    transform: translateY(2px);
  }
}

/* ---------------------------------------------------- Word reel (4) */

/*
 * The words cross-fade in place on a timer. A short blur on the outgoing and
 * incoming word reads as a focus pull rather than a slide, which is what keeps
 * it from looking scroll-linked now that it runs on its own clock.
 */
.has-motion .different__slot span {
  filter: blur(6px);
  transform: translateY(5px);
  transition:
    opacity var(--dur-word) var(--ease-entrance),
    filter var(--dur-word) var(--ease-entrance),
    transform var(--dur-word) var(--ease-entrance);
}

.has-motion .different__slot span[data-active='true'] {
  filter: none;
  transform: none;
}

/* --------------------------------------- Reveal on enter (5, 6, 7) */

.has-motion [data-reveal-item] {
  opacity: 0;
  transform: translateY(34px);
  transition:
    opacity var(--dur-reveal) var(--ease-entrance),
    transform var(--dur-reveal) var(--ease-entrance),
    filter var(--dur-reveal) var(--ease-entrance);
}

.has-motion [data-reveal-item][data-revealed='true'] {
  opacity: 1;
  transform: none;
}

/*
 * Photographs additionally rack into focus. On a brand built out of food
 * photography this reads as the image arriving, not as a generic card fade —
 * and it is what makes the effect legible at all on a slow scroll.
 */
.has-motion [data-reveal-item='media'] {
  filter: blur(10px);
}

.has-motion [data-reveal-item='media'][data-revealed='true'] {
  filter: blur(0);
}

/*
 * The team portraits take their time on desktop — there is room for the fade
 * to read as a fade there, and nine faces arriving in sequence is the point of
 * the section. Phones keep the standard duration: the cards are full-width and
 * one-per-screen, so a long fade would just feel like a slow page.
 */
@media (min-width: 1024px) {
  .has-motion .member[data-reveal-item] {
    transition-duration: 1800ms;
  }
}

/*
 * The two comparison cards arrive on the same longer clock as the portraits.
 * Scoped to the cards rather than raised on --dur-reveal, which the pillar
 * media and the stat cards also read from and which should stay as it is.
 */
.has-motion .fit__card[data-reveal-item] {
  transition-duration: 1800ms;
}

/* The comparison cards enter from opposite sides, together */
.has-motion [data-reveal='sides'] > [data-reveal-item]:nth-child(odd) {
  transform: translateX(-64px);
}

.has-motion [data-reveal='sides'] > [data-reveal-item]:nth-child(even) {
  transform: translateX(64px);
}

.has-motion [data-reveal='sides'] > [data-reveal-item][data-revealed='true'] {
  transform: none;
}

/* ------------------------------------------- Page title stagger */

/*
 * Each page's title arrives a word at a time. The words are already split into
 * spans in the markup, so with no JS (or no motion) the heading simply renders
 * complete — the class below is what makes them start hidden.
 */
.stagger__word {
  display: inline-block;
}

.has-motion [data-stagger] .stagger__word {
  opacity: 0;
  transform: translateY(0.4em);
}

.has-motion [data-stagger='ready'] .stagger__word {
  opacity: 1;
  transform: none;
  transition:
    opacity var(--dur-slow) var(--ease-entrance),
    transform var(--dur-slow) var(--ease-entrance);
  /* --i is the word's index, set in the markup */
  transition-delay: calc(var(--i) * 90ms);
}

/* ------------------------------------------------ Reduced motion */

@media (prefers-reduced-motion: reduce) {
  .why-pin.is-pinned .why__step,
  .why__scroll-hint svg,
  .hero__scroll svg {
    animation: none;
  }

  .different__slot span {
    transition: opacity var(--dur-fast) linear;
    filter: none;
    transform: none;
  }

  .has-motion [data-reveal-item],
  .has-motion [data-reveal-item='media'] {
    opacity: 1;
    transform: none;
    filter: none;
    transition: none;
  }

  .has-motion [data-stagger] .stagger__word,
  .has-motion [data-stagger='ready'] .stagger__word {
    opacity: 1;
    transform: none;
    transition: none;
  }
}
