/* Section composition only. Calendar geometry remains in visual-product.css and calendar-data.js. */
.product-story {
  --hero-inset: max(var(--page-gutter), calc((100% - var(--header-track)) / 2));
  --story-peek: 150px;
  --story-radius: var(--space-24);
  --story-gap: var(--space-24);

  /* Same mix as the end of .hero__fade in layout.css; a different start color reopens the seam. */
  background: color-mix(in srgb, var(--color-lp-hero-edge), var(--color-black) calc(var(--story-dark, 1) * 100%));
  color: var(--color-white);
}

/* Below 1024px this becomes the sticky track. display:contents keeps the desktop sticky parent as the section. */
.product-story__pin {
  display: contents;
}

.product-story__viewport {
  position: relative;
  overflow: clip;
  isolation: isolate;
}

/* Soft glows, not a Figma mesh layer. Colors are the LP glow tokens. Same fade as the black field. */
.product-story__mesh {
  position: absolute;
  z-index: 0;
  inset: 0;
  overflow: hidden;
  opacity: var(--story-dark, 1);
  /* The top edge meets the hero; a hard glow edge there would read as a section boundary. */
  mask-image: linear-gradient(to bottom, transparent, black 35%);
  pointer-events: none;
}

.product-story__glow {
  position: absolute;
  border-radius: 50%;
  filter: blur(140px);
}

.product-story__glow--violet {
  top: -18%;
  left: -12%;
  width: min(760px, 58vw);
  aspect-ratio: 1;
  background: var(--color-lp-violet-glow);
  opacity: 0.42;
}

.product-story__glow--ember {
  right: -8%;
  bottom: -20%;
  width: min(680px, 50vw);
  aspect-ratio: 1;
  background: var(--color-lp-ember-glow);
  opacity: 0.34;
}

.product-story__glow--sky {
  top: 8%;
  left: 38%;
  width: min(520px, 40vw);
  aspect-ratio: 1;
  background: var(--color-lp-glow);
  opacity: 0.3;
}

.product-story__layout {
  min-height: 100svh;
  padding-top: calc(var(--header-block) + var(--space-24) + var(--space-64));
}

.product-story__copy {
  position: relative;
  z-index: 3;
  max-width: 620px;
  min-width: 0;
  text-align: left;
}

.product-story__kicker {
  margin: 0;
  color: var(--color-lp-accent);
  font-family: var(--font-text);
  font-size: var(--type-caption-size);
  font-weight: 500;
  line-height: var(--type-caption-line-height);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.product-story__title {
  margin: var(--space-16) 0 0;
  color: var(--color-white);
  font-family: var(--font-display);
  font-size: var(--type-h2-size);
  font-weight: 500;
  line-height: var(--type-h2-line-height);
  letter-spacing: -0.03em;
}

.product-story__body {
  margin: var(--space-24) 0 0;
  color: var(--color-white);
  font-size: var(--type-body-1-size);
  line-height: var(--type-body-1-line-height);
}

.product-story__body p {
  margin: 0;
}

.product-story__body p + p {
  margin-top: var(--space-16);
}

.product-story__scene {
  --visual-stage-end-x: 0deg;
  --visual-stage-end-y: 0deg;

  perspective: none;
  pointer-events: none;
}

.product-story__product {
  transform: none;
}

.product-story__flight {
  display: none;
  position: absolute;
  z-index: 2;
  inset: 0;
  pointer-events: none;
}

.product-story__media {
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;
  background: var(--story-media-fill);
  pointer-events: none;
}

.product-story__media--primary {
  --story-media-fill: var(--color-lp-meta);
  z-index: 2;
}

.product-story__media--secondary {
  --story-media-fill: var(--color-lp-nav);
  z-index: 1;
}

/* Height is the fit axis, so the frame is never cropped top or bottom. Sides crop when the box is narrower than 16:9. max-width: none overrides base.css, which would shrink the picture to the box width and letterbox the height. */
.product-story__media > video {
  position: absolute;
  top: 0;
  left: 50%;
  width: auto;
  height: 100%;
  max-width: none;
  transform: translateX(-50%);
}

/* The same media node moves into .vp-tile__clip at landing, beneath its existing text. */
.product-story__media[data-docked] {
  z-index: -1;
  inset: 0;
  width: 100%;
  height: 100%;
  border-radius: inherit;
}

.product-story__product [data-story-media] {
  --tile-ink: var(--color-white);
  --tile-stroke: transparent;
}

.product-story__product [data-story-media] .vp-tile__title,
.product-story__product [data-story-media] .vp-tile__time {
  opacity: 1;
}

@media (min-width: 1024px) and (prefers-reduced-motion: no-preference) {
  .product-story[data-story-animated] {
    height: var(--story-track-height);
  }

  [data-story-animated] .product-story__viewport {
    position: sticky;
    top: 0;
    height: 100svh;
  }

  [data-story-animated] .product-story__layout {
    position: absolute;
    top: var(--story-layout-top, calc(var(--header-block) + var(--space-24)));
    width: 100%;
    height: var(--story-layout-height);
    min-height: 0;
    /* Copy and calendar share the row center, so the text sits vertically centered on the calendar. */
    align-items: center;
    padding-top: 0;
    padding-bottom: 0;
  }

  [data-story-animated] .product-story__flight {
    display: block;
  }

  [data-story-animated] .product-story__flight > .product-story__media {
    will-change: transform, width, height, border-radius;
  }

  [data-story-animated] .product-story__scene {
    will-change: transform, opacity;
  }
}

/* The hero stacks below 1366px. This section keeps its requested desktop pairing down to 1024px. */
@media (min-width: 1024px) and (max-width: 1365px) {
  .product-story__layout {
    grid-template-columns: minmax(0, 1.15fr) minmax(280px, 0.85fr);
    column-gap: var(--space-64);
    row-gap: 0;
    padding-left: var(--hero-inset);
    padding-bottom: var(--space-24);
  }

  .product-story__copy {
    width: 100%;
    text-align: left;
  }

  .product-story__scene {
    width: auto;
    /* Clears the essay. The hero stage margin would pull this calendar left over the copy. */
    margin-left: var(--space-48);
    justify-self: stretch;
  }
}

/*
  Below 1024px the essay leaves the grid (product-story.js sets data-story-flow).
  The calendar keeps the top-left corner on screen and is wide enough that Tuesday
  stays inside; layout.css's hero stage width and margin would crop a different fragment.
*/
@media (max-width: 1023px) {
  .product-story__layout {
    display: block;
    min-height: 0;
    padding: var(--story-scene-top, var(--space-24)) 0 0;
    row-gap: 0;
  }

  .product-story__scene {
    --visual-stage-scale: 1;

    width: var(--story-scene-width, 100%);
    margin-left: var(--story-scene-inset, var(--space-16));
    justify-self: start;
  }

  .product-story__copy[data-story-flow] {
    width: min(620px, calc(100% - 2 * var(--hero-inset)));
    margin: var(--space-48) auto 0;
    padding-bottom: var(--space-96);
    text-align: left;
  }
}

@media (max-width: 1023px) and (prefers-reduced-motion: no-preference) {
  .product-story[data-story-animated] .product-story__pin {
    display: block;
    height: var(--story-track-height);
  }

  [data-story-animated] .product-story__viewport {
    position: sticky;
    top: 0;
    height: 100svh;
  }

  [data-story-animated] .product-story__flight {
    display: block;
  }

  [data-story-animated] .product-story__flight > .product-story__media {
    will-change: transform, width, height, border-radius;
  }

  [data-story-animated] .product-story__scene {
    will-change: transform, opacity;
  }

  /*
    Negative shift from product-story.js. It overlaps the empty bottom of the sticky
    frame so the essay meets the calendar instead of waiting a full screen below it.
  */
  .product-story[data-story-animated] .product-story__copy[data-story-flow] {
    position: relative;
    z-index: 4;
    margin-top: var(--story-copy-shift, 0px);
  }

  .product-story[data-story-animated] .product-story__copy[data-story-flow]:not([data-story-visible]) {
    visibility: hidden;
  }
}
