/* ==========================================================================
   product-spin.css — 360 spin canvas, progress, custom cursor
   Split out of the original components.css; load order is preserved
   exactly, because several rules here depend on source order.
   ========================================================================== */

/* ---- Product spin (360° drag) ----
   The canvas fills its mount; `touch-action: none` is essential or the browser
   claims horizontal drags for scrolling before the pointer handlers ever see
   them. Cursor communicates the affordance. */
.product-spin {
  position: relative;
  /* Scales the product inside the canvas (read by product-spin.js). Applied at
     draw time rather than as a CSS transform, so enlarging stays sharp.
     Calibrated for the tightly-cropped 820x700 frames — keeps the product the
     same on-screen size it was at 1.5 with the old padded 1000px frames. */
  --spin-zoom: 0.51;
  touch-action: none;
  /* The native pointer is replaced by .spin-cursor while over this zone. */
  cursor: none;
  user-select: none;
  -webkit-user-select: none;
}

/* ---- Hero spin cursor (Figma 1507:70) ----
   Frosted pill + horizontal-scroll glyph, following the pointer. Fixed so it
   tracks viewport coordinates, and pointer-events:none so it never eats the
   move events that drive the spin. */
.spin-cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  padding: 12px 16px;
  border-radius: 40px;
  background: rgba(121, 121, 121, 0.32);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.25s var(--ease);
  will-change: transform;
}
.spin-cursor.is-visible { opacity: 1; }
.spin-cursor img { width: 24px; height: 24px; }

@media (hover: none), (pointer: coarse) {
  .spin-cursor { display: none; }
  .product-spin { cursor: default; }
}

.product-spin-canvas {
  display: block;
  width: 100%;
  height: 100%;
  /* Fades up once every frame is decoded, so the first paint isn't a flicker
     of half-loaded frames. */
  opacity: 0;
  transition: opacity 0.5s var(--ease);
}
.product-spin.is-ready .product-spin-canvas { opacity: 1; }

/* Slim determinate progress bar while the sequence preloads */
.product-spin-progress {
  position: absolute;
  left: 50%;
  bottom: 18%;
  transform: translateX(-50%);
  width: 132px;
  height: 2px;
  border-radius: 2px;
  background: rgba(12, 12, 12, 0.12);
  overflow: hidden;
  transition: opacity 0.4s var(--ease);
}
.product-spin.is-ready .product-spin-progress {
  opacity: 0;
  pointer-events: none;
}
.product-spin-bar {
  display: block;
  width: 0%;
  height: 100%;
  background: var(--ink);
  transition: width 0.2s linear;
}
