/* ============================================================
   SERAPHIN — hero exploded view (photographic)

   Ten transparent PNG layers cut from the product photograph,
   absolutely positioned so that at rest they reproduce the original
   shot exactly. Each layer then translates along a true assembly
   axis as --t goes 0 -> 1.

   Rigid translation only: no scale, rotate or skew, so parts stay
   intact and only their positions change.

   Contract:
     .xv          pinned container (tall, drives the scroll)
     .xv-stage    sticky viewport-height stage
     .xv-rig      square assembly box, 1:1, matching the source photo
     .xv-part     one photographic layer
     --dx --dy    travel at full explosion, % of the rig
     --t          0..1 progress, written by JS on .xv-stage
   ============================================================ */

.xv{
  position:relative;
  /* 0-36% explode, 36-64% hold, 64-100% reassemble.
     Generous runway so the separation reads slow and deliberate. */
  height:300vh;
  background:var(--bg);
}

.xv-stage{
  position:sticky;
  top:0;
  height:100svh;
  min-height:600px;
  overflow:hidden;
}

/* ---------- headline: over the product, recedes as it separates ---------- */
.xv-head{
  position:absolute;
  top:clamp(1.5rem,5vh,4rem);
  left:0;right:0;
  z-index:20;
  padding-inline:var(--bleed);
  max-width:var(--wrap);
  margin-inline:auto;
  pointer-events:none;
  opacity:clamp(.14, calc(1 - var(--t,0) * 1.3), 1);
  transition:opacity .2s linear;
}
.xv-head h2{
  font-size:clamp(2.4rem,6vw,5.2rem);
  line-height:.95;
  letter-spacing:-.035em;
  max-width:14ch;
}
.xv-head .lead{
  margin-top:clamp(1rem,2vh,1.6rem);
  font-size:clamp(.95rem,1.15vw,1.15rem);
  max-width:38ch;
}

/* ---------- canvas + rig ---------- */
.xv-canvas{
  position:absolute;
  inset:0;
  display:flex;
  align-items:center;
  justify-content:center;
  padding:clamp(10.5rem,27vh,17rem) var(--bleed) clamp(5.5rem,13vh,8.5rem);
}

/* The rig is square because the source photo is 800x800; every part's
   left/top/width is a percentage of it, so the whole assembly scales
   fluidly while staying in perfect register. */
.xv-rig{
  position:relative;
  width:min(100%, 76vh, 720px);
  aspect-ratio:1/1;
  display:flex;
  align-items:center;
  justify-content:center;
}

/* The product photograph, whole. It eases forward as the page scrolls —
   restrained, the way a product hero should behave. */
.xv-hero-shot{
  width:100%;
  height:auto;
  display:block;
  transform:scale(calc(1 + var(--t,0) * .11));
  transition:transform .14s linear;
  will-change:transform;
}

/* ---------- callouts ---------- */
.xv-note{
  position:absolute;
  z-index:30;
  font-family:var(--body);
  font-size:.7rem;
  font-weight:500;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--muted);
  white-space:nowrap;
  display:flex;
  align-items:center;
  gap:.6rem;
  /* each note has its own --at trigger point, so they arrive in sequence */
  opacity:clamp(0, calc((var(--t,0) - var(--at,0)) * 7), 1);
  transform:translateY(calc((1 - clamp(0, calc((var(--t,0) - var(--at,0)) * 7), 1)) * 8px));
  transition:opacity .2s linear, transform .2s ease-out;
  pointer-events:none;
}
.xv-note-r{flex-direction:row-reverse}
.xv-dot{
  width:5px;height:5px;
  background:var(--red);
  border-radius:50%;
  flex:none;
  box-shadow:0 0 0 4px rgba(237,28,36,.16);
}

/* ---------- progress rail ---------- */
.xv-rail{
  position:absolute;
  left:0;right:0;
  bottom:clamp(1.25rem,3.5vh,2.25rem);
  z-index:20;
  padding-inline:var(--bleed);
  max-width:var(--wrap);
  margin-inline:auto;
  pointer-events:none;
}
.xv-track{position:relative;height:1px;background:var(--line)}
.xv-fill{
  position:absolute;inset:0 auto 0 0;
  width:calc(var(--t,0) * 100%);
  background:var(--red);
  transition:width .12s linear;
}
.xv-steps{
  display:flex;justify-content:space-between;
  margin-top:.8rem;
  font-family:var(--display);
  font-size:.64rem;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;
  color:var(--muted);
}
.xv-steps span{transition:color .2s}
.xv-steps span[data-on="1"]{color:var(--red)}

@media (max-height:700px){
  .xv-head .lead{display:none}
  .xv-steps{font-size:.58rem}
}
@media (max-width:640px){
  .xv-note{font-size:.6rem;letter-spacing:.1em}
}

/* ---------- reduced motion / no JS ----------
   Render the separated state statically: the diagram is the point,
   the animation is the flourish. */
@media (prefers-reduced-motion:reduce){
  .xv{height:auto}
  .xv-stage{position:static;height:auto;min-height:0;padding:var(--gap-xl) 0}
  .xv-head{position:static;opacity:1;margin-bottom:var(--gap-lg)}
  .xv-canvas{position:static;display:block;padding:0 var(--bleed)}
  .xv-rig{width:min(100%,760px);margin-inline:auto}
  .xv-hero-shot{transform:none;transition:none}
  .xv-note{opacity:1}
  .xv-rail{display:none}
}

.no-js .xv{height:auto}
.no-js .xv-stage{position:static;height:auto;min-height:0;padding:var(--gap-xl) 0}
.no-js .xv-head{position:static;opacity:1;margin-bottom:var(--gap-lg)}
.no-js .xv-canvas{position:static;display:block;padding:0 var(--bleed)}
.no-js .xv-rig{width:min(100%,760px);margin-inline:auto}
.no-js .xv-hero-shot{transform:none}
.no-js .xv-note{opacity:1}
.no-js .xv-rail{display:none}
