/* Styles for the drag-to-spin viewer (spinner.js). Kept separate from the page
   so W4's real front end can adopt the component without inheriting the dev
   harness's look.

   Sizing lives on `.spinner-stage`, which the component creates, rather than on
   the caller's element: `background-size` is a percentage of the stage box, so
   any deviation between that box's aspect and the frame's aspect stretches
   every angle. Putting it on the caller's element would let a page rule like
   `#viewer { width: ... }` outrank the component and silently distort the
   product. The caller styles the outer `.spinner` freely; the stage stays in
   proportion. */

.spinner {
  /* Overridable budgets. --spinner-ar (unitless w/h) and --spinner-native-w are
     set from the manifest by spinner.js once it loads. */
  --spinner-max-h: 78vh;
  --spinner-ar: 0.75;
  --spinner-native-w: 100%;

  position: relative;
  display: flex;
  justify-content: center;
}

.spinner-stage {
  /* Constrain the WIDTH by the height budget and let aspect-ratio derive the
     height — `max-height` would clamp height while width stayed put, which is
     exactly the stretch this avoids. The last term stops the sprite being
     blown up past its own resolution, which only buys blur. */
  width: min(100%,
             calc(var(--spinner-max-h) * var(--spinner-ar)),
             var(--spinner-native-w));
  aspect-ratio: var(--spinner-ar);
  border-radius: 14px;
  overflow: hidden;
  background-color: #0d0d10;
  background-repeat: no-repeat;
  opacity: 0;
  transition: opacity 240ms ease;
  cursor: grab;
  /* Claim horizontal gestures so a sideways drag spins the object instead of
     scrolling the page on touch; vertical scroll still passes through. */
  touch-action: pan-y;
  -webkit-user-select: none;
  user-select: none;
  -webkit-user-drag: none;
}

/* The box is reserved before the sprite decodes, so the reveal doesn't shove
   the page around — a layout shift at the conversion moment reads as jank. */
.spinner.is-ready .spinner-stage { opacity: 1; }
.spinner.is-dragging .spinner-stage { cursor: grabbing; }

.spinner-stage:focus-visible {
  outline: 2px solid #7aa2ff;
  outline-offset: -2px;
}

.spinner-hint {
  position: absolute;
  left: 50%;
  bottom: 12px;
  transform: translateX(-50%);
  padding: 6px 12px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  font: 500 13px/1 system-ui, -apple-system, sans-serif;
  letter-spacing: 0.02em;
  pointer-events: none;
  opacity: 0;
  transition: opacity 300ms ease;
}

.spinner.is-ready .spinner-hint { opacity: 1; }
.spinner-hint.is-hidden { opacity: 0; }

.spinner.is-error::after {
  content: "preview unavailable";
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: #8a8a94;
  font: 400 14px/1 system-ui, -apple-system, sans-serif;
}

@media (prefers-reduced-motion: reduce) {
  .spinner-stage { transition: none; }
}
