/*
 * Guided Growth animation layer, drop-in.
 * Pairs with gg-anim.js. Together they are the whole integration surface:
 * one <link> and one <script> added to the existing page, nothing else touched.
 *
 * Every effect here is driven by the --gg-p custom property (0..1 scroll progress)
 * or by the .gg-in class (animate-once on entry). Both are set by gg-anim.js.
 */

/* ---- pinned scroll-scrub ------------------------------------------------ */

/* The spacer is the tall element that gives the pinned section scroll length. */
.gg-pin-spacer {
  position: relative;
}

/* The section itself sticks while the spacer scrolls past it. */
.gg-pin-spacer > .fold {
  position: sticky;
  top: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  overflow: hidden;
}

/*
 * Scrub reveal. Content is staged in bands: each child crosses in as --gg-p passes
 * its slice. Using a custom property keeps this readable and cheap, no per-frame JS
 * style writes beyond the single variable.
 */
.gg-scrub [data-gg-band] {
  opacity: calc((var(--gg-p, 0) - var(--gg-band-start, 0)) * var(--gg-band-gain, 4));
  transform: translateY(
    calc((1 - (var(--gg-p, 0) - var(--gg-band-start, 0)) * var(--gg-band-gain, 4)) * 26px)
  );
  will-change: opacity, transform;
}

/*
 * The mount point a Remotion Player attaches to. Sized by the page, not the Player.
 *
 * The page is light (sections are transparent over white, body text is #141d33) while
 * the compositions are built on the app's dark surface. So the mount is an explicit
 * dark inset, which is what makes the white-on-dark product moments legible here and
 * reads as a product surface rather than as loose text floating on the page.
 */
.gg-player-mount {
  position: relative;
  width: 100%;
  max-width: 720px;
  margin: 22px auto 0;
  aspect-ratio: 12 / 7;
  border-radius: 18px;
  overflow: hidden;
  background: #05070d;
  box-shadow:
    0 18px 50px rgba(12, 22, 55, 0.18),
    0 2px 8px rgba(12, 22, 55, 0.10);
}

/* Shown only until a Player registers, so the slot is never an empty hole. */
.gg-player-mount[data-gg-player="pending"]::after {
  content: "scroll-scrub slot, Remotion Player mounts here";
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font: 500 13px/1.4 -apple-system, BlinkMacSystemFont, "Inter", sans-serif;
  letter-spacing: 0.02em;
  color: rgba(238, 242, 255, 0.5);
  background: linear-gradient(
    120deg,
    rgba(30, 96, 235, calc(0.10 + var(--gg-p, 0) * 0.30)),
    rgba(220, 150, 18, calc(0.06 + var(--gg-p, 0) * 0.24))
  );
  border-radius: 18px;
}

/* Scrub progress readout, so both scroll directions are visibly verifiable. */
.gg-scrub-readout {
  position: absolute;
  right: 16px;
  bottom: 14px;
  z-index: 5;
  font: 600 11px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 0.06em;
  padding: 5px 8px;
  border-radius: 999px;
  color: rgba(255, 255, 255, 0.86);
  background: rgba(12, 22, 55, 0.62);
  border: 1px solid rgba(255, 255, 255, 0.16);
}

/* ---- animate-once on entry ---------------------------------------------- */

.gg-once [data-gg-band] {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 620ms cubic-bezier(0.22, 0.61, 0.36, 1),
    transform 620ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.gg-once.gg-in [data-gg-band] {
  opacity: 1;
  transform: none;
}

/* Stagger, cheap and predictable. */
.gg-once.gg-in [data-gg-band="0"] { transition-delay: 0ms; }
.gg-once.gg-in [data-gg-band="1"] { transition-delay: 90ms; }
.gg-once.gg-in [data-gg-band="2"] { transition-delay: 180ms; }
.gg-once.gg-in [data-gg-band="3"] { transition-delay: 270ms; }

/* Slow push on photographic stills. Camera move only, never a regenerated image. */
.gg-push img {
  transition: transform 1400ms cubic-bezier(0.22, 0.61, 0.36, 1);
  transform: scale(1.045);
}
.gg-push.gg-in img {
  transform: scale(1);
}

/* ---- real parallax ------------------------------------------------------ */

/*
 * Depth layers cut from one approved frame, moved at different rates. See
 * LAYER-CONVENTION.md. The container is the page's own .photo box, which is
 * already position:relative with overflow:hidden, so nothing new wraps the image.
 *
 * The flat image stays in the DOM and keeps defining the box. It is only made
 * invisible once every layer has actually decoded, so a missing or broken layer
 * leaves the original still on screen rather than a hole.
 *
 * Each layer is scaled by 1 + 2 x |depth| in JS, which is exactly enough overhang
 * to cover its own travel. That is why the asset side needs no bleed.
 */
.gg-plx-layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
  will-change: transform;
  transform: translate3d(0, 0, 0) scale(var(--gg-plx-scale, 1));
}
.gg-plx-on > img:not(.gg-plx-layer) {
  visibility: hidden;
}
/* The push and the parallax are two answers to the same problem. Once layers are
   live the push has to stop, or the still is scaled twice. */
.gg-plx-on img {
  transition: none !important;
  transform: none;
}

/* ---- scene, or watch the video ------------------------------------------ */

/*
 * The scene is the default and the video is one click away. The button has to read on
 * a photograph without a scrim over the whole image, so it carries its own frosted
 * surface rather than darkening the picture behind it.
 */
.gg-watch {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 12px 20px 12px 16px;
  border: 1px solid rgba(255, 255, 255, 0.75);
  border-radius: 999px;
  background: rgba(20, 29, 51, 0.42);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: #fff;
  font: 600 15px/1 inherit;
  letter-spacing: 0.01em;
  cursor: pointer;
  transition: background 200ms ease, transform 200ms ease;
}
.gg-watch:hover,
.gg-watch:focus-visible {
  background: rgba(20, 29, 51, 0.62);
  transform: translate(-50%, -50%) scale(1.04);
}
.gg-watch-tri {
  width: 0;
  height: 0;
  border-left: 11px solid #fff;
  border-top: 7px solid transparent;
  border-bottom: 7px solid transparent;
  margin-left: 3px;
}
.gg-scene-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* contain, not cover. The animation is baked into the frame, so cropping the video
     to the box would cut the wave or the words straight off. Letterboxing is correct. */
  object-fit: contain;
  background: #0b1020;
  z-index: 2;
}
/* While the video plays the scene underneath is dead weight, so stop moving it. */
.gg-scene-playing .gg-plx-layer {
  visibility: hidden;
}
.gg-watch-close {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 3;
  width: 34px;
  height: 34px;
  border: 0;
  border-radius: 999px;
  background: rgba(11, 16, 32, 0.7);
  color: #fff;
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
}

/* ---- live hero orb ------------------------------------------------------ */

/*
 * The transparent orb loop sits exactly where the PNG sat. The PNG stays as the
 * element background, so if the video fails to load or decode, the original still
 * shows through untouched.
 */
.gg-orb-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  pointer-events: none;
}

/* ---- accessibility and resilience --------------------------------------- */

/*
 * Reduced motion: no scrub, no stagger, no push. Every section is shown in its
 * finished state immediately. This is the branch the brief keeps binding.
 */
@media (prefers-reduced-motion: reduce) {
  .gg-pin-spacer { height: auto !important; }
  .gg-pin-spacer > .fold { position: static; min-height: 0; }
  .gg-scrub [data-gg-band],
  .gg-once [data-gg-band] {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  .gg-push img { transform: none !important; transition: none !important; }
  /* Layers stay stacked at rest, which reproduces the original frame exactly. */
  .gg-plx-layer { transform: none !important; }
  .gg-orb-video { display: none; }
  .gg-scrub-readout { display: none; }
}

/* Inside a pinned section the headline, the photo and the animation all have to
   share one viewport. Cap the photo so the animation is never pushed off screen. */
.gg-pin-spacer > .fold .photo img {
  max-height: 14vh;
  width: auto;
}
/* The section's own spacing assumes a normal scrolling fold. Pinned, everything
   shares one viewport, so tighten it or the animation falls below the fold. */
.gg-pin-spacer > .fold .wrap {
  margin-bottom: 18px !important;
}
.gg-pin-spacer > .fold .photo {
  margin-top: 16px !important;
}
/* Height driven, not width driven. The panel has to fit whatever vertical space is
   left after the headline and photo, so size it from the viewport and let the width
   follow the aspect ratio. A fixed 720px wide panel overflows shorter laptops. */
.gg-pin-spacer > .fold .gg-player-mount {
  height: min(36vh, 400px);
  width: auto;
  max-width: min(720px, 92vw);
  margin: 10px auto 0;
}
/* The fold's own vertical padding assumes a scrolling section, not a pinned one. */
.gg-pin-spacer > .fold {
  padding-top: 3vh;
  padding-bottom: 3vh;
}
