/* Motion layer shared by every page. One easing curve, short distances and
   opacity/transform only, so everything stays on the compositor. Hidden
   "before" states only apply while the inline head script (.anim-pending) or
   animations.js (.anim-ready) says so, so the site reads normally without JS
   and for visitors who prefer reduced motion. */

:root {
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.4, 0.64, 1);
  --motion-ease: cubic-bezier(0.2, 0, 0, 1);
  --motion-fast: 160ms;
  --motion-base: 240ms;
  --motion-slow: 600ms;
}

@keyframes fade-in {
  from {
    opacity: 0;
  }
}

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(var(--rise, 14px));
  }
}

/* Uses the individual scale/translate properties so the settle and the
   scroll drift can run on the same image without overwriting each other. */
@keyframes hero-settle {
  from {
    scale: 1.08;
  }
}

@keyframes hero-drift {
  to {
    translate: 0 14%;
  }
}

@keyframes word-rise {
  from {
    transform: translateY(110%);
  }
}

@keyframes rise-soft {
  from {
    opacity: 0;
    filter: blur(8px);
    transform: translateY(18px);
  }
}

@keyframes curtain {
  from {
    clip-path: inset(0 0 100% 0);
  }

  to {
    clip-path: inset(0);
  }
}

@keyframes image-settle {
  from {
    scale: 1.12;
  }
}

/* Petals open from their point, like a leaf unfurling. */
@keyframes bloom {
  from {
    opacity: 0;
    scale: 0;
  }
}

@keyframes petal-shimmer {
  to {
    opacity: 0.5;
  }
}

@keyframes page-out {
  to {
    opacity: 0;
  }
}

@keyframes page-in {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
}

@keyframes story-settle {
  from {
    transform: scale(1.12);
  }
}

@keyframes story-drift {
  from {
    transform: scale(1.14) translateY(-5%);
  }

  to {
    transform: scale(1.14) translateY(5%);
  }
}

@keyframes draw-up {
  from {
    transform: scaleY(0);
  }
}

@media (prefers-reduced-motion: no-preference) {
  /* ---------- Page load ---------- */
  /* Holds the hero copy back until animations.js takes over, so it never
     paints and then restarts. The delayed fade is the fallback if the script
     never arrives. */
  .anim-pending main :is(h1, h1 ~ *, :has(~ h1)) {
    animation: fade-in var(--motion-slow) var(--ease-out) 3s backwards;
  }

  .anim-ready [data-hero-item] {
    animation: rise 0.7s var(--ease-out) backwards;
    animation-delay: calc(var(--i, 0) * 70ms + 80ms);
  }

  .anim-ready .hero-media {
    animation: hero-settle 1.8s var(--ease-out) backwards;
  }

  /* The photograph trails the scroll slightly as the hero leaves. */
  @supports (animation-timeline: view()) {
    .anim-ready .hero-media {
      animation:
        hero-settle 1.8s var(--ease-out) backwards,
        hero-drift linear both;
      animation-timeline: auto, view();
      animation-range: normal, exit 0% exit 100%;
    }
  }

  /* The headline arrives a word at a time, each rising out of its own mask. */
  .hero-word {
    display: inline-block;
    overflow: hidden;
    margin-bottom: -0.14em;
    padding-bottom: 0.14em;
    vertical-align: top;
  }

  .hero-word > span {
    display: inline-block;
  }

  .anim-ready h1.hero-title--split {
    animation: none;
  }

  .anim-ready .hero-word > span {
    animation: word-rise 0.95s var(--ease-out) backwards;
    animation-delay: calc(var(--w, 0) * 55ms + 120ms);
  }

  /* ---------- Scroll reveal ---------- */
  /* A keyframe animation rather than a transition, so it never fights the
     element's own hover transitions and needs no cleanup afterwards. */
  .anim-ready [data-reveal]:not([data-reveal="in"]) {
    opacity: 0;
  }

  .anim-ready [data-reveal="in"] {
    animation: rise var(--motion-slow) var(--ease-out)
      var(--reveal-delay, 0ms) backwards;
  }

  /* Section headings come into focus as they rise. */
  .anim-ready :is(h2, .display)[data-reveal="in"] {
    animation: rise-soft 0.9s var(--ease-out) var(--reveal-delay, 0ms)
      backwards;
  }

  /* Card photographs are unveiled top to bottom while the image settles. */
  .anim-ready [data-reveal="in"] .insight__image {
    animation: curtain 1s var(--ease-out)
      calc(var(--reveal-delay, 0ms) + 80ms) backwards;
  }

  .anim-ready [data-reveal="in"] :is(.insight__image, .feature__image) img,
  .anim-ready figure[data-reveal="in"] img {
    animation: image-settle 1.6s var(--ease-out) var(--reveal-delay, 0ms)
      backwards;
  }

  /* ---------- Petals ---------- */
  .anim-ready [data-reveal="in"] .petal {
    animation: bloom 0.9s var(--ease-spring) backwards;
    animation-delay: calc(
      var(--reveal-delay, 0ms) + var(--n, 0) * 55ms + 140ms
    );
  }

  /* The footer fields bloom petal by petal, then keep a slow shimmer. */
  .anim-ready footer:not(.is-in) .footer-petal-field .petal {
    scale: 0;
  }

  .anim-ready footer.is-in .footer-petal-field .petal {
    animation:
      bloom 1s var(--ease-spring) calc(var(--n, 0) * 70ms) backwards,
      petal-shimmer 3.2s ease-in-out calc(var(--n, 0) * 280ms + 1.4s)
        infinite alternate;
  }

  /* ---------- Story band ---------- */
  /* The photographs stay put and opaque (fading the figure would lift its
     image above the wash); the image itself settles, or drifts with the
     scroll where the browser supports view timelines. */
  .anim-ready .story-band__media figure[data-reveal] {
    opacity: 1;
    animation: none;
  }

  .anim-ready .story-band__media [data-reveal="in"] img {
    animation: story-settle 1.8s var(--ease-out) backwards;
  }

  @supports (animation-timeline: view()) {
    .anim-ready .story-band__media figure img {
      animation: story-drift linear both;
      animation-timeline: view();
    }
  }

  .anim-ready .figure[data-reveal]:not([data-reveal="in"])::before {
    transform: scaleY(0);
  }

  .anim-ready .figure[data-reveal="in"]::before {
    animation: draw-up 0.9s var(--ease-out)
      calc(var(--reveal-delay, 0ms) + 150ms) backwards;
  }

  /* ---------- Menus ---------- */
  header .site-nav-panel {
    --rise: -6px;
    animation: rise 0.2s var(--ease-out) backwards;
  }

  /* ---------- Dialogs ---------- */
  dialog,
  dialog::backdrop {
    opacity: 0;
    transition:
      opacity var(--motion-base) var(--motion-ease),
      transform var(--motion-base) var(--ease-out),
      overlay var(--motion-base) allow-discrete,
      display var(--motion-base) allow-discrete;
  }

  dialog {
    transform: translateY(12px) scale(0.985);
  }

  dialog[open],
  dialog[open]::backdrop {
    opacity: 1;
  }

  dialog[open] {
    transform: none;
  }

  @starting-style {
    dialog[open],
    dialog[open]::backdrop {
      opacity: 0;
    }

    dialog[open] {
      transform: translateY(12px) scale(0.985);
    }
  }

  /* ---------- Accordions ---------- */
  details[open] > :not(summary) {
    animation: fade-in 0.3s var(--motion-ease) backwards;
  }

  @supports (interpolate-size: allow-keywords) {
    details {
      interpolate-size: allow-keywords;
    }

    details::details-content {
      block-size: 0;
      overflow: hidden;
      transition:
        block-size 0.3s var(--ease-out),
        content-visibility 0.3s allow-discrete;
    }

    details[open]::details-content {
      block-size: auto;
    }
  }

  /* ---------- Page to page ---------- */
  /* Supporting browsers cross-fade between pages; the header holds still. */
  @view-transition {
    navigation: auto;
  }

  header {
    view-transition-name: site-header;
  }

  ::view-transition-old(root) {
    animation: page-out 0.18s var(--motion-ease) both;
  }

  ::view-transition-new(root) {
    animation: page-in 0.45s var(--ease-out) 0.08s both;
  }

  /* ---------- Hover & press ---------- */
  a[class*="rounded-full"],
  button[class*="rounded-full"] {
    transition:
      transform var(--motion-fast) var(--motion-ease),
      background-color var(--motion-base) var(--motion-ease),
      border-color var(--motion-base) var(--motion-ease),
      color var(--motion-base) var(--motion-ease),
      opacity var(--motion-base) var(--motion-ease);
  }

  a[class*="rounded-full"]:active,
  button[class*="rounded-full"]:active {
    transform: scale(0.97);
  }

  main a.group {
    transition: box-shadow var(--motion-base) var(--motion-ease);
  }

  main a.group h2,
  main a.group h3,
  main a.group h4,
  .group [class*="group-hover:"] {
    transition:
      color var(--motion-base) var(--motion-ease),
      background-color var(--motion-base) var(--motion-ease),
      transform var(--motion-slow) var(--ease-out);
  }

  footer ul a,
  header nav[aria-label="Primary"] > a {
    background: linear-gradient(currentColor, currentColor) no-repeat 0 100% /
      0 1px;
    transition:
      background-size var(--motion-base) var(--ease-out),
      color var(--motion-fast) var(--motion-ease);
  }

  @media (hover: hover) {
    main a.group[class*="bg-white"]:hover {
      box-shadow: 0 18px 36px -28px rgb(63 48 41 / 0.35);
    }

    footer ul a:hover,
    header nav[aria-label="Primary"] > a:hover {
      background-size: 100% 1px;
    }
  }
}

/* ---------- Reading progress (article pages) ---------- */
.scroll-progress {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 60;
  height: 2px;
  background: var(--spring, #699f2f);
  transform: scaleX(var(--p, 0));
  transform-origin: 0 50%;
  pointer-events: none;
}

.count-up {
  font-variant-numeric: tabular-nums;
}
