/* Apex lux — Stripe / PayPal calm (sitewide) */

/* ── Decal colour dropdown ─────────────────────────────────────────── */
.column-decal-colour {
  display: block;
  margin-top: 0.5rem;
  width: 100%;
  box-sizing: border-box;
  padding: 0.5rem 0.625rem;
  border: 1.5px solid var(--border-light, #e5e7eb);
  border-radius: 0.5rem;
  font-family: inherit;
  font-size: 0.9375rem;
  background: white;
  color: var(--text, #111827);
  transition: border-color 0.15s;
}
.column-decal-colour:focus {
  outline: none;
  border-color: var(--accent, #7a1528);
}

/* ── Build math price breakdown ─────────────────────────────────────── */
.build-math__total {
  display: block;
  font-size: 1.25rem;
  font-weight: 700;
  color: var(--text, #111827);
  margin-bottom: 0.25rem;
}
.build-math__line {
  display: block;
  font-size: 0.875rem;
  color: var(--lux-muted, #6b7280);
  line-height: 1.5;
}

/* ── Coming-soon category card ─────────────────────────────────────── */
.category-card--soon {
  opacity: 0.82;
  cursor: default;
  pointer-events: none; /* disable navigation; lightbox still works via capture */
}
/* Re-enable pointer events on the image so lightbox can fire */
.category-card--soon img[data-lightbox] {
  pointer-events: auto;
  cursor: zoom-in;
}
.category-card--soon:hover {
  background: transparent;
}
.category-card--soon .category-card__name {
  color: var(--text, #111827);
}
.category-card__soon-badge {
  display: inline-block;
  margin-top: 0.25rem;
  padding: 0.1875rem 0.5rem;
  background: var(--lux-line, #e5e7eb);
  color: var(--lux-muted, #6b7280);
  border-radius: 0.375rem;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.category-card__status-badge {
  display: inline-block;
  margin-top: 0.25rem;
  padding: 0.1875rem 0.5rem;
  background: #fbe4e8;
  color: var(--lux-accent, #7a1528);
  border-radius: 0.375rem;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* Shop back-link ("← Label") — shared across every category, subcategory
   and product page (previously duplicated byte-for-byte as an identical
   inline <style> block, or an inline style="" attribute, on ~30 separate
   pages). Stays plain text with an arrow — no border, no background, no
   pill — just bolder and recoloured into the same maroon/pink palette used
   everywhere else on the site, with a colour shift + underline on hover
   and keyboard focus as the only interactive treatment. */
.apex-lux .product-page__back {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--lux-accent, #7a1528);
  text-decoration: none;
  margin-bottom: 0.5rem;
}

.apex-lux .product-page__back:hover,
.apex-lux .product-page__back:focus-visible {
  color: var(--brand-burgundy-dark, #620000);
  text-decoration: underline;
}

body.apex-lux {
  --lux-bg: #ffffff;
  --lux-surface: #fafafa;
  --lux-line: #ebe6e8;
  --lux-text: #1a1214;
  --lux-muted: #6e5c63;
  --lux-accent: #7a1528;
  --lux-radius: 8px;
  --lux-max: 28rem;

  /* Brighter/richer brand burgundy for PRIMARY CTA BUTTON BACKGROUNDS only.
     Kept identical to css/styles.css :root — the two scopes do not cascade,
     so any change here must be mirrored there. */
  --brand-burgundy: #880000;
  --brand-burgundy-dark: #620000;
  --brand-burgundy-chrome: radial-gradient(120% 88% at 50% 0%, rgba(255, 255, 255, 0.32) 0%, rgba(255, 255, 255, 0.06) 42%, rgba(255, 255, 255, 0) 62%), linear-gradient(180deg, #9d1a1a 0%, #880000 48%, #660000 100%);
  --brand-burgundy-chrome-hover: radial-gradient(120% 88% at 50% 0%, rgba(255, 255, 255, 0.4) 0%, rgba(255, 255, 255, 0.1) 42%, rgba(255, 255, 255, 0) 62%), linear-gradient(180deg, #ad2222 0%, #940f0f 48%, #6f0000 100%);
  
  /* Corporate theme colors */
  --corp-primary: #1e3a5f;
  --corp-accent: #d4af37;
  --corp-surface: #f8f9fb;
  --corp-text: #1a1a1a;
  --corp-muted: #5a6c7d;
  --corp-light: #e8f0f7;
  background: var(--lux-bg);
  color: var(--lux-text);
  font-family: var(--font-ui, "DM Sans", system-ui, sans-serif);
  -webkit-font-smoothing: antialiased;
  min-height: 100dvh;
}

/* —— Chrome —— */
.apex-lux .site-top-shell {
  background: rgba(255, 255, 255, 0.96);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--lux-line);
  box-shadow: none;
}

.apex-lux .site-header {
  /* Left padding trimmed slightly so the logo sits closer to the edge;
     right padding (nav side) is left untouched so nav position doesn't move. */
  padding: 0.3rem 1rem 0.3rem 0.65rem;
}

.apex-lux .logo-link {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  height: 100%;
  line-height: 0;
}

.apex-lux .logo-img {
  height: 5rem;
  max-height: none;
  width: auto;
  max-width: none;
  object-fit: contain;
  object-position: center;
  filter: none;
}

@media (min-width: 720px) {
  .apex-lux .site-header {
    padding: 0.4rem 1.5rem 0.4rem 1rem;
  }

  .apex-lux .logo-img {
    height: 6.25rem;
  }
}

/* ── Header navigation — two centred plain-text rows ──────────────────────
   Replaces the old glossy-pill Home/Shop buttons. .header-nav is now a
   2-column grid ([links][cart]) so the links wrapper can be truly centred
   in the space between the logo and Cart, regardless of either's width —
   `justify-self: center` inside the 1fr column, not a flex space-between
   trick, which would only center within the leftover space, not the full
   middle area. Built entirely by js/site-chrome.js's rebuildHeaderNav() —
   no per-page markup. Header height must not increase: both rows/gaps are
   deliberately tight (line-height 1, small row-gap), which comfortably
   fits under the logo's own rendered height (the actual height driver —
   see .apex-lux .logo-img below), not the other way around. */
.apex-lux .header-nav {
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 0.5rem;
}

.apex-lux .header-nav-links {
  justify-self: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.1rem;
  min-width: 0; /* grid items default to min-width:auto (content size) — without this the 1fr column refuses to shrink below the rows' natural width and overlaps Cart on narrow screens */
  max-width: 100%;
}

.apex-lux .header-nav-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
  line-height: 1;
  min-width: 0;
}

.apex-lux .header-nav .nav-link {
  position: relative;
  display: inline-block;
  padding: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  color: var(--lux-text, #1a1a1a);
  font-family: "Poppins", var(--font-ui, "DM Sans", system-ui, sans-serif);
  font-weight: 500;
  font-size: 0.52rem;
  letter-spacing: 0.01em;
  white-space: nowrap;
  text-decoration: none;
  text-underline-offset: 2px;
  transition: color 0.15s ease;
}

.apex-lux .header-nav .nav-link:hover,
.apex-lux .header-nav .nav-link:focus-visible {
  color: var(--lux-accent);
  text-decoration: underline;
}

.apex-lux .header-nav .nav-link.is-active {
  color: var(--lux-accent);
  text-decoration: underline;
  font-weight: 600;
}

/* Progressive size steps between the smallest supported phone (320px) and
   the 480px tier below — the old rule jumped straight from 0.52rem to
   0.68rem at 480px, leaving every common phone width in between (375/390/
   393/430) stuck at the tiny base size despite having visibly more room
   than a 320px screen. 320px itself stays closest to the original size —
   there genuinely isn't much spare width there (logo + Cart pill leave
   only ~136px for both nav rows, and the bottom row with the search icon
   is already the tighter of the two) — everything wider grows from there. */
@media (min-width: 375px) {
  .apex-lux .header-nav-row {
    gap: 0.4rem;
  }
  .apex-lux .header-nav .nav-link {
    font-size: 0.6rem;
  }
}

@media (min-width: 393px) {
  .apex-lux .header-nav-row {
    gap: 0.45rem;
  }
  .apex-lux .header-nav .nav-link {
    font-size: 0.64rem;
  }
}

@media (min-width: 430px) {
  .apex-lux .header-nav-row {
    gap: 0.55rem;
  }
  .apex-lux .header-nav .nav-link {
    font-size: 0.68rem;
  }
}

@media (min-width: 480px) {
  .apex-lux .header-nav-row {
    gap: 0.75rem;
  }
  .apex-lux .header-nav .nav-link {
    font-size: 0.72rem;
  }
}

@media (min-width: 720px) {
  .apex-lux .header-nav-links {
    gap: 0.2rem;
  }
  .apex-lux .header-nav-row {
    gap: 1.1rem;
  }
  .apex-lux .header-nav .nav-link {
    font-size: 0.8rem;
    letter-spacing: 0.04em;
  }
}

/* —— Site search —— now the final item of the second nav row (after
   Colour Chart), injected by js/site-chrome.js. Icon-only control, no
   underline (excluded from .nav-link entirely — it's a <button>, not an
   <a>, so the hover/active/is-active text rules above never apply to it).
   Sized to sit comfortably inline with the row's text without pushing the
   row taller than the text itself. */
.apex-lux .header-nav-row--bottom {
  gap: 0.45rem;
}
@media (min-width: 375px) {
  .apex-lux .header-nav-row--bottom {
    gap: 0.5rem;
  }
}
@media (min-width: 430px) {
  .apex-lux .header-nav-row--bottom {
    gap: 0.55rem;
  }
}
@media (min-width: 480px) {
  .apex-lux .header-nav-row--bottom {
    gap: 0.6rem;
  }
}
@media (min-width: 720px) {
  .apex-lux .header-nav-row--bottom {
    gap: 0.85rem;
  }
}

.apex-lux .header-nav .site-search__toggle {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  height: 1.05rem;
  width: 1.05rem;
  padding: 0;
  border: none;
  border-radius: 999px;
  background: none;
  box-shadow: none;
  color: var(--lux-accent);
  cursor: pointer;
  transition: opacity 0.15s ease, transform 0.15s ease;
}
@media (min-width: 375px) {
  .apex-lux .header-nav .site-search__toggle {
    height: 1.15rem;
    width: 1.15rem;
  }
}
@media (min-width: 430px) {
  .apex-lux .header-nav .site-search__toggle {
    height: 1.2rem;
    width: 1.2rem;
  }
}

.apex-lux .header-nav .site-search__toggle:hover,
.apex-lux .header-nav .site-search__toggle.is-active {
  opacity: 0.72;
}

.apex-lux .header-nav .site-search__toggle:active {
  transform: scale(0.92);
}

.apex-lux .header-nav .site-search__toggle svg {
  width: 100%;
  height: 100%;
  stroke: var(--lux-accent);
}

@media (min-width: 720px) {
  .apex-lux .header-nav .site-search__toggle {
    height: 1.2rem;
    width: 1.2rem;
  }
}

.apex-lux .site-search {
  display: inline-flex;
}

/* position:fixed with top/left set inline by js/site-chrome.js (viewport-
   relative, computed from the toggle's own on-screen position each time the
   panel opens) — a CSS-only anchor (position:absolute under the toggle)
   can't guarantee the panel stays on-screen, since the toggle's horizontal
   position among Home/Shop/Cart varies and isn't reliably close to either
   viewport edge, especially on narrow screens. */
.apex-lux .site-search__panel {
  position: fixed;
  z-index: 20;
  background: #fff;
  border: 1px solid var(--lux-line);
  border-radius: 12px;
  box-shadow: 0 12px 32px rgba(26, 15, 18, 0.14), 0 2px 8px rgba(26, 15, 18, 0.06);
  padding: 0.6rem;
  font-family: var(--font-ui, "DM Sans", system-ui, sans-serif);
}

.apex-lux .site-search__panel[hidden] {
  display: none;
}

.apex-lux .site-search__field {
  position: relative;
  display: flex;
  align-items: center;
}

.apex-lux .site-search__field svg {
  position: absolute;
  left: 0.65rem;
  width: 0.9rem;
  height: 0.9rem;
  stroke: var(--lux-muted);
  pointer-events: none;
}

.apex-lux .site-search__input {
  width: 100%;
  height: 2.35rem;
  padding: 0 0.75rem 0 2.15rem;
  border: 1px solid var(--lux-line);
  border-radius: var(--lux-radius);
  background: var(--lux-surface);
  color: var(--lux-text);
  font-family: inherit;
  font-size: 0.875rem;
  transition: border-color 0.15s ease;
}

.apex-lux .site-search__input::placeholder {
  color: var(--lux-muted);
}

.apex-lux .site-search__input:focus {
  outline: none;
  border-color: var(--lux-accent);
  background: #fff;
}

.apex-lux .site-search__results {
  margin: 0.5rem 0 0;
  padding: 0;
  list-style: none;
  max-height: 20rem;
  overflow-y: auto;
}

.apex-lux .site-search__results[hidden] {
  display: none;
}

/* Specificity note: css/apex-ui.css (loaded on the same pages) has its own
   unscoped, un-namespaced ".header-nav a:not(.cart-trigger)" /
   ":hover"/".is-active" rules — a plain descendant selector with no ">"
   restriction, so it still technically matches these nested result links
   and (once you include its "a"/":hover" type/pseudo-class components) is
   MORE specific than a same-class-count .apex-lux rule. Qualifying with the
   .site-search ancestor class adds the specificity needed to reliably win
   without touching apex-ui.css itself. */
.apex-lux .site-search .site-search__result {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  min-height: 2.75rem;
  padding: 0.4rem 0.5rem;
  border-radius: 10px;
  text-decoration: none;
  color: inherit;
  cursor: pointer;
}

.apex-lux .site-search .site-search__result:hover,
.apex-lux .site-search .site-search__result.is-active {
  background: var(--pink, #f8e8ec);
}

.apex-lux .site-search__result-thumb {
  flex: 0 0 auto;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 8px;
  object-fit: cover;
  background: var(--lux-surface);
}

.apex-lux .site-search__result-text {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.05rem;
}

.apex-lux .site-search__result-name {
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--lux-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.apex-lux .site-search__result-meta {
  font-size: 0.6875rem;
  color: var(--lux-muted);
}

.apex-lux .site-search__empty {
  padding: 0.75rem 0.5rem;
  font-size: 0.8125rem;
  color: var(--lux-muted);
  text-align: center;
  line-height: 1.5;
}

.apex-lux .site-search__colour-hint {
  color: var(--lux-accent);
  font-weight: 600;
  text-decoration: underline;
}

/* Header CART button — restored to the real supplied artwork (reverted
   after an earlier pass wrongly replaced it with a text pill). The image
   is used uncropped-in-file, zoomed/positioned via background-size/
   position to trim the artwork's own transparent-white margin — the
   source file itself is never edited — sized to the button box using the
   pill's own aspect ratio. The literal "Cart" text stays in the
   accessible name but visually transparent, matching the artwork's own
   "CART" wordmark; the live count (below) is now plain text positioned
   after that wordmark instead of the small circle badge it used to sit
   in, which is what caused it to overlap/misalign. */
.apex-lux .cart-trigger {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  height: 2.25rem;
  width: 4.85rem;
  aspect-ratio: 2.15;
  background-color: transparent;
  background-image: url("../assets/buttons/cart-button.png");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 155.84% 223.46%;
  color: transparent !important;
  border: none;
  border-radius: 999px;
  box-shadow: none;
  padding: 0;
  font-family: "Poppins", var(--font-ui, "DM Sans", system-ui, sans-serif);
  font-size: 0.8125rem;
  font-weight: 500;
  transition: filter 0.2s ease, transform 0.15s ease;
}

.apex-lux .cart-trigger:hover {
  filter: brightness(1.06);
}

.apex-lux .cart-trigger:active {
  transform: scale(0.97);
}

.apex-lux .cart-trigger::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(115deg, transparent 35%, rgba(255, 255, 255, 0.55) 50%, transparent 65%);
  transform: translateX(-120%);
  pointer-events: none;
}

.apex-lux .cart-trigger:hover::after,
.apex-lux .cart-trigger:focus-visible::after {
  animation: apex-btn-shine 1.1s ease-in-out;
}

/* Plain inline text matching "Cart" exactly — same font-family/size/
   weight/colour it inherits from .cart-trigger, no circle/badge/background
   of its own. A small margin-left is the only separation from the word
   "Cart", so it reads as "Cart 3" rather than overlapping or floating.
   `left` is measured from the artwork itself: the "CART" wordmark's own
   right edge sits at ~57% of the button's width, so this starts right
   after the "T" with a small gap. Burgundy (var(--lux-accent), the same
   brand colour used elsewhere on the site) for clear visibility against
   the artwork, matching "Cart"'s own typography (the real "Cart" text
   node is invisible behind the artwork) — no circle/pill background of
   any kind, which is what let the count overlap/misread before. */
.apex-lux .cart-trigger__count {
  position: absolute;
  left: 60%;
  top: 50%;
  transform: translateY(-50%);
  display: inline-block;
  color: var(--lux-accent);
  font-family: "Poppins", var(--font-ui, "DM Sans", system-ui, sans-serif);
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

@media (min-width: 720px) {
  .apex-lux .cart-trigger {
    height: 2.5rem;
    width: 5.4rem;
  }
}

/* Homepage "Order balloon bouquets" CTA — styled to be visually identical
   to the header's Cart button above: same height, border-radius, font-
   family/weight/size, and hover/active/shine mechanics (the transition,
   active-press scale, and shine-sweep pseudo-element + the shared
   apex-btn-shine keyframe are reused verbatim from .cart-trigger via the
   combined selectors below, not redeclared). Cart itself is a fixed-
   aspect-ratio PNG artwork button with its text hidden (color: transparent)
   and zero padding — neither is reusable for a full, visible sentence of
   text, so the same pink/maroon gradient this site already uses elsewhere
   to visually replicate the Cart artwork on a real text pill (see
   .header-nav .site-search__toggle) is used here instead, with padding
   sized to keep the text legible inside the pill's curved ends. */
.apex-lux .home-cta--cart-match {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  height: 2.25rem;
  padding: 0 1.1rem;
  background: linear-gradient(160deg, #fdf6f8 0%, var(--pink, #f8e8ec) 55%, var(--pink-deep, #e8b4c4) 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.65), 0 2px 8px rgba(122, 21, 40, 0.14);
  color: var(--lux-accent);
  text-decoration: none;
  text-align: center;
}

.apex-lux .home-cta--cart-match,
.apex-lux .cart-trigger {
  border: none;
  border-radius: 999px;
  font-family: "Poppins", var(--font-ui, "DM Sans", system-ui, sans-serif);
  font-size: 0.8125rem;
  font-weight: 500;
  transition: filter 0.2s ease, transform 0.15s ease;
}

.apex-lux .home-cta--cart-match:hover,
.apex-lux .cart-trigger:hover {
  filter: brightness(1.06);
}

.apex-lux .home-cta--cart-match:active,
.apex-lux .cart-trigger:active {
  transform: scale(0.97);
}

.apex-lux .home-cta--cart-match::after,
.apex-lux .cart-trigger::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(115deg, transparent 35%, rgba(255, 255, 255, 0.55) 50%, transparent 65%);
  transform: translateX(-120%);
  pointer-events: none;
}

.apex-lux .home-cta--cart-match:hover::after,
.apex-lux .home-cta--cart-match:focus-visible::after,
.apex-lux .cart-trigger:hover::after,
.apex-lux .cart-trigger:focus-visible::after {
  animation: apex-btn-shine 1.1s ease-in-out;
}

@media (min-width: 720px) {
  .apex-lux .home-cta--cart-match {
    height: 2.5rem;
    padding: 0 1.35rem;
  }
}

.apex-lux .promo-bar,
.apex-lux .hifloat-bar {
  background: var(--lux-surface);
  border-top: none;
  border-bottom: 1px solid var(--lux-line);
  padding: 0.5rem 1rem;
}

/* The promo bar is now the scrolling marquee at every width, and the marquee
   manages its own internal padding. Zero the lux side/vertical padding here
   (higher specificity than styles.css's .promo-bar.hifloat-bar) so the banner
   hugs the full-bleed marquee on apex-lux pages at all breakpoints. */
.apex-lux .promo-bar.hifloat-bar,
.apex-lux .hifloat-bar.promo-bar {
  padding: 0;
  margin: 0;
  /* Soft brand pink instead of the plain lux surface, framed with thin
     pink-deep borders top and bottom — same variables used for selected
     colour tiles elsewhere on the site, so the banner reads as part of the
     same design language rather than a one-off colour. */
  background: var(--pink, #f8e8ec);
  border-top: 1px solid var(--pink-deep, #e8b4c4);
  border-bottom: 1px solid var(--pink-deep, #e8b4c4);
}

/* Shimmer: a soft diagonal highlight sweeps across the pink banner on a
   slow loop — same technique as the header CART button's hover shine
   (linear-gradient + translateX), just continuous and much subtler/slower
   so it reads as a gentle glow rather than a flashy effect. Positioned on
   .promo-marquee (already overflow:hidden for the scrolling text) so the
   sweep never causes horizontal overflow. */
.apex-lux .promo-marquee {
  position: relative;
}

.apex-lux .promo-marquee::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, transparent 40%, rgba(255, 255, 255, 0.55) 50%, transparent 60%);
  transform: translateX(-120%);
  animation: apex-promo-shimmer 9s ease-in-out infinite;
  pointer-events: none;
  will-change: transform;
}

/* Retuned: the previous 0%,30% / 70%,100% hold-then-dart shape compressed
   all the actual movement into ~40% of the loop, which read as a quick,
   almost random flick rather than a slow glow. Sweeping evenly across the
   full duration (plus a longer 9s duration) keeps it continuous and smooth
   throughout instead of holding still and then darting. */
@keyframes apex-promo-shimmer {
  0% {
    transform: translateX(-120%);
  }
  100% {
    transform: translateX(120%);
  }
}

/* Reduced motion: freeze the sweep and the marquee scroll (marquee's own
   reduced-motion handling lives in styles.css); replace the moving shimmer
   with a static soft glow so the banner still reads as "glowing" pink
   without any motion. */
@media (prefers-reduced-motion: reduce) {
  .apex-lux .promo-marquee::after {
    animation: none;
    transform: none;
    inset: 0;
    background: radial-gradient(120% 140% at 50% 0%, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0) 70%);
  }
}

.apex-lux .promo-bar__text,
.apex-lux .hifloat-bar__text {
  font-size: 0.75rem;
  font-weight: 400;
  color: var(--lux-muted);
}

.apex-lux .promo-bar__chip {
  background: transparent;
  border: none;
  padding: 0;
  font-weight: 400;
  color: var(--lux-muted);
}

.apex-lux .promo-bar__chip strong,
.apex-lux .hifloat-bar__text strong {
  font-weight: 600;
  color: var(--lux-text);
  text-transform: none;
  letter-spacing: 0;
  font-size: inherit;
}

.apex-lux .site-footer__contact,
.apex-lux .site-footer__nap,
.apex-lux .site-footer__copy {
  margin: 0.35rem 0 0;
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--lux-muted);
  text-align: center;
}

/* Contact line (email/phone) sits above the nav links, in the same quiet
   weight as the copyright line rather than competing with the nav row's
   pill-style links — this is plain reference info, not navigation. */
.apex-lux .site-footer__contact {
  font-weight: 500;
  letter-spacing: 0.01em;
}

.apex-lux .site-footer__contact a {
  color: var(--lux-text);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color 0.15s ease, color 0.15s ease;
}

.apex-lux .site-footer__contact a:hover,
.apex-lux .site-footer__contact a:focus-visible {
  color: var(--lux-accent);
  border-bottom-color: currentColor;
}

/* Links use the same maroon accent + soft-pink hover chip already
   established elsewhere on the site (header nav pills, selected-tile
   states) rather than a plain underline, so the footer reads as part of
   the same pink/maroon visual language instead of a generic link list. */
.apex-lux .site-footer__nap a {
  color: var(--lux-accent);
  font-weight: 500;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  padding: 0.15rem 0.4rem;
  margin: -0.15rem -0.05rem;
  border-radius: 999px;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.apex-lux .site-footer__nap a:hover,
.apex-lux .site-footer__nap a:focus-visible {
  background: var(--pink, #f8e8ec);
  color: var(--brand-burgundy-dark, #620000);
}

.apex-lux .site-footer__nap svg {
  flex-shrink: 0;
}

/* Copyright — a hairline pink-deep divider (same token as the promo
   banner's own top/bottom borders) separates it from the links above so
   it visually complements rather than competes with them, with slightly
   wider letter-spacing for a quieter, more considered feel. */
.apex-lux .site-footer__copy {
  margin-top: 0.6rem;
  padding-top: 0.55rem;
  border-top: 1px solid var(--pink-deep, #e8b4c4);
  letter-spacing: 0.02em;
}

/* —— Layout shell —— */
.apex-lux .lux-page,
.apex-lux .shell {
  max-width: var(--lux-max);
  margin: 0 auto;
  padding: 1.5rem 1.5rem 2rem;
}

@media (min-width: 720px) {
  /* Site-wide desktop content width — a single responsive token so every
     container below grows/shrinks together instead of each page carrying
     its own fixed max-width. Scales smoothly between laptop and large
     monitor widths rather than jumping to one fixed size. Unchanged from
     the original value — standard/narrow desktop keeps its existing width;
     only the >=1440px tier below goes wider. */
  body.apex-lux {
    /* Was clamp(40rem, 78vw, 72rem) — the 72rem (1152px) ceiling made
       standard/narrow desktop (720-1439px) content stop noticeably short
       of the viewport well before the 1440px tier even kicks in. Raised
       modestly (76rem ceiling, 82vw target) — deliberately NOT pushed as
       far as the >=1440px tier below, so narrow desktop/tablet never goes
       wide enough to feel cramped. */
    --lux-max: clamp(40rem, 82vw, 76rem);
  }

  .apex-lux .lux-page,
  .apex-lux .shell {
    max-width: var(--lux-max);
    padding: 2rem 2rem 3rem;
  }
}

/* .category-main (the 3 Number Tower range/listing pages) had no width or
   padding rule at any breakpoint before this — deliberately left that way
   below 960px (unchanged tablet/narrow-desktop/mobile appearance) and only
   constrained at "desktop" and up, matching .config-main's own tiers so
   every subcategory page ends up on the same shared width system. */
@media (min-width: 960px) {
  .apex-lux .category-main {
    max-width: 1160px;
    margin: 0 auto;
    padding: 2rem 2.5rem 3rem;
  }
}

/* Wide desktop only (large monitors) — every container that already tracks
   --lux-max (.lux-page/.shell above, .cart-page, .config-main below)
   widens together from one shared token. Does not touch mobile, tablet, or
   the 720-1439px "standard/narrow desktop" tier above, which keeps its
   current width unchanged. */
@media (min-width: 1440px) {
  body.apex-lux {
    /* Was clamp(72rem, 82vw, 90rem) — the 90rem (1440px) ceiling meant any
       screen wider than 1440px (e.g. 1920px) flatlined at a fixed 1440px
       of content, using well under 80% of a large monitor. Raised to a
       112rem (1792px) ceiling at 88vw target — still leaves comfortable,
       reasonable edge padding (~64px per side at 1920px) rather than
       Hug & Kiss's near-zero-padding, full-bleed treatment. */
    --lux-max: clamp(76rem, 88vw, 112rem);
  }

  .apex-lux .category-main {
    max-width: 1760px;
  }
}

.apex-lux .category-header.lux-page__header {
  text-align: center;
}

.apex-lux .lux-page__label {
  margin: 0 0 0.75rem;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--lux-muted);
}

.apex-lux .lux-page__title,
.apex-lux .shop-hub__intro h1,
.apex-lux .config-intro h1,
.apex-lux .cart-page__head h1,
.apex-lux .success-main h1 {
  margin: 0;
  font-family: inherit;
  font-size: clamp(1.625rem, 7vw, 2rem);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.03em;
  color: var(--lux-text);
}

.apex-lux .success-main .lead {
  margin: 0.75rem 0 0;
  font-size: 1rem;
  line-height: 1.55;
  color: var(--lux-muted);
  max-width: 22em;
}

.apex-lux .lead,
.apex-lux .shop-hub__intro .lead,
.apex-lux .config-intro .lead,
.apex-lux .lux-page__desc {
  margin: 0.75rem 0 0;
  font-size: 0.6875rem;
  line-height: 1.4;
  color: var(--lux-muted);
  max-width: 26rem;
  /* Mobile-only breathing room (reset to 0 at >=720px below). This can't
     rely on an ancestor's own side padding or on max-width + margin:auto
     centring — margin:auto only centres once the viewport EXCEEDS
     max-width (26rem/416px), which is never true on a phone, so on some
     pages (e.g. the Mini/Mega Number Stack range headers'
     .lux-page__desc, whose immediate wrapper carries no padding of its
     own) the text was rendering flush to both screen edges. Padding the
     description itself guarantees the inset regardless of which
     page/ancestor it's nested in. */
  padding-inline: 1rem;
}

@media (min-width: 720px) {
  /* Desktop description font size matches .lux-page__label's existing
     0.8125rem (the "Sydney & Hills District · …" line) — applies globally
     to every category/product description that uses .lead, site-wide.
     Mobile keeps its own smaller size above, unchanged. */
  .apex-lux .lead,
  .apex-lux .shop-hub__intro .lead,
  .apex-lux .config-intro .lead,
  .apex-lux .lux-page__desc {
    font-size: 0.8125rem;
    line-height: 1.5;
    max-width: 32rem;
    /* Desktop/tablet never needed the mobile-only inset above — every
       desktop container already has its own side padding and/or the
       viewport genuinely exceeds max-width so margin:auto centres it. */
    padding-inline: 0;
  }
}

/* Product/category heading tagline — centred under the H1 on every product
   page (mobile + desktop). The .lead block above only sets type; this centres
   the paragraph and its own max-width box so it sits under the heading.
   .lux-page__desc (category/sub-category hub headers) reuses the identical
   product-page typography above, and is centred here the same way so hub
   pages match product pages exactly. */
.apex-lux .config-intro .lead,
.apex-lux .category-header.lux-page__header .lux-page__desc {
  margin-inline: auto;
  text-align: center;
}

/* An inline text link inside a .lead/.lux-page__desc description (e.g.
   Helium Bouquet Basics' "See our Helium Number Bouquets" cross-link) —
   without this it would fall back to the browser's default blue/underline,
   which clashes with the brand palette used everywhere else. Same accent
   colour + hover treatment as .product-page__back above. */
.apex-lux .lead a,
.apex-lux .lux-page__desc a {
  color: var(--lux-accent, #7a1528);
  text-decoration: underline;
}
.apex-lux .lead a:hover,
.apex-lux .lead a:focus-visible,
.apex-lux .lux-page__desc a:hover,
.apex-lux .lux-page__desc a:focus-visible {
  color: var(--brand-burgundy-dark, #620000);
}

/* "From $X" appended to a product's .lead description (or standing alone
   when there's no description yet) — bold, deep brand red, same font-size
   as the surrounding description text (inherited, not overridden here). */
.apex-lux .lead-price {
  font-weight: 700;
  color: var(--lux-accent, var(--maroon, #7a1528));
}

.apex-lux .eyebrow {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--lux-muted);
  margin: 0 0 0.5rem;
}

.apex-lux .breadcrumb {
  font-size: 0.8125rem;
  color: var(--lux-muted);
  margin-bottom: 1.25rem;
}

.apex-lux .breadcrumb a {
  color: var(--lux-muted);
  font-weight: 500;
}

.apex-lux .breadcrumb a:hover {
  color: var(--lux-accent);
}

/* —— Buttons —— */
.apex-lux .btn {
  font-family: inherit;
  font-weight: 500;
  border-radius: var(--lux-radius);
  box-shadow: none;
  letter-spacing: 0;
}

.apex-lux .btn-primary {
  background: var(--brand-burgundy);
  background: var(--brand-burgundy-chrome);
  color: #fff;
  box-shadow: 0 3px 14px rgba(136, 0, 0, 0.24), inset 0 1px 0 rgba(255, 255, 255, 0.22);
}

.apex-lux .btn-primary:hover:not(:disabled) {
  background: var(--brand-burgundy-chrome-hover);
  transform: none;
}

.apex-lux .btn-primary:focus-visible {
  outline: 2px solid var(--brand-burgundy-dark);
  outline-offset: 2px;
}

.apex-lux .btn-glow:hover {
  transform: none;
  box-shadow: none;
}

.apex-lux .btn-ghost {
  background: transparent;
  color: var(--lux-muted);
  border: 1px solid var(--lux-line);
}

.apex-lux .btn:disabled {
  opacity: 0.45;
}

/* —— Footer —— */
.apex-lux .site-footer,
.apex-lux .site-footer--slim,
.apex-lux .site-footer--lux {
  background: var(--lux-bg);
  color: var(--lux-muted);
  border-top: 1px solid var(--lux-line);
  padding: 2rem 1.5rem calc(1.75rem + var(--safe-bottom));
  text-align: center;
  max-width: var(--lux-max);
  margin: 0 auto;
}

.apex-lux .site-footer .footer-logo {
  display: none;
}

.apex-lux .site-footer p {
  margin: 0.2rem 0;
  font-size: 0.8125rem;
  opacity: 1;
}

.apex-lux .site-footer a {
  color: var(--lux-accent);
  font-weight: 500;
  text-decoration: none;
}

.apex-lux .site-footer a:hover {
  text-decoration: underline;
}

.apex-lux .site-footer__brand {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--lux-text);
  margin-bottom: 0.35rem;
  text-align: center;
}

/* Visually hidden but still present for screen readers/SEO — the standard
   accessible pattern (not display:none/visibility:hidden, which remove the
   element from the accessibility tree entirely). */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* —— Shop hub —— */
/* Now that the breadcrumb is gone and the SEO label/H1 are visually hidden,
   the shared .lux-page top padding (used by every other page — cart,
   success, etc., so not safe to change globally) leaves too much empty
   space above the title image. Tighten it here, scoped to this page only,
   and balance it against a matching margin below the image. */
.apex-lux .shop-hub.lux-page {
  padding-top: 0.85rem;
}

.apex-lux .shop-hub__title-img {
  display: block;
  width: 100%;
  max-width: 26rem;
  height: auto;
  margin: 0 auto 0.85rem;
}

@media (min-width: 720px) {
  .apex-lux .shop-hub.lux-page {
    padding-top: 1.1rem;
  }

  .apex-lux .shop-hub__title-img {
    max-width: 34rem;
    margin-bottom: 1.1rem;
  }
}

.apex-lux .shop-hub__note {
  margin-top: 1.5rem;
  padding: 0;
  background: transparent;
  border-radius: 0;
  font-size: 0.8125rem;
  color: var(--lux-muted);
  text-align: left;
}

.apex-lux .category-grid {
  gap: 0;
  border-top: 1px solid var(--lux-line);
}

.apex-lux .category-card {
  flex-direction: row;
  align-items: stretch;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--lux-line);
  border-radius: 0;
  box-shadow: none;
  padding: 0;
  gap: 1rem;
}

.apex-lux .category-card--live:hover {
  transform: none;
  opacity: 0.72;
  box-shadow: none;
}

.apex-lux .category-card--soon {
  opacity: 0.55;
}

.apex-lux .category-card--peek {
  opacity: 1;
  text-decoration: none;
  color: inherit;
}

.apex-lux .category-card--peek:hover {
  opacity: 0.72;
}

/* Side thumbnail, in its original position beside the text. No border,
   background or radius of its own — the image sits directly inside the
   outer card, which stays the only visible card outline. On mobile the box
   stretches to match the height of the text column beside it (title through
   price) instead of a fixed square, so the product image reads larger with
   less wasted white space; desktop keeps its own fixed square size below. */
.apex-lux .category-card__visual {
  flex-shrink: 0;
  align-self: stretch;
  width: 7rem;
  max-width: 7rem;
  min-height: 8rem;
  height: auto;
  overflow: hidden;
  background: transparent;
  border: none;
  border-radius: 0;
  padding: 0;
  box-shadow: none;
}

/* Spring Sale (2026) — Shop hub's Helium Bouquet Characters tile only
   (js/shop-hub.js gates the ribbon markup itself to this one category id;
   this just gives its thumbnail the positioning context the reused
   .trending-sale-ribbon rule (css/home.css) needs — same overflow:hidden
   already set above, plus position:relative so the ribbon's `top: 63%`
   is relative to this thumbnail, not the page). Every other Shop hub tile
   is unaffected. */
.apex-lux .category-card[data-cat-id="helium-bouquet-characters"] .category-card__visual {
  position: relative;
}

.apex-lux .category-card__visual img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center;
  min-height: 100%;
}

.apex-lux .category-card__body {
  padding: 1rem 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  text-align: left;
}

/* Category title — Baloo Bhaijaan Bold, the brand heading font (same font
   used in the Step panel headings). */
.apex-lux .category-card__name {
  font-family: var(--font-step-heading);
  font-size: 1.2rem;
  font-weight: 700;
  line-height: 1.2;
  text-align: left;
  color: var(--brand-burgundy, #880000);
}

/* Category description — Poppins, one notch smaller, left aligned. */
.apex-lux .category-card__desc {
  font-family: "Poppins", var(--font-ui, "DM Sans", system-ui, sans-serif);
  font-size: 0.75rem;
  line-height: 1.5;
  text-align: left;
  margin-top: 0.3rem;
}

/* Mobile only: title and description read much smaller than on desktop, so
   the enlarged image (above) can use the extra card height, while staying
   legible (same fonts, same wording — size and line-height only). */
@media (max-width: 719px) {
  .apex-lux .category-card__name {
    font-size: 1.05rem;
    line-height: 1.2;
  }
}

/* Prices From — Apex Balloons secondary brand colour (#620000, from the
   brand colour reference), left aligned with the rest of the card text. */
.apex-lux .category-card__price {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--brand-burgundy-dark);
  margin-top: 0.4rem;
  text-align: left;
}

.apex-lux .category-card__soon {
  font-size: 0.625rem;
  background: var(--lux-surface);
  color: var(--lux-muted);
  border: 1px solid var(--lux-line);
}

/* Desktop: slightly larger thumbnail (still beside the text, same position)
   and a larger card title. Desktop keeps the fixed square image treatment —
   only mobile stretches the thumbnail to match the text column height. */
@media (min-width: 720px) {
  .apex-lux .category-card {
    align-items: center;
  }

  .apex-lux .category-card__visual {
    align-self: center;
    width: 7rem;
    max-width: 7rem;
    height: 7rem;
    min-height: 7rem;
  }

  .apex-lux .category-card__name {
    font-size: 1.4rem;
  }
}

/* —— Configurator / helium —— */
.apex-lux.page-helium {
  padding-bottom: calc(6.5rem + var(--safe-bottom));
}

.apex-lux .config-main {
  max-width: var(--lux-max);
  margin: 0 auto;
  padding: 0 1.5rem 1.5rem;
}

@media (min-width: 720px) {
  .apex-lux .config-main {
    max-width: 32rem;
    padding-inline: 2rem;
  }
}

.apex-lux .config-intro {
  padding: 1.25rem 0 0.25rem;
}

.apex-lux .composer--summary {
  margin: 0 0 1rem;
  padding: 0.5rem 0;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--lux-line);
  border-radius: 0;
  box-shadow: none;
}

.apex-lux .composer__math {
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--lux-muted);
}

.apex-lux .config-form--simple .config-step {
  border: none;
  border-bottom: 1px solid var(--lux-line);
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  margin: 0;
}

.apex-lux .config-step__head,
.apex-lux .config-step summary {
  padding: 1rem 0;
  font-family: inherit;
}

.apex-lux .config-step__num {
  width: auto;
  height: auto;
  font-family: var(--font-step-heading);
  font-size: clamp(0.8rem, 2.4vw, 1rem);
  font-weight: 700;
  background: none;
  color: var(--brand-burgundy, #880000);
  border: none;
  border-radius: 0;
  box-shadow: none;
}

.apex-lux .config-step__label {
  font-family: var(--font-step-heading);
  font-size: clamp(0.8rem, 2.4vw, 1rem);
  font-weight: 700;
  color: var(--brand-burgundy, #880000);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.apex-lux .config-step__pick {
  font-size: 0.8125rem;
  color: var(--lux-muted);
  flex-shrink: 0;
  white-space: nowrap;
}

.apex-lux .config-step__body {
  padding: 0 0 1.25rem;
}

.apex-lux .bouquet-sets-hint {
  font-size: 0.75rem;
  color: var(--lux-muted);
  margin-bottom: 0.75rem;
}

.apex-lux .bouquet-set__card {
  border: 1px solid var(--lux-line);
  border-radius: var(--lux-radius);
  box-shadow: none;
  overflow: hidden;
}

.apex-lux .bouquet-set.is-selected .bouquet-set__card {
  border-color: var(--lux-accent);
  box-shadow: 0 0 0 1px var(--lux-accent);
}

.apex-lux .bouquet-set__meta {
  background: var(--lux-bg);
  color: var(--lux-text);
}

.apex-lux .bouquet-set.is-selected .bouquet-set__meta {
  background: var(--lux-accent);
  color: #fff;
}

.apex-lux .bouquet-set__tag {
  background: var(--lux-surface);
  color: var(--lux-text);
  border: 1px solid var(--lux-line);
  font-size: 0.625rem;
  font-weight: 600;
}

.apex-lux .bouquet-set__tag--sydney {
  background: var(--lux-accent);
  color: #fff;
  border-color: var(--lux-accent);
}

.apex-lux .bouquet-set__tag--gift {
  background: var(--lux-surface);
  color: var(--lux-muted);
}

.apex-lux .bouquet-set__meta-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  width: 100%;
  gap: 0.35rem;
}

.apex-lux .bouquet-set__hint {
  margin: 0.35rem 0 0;
  width: 100%;
  font-size: 0.6875rem;
  font-weight: 500;
  line-height: 1.35;
  color: var(--lux-muted);
}

.apex-lux .bouquet-set.is-selected .bouquet-set__hint {
  color: rgba(255, 255, 255, 0.88);
}

.apex-lux .bouquet-set__radio {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.apex-lux .bouquet-set {
  display: flex;
  flex-direction: column;
  flex: 0 0 auto;
}

.apex-lux .bouquet-set__card {
  display: block;
  cursor: pointer;
}

.apex-lux .bouquet-set__height {
  display: flex;
  gap: 0.35rem;
  padding: 0.4rem 0.5rem 0.45rem;
  background: var(--lux-bg);
  border: 1px solid var(--lux-line);
  border-top: none;
  border-radius: 0 0 var(--lux-radius) var(--lux-radius);
  margin-top: -1px;
}

.apex-lux .bouquet-set.is-selected .bouquet-set__height {
  border-color: var(--lux-accent);
}

.apex-lux .height-pill {
  flex: 1;
  margin: 0;
  cursor: pointer;
}

.apex-lux .height-pill input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.apex-lux .height-pill span {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-size: 0.6875rem;
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: 0.03em;
  padding: 0.32rem 0.35rem;
  border-radius: calc(var(--lux-radius) - 2px);
  border: 1px solid var(--lux-line);
  background: var(--lux-surface);
  color: var(--lux-muted);
  transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
}

.apex-lux .height-pill input:checked + span {
  border-color: var(--lux-accent);
  background: var(--lux-surface);
  color: var(--lux-text);
  box-shadow: 0 0 0 1px var(--lux-accent);
}

.apex-lux .bouquet-set.is-selected .height-pill input:checked + span {
  background: #fff;
  color: var(--lux-accent);
}

/* ── Shared Table/Floor Quantity Architecture round: independent −/0/+
   quantity per height, replacing the old single radio-pill + shared
   stepper. Reuses the exact same container position/shape as
   .bouquet-set__height above — only the interior swaps a checkbox-style
   pill for a plain label + compact stepper. No boxes-within-boxes, no
   borders around the −/+ buttons themselves, no extra copy. */
.apex-lux .bouquet-set__height-qty {
  display: flex;
  gap: 0.35rem;
  padding: 0.4rem 0.5rem 0.45rem;
  background: var(--lux-bg);
  border: 1px solid var(--lux-line);
  border-top: none;
  border-radius: 0 0 var(--lux-radius) var(--lux-radius);
  margin-top: -1px;
}

.apex-lux .bouquet-set.is-selected .bouquet-set__height-qty {
  border-color: var(--lux-accent);
}

.apex-lux .height-qty-block {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.2rem;
  min-width: 0;
}

.apex-lux .height-qty-block__label {
  font-size: 0.6875rem;
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: 0.03em;
  color: var(--lux-muted);
  text-align: center;
}

/* Mobile-only alignment fix: at narrow widths "Table Height" wraps to two
   lines while "Floor Height" stays on one, so the shorter label (and its
   stepper below it) sat higher than the wrapped one. Reserving two lines'
   worth of height on both labels keeps them at the same vertical position
   regardless of which one wraps — desktop/tablet are untouched since they
   have room for both labels on one line already. */
@media (max-width: 719px) {
  .apex-lux .height-qty-block__label {
    min-height: 2.3em;
    display: flex;
    align-items: center;
    justify-content: center;
  }
}

.apex-lux .qty-stepper--mini {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
  padding: 0;
  background: none;
  border: none;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

.apex-lux .qty-stepper--mini .qty-stepper__btn {
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 7px;
  background: var(--lux-surface);
  border: 1px solid var(--lux-line);
  color: var(--lux-accent);
}

.apex-lux .qty-stepper--mini .qty-stepper__icon {
  width: 0.8rem;
  height: 0.8rem;
}

.apex-lux .qty-stepper--mini .qty-stepper__value {
  min-width: 1.15rem;
  padding: 0;
  font-size: 0.8125rem;
  font-weight: 700;
  background: none;
  color: var(--lux-text);
}

.apex-lux .bouquet-set.is-selected .bouquet-set__card {
  border-radius: var(--lux-radius) var(--lux-radius) 0 0;
}

.apex-lux .choice-pill span {
  border: 1px solid var(--lux-line);
  border-radius: var(--lux-radius);
  background: var(--lux-bg);
  box-shadow: none;
  font-weight: 500;
}

.apex-lux .choice-pill input:checked + span {
  border-color: var(--lux-accent);
  background: var(--lux-surface);
  color: var(--lux-text);
  box-shadow: 0 0 0 1px var(--lux-accent);
}

.apex-lux .choice-pill--simple strong {
  font-weight: 600;
}

/* Field/section headings — burgundy + semibold, matching the treatment
   .fulfilment-time__field > span (checkout-extras.css) already used for
   "Delivery Time Slot" etc. This rule previously set plain dark text at a
   lighter weight, which is why that one label looked bold/burgundy while
   "Delivery Address", "Recipient Name", "Email" and similar field
   headings all looked like ordinary body text right next to it — same
   component, inconsistent styling. Helper text (.field__hint) is
   deliberately untouched — it stays smaller/grey/lighter so the two tiers
   stay visually distinct. */
.apex-lux .field span {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--lux-accent);
}

.apex-lux .field input,
.apex-lux .field textarea,
.apex-lux .field select {
  border: 1px solid var(--lux-line);
  border-radius: var(--lux-radius);
  background: #fff;
  box-shadow: none;
  font-size: 1rem;
}

.apex-lux .field input:focus,
.apex-lux .field textarea:focus {
  border-color: var(--lux-accent);
  outline: 2px solid rgba(122, 21, 40, 0.1);
  outline-offset: 0;
}

.apex-lux .delivery-msg {
  font-size: 0.8125rem;
  color: var(--lux-muted);
}

.apex-lux .hifloat-included-note {
  margin: 0.75rem 0 0;
  padding: 0.85rem 1rem;
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--lux-muted);
  background: var(--lux-surface);
  border: 1px solid var(--lux-line);
  border-radius: var(--lux-radius);
}

.apex-lux .hifloat-included-note strong {
  color: var(--lux-text);
  font-weight: 600;
}

.apex-lux .check-row {
  font-size: 0.875rem;
}

.apex-lux .colour-swatch,
.apex-lux .ribbon-swatch {
  border-radius: var(--lux-radius);
  border: 1px solid var(--lux-line);
}

.apex-lux .colour-swatch.is-selected,
.apex-lux .ribbon-swatch.is-selected {
  outline: 2px solid var(--lux-accent);
  outline-offset: 2px;
}

/* Small option-title typography (Quantity, Custom Message, Standard Balloon
   Colours, Chrome/Reflex Finish, Ribbon Colour, Weight Colour, Special
   Instructions, Height, Foil Number, etc.) — standardised sitewide on the
   Standard Balloon Column's typography (shop/products/balloon-column.html
   ?slug=latex), the agreed visual source of truth. This selector wins over
   the plain .colour-section__title base rule on every product page (all
   carry the apex-lux body class), so it's the rule that actually needs to
   match, not just the base. */
.apex-lux .colour-section__title,
.apex-lux .colour-section-label {
  font-family: inherit;
  font-size: 0.9375rem;
  font-weight: 700;
  letter-spacing: normal;
  text-transform: none;
  color: var(--lux-accent, var(--maroon, #7a1528));
}

.apex-lux .colour-section {
  border-bottom: 1px solid var(--lux-line);
  padding-bottom: 1rem;
}

.apex-lux .colour-step-hint,
.apex-lux .colour-more summary {
  font-size: 0.8125rem;
  color: var(--lux-muted);
}

.apex-lux .colour-step-hint--prominent {
  font-size: 1.05rem;
  font-weight: 800;
  color: var(--maroon-dark, #5c0f1e);
}

.apex-lux .height-set__card {
  border: 1px solid var(--lux-line);
  border-radius: var(--lux-radius);
  box-shadow: none;
}

.apex-lux .height-set.is-selected .height-set__card {
  border-color: var(--lux-accent);
  box-shadow: 0 0 0 1px var(--lux-accent);
}

.apex-lux .preview-stage {
  border: 1px solid var(--lux-line);
  border-radius: var(--lux-radius);
  background: var(--lux-surface);
  box-shadow: none;
}

.apex-lux .cart-page__details .config-step {
  margin-top: 1rem;
}

/* —— Checkout bar —— */
.apex-lux .checkout-bar {
  background: #fff;
  border-top: 1px solid var(--lux-line);
  box-shadow: none;
  padding: 0.75rem 1.25rem calc(0.75rem + var(--safe-bottom));
  gap: 0.75rem;
  max-width: 32rem;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
}

.apex-lux .checkout-bar__label {
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--lux-muted);
}

.apex-lux .checkout-bar__amount {
  font-family: inherit;
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--lux-text);
}

.apex-lux .checkout-bar__detail {
  font-size: 0.75rem;
  color: var(--lux-muted);
}

.apex-lux .checkout-bar__breakdown {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  margin-top: 0.2rem;
  max-height: 3.6rem;
  overflow-y: auto;
  /* Secondary detail line under Total/Subtotal — same muted/helper
     treatment as .checkout-bar__detail above, so it reads as supporting
     text rather than repeating the main amount's visual weight. Only sets
     font-size/color here (the .checkout-bar__breakdown-row/-label/-amount
     children below already define their own smaller font-size and muted
     colour explicitly, so this has no effect on that cart-page variant). */
  font-size: 0.75rem;
  color: var(--lux-muted);
}

.apex-lux .checkout-bar__breakdown-row {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  font-size: 0.5625rem;
  line-height: 1.35;
  color: var(--lux-muted);
}

.apex-lux .checkout-bar__breakdown-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.apex-lux .checkout-bar__breakdown-amount {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
}

.apex-lux .checkout-bar__btn {
  min-height: 2.75rem;
  font-size: 0.9375rem;
  border-radius: var(--lux-radius);
}

/* Cart page "Pay $X" button — styled to be visually identical to the header
   Cart button (pink/maroon pill) instead of the site's default burgundy
   .btn-primary chrome. Scoped to #cartPayBtn only — not the shared
   .checkout-bar__btn class every other product page's own Pay/Add-to-cart
   bar also uses — so no other page's button is affected, and the header
   Cart button itself (.cart-trigger) is only read from, never redeclared
   with different values. Dynamic $ amount, disabled-state dimming
   (.btn:disabled's existing opacity rule still applies unchanged), and all
   Pay/Stripe logic are untouched — styling only. */
#cartPayBtn.checkout-bar__btn {
  position: relative;
  overflow: hidden;
  height: 2.5rem;
  min-height: 0;
  padding: 0 1.35rem;
  background: linear-gradient(160deg, #fdf6f8 0%, var(--pink, #f8e8ec) 55%, var(--pink-deep, #e8b4c4) 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.65), 0 2px 8px rgba(122, 21, 40, 0.14);
  color: var(--lux-accent);
  border: none;
  border-radius: 999px;
  font-family: "Poppins", var(--font-ui, "DM Sans", system-ui, sans-serif);
  font-size: 0.8125rem;
  font-weight: 500;
  transition: filter 0.2s ease, transform 0.15s ease;
}

#cartPayBtn.checkout-bar__btn:hover:not(:disabled) {
  background: linear-gradient(160deg, #fdf6f8 0%, var(--pink, #f8e8ec) 55%, var(--pink-deep, #e8b4c4) 100%);
  filter: brightness(1.06);
}

#cartPayBtn.checkout-bar__btn:active:not(:disabled) {
  transform: scale(0.97);
}

#cartPayBtn.checkout-bar__btn::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(115deg, transparent 35%, rgba(255, 255, 255, 0.55) 50%, transparent 65%);
  transform: translateX(-120%);
  pointer-events: none;
}

#cartPayBtn.checkout-bar__btn:hover:not(:disabled)::after,
#cartPayBtn.checkout-bar__btn:focus-visible::after {
  animation: apex-btn-shine 1.1s ease-in-out;
}

/* Global ADD TO CART button — supplied glossy artwork as the visual on the
   real <button>. background-size/position only zoom past the artwork's own
   transparent-white canvas margin to the pill's own aspect ratio (the
   source file is never edited) so it reads as a normal-proportioned button.
   Text stays exactly as configurator.js/number-tower*.js set it (including
   the "Tap + for quantity" / "Swipe and add quantity" hint states) — it's
   only visually hidden via color: transparent, so screen readers still hear
   the real current label. Existing .btn-primary:disabled opacity dimming
   (styles.css) continues to apply on top of the artwork unchanged. */
#addToCartBtn {
  position: relative;
  overflow: hidden;
  height: 2.85rem;
  width: 8.1rem;
  aspect-ratio: 2.85;
  min-height: 0;
  background-color: transparent;
  background-image: url("../assets/buttons/add-to-cart-button.png");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 135.14% 256.41%;
  color: transparent;
  border: none;
  border-radius: 999px;
  box-shadow: none;
  padding: 0;
  transition: filter 0.2s ease, transform 0.15s ease;
}

#addToCartBtn:hover:not(:disabled) {
  filter: brightness(1.06);
}

#addToCartBtn:active:not(:disabled) {
  transform: scale(0.97);
}

#addToCartBtn::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(115deg, transparent 35%, rgba(255, 255, 255, 0.55) 50%, transparent 65%);
  transform: translateX(-120%);
  pointer-events: none;
}

#addToCartBtn:hover:not(:disabled)::after,
#addToCartBtn:focus-visible::after {
  animation: apex-btn-shine 1.1s ease-in-out;
}

@keyframes apex-btn-shine {
  0% { transform: translateX(-120%); }
  100% { transform: translateX(120%); }
}

@media (prefers-reduced-motion: reduce) {
  #addToCartBtn::after,
  .apex-lux .cart-trigger::after {
    display: none;
  }

  #addToCartBtn:hover:not(:disabled),
  .apex-lux .cart-trigger:hover {
    filter: brightness(1.1);
  }

  #addToCartBtn,
  .apex-lux .cart-trigger,
  #addToCartBtn::after,
  .apex-lux .cart-trigger::after {
    transition: none;
    animation: none;
  }
}

@media (min-width: 720px) {
  #addToCartBtn {
    height: 3.25rem;
    width: 9.25rem;
  }
}

.apex-lux .checkout-bar__cart {
  font-size: 0.8125rem;
  color: var(--lux-muted);
  font-weight: 500;
}

.apex-lux .checkout-bar__cart:hover {
  color: var(--lux-accent);
}

/* —— Cart —— */
.apex-lux.page-cart {
  padding-bottom: calc(5rem + var(--safe-bottom));
}

.apex-lux .cart-page {
  max-width: var(--lux-max);
  margin: 0 auto;
  padding: 1.5rem 1.5rem 2rem;
}

@media (min-width: 720px) {
  .apex-lux .cart-page {
    max-width: var(--lux-max);
    padding-inline: 2rem;
  }
}

.apex-lux .cart-page__head {
  align-items: flex-start;
  border-bottom: 1px solid var(--lux-line);
  padding-bottom: 1rem;
  margin-bottom: 0;
}

.apex-lux .cart-page__link {
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--lux-accent);
}

.apex-lux .cart-page__flash {
  font-size: 0.8125rem;
  background: var(--lux-surface);
  border: 1px solid var(--lux-line);
  color: var(--lux-text);
  border-radius: var(--lux-radius);
}

/* Cart item card — proportioned after the mobile subcategory product card
   (image left, name/details right, compact) rather than the old flush,
   border-bottom-only list row this replaces. Real internal padding on all
   sides so title/options/price/actions never sit flush against the card
   edge; a visible border + radius so it actually reads as a card, matching
   how every other bordered content block on this page (.pickup-location,
   .cart-page__flash) is already presented. Cards are separated by a gap
   between <li> elements now, not a shared border line. */
/* Matches the current Custom Balloon Columns subcategory product-card
   reference exactly (.category-card in css/styles.css): the CARD itself
   is white/bordered, not grey/pink — pink belongs only to the image area
   (.cart-line__image below), same split as that reference. */
.apex-lux .cart-line {
  display: flex;
  align-items: stretch;
  gap: 1rem;
  border: 1px solid var(--border, var(--lux-line));
  border-radius: var(--radius, 12px);
  padding: 1rem;
  box-shadow: var(--shadow, none);
  background: var(--white, #fff);
  list-style: none;
}

.apex-lux .cart-page__lines {
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
  margin: 0;
  padding: 0;
}

/* Light Apex pink field (reusing the site's own --pink/--pink-deep tokens,
   not a new shade) instead of a white boxed thumbnail — the image itself
   fills this area at a proportion that feels intentional, not a small icon
   floating in empty white space. */
/* cover (previous pass) visibly zoomed/cropped real product detail on
   several shapes — reverted. Portrait ratio (not square) chosen to match
   the catalogue's dominant photo shape (~0.71-0.80 w/h for bouquets,
   columns, baby shower, gender reveal), so object-fit: contain has very
   little dead space to fill on those without cropping anything; a
   perfect-square photo (table centrepieces) just centers with modest
   letterboxing instead. Compact, not enlarged just to fit images. */
.apex-lux .cart-line__image {
  flex-shrink: 0;
  width: 5.25rem;
  height: 6.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(165deg, var(--pink, #f8e8ec) 0%, var(--cream, #fdf6f0) 100%);
  border-radius: 10px;
  overflow: hidden;
}

.apex-lux .cart-line__image img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

.apex-lux .cart-line__body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.3rem;
}

.apex-lux .cart-line__body strong {
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--maroon-dark, var(--lux-text));
  line-height: 1.3;
}

.apex-lux .cart-line__side {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: center;
  gap: 0.5rem;
  text-align: right;
}

/* Secondary to the title/image/price — selected options are useful detail,
   not the visual focus of the card. Reuses the exact same small-helper
   typography as "Minimum 3 days' notice" (.field__hint) for consistency
   across the whole Cart, not a separate similar-looking style. */
.apex-lux .cart-line__meta {
  font-size: 0.7rem;
  font-weight: 400;
  color: var(--muted, #6b5560);
  line-height: 1.55;
  margin: 0;
}

.apex-lux .cart-line__price {
  font-weight: 600;
  color: var(--maroon, var(--lux-text));
}

.apex-lux .cart-line__actions {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.3rem;
}

.apex-lux .cart-line__edit,
.apex-lux .cart-line__remove {
  font-size: 0.75rem;
  font-weight: 500;
  background: none;
  border: none;
  padding: 0.1rem 0;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.apex-lux .cart-line__edit {
  color: var(--lux-accent);
}

.apex-lux .cart-line__remove {
  color: #a34848;
}

.apex-lux .cart-page__empty {
  padding: 2rem 0;
  text-align: left;
}

/* Checkout acknowledgements — sits in normal page flow immediately above
   the sticky Pay bar, so it scrolls into view right before the button
   rather than being squeezed into the fixed bar itself. */
.apex-lux .cart-terms-ack {
  margin-top: 1.25rem;
  padding-top: 1rem;
  border-top: 1px solid var(--lux-line);
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.apex-lux .cart-terms-ack__row {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  cursor: pointer;
}

.apex-lux .cart-terms-ack__row input[type="checkbox"] {
  width: 18px;
  height: 18px;
  min-height: 0;
  flex: 0 0 auto;
  margin-top: 1px;
  padding: 0;
  accent-color: var(--lux-accent);
}

.apex-lux .cart-terms-ack__row span {
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--lux-muted);
}

.apex-lux .cart-terms-ack__row a {
  color: var(--lux-accent);
  font-weight: 500;
  text-decoration: underline;
}

.apex-lux .cart-page__empty p {
  color: var(--lux-muted);
  font-size: 0.9375rem;
}

.apex-lux .cart-page__summary {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--lux-line);
  background: transparent;
  border-radius: 0;
  box-shadow: none;
}

.apex-lux .order-row {
  font-size: 0.875rem;
  padding: 0.4rem 0;
  color: var(--lux-muted);
}

.apex-lux .order-row span:last-child {
  color: var(--lux-text);
  font-weight: 500;
}

.apex-lux .order-row--total {
  font-size: 1rem;
  padding-top: 0.75rem;
  margin-top: 0.35rem;
  border-top: 1px solid var(--lux-line);
}

.apex-lux .order-row--total span {
  font-weight: 600;
  color: var(--lux-text);
}

.apex-lux .order-row--included span:last-child {
  color: var(--lux-muted);
  font-weight: 400;
}

.apex-lux .checkout-bar--cart {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

/* Go Shopping — supplied artwork, empty-cart-only substitute for Continue
   Shopping (kept from Phase 2). The Pay button itself reverted to its
   pre-Phase-2 gradient-pill implementation (#cartPayBtn.checkout-bar__btn
   above) — Go Shopping keeps its own fixed, proportional size rather than
   growing/stretching, sitting to the left of Pay exactly where Continue
   Shopping normally sits. */
.apex-lux .checkout-bar--cart .checkout-bar__go-shopping {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  height: 2.85rem;
  width: 6.15rem;
  padding: 0 1.1rem;
  border: none;
  border-radius: 999px;
  background-repeat: no-repeat;
  background-size: 100% 100%;
  background-position: center;
  box-shadow: none;
  color: transparent;
  font-family: "Poppins", var(--font-ui, "DM Sans", system-ui, sans-serif);
  transition: filter 0.15s ease, transform 0.1s ease;
  /* Real link text stays in the DOM for accessibility, but it's
     colour:transparent (the artwork already carries "Go Shopping!" as a
     baked-in wordmark) — without a fixed width + overflow:hidden here,
     that invisible text still grows the box past its own glyphs,
     stretching the artwork off its native ~2.151 aspect ratio. */
  overflow: hidden;
  white-space: nowrap;
  background-image: url("../assets/buttons/go-shopping-button-trimmed.png");
  text-decoration: none;
}

.apex-lux .checkout-bar--cart .checkout-bar__go-shopping:hover {
  filter: brightness(1.04);
}

.apex-lux .checkout-bar--cart .checkout-bar__go-shopping:active {
  transform: scale(0.98);
}

/* Cart page desktop: styles.css flips .checkout-bar to position:sticky at
   ≥768px, but lux.css keeps left:50%+right:0+transform — a combo designed
   for fixed that misfires under sticky and shifts the bar ~295px off-screen
   left. Restore fixed + full-width at 768px, then re-apply centred layout
   cleanly at ≥960px where the bar should match .config-main's 1040px width. */
@media (min-width: 768px) {
  .apex-lux.page-cart .checkout-bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    transform: none;
    max-width: none;
    margin: 0;
  }
}

@media (min-width: 960px) {
  .apex-lux.page-cart .checkout-bar {
    left: 50%;
    right: auto;
    width: 100%;
    max-width: 1160px;
    transform: translateX(-50%);
  }
}

.apex-lux .checkout-bar__back {
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--lux-muted);
}

/* Qty pill — minimal */
.apex-lux .qty-pill {
  border: 1px solid var(--lux-line);
  border-radius: var(--lux-radius);
  background: var(--lux-bg);
  box-shadow: none;
}

.apex-lux .qty-pill__btn {
  font-weight: 500;
  color: var(--lux-text);
}

/* Success */
.apex-lux .success-main {
  max-width: 34rem;
  margin: 0 auto;
  padding: 3rem 1.5rem 4rem;
  text-align: left;
}

.apex-lux .success-hero {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin: 0 0 0.5rem;
}

.apex-lux .success-hero h1 {
  margin: 0;
  font-size: 1.5rem;
  line-height: 1.25;
}

.apex-lux .success-tick {
  flex-shrink: 0;
  width: 1.9rem;
  height: 1.9rem;
  color: #1a8c4a;
}

.apex-lux .success-main .lead {
  margin: 0 0 2rem;
  color: var(--lux-muted);
  font-size: 0.95rem;
}

.apex-lux .success-section {
  border-top: 1px solid var(--lux-line);
  padding-top: 1.25rem;
  margin-bottom: 1.75rem;
}

.apex-lux .success-section__title {
  margin: 0 0 0.9rem;
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--lux-text);
}

.apex-lux .success-rows {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}

.apex-lux .success-row {
  display: flex;
  gap: 0.6rem;
  font-size: 0.9rem;
  line-height: 1.5;
}

.apex-lux .success-row__label {
  flex: 0 0 6.5rem;
  color: var(--lux-muted);
  font-weight: 500;
}

.apex-lux .success-row__value {
  color: var(--lux-text);
  word-break: break-word;
}

.apex-lux .success-actions {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-top: 2rem;
}

.apex-lux .success-actions .home-cta--cart-match,
.apex-lux .success-actions .btn-ghost {
  min-width: 9.5rem;
  height: 2.5rem;
  min-height: 0;
  border-radius: 999px;
}

@media (max-width: 480px) {
  .apex-lux .success-row {
    flex-direction: column;
    gap: 0.15rem;
  }
  .apex-lux .success-row__label {
    flex: none;
  }
  .apex-lux .success-actions {
    flex-direction: column;
  }
  .apex-lux .success-actions .home-cta--cart-match,
  .apex-lux .success-actions .btn-ghost {
    width: 100%;
  }
}

/* No scroll-reveal fade on lux pages */
.apex-lux .reveal {
  opacity: 1;
  transform: none;
}

@media (min-width: 720px) {
  .apex-lux .site-footer,
  .apex-lux .site-footer--slim,
  .apex-lux .site-footer--lux {
    max-width: var(--lux-max);
    padding-inline: 2rem;
  }

  .apex-lux .checkout-bar {
    max-width: var(--lux-max);
  }
}

/* Premium step header bars (Step 1 / Step 2 / Step 3). Generalised from the
   approved helium design to every configurator product page via the shared
   .page-helium--simple body class (helium, number combos, baby shower, gender
   reveal, graduation, columns, centrepieces, number towers). Non-configurator
   pages that also use .config-step (cart, bubble-bouquets, stacks) keep the
   plain treatment defined above. Only visual treatment changes here — no step
   title wording is affected. */
.apex-lux.page-helium--simple .config-step {
  border-bottom: none;
  margin-top: 0.75rem;
  margin-bottom: 0.75rem;
}

.apex-lux.page-helium--simple .config-step__head,
.apex-lux.page-helium--simple .config-step summary {
  padding: 0.9rem 1rem;
  margin: 0;
  background: linear-gradient(135deg, var(--cream, #fffbfc) 0%, var(--lux-surface, #fff) 55%, rgba(232, 180, 196, 0.16) 100%);
  border: 1px solid var(--lux-line);
  border-radius: var(--lux-radius);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.6) inset, 0 6px 16px rgba(122, 21, 40, 0.06);
}

/* Mobile-only: trim the STEP banner's top/bottom padding — width, text
   size and horizontal padding are untouched, and align-items:center
   (inherited from .config-step__head) keeps the text vertically centred
   in the shorter bar. Desktop/tablet keep the roomier 0.9rem above. */
@media (max-width: 719px) {
  .apex-lux.page-helium--simple .config-step__head,
  .apex-lux.page-helium--simple .config-step summary {
    padding-top: 0.55rem;
    padding-bottom: 0.55rem;
  }
}

.apex-lux.page-helium--simple .config-step[open] > .config-step__head,
.apex-lux.page-helium--simple .config-step[open] > summary {
  background: linear-gradient(135deg, rgba(232, 180, 196, 0.24) 0%, var(--cream, #fffbfc) 60%, var(--lux-surface, #fff) 100%);
  border-color: var(--lux-accent);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.7) inset, 0 8px 20px rgba(122, 21, 40, 0.1);
}

.apex-lux.page-helium--simple .config-step__num {
  width: auto;
  height: auto;
  font-family: var(--font-step-heading);
  font-size: clamp(0.8rem, 2.4vw, 1rem);
  font-weight: 700;
  background: none;
  color: var(--brand-burgundy, #880000);
  border: none;
  box-shadow: none;
  white-space: nowrap;
}

.apex-lux.page-helium--simple #colourStepHint {
  text-transform: none;
}

.apex-lux.page-helium--simple .config-step__label {
  font-family: var(--font-step-heading);
  font-size: clamp(0.8rem, 2.4vw, 1rem);
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--brand-burgundy, #880000);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.apex-lux.page-helium--simple .config-step__pick {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--lux-accent);
}

/* "STEP 1 - Size and Qty" / "STEP 2 - Colour/s" heading treatment — the
   approved Helium Balloon Bouquets standard, propagated to every product
   that shares its Step 1/2 bouquet-customisation system (Number Combos,
   Baby Shower/Gender Reveal/Graduation). Explicitly scoped to just these
   three page classes rather than the shared .page-helium--simple body
   class, which also covers Balloon Columns, Table Centrepieces and Number
   Towers — those keep their original (unchanged) heading treatment above. */
.apex-lux.page-helium .config-step__num,
.apex-lux.page-number-combos .config-step__num,
.apex-lux.page-baby-shower .config-step__num {
  width: auto;
  height: auto;
  font-family: var(--font-step-heading);
  font-size: clamp(0.8rem, 2.4vw, 1rem);
  font-weight: 700;
  background: none;
  color: var(--brand-burgundy, #880000);
  border: none;
  box-shadow: none;
  white-space: nowrap;
}

.apex-lux.page-helium .config-step__label,
.apex-lux.page-number-combos .config-step__label,
.apex-lux.page-baby-shower .config-step__label {
  font-family: var(--font-step-heading);
  font-size: clamp(0.8rem, 2.4vw, 1rem);
  font-weight: 700;
  color: var(--brand-burgundy, #880000);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.apex-lux.page-helium #stepPick1,
.apex-lux.page-number-combos #stepPick1,
.apex-lux.page-baby-shower #stepPick1 {
  white-space: pre-line;
  line-height: 1.2;
  font-size: 0.6875rem;
  max-width: 55%;
}

/* Helium size cards — "4 Balloon Bouquet" title on one line, price centred
   underneath on its own line (all breakpoints). */
.apex-lux.page-helium .bouquet-set__count::after {
  content: " Balloon Bouquet";
}

.apex-lux.page-helium .bouquet-set__meta-row {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 0.2rem;
}

.apex-lux.page-helium .bouquet-set__count {
  font-family: var(--font-ui, inherit);
  font-size: 0.66rem !important;
  font-weight: 700;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  white-space: nowrap;
}

.apex-lux.page-helium .bouquet-set__count::after {
  display: inline;
  margin: 0;
  font-size: inherit;
  font-weight: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
}

.apex-lux.page-helium .bouquet-set__price {
  width: 100%;
  font-size: 0.85rem !important;
  font-weight: 700;
  text-align: center;
}

.apex-lux.page-helium .bouquet-set__price-each {
  font-size: 0.62em;
  font-weight: 400;
  margin-left: 0.15em;
}

/* Helium — mobile: bouquet slider + qty tap targets */
@media (max-width: 719px) {
  .apex-lux.page-helium .bouquet-sets-scroll {
    scroll-padding-inline: 1.1rem;
    margin-inline: -0.15rem;
  }

  .apex-lux.page-helium .bouquet-set {
    width: clamp(8.75rem, 42vw, 10.5rem);
  }

  .apex-lux.page-helium .height-pill span {
    min-height: 2.75rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    line-height: 1.15;
    padding: 0.3rem 0.25rem;
  }

  .apex-lux.page-helium .qty-stepper--sm .qty-stepper__btn,
  .apex-lux.page-helium .qty-stepper--sm .qty-pill__btn {
    width: 2.75rem;
    height: 2.75rem;
  }

  .apex-lux.page-helium .config-main {
    padding-inline: 1rem;
  }

  /* Selected-card title/price must read white on the burgundy meta strip for
     every configurator slider (helium, number combos, baby-shower / gender-
     reveal / graduation bouquets) — scoped to the shared .page-helium--simple
     body class so it isn't limited to helium. Overrides the maroon colour the
     base .bouquet-set__count / .bouquet-set__price rules set in styles.css. */
  .apex-lux.page-helium--simple .bouquet-set.is-selected .bouquet-set__price {
    color: #fff;
  }

  .apex-lux.page-helium--simple .bouquet-set.is-selected .bouquet-set__count,
  .apex-lux.page-helium--simple .bouquet-set.is-selected .bouquet-set__count::after {
    color: #fff;
  }

  .apex-lux.page-helium .bouquet-set__hint {
    display: none;
  }
}

/* Helium step 1 — desktop: wider row, bigger cards, full maroon when selected */
@media (min-width: 720px) {
  /* .config-main's own max-width override used to live here (56rem,
     896px) — removed so 30cm inherits the exact same shared .config-main
     desktop widths (32rem at 720px+, 1040px at 960px+, 1400px at 1440px+
     — see above/below) that 45cm and 60cm already use, since neither of
     those pages ever had a competing page-specific override. This was the
     root cause of 30cm rendering noticeably smaller on full desktop
     widths: this more-specific selector was overriding the shared rule
     down to a fixed 896px regardless of viewport, while 45cm/60cm freely
     widened to 1040px/1400px. Everything else in this block (slider drag
     behaviour, card sizing, the 1100px+ flat-row transition) is unrelated
     to overall page width and stays exactly as it was. */

  .apex-lux.page-helium #heliumTagline {
    margin-inline: auto;
    text-align: center;
  }

  /* 720–1099px ("narrow desktop"): keep the mobile-style horizontal slider
     instead of squeezing cards into a full-width row — the row only becomes
     a flat non-scrolling grid once there's genuinely enough room, at
     min-width:1100px below. Cards keep their natural clamped width and
     scroll-snap so nothing gets compressed or cut off. */
  .apex-lux.page-helium .bouquet-sets-scroll {
    /* Re-assert the slider (a generic, non-helium-scoped rule elsewhere
       flattens .bouquet-sets-scroll to overflow:visible from 960px up —
       this wins over it here via higher selector specificity so the row
       stays a scrollable slider through the whole 720–1099px range). */
    overflow-x: auto;
    overflow-y: hidden;
    flex-wrap: nowrap;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: 1rem;
    scroll-behavior: smooth;
    cursor: grab;
    /* A mouse/trackpad desktop needs a real, visible, draggable scrollbar —
       unlike mobile (touch scrolling makes a permanent scrollbar redundant
       there), so explicitly turn back on what the base mobile-first rule
       hides via scrollbar-width:none / -webkit-scrollbar{display:none}. */
    scrollbar-width: auto;
    scrollbar-color: var(--lux-accent, #7a1528) var(--lux-bg, #f6eef0);
    padding-bottom: 0.85rem;
  }

  .apex-lux.page-helium .bouquet-sets-scroll::-webkit-scrollbar {
    display: block;
    height: 10px;
  }

  .apex-lux.page-helium .bouquet-sets-scroll::-webkit-scrollbar-track {
    background: var(--lux-bg, #f6eef0);
    border-radius: 6px;
  }

  .apex-lux.page-helium .bouquet-sets-scroll::-webkit-scrollbar-thumb {
    background: var(--lux-accent, #7a1528);
    border-radius: 6px;
  }

  .apex-lux.page-helium .bouquet-sets-scroll:active {
    cursor: grabbing;
  }

  .apex-lux.page-helium .bouquet-sets-scroll.is-dragging {
    scroll-snap-type: none;
  }

  .apex-lux.page-helium .bouquet-sets {
    display: flex;
    flex-wrap: nowrap;
    width: max-content;
  }

  .apex-lux.page-helium .bouquet-set {
    flex: 0 0 auto;
    width: clamp(9.25rem, 22vw, 10.75rem);
    scroll-snap-align: center;
  }

  /* No box-shadow on the outer .bouquet-set here — that wrapped a ring
     around the card AND the height pills AND the qty stepper beneath it.
     Selection is shown the same way as mobile: only .bouquet-set__card and
     .bouquet-set__height (below, and via the shared 720px+ rules further
     down this file) get the accent border/highlight. */

  .apex-lux.page-helium .bouquet-set__hint {
    display: none;
  }
}

/* ≥1100px ("wide desktop"): plenty of room — lay the bouquet cards out as a
   normal full-width row instead of a slider. */
@media (min-width: 1100px) {
  .apex-lux.page-helium .bouquet-sets-scroll {
    overflow-x: visible;
    scroll-snap-type: none;
    -webkit-overflow-scrolling: auto;
    overscroll-behavior-x: auto;
    margin: 0;
    padding-inline: 0;
    cursor: default;
  }

  .apex-lux.page-helium .bouquet-sets {
    width: 100%;
    gap: 0.55rem;
  }

  .apex-lux.page-helium .bouquet-set {
    flex: 1 1 0;
    min-width: 0;
    width: auto;
    scroll-snap-align: unset;
    border-radius: var(--lux-radius);
    overflow: hidden;
  }
}

@media (min-width: 720px) {
  .apex-lux.page-helium .bouquet-set__meta {
    padding: 0.4rem 0.5rem 0.45rem;
  }

  .apex-lux.page-helium .bouquet-set__meta-row {
    flex-direction: column;
    align-items: center;
    justify-content: center;
  }

  .apex-lux.page-helium .bouquet-set__count {
    font-size: 0.68rem !important;
    letter-spacing: 0.003em;
    line-height: 1.2;
    padding-inline: 0.1rem;
  }

  .apex-lux.page-helium .bouquet-set__count::after {
    display: inline;
    margin: 0;
    font-size: inherit;
  }

  .apex-lux.page-helium .bouquet-set__price {
    font-size: 0.92rem !important;
  }

  .apex-lux.page-helium .bouquet-set__tag {
    font-size: 0.52rem;
    padding: 0.15rem 0.35rem;
  }

  .apex-lux.page-helium .bouquet-set__height {
    padding: 0.38rem 0.45rem;
    gap: 0.3rem;
  }

  .apex-lux.page-helium .height-pill span {
    font-size: 0.625rem;
    padding: 0.34rem 0.2rem;
  }

  .apex-lux.page-helium .bouquet-set.is-selected .bouquet-set__card {
    border-color: var(--lux-accent);
    box-shadow: 0 0 0 1px var(--lux-accent);
    transform: none;
  }

  .apex-lux.page-helium .bouquet-set.is-selected .bouquet-set__meta {
    background: var(--lux-accent);
    color: #fff;
    border-top-color: var(--lux-accent);
  }

  .apex-lux.page-helium--simple .bouquet-set.is-selected .bouquet-set__count,
  .apex-lux.page-helium--simple .bouquet-set.is-selected .bouquet-set__price,
  .apex-lux.page-helium--simple .bouquet-set.is-selected .bouquet-set__count::after {
    color: #fff !important;
  }

  /* Height row keeps its normal light background even when the card is
     selected (matches mobile, which never tints this row) — so Table/Floor
     pills use the same base light-bg styling on both breakpoints instead of
     the stale translucent-white-on-burgundy treatment that only made sense
     when this row had a burgundy fill. */
  .apex-lux.page-helium .bouquet-set.is-selected .bouquet-set__height {
    border-color: var(--lux-accent);
  }

  .apex-lux.page-helium .bouquet-set.is-selected .bouquet-set__qty {
    padding: 0.2rem 0.4rem 0.35rem;
    margin-top: -1px;
  }

  /* Quantity number must always read as the standardised deep-red brand
     colour on desktop — default, selected, hover and focus — never white
     against the selected pink/maroon card (the original bug this rule
     fixed; deep red has the same safe contrast black did against every
     one of these states, so swapping the colour doesn't reopen it). */
  .apex-lux.page-helium .qty-stepper__value,
  .apex-lux.page-helium .bouquet-set .qty-stepper__value,
  .apex-lux.page-helium .bouquet-set.is-selected .qty-stepper__value:hover,
  .apex-lux.page-helium .bouquet-set.is-selected .qty-stepper__value:focus {
    color: var(--lux-accent, var(--maroon, #7a1528)) !important;
  }

  .apex-lux.page-helium .qty-stepper--card {
    max-width: 100%;
    justify-content: center;
  }

  .apex-lux.page-helium .qty-stepper--sm .qty-stepper__btn,
  .apex-lux.page-helium .qty-stepper--sm .qty-pill__btn {
    width: 2rem;
    height: 2rem;
  }

  .apex-lux.page-helium .qty-stepper--sm .qty-stepper__value,
  .apex-lux.page-helium .qty-stepper--sm .qty-pill__val {
    font-size: 1rem;
    min-width: 1.75rem;
  }

  /* Sticky Add to Cart bar — desktop. The shared .checkout-bar rules (in
     styles.css/lux.css, used across product pages) cap this at a fixed
     ~32rem/1040px panel centred with left:50%+transform, and separately flip
     position to sticky at 768px — combined, that produced a fixed-width
     floating panel that could clip or fail to span the viewport at in-between
     desktop/laptop widths. On every configurator page (page-helium--simple,
     shared by helium, number combos and the baby-shower/gender-reveal/
     graduation bouquet family), pin it back to the full viewport width exactly
     like the mobile bar (which is untouched by any of this), and let its
     contents wrap onto a second row instead of clipping when narrow. */
  .apex-lux.page-helium--simple .checkout-bar {
    position: fixed;
    top: auto;
    left: 0;
    right: 0;
    bottom: 0;
    transform: none;
    width: 100%;
    max-width: none;
    margin: 0;
    border-radius: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    row-gap: 0.4rem;
  }

  .apex-lux.page-helium--simple .checkout-bar__main {
    flex: 1 1 240px;
    min-width: 0;
  }

  .apex-lux.page-helium--simple .checkout-bar__btn {
    flex: 0 0 auto;
  }

  .apex-lux.page-helium--simple .checkout-bar__cart {
    flex: 0 0 auto;
  }
}

/* Business Balloon Columns category card — brand (burgundy) styling,
   matching the rest of the site instead of the old navy/gold "corporate"
   theme. The card otherwise inherits the standard .category-card look. */
.category-card--corporate {
  position: relative;
}

.category-card--corporate:hover {
  border-color: var(--accent, #7a1528);
  box-shadow: 0 8px 24px rgba(26, 15, 18, 0.12);
  transform: translateY(-2px);
}

.category-card--corporate .category-card__name {
  font-weight: 600;
}

/* Business Balloon Columns shop-hub tile — new thumbnail is a flat white
   studio photo (like the subcategory-page thumbnails); blend the white out
   instead of cropping. Scoped to this one card only. */
.category-card--corporate .category-card__visual img {
  mix-blend-mode: multiply;
}

/* Helium Balloon Bouquets, Helium Number Balloon Bouquets, Gender Reveal
   Balloons, Baby Shower Balloons, and Helium Bouquet Basics shop-hub tiles —
   same flat white studio-photo thumbnails as the corporate-columns tile
   above; blend the white out instead of cropping. Scoped by href since
   these categories don't carry a theme flag of their own. */
body.page-shop-hub a[href="helium.html"] .category-card__visual img,
body.page-shop-hub a[href="number-combos.html"] .category-card__visual img,
body.page-shop-hub a[href="gender-reveal.html"] .category-card__visual img,
body.page-shop-hub a[href="baby-shower.html"] .category-card__visual img,
body.page-shop-hub a[href="helium-bouquet-basics.html"] .category-card__visual img,
body.page-shop-hub a[href="table-centrepieces.html"] .category-card__visual img,
body.page-shop-hub a[href="balloon-displays.html"] .category-card__visual img,
body.page-shop-hub a[href="balloon-sculptures.html"] .category-card__visual img,
body.page-shop-hub a[href="graduation.html"] .category-card__visual img,
body.page-shop-hub a[href="number-balloon-towers.html"] .category-card__visual img,
body.page-shop-hub a[href="balloon-garlands.html"] .category-card__visual img {
  /* table-centrepieces added — its thumbnail is the same flat white studio
     photo as the others above (verified via canvas pixel sampling: corner
     pixels are pure #fff, unlike graduation/number-balloon-towers/stacks,
     whose thumbnails are genuine lifestyle photos and correctly excluded).
     balloon-displays/balloon-sculptures added — same flat-white Canva
     cutout thumbnails, confirmed via image inspection.
     graduation/number-balloon-towers added — re-verified by direct pixel
     sampling of the CURRENT thumbnail files (all four corners pure #fff on
     both): the note above about these two being excluded no longer holds,
     their thumbnail assets have since been replaced with flat-white studio
     photos like every other tile in this list.
     balloon-garlands added — same flat-white studio photo (3 of 4 corners
     pure #fff, verified via pixel sampling). */
  mix-blend-mode: multiply;
}

/* Corporate highlight for homepage tagline */
.corporate-highlight {
  color: var(--corp-primary);
  font-weight: 500;
}

/* Corporate Page Content Styles */
.corporate-services {
  padding: 3rem 0;
  background: var(--corp-surface);
}

.service-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 2rem;
  margin-top: 2rem;
}

.service-card {
  background: white;
  padding: 2rem;
  border-radius: var(--lux-radius);
  border: 1px solid var(--corp-light);
  box-shadow: 0 2px 8px rgba(30, 58, 95, 0.08);
}

.service-card h3 {
  color: var(--corp-primary);
  margin-bottom: 1rem;
  font-size: 1.25rem;
  font-weight: 600;
}

.service-card ul {
  list-style: none;
  padding: 0;
  margin: 1rem 0;
}

.service-card li {
  padding: 0.25rem 0;
  color: var(--corp-muted);
}

.service-card li::before {
  content: "✓";
  color: var(--corp-accent);
  font-weight: bold;
  margin-right: 0.5rem;
}

.service-price {
  color: var(--corp-accent);
  font-weight: 600;
  font-size: 1.125rem;
  margin-top: 1.5rem;
}

.corporate-areas {
  padding: 3rem 0;
}

.areas-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 2rem;
  margin-top: 2rem;
}

.area-column h3 {
  color: var(--corp-primary);
  margin-bottom: 1rem;
}

.area-column ul {
  list-style: none;
  padding: 0;
}

.area-column li {
  padding: 0.25rem 0;
  color: var(--corp-muted);
}

.corporate-process {
  padding: 3rem 0;
  background: var(--corp-surface);
}

.process-steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 2rem;
  margin-top: 2rem;
}

.process-step {
  text-align: center;
}

.step-number {
  width: 3rem;
  height: 3rem;
  background: var(--corp-primary);
  color: white;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  font-size: 1.25rem;
  margin: 0 auto 1rem;
}

.process-step h3 {
  color: var(--corp-primary);
  margin-bottom: 1rem;
}

.corporate-cta {
  padding: 3rem 0;
  background: var(--corp-primary);
  color: white;
  text-align: center;
}

.corporate-cta h2 {
  color: white;
  margin-bottom: 1rem;
}

.cta-buttons {
  display: flex;
  gap: 1rem;
  justify-content: center;
  flex-wrap: wrap;
  margin: 2rem 0;
}

.cta-note {
  font-size: 0.875rem;
  opacity: 0.8;
  margin-top: 1rem;
}

.btn-secondary {
  background: transparent;
  border: 2px solid white;
  color: white;
}

.btn-secondary:hover {
  background: white;
  color: var(--corp-primary);
}

/* ─── Desktop builder layout (≥ 960 px) ─────────────────────────────────── */
@media (min-width: 960px) {
  /* Unchanged from the original 1040px — this "standard desktop" tier
     keeps its existing width. The >=1440px "wide desktop" tier further
     below widens it. Helium (30cm) used to carry its own separate, more
     specific 56rem .config-main override, which capped it well below this
     shared width on desktop while 45cm/60cm (no such override) inherited
     this rule directly — that's what made 30cm look noticeably smaller.
     Removed (see the 720px block below) so all three sizes share this one
     rule automatically. The sticky checkout bar below keeps its own
     1040px too, unchanged at every width. */
  .apex-lux .config-main {
    max-width: 1160px;
    padding-left: 2.5rem;
    padding-right: 2.5rem;
  }

  /* Stretch checkout bar to match content width */
  .apex-lux .checkout-bar {
    max-width: 1160px;
  }

  /* Desktop only: keep each subtotal line's price snug beside its label
     instead of stretching to the far right of the bar. */
  .apex-lux .checkout-bar__breakdown-label {
    flex: 0 1 auto;
  }

  /* Sub-category colour cards: 2-column grid */
  .number-subcat-grid.category-grid,
  .baby-subcat-grid.category-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
  }
  /* Restore border between right-column card and its neighbour */
  .number-subcat-grid .category-card:nth-child(odd),
  .baby-subcat-grid .category-card:nth-child(odd) {
    border-right: 1px solid var(--lux-line);
  }
}

/* ─── Wide desktop only (large monitors, ≥1440px) ──────────────────────────
   Widens .config-main (every product/category/checkout configurator page)
   beyond its 1040px "standard desktop" width above. Mobile, tablet and the
   720–1439px "standard/narrow desktop" tier are untouched. Helium (30cm)
   used to carry its own narrower 56rem .config-main/.checkout-bar override
   that won on specificity here — removed (see the 720px block above) so
   it now widens to 1400px along with every other configurator page,
   including 45cm/60cm which already did. The sticky checkout bar is
   reined in to match, below. */
@media (min-width: 1440px) {
  .apex-lux .config-main {
    max-width: 1760px;
  }

  /* Sticky Add to Cart bar — wide desktop only. Below this breakpoint the
     bar intentionally spans the full viewport (see the page-helium--simple
     rule above, and the standard-desktop 1040px cap further above) — those
     stay untouched. At ≥1440px only, pin the bar's own width/position to
     match .config-main (1400px, centred) instead of stretching edge-to-edge
     like the site header, while keeping it fixed to the viewport bottom.
     Helium (30cm) now gets this same generic 1400px treatment too. */
  .apex-lux .checkout-bar,
  .apex-lux.page-helium--simple .checkout-bar {
    left: 50%;
    right: auto;
    width: 100%;
    max-width: 1760px;
    transform: translateX(-50%);
    padding-left: 2.5rem;
    padding-right: 2.5rem;
    border-radius: 16px 16px 0 0;
  }
}

/* ─── Step 5: helium size-card visual treatment for the named bouquet
   sliders — Helium Number Balloon Bouquets (.page-number-combos), the
   Baby Shower / Gender Reveal / Graduation bouquet pages (all
   .page-baby-shower), and Balloon Centrepieces (.page-table-centrepieces,
   added in the Full Acceptance Audit round — Centrepieces now show a Ribbon/
   inclusion line + price "each" exactly like these other pages, so its
   Type-card title/inclusion/price rows must stack vertically the same way;
   the row-layout base rule left it as a single horizontal row, which is
   what the acceptance audit caught). Mirrors helium's Step-1 card look: the
   title and price stack and centre inside the meta strip, price bold. The
   count font itself is deliberately left to each page's own styling (these
   cards show product-name titles, not helium's numeric counts), and the
   selected-state burgundy fill / white text already come from the shared
   base .bouquet-set rules. Balloon Columns and standalone product pages
   remain intentionally excluded (different Type-card shape entirely). */
.apex-lux.page-number-combos .bouquet-set__meta-row,
.apex-lux.page-baby-shower .bouquet-set__meta-row,
.apex-lux.page-table-centrepieces .bouquet-set__meta-row {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 0.2rem;
}

.apex-lux.page-number-combos .bouquet-set__price,
.apex-lux.page-baby-shower .bouquet-set__price,
.apex-lux.page-table-centrepieces .bouquet-set__price {
  width: 100%;
  text-align: center;
  font-weight: 700;
}

/* Baby Shower Type-card typography correction round: this page never had
   its own .bouquet-set__count/.bouquet-set__price/.bouquet-set__price-each
   font-size rules (the shared block just above intentionally left the count
   font "to each page's own styling" — that styling was simply never
   written), so every card fell through to the old pre-lux base rules in
   styles.css/apex-ui.css (1.5rem/16px/16px, no letter-spacing, no
   uppercase, wrong "each"/inclusion-line colour and weight) instead of the
   compact approved 30cm Type-card sizing every other product-family page
   already has. Root cause confirmed via computed-style comparison against
   30cm (js/configurator.js's #packageGrid), not guessed. Values below are
   copied verbatim from .apex-lux.page-helium's own rules (canonical
   reference) — same numbers, same breakpoint, no new sizing invented.
   Baby Shower's Type titles are already full descriptive names ("Custom
   Teddy + 3 Balloons"), the same shape as Number Combos' titles, so
   ::after is suppressed exactly like .page-number-combos above (30cm's
   own ::after appends " Balloon Bouquet" to a bare number and must not be
   copied here). */
.apex-lux.page-baby-shower .bouquet-set__count::after {
  content: none;
}
.apex-lux.page-baby-shower .bouquet-set__count {
  font-family: var(--font-ui, inherit);
  font-size: 0.66rem !important;
  font-weight: 700;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  white-space: nowrap;
}
.apex-lux.page-baby-shower .bouquet-set__price {
  font-size: 0.85rem !important;
}
.apex-lux.page-baby-shower .bouquet-set__price-each {
  font-size: 0.62em;
  font-weight: 400;
  margin-left: 0.15em;
}
@media (min-width: 720px) {
  .apex-lux.page-baby-shower .bouquet-set__count {
    font-size: 0.68rem !important;
    letter-spacing: 0.003em;
    line-height: 1.2;
    padding-inline: 0.1rem;
  }
  .apex-lux.page-baby-shower .bouquet-set__price {
    font-size: 0.92rem !important;
  }
}

/* Balloon Centrepieces Type-card typography + FIT (build round, later
   superseded by the Pass 3 Final Specification round): this page never had
   its own .bouquet-set__count/__price font-size rules either (previously
   each product only ever showed a single fixed design, so the gap was
   latent — now that it carries real multi-Type products with titles as
   long as "White and Rose Gold Milestone", it needs exactly the same
   treatment Baby Shower just received). Values copied verbatim from
   .page-helium (canonical reference) — same numbers, no new sizing. No
   ::after suffix (titles are already full descriptive text). SUPERSEDED:
   Centrepieces now include 3 helium balloons + Ribbon in every final Type
   price (Pass 3 Final Specification round) and show the "Ribbon and 3
   Helium Balloons Inc." inclusion line — .page-table-centrepieces was
   added to the shared .bouquet-set__included selector list above. */
.apex-lux.page-table-centrepieces .bouquet-set__count::after {
  content: none;
}
.apex-lux.page-table-centrepieces .bouquet-set__count {
  font-family: var(--font-ui, inherit);
  font-size: 0.66rem !important;
  font-weight: 700;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  white-space: nowrap;
}
.apex-lux.page-table-centrepieces .bouquet-set__price {
  font-size: 0.85rem !important;
}
.apex-lux.page-table-centrepieces .bouquet-set__price-each {
  font-size: 0.62em;
  font-weight: 400;
  margin-left: 0.15em;
}
@media (min-width: 720px) {
  .apex-lux.page-table-centrepieces .bouquet-set__count {
    font-size: 0.68rem !important;
    letter-spacing: 0.003em;
    line-height: 1.2;
    padding-inline: 0.1rem;
  }
  .apex-lux.page-table-centrepieces .bouquet-set__price {
    font-size: 0.92rem !important;
  }
}
@media (max-width: 719px) {
  .apex-lux.page-table-centrepieces .bouquet-set {
    width: clamp(14rem, 58vw, 15.5rem);
  }
}

/* Baby Shower Type-card FIT correction, mobile (<720px): the generic
   unscoped .bouquet-set width rule (css/styles.css, clamp(9.25rem, 40vw,
   10.75rem), 172px ceiling) is what every product without its own mobile
   override falls back to — same 172px ceiling as the desktop narrow-slider
   stage, same too-narrow-for-this-content problem, confirmed live at 430px
   (card 172px, title "Custom Teddy + 3 Balloons" needs ~201px). Widened the
   same way as the 720-1099px fix above — slider mechanics (already the
   shared default mobile overflow-x: auto) are untouched, only the card
   width ceiling grows enough for the longest title/inclusion text. */
@media (max-width: 719px) {
  .apex-lux.page-baby-shower .bouquet-set {
    width: clamp(14rem, 58vw, 15.5rem);
  }
}

/* ─── Step 6: restore the approved helium desktop slider behaviour on every
   other configurator product slider. 720–1099px keeps a horizontally
   scrollable row with a real, visible desktop scrollbar (instead of the
   generic ≥960px flat grid); ≥1100px lays the cards out as a normal flat row.
   Helium itself keeps its own equivalent rules above; this block covers the
   remaining slider pages. */
@media (min-width: 720px) {
  .apex-lux.page-number-combos .bouquet-sets-scroll,
  .apex-lux.page-baby-shower .bouquet-sets-scroll,
  .apex-lux.page-corporate-columns .bouquet-sets-scroll,
  .apex-lux.page-graduation-column .bouquet-sets-scroll,
  .apex-lux.page-table-centrepieces .bouquet-sets-scroll {
    overflow-x: auto;
    overflow-y: hidden;
    flex-wrap: nowrap;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: 1rem;
    scroll-behavior: smooth;
    cursor: grab;
    scrollbar-width: auto;
    scrollbar-color: var(--lux-accent, #7a1528) var(--lux-bg, #f6eef0);
    padding-bottom: 0.85rem;
  }

  .apex-lux.page-number-combos .bouquet-sets-scroll::-webkit-scrollbar,
  .apex-lux.page-baby-shower .bouquet-sets-scroll::-webkit-scrollbar,
  .apex-lux.page-corporate-columns .bouquet-sets-scroll::-webkit-scrollbar,
  .apex-lux.page-graduation-column .bouquet-sets-scroll::-webkit-scrollbar,
  .apex-lux.page-table-centrepieces .bouquet-sets-scroll::-webkit-scrollbar {
    display: block;
    height: 10px;
  }

  .apex-lux.page-number-combos .bouquet-sets-scroll::-webkit-scrollbar-track,
  .apex-lux.page-baby-shower .bouquet-sets-scroll::-webkit-scrollbar-track,
  .apex-lux.page-corporate-columns .bouquet-sets-scroll::-webkit-scrollbar-track,
  .apex-lux.page-graduation-column .bouquet-sets-scroll::-webkit-scrollbar-track,
  .apex-lux.page-table-centrepieces .bouquet-sets-scroll::-webkit-scrollbar-track {
    background: var(--lux-bg, #f6eef0);
    border-radius: 6px;
  }

  .apex-lux.page-number-combos .bouquet-sets-scroll::-webkit-scrollbar-thumb,
  .apex-lux.page-baby-shower .bouquet-sets-scroll::-webkit-scrollbar-thumb,
  .apex-lux.page-corporate-columns .bouquet-sets-scroll::-webkit-scrollbar-thumb,
  .apex-lux.page-graduation-column .bouquet-sets-scroll::-webkit-scrollbar-thumb,
  .apex-lux.page-table-centrepieces .bouquet-sets-scroll::-webkit-scrollbar-thumb {
    background: var(--lux-accent, #7a1528);
    border-radius: 6px;
  }

  .apex-lux.page-number-combos .bouquet-sets-scroll:active,
  .apex-lux.page-baby-shower .bouquet-sets-scroll:active,
  .apex-lux.page-corporate-columns .bouquet-sets-scroll:active,
  .apex-lux.page-graduation-column .bouquet-sets-scroll:active,
  .apex-lux.page-table-centrepieces .bouquet-sets-scroll:active {
    cursor: grabbing;
  }

  .apex-lux.page-number-combos .bouquet-sets-scroll.is-dragging,
  .apex-lux.page-baby-shower .bouquet-sets-scroll.is-dragging,
  .apex-lux.page-corporate-columns .bouquet-sets-scroll.is-dragging,
  .apex-lux.page-graduation-column .bouquet-sets-scroll.is-dragging,
  .apex-lux.page-table-centrepieces .bouquet-sets-scroll.is-dragging {
    scroll-snap-type: none;
  }

  .apex-lux.page-number-combos .bouquet-sets,
  .apex-lux.page-baby-shower .bouquet-sets,
  .apex-lux.page-corporate-columns .bouquet-sets,
  .apex-lux.page-graduation-column .bouquet-sets,
  .apex-lux.page-table-centrepieces .bouquet-sets {
    display: flex;
    flex-wrap: nowrap;
    width: max-content;
  }

  .apex-lux.page-number-combos .bouquet-set,
  .apex-lux.page-corporate-columns .bouquet-set,
  .apex-lux.page-graduation-column .bouquet-set {
    flex: 0 0 auto;
    width: clamp(9.25rem, 22vw, 10.75rem);
    scroll-snap-align: center;
  }

  /* Balloon Centrepieces gets the exact same widened clamp() as Baby Shower
     just below, for the exact same reason (its longest Type title, "White
     and Rose Gold Milestone", is even longer than Baby Shower's longest).
     Same shared slider mechanics above, only the width ceiling differs. */
  .apex-lux.page-table-centrepieces .bouquet-set {
    flex: 0 0 auto;
    width: clamp(10.75rem, 30vw, 15rem);
    scroll-snap-align: center;
  }

  /* Baby Shower Type-card FIT correction (root-cause round): the container/
     slider mechanics above (overflow-x, scroll-snap, scrollbar) are fully
     shared and correct — proven identical to 30cm by direct computed-style
     comparison (172px card / 154px meta-row at 1024px on both pages). The
     actual bug is that this width formula was tuned for 30cm/Number Combos/
     Balloon Columns' SHORT titles ("5 Balloon Bouquet", ~120px) and never
     re-tuned for Baby Shower's genuinely longer content — its longest Type
     title ("Custom Teddy + 3 Balloons") measures ~201px and its inclusion
     line ("Decal, Ribbon and Weight Inc.") measures ~219px, both wider than
     the 172px card (154px available row width) the shared clamp() allows,
     so the text was overflowing its row and being clipped at the card edge
     — not a missing mechanism, a too-narrow shared width for this page's
     content. Fix: give Baby Shower its own wider clamp() ceiling (matching
     the same precedent 60cm/Heart already set — those pages also have
     comparably long titles, e.g. 60cm's "1 Balloon + Satin Bow Ribbon", and
     were given wider cards rather than smaller text). Slider mechanics
     (overflow-x/scroll-snap/scrollbar, shared above) are completely
     unchanged — cards still overflow and become horizontally scrollable at
     this range whenever 3 of them don't fit the row, exactly like 30cm. */
  .apex-lux.page-baby-shower .bouquet-set {
    flex: 0 0 auto;
    width: clamp(10.75rem, 30vw, 15rem);
    scroll-snap-align: center;
  }
}

@media (min-width: 1100px) {
  .apex-lux.page-number-combos .bouquet-sets-scroll,
  .apex-lux.page-baby-shower .bouquet-sets-scroll,
  .apex-lux.page-corporate-columns .bouquet-sets-scroll,
  .apex-lux.page-graduation-column .bouquet-sets-scroll,
  .apex-lux.page-table-centrepieces .bouquet-sets-scroll {
    overflow-x: visible;
    scroll-snap-type: none;
    -webkit-overflow-scrolling: auto;
    overscroll-behavior-x: auto;
    margin: 0;
    padding-inline: 0;
    cursor: default;
  }

  .apex-lux.page-number-combos .bouquet-sets,
  .apex-lux.page-baby-shower .bouquet-sets,
  .apex-lux.page-corporate-columns .bouquet-sets,
  .apex-lux.page-graduation-column .bouquet-sets,
  .apex-lux.page-table-centrepieces .bouquet-sets {
    width: 100%;
    gap: 0.55rem;
  }

  .apex-lux.page-number-combos .bouquet-set,
  .apex-lux.page-baby-shower .bouquet-set,
  .apex-lux.page-corporate-columns .bouquet-set,
  .apex-lux.page-graduation-column .bouquet-set,
  .apex-lux.page-table-centrepieces .bouquet-set {
    flex: 1 1 0;
    min-width: 0;
    width: auto;
    scroll-snap-align: unset;
    border-radius: var(--lux-radius);
    overflow: hidden;
  }
}

/* Number Bouquet product-type titles ("Number Only", "Number + 3 Balloons"
   etc) — full descriptive names now sit where a bare digit + the shared
   " Balloon Bouquet" suffix used to (see js/configurator.js countDisplay),
   so that suffix must not append here. Everything else below is an exact
   copy of Helium's own .bouquet-set__count treatment (same selectors,
   same values, just re-scoped to .page-number-combos) rather than a new
   styling variation — text length is comparable ("3 Balloon Bouquet" vs
   "Number + 3 Balloons"), so the same sizes fit cleanly at every width. */
.apex-lux.page-number-combos .bouquet-set__count::after {
  content: none;
}
.apex-lux.page-number-combos .bouquet-set__meta-row {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
}
.apex-lux.page-number-combos .bouquet-set__count {
  font-family: var(--font-ui, inherit);
  font-size: 0.66rem !important;
  font-weight: 700;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  white-space: nowrap;
}
@media (min-width: 720px) {
  .apex-lux.page-number-combos .bouquet-set__meta {
    padding: 0.4rem 0.5rem 0.45rem;
  }
  .apex-lux.page-number-combos .bouquet-set__meta-row {
    flex-direction: column;
    align-items: center;
    justify-content: center;
  }
  .apex-lux.page-number-combos .bouquet-set__count {
    font-size: 0.68rem !important;
    letter-spacing: 0.003em;
    line-height: 1.2;
    padding-inline: 0.1rem;
  }
}

/* "Ribbon and Weight Inc." — sits between the title and price on Helium
   Balloon Bouquets (30cm + 45cm), Helium Number Balloon Bouquets and Gender
   Reveal product-type cards. Compact by design (small/grey/tight
   line-height, deliberately smaller than .bouquet-set__count) so the card
   never grows taller to fit it and the title stays the dominant element
   (Type-card typography hierarchy rule, see CATALOGUE_COMPLETION_PLAN.md).
   .page-helium-45 was missing from this selector list (Type-card typography
   hierarchy round) — it fell through to no explicit font-size at all, i.e.
   the browser default (~16px), which made the inclusions line render LARGER
   than the 0.66rem/0.68rem title (10.88px/10.88px) on that page only — the
   one confirmed instance of the reported "backwards" hierarchy bug. Every
   other architecture with an inclusions line (30cm, Number Combos, Gender
   Reveal) already had title > inclusions live-verified before this round;
   this fix brings 45cm in line with them rather than changing already-
   correct sizes elsewhere. Baby Shower Type-card typography correction
   round: .page-baby-shower was the same kind of missing entry (fell
   through to no explicit font-size/colour at all), added here for the
   same reason. */
.apex-lux.page-helium .bouquet-set__included,
.apex-lux.page-helium-45 .bouquet-set__included,
.apex-lux.page-helium-60 .bouquet-set__included,
.apex-lux.page-helium-heart .bouquet-set__included,
.apex-lux.page-number-combos .bouquet-set__included,
.apex-lux.page-baby-shower .bouquet-set__included,
.apex-lux.page-table-centrepieces .bouquet-set__included,
.bouquet-set--gender-reveal .bouquet-set__included {
  display: block;
  font-size: 0.58rem;
  font-weight: 400;
  font-style: normal;
  color: var(--lux-muted, #6b5c60);
  text-align: center;
  line-height: 1.15;
  margin: 0.1rem 0 0;
  white-space: nowrap;
}

/* Gender Reveal product-type cards (Baby Boy/Girl, Supershape Boy/Girl,
   Gender Reveal Bouquet, Supershape Gender Reveal Bouquet) — exact copy of
   Helium's own .bouquet-set__count / .bouquet-set__price-each treatment
   (same selectors/values as the Number Combo copy above), scoped to the
   .bouquet-set--gender-reveal marker so unrelated Baby Shower products
   sharing the same page keep their own styling untouched. */
.bouquet-set--gender-reveal .bouquet-set__count::after {
  content: none;
}
.bouquet-set--gender-reveal .bouquet-set__count {
  font-family: var(--font-ui, inherit);
  font-size: 0.66rem !important;
  font-weight: 700;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  white-space: normal;
  line-height: 1.25;
}
.bouquet-set--gender-reveal .bouquet-set__price-each {
  font-size: 0.62em;
  font-weight: 400;
  margin-left: 0.15em;
}
@media (min-width: 720px) {
  .bouquet-set--gender-reveal .bouquet-set__count {
    font-size: 0.68rem !important;
    letter-spacing: 0.003em;
    line-height: 1.25;
  }
}

/* Helium Balloon Bouquets 45cm — Type cards (3 cards: "1/3/5 Balloon
   Bouquet"). Root cause of the desktop clipping bug (fixed two rounds ago):
   .page-helium-45 was never added to any of the page-class selector lists
   above (the shared flex shrink-to-fit mechanism used by .page-helium
   itself and by page-baby-shower/page-number-combos/page-corporate-columns/
   page-graduation-column/page-table-centrepieces), so at >=960px it fell
   back to the generic, non-page-scoped base rules in styles.css: a
   `display:grid; grid-template-columns:repeat(auto-fill,minmax(160px,1fr))`
   track list sized for an arbitrary card count, plus the oversized base
   `.bouquet-set__count` treatment (1.65rem font, `::after{content:"
   balloons"}` instead of the intended "N Balloon Bouquet" title) — the
   large title text then clipped/overflowed inside each card's
   `overflow:hidden` (.bouquet-set__card, line ~888/958).
   Fix reuses the exact same technique already proven on page-helium
   (bare digit + " Balloon Bouquet" suffix, small uppercase count font) and
   on the Gender Reveal Supershape reference (shrink-to-fit flex row:
   flex:1 1 0; min-width:0; width:auto — see the page-baby-shower rules in
   the (min-width:1100px) block above) — not a new one-off mechanism.

   MOBILE/TABLET FOLLOW-UP (this round): the desktop fix below was scoped to
   (min-width:960px) only, so <960px kept falling back to the same generic
   base rules described above (oversized 1.65rem count font, wrong " balloons"
   suffix, and a `.bouquet-set__meta-row` left in its base `flex-direction:row;
   justify-content:space-between` — title+price side-by-side). Root cause
   confirmed live at 375/390/430/768px: `.bouquet-set__meta-row` scrollWidth
   (167px) exceeded its clientWidth (132px) inside each ~150-172px-wide card,
   clipped by the card's `overflow:hidden`. Reference mechanism: .page-helium
   applies its own equivalent count/meta-row/price treatment UNCONDITIONALLY
   (no media query — see the .apex-lux.page-helium rules above, ~line 1611),
   so the card looks correct at every width, not just desktop; the >=960px
   block further below is only the shrink-to-fit *row layout* switch, not the
   text treatment. Porting that same all-widths pattern here (unscoped, no
   media query) rather than inventing a new mobile-only mechanism. */
.apex-lux.page-helium-45 .bouquet-set__count::after {
  content: " Balloon Bouquet";
}

.apex-lux.page-helium-45 .bouquet-set__meta-row {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 0.2rem;
}

.apex-lux.page-helium-45 .bouquet-set__count {
  font-family: var(--font-ui, inherit);
  font-size: 0.66rem !important;
  font-weight: 700;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  white-space: nowrap;
}

.apex-lux.page-helium-45 .bouquet-set__count::after {
  display: inline;
  margin: 0;
  font-size: inherit;
  font-weight: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
}

.apex-lux.page-helium-45 .bouquet-set__price {
  width: 100%;
  font-size: 0.85rem !important;
  font-weight: 700;
  text-align: center;
}

.apex-lux.page-helium-45 .bouquet-set__price-each {
  font-size: 0.62em;
  font-weight: 400;
  margin-left: 0.15em;
}

/* >=720px ("tablet+"): exact copy of .page-helium's own 720px count/price
   bump (see the .apex-lux.page-helium rules above, ~line 1829) — 45cm was
   missing this block entirely, so it stayed on the 0.66rem/0.85rem
   mobile-base sizes all the way up to 960px while 30cm had already bumped
   to 0.68rem/0.92rem at 720px. That gap (not any wrapping/clipping issue)
   was the actual cause of 45cm's price/title rendering smaller than 30cm's
   at 768px. Same selectors, same values as 30cm — not a new size. */
@media (min-width: 720px) {
  .apex-lux.page-helium-45 .bouquet-set__meta {
    padding: 0.4rem 0.5rem 0.45rem;
  }

  .apex-lux.page-helium-45 .bouquet-set__meta-row {
    flex-direction: column;
    align-items: center;
    justify-content: center;
  }

  .apex-lux.page-helium-45 .bouquet-set__count {
    font-size: 0.68rem !important;
    letter-spacing: 0.003em;
    line-height: 1.2;
    padding-inline: 0.1rem;
  }

  .apex-lux.page-helium-45 .bouquet-set__count::after {
    display: inline;
    margin: 0;
    font-size: inherit;
  }

  .apex-lux.page-helium-45 .bouquet-set__price {
    font-size: 0.92rem !important;
  }
}

/* Desktop-only (>=960px): switch the card row from the generic mobile
   horizontal-scroll slider to a flat shrink-to-fit flex row (layout only —
   the count/price font sizing is handled by the shared 720px block above,
   mirroring how .page-helium's own >=1100px block only touches layout, not
   fonts). Previously this block also redefined .bouquet-set__count with a
   line-height of 1.25 and white-space:normal, which diverged from 30cm's
   1.2 line-height / nowrap at the same widths — removed so 45cm falls
   through to the shared 720px block's values, identical to 30cm. */
@media (min-width: 960px) {
  .apex-lux.page-helium-45 .bouquet-sets {
    display: flex;
    flex-wrap: nowrap;
    width: 100%;
    gap: 0.55rem;
  }

  .apex-lux.page-helium-45 .bouquet-set {
    flex: 1 1 0;
    min-width: 0;
    width: auto;
    scroll-snap-align: unset;
  }
}

/* Helium Balloon Bouquets 60cm — Type cards (3 cards: "1 Balloon" / "1
   Balloon + Satin Bow Ribbon" / "1 Balloon + Tassel Tail"). NEW rule block
   (B1 shell pass) — does NOT modify any .page-helium-45 rule above. Reuses
   the exact same typography values already proven correct on 30cm/45cm
   (Type-card typography hierarchy rule, CATALOGUE_COMPLETION_PLAN.md), not
   invented one-off sizing. Unlike 45cm, 60cm's .bouquet-set__count text is
   already the full Type title (e.g. "1 Balloon + Satin Bow Ribbon", set via
   js/configurator.js's countDisplay), not a bare digit — so no ::after
   suffix is added here. */
.apex-lux.page-helium-60 .bouquet-set__count::after {
  content: none;
}

.apex-lux.page-helium-60 .bouquet-set__meta-row {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 0.2rem;
}

.apex-lux.page-helium-60 .bouquet-set__count {
  font-family: var(--font-ui, inherit);
  font-size: 0.66rem !important;
  font-weight: 700;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  white-space: nowrap;
}

.apex-lux.page-helium-60 .bouquet-set__price {
  width: 100%;
  font-size: 0.85rem !important;
  font-weight: 700;
  text-align: center;
}

.apex-lux.page-helium-60 .bouquet-set__price-each {
  font-size: 0.62em;
  font-weight: 400;
  margin-left: 0.15em;
}

/* >=720px ("tablet+"): exact copy of .page-helium/.page-helium-45's own
   720px count/price bump — same selectors, same values, not a new size. */
@media (min-width: 720px) {
  .apex-lux.page-helium-60 .bouquet-set__meta {
    padding: 0.4rem 0.5rem 0.45rem;
  }

  .apex-lux.page-helium-60 .bouquet-set__meta-row {
    flex-direction: column;
    align-items: center;
    justify-content: center;
  }

  .apex-lux.page-helium-60 .bouquet-set__count {
    font-size: 0.68rem !important;
    letter-spacing: 0.003em;
    line-height: 1.2;
    padding-inline: 0.1rem;
  }

  .apex-lux.page-helium-60 .bouquet-set__price {
    font-size: 0.92rem !important;
  }
}

/* Desktop-only (>=960px): switch the card row from the generic mobile
   horizontal-scroll slider to a flat shrink-to-fit flex row (layout only),
   exact copy of the .page-helium-45 >=960px block. */
@media (min-width: 960px) {
  .apex-lux.page-helium-60 .bouquet-sets {
    display: flex;
    flex-wrap: nowrap;
    width: 100%;
    gap: 0.55rem;
  }

  .apex-lux.page-helium-60 .bouquet-set {
    flex: 1 1 0;
    min-width: 0;
    width: auto;
    scroll-snap-align: unset;
  }
}

/* Helium Heart Bouquets — Type cards (5 cards: "1 Heart" / "2 Hearts" /
   "3 Hearts" / "4 Hearts" / "6 Hearts"). Exact copy of the .page-helium-60
   block above — Heart's .bouquet-set__count text is also the full Type
   title (js/configurator.js countDisplay), not a bare digit, so no ::after
   suffix is added here either. Does NOT modify .page-helium-45/-60 rules. */
.apex-lux.page-helium-heart .bouquet-set__count::after {
  content: none;
}

.apex-lux.page-helium-heart .bouquet-set__meta-row {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 0.2rem;
}

.apex-lux.page-helium-heart .bouquet-set__count {
  font-family: var(--font-ui, inherit);
  font-size: 0.66rem !important;
  font-weight: 700;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  white-space: nowrap;
}

.apex-lux.page-helium-heart .bouquet-set__price {
  width: 100%;
  font-size: 0.85rem !important;
  font-weight: 700;
  text-align: center;
}

.apex-lux.page-helium-heart .bouquet-set__price-each {
  font-size: 0.62em;
  font-weight: 400;
  margin-left: 0.15em;
}

@media (min-width: 720px) {
  .apex-lux.page-helium-heart .bouquet-set__meta {
    padding: 0.4rem 0.5rem 0.45rem;
  }

  .apex-lux.page-helium-heart .bouquet-set__meta-row {
    flex-direction: column;
    align-items: center;
    justify-content: center;
  }

  .apex-lux.page-helium-heart .bouquet-set__count {
    font-size: 0.68rem !important;
    letter-spacing: 0.003em;
    line-height: 1.2;
    padding-inline: 0.1rem;
  }

  .apex-lux.page-helium-heart .bouquet-set__price {
    font-size: 0.92rem !important;
  }
}

@media (min-width: 960px) {
  .apex-lux.page-helium-heart .bouquet-sets {
    display: flex;
    flex-wrap: nowrap;
    width: 100%;
    gap: 0.55rem;
  }

  .apex-lux.page-helium-heart .bouquet-set {
    flex: 1 1 0;
    min-width: 0;
    width: auto;
    scroll-snap-align: unset;
  }
}

/* ─── Standalone product gallery image sizing (shared) ─────────────────────
   Consistent image sizing shared across every standalone product (not just
   Ceiling Balloons): the main image fits a fixed-aspect container without
   stretching or cropping (object-fit: contain preserves the full balloon
   arrangement), and never upscales past its natural resolution.
   NOTE: the previous generic .page-standalone-product / .standalone-
   product-gallery two-column desktop grid that used to live here has been
   REMOVED and superseded — standalone product pages now follow the Balloon
   Columns layout reference (shop/products/balloon-column.html /
   body.page-corporate-columns) directly, implemented per-page in that
   page's own scoped inline <style> (see shop/helium-ceiling-balloons.html
   for the Ceiling Balloons implementation), not as a shared generic class
   here. See docs/catalogue/CATALOGUE_COMPLETION_PLAN.md's "Confirmed global
   implementation rules" for the standing rule. */
.standalone-product-gallery__main,
.ceiling-gallery__main {
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: 12px;
  /* Plain white, not var(--lux-surface) (#fafafa) — the Party Pole /
     Balloon Column reference (shop/products/balloon-column.html's
     .col-gallery-desktop__main) uses a flat #fff main-image background
     with no grey card tint. Using --lux-surface here was the actual root
     cause of the "grey shaded box" around the main image reported as
     still present despite an earlier round claiming it fixed. */
  background: #fff;
}
.standalone-product-gallery__main img,
.ceiling-gallery__main img {
  width: 100%;
  height: 100%;
  max-width: 100%;
  object-fit: contain;
  border-radius: 12px;
  display: block;
  cursor: zoom-in;
  transform-origin: center center;
  transition: transform 0.15s ease-out;
  will-change: transform;
}
.ceiling-gallery__main.is-zoomed img {
  transform: scale(2);
  transition: none;
}

/* Helium Ceiling Balloons product page — simple gallery + qty stepper.
   Real lifestyle photos (customer ceilings), not flat-white studio shots,
   so no mix-blend-mode treatment here (unlike the shop-hub tile thumbnails
   above). */
.ceiling-gallery {
  max-width: 640px;
  margin: 0 auto 1.25rem;
  padding: 0 1rem;
}
.ceiling-gallery__main img {
  width: 100%;
  border-radius: 12px;
  display: block;
  cursor: zoom-in;
}
.ceiling-gallery__thumbs {
  display: flex;
  gap: 0.5rem;
  overflow-x: auto;
  margin-top: 0.6rem;
  padding-bottom: 0.25rem;
}
.ceiling-gallery__thumb {
  flex: 0 0 auto;
  width: 56px;
  height: 56px;
  border-radius: 8px;
  overflow: hidden;
  border: 2px solid transparent;
  padding: 0;
  background: none;
  cursor: pointer;
}
.ceiling-gallery__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.ceiling-gallery__thumb.is-active {
  border-color: var(--brand-primary, #7a1f3d);
}
/* NOTE: the previous .ceiling-qty custom round-button qty control and
   .page-helium-ceiling-balloons .lead-note (duplicate per-balloon/minimum
   text under the header) have been REMOVED — quantity now uses the shared
   Balloon Columns .qty-stepper--card control (css/apex-ui.css) and the
   per-balloon/minimum text now appears exactly once, as STEP 1's helper
   text (see shop/helium-ceiling-balloons.html's .qty-helper-text). */
