/* Galxboy Bundles — storefront picker. Mobile-FIRST, clean SA streetwear:
   high-contrast monochrome ink + a single accent, big tap targets (>=44px),
   system font stack (no external fonts), smooth bottom-sheet motion.

   Everything is scoped under `.gbb` so the theme can't break the picker and the
   picker can't leak into the theme. Tokens have safe fallbacks. Layout space is
   reserved (skeleton + sticky reserve) so hydration causes zero CLS. */

.gbb {
  --gb-ink: #0a0a0a;
  --gb-paper: #ffffff;
  --gb-muted: #6b6b6b;
  --gb-line: #e6e6e6;
  --gb-soft: #f4f4f4;
  /* Fill for CTAs, selected pills and badges. Defaults to the ink so the stock
     look is unchanged; a merchant accent overrides it alone, without dragging
     the text/border colour with it. --gb-on-accent is the label ON this fill. */
  --gb-accent: var(--gb-ink);
  --gb-on-accent: #ffffff;
  --gb-save: #0a7d3b;
  --gb-danger: #b00020;
  --gb-radius: 14px;
  --gb-radius-sm: 10px;
  --gb-border-w: 2px;          /* merchant can switch the card border off */

  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
    Arial, sans-serif;
  color: var(--gb-ink);
  display: block;
  margin: 18px 0;
  -webkit-tap-highlight-color: transparent;
  box-sizing: border-box;
}
/* The bottom sheet and the toast are appended to document.body, NOT to the
   mount, so they have no `.gbb` ancestor to inherit the tokens from — every
   var() inside them would otherwise be invalid at computed-value time (a
   transparent sheet). Restate the defaults here; applyAppearanceTo() copies any
   merchant overrides onto these nodes at creation time. */
.gbb__sheet,
.gbb__toast {
  --gb-ink: #0a0a0a;
  --gb-paper: #ffffff;
  --gb-muted: #6b6b6b;
  --gb-line: #e6e6e6;
  --gb-soft: #f4f4f4;
  --gb-accent: var(--gb-ink);
  --gb-on-accent: #ffffff;
  --gb-save: #0a7d3b;
  --gb-danger: #b00020;
  --gb-radius: 14px;
  --gb-radius-sm: 10px;
  --gb-border-w: 2px;
}
.gbb *,
.gbb *::before,
.gbb *::after,
.gbb__sheet *,
.gbb__sheet *::before,
.gbb__sheet *::after {
  box-sizing: border-box;
}
.gbb--hidden {
  display: none !important;
}

/* Keyboard focus. Scoped + :focus-visible so it never shows on mouse/touch and
   survives themes that ship a global `outline:none` reset (which would otherwise
   make the whole builder invisible to navigate). */
.gbb :is(button, a, [role="radio"]):focus-visible {
  outline: 2px solid var(--gb-ink);
  outline-offset: 2px;
}
/* Light ring on the black-filled selected pills so it stays visible on the fill. */
.gbb__optval--on:focus-visible,
.gbb__vchip--on:focus-visible,
.gbb__add:focus-visible {
  outline-color: var(--gb-on-accent);
}

/* ── skeleton (reserves height) ─────────────────────────────────────────── */
.gbb__skeleton {
  min-height: 188px;
  display: grid;
  gap: 12px;
}
.gbb__skel-line {
  height: 20px;
  width: 60%;
  border-radius: 6px;
}
.gbb__skel-row {
  display: flex;
  gap: 10px;
}
.gbb__skel-chip {
  flex: 0 0 116px;
  height: 132px;
  border-radius: var(--gb-radius);
}
.gbb__skel-bar {
  height: 56px;
  border-radius: var(--gb-radius);
}
.gbb__skel-line,
.gbb__skel-chip,
.gbb__skel-bar {
  background: linear-gradient(100deg, #ededed 28%, #f7f7f7 50%, #ededed 72%);
  background-size: 200% 100%;
  animation: gbb-shimmer 1.3s linear infinite;
}
@keyframes gbb-shimmer {
  to {
    background-position: -200% 0;
  }
}
@media (prefers-reduced-motion: reduce) {
  .gbb__skel-line,
  .gbb__skel-chip,
  .gbb__skel-bar {
    animation: none;
  }
  /* Honour the OS "reduce motion" setting everywhere: no tap-bounce transforms,
     no transitions. (The JS smooth-scroll is gated separately via motionBehavior.) */
  .gbb *,
  .gbb *::before,
  .gbb *::after {
    transition: none !important;
    animation: none !important;
  }
  .gbb__slot:active,
  .gbb__chip:active,
  .gbb__optval:active,
  .gbb__vchip:active,
  .gbb__add:active {
    transform: none;
  }
}

/* ── panel ───────────────────────────────────────────────────────────────── */
.gbb__panel {
  background: var(--gb-paper);
  border: var(--gb-border-w, 2px) solid var(--gb-ink);
  border-radius: var(--gb-radius);
  padding: 16px;
}

/* ── card (cover + builder) ──────────────────────────────────────────────────
   The card is the interactive bundle. Mobile = single column (cover stacked over
   the builder, padding 0 so the hero is edge-to-edge). Desktop = 2-column grid
   via the container/media queries further down. */
.gbb__card {
  padding: 0;
  overflow: hidden; /* clip the hero to the card's rounded corners */
}
/* Enable container queries ONLY on wider viewports. `container-type: inline-size`
   makes the element a containing block for `position: fixed` descendants, which
   would break the mobile fixed sticky bar — so we never set it on phones. */
@media (min-width: 750px) {
  .gbb__card {
    container-type: inline-size;
    container-name: gbbcard;
  }
}

/* ── cover / hero ────────────────────────────────────────────────────────── */
.gbb__cover {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  background: var(--gb-ink);
}
/* Hero height is merchant-configurable (Appearance → Hero image size). The size
   class lives on the MOUNT, not the cover, because render() rebuilds the cover on
   every state change. Each breakpoint below redefines all three so the later,
   more specific rule always wins. */
.gbb__cover--img {
  min-height: 200px;
}
.gbb--hero-sm .gbb__cover--img {
  min-height: 132px;
}
.gbb--hero-lg .gbb__cover--img {
  min-height: 300px;
}
/* No hero image: a clean, on-brand header band (never a broken image). */
.gbb__cover--plain {
  background: var(--gb-ink);
  color: var(--gb-on-accent);
}
/* Landing page with an imageless cover and no badges: the proxy hero already owns
   the title, so collapse the otherwise-empty ink band. */
.gbb__cover--collapsed {
  display: none;
}
.gbb__cover-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Legibility scrim under the title when a photo is present. */
.gbb__cover--img::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to top,
    rgba(0, 0, 0, 0.72) 0%,
    rgba(0, 0, 0, 0.28) 42%,
    rgba(0, 0, 0, 0) 72%
  );
  pointer-events: none;
}

.gbb__head {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 18px;
}
.gbb__cover--img .gbb__head {
  padding-top: 64px;
  color: var(--gb-on-accent);
}
.gbb__cover--plain .gbb__head {
  color: var(--gb-on-accent);
}
.gbb__eyebrow {
  margin: 0;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  opacity: 0.7;
}
.gbb__title {
  font-size: 22px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.04;
  text-transform: uppercase;
  margin: 0;
  color: inherit;
}

/* ── builder column ──────────────────────────────────────────────────────── */
.gbb__builder {
  padding: 16px;
}
.gbb__badges {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.gbb__badge {
  font-size: 11px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 4px 9px;
  border-radius: 999px;
  border: 1.5px solid var(--gb-ink);
  white-space: nowrap;
}
.gbb__badge--save {
  background: var(--gb-accent);
  color: var(--gb-on-accent);
}
.gbb__badge--ship {
  background: var(--gb-paper);
  color: var(--gb-ink);
}
.gbb__badge--gift {
  background: var(--gb-save);
  border-color: var(--gb-save);
  color: #fff;
}
/* On a dark cover the badges need light borders + an inverted "save" chip. */
.gbb__cover--img .gbb__badge,
.gbb__cover--plain .gbb__badge {
  border-color: rgba(255, 255, 255, 0.85);
}
.gbb__cover--img .gbb__badge--save,
.gbb__cover--plain .gbb__badge--save {
  background: var(--gb-paper);
  color: var(--gb-ink);
  border-color: var(--gb-paper);
}
.gbb__cover--img .gbb__badge--ship,
.gbb__cover--plain .gbb__badge--ship {
  background: transparent;
  color: var(--gb-on-accent);
}

/* ── builder tools (Clear) ───────────────────────────────────────────────── */
.gbb__builder-tools {
  display: flex;
  justify-content: flex-end;
  margin-bottom: 8px;
}
.gbb__clear {
  appearance: none;
  border: 0;
  background: transparent;
  cursor: pointer;
  font: inherit;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--gb-muted);
  text-decoration: underline;
  text-underline-offset: 2px;
  padding: 4px 2px;
}
.gbb__clear:hover {
  color: var(--gb-ink);
}

/* ── slot rows ───────────────────────────────────────────────────────────── */
.gbb__slots {
  display: grid;
  gap: 10px;
}
.gbb__slot {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 60px;
  padding: 12px 14px;
  text-align: left;
  font: inherit;
  color: inherit;
  background: var(--gb-paper);
  border: 1.5px solid var(--gb-line);
  border-radius: var(--gb-radius-sm);
  cursor: pointer;
  transition: border-color 0.15s ease, transform 0.06s ease;
}
.gbb__slot:active {
  transform: scale(0.99);
}
.gbb__slot--active {
  border-color: var(--gb-ink);
}
.gbb__slot--filled {
  border-color: var(--gb-ink);
}
.gbb__slot-num {
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 800;
  color: var(--gb-on-accent);
  background: var(--gb-muted);
}
.gbb__slot--active .gbb__slot-num,
.gbb__slot--filled .gbb__slot-num {
  background: var(--gb-accent);
}
.gbb__slot-main {
  flex: 1 1 auto;
  min-width: 0;
}
.gbb__slot-label {
  font-size: 14px;
  font-weight: 700;
  color: var(--gb-ink);
}
.gbb__slot-sub {
  font-size: 12px;
  color: var(--gb-muted);
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.gbb__slot-thumb {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: 8px;
  object-fit: cover;
  border: 1.5px solid var(--gb-line);
}
.gbb__slot-cta {
  flex: 0 0 auto;
  font-size: 13px;
  font-weight: 800;
  color: var(--gb-ink);
  white-space: nowrap;
}
.gbb__slot-change {
  flex: 0 0 auto;
  font-size: 12px;
  font-weight: 700;
  color: var(--gb-muted);
  white-space: nowrap;
}

/* ── locked state ────────────────────────────────────────────────────────── */
.gbb__locked {
  text-align: center;
  display: grid;
  gap: 12px;
  justify-items: center;
  background: var(--gb-soft);
  padding: 32px 22px;
}
.gbb__lock-badge {
  width: 46px;
  height: 46px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  background: var(--gb-accent);
  color: var(--gb-on-accent);
}
.gbb__locked-title {
  font-size: 12px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--gb-muted);
  margin: 6px 0 0;
}
.gbb__locked-headline {
  font-size: 18px;
  font-weight: 800;
  margin: 0;
  color: var(--gb-ink);
}
.gbb__locked-sub {
  font-size: 13px;
  color: var(--gb-muted);
  margin: 0;
  max-width: 30ch;
}
.gbb__login {
  margin-top: 12px;
  display: inline-block;
  font-size: 13px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  text-decoration: none;
  color: var(--gb-on-accent);
  background: var(--gb-accent);
  padding: 11px 22px;
  border-radius: 999px;
  min-height: 44px;
  line-height: 22px;
}

/* ── inline picker (desktop) ─────────────────────────────────────────────── */
.gbb__inline {
  margin-top: 14px;
  border-top: 1.5px dashed var(--gb-line);
  padding-top: 14px;
}
.gbb__inline-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}
.gbb__inline-title {
  font-size: 14px;
  font-weight: 800;
  text-transform: uppercase;
  margin: 0;
}
.gbb__inline-close {
  appearance: none;
  border: 0;
  background: none;
  font-size: 24px;
  line-height: 1;
  color: var(--gb-muted);
  cursor: pointer;
  min-width: 44px;
  min-height: 44px;
}
.gbb__inline-foot {
  margin-top: 12px;
}
.gbb__inline-foot .gbb__add {
  width: 100%;
}

/* ── option chips (shared by sheet + inline) ─────────────────────────────── */
.gbb__options {
  display: block;
}
.gbb__chip-row {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
  padding: 2px 2px 10px;
  margin: 0 -2px;
}
.gbb__chip-row::-webkit-scrollbar {
  height: 6px;
}
.gbb__chip-row::-webkit-scrollbar-thumb {
  background: var(--gb-line);
  border-radius: 999px;
}
.gbb__chip {
  flex: 0 0 140px;
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px;
  text-align: left;
  font: inherit;
  color: inherit;
  background: var(--gb-paper);
  border: 2px solid var(--gb-line);
  border-radius: var(--gb-radius);
  cursor: pointer;
  transition: border-color 0.15s ease, transform 0.06s ease;
}
.gbb__chip:active {
  transform: scale(0.98);
}
.gbb__chip--on {
  border-color: var(--gb-ink);
}
.gbb__chip--soldout {
  opacity: 0.6;
  cursor: not-allowed;
}
.gbb__chip-img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: var(--gb-radius-sm);
  background: var(--gb-soft);
}
.gbb__chip-img--ph {
  background: var(--gb-soft);
}
.gbb__chip-title {
  font-size: 13px;
  font-weight: 700;
  line-height: 1.25;
  color: var(--gb-ink);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.gbb__chip-price {
  font-size: 13px;
  font-weight: 800;
  color: var(--gb-ink);
}
.gbb__chip-badge {
  font-size: 10px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--gb-save);
}
.gbb__chip-badge--out {
  color: var(--gb-danger);
}
.gbb__empty {
  font-size: 13px;
  color: var(--gb-muted);
  padding: 18px 6px;
}

/* variant sub-row */
.gbb__variant-host {
  margin-top: 4px;
}
.gbb__variant-label {
  font-size: 12px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--gb-muted);
  margin: 4px 0 8px;
}
.gbb__variant-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.gbb__vchip {
  appearance: none;
  cursor: pointer;
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  min-height: 44px;
  padding: 8px 14px;
  border-radius: 999px;
  border: 2px solid var(--gb-line);
  background: var(--gb-paper);
  color: var(--gb-ink);
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.gbb__vchip--on {
  border-color: var(--gb-accent);
  background: var(--gb-accent);
  color: var(--gb-on-accent);
}
.gbb__vchip--soldout {
  color: var(--gb-muted);
  cursor: not-allowed;
  text-decoration: line-through;
}
.gbb__vchip-price {
  font-weight: 800;
  opacity: 0.85;
}
.gbb__vchip--capped {
  color: var(--gb-muted);
  cursor: not-allowed;
}

/* ── option selectors (Size / Colour … like a real PDP) ──────────────────── */
.gbb__optgroup {
  margin-top: 14px;
}
.gbb__optgroup:first-child {
  margin-top: 6px;
}
.gbb__optgroup-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 8px;
}
.gbb__optgroup-name {
  font-size: 12px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--gb-ink);
}
.gbb__optgroup-value {
  font-size: 12px;
  font-weight: 700;
  color: var(--gb-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 55%;
}
.gbb__optvals {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.gbb__optval {
  appearance: none;
  cursor: pointer;
  font: inherit;
  font-size: 14px;
  font-weight: 700;
  min-height: 44px;
  min-width: 44px;
  padding: 10px 16px;
  border-radius: 999px;
  border: 2px solid var(--gb-line);
  background: var(--gb-paper);
  color: var(--gb-ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: border-color 0.12s ease, background 0.12s ease, transform 0.06s ease;
}
.gbb__optval:active {
  transform: scale(0.96);
}
.gbb__optval--on {
  border-color: var(--gb-accent);
  background: var(--gb-accent);
  color: var(--gb-on-accent);
}
/* unreachable value given the current selection: muted + struck (color instead of
   low opacity so it stays >=3:1 legible — the shopper still needs to read WHICH
   size is gone). */
.gbb__optval--off {
  color: var(--gb-muted);
  background: var(--gb-soft);
  border-color: var(--gb-line);
  cursor: not-allowed;
  text-decoration: line-through;
  text-decoration-thickness: 1.5px;
}
.gbb__optval:disabled {
  cursor: not-allowed;
}

/* resolution footer under the selectors */
.gbb__optfoot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1.5px solid var(--gb-line);
}
.gbb__optfoot-status {
  font-size: 13px;
  font-weight: 700;
  color: var(--gb-muted);
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
}
.gbb__optfoot-status--err {
  color: var(--gb-danger);
}
.gbb__optfoot-pick {
  color: var(--gb-ink);
  font-weight: 800;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 20ch;
}
.gbb__optfoot-price {
  color: var(--gb-ink);
  font-weight: 800;
  white-space: nowrap;
}
.gbb__optadd {
  flex: 0 0 auto;
  appearance: none;
  border: 0;
  cursor: pointer;
  font: inherit;
  font-size: 13px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--gb-on-accent);
  background: var(--gb-accent);
  padding: 11px 18px;
  border-radius: 999px;
  min-height: 44px;
  white-space: nowrap;
  transition: opacity 0.15s ease, transform 0.06s ease;
}
.gbb__optadd:active {
  transform: scale(0.98);
}
.gbb__optadd:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

/* ── slot row: section counter pill ──────────────────────────────────────── */
.gbb__slot-counter {
  display: inline-block;
  margin-top: 4px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.02em;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1.5px solid var(--gb-line);
  color: var(--gb-muted);
}
.gbb__slot-counter--ok {
  border-color: var(--gb-save);
  color: var(--gb-save);
}

/* ── section tray (multi-select picker) ──────────────────────────────────── */
.gbb__section {
  margin-bottom: 12px;
  padding: 12px;
  border: 1.5px solid var(--gb-line);
  border-radius: var(--gb-radius-sm);
  background: var(--gb-soft);
}
.gbb__section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 8px;
}
.gbb__section-count {
  font-size: 13px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--gb-ink);
}
.gbb__section-count--ok {
  color: var(--gb-save);
}
.gbb__section-hint {
  font-size: 11px;
  font-weight: 700;
  color: var(--gb-muted);
  white-space: nowrap;
}
.gbb__section-list {
  display: grid;
  gap: 8px;
}
.gbb__pick {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px;
  background: var(--gb-paper);
  border: 1.5px solid var(--gb-line);
  border-radius: var(--gb-radius-sm);
}
.gbb__pick-img {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: 8px;
  object-fit: cover;
  background: var(--gb-soft);
}
.gbb__pick-img--ph {
  background: var(--gb-soft);
}
.gbb__pick-meta {
  flex: 1 1 auto;
  min-width: 0;
}
.gbb__pick-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--gb-ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.gbb__pick-sub {
  font-size: 12px;
  color: var(--gb-muted);
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.gbb__stepper {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 2px;
  border: 1.5px solid var(--gb-ink);
  border-radius: 999px;
  padding: 2px;
}
.gbb__step {
  appearance: none;
  border: 0;
  background: none;
  cursor: pointer;
  font: inherit;
  font-size: 18px;
  font-weight: 800;
  line-height: 1;
  color: var(--gb-ink);
  width: 44px;
  height: 44px;
  min-width: 44px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.gbb__step:active {
  background: var(--gb-soft);
}
.gbb__step:disabled {
  opacity: 0.3;
  cursor: not-allowed;
}
.gbb__step-qty {
  min-width: 22px;
  text-align: center;
  font-size: 14px;
  font-weight: 800;
  color: var(--gb-ink);
}

/* section chip add-state */
.gbb__chip-badge--in {
  color: var(--gb-ink);
}
.gbb__chip--capped {
  opacity: 0.6;
  cursor: not-allowed;
}

/* ── sticky footer ───────────────────────────────────────────────────────── */
.gbb__sticky {
  position: sticky;
  bottom: 0;
  z-index: 30;
  margin-top: 12px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 14px;
  background: var(--gb-paper);
  border: 2px solid var(--gb-ink);
  border-radius: var(--gb-radius);
  box-shadow: 0 -4px 18px rgba(0, 0, 0, 0.06);
}
/* On desktop the card clips overflow, so a sticky footer can't pin to the page.
   Render it as a clean static footer at the foot of the builder column instead.
   (Mobile keeps the pinned fixed bar via the max-width:749px rules below.) */
@media (min-width: 750px) {
  .gbb__builder .gbb__sticky {
    position: static;
    margin-top: 16px;
  }
}
.gbb__sticky-info {
  min-width: 0;
}
.gbb__dots {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 5px;
  margin-bottom: 5px;
}
.gbb__dot {
  width: 9px;
  height: 9px;
  border-radius: 999px;
  background: var(--gb-line);
}
.gbb__dot--on {
  background: var(--gb-accent);
}
.gbb__dots-count {
  font-size: 11px;
  font-weight: 700;
  color: var(--gb-muted);
  margin-left: 4px;
}
.gbb__price {
  font-size: 15px;
  display: flex;
  flex-direction: column;
  align-items: flex-start; /* children hug their content, don't stretch full width */
  gap: 4px;
}
/* was-price + current price share one baseline row; the save badge sits below. */
.gbb__price-line {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 6px;
}
.gbb__price strong {
  font-size: 16px;
  font-weight: 800;
  color: var(--gb-ink);
}
.gbb__price-was {
  font-size: 13px;
  font-weight: 600;
  color: var(--gb-muted);
  text-decoration: line-through;
}
.gbb__price-save {
  font-size: 12px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--gb-save);
}
/* Completed-bundle saving is the whole value prop — promote it to a filled pill on
   its own line so it never competes with the was-price for wrap space. */
.gbb__price-save--badge {
  align-self: flex-start; /* hug the text — no empty green trailing the label */
  font-size: 13px;
  color: var(--gb-on-accent);
  background: var(--gb-save);
  padding: 2px 8px;
  border-radius: 999px;
}
.gbb__price-note {
  font-size: 11px;
  color: var(--gb-muted);
}
/* Landing-page load error / retry (PDP blocks hide instead). */
.gbb__error {
  text-align: center;
  padding: 32px 20px;
}
.gbb__error-title {
  font-size: 16px;
  font-weight: 800;
  color: var(--gb-ink);
  margin: 0 0 4px;
}
.gbb__error-sub {
  font-size: 13px;
  color: var(--gb-muted);
  margin: 0 0 16px;
}
.gbb__add {
  /* Shrinkable. It used to be `flex: 0 0 auto` with nowrap, so a long label
     pushed the pill straight past the bar's right edge on a narrow phone. */
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  appearance: none;
  border: 0;
  cursor: pointer;
  font: inherit;
  font-size: 14px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--gb-on-accent);
  background: var(--gb-accent);
  padding: 13px 22px;
  border-radius: 999px;
  min-height: 48px;
  white-space: nowrap;
  transition: opacity 0.15s ease, transform 0.06s ease;
}
.gbb__add:active {
  transform: scale(0.98);
}
.gbb__add:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.gbb__add--busy {
  opacity: 0.6;
  cursor: progress;
}
/* Success confirmation on the button itself ("Added ✓"). opacity:1 overrides the
   :disabled dim that lingers while the best-effort gift line posts. */
.gbb__add--done {
  background: var(--gb-save);
  opacity: 1;
  cursor: default;
}
.gbb__add--done:disabled {
  opacity: 1;
}

/* ── bottom sheet (mobile) ───────────────────────────────────────────────── */
/* This dialog lives in the TOP LAYER on document.body, outside the mount and
   outside the theme's DOM. Two consequences it must survive:
   1. Every var() here needs a LITERAL fallback. If the token block above is ever
      missing — a stale CDN copy of this file on a PDP, a theme that resets
      custom properties — `background: var(--gb-paper)` is invalid at
      computed-value time and the sheet renders fully TRANSPARENT over the page.
   2. It is selected as `dialog.gbb__sheet` so a theme's own `dialog { … }` rules
      (Prestige styles its drawers this way) can't win on specificity. */
dialog.gbb__sheet {
  border: 0;
  padding: 0;
  margin: 0 auto;
  width: 100%;
  max-width: 560px;
  max-height: 88vh;
  border-radius: 20px 20px 0 0;
  background: var(--gb-paper, #ffffff);
  color: var(--gb-ink, #0a0a0a);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
    Arial, sans-serif;
  position: fixed;
  inset: auto 0 0 0;
  will-change: transform;
}
.gbb__sheet[open] {
  display: flex;
  flex-direction: column;
  animation: gbb-slide-up 0.24s cubic-bezier(0.2, 0.8, 0.2, 1);
}
@keyframes gbb-slide-up {
  from {
    transform: translateY(100%);
  }
  to {
    transform: translateY(0);
  }
}
@media (prefers-reduced-motion: reduce) {
  .gbb__sheet[open] {
    animation: none;
  }
}
.gbb__sheet::backdrop {
  background: rgba(0, 0, 0, 0.5);
}
.gbb__sheet-handle {
  width: 40px;
  height: 4px;
  border-radius: 999px;
  background: var(--gb-line);
  margin: 10px auto 4px;
}
.gbb__sheet-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 16px 12px;
  border-bottom: 1.5px solid var(--gb-line);
}
.gbb__sheet-title {
  font-size: 15px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  margin: 0;
}
.gbb__sheet-close {
  appearance: none;
  border: 0;
  background: none;
  font-size: 26px;
  line-height: 1;
  color: var(--gb-muted);
  cursor: pointer;
  min-width: 44px;
  min-height: 44px;
}
.gbb__sheet-body {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 14px 16px 6px;
  flex: 1 1 auto;
}
.gbb__sheet-foot {
  padding: 12px 16px;
  padding-bottom: max(12px, env(safe-area-inset-bottom));
  border-top: 1.5px solid var(--gb-line, #e6e6e6);
  background: var(--gb-paper, #ffffff);
}
/* Hidden on single-pick slots (no confirm step). `hidden` alone loses to the
   padding/display above, so state it. */
.gbb__sheet-foot[hidden] {
  display: none;
}
.gbb__sheet-add {
  width: 100%;
}

/* On desktop the bottom-sheet dialog (if ever shown) centers instead. */
@media (min-width: 750px) {
  .gbb__sheet {
    border-radius: 18px;
    margin: auto;
    max-height: 82vh;
    position: relative;
    bottom: auto;
  }
  .gbb__sheet[open] {
    animation: none;
  }
}

/* Lock body scroll while the sheet is open. */
body.gbb-scroll-lock {
  position: fixed;
  width: 100%;
  overflow: hidden;
}

/* ── toast ───────────────────────────────────────────────────────────────── */
.gbb__toast {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: max(20px, env(safe-area-inset-bottom));
  z-index: 2147483000;
  background: var(--gb-accent);
  color: var(--gb-on-accent);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
    Arial, sans-serif;
  font-size: 13px;
  font-weight: 700;
  padding: 11px 18px;
  border-radius: 999px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.25);
}
.gbb__toast--show {
  opacity: 1;
}

/* ── mobile sticky -> fixed bar + reserve space ──────────────────────────── */
@media (max-width: 749px) {
  .gbb__sticky {
    position: fixed;
    left: 10px;
    right: 10px;
    bottom: max(10px, env(safe-area-inset-bottom));
    margin: 0;
    gap: 10px;
    /* Extra room on the RIGHT so the CTA never sits under the storefront's
       floating chat bubble, which pins itself to the bottom-right corner above
       everything else. Without it the button is tappable in theory and covered
       in practice. */
    padding: 11px 60px 11px 14px;
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.18);
  }
  /* Tighter type so a short label still fits the narrowed pill. */
  .gbb__add {
    font-size: 13px;
    letter-spacing: 0.02em;
    padding: 12px 16px;
  }
  .gbb {
    margin-bottom: 96px; /* reserve room for the fixed bar */
  }
}

/* ── mobile polish: tighter, bigger tap targets, cleaner type ────────────── */
@media (max-width: 749px) {
  .gbb {
    margin: 14px 0 96px;
  }
  /* Non-card panels (locked state) keep their inner padding. The card keeps
     padding 0 so the hero stays edge-to-edge; the builder supplies its own. */
  .gbb__panel:not(.gbb__card) {
    padding: 14px;
    border-radius: var(--gb-radius);
  }
  .gbb__builder {
    padding: 14px;
  }
  .gbb__cover--img {
    min-height: 168px;
  }
  .gbb--hero-sm .gbb__cover--img {
    min-height: 112px;
  }
  .gbb--hero-lg .gbb__cover--img {
    min-height: 260px;
  }
  .gbb__cover .gbb__head {
    padding: 14px;
  }
  .gbb__cover--img .gbb__head {
    padding-top: 52px;
  }
  .gbb__title {
    font-size: 20px;
  }
  .gbb__slots {
    gap: 8px;
  }
  /* Roomier slot rows so the whole row is an easy 60px+ tap target. */
  .gbb__slot {
    min-height: 64px;
    padding: 12px 14px;
    gap: 12px;
  }
  .gbb__slot-label {
    font-size: 14.5px;
  }
  .gbb__slot-thumb {
    width: 44px;
    height: 44px;
  }
  /* The "Choose ->" / "Change" affordance reads as a clear, tappable cue. */
  .gbb__slot-cta {
    font-size: 13px;
  }
  .gbb__slot-change {
    font-size: 12px;
  }

  /* Larger product chips read better on a phone; snap cleanly. */
  .gbb__chip {
    flex-basis: 144px;
    border-radius: var(--gb-radius);
  }
  .gbb__chip-row {
    gap: 10px;
    scroll-snap-type: x mandatory;
    scroll-padding-left: 2px;
  }

  /* Sheet: edge-to-edge feel, comfortable reading width, safe-area aware. */
  .gbb__sheet-body {
    padding: 14px 16px 8px;
  }
  .gbb__sheet-title {
    font-size: 15px;
  }

  /* Option pills: full 44px targets, generous wrap. */
  .gbb__optval {
    font-size: 15px;
    padding: 11px 18px;
  }

  /* Footer: keep the price legible, button thumb-reachable on the right. */
  .gbb__add {
    padding: 13px 20px;
    min-height: 50px;
  }
  .gbb__price strong {
    font-size: 15px;
  }
  .gbb__dots {
    gap: 4px;
    margin-bottom: 4px;
  }
}

/* Hairline-crisp borders on retina; avoids muddy 2px lines on phones. */
@media (max-width: 749px) and (min-resolution: 2dppx) {
  .gbb__slot {
    border-width: 1px;
  }
}

/* ── DESKTOP CARD: 2-column layout ───────────────────────────────────────────
   When the CARD has room (its inline container >= 720px), present it as a proper
   card: a tall cover/summary column on the left and the slot builder on the
   right, with a comfortable max width. Uses a container query so it adapts to
   the PDP column AND the wide landing page; a @media fallback covers browsers
   without container-query support. NOTHING here applies on mobile. */
@container gbbcard (min-width: 720px) {
  .gbb__card {
    display: grid;
    grid-template-columns: minmax(300px, 42%) 1fr;
    align-items: stretch;
  }
  .gbb__cover {
    min-height: 100%;
    border-right: var(--gb-border-w, 2px) solid var(--gb-ink);
  }
  .gbb__cover--img {
    min-height: 420px;
  }
  .gbb--hero-sm .gbb__cover--img {
    min-height: 280px;
  }
  .gbb--hero-lg .gbb__cover--img {
    min-height: 560px;
  }
  .gbb__cover--plain {
    min-height: 320px;
  }
  .gbb__cover .gbb__head {
    padding: 24px;
  }
  .gbb__cover--img .gbb__head {
    padding-top: 24px;
  }
  .gbb__title {
    font-size: 30px;
  }
  .gbb__builder {
    padding: 24px;
    display: flex;
    flex-direction: column;
  }
  .gbb__slots {
    gap: 12px;
  }
  /* Roomier slot rows on desktop. */
  .gbb__slot {
    min-height: 68px;
    padding: 14px 18px;
  }
  .gbb__slot-thumb {
    width: 48px;
    height: 48px;
  }
  /* Desktop footer: static under the slots with a clear gap. (A prior `margin-top:
     auto` collapsed to 0 when the builder filled its column, making the footer
     touch the last slot row.) */
  .gbb__builder .gbb__sticky {
    position: static;
    margin-top: 16px;
  }
}

/* Fallback for browsers without container queries: switch on viewport width but
   only when the picker is NOT inside the mobile-first fixed-bar regime. */
@supports not (container-type: inline-size) {
  @media (min-width: 960px) {
    .gbb__card {
      display: grid;
      grid-template-columns: minmax(300px, 42%) 1fr;
      align-items: stretch;
      max-width: 1040px;
      margin-left: auto;
      margin-right: auto;
    }
    .gbb__cover {
      border-right: var(--gb-border-w, 2px) solid var(--gb-ink);
    }
    .gbb__cover--img {
      min-height: 420px;
    }
    .gbb--hero-sm .gbb__cover--img {
      min-height: 280px;
    }
    .gbb--hero-lg .gbb__cover--img {
      min-height: 560px;
    }
    .gbb__cover--plain {
      min-height: 320px;
    }
    .gbb__cover .gbb__head {
      padding: 24px;
    }
    .gbb__cover--img .gbb__head {
      padding-top: 24px;
    }
    .gbb__title {
      font-size: 30px;
    }
    .gbb__builder {
      padding: 24px;
      display: flex;
      flex-direction: column;
    }
    .gbb__builder .gbb__sticky {
      position: static;
      margin-top: 16px;
    }
  }
}
