/* ═══════════════════════════════════════════════════════════
   TUNEX SERVICES — 3D CAROUSEL
   Port of the "ThreeDPhotoCarousel" pattern to vanilla CSS/JS.

   Only the demo file was supplied, so the mechanic is rebuilt
   from the known pattern: a cylinder of cards you can spin.
   The original is a PHOTO carousel; Tunex services are icon +
   copy, so the cards carry the brand's card treatment instead
   of imagery.

   All 24 services sit on one ring at 360/24 = 15° apart.
   The idle spin is a plain CSS animation on an inner element
   and drag is a custom property on an outer one, so the two
   compose without JavaScript driving every frame.
   ═══════════════════════════════════════════════════════════ */

.svc3d-section {
  background: var(--off);
  padding: 96px 56px 80px;
  border-top: 1.5px solid var(--border);
  overflow: hidden;
}

.svc3d-head {
  text-align: center;
  max-width: 640px;
  margin: 0 auto;
}
.svc3d-sub {
  margin-top: 14px;
  font-size: 14px;
  line-height: 1.75;
  color: var(--muted);
}

/* ── STAGE ─────────────────────────────────────────────── */

.svc3d-stage {
  /* radius must clear the cards: (cw / 2) / tan(step / 2) */
  --svc3d-radius: 950px;
  --svc3d-step: 15deg;
  --svc3d-cw: 240px;
  --svc3d-ch: 232px;
  /* how far the ring is parked behind the screen plane, as a share of the
     radius. 1 = front card dead flat; less than 1 keeps some magnification
     so the curve still reads as a curve. */
  --svc3d-push: 0.8;

  position: relative;
  height: 400px;
  margin-top: 44px;
  perspective: 1600px;
  cursor: grab;
  touch-action: pan-y;
}
.svc3d-section.is-dragging .svc3d-stage {
  cursor: grabbing;
}

/* Atmosphere: a soft spectral halo behind the ring, so the cards read as
   orbiting something rather than floating on flat paper. */
.svc3d-stage::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 52%;
  width: min(780px, 84%);
  height: 300px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: conic-gradient(
    from 0deg,
    hsl(0 70% 60% / 0.18),
    hsl(60 70% 60% / 0.18),
    hsl(120 70% 60% / 0.18),
    hsl(180 70% 60% / 0.18),
    hsl(240 70% 60% / 0.18),
    hsl(300 70% 60% / 0.18),
    hsl(360 70% 60% / 0.18)
  );
  filter: blur(64px);
  opacity: 0.85;
  pointer-events: none;
  z-index: 0;
}

/* Outer: user drag — and it pushes the whole ring back by exactly its own
   radius. Without that the front cards sit at z = +radius, right against the
   camera: at perspective 1400 / radius 720 they magnify 2.06x and a 190px
   card lands on screen at nearly 400px. Parking the ring's centre at
   z = -radius puts the front card back on the screen plane at natural size
   while the far side still recedes. */
.svc3d-drag {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  /* rotateX tips the orbit so the ring is seen slightly from above: the path
     becomes an ellipse and cards rise and fall as they come round, which is
     what sells "planet turning" rather than "row of cards sliding". The tilt
     is on X only — a Z tilt would be a truer axial tilt but it slants every
     card's text, and these cards have to stay readable. */
  transform: rotateX(8deg)
    translateZ(calc(var(--svc3d-radius) * var(--svc3d-push) * -1))
    rotateY(var(--drag, 0deg));
}

/* inner: idle spin, pure CSS so no rAF loop is needed */
.svc3d-spin {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  animation: svc3d-orbit 90s linear infinite;
}

@keyframes svc3d-orbit {
  from {
    transform: rotateY(0deg);
  }
  to {
    transform: rotateY(-360deg);
  }
}

/* stop the ring whenever someone is actually trying to read it */
.svc3d-stage:hover .svc3d-spin,
.svc3d-section.is-dragging .svc3d-spin,
.svc3d-section.has-selection .svc3d-spin {
  animation-play-state: paused;
}

/* ── CARD ──────────────────────────────────────────────── */

/* Position on the ring drives the hue, so the spectrum turns with the ring.
   30deg per card, not 15: only about seven cards are on screen at once, and
   at 15deg that slice spans a mere quarter of the wheel — it just looks
   red-ish. At 30deg the spectrum wraps twice around the ring and every
   visible arc carries a full rainbow.
   Cards stay white with dark copy; the hue only drives accents, which keeps
   24 different colours legible instead of garish. */
.svc3d-card {
  --hue: calc(var(--i) * 30);
  --accent: hsl(var(--hue) 72% 52%);
  --accent-soft: hsl(var(--hue) 80% 96%);
  --accent-ink: hsl(var(--hue) 65% 42%);

  position: absolute;
  left: 50%;
  top: 50%;
  overflow: hidden;
  width: var(--svc3d-cw);
  height: var(--svc3d-ch);
  margin-left: calc(var(--svc3d-cw) / -2);
  margin-top: calc(var(--svc3d-ch) / -2);

  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 20px 18px;
  text-align: left;

  background: var(--w);
  border: 1.5px solid var(--border);
  border-radius: 12px;
  font-family: 'Inter', sans-serif;
  cursor: pointer;

  transform: rotateY(calc(var(--i) * var(--svc3d-step)))
    translateZ(var(--svc3d-radius));
  /* the far half of the ring would otherwise show mirrored text */
  backface-visibility: hidden;
  transition: border-color 0.25s var(--ease), box-shadow 0.25s var(--ease);
}

/* the hue's signature stripe across the top of each card */
.svc3d-card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background: linear-gradient(
    90deg,
    var(--accent),
    hsl(calc(var(--hue) + 34) 78% 58%)
  );
}

.svc3d-card:hover,
.svc3d-card:focus-visible {
  border-color: var(--accent);
  box-shadow: 0 14px 40px hsl(var(--hue) 60% 45% / 0.22);
}
.svc3d-card:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}
.svc3d-card.is-active {
  border-color: var(--accent);
  box-shadow: 0 18px 50px hsl(var(--hue) 65% 45% / 0.32);
}

.svc3d-cat {
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--accent-ink);
}

.svc3d-icon {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: 10px;
  background: var(--accent-soft);
}
.svc3d-icon i {
  font-size: 22px;
  color: var(--accent-ink);
}

.svc3d-name {
  font-size: 15px;
  font-weight: 700;
  line-height: 1.35;
  color: var(--b);
}

/* The bigger cards have room for a taste of the copy, so the ring carries
   real information rather than just larger empty boxes. */
/* Not -webkit-line-clamp: the card is a flex column, and a flex item's display
   is blockified, so `display: -webkit-box` never survives and the clamp is
   silently ignored. A fixed three-line box with a fade-out mask does the same
   job and does not depend on that legacy display value. */
.svc3d-desc {
  flex: none;
  height: calc(1.6em * 3);
  overflow: hidden;
  font-size: 12px;
  line-height: 1.6;
  color: var(--muted);
  -webkit-mask-image: linear-gradient(to bottom, #000 62%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 62%, transparent 100%);
}

/* Kept in the DOM (crawlable, and the detail panel reads from it) but not
   drawn on the ring, where there is no room for it. */
.svc3d-tags {
  display: none;
}

/* ── DETAIL PANEL ──────────────────────────────────────── */

/* JS copies the selected card's --hue here so the panel stays tied to the
   card you picked. Falls back to the brand red before anything is selected. */
.svc3d-detail {
  --accent: hsl(var(--hue, 350) 72% 52%);
  --accent-ink: hsl(var(--hue, 350) 65% 42%);

  position: relative;
  max-width: 720px;
  margin: 36px auto 0;
  padding: 26px 28px;
  background: var(--w);
  border: 1.5px solid var(--border);
  border-left: 4px solid var(--accent);
  border-radius: 14px;
  text-align: left;
  min-height: 150px;
  transition: border-color 0.35s var(--ease);
}
.svc3d-detail-cat {
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--accent-ink);
  transition: color 0.35s var(--ease);
}
.svc3d-detail-name {
  font-family: 'Bebas Neue', cursive, sans-serif;
  font-size: 30px;
  line-height: 1.05;
  letter-spacing: -0.5px;
  color: var(--b);
  margin: 8px 0 10px;
}
.svc3d-detail-desc {
  font-size: 14px;
  line-height: 1.8;
  color: var(--muted);
}
.svc3d-detail-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  margin-top: 14px;
}
.svc3d-detail-tags span {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--b);
  background: var(--off);
  border: 1px solid var(--border);
  border-radius: 100px;
  padding: 5px 11px;
}

.svc3d-hint {
  margin-top: 18px;
  text-align: center;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--muted);
}
.svc3d-hint i {
  color: var(--r);
}

/* ── STATIC FALLBACK ───────────────────────────────────── */

/* A cylinder you spin with a mouse has no touch equivalent, and a 720px
   radius cannot shrink to a phone without the cards colliding. Below the
   tablet breakpoint the same 24 cards become a plain grid — no 3D, no
   spin, every service visible at once. */
@media (max-width: 900px) {
  .svc3d-section {
    padding: 72px 24px 64px;
  }
  .svc3d-stage {
    height: auto;
    margin-top: 32px;
    perspective: none;
    cursor: auto;
  }
  .svc3d-drag,
  .svc3d-spin {
    position: static;
    transform: none;
    transform-style: flat;
    animation: none;
  }
  .svc3d-stage::before {
    display: none;
  }
  .svc3d-spin {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: 14px;
  }
  .svc3d-card {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    transform: none;
    backface-visibility: visible;
  }
  /* no ring to keep tidy here, so show the whole description */
  .svc3d-desc {
    height: auto;
    overflow: visible;
    font-size: 12.5px;
    -webkit-mask-image: none;
    mask-image: none;
  }
  .svc3d-detail,
  .svc3d-hint {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .svc3d-spin {
    animation: none;
  }
  .svc3d-card {
    transition: none;
  }
}
