/* ============================================================
   visualizer.css — all styles for the /visualizer page.
   Loaded from Views/layouts/visualizer.php alongside Tailwind.
============================================================ */

:root {
  /* Mannequin is fixed-size — resizing the window must not move or scale any element.
     Values are locked at the design-canvas maximums (400 × 775 px).
     To shift or rescale the whole layout, edit these two variables only. */
  --mannequin-w: 400px;
  --mannequin-h: 775px;
  /* Fixed vertical offset (was mannequin-h×0.21 − 14vh; frozen at 900 px ref height). */
  --viz-v-center: 37px;
  /* Global vertical nudge (vh). Adjust in the debug panel to align content across screen sizes. */
  --viz-offset-vh: 6.5;
  /* Independent vertical nudge (vh) for the sides strip carousel only. */
  --viz-strip-offset-vh: 9;
  /* Horizontal spacing between strip items. Smaller = columns closer together. */
  --strip-item-w: calc(var(--mannequin-w) * 0.62);
  --ease-smooth: cubic-bezier(.22, .61, .36, 1);
  /* ── CENTER (active/worn) — position & scale knobs ── */
  --pos-head-y:     12.5;
  --pos-full-y:     27;
  --pos-pants-y:    48;
  --pos-bags-y:     31.5;
  --pos-bags-x:     7;
  --pos-shirts-y:   51;
  --pos-hoodies-y: -31;
  --pos-tops-y:     51;
  --scale-caps:     0.72;
  --scale-shirts:   0.66;
  --scale-hoodies:  1.02;
  --scale-tops:     0.66;
  --scale-dresses:  0.69;
  --scale-pants:    0.6;
  --scale-bags:     0.7;
  /* ── SIDES (strip carousel items) — position & scale knobs ── */
  --strip-pos-caps-y:     27;
  --strip-pos-shirts-y:    0;
  --strip-pos-hoodies-y:  -42;
  --strip-pos-tops-y:      0;
  --strip-pos-dresses-y:   0;
  --strip-pos-pants-y:    -48;
  --strip-pos-bags-x:      10;
  --strip-pos-bags-y:     -22;
  --strip-scale-caps:     0.79;
  --strip-scale-shirts:   0.875;
  --strip-scale-hoodies:  1.25;
  --strip-scale-tops:     0.875;
  --strip-scale-dresses:  1.19;
  --strip-scale-pants:    0.75;
  --strip-scale-bags:     0.82;
}
/* Mannequin zones: head (caps/hoods), upper (shirts etc), full (dresses), pants, bags (side). */
html {
  height: 100%;
  background: var(--bg, #8c75ff);
}
body {
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
  background: var(--bg, #8c75ff);
  color: #f4f4f4;
}
body::before {
  content: '';
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.68' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)'/%3E%3C/svg%3E"),
    radial-gradient(ellipse at 100% 0%, rgba(254,134,244,0.28) 0%, transparent 62%);
  background-repeat: repeat, no-repeat;
  background-size: 180px 180px, 100% 100%;
  mix-blend-mode: overlay;
  opacity: 0.45;
}

/* Mannequin — centered in stage, fluid */
.person {
  position: absolute;
  left: 50%;
  top: calc(50% + var(--viz-v-center) + var(--viz-offset-vh, 0) * 1vh);
  transform: translate(-50%, -50%);
  width: var(--mannequin-w);
  height: var(--mannequin-h);
  z-index: 3;
  pointer-events: none;
}
.person > svg { display: none; }

.slot {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  pointer-events: none;
  opacity: 1;
  overflow: hidden;
  transition: opacity .45s var(--ease-smooth);
  will-change: opacity;
}
.slot-head    { top: calc(var(--pos-head-y,  3)  * 1%); height: 31.7%; z-index: 10; }
.slot-upper   { top: 16%;  height: 62%;   z-index: 2; overflow: visible; }
.slot-full    { top: calc(var(--pos-full-y,  16) * 1%); height: 64%;   z-index: 2; }
.slot-pants   { top: calc(var(--pos-pants-y, 50) * 1%); height: 46%;   z-index: 1; }
/* Bag slot: ~1/3 area of shirt slot, shifted left so shirts stay clickable */
.slot-bags {
  left: calc(var(--pos-bags-x, -2) * 1%);
  transform: none;
  right: auto;
  width: 48%;
  top: calc(var(--pos-bags-y, 25) * 1%);
  height: 28%;
  z-index: 15;
}

.slot.faded { opacity: 0; }
.slot.faded .worn.active { pointer-events: none; }

.worn {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity .4s var(--ease-smooth);
  pointer-events: none;
  will-change: opacity;
}
.worn.active { opacity: 1; pointer-events: auto; cursor: pointer; }
.worn svg { width: 100%; height: 100%; transition: filter .25s ease; }
.worn.active:hover svg { filter: brightness(1.12); }
.worn.active.js-hi .product-img { filter: brightness(1.12); }

/* Strips */
.strip {
  position: absolute;
  left: 0;
  right: 0;
  display: flex;
  gap: 0;
  /* Horizontal gutter so every strip (even short ones like bottoms with
     only 3 items) has enough scroll range to center any item under the
     mannequin. Without this, the browser clamps scrollLeft to 0 and the
     column ends up offset from tops/caps. */
  padding: 0 50vw;
  box-sizing: border-box;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  -ms-overflow-style: none;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-x;
  overscroll-behavior-x: none;
  z-index: 2;
  cursor: pointer;
  transition: opacity .45s var(--ease-smooth);
  will-change: scroll-position;
}
.strip::-webkit-scrollbar { display: none; }

.strip-bottoms {
  top: calc(50% + var(--viz-v-center) + var(--viz-offset-vh, 0) * 1vh + var(--viz-strip-offset-vh, 0) * 1vh - var(--mannequin-h) / 2 + var(--mannequin-h) * 0.16);
  height: calc(var(--mannequin-h) * 0.62);
}
.strip-pants {
  top: calc(50% + var(--viz-v-center) + var(--viz-offset-vh, 0) * 1vh + var(--viz-strip-offset-vh, 0) * 1vh - var(--mannequin-h) / 2 + var(--mannequin-h) * 0.39 + var(--strip-pos-pants-y, 0) * 1px);
  height: calc(var(--mannequin-h) * 0.54);
  z-index: 3;
}
.strip-bags {
  top: calc(50% + var(--viz-v-center) + var(--viz-offset-vh, 0) * 1vh + var(--viz-strip-offset-vh, 0) * 1vh - var(--mannequin-h) / 2 + var(--mannequin-h) * 0.25);
  height: calc(var(--mannequin-h) * 0.28);
  z-index: 6;
  opacity: 0.75;
  /* Align ghost items with the worn bag slot (left: -2%, width: 48% → centre at ~22% from
     mannequin left edge = 50vw - 0.28 × mannequin-w from screen centre) */
  transform: translateX(calc(-0.28 * var(--mannequin-w)));
}
/* Scale bag ghost items down to match the smaller worn slot */
.strip-bags .item svg,
.strip-bags .item .product-img {
  transform: translateX(calc(var(--strip-pos-bags-x, 0) * 1px)) translateY(calc(var(--strip-pos-bags-y, 0) * 1px)) scale(var(--strip-scale-bags, 0.7));
  transform-origin: top center;
}
/* Bags strip: positioned left of mannequin, synced with bottoms scroll */
.strip-tops {
  top: calc(50% + var(--viz-v-center) + var(--viz-offset-vh, 0) * 1vh + var(--viz-strip-offset-vh, 0) * 1vh - var(--mannequin-h) / 2 - var(--mannequin-h) * 0.03 + 54px);
  height: calc(var(--mannequin-h) * 0.317);
  z-index: 4;
}

.strip .item {
  flex: 0 0 var(--strip-item-w);
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: visible;
  /* Allow images to spill left/right (hoodie arms) but not vertically (would bleed into adjacent strips) */
  clip-path: inset(0 -50vw);
  opacity: 0;
  transform: scale(0.86) translateZ(0);
  /* Anchor scaling to the top so cap (tops strip) and shirt (bottoms strip)
     both pin to their strip's top edge — keeps the gap between them fixed
     at every scale level instead of drifting as items shrink from center. */
  transform-origin: top center;
  transition: opacity .45s var(--ease-smooth),
              transform .45s var(--ease-smooth);
  /* pointer-events on the div disabled — SVG (visiblePainted) and img handle
     hit-testing directly; events bubble to .strip for wheel/drag/click. */
  pointer-events: none;
  will-change: transform, opacity;
}
.strip .item.center { opacity: 0; pointer-events: none; }
.strip .item.near-1 { opacity: 0.55; transform: scale(0.77) translateZ(0); }
.strip .item.near-2 { opacity: 0.28; transform: scale(0.77) translateZ(0); }
.strip .item.near-3 { opacity: 0.12; transform: scale(0.77) translateZ(0); }
/* Hover: target parent .item via :has() so the parent opacity (not just child) goes to 1.
   SVG items fill their box 1:1 so native CSS hover is pixel-accurate.
   PNG items use object-fit:contain and have transparent dead zones below/beside the image;
   their hover state is managed by the JS mousemove handler (pixel-perfect content-rect
   hit test) which sets inline opacity directly on the .item element. */
.strip .item.near-1:has(svg:hover),
.strip .item.near-2:has(svg:hover),
.strip .item.near-3:has(svg:hover) { opacity: 1; }

/* Bags strip items follow the same near-opacity rules as other strips */
.strip .item svg,
.strip .item .product-img { width: 100%; height: 100%; display: block; object-fit: contain; object-position: top center; }

/* Strip product images: auto pointer-events so events reach the strip
   via bubbling (needed for click-to-navigate); native drag still blocked. */
.strip .item .product-img {
  pointer-events: auto;
  cursor: pointer;
  user-select: none;
  -webkit-user-drag: none;
  -webkit-touch-callout: none;
}

/* Strip item scales — independent from the worn (center) values */
.strip .item[data-cat="caps"]        .product-img,
.strip .item[data-cat="hoods"]       .product-img {
  transform: translateY(calc(var(--strip-pos-caps-y, 0) * 1px)) scale(var(--strip-scale-caps, 1));
  transform-origin: top center;
}
.strip .item[data-cat="hoodies"]     .product-img,
.strip .item[data-cat="sweaters"]    .product-img,
.strip .item[data-cat="longsleeves"] .product-img {
  transform: translateY(calc(var(--strip-pos-hoodies-y, 0) * 1px)) scale(var(--strip-scale-hoodies, 1.25));
  transform-origin: top center;
}
.strip .item[data-cat="tops"] .product-img {
  transform: translateY(calc(var(--strip-pos-tops-y, 0) * 1px)) scale(var(--strip-scale-tops, 1.25));
  transform-origin: top center;
}
.strip .item[data-cat="dresses"]     .product-img,
.strip .item[data-cat="cutoutsets"]  .product-img {
  transform: translateY(calc(var(--strip-pos-dresses-y, 0) * 1px)) scale(var(--strip-scale-dresses, 1.25));
  transform-origin: top center;
}
.strip .item[data-cat="tshirts"] .product-img {
  transform: translateY(calc(var(--strip-pos-shirts-y, 0) * 1px)) scale(var(--strip-scale-shirts, 0.875));
  transform-origin: top center;
}
.strip .item[data-cat="pants"] .product-img {
  transform: scale(var(--strip-scale-pants, 0.75));
  transform-origin: top center;
}

.worn .product-img { width: 100%; height: 100%; display: block; object-fit: contain; object-position: top center; pointer-events: none; user-select: none; -webkit-user-drag: none; transition: filter .25s ease; }
/* Per-category scale + Y offset on worn (on-model) images */
.worn[data-cat="caps"]  .product-img,
.worn[data-cat="hoods"] .product-img {
  transform: scale(var(--scale-caps, 1));
  transform-origin: top center;
}
.worn[data-cat="longsleeves"] .product-img,
.worn[data-cat="hoodies"]     .product-img,
.worn[data-cat="sweaters"]    .product-img {
  transform: translateY(calc(var(--pos-hoodies-y, 0) * 1px)) scale(var(--scale-hoodies, 1.25));
  transform-origin: top center;
}
.worn[data-cat="tops"] .product-img {
  transform: translateY(calc(var(--pos-tops-y, 0) * 1px)) scale(var(--scale-tops, 1.02));
  transform-origin: top center;
}
.worn[data-cat="dresses"]    .product-img,
.worn[data-cat="cutoutsets"] .product-img {
  transform: scale(var(--scale-dresses, 1.25));
  transform-origin: top center;
}
.worn[data-cat="tshirts"] .product-img {
  transform: translateY(calc(var(--pos-shirts-y, 0) * 1px)) scale(var(--scale-shirts, 0.875));
  transform-origin: top center;
}
.worn[data-cat="pants"] .product-img {
  transform: scale(var(--scale-pants, 0.78));
  transform-origin: top center;
}
/* Bags strip ghost scale */
.strip-bags .item svg,
.strip-bags .item .product-img {
  transform: translateY(calc(var(--strip-pos-bags-y, 0) * 1px)) scale(var(--strip-scale-bags, 0.7));
  transform-origin: top center;
}
.worn.active:hover .product-img { filter: brightness(1.12); }

/* ── Drag-to-browse hint (laptop/desktop only) ───────────────────── */
/* Same pill styling as .pp-buy-btn--inv (the "Sort" button): solid
   purple/pink pill, bold uppercase, no border. */
#viz-swipe-hint {
  display: none;
  position: fixed;
  left: 1.5rem;
  /* Matches .footer-actions's own padding-bottom (2.25rem) at this same
     min-width:1024px breakpoint, so this sits level with Sort/Buy Combo
     instead of ~12px lower. */
  bottom: 2.25rem;
  z-index: 40;
  align-items: center;
  gap: 0.5rem;
  padding: 10px 20px;
  font-weight: 700;
  font-size: 13px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ca, #fe86f4);
  background: var(--cp, #8c75ff);
  border: none;
  border-radius: 999px;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  animation: viz-swipe-hint-in 0.6s ease 1.2s forwards;
  transition: opacity 0.4s ease;
}
#viz-swipe-hint.is-hidden { opacity: 0 !important; }
@media (min-width: 1024px) {
  #viz-swipe-hint { display: flex; }
}
.viz-swipe-hint__arrow {
  display: inline-block;
  font-size: 15px;
  line-height: 1;
}
.viz-swipe-hint__arrow--left  { animation: viz-swipe-nudge-left  1.6s ease-in-out infinite; }
.viz-swipe-hint__arrow--right { animation: viz-swipe-nudge-right 1.6s ease-in-out infinite; }
@keyframes viz-swipe-nudge-left  { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(-4px); } }
@keyframes viz-swipe-nudge-right { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(4px);  } }
@keyframes viz-swipe-hint-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  #viz-swipe-hint,
  .viz-swipe-hint__arrow--left,
  .viz-swipe-hint__arrow--right { animation: none; opacity: 1; }
}

/* ── Strip product tooltip ──────────────────────────────────────── */
#viz-tooltip {
  position: fixed;
  z-index: 600;
  pointer-events: none;
  background: var(--ca, #fe86f4);
  color: var(--cp, #8c75ff);
  padding: 8px 14px 9px;
  border-radius: 3px;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  line-height: 1.4;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.10s ease;
}
#viz-tooltip.visible { opacity: 1; }
#viz-tooltip .tip-name  { font-weight: 700; }
#viz-tooltip .tip-price { font-size: 13px; font-weight: 900; margin-top: 2px; letter-spacing: 0.04em; }

/* ── Position debug panel ───────────────────────────────────────── */
#pos-panel {
  position: fixed;
  bottom: 14px;
  left: 14px;
  z-index: 9999;
  background: rgba(8, 8, 8, 0.95);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 4px;
  padding: 14px 16px 12px;
  width: 680px;
  font-family: monospace;
  font-size: 11px;
  color: #888;
  pointer-events: auto;
  display: none;
}
#pos-panel .pos-title {
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: .2em;
  color: #444;
  margin-bottom: 10px;
  display: flex;
  justify-content: space-between;
}
#pos-panel .pos-title span { color: #333; }
#pos-panel .pos-close {
  background: transparent; border: none; color: #555;
  cursor: pointer; font: inherit; font-size: 15px;
  line-height: 1; padding: 0 2px; margin-left: auto;
}
#pos-panel .pos-close:hover { color: #fff; }
/* Each category row */
#pos-panel .pos-row {
  display: grid;
  grid-template-columns: 52px 1fr 1fr;
  align-items: center;
  gap: 6px;
  margin-bottom: 7px;
}
/* Bags row has 4 columns: label + Y + X + SZ */
#pos-panel .pos-row.has-x {
  grid-template-columns: 52px 1fr 1fr 1fr;
}
#pos-panel .pos-label { color: #666; font-size: 10px; }
/* Sub-group: tiny axis label + slider + value */
#pos-panel .pos-group {
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
}
#pos-panel .pos-axis {
  font-size: 9px;
  color: #444;
  flex-shrink: 0;
  width: 14px;
}
#pos-panel .pos-slider {
  flex: 1;
  min-width: 0;
  accent-color: #fe86f4;
  height: 3px;
}
#pos-panel .pos-val {
  width: 38px;
  text-align: right;
  color: #bbb;
  flex-shrink: 0;
  font-size: 10px;
  white-space: nowrap;
  overflow: visible;
}
#pos-panel .pos-section {
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: .2em;
  color: #555;
  margin: 12px 0 8px;
  padding-top: 10px;
  border-top: 1px solid rgba(255, 255, 255, 0.07);
}
#pos-panel .pos-copy {
  width: 100%;
  margin-top: 10px;
  padding: 6px 0;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 2px;
  color: #888;
  font: inherit;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: .15em;
  cursor: pointer;
}
#pos-panel .pos-copy:hover { color: #ccc; border-color: rgba(255, 255, 255, 0.38); }
#pos-trigger {
  position: fixed;
  bottom: 0;
  left: 0;
  width: 64px;
  height: 64px;
  z-index: 9998;
  pointer-events: auto;
}

/* Grain overlay on the product modal — matches site-wide body::before grain.
   Sits BELOW #pp-image-panel (z-index 2) so it never dulls/pixelates the
   product photo itself; it still shows over the info-panel/chrome side. */
#product-page::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.68' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)'/%3E%3C/svg%3E");
  background-repeat: repeat;
  background-size: 180px 180px;
  mix-blend-mode: overlay;
  opacity: 0.45;
}
#pp-image-panel { z-index: 2; }

/* pp-visual fills the entire image panel absolutely */
#pp-visual {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* Single-image mode: contained, full product visible against the panel background */
#pp-main-image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center center;
  display: block;
  padding: 8%;
  transition: opacity 0.15s ease;
  box-sizing: border-box;
}
/* Gallery mode (2+ images): full-bleed cover, edge-to-edge, no padding */
#pp-image-panel.pp-gallery #pp-main-image {
  object-fit: cover;
  object-position: center top;
  padding: 0;
}
/* SVG fallback illustration — natural size, centered */
#pp-visual svg {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  display: block;
}

.strip.dimmed { opacity: 0; pointer-events: none; }

/* -------- Footer action row (Sort + Buy Combo) -------- */
.footer-actions {
  position: relative;
  z-index: 30;
  /* On mobile the fixed mini-player sits at ~64px from the bottom — push buttons above it */
  padding-bottom: env(safe-area-inset-bottom, 0);
  display: flex;
  flex-wrap: nowrap;
  justify-content: space-between;
  align-items: center;
  gap: 0.75rem;
  padding: 1.5rem 1.25rem 4.5rem;
}
.footer-actions__center {
  display: flex;
  flex-wrap: nowrap;
  justify-content: center;
  align-items: center;
  gap: 0.75rem;
  flex: 1 1 auto;
}
@media (min-width: 768px) { .footer-actions { padding: 1.75rem 2rem 2.25rem; gap: 1rem; } }
@media (min-width: 768px) { .footer-actions__center { gap: 1rem; } }

/* -------- Scroll navigation buttons (up/down) -------- */
.scroll-nav-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: rgba(254, 134, 244, 0.15);
  border: 1px solid rgba(254, 134, 244, 0.3);
  color: #fe86f4;
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease, transform 0.15s ease;
  flex-shrink: 0;
}
.scroll-nav-btn:hover {
  background: rgba(254, 134, 244, 0.25);
  border-color: rgba(254, 134, 244, 0.5);
}
.scroll-nav-btn:active {
  transform: scale(0.92);
}
.scroll-nav-btn--down {
  margin-left: auto;
}

/* -------- Brutalist slime Buy Combo button -------- */
.buy-combo-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5em;
  min-width: 140px;
  padding: 9px 17px;
  font-weight: 900;
  font-size: 15px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: #0a0004;
  background:
    linear-gradient(135deg, #ff2d87 0%, #ff6a00 35%, #b2005a 70%, #7b1fa2 100%);
  background-size: 220% 220%;
  border: 3px solid #0a0004;
  border-radius: 0;
  box-shadow: 6px 6px 0 0 #0a0004;
  cursor: pointer;
  transform: translate(0, 0);
  transition:
    transform .12s var(--ease-smooth),
    box-shadow .15s var(--ease-smooth),
    background-color .18s ease,
    color .18s ease,
    border-color .18s ease;
  animation: combo-slime 6s ease-in-out infinite alternate;
  isolation: isolate;
}
.buy-combo-btn:hover {
  transform: translate(-2px, -2px);
  background: #0a0004;
  background-image: none;
  animation: none;
  color: #fe86f4;
  border-color: #fe86f4;
  box-shadow: 9px 9px 0 0 #fe86f4;
}
.buy-combo-btn:active {
  transform: translate(4px, 4px);
  box-shadow: 2px 2px 0 0 #0a0004;
}
.buy-combo-btn:disabled {
  opacity: 0.7;
  cursor: wait;
}
@keyframes combo-slime {
  0%   { background-position:   0% 50%; }
  100% { background-position: 100% 50%; }
}
/* Secondary (Sort clothes) variant — monochrome, still brutalist. */
.buy-combo-btn.secondary {
  color: #f4f4f4;
  background: #0a0004;
  border-color: #f4f4f4;
  box-shadow: 6px 6px 0 0 rgba(244, 244, 244, 0.9);
  animation: none;
}
.buy-combo-btn.secondary:hover {
  transform: translate(-2px, -2px);
  background: #f4f4f4;
  color: #0a0004;
  border-color: #0a0004;
  box-shadow: 9px 9px 0 0 #0a0004;
}
.buy-combo-btn.secondary:active {
  transform: translate(4px, 4px);
  box-shadow: 2px 2px 0 0 rgba(244, 244, 244, 0.95);
}
.buy-combo-btn.spinning,
.buy-combo-btn.secondary.spinning {
  pointer-events: none;
  opacity: 0.85;
}

/* -------- Right-side controls column (cotton + next + prev) -------- */
.pp-side-controls {
  position: absolute;
  right: 12px;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  z-index: 20;
}
/* When inside the column, reset individual absolute positioning */
.pp-side-controls .pp-cotton-badge {
  position: relative;
  top: auto;
  right: auto;
  left: auto;
  transform: none;
}

/* -------- Cotton badge — primary bg, accent text+border -------- */
.pp-cotton-badge {
  position: absolute;
  top: 1.25rem;
  right: 1.25rem;
  width: 58px;
  height: 58px;
  border-radius: 50%;
  background: #8c75ff;
  color: #fe86f4;
  border: 2px solid #fe86f4;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-align: center;
  line-height: 1.25;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4px;
  z-index: 20;
  pointer-events: none;
}

/* -------- Product attributes badges — minimal monochrome -------- */
.pp-attributes { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.pp-attr-badge {
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.35rem 0.7rem;
  background: rgba(254, 134, 244, 0.12);
  border: 1px solid rgba(254, 134, 244, 0.25);
  border-radius: 3px;
  font-size: 0.58rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: #fe86f4;
  line-height: 1;
}
.pp-attr-badge svg { width: 14px; height: 14px; fill: currentColor; flex-shrink: 0; }
.pp-attr-badge span { white-space: nowrap; }

/* Collaboration badge — themed tooltip with collaborator name on hover */
.pp-attr-badge[data-collab] { position: relative; cursor: default; }
.pp-attr-badge[data-collab]:hover::after,
.pp-attr-badge[data-collab]:hover::before { opacity: 1; pointer-events: none; }
.pp-attr-badge[data-collab]::after {
  content: 'with ' attr(data-collab);
  position: absolute;
  bottom: calc(100% + 10px);
  left: 50%;
  transform: translateX(-50%);
  background: var(--ca, #fe86f4);
  color: var(--cp, #8c75ff);
  padding: 5px 13px;
  border-radius: 3px;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  white-space: nowrap;
  z-index: 200;
  opacity: 0;
  transition: opacity 0.15s ease;
  pointer-events: none;
}
.pp-attr-badge[data-collab]::before {
  content: '';
  position: absolute;
  bottom: calc(100% + 4px);
  left: 50%;
  transform: translateX(-50%);
  border: 5px solid transparent;
  border-top-color: var(--ca, #fe86f4);
  z-index: 200;
  opacity: 0;
  transition: opacity 0.15s ease;
  pointer-events: none;
}

/* -------- Gallery arrows — accent bg, primary text+border -------- */
.pp-gal-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: #fe86f4;
  color: #8c75ff;
  border: 2px solid #8c75ff;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 20;
  transition: opacity .18s ease, transform .12s ease;
}
.pp-gal-arrow:hover  { opacity: .88; }
.pp-gal-arrow:active { transform: translateY(-50%) scale(.96); }
.pp-gal-arrow--prev { left: 12px; }
.pp-gal-arrow--next { right: 12px; }

/* -------- Bottom gallery nav bar (prev · dots · next) -------- */
.pp-gal-bottom {
  position: absolute;
  bottom: 14px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 10px;
  z-index: 20;
}
.pp-gal-bottom .pp-gal-arrow {
  position: relative;
  top: auto; left: auto; right: auto;
  transform: none;
}
.pp-gal-bottom .pp-gal-arrow:active { transform: scale(.96); }
.pp-gal-bottom .pp-gal-dots {
  position: relative;
  bottom: auto; left: auto;
  transform: none;
}

/* -------- Gallery dots -------- */
.pp-gal-dots {
  position: absolute;
  bottom: 12px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 6px;
  align-items: center;
  z-index: 20;
}
.pp-gal-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: rgba(254,134,244,.35);
  transition: background .2s ease;
}
.pp-gal-dot.active { background: #fe86f4; }

/* -------- Color swatches -------- */
.pp-colors {
  display: flex !important;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
#pp-colors span,
.pp-color-dot {
  display: block !important;
  width: 22px !important;
  height: 22px !important;
  min-width: 22px;
  min-height: 22px;
  border-radius: 50% !important;
  border: 2px solid rgba(254,134,244,.5) !important;
  background-color: var(--dot-c, #ccc) !important;
  flex-shrink: 0;
  box-shadow: 0 1px 4px rgba(0,0,0,.35);
}

/* -------- Product description — 6-line scroll -------- */
/* Scrolls internally (scrollbar hidden) instead of growing and pushing the
   attribute badges/price/buy button below it out of view. This used to live
   in layout.css, which the visualizer page never loads — dead code. */
#pp-desc {
  max-height: calc(1.4em * 6);
  overflow-y: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
#pp-desc::-webkit-scrollbar { display: none; }
@media (max-width: 768px) {
  #pp-desc {
    line-height: 1.2;
    max-height: calc(1.2em * 6);
  }
}

/* -------- Product info panel — invisible fallback scroll -------- */
/* #pp-desc caps itself at 6 lines above, but the panel around it (title,
   attributes, price, buy button) is its own separate overflow-y:auto
   safety net for when everything combined still doesn't fit the modal
   height — that scrollbar was visible, breaking the "invisible slider"
   look the description already has. Match it. */
.pp-info-panel {
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.pp-info-panel::-webkit-scrollbar { display: none; }

/* -------- Unique piece label above title -------- */
.pp-unique-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  opacity: .65;
}

/* -------- Stock badge -------- */
.pp-stock-badge {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  opacity: .75;
}


/* -------- Product modal buy button -------- */
.pp-buy-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 10px 24px;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #8c75ff;
  background: #fe86f4;
  border: 2px solid #fe86f4;
  border-radius: 999px;
  cursor: pointer;
  transition: opacity .18s ease, transform .12s ease;
}
.pp-buy-btn:hover  { opacity: .88; }
.pp-buy-btn:active { transform: scale(.96); }
.pp-buy-btn:disabled { opacity: .5; cursor: wait; }
.pp-buy-btn--inv {
  background: #8c75ff;
  border-color: #fe86f4;
  color: #fe86f4;
}
