/* Homepage motion: hero entrance, photo reveals, statement word reveal and
   page transitions. On by default; `build.py --no-motion` leaves it out. Transforms and opacity only;
   critically damped spring easing (--spring); every effect has a reduced-motion fallback.
   Initial states apply only under .motion, which an inline script adds, so the page is
   fully visible if scripts never run. */

/* ---------- 1. Hero entrance: the name rises line by line, the photo settles ---------- */

.motion .hero-title .line {
  display: block;
  overflow: hidden;
  /* Grow the clip box so ascenders and the "y" descender are not cut off */
  padding: 0.08em 0 0.12em;
  margin: -0.08em 0 -0.12em;
}
.motion .hero-title .line > span {
  display: inline-block;
  transition: transform 1000ms var(--spring);
}
.motion .hero-title .line + .line > span { transition-delay: 90ms; }
.motion:not(.hero-in) .hero-title .line > span { transform: translateY(110%); }

.motion .hero-role,
.motion .hero-sub,
.motion .hero-meta,
.motion .hero .cta-row {
  transition: opacity 600ms ease, transform 1000ms var(--spring);
}
.motion .hero-role { transition-delay: 200ms; }
.motion .hero-sub { transition-delay: 320ms; }
.motion .hero-meta { transition-delay: 420ms; }
.motion .hero .cta-row { transition-delay: 500ms; }
.motion:not(.hero-in) .hero-role,
.motion:not(.hero-in) .hero-sub,
.motion:not(.hero-in) .hero-meta,
.motion:not(.hero-in) .hero .cta-row {
  opacity: 0;
  transform: translateY(14px);
}

.motion .hero-media img { transition: opacity 900ms ease, transform 1600ms var(--spring); }
.motion:not(.hero-in) .hero-media img { opacity: 0; transform: scale(1.06); }

/* ---------- 2. Photo reveals: each photo uncovers upwards inside its frame ---------- */

/* These blocks reveal their parts individually instead of fading as a whole */
.motion .discipline.reveal,
.motion .about-media.reveal {
  opacity: 1;
  transform: none;
}

.motion .d-main,
.motion .d-a,
.motion .d-b,
.motion .about-media {
  clip-path: inset(0 round var(--radius-sm));
  transition: clip-path 1100ms var(--spring);
}
.motion .d-main img,
.motion .d-a img,
.motion .d-b img,
.motion .about-media img {
  transition: transform 1500ms var(--spring);
}
.motion .d-a, .motion .d-a img { transition-delay: 120ms; }
.motion .d-b, .motion .d-b img { transition-delay: 220ms; }

.motion .discipline:not(.is-in) :is(.d-main, .d-a, .d-b),
.motion .about-media:not(.is-in) {
  clip-path: inset(100% 0 0 0 round var(--radius-sm));
}
.motion .discipline:not(.is-in) :is(.d-main, .d-a, .d-b) img,
.motion .about-media:not(.is-in) img {
  transform: scale(1.14);
}

.motion .discipline .d-text,
.motion .discipline .d-more {
  transition: opacity 600ms ease, transform 1000ms var(--spring);
}
.motion .discipline .d-more { transition-delay: 160ms; }
.motion .discipline:not(.is-in) :is(.d-text, .d-more) {
  opacity: 0;
  transform: translateY(18px);
}

/* ---------- 3. Statement: words brighten as you scroll past (opacity set by motion.js) ---------- */

.motion .statement h2.reveal { opacity: 1; transform: none; }
.motion .words .w { opacity: 0.5; }  /* half strength keeps 3:1 contrast until the scroll brightens it */

/* ---------- 5. One image, a thousand words (drawn by motion.js on the canvas) ---------- */

.dissolve-scene { padding-bottom: clamp(48px, 8vw, 120px); }
.dissolve-sticky { display: grid; place-items: center; }
.dissolve-frame {
  position: relative;
  overflow: hidden;
  width: min(calc(100% - 2 * var(--gutter)), calc(var(--maxw) - 2 * var(--gutter)));
  aspect-ratio: 16 / 10;
  border-radius: var(--radius);
  background: #0d0d0c;
}
.dissolve-frame img { width: 100%; height: 100%; object-fit: cover; }
.dissolve-frame canvas { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; }
.dissolve-scene.is-ready canvas { opacity: 1; }
@media (max-width: 699px) {
  .dissolve-frame { aspect-ratio: 5 / 8; }
}

/* The scene is tall so the dissolve plays out over a stretch of normal scrolling,
   with the frame held in view (sticky), centred below the header */
.motion .dissolve-scene { height: 260vh; padding-bottom: 0; }
.motion .dissolve-sticky {
  position: sticky;
  top: var(--header-h);
  height: calc(100svh - var(--header-h));
}
.motion .dissolve-frame {
  width: min(calc(100% - 2 * var(--gutter)), calc((100svh - var(--header-h) - 48px) * 1.6), calc(var(--maxw) - 2 * var(--gutter)));
}
@media (max-width: 699px) {
  .motion .dissolve-frame {
    width: min(calc(100% - 2 * var(--gutter)), calc((100svh - var(--header-h) - 48px) * 0.625));
  }
}

/* ---------- 4. Page transitions (browsers with cross-document View Transitions) ---------- */

@view-transition { navigation: auto; }

/* The header stays put while the page underneath changes */
.site-header { view-transition-name: site-header; }

::view-transition-old(root),
::view-transition-new(root) { animation-duration: 260ms; }

/* The photo you clicked grows into its place on the gallery page */
::view-transition-group(shared-photo) {
  animation-duration: 700ms;
  animation-timing-function: var(--spring);
}
::view-transition-old(shared-photo),
::view-transition-new(shared-photo) {
  height: 100%;
  object-fit: cover;
  overflow: clip;
}

/* ---------- Reduced motion: short fades, nothing moves ---------- */

@media (prefers-reduced-motion: reduce) {
  .motion:not(.hero-in) .hero-title .line > span { transform: none; opacity: 0; }
  .motion .hero-title .line > span { transition: opacity 300ms ease !important; }
  .motion:not(.hero-in) :is(.hero-role, .hero-sub, .hero-meta, .hero .cta-row) { transform: none; }
  .motion:not(.hero-in) .hero-media img { transform: none; }

  .motion .discipline:not(.is-in) :is(.d-main, .d-a, .d-b),
  .motion .about-media:not(.is-in) { clip-path: inset(0 round var(--radius-sm)); opacity: 0; }
  .motion :is(.d-main, .d-a, .d-b, .about-media) { transition: opacity 300ms ease !important; }
  .motion .discipline:not(.is-in) :is(.d-main, .d-a, .d-b) img,
  .motion .about-media:not(.is-in) img { transform: none; }
  .motion .discipline:not(.is-in) :is(.d-text, .d-more) { transform: none; }

  .motion .words .w { opacity: 1 !important; }

  /* The finished word-picture, shown still in the normal page flow */
  .motion .dissolve-scene { height: auto; padding-bottom: clamp(48px, 8vw, 120px); }
  .motion .dissolve-sticky { position: static; height: auto; }

  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation-duration: 160ms !important; }
}
