/* ═══════════════════════════════════════════════════════════
   TUNEX — SCROLL MORPH SHOWCASE
   Vanilla port of the 21st.dev "Scroll Morph Hero".

   Two deliberate changes from the original:

   1. The original hijacks the wheel — it calls preventDefault()
      on every wheel event inside the container and scrubs a
      virtual scroll value instead. One of those on a page is a
      strong choice; the page simply stops scrolling whenever
      the cursor is over it. Here the progress comes from the
      section's own position in the viewport instead, via a tall
      section with a sticky stage, so the page scrolls normally
      and the animation scrubs as a consequence.

   2. The original morphs 20 stock photographs whose flip side
      reads "View / Details". These tiles carry a service icon
      and its name, because on this site the copy is the point.

   Guardrails match the rest of the site: desktop + fine pointer
   only, off for prefers-reduced-motion, and parked while the
   section is off screen. In every disabled case the tiles fall
   back to a plain static grid, so the services still read.
   ═══════════════════════════════════════════════════════════ */

.mph-section {
  position: relative;
  background: var(--black, #080808);
  /* the scroll distance the morph is scrubbed across; the sticky
     stage below pins for this whole run */
  height: 300vh;
}

.mph-sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}

.mph-stage {
  position: relative;
  width: 100%;
  height: 100%;
  perspective: 1000px;
}

/* red bloom behind the ring, so the section reads as part of the
   lamp family rather than a bolted-on widget */
.mph-stage::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 760px;
  height: 760px;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle, rgba(196,30,58,.20), transparent 62%);
  pointer-events: none;
}

/* ── copy ────────────────────────────────────────────────── */

.mph-intro,
.mph-outro {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  width: min(680px, 88vw);
  text-align: center;
  pointer-events: none;
  z-index: 3;
}

.mph-intro { top: 50%; margin-top: -60px }
.mph-outro { top: 9%; opacity: 0 }

.mph-intro h2,
.mph-outro h2 {
  font-family: 'Bebas Neue', Impact, sans-serif;
  font-size: clamp(32px, 5vw, 60px);
  line-height: .98;
  color: #fff;
  margin: 0 0 14px;
}

.mph-intro h2 em,
.mph-outro h2 em { color: #ff3b57; font-style: normal }

.mph-intro p,
.mph-outro p {
  font-size: 14.5px;
  line-height: 1.75;
  color: rgba(255,255,255,.55);
  margin: 0 auto;
  max-width: 520px;
}

.mph-hint {
  margin-top: 18px;
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: rgba(255,255,255,.42);
}

/* ── tiles ───────────────────────────────────────────────── */

.mph-tiles {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.mph-tile {
  position: absolute;
  width: 78px;
  height: 98px;
  border-radius: 13px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 8px 6px;
  text-align: center;
  background: linear-gradient(160deg, #171717, #0d0d0d);
  border: 1px solid rgba(255,255,255,.11);
  box-shadow: 0 8px 22px rgba(0,0,0,.5);
  /* JS writes --x/--y/--r/--s every frame; keeping the transform in
     CSS means the compositor handles it and JS only touches vars */
  transform:
    translate3d(calc(var(--x, 0px) - 50%), calc(var(--y, 0px) - 50%), 0)
    rotate(var(--r, 0deg))
    scale(var(--s, 1));
  opacity: var(--o, 1);
  will-change: transform, opacity;
}

.mph-tile i { font-size: 21px; color: #ff3b57; line-height: 1 }

.mph-tile span {
  font-size: 8.5px;
  font-weight: 700;
  line-height: 1.28;
  letter-spacing: .2px;
  color: rgba(255,255,255,.82);
  /* two lines then clip; these tiles are 78px wide */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* the tile the arc has brought to centre */
.mph-tile.is-focus {
  border-color: rgba(196,30,58,.75);
  box-shadow: 0 12px 34px rgba(196,30,58,.4);
}

/* ── static fallback ─────────────────────────────────────────
   Used when the morph is off (reduced motion, coarse pointer,
   narrow viewport, or no JS). The section collapses to its
   content height and the tiles become an ordinary grid. */

.mph-section.is-static { height: auto; padding: 92px 24px 100px }
.mph-section.is-static .mph-sticky { position: static; height: auto; display: block }
.mph-section.is-static .mph-stage { height: auto; perspective: none }
.mph-section.is-static .mph-stage::before { display: none }

.mph-section.is-static .mph-intro,
.mph-section.is-static .mph-outro {
  position: static;
  transform: none;
  opacity: 1;
  margin: 0 auto 40px;
  width: auto;
}

.mph-section.is-static .mph-outro,
.mph-section.is-static .mph-hint { display: none }

.mph-section.is-static .mph-tiles {
  position: static;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 14px;
  max-width: 1080px;
  margin: 0 auto;
}

.mph-section.is-static .mph-tile {
  position: static;
  width: auto;
  height: auto;
  min-height: 104px;
  transform: none;
  opacity: 1;
  will-change: auto;
}

.mph-section.is-static .mph-tile span { font-size: 11px; -webkit-line-clamp: 3 }
.mph-section.is-static .mph-tile i { font-size: 24px }

@media (max-width: 700px) {
  .mph-section.is-static { padding: 68px 20px 76px }
  .mph-section.is-static .mph-tiles { grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)) }
}
