/* Instagram-style post carousel — infinite.
   Three viewports (prev peek / post / next peek) share one index and one
   transition, so the neighbouring image visibly slides into the post frame.
   The tracks are cloned and wrapped in JS: the post stays centred and both
   neighbours are always filled.
   Sizes are in px/vw on purpose: this page inherits html{font-size:.625vw}
   from main-style.css, so rem here would track the viewport twice over. */

.igp-wrap {
  display: flex;
  justify-content: center;
  width: 100%;
}

.igp {
  /* The vw coefficients are what make this fit beside the section copy, so they
     are picked against that column rather than by eye. This page's root
     font-size is .625vw, so the headline next to the post is 10rem = 6.25vw and
     claims a constant ~33vw whatever the screen; the content column is 83vw and
     the gap 3.75vw, which leaves ~44vw for the post at every width.
     Fanned footprint = --igp-w + 2·--igp-peek-w - 2·3vw (the peek overlap),
     i.e. 23 + 24 - 6 = 41vw here. The px caps still bite first on ultrawide
     (23vw ≥ 500px from 2175 up), so that layout is unchanged. */
  --igp-w: clamp(280px, 23vw, 500px);
  --igp-ratio: 1 / 1;
  --igp-peek-w: clamp(140px, 12vw, 330px);
  --igp-radius: 18px;
  /* Measured off the reference recording: the change is a cross-dissolve, not a
     full-width slide. The incoming image enters ~15% of the width away and eases
     to 0 while fading in; the outgoing drifts the same distance the other way.
     The curve is a hard ease-out — ~60% done at 100ms, ~87% at 200ms, then a
     long soft settle, which is what makes it feel smooth rather than mechanical. */
  --igp-ease: cubic-bezier(.16, 1, .3, 1);
  --igp-dur: 700ms;
  --igp-travel: 15%;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  padding: clamp(20px, 4vw, 56px) 0;
  font-family: "Acid Grotesk", system-ui, -apple-system, "Segoe UI", sans-serif;
  color: #fff;
  -webkit-user-select: none;
  user-select: none;
}

/* ---- neighbouring images ---------------------------------------------- */

.igp__peek {
  position: relative;
  /* shrinkable, not `flex: none`: if the copy beside it ever needs more room
     than the vw maths above assumed (a longer headline, a wider font fallback),
     the post has to give way instead of overflowing across the text */
  flex: 0 1 auto;
  min-width: 0;
  width: var(--igp-peek-w);
  /* follows the post's own ratio, so a 9:16 reel does not leave the neighbours
     as short 4:3 bands beside a tall card */
  aspect-ratio: var(--igp-ratio);
  border-radius: 16px;
  overflow: hidden;
  background: #0a0a0b;
  opacity: 1;
  transition: opacity .45s ease;
}

.igp__peek--prev {
  margin-right: clamp(-60px, -3vw, -24px);
}

.igp__peek--next {
  margin-left: clamp(-60px, -3vw, -24px);
}

.igp__peek .igp__slide img {
  filter: brightness(.5);
}

/* hidden neighbours: the post keeps its own size, the peeks fold away */
.igp[data-peek="off"] .igp__peek {
  width: 0;
  margin: 0;
  opacity: 0;
  pointer-events: none;
}

/* ---- the post --------------------------------------------------------- */

.igp__card {
  position: relative;
  z-index: 2;
  flex: 0 1 auto;
  min-width: 0;
  width: var(--igp-w);
  background: #000;
  border: 1px solid rgba(255, 255, 255, .1);
  border-radius: var(--igp-radius);
  overflow: hidden;
  box-shadow: 0 40px 90px -34px rgba(0, 0, 0, .95);
}

.igp__head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
}

.igp__avatar {
  flex: none;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  overflow: hidden;
  background: #1c1c1e;
  color: #fff;
}

.igp__avatar img,
.igp__avatar svg {
  width: 58%;
  height: 58%;
  object-fit: contain;
  display: block;
}

/* Client marks, same two cases the story reel handles: a black-on-transparent
   wordmark has to flip on the #1c1c1e disc, and an opaque logo fills it rather
   than floating inset, where its own square backdrop would show. */
.igp__avatar img.is-inverted {
  filter: invert(1);
}

.igp__avatar img.is-fill {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.igp__ids {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.igp__user {
  font-size: 15px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -.01em;
}

/* location / music / whatever the post wants to say up top */
.igp__sub {
  font-size: 12px;
  line-height: 1.2;
  color: rgba(255, 255, 255, .6);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.igp__sub:empty {
  display: none;
}

.igp__more {
  margin-left: auto;
  flex: none;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: #fff;
  cursor: pointer;
  transition: background .25s;
}

.igp__more:hover {
  background: rgba(255, 255, 255, .1);
}

/* ---- media ------------------------------------------------------------ */

.igp__media {
  position: relative;
  z-index: 1;
  touch-action: pan-y;
  cursor: grab;
}

.igp__media.is-dragging {
  cursor: grabbing;
}

.igp__viewport {
  position: relative;
  width: 100%;
  aspect-ratio: var(--igp-ratio);
  overflow: hidden;
  background: #0a0a0b;
  /* keep the slides' z-index inside this box. Without it the peeks' layers sit
     in the same stacking context as .igp__card (also z-index 2) and, being
     later in the DOM, paint over the post. */
  isolation: isolate;
}

/* the peek box already sets the frame; its viewport just fills it */
.igp__peek .igp__viewport {
  height: 100%;
  aspect-ratio: auto;
}

/* the track is a stack now — every slide sits on top of the others and only
   opacity + a short drift separate them */
.igp__track {
  position: relative;
  height: 100%;
}

.igp__slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  z-index: 1;
  /* the script writes `transform` directly — going through a custom property
     costs a couple of frames before the transition picks the change up */
  transform: translate3d(0, 0, 0);
  will-change: transform, opacity;
  pointer-events: none;
}

/* The layer being replaced stays FULLY OPAQUE underneath while the incoming one
   fades in over it. Fading both at once looks like the obvious thing to do and
   is wrong: two half-transparent layers composite to
   0.5·new + 0.25·old + 0.25·background, so the post visibly dips towards black
   half way through. Holding the bottom layer at 1 makes the composite exactly
   a·new + (1-a)·old — a true dissolve. */
.igp__slide.is-under {
  opacity: 1;
  z-index: 2;
}

.igp__slide.is-cur {
  opacity: 1;
  z-index: 3;
}

/* only animate once the script has armed it, so the first paint doesn't fade in */
.igp__track.is-live .igp__slide {
  transition:
    opacity var(--igp-dur) var(--igp-ease),
    transform var(--igp-dur) var(--igp-ease);
}

/* while a finger is down the layers track it directly, with no easing */
.igp__track.is-scrubbing .igp__slide {
  transition: none;
}

.igp__slide img,
.igp__slide video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  pointer-events: none;
}

/* ---- arrows ----------------------------------------------------------- */

.igp__nav {
  position: absolute;
  top: 50%;
  z-index: 3;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  margin-top: -20px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(20, 20, 22, .72);
  color: #fff;
  cursor: pointer;
  transition: background .25s, opacity .25s, transform .25s;
}

.igp__nav:hover {
  background: rgba(38, 38, 42, .9);
}

.igp__nav--prev {
  left: 14px;
}

.igp__nav--next {
  right: 14px;
}

.igp__nav svg {
  width: 18px;
  height: 18px;
  display: block;
}

/* ---- dots ------------------------------------------------------------- */

.igp__dots {
  position: absolute;
  left: 50%;
  bottom: 14px;
  z-index: 3;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(10, 10, 12, .55);
  backdrop-filter: blur(8px);
}

.igp__dot {
  width: 6px;
  height: 6px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, .38);
  cursor: pointer;
  transition: background .3s, transform .3s;
}

.igp__dot.is-sel {
  background: #fff;
  transform: scale(1.34);
}

/* ---- actions ---------------------------------------------------------- */

.igp__actions {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 14px 16px 6px;
}

.igp__act {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 0;
  border: 0;
  background: transparent;
  color: #fff;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: opacity .25s, transform .25s;
}

.igp__act:hover {
  opacity: .65;
}

.igp__act svg {
  width: 26px;
  height: 26px;
  display: block;
}

.igp__act--save {
  margin-left: auto;
}

.igp__like.is-on {
  color: #ff2d55;
}

.igp__like.is-on svg {
  fill: currentColor;
  animation: igp-pop .4s var(--igp-ease);
}

.igp__like-count {
  color: #fff;
}

@keyframes igp-pop {
  40% {
    transform: scale(1.25);
  }

  to {
    transform: scale(1);
  }
}

/* ---- caption ---------------------------------------------------------- */

.igp__caption {
  padding: 4px 16px 18px;
  font-size: 14px;
  line-height: 1.45;
  color: rgba(255, 255, 255, .92);
}

.igp__caption b {
  font-weight: 700;
  margin-right: 6px;
}

/* ---- beside the section copy ------------------------------------------ */

/* .vsr-section__inner is a flex row: headline on the left, post on the right.
   Both items over-claim (the head asks for its text width, .igp-wrap for 100%)
   so flex shrinks them in proportion — and .vsr-section__head carries
   min-width: 0, which is what let the post crush the headline on laptops.
   Floor the head at its own text width and let the post absorb the shrink.
   Left off above 2000px on purpose: the ultrawide composition is the one this
   section was designed around, and it has slack to spare there anyway. */
@media (max-width: 1999px) {
  .vsr-section__inner--igp .vsr-section__head {
    min-width: min-content;
  }

  .vsr-section__inner--igp .igp-wrap {
    min-width: 0;
  }
}

/* Vertically centre the copy against the post.
   The section defaults to align-items: flex-start, which is right for the story
   reel — a tall fanned stack the headline reads with from its top edge. The post
   is a compact card instead, and the two columns only read as a pair when their
   centres line up, so the optical top-padding nudges are dropped here. */
@media (min-width: 1240px) {
  .vsr-section__inner--igp {
    align-items: center;
  }

  .vsr-section__inner--igp .vsr-section__head {
    padding-top: 0;
  }
}

/* stacked under the copy: the post has the whole column, so it can grow back */
@media (max-width: 1239px) {
  .igp {
    --igp-w: min(38vw, 460px);
    --igp-peek-w: min(20vw, 300px);
  }
}

@media (max-width: 1099px) {
  .igp {
    --igp-w: min(88vw, 460px);
  }

  .igp__peek {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {

  .igp__track.is-live .igp__slide,
  .igp__peek {
    transition-duration: .01ms;
  }

  .igp__like.is-on svg {
    animation: none;
  }
}
