/* ============================================================
   Depth: the content itself is physical. Cards and media rise out of the
   world's depth as they scroll in, tilt toward a fine pointer and catch a
   moving light. Driven by js/animations/depth.js.

   Everything here is scoped by html.has-depth (added by the module only when
   motion is allowed) and html.has-depth-pointer (fine pointer, no low power).
   Without the class the sheet is inert: reduced motion, no JS, or a failed
   module all leave the page exactly as the other stylesheets render it.

   Transforms are composed from unitless custom properties so two drivers can
   share one element without fighting over `transform`:
     --dz   translateZ in px (scroll)        --rx  rotateX in deg (scroll)
     --op   opacity (scroll)                  --py  translateY in px / % (scroll)
     --tx   rotateX in deg (pointer)          --ty  rotateY in deg (pointer)
     --mx   light x in %  (pointer)           --my  light y in % (pointer)
     --sheen light opacity (pointer)          --sweep / --sweep-o edge light (scroll)
   At rest every value is 0 (or 1 for opacity): the element is flat and solid.
   ============================================================ */

/* ---------- moments: three media tiles after the live chapter ---------- */
.has-depth .moments { perspective: 1100px; perspective-origin: 50% 40%; }
.has-depth .moments__item { transform-style: preserve-3d; }
.has-depth .moments .moments__media {
  --dz: 0; --rx: 0; --op: 1; --tx: 0; --ty: 0;
  transform: translateZ(calc(var(--dz) * 1px)) rotateX(calc((var(--rx) + var(--tx)) * 1deg)) rotateY(calc(var(--ty) * 1deg));
  transform-origin: 50% 100%;
  opacity: var(--op);
  backface-visibility: hidden;
  will-change: transform, opacity;
}

/* ---------- about: the two casual photographs are objects behind their frames ---------- */
.has-depth .about__photo { isolation: isolate; }
.has-depth .about__photo img {
  --py: 0; --ry: 0;
  /* the figure is parallaxed by reveals.js and clips with overflow:hidden, so the
     image carries its own perspective; scale leaves bleed for the parallax travel */
  transform: perspective(900px) translate3d(0, calc(var(--py) * 1%), 0) rotateY(calc(var(--ry) * 1deg)) scale(1.16);
  transform-origin: 50% 50%;
  backface-visibility: hidden;
  will-change: transform;
}

/* ---------- songs: each row rises from depth with a magenta edge light ---------- */
.has-depth .songs { perspective: 1200px; }
.has-depth .songs .song {
  --dz: 0; --rx: 0; --op: 1; --tx: 0; --ty: 0; --mx: 50; --my: 50; --sheen: 0; --sweep: 0; --sweep-o: 0;
  position: relative;
  transform: translateZ(calc(var(--dz) * 1px)) rotateX(calc((var(--rx) + var(--tx)) * 1deg)) rotateY(calc(var(--ty) * 1deg));
  transform-origin: 50% 50%;
  opacity: var(--op);
  transition: background-color .4s;
  backface-visibility: hidden;
  will-change: transform, opacity;
}
/* the edge light: a thin magenta line with a soft halo, travelling along the row's
   bottom edge from the reading start to the reading end as the row rises */
.has-depth .songs .song::after {
  content: "";
  position: absolute;
  bottom: -8px;
  height: 16px;
  width: 34%;
  inset-inline-start: calc(var(--sweep) * 66%);
  pointer-events: none;
  opacity: var(--sweep-o);
  background:
    linear-gradient(90deg, rgba(255, 143, 187, 0) 0%, #ff8fbb 50%, rgba(255, 143, 187, 0) 100%) 50% 50% / 100% 1px no-repeat,
    radial-gradient(50% 50% at 50% 50%, rgba(255, 143, 187, .45) 0%, rgba(255, 143, 187, 0) 70%);
}

/* ---------- contact: action cards and the booking panel ---------- */
.has-depth .contact__actions { perspective: 1000px; }
.has-depth .contact__inner { perspective: 1400px; }
/* the <li> is the depth host: the .caction inside is moved inline by magnetic.js,
   so the rise and the tilt live one level up and the card keeps its own motion.
   The .rv fade-up on this node is replaced by the rise (same intent, now in 3D). */
.has-depth .contact__actions > li {
  --dz: 0; --rx: 0; --op: 1; --tx: 0; --ty: 0; --mx: 50; --my: 50; --sheen: 0;
  transform: translateZ(calc(var(--dz) * 1px)) rotateX(calc((var(--rx) + var(--tx)) * 1deg)) rotateY(calc(var(--ty) * 1deg));
  transform-origin: 50% 50%;
  opacity: var(--op);
  transition: none;
  backface-visibility: hidden;
  will-change: transform, opacity;
}
.has-depth .contact__actions .caction { position: relative; }
.has-depth .contact .bform {
  --dz: 0; --rx: 0; --op: 1; --tx: 0; --ty: 0; --mx: 50; --my: 50; --sheen: 0;
  transform: translateZ(calc(var(--dz) * 1px)) rotateX(calc((var(--rx) + var(--tx)) * 1deg)) rotateY(calc(var(--ty) * 1deg));
  transform-origin: 50% 50%;
  opacity: var(--op);
  transition: none;
  backface-visibility: hidden;
  will-change: transform, opacity;
}

/* ---------- quotes dots and footer: depth parallax only ---------- */
.has-depth .quotes__dots {
  --py: 0;
  transform: translateX(-50%) translateY(calc(var(--py) * 1px));
  will-change: transform;
}
.has-depth .footer { perspective: 1200px; }
.has-depth .footer__inner {
  --dz: 0; --py: 0;
  transform: translateZ(calc(var(--dz) * 1px)) translateY(calc(var(--py) * 1px));
  transform-origin: 50% 100%;
  will-change: transform;
}

/* ---------- the moving light (fine pointer only) ----------
   A pink specular sheen follows the pointer over the tilted surface. Each host sets
   --mx / --my / --sheen; the pseudo-element on the clipped card reads them (custom
   properties inherit), so the light is cut by the card's own radius. */
.has-depth-pointer .moments .moments__media::before,
.has-depth-pointer .songs .song::before,
.has-depth-pointer .contact__actions .caction::after,
.has-depth-pointer .contact .bform::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  border-radius: inherit;
  pointer-events: none;
  opacity: var(--sheen);
  transition: opacity .5s var(--ease-soft);
  background: radial-gradient(200px circle at calc(var(--mx) * 1%) calc(var(--my) * 1%), rgba(255, 143, 187, .20) 0%, rgba(255, 143, 187, .06) 42%, rgba(255, 143, 187, 0) 70%);
}
.has-depth-pointer .songs .song::before {
  background: radial-gradient(320px circle at calc(var(--mx) * 1%) calc(var(--my) * 1%), rgba(255, 143, 187, .09) 0%, rgba(255, 143, 187, 0) 70%);
}
.has-depth-pointer .contact .bform::after {
  background: radial-gradient(420px circle at calc(var(--mx) * 1%) calc(var(--my) * 1%), rgba(255, 143, 187, .12) 0%, rgba(255, 143, 187, .03) 45%, rgba(255, 143, 187, 0) 70%);
}

/* ---------- safety net: if the OS setting flips mid-visit, everything is flat and solid ---------- */
@media (prefers-reduced-motion: reduce) {
  .has-depth .moments .moments__media, .has-depth .about__photo img, .has-depth .songs .song,
  .has-depth .contact__actions > li, .has-depth .contact .bform, .has-depth .quotes__dots, .has-depth .footer__inner {
    transform: none !important; opacity: 1 !important; will-change: auto;
  }
  .has-depth .quotes__dots { transform: translateX(-50%) !important; }
  .has-depth .songs .song::after, .has-depth-pointer .moments .moments__media::before, .has-depth-pointer .songs .song::before,
  .has-depth-pointer .contact__actions .caction::after, .has-depth-pointer .contact .bform::after { display: none; }
}
