/* Page transition — aaltra.
 *
 * Replaces the old white preloader panel. The veil is painted in the colour of
 * the page you came from and lifts away to reveal the colour of the page you
 * landed on, so a navigation reads as one continuous colour change with no
 * white step in between. Hero content rises in while the veil is still moving.
 *
 * Only `transform` and `opacity` are animated. */

:root {
  /* Both curves are a cubic ease-out — quick off the mark, settling into the
   * finish. Deliberately not a quint or expo ease: those front-load so hard
   * that the motion is visually over in a third of its duration, which reads as
   * a snap rather than a glide. The veil clears at 700ms and the last element
   * lands at 1030ms, so the whole transition reads as about a second. */
  --pt-veil-duration: 700ms;
  --pt-veil-ease: cubic-bezier(0.33, 1, 0.68, 1);

  --pt-rise-duration: 650ms;
  --pt-rise-ease: cubic-bezier(0.33, 1, 0.68, 1);
  --pt-rise-distance: 22px;

  --pt-delay-eyebrow: 180ms;
  --pt-delay-heading: 260ms;
  --pt-delay-media: 380ms;
}

/* The veil is a pseudo-element on <html> so it paints on the very first frame,
 * before <body> exists — no markup, no flash of the incoming page. */
html.pt-veil::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 2147483000;
  background-color: var(--pt-veil-color, var(--pt-page-color, #fff));
  transform: translateY(0);
  pointer-events: none;
  will-change: transform;
}

html.pt-veil-lift::before {
  transform: translateY(-100%);
  transition: transform var(--pt-veil-duration) var(--pt-veil-ease);
}

/* Hero intro. `pt-intro` lands before first paint and holds the content back;
 * `pt-intro-run` starts the reveal on the same frame the veil begins to lift. */
/* `hero-lede` is opt-in, and it has to be: the obvious structural selectors do
 * not work here. `header p` catches the two dozen case-card eyebrows inside
 * /our-work's header, and `.hero p` catches the whole of /contact and
 * /privacy-policy, both of which sit their body copy inside .hero. A class says
 * exactly which paragraph is the hero's lede and nothing else. */
/* The three service pages set their title at .heading-3 large rather than
 * .heading-1, so the biggest thing in the hero was the one element that never
 * moved. `h1.heading-3` is exactly those three and nothing else — the other
 * .heading-3.large on the site are h2 ("Next case", "Explore our other
 * services") and the p's on /contact, none of which should join the intro. */
html.pt-intro .eyebrow,
html.pt-intro .heading-1,
html.pt-intro h1.heading-3,
html.pt-intro .hero-lede,
html.pt-intro .hero-image {
  opacity: 0;
}

@keyframes pt-rise {
  from {
    opacity: 0;
    transform: translateY(var(--pt-rise-distance));
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

html.pt-intro-run .eyebrow {
  animation: pt-rise var(--pt-rise-duration) var(--pt-rise-ease) var(--pt-delay-eyebrow) both;
}

html.pt-intro-run .heading-1,
html.pt-intro-run h1.heading-3 {
  animation: pt-rise var(--pt-rise-duration) var(--pt-rise-ease) var(--pt-delay-heading) both;
}

/* The lede rides the heading's delay rather than taking a rung of its own, so
 * the title and the line under it lift as one block. Giving it its own step
 * between heading and media was tried and reads as a third beat in what is
 * meant to be a single movement. */
html.pt-intro-run .hero-lede {
  animation: pt-rise var(--pt-rise-duration) var(--pt-rise-ease) var(--pt-delay-heading) both;
}

html.pt-intro-run .hero-image {
  animation: pt-rise var(--pt-rise-duration) var(--pt-rise-ease) var(--pt-delay-media) both;
}

@media (prefers-reduced-motion: reduce) {
  html.pt-veil::before,
  html.pt-veil-lift::before {
    display: none;
  }

  html.pt-intro .eyebrow,
  html.pt-intro .heading-1,
  html.pt-intro h1.heading-3,
  html.pt-intro .hero-lede,
  html.pt-intro .hero-image,
  html.pt-intro-run .eyebrow,
  html.pt-intro-run .heading-1,
  html.pt-intro-run h1.heading-3,
  html.pt-intro-run .hero-lede,
  html.pt-intro-run .hero-image {
    opacity: 1;
    animation: none;
  }
}
