/* The 3D syringe lead-in to Before & After.
 *
 * The section is tall and the stage inside it sticks. No fixed positioning
 * and no transform on any ancestor, because either one silently kills
 * position: sticky on the child.
 */

/* Stockie's .site-content and the homepage's own .joelle-home both carry
 * overflow: hidden to stop sideways overflow from the sliders. That quietly
 * makes each of them the containing block for position: sticky, so the stage
 * below pins to a box that never scrolls and the section just scrolls past.
 *
 * overflow: clip does the same clipping without creating a scroll container,
 * which is what sticky needs. Scoped to the body class so it only applies on
 * the homepage, only while the section is switched on, and reverts by itself
 * the moment it is switched off.
 */
.jh-syringe-on .joelle-home,
.jh-syringe-on .site-content {
  overflow-x: clip;
  overflow-y: visible;
}

.jh-syringe {
  --jh-syringe-navy: #232e51;

  position: relative;
  height: 400vh;             /* scroll distance the animation is spread over */
  margin: 0;
  background: var(--jh-syringe-navy);
  color: #fff;
}

.jh-syringe-stage {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;            /* so the mobile URL bar doesn't crop it */
  overflow: hidden;
  display: grid;
  place-items: center;
}

.jh-syringe-canvas-wrap,
.jh-syringe-poster,
.jh-syringe-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.jh-syringe-poster {
  object-fit: contain;
  opacity: 1;
  transition: opacity 0.6s ease;
}

/* On a wide screen the render rests right of centre, clear of the copy
   (REST_SHIFT in the module: 0.13 of the width). The still sits in the
   same place, so a crossfade between the two doesn't jump. */
@media (min-aspect-ratio: 6/5) and (min-width: 761px) {
  .jh-syringe-poster {
    object-position: calc(50% + 13vw) 50%;
  }
}

/* The still stays until the renderer has drawn its first frame, so there is
   never a navy void while 3.5MB arrives. */
.jh-syringe.is-live .jh-syringe-poster {
  opacity: 0;
}

.jh-syringe-canvas {
  display: block;
  opacity: 0;
  transition: opacity 0.6s ease;
}

.jh-syringe.is-live .jh-syringe-canvas {
  opacity: 1;
}

/* Copy sits over the render, pinned low-left, out of the model's way. */
.jh-syringe-copy {
  position: relative;
  z-index: 2;
  align-self: end;
  justify-self: start;
  max-width: 32rem;
  margin: 0 0 clamp(3rem, 9vh, 7rem) clamp(1.25rem, 6vw, 6rem);
  text-shadow: 0 1px 24px rgba(10, 18, 40, 0.75);
}

.jh-syringe-eyebrow {
  margin: 0 0 0.75rem;
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: #e6bc56;
}

.jh-syringe-title {
  margin: 0 0 0.9rem;
  font-size: clamp(1.9rem, 4.6vw, 3.4rem);
  line-height: 1.08;
  font-weight: 400;
  color: #fff;
}

.jh-syringe-lede {
  margin: 0;
  font-size: clamp(0.98rem, 1.5vw, 1.12rem);
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.78);
}

/* The copy is the caption, the syringe the subject: while the 3D is
   running, the words wait for the syringe to land and then rise in, one
   line after another, as the gold unfurls. Hidden only under is-live, which
   the module adds before the section is on screen and takes away if
   anything fails — so without the 3D the copy is simply there. */
.jh-syringe.is-live .jh-syringe-copy > * {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.7s ease, transform 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}

.jh-syringe.is-landed .jh-syringe-copy > * {
  opacity: 1;
  transform: none;
}

.jh-syringe.is-landed .jh-syringe-copy > :nth-child(2) {
  transition-delay: 0.1s;
}

.jh-syringe.is-landed .jh-syringe-copy > :nth-child(3) {
  transition-delay: 0.2s;
}

.jh-syringe-cue {
  position: absolute;
  bottom: 1.5rem;
  left: 0;
  right: 0;
  margin: 0;
  text-align: center;
  font-size: 0.68rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.45);
  transition: opacity 0.4s ease;
}

.jh-syringe.is-past-start .jh-syringe-cue {
  opacity: 0;
}

/* Where the drop lands: a gold hairline along the bottom edge of the stage,
   opened out by the module from the point of impact (--jh-impact), and a
   ring spreading from the same point. Strongest where the drop fell and
   fading to nothing at both ends, like the hairlines round the gallery.
   It sits on the stage's bottom edge, so when the stage lets go it is the
   seam between this section and the results. */
.jh-syringe-seam,
.jh-syringe-ripple {
  position: absolute;
  bottom: 0;
  z-index: 3;
  pointer-events: none;
}

.jh-syringe-seam {
  left: 0;
  right: 0;
  height: 1px;
  background: linear-gradient(to right,
    rgba(230, 188, 86, 0) 0%,
    rgba(230, 188, 86, 0.9) var(--jh-impact, 50%),
    rgba(230, 188, 86, 0) 100%);
  transform: scaleX(0);
  transform-origin: var(--jh-impact, 50%) 50%;
}

.jh-syringe-ripple {
  left: var(--jh-impact, 50%);
  width: 180px;
  height: 40px;
  border: 1px solid rgba(230, 188, 86, 0.8);
  border-radius: 50%;
  opacity: 0;
  transform: translate(-50%, 50%) scale(0.2);
}

/* With the 3D running, the cue waits for the entrance to finish, and then
   only appears for someone who has stopped to watch: anyone still scrolling
   is past it before the delay runs out. */
.jh-syringe.is-live .jh-syringe-cue {
  opacity: 0;
  transition: opacity 0.3s ease;
}

.jh-syringe.is-settled:not(.is-past-start) .jh-syringe-cue {
  opacity: 1;
  transition: opacity 0.8s ease 0.6s;
}

/* Phones: the model is framed portrait, so give the copy the bottom third
   and let the render have the rest. */
@media (max-width: 760px) {
  .jh-syringe {
    height: 330vh;
  }

  /* There is no room beside the model on a phone, so it gets the top of the
     stage and the copy gets the bottom. Overlapping them put the headline
     straight through the barrel. The module frames the composition into
     the top 64% (PHONE_FRAME) but its canvas covers the whole stage, so
     the drop at the end can fall all the way to the bottom edge; the still
     goes where the composition is. */
  .jh-syringe-poster {
    height: 64%;
  }

  /* The waterfall runs the full height of the stage and, on a screen this
     narrow, behind the ends of the lines. So the copy sits on a soft pool of
     navy that lets the water show above and below it but not through the
     words, and keeps the shadow it has on desktop. The pool fades with the
     copy, since it belongs to it. */
  .jh-syringe-copy {
    justify-self: center;
    text-align: center;
    margin: 0 1.25rem clamp(2.5rem, 7vh, 4.5rem);
  }

  .jh-syringe-copy::before {
    content: '';
    position: absolute;
    inset: -2.5rem -1.25rem -1.75rem;
    z-index: -1;
    pointer-events: none;
    background: radial-gradient(ellipse closest-side at 50% 55%,
      rgba(35, 46, 81, 0.94) 0%,
      rgba(35, 46, 81, 0.82) 62%,
      rgba(35, 46, 81, 0) 100%);
  }
}

/* Someone who has asked for less motion gets the still and a normal-height
   section — no pinning, no scroll-linked rotation, no WebGL context. */
@media (prefers-reduced-motion: reduce) {
  .jh-syringe {
    height: auto;
  }

  .jh-syringe-stage {
    position: static;
    height: auto;
    min-height: 70vh;
    padding: clamp(2rem, 8vh, 5rem) 0;
  }

  .jh-syringe-canvas-wrap {
    position: relative;
    height: min(70vh, 620px);
  }

  .jh-syringe-canvas {
    display: none;
  }

  .jh-syringe-poster,
  .jh-syringe.is-live .jh-syringe-poster {
    height: 100%;
    opacity: 1;
    transition: none;
  }

  .jh-syringe-seam,
  .jh-syringe-ripple {
    display: none;
  }

  .jh-syringe-copy {
    margin-bottom: 0;
  }

  .jh-syringe-cue {
    display: none;
  }
}
