/* =====================================================================
   RobloxPets — Single Product Page V2  (visual / composition polish)

   Every selector is scoped under .rbp-spv2 (background fill uses the
   body.rbp-spv2-active page flag only, same pattern as the sidecart
   module's body.rp-sidecart-active). No html/:root/.woocommerce/
   .product/.breakdance/.section global selectors — a previous attempt
   leaked global product CSS and collapsed other pages.

   Design system refs: §3 colour, §6 background, §7 cards, §8 buttons,
   §9 badges/status, §10 game/category card language, §11 mobile.
   ===================================================================== */

body.rbp-spv2-active {
  background-color: #050913;
}

.rbp-spv2 {
  --spv2-accent: #4da3ff;
  --spv2-accent-2: #3b82f6;
  --spv2-card: linear-gradient(180deg, rgba(20, 38, 80, .56), rgba(10, 21, 48, .58));
  --spv2-card-glow: radial-gradient(420px 180px at 18% 0%, rgba(77, 163, 255, .1), transparent 70%);
  --spv2-border: rgba(96, 165, 250, .22);
  --spv2-border-soft: rgba(96, 165, 250, .16);
  --spv2-text: #e6edf7;
  --spv2-muted: #9aa9c2;

  /* Reuse the canonical RobloxPets product-image background. Same asset
     the homepage product slider + game-category cards render on, sourced
     from the product-display + game-category-page modules so V2 picks up
     any future change to that file automatically. Falling back to the
     literal URL ensures the stage still paints even if a future module
     stops defining the variable. */
  --spv2-prod-bg: url("https://robloxpets.com/wp-content/uploads/2026/01/ProductBackgroundImage.webp");
  --spv2-stage-radius: 16px;

  position: relative;
  display: block;
  box-sizing: border-box;
  min-height: 70vh;
  color: var(--spv2-text);
  background-color: #050913;
  /* Signature RobloxPets shop texture. This is the *same* layered
     dots-plus-diagonal-lines language the homepage hero and the game/
     category surfaces paint (`.rbp-gcp`) so single-product feels like
     part of the same shopping section, not a separate page. Layers,
     back-to-front:
       1. Two soft loot-cluster radial glows for ambient tint.
       2. Sparse "item orb" dot field on an offset double lattice so the
          pattern reads as a scatter, not a regular blueprint grid.
       3. Faint diagonal shop-shelf lines at a 96px cadence.
     Alpha values match the GCP page exactly. Cards / panels paint their
     own opaque-enough surfaces on top, so the texture only reads in the
     gutters between sections. */
  background-image:
    radial-gradient(900px 700px at 18% 22%, rgba(59, 130, 246, 0.10), transparent 60%),
    radial-gradient(820px 620px at 82% 78%, rgba(96, 165, 250, 0.09), transparent 60%),
    radial-gradient(circle at 18px 18px, rgba(147, 197, 253, 0.22) 1.6px, transparent 2.4px),
    radial-gradient(circle at 78px 78px, rgba(96, 165, 250, 0.13) 1.2px, transparent 2px),
    repeating-linear-gradient(135deg, rgba(96, 165, 250, 0.045) 0 1px, transparent 1px 96px);
  background-size:
    auto, auto,
    120px 120px,
    120px 120px,
    auto;
  background-position:
    0 0, 0 0,
    0 0,
    60px 60px,
    0 0;
  background-attachment: fixed, fixed, scroll, scroll, scroll;
  font-family: inherit;

  /* Start cleanly below the fixed RobloxPets header + sticky subheader.
     Mirrors the exact offset recipe the game/category surface uses so V2
     lines up with the rest of the storefront. These vars are owned by the
     header module; we only read them. */
  padding-top: calc(
    var(--rbp-fixed-main-h, var(--rbp-h-main-d, 88px))
    + var(--rbp-fixed-sub-h, 0px)
    + clamp(10px, 1.4vw, 18px)
  );
  padding-bottom: 44px;
}

.rbp-spv2 *,
.rbp-spv2 *::before,
.rbp-spv2 *::after {
  box-sizing: border-box;
}

.rbp-spv2 .rbp-spv2__shell {
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 clamp(14px, 3vw, 28px);
}

/* The hero/buy pair is intentionally narrower than the full shell so the
   media and buy cards sit close to centre with sensible whitespace, not
   pushed to opposite edges of a 1180px container. Other sections
   (reassurance strip, accordion, related) keep the full shell width. */
.rbp-spv2 .rbp-spv2-hero,
.rbp-spv2 .rbp-spv2__crumbs {
  max-width: 900px;
  margin-left: auto;
  margin-right: auto;
}

.rbp-spv2 svg {
  width: 1em;
  height: 1em;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ---- Breadcrumb / back ---- */
.rbp-spv2 .rbp-spv2__crumbs {
  margin: 0 0 clamp(10px, 1.4vw, 14px);
}

.rbp-spv2 .rbp-spv2__back {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border-radius: 999px;
  border: 1px solid var(--spv2-border-soft);
  background: rgba(13, 27, 52, .55);
  color: #cfe1ff;
  font-size: 13px;
  font-weight: 700;
  text-decoration: none;
  transition: border-color .18s ease, transform .18s ease, color .18s ease;
}

.rbp-spv2 .rbp-spv2__back svg { width: 16px; height: 16px; }

.rbp-spv2 .rbp-spv2__back:hover {
  border-color: rgba(96, 165, 250, .4);
  color: #fff;
  transform: translateY(-1px);
}

/* ---- Hero composition ----
   Centred two-card layout. Media (left) and buy (right) sit at fixed,
   bounded widths so they meet visually near the centre of the page
   instead of being pushed to opposite edges of a 1180px shell. Pre-cap
   widths come from the cards' own max-widths below; the grid only sets
   the gap and column intent. */
.rbp-spv2 .rbp-spv2-hero {
  display: grid;
  grid-template-columns: minmax(0, 460px) minmax(0, 380px);
  justify-content: center;
  gap: clamp(16px, 1.8vw, 26px);
  align-items: start;
}

/* ---- Media showcase ----
   Not sticky: the media card aligns to the top of the buy panel (grid
   align-items:start) and scrolls normally with the page. */
.rbp-spv2 .rbp-spv2-media {
  position: relative;
}

.rbp-spv2 .rbp-spv2-media__card {
  position: relative;
  overflow: hidden;
  /* Tight frame around the branded stage. The grid track already caps
     the column at 540px so the card fills it cleanly without a wide
     dead band of navy around the cloud bg. */
  width: 100%;
  max-width: 460px;
  margin: 0 auto;
  border: 1px solid var(--spv2-border);
  border-radius: 22px;
  padding: clamp(12px, 1.4vw, 16px);
  background: var(--spv2-card-glow), var(--spv2-card);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .05),
    0 18px 50px -34px rgba(2, 6, 18, .95);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}

/* Soft accent halo behind the stage — kept subtle (the branded blue stage
   is now the visual focus, not a glow blob). */
.rbp-spv2 .rbp-spv2-media__glow {
  position: absolute;
  inset: -10% 8% auto 8%;
  height: 38%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(77, 163, 255, .22), transparent 70%);
  filter: blur(14px);
  pointer-events: none;
  z-index: 0;
}

/* Game + stock pills are absolutely positioned INSIDE the stage
   (template change), so the inset values are now measured against the
   bright blue cloud, not the dark card. Sit cleanly inside the stage
   with consistent padding from each corner. */
.rbp-spv2 .rbp-spv2-media__ctx {
  position: absolute;
  top: clamp(10px, 2.4%, 14px);
  left: clamp(10px, 2.4%, 14px);
  z-index: 4;
  display: inline-flex;
  align-items: center;
  padding: 5px 11px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .04em;
  text-transform: uppercase;
  border: 1px solid rgba(8, 18, 38, .55);
  background: rgba(8, 18, 38, .82);
  color: #cfe1ff;
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  box-shadow: 0 4px 12px rgba(2, 6, 18, .35);
}

.rbp-spv2 .rbp-spv2-media__state {
  position: absolute;
  top: clamp(10px, 2.4%, 14px);
  right: clamp(10px, 2.4%, 14px);
  z-index: 4;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 11px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .04em;
  text-transform: uppercase;
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  box-shadow: 0 4px 12px rgba(2, 6, 18, .35);
}

.rbp-spv2 .rbp-spv2-media__state--in {
  border: 1px solid rgba(34, 197, 94, .55);
  background: rgba(8, 22, 18, .78);
  color: #8ff3bd;
}

.rbp-spv2 .rbp-spv2-media__state--out {
  border: 1px solid rgba(239, 68, 68, .55);
  background: rgba(28, 12, 14, .78);
  color: #fca5a5;
}

/* Branded product stage.
   Mirrors the exact treatment the homepage / game-category cards use:
   a square stage filled by the canonical RobloxPets product background
   image (rp-prod-bg / rbp-gcp-card-bg → ProductBackgroundImage.webp),
   with the product image floated above at z-index 2 and the game/stock
   pills floating in the corners of the SAME stage (template now nests
   the badges inside .rbp-spv2-media__main so the offsets read against
   the cloud, not the dark card frame).

   Sized as a square via aspect-ratio: 1 / 1 BUT capped by max-height
   so a wide hero column can never blow the stage up to 700px tall.
   The square then settles at min(card-width, max-height). On a 700px
   wide column with max-height ~480px the stage is 480x480 centred. */
.rbp-spv2 .rbp-spv2-media__main {
  position: relative;
  z-index: 1;
  width: 100%;
  /* Stage fills the card width (minus card padding) so the navy band
     around the cloud is just the card's inner padding — no dead space.
     The aspect-ratio keeps it square; max-height caps it on very wide
     hero columns so the page never grows into a 500px-tall hero. */
  max-width: 100%;
  max-height: 400px;
  margin: 0 auto;
  aspect-ratio: 1 / 1;
  border-radius: var(--spv2-stage-radius);
  overflow: hidden;
  box-shadow:
    inset 0 0 0 1px rgba(96, 165, 250, .18),
    0 18px 36px -22px rgba(2, 6, 18, .85);
}

.rbp-spv2 .rbp-spv2-media__main::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: inherit;
  background: var(--spv2-prod-bg) center / cover no-repeat;
  /* Slight blue tint on top of the image to ground it inside the dark
     theme. Same recipe as the legacy product gallery, just gentler so
     the existing branded bg colours come through. */
  box-shadow: inset 0 0 0 9999px rgba(8, 20, 44, .04);
}

.rbp-spv2 .rbp-spv2-media__img {
  position: relative;
  z-index: 2;
  display: block;
  width: 100%;
  height: 100%;
  /* Interior padding so the product image sits centred at roughly
     58-62% of the stage — featured without dominating, and small
     enough that square Roblox icons don't kiss the stage edges. */
  padding: clamp(32px, 16%, 80px);
  box-sizing: border-box;
  object-fit: contain;
  filter: drop-shadow(0 18px 30px rgba(2, 6, 18, .55));
}

/* Out-of-stock visual: dim + grayscale the product slightly + soft dark
   overlay above the branded bg. Mirrors the legacy gallery's pattern so
   the out-of-stock cue feels native to the storefront. */
.rbp-spv2[data-spv2-stock="out"] .rbp-spv2-media__main::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  border-radius: inherit;
  background: rgba(10, 12, 16, .58);
  pointer-events: none;
}
.rbp-spv2[data-spv2-stock="out"] .rbp-spv2-media__img {
  opacity: .85;
  filter:
    grayscale(.35)
    brightness(.88)
    drop-shadow(0 18px 28px rgba(2, 6, 18, .55));
}

.rbp-spv2 .rbp-spv2-media__main--empty .rbp-spv2-media__empty-glyph {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(255, 255, 255, .85);
}
.rbp-spv2 .rbp-spv2-media__main--empty .rbp-spv2-media__empty-glyph svg { width: 84px; height: 84px; }

.rbp-spv2 .rbp-spv2-media__thumbs {
  position: relative;
  z-index: 2;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  margin-top: 16px;
}

.rbp-spv2 .rbp-spv2-media__thumb {
  width: 62px;
  height: 62px;
  padding: 5px;
  border-radius: 12px;
  border: 1px solid var(--spv2-border-soft);
  background: rgba(8, 18, 38, .6);
  cursor: pointer;
  overflow: hidden;
  transition: border-color .18s ease, transform .18s ease;
}

.rbp-spv2 .rbp-spv2-media__thumb img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.rbp-spv2 .rbp-spv2-media__thumb:hover { transform: translateY(-1px); }
.rbp-spv2 .rbp-spv2-media__thumb.is-active { border-color: rgba(96, 165, 250, .6); }

/* ---- Purchase panel ---- */
.rbp-spv2 .rbp-spv2-buy {
  display: flex;
  flex-direction: column;
  gap: 10px;
  border: 1px solid var(--spv2-border);
  border-radius: 22px;
  padding: clamp(18px, 2vw, 26px);
  background: var(--spv2-card-glow), var(--spv2-card);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .05),
    0 18px 50px -34px rgba(2, 6, 18, .95);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}

.rbp-spv2 .rbp-spv2-buy__chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.rbp-spv2 .rbp-spv2-chip {
  display: inline-flex;
  align-items: center;
  padding: 4px 12px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .04em;
  text-transform: uppercase;
  border: 1px solid rgba(96, 165, 250, .32);
  background: rgba(59, 130, 246, .17);
  color: #bfdbfe;
}

.rbp-spv2 .rbp-spv2-badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 4px 12px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .04em;
  text-transform: uppercase;
}

.rbp-spv2 .rbp-spv2-badge__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
}

.rbp-spv2 .rbp-spv2-badge--in-stock {
  border: 1px solid rgba(34, 197, 94, .28);
  background: rgba(34, 197, 94, .11);
  color: #8ff3bd;
}

.rbp-spv2 .rbp-spv2-badge--out-of-stock {
  border: 1px solid rgba(239, 68, 68, .32);
  background: rgba(239, 68, 68, .10);
  color: #fca5a5;
}

.rbp-spv2 .rbp-spv2-badge--available-on-backorder {
  border: 1px solid rgba(245, 185, 66, .28);
  background: rgba(245, 185, 66, .09);
  color: #ffd59a;
}

.rbp-spv2 .rbp-spv2-buy__title {
  margin: 4px 0 0;
  font-size: clamp(22px, 2.6vw, 30px);
  font-weight: 900;
  line-height: 1.15;
  color: #fff;
  letter-spacing: -.012em;
}

.rbp-spv2 .rbp-spv2-buy__price {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 10px;
  margin: 2px 0 0;
  font-size: clamp(22px, 2.4vw, 30px);
  font-weight: 900;
  color: #fff;
  letter-spacing: -.012em;
}

.rbp-spv2 .rbp-spv2-buy__price del,
.rbp-spv2 .rbp-spv2-buy__price del * {
  color: var(--spv2-muted);
  font-size: .62em;
  font-weight: 600;
  opacity: .7;
}

.rbp-spv2 .rbp-spv2-buy__price ins {
  text-decoration: none;
}

.rbp-spv2 .rbp-spv2-buy__price ins,
.rbp-spv2 .rbp-spv2-buy__price ins * {
  color: #8ff3bd;
}

.rbp-spv2 .rbp-spv2-buy__excerpt {
  margin: 0;
  color: var(--spv2-muted);
  font-size: 14px;
  line-height: 1.6;
}

.rbp-spv2 .rbp-spv2-buy__divider {
  height: 1px;
  margin: 2px 0;
  background: linear-gradient(90deg, transparent, var(--spv2-border), transparent);
}

/* WooCommerce's native simple add-to-cart template echoes
   wc_get_stock_html() ("In stock" / "Out of stock") above the form.
   We already surface stock as the purchase badge (chips row) and the
   media overlay, so this third copy is redundant and confusing — keep
   it for assistive tech but remove it visually. */
.rbp-spv2 .rbp-spv2-buy__cart p.stock {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ---- Native WooCommerce add-to-cart, restyled (scoped) ---- */
.rbp-spv2 .rbp-spv2-buy__cart form.cart {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 10px;
  margin: 0;
}

/* Quantity selector — full Breakdance/BDE neutralisation, replaced with a
   clean RobloxPets segmented pill. JS injects custom -/+ buttons that
   drive the native <input type="number"> via a real `change` event so
   stock caps, min/max, AJAX add-to-cart and variations all keep working.
   Order is enforced via flex `order:` so the legacy BDE buttons (if a
   browser briefly renders them before JS removes them) never appear
   between our buttons. */
.rbp-spv2 .rbp-spv2-buy__cart .quantity {
  display: inline-flex;
  align-items: stretch;
  flex: 0 0 auto;
  width: auto;
  max-width: none;
  border: 1px solid var(--spv2-border);
  border-radius: 14px;
  background: rgba(8, 18, 38, .55);
  overflow: hidden;
  padding: 0;
}

/* Belt-and-braces: kill Breakdance's native quantity buttons inside
   .rbp-spv2 even if the JS that removes them from the DOM didn't run.
   Without this you see the BDE -/+ side tabs leaking through. */
.rbp-spv2 .rbp-spv2-buy__cart .quantity .bde-quantity-button,
.rbp-spv2 .rbp-spv2-buy__cart .quantity .bde-quantity-button--dec,
.rbp-spv2 .rbp-spv2-buy__cart .quantity .bde-quantity-button--inc {
  display: none !important;
}

/* Screen-reader-only WC quantity label — keep accessible, no visual. */
.rbp-spv2 .rbp-spv2-buy__cart .quantity > label.screen-reader-text {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}

.rbp-spv2 .rbp-spv2-buy__cart .quantity input.qty {
  width: 56px;
  min-height: 48px;
  padding: 0 6px;
  border: 0;
  background: transparent;
  color: #fff;
  font-size: 15px;
  font-weight: 800;
  text-align: center;
  -moz-appearance: textfield;
  appearance: textfield;
  order: 2;
}

.rbp-spv2 .rbp-spv2-buy__cart .quantity input.qty::-webkit-outer-spin-button,
.rbp-spv2 .rbp-spv2-buy__cart .quantity input.qty::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* JS-injected stepper buttons (visible when JS has hydrated the form). */
.rbp-spv2 .rbp-spv2-buy__cart .quantity .rbp-spv2-qty-step {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  min-height: 48px;
  padding: 0;
  margin: 0;
  border: 0;
  background: transparent;
  color: #cfe1ff;
  font-size: 18px;
  font-weight: 900;
  line-height: 1;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  -webkit-tap-highlight-color: transparent;
  transition: background-color .15s ease, color .15s ease;
}
.rbp-spv2 .rbp-spv2-buy__cart .quantity .rbp-spv2-qty-step:hover { background: rgba(77, 163, 255, .12); color: #fff; }
.rbp-spv2 .rbp-spv2-buy__cart .quantity .rbp-spv2-qty-step:disabled { opacity: .35; cursor: not-allowed; background: transparent !important; }
.rbp-spv2 .rbp-spv2-buy__cart .quantity .rbp-spv2-qty-step--minus { order: 1; border-right: 1px solid var(--spv2-border-soft); }
.rbp-spv2 .rbp-spv2-buy__cart .quantity .rbp-spv2-qty-step--plus  { order: 3; border-left:  1px solid var(--spv2-border-soft); }

/* Hide the quantity control entirely when the product can only be
   bought one at a time. The Add to basket button then takes the full
   width of the row so it reads as the single primary action. */
.rbp-spv2[data-spv2-qty="off"] .rbp-spv2-buy__cart .quantity {
  display: none !important;
}
.rbp-spv2[data-spv2-qty="off"] .rbp-spv2-buy__cart .single_add_to_cart_button {
  flex: 1 1 100%;
  width: 100%;
}

.rbp-spv2 .rbp-spv2-buy__cart .single_add_to_cart_button,
.rbp-spv2 .rbp-spv2-buy__cart button.single_add_to_cart_button {
  flex: 1 1 220px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 48px;
  max-height: 56px;
  padding: 0 24px;
  border: 1px solid rgba(186, 213, 255, .32);
  border-radius: 12px;
  background: linear-gradient(180deg, #4ea1ff 0%, #2c70d8 100%);
  color: #fff;
  font-size: 15px;
  font-weight: 900;
  letter-spacing: .01em;
  line-height: 1;
  text-transform: none;
  cursor: pointer;
  white-space: nowrap;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .22),
    0 10px 24px rgba(46, 113, 215, .4);
  transition: transform .16s ease, box-shadow .16s ease, filter .16s ease, background .16s ease, border-color .16s ease;
}

.rbp-spv2 .rbp-spv2-buy__cart .single_add_to_cart_button:hover {
  transform: translateY(-1px);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .22),
    0 16px 32px rgba(46, 113, 215, .55);
}

.rbp-spv2 .rbp-spv2-buy__cart .single_add_to_cart_button:active {
  transform: translateY(0);
}

.rbp-spv2 .rbp-spv2-buy__cart .single_add_to_cart_button:disabled,
.rbp-spv2 .rbp-spv2-buy__cart .single_add_to_cart_button.disabled {
  filter: grayscale(.4) brightness(.8);
  cursor: not-allowed;
  transform: none;
}

.rbp-spv2 .rbp-spv2-buy__cart .single_add_to_cart_button.rbp-spv2-loading {
  pointer-events: none;
  opacity: .85;
}

/* "Added" success state. Mirrors the look the category/loop cards use
   (product-display's flashAdded) but scoped to the V2 CTA — green
   gradient, check glyph injected via ::before, brief shine via ::after.
   Triggered by JS when the AJAX add resolves. */
.rbp-spv2 .rbp-spv2-buy__cart .single_add_to_cart_button.rp-atc-confirmed {
  position: relative;
  overflow: hidden;
  border-color: rgba(52, 211, 153, .58) !important;
  background:
    radial-gradient(140px 70px at 24% 0%, rgba(187, 247, 208, .28), transparent 68%),
    linear-gradient(180deg, #2ee89a 0%, #16c983 55%, #0fa76b 100%) !important;
  color: #fff;
  text-shadow: 0 1px 0 rgba(2, 24, 16, .28);
  box-shadow:
    0 10px 24px rgba(16, 185, 129, .34),
    inset 0 1px 0 rgba(255, 255, 255, .28);
}
.rbp-spv2 .rbp-spv2-buy__cart .single_add_to_cart_button.rp-atc-confirmed::before {
  content: "";
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  background: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat;
}
.rbp-spv2 .rbp-spv2-buy__cart .single_add_to_cart_button.rp-atc-restoring {
  filter: none;
}

.rbp-spv2 .rbp-spv2-buy__cart .woocommerce-variation-add-to-cart,
.rbp-spv2 .rbp-spv2-buy__cart .variations {
  width: 100%;
}

.rbp-spv2 .rbp-spv2-buy__cart .variations td,
.rbp-spv2 .rbp-spv2-buy__cart .variations th {
  padding: 4px 8px 4px 0;
}

.rbp-spv2 .rbp-spv2-buy__cart .reset_variations {
  color: var(--spv2-muted);
  font-size: 12px;
}

/* Hide the WooCommerce post-add "View cart" forward link — the sidecart
   is the canonical surface for that on this site. */
.rbp-spv2 .rbp-spv2-buy__cart .added_to_cart.wc-forward {
  display: none !important;
}

/* ---- Delivery reassurance strip ---- */
.rbp-spv2 .rbp-spv2-strip {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  margin-top: clamp(14px, 2vw, 22px);
}

.rbp-spv2 .rbp-spv2-strip__item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 14px;
  border: 1px solid var(--spv2-border-soft);
  border-radius: 14px;
  background: var(--spv2-card);
  transition: border-color .18s ease, transform .18s ease;
}
.rbp-spv2 .rbp-spv2-strip__item:hover {
  border-color: rgba(96, 165, 250, .35);
  transform: translateY(-1px);
}

.rbp-spv2 .rbp-spv2-strip__ico {
  display: grid;
  place-items: center;
  flex: 0 0 36px;
  width: 36px;
  height: 36px;
  padding: 0;
  border-radius: 10px;
  border: 1px solid rgba(96, 165, 250, .28);
  background: rgba(59, 130, 246, .14);
  color: var(--spv2-accent);
  line-height: 0;
}
.rbp-spv2 .rbp-spv2-strip__ico svg {
  display: block;
  width: 17px;
  height: 17px;
  margin: 0;
  flex: none;
}

.rbp-spv2 .rbp-spv2-strip__item > div > strong {
  display: block;
  color: #fff;
  font-size: 13.5px;
  font-weight: 800;
}

/* Scope to the text span only — a bare `span` selector here also matches the
   icon <span> (.rbp-spv2-strip__ico) and, at higher specificity, overrode its
   display:grid centring, dropping the SVG into the top-left corner. */
.rbp-spv2 .rbp-spv2-strip__item > div > span {
  display: block;
  margin-top: 2px;
  color: var(--spv2-muted);
  font-size: 12.5px;
  line-height: 1.45;
}

/* ---- Details accordion ---- */
.rbp-spv2 .rbp-spv2-details {
  margin-top: clamp(14px, 2vw, 22px);
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.rbp-spv2 .rbp-spv2-acc {
  position: relative;
  border: 1px solid var(--spv2-border);
  border-radius: 16px;
  background: var(--spv2-card);
  overflow: hidden;
  transition: border-color .18s ease, background-color .18s ease;
}
.rbp-spv2 .rbp-spv2-acc:hover {
  border-color: rgba(96, 165, 250, .35);
}
/* Open state — soft accent strip on the left so the active card reads
   clearly without changing height or shifting siblings. */
.rbp-spv2 .rbp-spv2-acc.is-open {
  border-color: rgba(96, 165, 250, .42);
  background: linear-gradient(180deg, rgba(22, 42, 84, .55), rgba(11, 23, 50, .58));
}
.rbp-spv2 .rbp-spv2-acc.is-open::before {
  content: "";
  position: absolute;
  top: 14px;
  bottom: 14px;
  left: 0;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: linear-gradient(180deg, #5fb0ff, #3b82f6);
}

.rbp-spv2 .rbp-spv2-acc__head {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 15px 18px;
  border: 0;
  background: transparent;
  color: #fff;
  font-size: 15px;
  font-weight: 800;
  text-align: left;
  cursor: pointer;
}

.rbp-spv2 .rbp-spv2-acc__ico {
  display: inline-flex;
  color: var(--spv2-accent);
}
.rbp-spv2 .rbp-spv2-acc__ico svg { width: 18px; height: 18px; }

.rbp-spv2 .rbp-spv2-acc__title { flex: 1; }

.rbp-spv2 .rbp-spv2-acc__chev {
  display: inline-flex;
  color: var(--spv2-muted);
  transition: transform .2s ease;
}
.rbp-spv2 .rbp-spv2-acc__chev svg { width: 18px; height: 18px; }
.rbp-spv2 .rbp-spv2-acc.is-open .rbp-spv2-acc__chev { transform: rotate(180deg); }

.rbp-spv2 .rbp-spv2-acc__body {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .26s ease;
}
.rbp-spv2 .rbp-spv2-acc.is-open .rbp-spv2-acc__body {
  grid-template-rows: 1fr;
}

.rbp-spv2 .rbp-spv2-acc__inner {
  overflow: hidden;
  padding: 0 18px;
  color: var(--spv2-muted);
  font-size: 14px;
  line-height: 1.6;
}
.rbp-spv2 .rbp-spv2-acc.is-open .rbp-spv2-acc__inner {
  padding-bottom: 18px;
}
.rbp-spv2 .rbp-spv2-acc__inner p { margin: 0 0 10px; }
.rbp-spv2 .rbp-spv2-acc__inner p:last-child { margin-bottom: 0; }

/* Quick-facts fallback list (server-side rendered when the product has
   no long description). Two-column grid label/value rows so practical
   product info reads as a clean spec table, not a paragraph block. */
.rbp-spv2 .rbp-spv2-acc__inner .rbp-spv2-acc__facts {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: minmax(110px, max-content) minmax(0, 1fr);
  column-gap: 14px;
  row-gap: 6px;
  font-size: 13.5px;
}
.rbp-spv2 .rbp-spv2-acc__inner .rbp-spv2-acc__facts li {
  display: contents;
  color: var(--spv2-muted);
}
.rbp-spv2 .rbp-spv2-acc__inner .rbp-spv2-acc__facts li strong {
  color: #cfe1ff;
  font-weight: 700;
}
@media (max-width: 480px) {
  .rbp-spv2 .rbp-spv2-acc__inner .rbp-spv2-acc__facts {
    grid-template-columns: 1fr;
    row-gap: 4px;
  }
  .rbp-spv2 .rbp-spv2-acc__inner .rbp-spv2-acc__facts li strong {
    display: block;
    margin-top: 6px;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--spv2-muted);
  }
}

/* ---- Related ---- */
.rbp-spv2 .rbp-spv2-related {
  margin-top: clamp(20px, 2.8vw, 32px);
}

.rbp-spv2 .rbp-spv2-related__head {
  margin: 0 0 14px;
}

.rbp-spv2 .rbp-spv2-related__title {
  margin: 0;
  font-size: clamp(19px, 2vw, 24px);
  font-weight: 900;
  color: #fff;
}

/* Related products REUSE the real polished card system unchanged: the
   WooCommerce [products] shortcode + the product-display module hooks +
   the game-category-page.css card design (same renderer the homepage,
   game pages and category/browse grids use). It only looked broken on V2
   because that stylesheet sizes cards via --rbp-gcp-* custom properties
   defined on the GCP page root (.rbp-gcp), which V2 does not have, and it
   force-flexes ul.products into a horizontal slider. We fix exactly those
   two things, scoped to .rbp-spv2 — we do NOT fork or restyle the card. */
.rbp-spv2 .rbp-gcp-slider {
  /* Supply the card-geometry vars the GCP card design expects so card
     width / padding / gap / radius / badge offsets all resolve. The
     card width mirrors GCP's default (clamp 168–208px) so auto-fill
     produces the same responsive column counts the category pages use:
     5 wide on desktop, 4 on tablet, 2 on mobile, never tinier. */
  --rbp-gcp-card-w: clamp(150px, 14vw, 200px);
  --rbp-gcp-card-pad: clamp(8px, 0.9vw, 14px);
  --rbp-gcp-card-gap: clamp(8px, 0.8vw, 14px);
  --rbp-gcp-radius-sm: 12px;
  /* CRITICAL: the GCP card design paints the branded blue product
     background via `--rbp-gcp-card-bg` on the LoopProduct-link ::before.
     That variable is defined on `.rbp-gcp` (the category-page root),
     which V2 does not have as an ancestor, so without supplying it
     here related-product cards would render on dark navy panels
     instead of the bright PS99 cloud the homepage cards use. Same
     URL/asset, just made visible inside the V2 scope. */
  --rbp-gcp-card-bg: var(--spv2-prod-bg);
  /* Cancel the slider's negative inline bleed so the grid lines up with
     the rest of the V2 shell. */
  margin-inline: 0;
  padding-inline: 0;
}

/* Pull a bit more presence out of each related card without forking the
   shared GCP card design:
     • Image transform-scale(.9) from the GCP rule leaves a 10% dead band
       around small Roblox icons — bump to 1.0 (and slightly larger on
       hover) so the product actually fills its frame.
     • The default loop "Add to basket" button can render as a large blue
       chip stacked under the card. Compact it for the related rail.
     • Slightly shorter card title clamp avoids tall variable card
       heights when titles are 1 vs 2 lines.
   All overrides are strictly inside `.rbp-spv2 .rbp-gcp-slider--grid`. */
.rbp-spv2 .rbp-gcp-slider--grid ul.products > li.product a.woocommerce-LoopProduct-link img {
  padding: 8px;
  transform: scale(1);
  transform-origin: 50% 55%;
}
.rbp-spv2 .rbp-gcp-slider--grid ul.products > li.product:hover a.woocommerce-LoopProduct-link img {
  transform: scale(1.05);
}
.rbp-spv2 .rbp-gcp-slider--grid ul.products > li.product .woocommerce-loop-product__title,
.rbp-spv2 .rbp-gcp-slider--grid ul.products > li.product h2.woocommerce-loop-product__title,
.rbp-spv2 .rbp-gcp-slider--grid ul.products > li.product h3.woocommerce-loop-product__title {
  font-size: 13.5px;
  line-height: 1.3;
}
.rbp-spv2 .rbp-gcp-slider--grid ul.products > li.product .price,
.rbp-spv2 .rbp-gcp-slider--grid ul.products > li.product .price * {
  font-size: 14.5px;
}
/* Native WC loop "Add to basket" / "Read more" link — render as the
   compact secondary action that matches the rest of V2 (no shouting,
   keeps every WC click handler / AJAX hook). */
.rbp-spv2 .rbp-gcp-slider--grid ul.products > li.product .button,
.rbp-spv2 .rbp-gcp-slider--grid ul.products > li.product a.add_to_cart_button,
.rbp-spv2 .rbp-gcp-slider--grid ul.products > li.product a.product_type_simple,
.rbp-spv2 .rbp-gcp-slider--grid ul.products > li.product a.product_type_variable,
.rbp-spv2 .rbp-gcp-slider--grid ul.products > li.product a.product_type_external {
  min-height: 38px;
  padding: 8px 12px;
  font-size: 12.5px;
  border-radius: 10px;
}

/* Convert the forced horizontal flex slider into a contained, intentional
   responsive grid (overrides the GCP !important slider geometry).
   `auto-fill` with the same --rbp-gcp-card-w envelope the category pages
   use means the grid naturally falls to 4 / 3 / 2 columns as the viewport
   narrows — no manual breakpoint table, no 5-tiny-columns-on-mobile. */
.rbp-spv2 .rbp-gcp-slider--grid ul.products,
.rbp-spv2 .rbp-gcp-slider--grid .woocommerce > ul.products,
.rbp-spv2 .rbp-gcp-slider--grid ul.products.columns-1,
.rbp-spv2 .rbp-gcp-slider--grid ul.products.columns-2,
.rbp-spv2 .rbp-gcp-slider--grid ul.products.columns-3,
.rbp-spv2 .rbp-gcp-slider--grid ul.products.columns-4,
.rbp-spv2 .rbp-gcp-slider--grid ul.products.columns-5,
.rbp-spv2 .rbp-gcp-slider--grid ul.products.columns-6 {
  display: grid !important;
  grid-template-columns: repeat(auto-fill, minmax(var(--rbp-gcp-card-w), 1fr)) !important;
  gap: var(--rbp-gcp-card-gap) !important;
  margin: 0 !important;
  padding: 0 !important;
  overflow: visible !important;
}

/* The slider appends an ::after flex spacer for scroll runway — in a grid
   that becomes a stray empty cell. Remove it. */
.rbp-spv2 .rbp-gcp-slider--grid ul.products::after {
  display: none !important;
}

/* Free the card from the slider's fixed-width pinning so it fills its
   grid track; everything else (surface, image stage, title, price, sale
   ribbon, In Stock / Out of Stock pills, button, hover) is inherited
   unchanged from game-category-page.css. */
.rbp-spv2 .rbp-gcp-slider--grid ul.products > li.product {
  flex: initial !important;
  width: auto !important;
  max-width: none !important;
  min-width: 0 !important;
  scroll-snap-align: none;
}

/* auto-fill already handles desktop → tablet column step-down; no manual
   breakpoint columns needed here. */

/* ---- Restock widget spacing inside panel ---- */
.rbp-spv2 .rp-restock-watch {
  margin: 12px 0 0;
}

/* ---- Tablet / mobile ---- */
@media (max-width: 960px) {
  .rbp-spv2 .rbp-spv2-hero {
    grid-template-columns: minmax(0, 460px);
    justify-content: center;
  }
  .rbp-spv2 .rbp-spv2-media {
    position: static;
  }
  /* On stacked layouts the stage shrinks so the customer reaches the
     purchase panel quickly — no 480px tall image dominating the phone. */
  .rbp-spv2 .rbp-spv2-media__card {
    max-width: 460px;
  }
  .rbp-spv2 .rbp-spv2-media__main {
    max-width: 100%;
    max-height: clamp(260px, 50vw, 360px);
  }
  .rbp-spv2 .rbp-spv2-strip {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 760px) {
  .rbp-spv2 {
    /* Small buffer only — nav space reserved below the footer by body padding. */
    padding-bottom: 24px;
  }
  /* Keep qty + CTA on one row at typical phone widths; the qty pill is
     ~140px wide (38 + 56 + 38 + borders) and the CTA flex-fills the rest.
     That fits cleanly on a 360px+ viewport and avoids the giant
     full-width-then-stacked button look. */
  .rbp-spv2 .rbp-spv2-buy__cart form.cart {
    flex-wrap: nowrap;
    align-items: center;
  }
  .rbp-spv2 .rbp-spv2-buy__cart .quantity {
    flex: 0 0 auto;
  }
  .rbp-spv2 .rbp-spv2-buy__cart .single_add_to_cart_button {
    flex: 1 1 auto;
    width: auto;
    min-width: 0;
  }
}

/* On phones the orb lattice clusters too tightly at device density —
   soften it to match the same treatment .rbp-gcp applies at @640px so
   the texture doesn't compete with mobile copy. */
@media (max-width: 640px) {
  .rbp-spv2 {
    background-image:
      radial-gradient(900px 700px at 18% 22%, rgba(59, 130, 246, 0.10), transparent 60%),
      radial-gradient(820px 620px at 82% 78%, rgba(96, 165, 250, 0.09), transparent 60%),
      radial-gradient(circle at 16px 16px, rgba(147, 197, 253, 0.16) 1.3px, transparent 2px),
      radial-gradient(circle at 70px 70px, rgba(96, 165, 250, 0.10) 1px, transparent 1.8px),
      repeating-linear-gradient(135deg, rgba(96, 165, 250, 0.03) 0 1px, transparent 1px 80px);
  }
  /* Smaller related cards on phones, same envelope GCP uses at this
     breakpoint, so the upsell grid scales the way category pages do
     (two readable columns at 360-430px, never tinier). */
  .rbp-spv2 .rbp-gcp-slider {
    --rbp-gcp-card-w: clamp(140px, 42vw, 168px);
  }
}

@media (max-width: 430px) {
  .rbp-spv2 .rbp-spv2__shell {
    padding-left: 14px;
    padding-right: 14px;
  }
  .rbp-spv2 .rbp-spv2-media__card {
    padding: 12px;
  }
  .rbp-spv2 .rbp-spv2-media__main {
    max-width: 100%;
    max-height: clamp(220px, 64vw, 300px);
  }
  /* Tighter chip insets on tiny phones so they don't kiss the image. */
  .rbp-spv2 .rbp-spv2-media__ctx { top: 10px; left: 10px; padding: 4px 9px; font-size: 10.5px; }
  .rbp-spv2 .rbp-spv2-media__state { top: 10px; right: 10px; padding: 4px 9px; font-size: 10.5px; }
  .rbp-spv2 .rbp-spv2-buy {
    padding: 16px;
  }
  .rbp-spv2 .rbp-spv2-buy__cart .quantity input.qty { width: 42px; }
  .rbp-spv2 .rbp-spv2-buy__cart .quantity .rbp-spv2-qty-step { width: 34px; }
  .rbp-spv2 .rbp-spv2-buy__cart .single_add_to_cart_button {
    padding: 0 16px;
    font-size: 14px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .rbp-spv2 .rbp-spv2-acc__body,
  .rbp-spv2 .rbp-spv2-acc__chev,
  .rbp-spv2 .rbp-spv2__back,
  .rbp-spv2 .rbp-spv2-media__thumb,
  .rbp-spv2 .rbp-spv2-buy__cart .single_add_to_cart_button {
    transition: none !important;
  }
}
