/* Skylines Productions motion layer.
   Loaded after every legacy stylesheet so these rules are authoritative. */

.reveal:not(.reveal-hero) {
  --enter-x: 0px;
  --enter-y: 46px;
  --enter-scale: .965;
  opacity: 0;
  filter: none;
  transform: translate3d(var(--enter-x), var(--enter-y), 0) scale(var(--enter-scale));
  transition:
    opacity 760ms cubic-bezier(.2, .65, .25, 1) var(--reveal-delay),
    transform 1100ms cubic-bezier(.16, 1, .3, 1) var(--reveal-delay),
    clip-path 1100ms cubic-bezier(.16, 1, .3, 1) var(--reveal-delay);
  animation: none;
  will-change: opacity, transform;
}

.reveal.reveal-title:not(.reveal-hero) { --enter-y: 64px; --enter-scale: .94; }
.reveal.reveal-media:not(.reveal-hero) {
  --enter-y: 62px;
  --enter-scale: .935;
  clip-path: inset(9% 0 0 0 round 2px);
  transition-duration: 850ms, 1250ms, 1250ms;
}
.reveal.reveal-stage:not(.reveal-hero) { --enter-y: 54px; }
.reveal.reveal-from-left:not(.reveal-hero) { --enter-x: -48px; --enter-y: 40px; }
.reveal.reveal-from-right:not(.reveal-hero) { --enter-x: 48px; --enter-y: 40px; }
.reveal.reveal-callout:not(.reveal-hero) { --enter-y: 68px; --enter-scale: .94; }
.reveal.reveal-cta:not(.reveal-hero) { --enter-y: 72px; --enter-scale: .94; }

.reveal:not(.reveal-hero).is-visible,
.reveal.reveal-media:not(.reveal-hero).is-visible {
  opacity: 1;
  filter: none;
  transform: translate3d(0, 0, 0) scale(1);
  clip-path: inset(0 0 0 0 round 0);
  animation: none;
  will-change: auto;
}

/* Text groups animate their children only, avoiding competing parent motion. */
.reveal-stagger:not(.reveal-hero),
.reveal-stagger.is-visible:not(.reveal-hero) {
  opacity: 1;
  transform: none;
  transition: none;
  animation: none;
}

.reveal-stagger:not(.reveal-hero) > * {
  opacity: 0;
  transform: translate3d(0, 30px, 0) scale(.985) skewY(1deg);
  transition:
    opacity 680ms cubic-bezier(.2, .65, .25, 1),
    transform 960ms cubic-bezier(.16, 1, .3, 1);
}

.reveal-stagger.is-visible:not(.reveal-hero) > * {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

.reveal-stagger.is-visible:not(.reveal-hero) > *:nth-child(1) { transition-delay: 70ms; }
.reveal-stagger.is-visible:not(.reveal-hero) > *:nth-child(2) { transition-delay: 180ms; }
.reveal-stagger.is-visible:not(.reveal-hero) > *:nth-child(3) { transition-delay: 290ms; }
.reveal-stagger.is-visible:not(.reveal-hero) > *:nth-child(4) { transition-delay: 400ms; }
.reveal-stagger.is-visible:not(.reveal-hero) > *:nth-child(5) { transition-delay: 510ms; }
.reveal-stagger.is-visible:not(.reveal-hero) > *:nth-child(n+6) { transition-delay: 620ms; }

/* Callouts and CTAs get a second, restrained content cascade after their
   section settles into view. */
.reveal-callout:not(.reveal-hero) > *,
.reveal-cta:not(.reveal-hero) > * {
  opacity: 0;
  transform: translate3d(0, 24px, 0);
  transition:
    opacity 720ms cubic-bezier(.2, .65, .25, 1),
    transform 980ms cubic-bezier(.16, 1, .3, 1);
}

.reveal-callout.is-visible:not(.reveal-hero) > *,
.reveal-cta.is-visible:not(.reveal-hero) > * {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

.reveal-callout.is-visible:not(.reveal-hero) > *:nth-child(1),
.reveal-cta.is-visible:not(.reveal-hero) > *:nth-child(1) { transition-delay: 180ms; }
.reveal-callout.is-visible:not(.reveal-hero) > *:nth-child(2),
.reveal-cta.is-visible:not(.reveal-hero) > *:nth-child(2) { transition-delay: 340ms; }
.reveal-callout.is-visible:not(.reveal-hero) > *:nth-child(3),
.reveal-cta.is-visible:not(.reveal-hero) > *:nth-child(3) { transition-delay: 500ms; }

/* White base plus one black duplicate revealed by a feathered left-to-right
   mask. The last keyframe becomes a solid mask, guaranteeing a black finish. */
.home-main .aerial-callout h2 .premium-word {
  position: relative;
  display: inline-block;
  color: transparent !important;
  -webkit-text-fill-color: transparent !important;
  background-image: linear-gradient(90deg, #111 0 34%, rgba(17,17,17,.96) 37%, rgba(17,17,17,.78) 41%, rgba(17,17,17,.52) 45%, rgba(17,17,17,.27) 49%, rgba(17,17,17,.08) 52%, #fff 56% 100%);
  background-size: 300% 100%;
  background-position: 100% 0;
  background-repeat: no-repeat;
  -webkit-background-clip: text;
  background-clip: text;
  animation: none !important;
}

.home-main .aerial-callout .premium-word::before {
  display: none !important;
  animation: none !important;
}

.home-main .aerial-callout .premium-word::after {
  display: none !important;
  animation: none !important;
}

.home-main .aerial-callout .premium-word.premium-wipe-visible {
  animation: premium-white-to-black-final 2400ms cubic-bezier(.65, 0, .35, 1) 0ms both !important;
}

@keyframes premium-white-to-black-final {
  /* Begin with the feathered edge already touching the left side of the word,
     so black appears immediately instead of spending the opening frames off-text. */
  from {
    background-position: 84% 0;
  }
  to {
    background-position: 0 0;
  }
}

@media (max-width: 700px) {
  .reveal:not(.reveal-hero) { --enter-x: 0px; --enter-y: 34px; --enter-scale: .97; }
  .reveal-stagger:not(.reveal-hero) > * { transform: translate3d(0, 20px, 0) scale(.99); }
}

@media (prefers-reduced-motion: reduce) {
  .reveal:not(.reveal-hero),
  .reveal.is-visible:not(.reveal-hero),
  .reveal-stagger:not(.reveal-hero),
  .reveal-stagger:not(.reveal-hero) > * {
    opacity: 1 !important;
    filter: none !important;
    transform: none !important;
    transition: none !important;
    animation: none !important;
  }
  .home-main .aerial-callout h2 .premium-word {
    color: #111 !important;
    -webkit-text-fill-color: #111 !important;
    background: none !important;
  }
  .home-main .aerial-callout .premium-word::before,
  .home-main .aerial-callout .premium-word::after { display: none !important; }
}

/* v82: individual content choreography. Wrapper reveals are neutralized so
   every visible content item owns one clean, hero-inspired entrance. */
.reveal:not(.reveal-hero):not(.content-motion),
.reveal.is-visible:not(.reveal-hero):not(.content-motion),
.reveal-stagger:not(.reveal-hero),
.reveal-stagger.is-visible:not(.reveal-hero) {
  opacity: 1;
  filter: none;
  transform: none;
  clip-path: none;
  animation: none;
  transition: none;
}

.reveal-stagger:not(.reveal-hero) > *,
.reveal-callout:not(.reveal-hero) > *,
.reveal-cta:not(.reveal-hero) > * {
  opacity: 1;
  transform: none;
  transition: none;
}

.content-motion {
  --motion-x: -74px;
  --motion-y: 30px;
  --motion-skew: -3deg;
  --motion-over: 9px;
  --motion-delay: 0ms;
  opacity: 0;
  filter: blur(7px);
  transform: translate3d(var(--motion-x), var(--motion-y), 0) scale(.94) skewX(var(--motion-skew));
  transform-origin: 30% 60%;
  will-change: opacity, transform, filter;
}

/* Media wrappers also carry legacy reveal classes; this equal-specificity
   rule keeps their starting pose in the new choreography. */
.reveal.content-motion {
  opacity: 0;
  filter: blur(7px);
  transform: translate3d(var(--motion-x), var(--motion-y), 0) scale(.94) skewX(var(--motion-skew));
  will-change: opacity, transform, filter;
}

.content-motion:not(.is-motion-visible) {
  opacity: 0 !important;
  filter: blur(7px) !important;
  transform: translate3d(var(--motion-x), var(--motion-y), 0) scale(.94) skewX(var(--motion-skew)) !important;
  transition: none !important;
  animation: none !important;
}

.content-motion.motion-media:not(.is-motion-visible) {
  filter: blur(9px) saturate(.78) !important;
  clip-path: inset(10% 3% 2% 3% round 3px) !important;
  transform: translate3d(var(--motion-x), var(--motion-y), 0) scale(.91) !important;
}

.content-motion.motion-from-right {
  --motion-x: 74px;
  --motion-skew: 3deg;
  --motion-over: -9px;
  transform-origin: 70% 60%;
}

.content-motion.motion-copy {
  --motion-x: -34px;
  --motion-y: 36px;
  --motion-skew: -1deg;
}

.content-motion.motion-copy.motion-from-right {
  --motion-x: 34px;
  --motion-skew: 1deg;
}

.content-motion.motion-media {
  --motion-y: 52px;
  clip-path: inset(10% 3% 2% 3% round 3px);
}

.content-motion.motion-action {
  --motion-x: 0px;
  --motion-y: 32px;
  --motion-skew: 0deg;
  filter: none;
  transform: translate3d(0, var(--motion-y), 0) scale(.86);
}

.content-motion.motion-action:not(.is-motion-visible) {
  filter: none !important;
}

.content-motion.is-motion-visible {
  animation: content-cinematic-arrival 1250ms cubic-bezier(.16, .84, .24, 1) var(--motion-delay) both !important;
}

.content-motion.motion-media.is-motion-visible {
  animation: content-media-arrival 1450ms cubic-bezier(.16, .84, .24, 1) var(--motion-delay) both !important;
}

.content-motion.motion-action.is-motion-visible {
  animation: content-action-arrival 1050ms cubic-bezier(.16, .84, .24, 1) var(--motion-delay) both !important;
}

@keyframes content-cinematic-arrival {
  0% {
    opacity: 0;
    filter: blur(7px);
    transform: translate3d(var(--motion-x), var(--motion-y), 0) scale(.94) skewX(var(--motion-skew));
  }
  100% {
    opacity: 1;
    filter: none;
    transform: translate3d(0, 0, 0) scale(1);
  }
}

@keyframes content-media-arrival {
  0% {
    opacity: 0;
    filter: blur(9px) saturate(.78);
    clip-path: inset(10% 3% 2% 3% round 3px);
    transform: translate3d(var(--motion-x), var(--motion-y), 0) scale(.91);
  }
  100% {
    opacity: 1;
    filter: none;
    clip-path: inset(0 0 0 0 round 0);
    transform: translate3d(0, 0, 0) scale(1);
  }
}

@keyframes content-action-arrival {
  0% { opacity: 0; filter: none; transform: translate3d(0, 32px, 0) scale(.86); }
  100% { opacity: 1; filter: none; transform: translate3d(0, 0, 0) scale(1); }
}

@media (max-width: 700px) {
  .content-motion,
  .content-motion.motion-from-right {
    --motion-x: 0px;
    --motion-y: 38px;
    --motion-skew: 0deg;
    --motion-over: 0px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .content-motion,
  .content-motion.is-motion-visible {
    opacity: 1 !important;
    filter: none !important;
    clip-path: none !important;
    transform: none !important;
    animation: none !important;
  }
}

/* v96: smooth, reversible mobile drawer motion.
   The drawer travels fully from above the viewport and uses one balanced
   accelerate/decelerate curve in both directions. Visibility is controlled by
   the mounted state, so it cannot blink out before the transform completes. */
@media (max-width: 1100px) {
  .mobile-menu,
  body.menu-is-open .mobile-menu {
    opacity: 1;
    transform: translate3d(0, -100%, 0);
    transition-property: transform;
    transition-duration: 560ms;
    transition-timing-function: cubic-bezier(.4, 0, .2, 1);
    transition-delay: 0s;
    will-change: transform;
  }

  .mobile-menu.is-mounted,
  body.menu-is-open .mobile-menu.is-mounted,
  .mobile-menu.is-closing,
  body.menu-is-open .mobile-menu.is-closing {
    visibility: visible;
  }

  .mobile-menu.open,
  body.menu-is-open .mobile-menu.open {
    visibility: visible;
    pointer-events: auto;
    transform: translate3d(0, 0, 0);
  }

  .mobile-menu.is-closing,
  body.menu-is-open .mobile-menu.is-closing {
    pointer-events: none;
    transform: translate3d(0, -100%, 0);
    transition-duration: 500ms;
    transition-timing-function: cubic-bezier(.4, 0, .2, 1);
  }
}

@media (prefers-reduced-motion: reduce) and (max-width: 1100px) {
  .mobile-menu,
  body.menu-is-open .mobile-menu,
  .mobile-menu.is-closing,
  body.menu-is-open .mobile-menu.is-closing {
    transition-duration: 1ms;
  }
}

/* v90: one calm entrance for all scroll-revealed content. */
.content-motion,
.reveal.content-motion,
.content-motion.motion-copy,
.content-motion.motion-media,
.content-motion.motion-heading,
.content-motion.motion-action {
  --motion-delay: 0ms;
  opacity: 0;
  filter: blur(9px);
  clip-path: none;
  transform: translate3d(0, 42px, 0);
  transition: none;
  animation: none;
  will-change: opacity, transform, filter;
}

.content-motion:not(.is-motion-visible),
.content-motion.motion-media:not(.is-motion-visible),
.content-motion.motion-action:not(.is-motion-visible) {
  opacity: 0 !important;
  filter: blur(9px) !important;
  clip-path: none !important;
  transform: translate3d(0, 42px, 0) !important;
  transition: none !important;
  animation: none !important;
}

.content-motion.is-motion-visible,
.content-motion.motion-media.is-motion-visible,
.content-motion.motion-action.is-motion-visible {
  animation: content-rise-and-focus 980ms cubic-bezier(.22, 1, .36, 1) var(--motion-delay) both !important;
}

@keyframes content-rise-and-focus {
  from {
    opacity: 0;
    filter: blur(9px);
    clip-path: none;
    transform: translate3d(0, 42px, 0);
  }
  to {
    opacity: 1;
    filter: blur(0);
    clip-path: none;
    transform: translate3d(0, 0, 0);
  }
}

.home-main .aerial-callout .premium-word.premium-wipe-visible {
  animation: premium-white-to-black-final 2400ms cubic-bezier(.65, 0, .35, 1) 0ms both !important;
}

@media (prefers-reduced-motion: reduce) {
  .content-motion,
  .content-motion.is-motion-visible {
    opacity: 1 !important;
    filter: none !important;
    transform: none !important;
    animation: none !important;
  }
}


/* v102: Gallery frames now reuse the exact homepage showcase backing, while
   number badges live in a reserved card gutter. This prevents clipping from
   page overflow, transforms, filters, and the desktop/mobile number swap. */
.gallery-page .gallery-section,
.gallery-page .gallery-section > .wrap,
.gallery-page .video-grid,
.gallery-page .video-card {
  overflow: visible !important;
}

.gallery-page .video-grid {
  padding: 34px 28px 44px;
}

.gallery-page .video-card,
.gallery-page .video-card.vertical {
  position: relative;
  width: 100%;
  justify-self: stretch;
  padding: 16px 8px 8px 16px;
  border: 0;
  background: transparent;
  box-shadow: none;
  contain: none;
  isolation: isolate;
}

/* Use the same framed-media + showcase-film treatment as the homepage film. */
.gallery-page .video-backdrop.framed-media.showcase-film,
.gallery-page .video-card.vertical .video-backdrop.framed-media.showcase-film {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: none;
  justify-self: stretch;
  aspect-ratio: 16 / 9;
  border: 3px solid var(--line);
  background: #000;
  box-shadow: 6px 6px 0 var(--line);
  overflow: hidden;
  contain: layout paint;
  transform: translateZ(0);
}

.gallery-page .video-backdrop.framed-media.showcase-film iframe,
.gallery-page .video-card.vertical .video-backdrop.framed-media.showcase-film iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: 100%;
  aspect-ratio: auto;
  border: 0;
  background: #000;
}

/* The badge overlaps the frame but remains completely inside the outer card's
   reserved top-left gutter, so no ancestor can crop its border or digits. */
.gallery-page .video-number {
  z-index: 6;
  top: 0;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: auto;
  min-width: 50px;
  height: 38px;
  min-height: 38px;
  padding: 0 8px;
  border: 3px solid var(--line);
  overflow: visible !important;
  contain: none;
  clip-path: none;
  -webkit-clip-path: none;
  filter: none !important;
  line-height: 1;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  transform: translate3d(0, 0, 1px);
}

.gallery-page .video-number > span {
  width: auto;
  line-height: 1;
  text-align: center;
  overflow: visible;
}

/* Only one numbering variant may participate in layout. The previous generic
   > span rule overrode these states and made a second number spill into video. */
.gallery-page .video-number .video-number-desktop {
  display: block;
}

.gallery-page .video-number .video-number-mobile {
  display: none;
}

@media (max-width: 700px) {
  .gallery-page .video-grid {
    padding: 31px 20px 42px;
    gap: 46px;
  }

  .gallery-page .video-card,
  .gallery-page .video-card.vertical {
    padding: 14px 6px 6px 14px;
  }

  .gallery-page .video-number {
    top: 0;
    left: 0;
    min-width: 48px;
    height: 36px;
    min-height: 36px;
    padding-inline: 7px;
  }

  .gallery-page .video-number .video-number-desktop {
    display: none;
  }

  .gallery-page .video-number .video-number-mobile {
    display: block;
  }
}

/* v104: Projects and Aerials use the homepage text reveal timing and curve.
   JavaScript now guarantees a painted hidden frame before this animation starts,
   preventing first-load cards from blinking directly to their final state. The
   card rises once while the framed video focuses once; no scale or overshoot. */
.gallery-page .video-card,
.gallery-page .video-card.content-motion,
.gallery-page .video-card.content-motion.is-motion-visible {
  --hang-x: var(--hang-x-base, 0px);
  --hang-y: var(--hang-y-base, 0px);
  --hang-rotate: var(--hang-rotate-base, 0deg);
  transform-origin: 50% 7%;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

.gallery-page .video-card.content-motion:not(.is-motion-visible) {
  opacity: 0 !important;
  filter: none !important;
  transform:
    translate3d(var(--hang-x), calc(var(--hang-y) + 42px), 0)
    rotate(var(--hang-rotate)) !important;
  animation: none !important;
  transition: none !important;
  will-change: auto;
}

.gallery-page .video-card.content-motion.is-motion-visible {
  animation: gallery-video-blur-hang-in 980ms cubic-bezier(.22, 1, .36, 1) var(--motion-delay) both !important;
  will-change: opacity, transform;
}

@keyframes gallery-video-blur-hang-in {
  from {
    opacity: 0;
    filter: none;
    transform:
      translate3d(var(--hang-x), calc(var(--hang-y) + 42px), 0)
      rotate(var(--hang-rotate));
  }
  to {
    opacity: 1;
    filter: none;
    transform:
      translate3d(var(--hang-x), var(--hang-y), 0)
      rotate(var(--hang-rotate));
  }
}

/* Keep the familiar blur-to-focus finish on the video stage, but use a lower
   blur radius and no scale/overshoot so large iframe surfaces remain smooth.
   Offscreen cards stay unfiltered and unpromoted until their one-time reveal. */
.gallery-page .video-card.content-motion .video-backdrop,
.gallery-page .video-card.content-motion:not(.is-motion-visible) .video-backdrop {
  opacity: 1;
  filter: none;
  transform: translateZ(0);
  animation: none;
  transition: none;
  will-change: auto;
}

.gallery-page .video-card.content-motion.is-motion-visible .video-backdrop {
  animation: gallery-video-backdrop-focus-in 980ms cubic-bezier(.22, 1, .36, 1) var(--motion-delay) both;
  will-change: filter;
}

@keyframes gallery-video-backdrop-focus-in {
  from {
    opacity: 1;
    filter: blur(7px) saturate(.94);
    transform: translateZ(0);
  }
  to {
    opacity: 1;
    filter: none;
    transform: translateZ(0);
  }
}

/* Freeze the final pose and discard retained animation/compositor state after
   the one-time entrance. This prevents hidden animation layers from building
   up as the user scrolls through long Projects and Aerials galleries. */
.gallery-page .video-card.content-motion.motion-complete,
.gallery-page .video-card.content-motion.is-motion-visible.motion-complete {
  opacity: 1 !important;
  filter: none !important;
  transform:
    translate3d(var(--hang-x), var(--hang-y), 0)
    rotate(var(--hang-rotate)) !important;
  animation: none !important;
  will-change: auto !important;
}

.gallery-page .video-card.content-motion.motion-complete .video-backdrop,
.gallery-page .video-card.content-motion.is-motion-visible.motion-complete .video-backdrop {
  opacity: 1 !important;
  filter: none !important;
  transform: translateZ(0) !important;
  animation: none !important;
  will-change: auto !important;
}

@media (max-width: 700px) {
  .gallery-page .video-card,
  .gallery-page .video-card.content-motion,
  .gallery-page .video-card.content-motion.is-motion-visible {
    --hang-x: var(--hang-x-mobile, 0px);
    --hang-y: var(--hang-y-mobile, 0px);
    --hang-rotate: var(--hang-rotate-mobile, 0deg);
  }

  .gallery-page .video-card.content-motion:not(.is-motion-visible) {
    transform:
      translate3d(var(--hang-x), calc(var(--hang-y) + 32px), 0)
      rotate(var(--hang-rotate)) !important;
  }

  @keyframes gallery-video-blur-hang-in {
    from {
      opacity: 0;
      filter: none;
      transform:
        translate3d(var(--hang-x), calc(var(--hang-y) + 32px), 0)
        rotate(var(--hang-rotate));
    }
    to {
      opacity: 1;
      filter: none;
      transform:
        translate3d(var(--hang-x), var(--hang-y), 0)
        rotate(var(--hang-rotate));
    }
  }
}

@media (prefers-reduced-motion: reduce) {
  .gallery-page .video-card.content-motion,
  .gallery-page .video-card.content-motion.is-motion-visible {
    opacity: 1 !important;
    filter: none !important;
    transform: translate3d(var(--hang-x), var(--hang-y), 0) rotate(var(--hang-rotate)) !important;
    animation: none !important;
    will-change: auto !important;
  }

  .gallery-page .video-card.content-motion .video-backdrop,
  .gallery-page .video-card.content-motion.is-motion-visible .video-backdrop {
    opacity: 1 !important;
    filter: none !important;
    transform: translateZ(0) !important;
    animation: none !important;
    will-change: auto !important;
  }
}

