/* Solris — single product page, bundle selector, A+ content. */

.single-product .woo-wrap{padding-block:var(--sp-6) var(--sp-16)}

/* ---------- two-column layout ---------- */
/* `minmax(0,1fr)` on the single-column case is load-bearing, not decoration.
   A grid track defaults to `auto`, which floors at the item's min-content
   width — and the gallery's min-content width is the product image's
   intrinsic 600px. On a 360px phone that pushed the page 293px wide and gave
   the whole product page a horizontal scrollbar. `minmax(0,...)` lets the
   track shrink below min-content so `max-width:100%` on the image can do its
   job. The `min-width:0` on children is the same fix one level down. */
.single-product div.product{display:grid;gap:var(--sp-8);align-items:start;
  grid-template-columns:minmax(0,1fr)}
.single-product div.product>*{min-width:0}
@media (min-width:1024px){
  .single-product div.product{
    grid-template-columns:minmax(0,58fr) minmax(360px,42fr);
    gap:var(--sp-10) var(--sp-12);
  }

  /* Everything below the fold spans both columns; only the gallery and the
     summary are placed side by side.
     
     This is written as "span by default, place the two exceptions" rather
     than as a list of things to span, because `div.product` is a hook target:
     WooCommerce, Judge.me and any plugin can add children to it. Enumerating
     what to span means every new plugin silently drops a section into the
     narrow left column — which is exactly what happened to the FAQ block and
     the Judge.me review widget. */
  .single-product div.product>*{grid-column:1 / -1}
  .single-product div.product>.gallery{grid-column:1;grid-row:1}
  .single-product div.product>.summary{grid-column:2;grid-row:1}

  /* NOT sticky — deliberately.
     Chrome sticks a grid item inside the grid CONTAINER rather than inside
     its own grid area, so a sticky summary escapes row 1 and rides down over
     the A+ content, the FAQ and the related products. The workarounds all
     involve an extra wrapper that WooCommerce does not give us a hook to add.
     The mobile sticky add-to-cart bar already solves the real problem (a
     reachable CTA on a long page), and on desktop the gallery and the summary
     are close enough in height that sticky bought very little anyway. */ 
}

/* Hook targets that render nothing still occupy a grid cell and contribute a
   row gap, opening unexplained vertical holes between sections. */
.single-product div.product>div:empty{display:none}

/* Sections rendered by plugins carry their own .container, which would nest
   inside the page container and pinch the width. Inside the product grid the
   grid already owns the measure. */
.single-product div.product>.container{width:auto;max-width:none;margin-inline:0}

/* ---------- gallery ---------- */
.gallery__stage{position:relative;isolation:isolate}
.gallery__badge{position:absolute;top:var(--sp-4);left:var(--sp-4);z-index:3}
/* Woo prints .onsale in a few other places; never let it be a grid item. */
.single-product div.product>.onsale{display:none}

.gallery__track{display:grid;grid-auto-flow:column;grid-auto-columns:100%;
  list-style:none;margin:0;padding:0;gap:0;
  overflow-x:auto;scroll-snap-type:x mandatory;scroll-behavior:smooth;
  overscroll-behavior-inline:contain;scrollbar-width:none;
  border-radius:var(--r-lg);background:var(--surface-2)}
.gallery__track::-webkit-scrollbar{display:none}
.gallery__slide{scroll-snap-align:center;scroll-snap-stop:always}
.gallery__slide .ratio-box{border-radius:var(--r-lg)}
@media (prefers-reduced-motion:reduce){ .gallery__track{scroll-behavior:auto} }

/* Arrows on EVERY device. They used to be hidden at `hover:none` on the
   theory that touch users swipe — but a swipe is invisible, and on a product
   page the arrows are what tell you there is more than one photo at all. They
   cost 40px of a corner and they are the single clearest "there is more"
   signal the gallery has. */
.gallery__arrow{position:absolute;top:50%;transform:translateY(-50%);z-index:2;
  display:grid;place-items:center;width:40px;height:40px;border-radius:var(--r-pill);
  background:rgb(255 255 255/.94);color:var(--navy-800);
  box-shadow:0 2px 10px rgb(14 35 64/.18),0 0 0 1px rgb(14 35 64/.08);
  transition:background-color .15s ease,opacity .15s ease,transform .15s ease}
.gallery__arrow:hover{background:#fff}
.gallery__arrow:active{transform:translateY(-50%) scale(.94)}
.gallery__arrow:focus-visible{box-shadow:var(--sh-focus);outline:none}
.gallery__arrow--prev{left:var(--sp-3)}
.gallery__arrow--next{right:var(--sp-3)}
.gallery__arrow[disabled]{opacity:0;pointer-events:none}

/* Zoom affordance — visible, not discovered by guessing. */
.gallery__zoom{position:absolute;right:var(--sp-3);bottom:var(--sp-3);z-index:2;
  display:inline-flex;align-items:center;gap:6px;
  min-height:36px;padding:0 10px;border-radius:var(--r-pill);
  background:rgb(14 35 64/.72);color:#fff;backdrop-filter:blur(6px);
  transition:background-color .15s ease}
.gallery__zoom:hover{background:rgb(14 35 64/.88)}
.gallery__zoom:focus-visible{box-shadow:var(--sh-focus);outline:none}
.gallery__slide{cursor:zoom-in}

/* Indicators sit ON the photo, so they need their own contrast, not the
   photo's. A translucent white pill over a white product shot is invisible —
   which is what these were. Dark track, white active. */
.gallery__dots{position:absolute;inset-inline:0;bottom:var(--sp-3);z-index:2;
  display:flex;justify-content:center;gap:6px;list-style:none;margin:0;padding:0;
  pointer-events:none}
.gallery__dots li{pointer-events:auto;display:flex}
.gallery__dots button{display:block;width:8px;height:8px;padding:0;border:0;
  border-radius:var(--r-pill);background:rgb(14 35 64/.30);
  box-shadow:0 0 0 1.5px rgb(255 255 255/.85);cursor:pointer;
  transition:width .2s ease,background-color .2s ease}
.gallery__dots button:hover{background:rgb(14 35 64/.55)}
.gallery__dots [aria-current]{width:22px;background:var(--navy-800)}
.gallery__dots button:focus-visible{box-shadow:var(--sh-focus);outline:none}

/* ---------- zoom viewer ---------- */
.lightbox{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;
  margin:0;padding:0;border:0;background:var(--navy-900,#0B1B33);color:#fff;
  overflow:hidden}
.lightbox:not([open]){display:none}
.lightbox[open]{display:grid;grid-template-rows:auto 1fr auto}
.lightbox::backdrop{background:rgb(7 16 32/.94)}

.lightbox__bar{display:flex;align-items:center;justify-content:space-between;
  gap:var(--sp-3);padding:var(--sp-3) var(--sp-4);
  padding-block-start:max(var(--sp-3),env(safe-area-inset-top))}
.lightbox__count{margin:0;font-size:var(--fs--1);color:rgb(255 255 255/.72);
  font-variant-numeric:tabular-nums}
.lightbox__close{color:#fff;width:40px;height:40px;border-radius:var(--r-pill);
  display:grid;place-items:center;background:rgb(255 255 255/.14);
  box-shadow:0 0 0 1px rgb(255 255 255/.18)}
.lightbox__close:hover{background:rgb(255 255 255/.26)}

.lightbox__stage{position:relative;display:grid;place-items:center;
  overflow:auto;overscroll-behavior:contain;padding:var(--sp-2);cursor:zoom-in}
.lightbox__stage.is-zoomed{cursor:zoom-out}
.lightbox__img{max-width:100%;max-height:100%;width:auto;height:auto;
  object-fit:contain;transition:transform .25s ease;will-change:transform}
@media (prefers-reduced-motion:reduce){ .lightbox__img{transition:none} }

/* Solid, not translucent. These sit OVER the photo, and most of this
   catalogue is shot on white — a 12%-white pill on a white background is an
   invisible control. Dark fill plus a light ring reads on both the dark
   chrome above and the photo behind. */
.lightbox__arrow{position:absolute;top:50%;transform:translateY(-50%);z-index:2;
  display:grid;place-items:center;width:44px;height:44px;border-radius:var(--r-pill);
  background:rgb(8 22 41/.82);color:#fff;backdrop-filter:blur(6px);
  box-shadow:0 0 0 1px rgb(255 255 255/.22),0 4px 14px rgb(0 0 0/.35);
  transition:background-color .15s ease,transform .15s ease}
.lightbox__arrow:hover{background:rgb(8 22 41/.95)}
.lightbox__arrow:active{transform:translateY(-50%) scale(.94)}
.lightbox__arrow:focus-visible{box-shadow:var(--sh-focus);outline:none}
.lightbox__arrow--prev{left:var(--sp-3)}
.lightbox__arrow--next{right:var(--sp-3)}

.lightbox__hint{margin:0;padding:var(--sp-3) var(--sp-4);text-align:center;
  font-size:var(--fs--2);color:rgb(255 255 255/.55);
  padding-block-end:max(var(--sp-3),env(safe-area-inset-bottom))}

.gallery__thumbs{display:flex;gap:var(--sp-2);list-style:none;margin:var(--sp-3) 0 0;padding:0 0 4px;
  overflow-x:auto;scrollbar-width:thin;overscroll-behavior-inline:contain}
.gallery__thumb{width:64px;height:64px;border:2px solid var(--border);border-radius:var(--r-sm);
  overflow:hidden;padding:0;flex:0 0 auto;background:var(--surface-2);
  transition:border-color .15s ease}
@media (min-width:768px){ .gallery__thumb{width:76px;height:76px} }
.gallery__thumb img{width:100%;height:100%;object-fit:cover}
.gallery__thumb.is-current{border-color:var(--navy-800);
  box-shadow:0 0 0 2px var(--amber-400)}
.gallery__thumb:focus-visible{box-shadow:var(--sh-focus);outline:none}

/* ---------- summary ---------- */
/* The purchase box is a single vertical rhythm: every direct child is a row
   with the same gap, so the title, price, variations, packs, quantity, CTA
   and trust block line up on one edge at every width. Woo injects its own
   markup here, so the spacing is owned by the container, not by each part. */
.summary{display:flex;flex-direction:column;gap:var(--sp-4);align-items:stretch}
.summary>*{margin:0}

.summary .product_title{font-size:var(--fs-3);line-height:var(--lh-snug)}
.summary .price{font-size:var(--fs-4);font-weight:var(--fw-bold);color:var(--price);
  font-variant-numeric:tabular-nums;display:flex;align-items:baseline;gap:var(--sp-3);
  flex-wrap:wrap;line-height:1.1}
.summary .price del{font-size:var(--fs-1);font-weight:var(--fw-regular);color:var(--ink-3);
  order:-1;text-decoration-thickness:1px}
.summary .price ins{text-decoration:none;color:var(--price-sale)}
.summary .price .woocommerce-Price-amount{white-space:nowrap}

.woocommerce-product-details__short-description{color:var(--ink-2);font-size:var(--fs-0)}
.woocommerce-product-details__short-description p{margin:0}
.woocommerce-product-rating{display:flex;align-items:center;gap:var(--sp-2);
  font-size:var(--fs--1);color:var(--ink-3)}
.woocommerce-product-rating .star-rating{margin:0}

/* ---------- variations ---------- */
.variations{display:grid;gap:var(--sp-3);margin:0;width:100%}
.variations tbody,.variations tr,.variations td,.variations th{display:block;width:100%;
  padding:0;border:0;background:none}
.variations .label{margin-block-end:6px}
.variations label{font-size:var(--fs--1);font-weight:var(--fw-semibold);
  color:var(--ink-2);margin:0}
.variations select{width:100%;min-height:48px}
.reset_variations{display:inline-block;font-size:var(--fs--1);color:var(--ink-3);
  margin-block-start:var(--sp-2)}
.woocommerce-variation-price{font-size:var(--fs-3);font-weight:var(--fw-bold);
  font-variant-numeric:tabular-nums}
.woocommerce-variation-availability{font-size:var(--fs--1);color:var(--ink-2)}

/* ---------- add to cart row ---------- */
/* Quantity and the CTA share one row on every width: a full-width quantity
   field above a full-width button wastes the most valuable strip of the page
   and reads as two equally important controls, which they are not. */
/* The purchase stack is ONE column with ONE gap.
   Woo prints these controls as bare siblings: for a variable product the row,
   the Buy it now button, <wc-order-attribution-inputs>, Stripe's express
   wrappers and three hidden inputs all land inside .woocommerce-variation-add-to-cart
   with no wrapper and no layout. Because Buy it now is a 100%-wide button —
   inline-level — every inline sibling after it opens its own line box, and
   that stack of empty line boxes is the dead band under the button. Declaring
   the wrapper a grid removes line boxes entirely, so spacing comes only from
   `gap` and only between things that actually render. */
form.cart,
form.cart .woocommerce-variation-add-to-cart{display:grid;gap:var(--sp-3);margin:0;width:100%}

/* Grid and flex items default to `min-width:auto` — "never shrink below your
   own content". The pack rail's min-content is the full width of every pack
   laid end to end, so without this the wrapper grows to that width and takes
   the page with it, and the rail never scrolls because it was never
   constrained. Every box between the summary and the rail has to opt out. */
.summary > *,
form.cart > *,
form.cart .woocommerce-variation-add-to-cart > *,
form.cart .single_variation_wrap,
form.cart .single_variation_wrap > *{min-width:0}

/* Add to cart and Buy it now are one control pair and read as one, so they
   sit closer to each other (8px) than to anything else in the form (12px).
   One rule, expressed against the shared gap, so it holds for a simple
   product (parent: form.cart) and a variable one (parent: the variation
   wrapper) without either container needing its own override. */
.solris-buy-row + .solris-buy-now{margin-block-start:calc(var(--sp-2) - var(--sp-3))}

/* Bookkeeping elements render nothing but would each still take a grid row,
   and a row costs a gap. The .single_variation alert box is Woo's slot for
   the selected variation's price and stock line; we already show both in the
   summary, so while it is empty it is one more invisible row. */
form.cart wc-order-attribution-inputs,
form.cart input[type="hidden"],
form.cart .single_variation:empty,
form.cart .wc-stripe-clear{display:none}
form.cart .quantity{display:inline-flex;align-items:center;height:52px;
  border:1.5px solid var(--border-strong);border-radius:var(--r-md);overflow:hidden;
  margin:0;flex:0 0 auto;background:var(--surface)}
form.cart .quantity input{width:56px;min-height:50px;border:0;text-align:center;
  font-weight:var(--fw-semibold);font-variant-numeric:tabular-nums;
  -moz-appearance:textfield;background:none}
form.cart .quantity input::-webkit-outer-spin-button,
form.cart .quantity input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.solris-qty-btn{width:40px;height:50px;display:grid;place-items:center;
  color:var(--ink-2);font-size:var(--fs-1);line-height:1;background:none;border:0}
.solris-qty-btn:hover{background:var(--navy-50);color:var(--ink)}
.solris-qty-btn:disabled{color:var(--navy-300);cursor:not-allowed}

.solris-buy-row{display:flex;gap:var(--sp-3);align-items:stretch;width:100%}
.single_add_to_cart_button{flex:1 1 auto;display:inline-flex;align-items:center;
  justify-content:center;min-height:52px;padding:0 var(--sp-6);border-radius:var(--r-md);
  background:var(--amber-400);color:var(--navy-800);
  font-weight:var(--fw-semibold);font-size:var(--fs-1);border:0;cursor:pointer;
  transition:background-color .15s ease;white-space:nowrap}
.single_add_to_cart_button:hover{background:var(--amber-300)}
.single_add_to_cart_button:active{background:var(--amber-500)}
.single_add_to_cart_button:focus-visible{box-shadow:var(--sh-focus);outline:none}
.single_add_to_cart_button.disabled,.single_add_to_cart_button[disabled]{
  background:var(--navy-100);color:var(--navy-300);cursor:not-allowed}
.solris-buy-now{display:block;width:100%;min-height:52px}

/* Woo's own variation dropdowns stay in the DOM (the pack selector mirrors
   into them) but are hidden when a pack selector is present. */
.packs ~ .variations,
.variations:has(~ * .packs){display:none}
[data-packs] + .variations{display:none}

/* ---------- pack selector ---------- */
/* A <fieldset> defaults to `min-inline-size: min-content` and will not shrink
 * below its contents — so instead of the pack rail scrolling inside it, the
 * fieldset grew to the rail's full width and pushed the whole page sideways.
 * This one line is what makes the rail scroll rather than overflow. */
.packs{border:0;padding:0;margin:var(--sp-5) 0;min-inline-size:0}
.packs__legend{font-size:var(--fs-0);font-weight:var(--fw-semibold);padding:0;margin-block-end:var(--sp-1)}
.packs__help{font-size:var(--fs--1);color:var(--ink-3);margin-block-end:var(--sp-3)}
/* One row at every width — but never a squeezed one.
 *
 * The packs used to be `repeat(var(--pack-count), 1fr)` with the type shrunk
 * to 9-10px below 480px so four would always fit. Four packs across a 390px
 * phone is ~91px per card carrying a name, a price, a per-light price and a
 * save badge: technically one row, actually unreadable.
 *
 * `grid-auto-columns: minmax(--pack-min, 1fr)` does both jobs with one rule.
 * While the packs fit, `1fr` divides the row exactly and nothing scrolls.
 * Once they do not, the minimum wins, the track overflows, and the row is a
 * scroll-snap rail. No media query decides this — the content does, so it
 * behaves the same for two packs as for six. */
.packs__grid{--pack-min:118px;
  display:grid;grid-auto-flow:column;grid-auto-columns:minmax(var(--pack-min),1fr);
  gap:var(--sp-2);
  overflow-x:auto;overscroll-behavior-x:contain;scroll-snap-type:x proximity;
  scrollbar-width:none;
  /* overflow-x:auto makes overflow-y `auto` too, which would clip the "Best
     value" ribbon hanging above the card. Pad the box instead of moving the
     ribbon. */
  padding-block:12px 4px;margin-block:-12px -4px;
}
.packs__grid::-webkit-scrollbar{display:none}
.pack{scroll-snap-align:center}

@media (min-width:480px){ .packs__grid{gap:var(--sp-3)} }

/* Two packs should not be two enormous slabs. */
.packs__grid:has(.pack:nth-child(2):last-child){grid-auto-columns:minmax(var(--pack-min),200px)}

.pack{position:relative;display:flex;flex-direction:column;gap:2px;
  padding:var(--sp-4) var(--sp-3);border:2px solid var(--border);border-radius:var(--r-md);
  background:var(--surface);cursor:pointer;text-align:center;
  transition:border-color .15s ease,background-color .15s ease,box-shadow .15s ease}
.pack:hover{border-color:var(--border-strong)}
.pack:has(input:checked){border-color:var(--navy-800);background:var(--amber-100);box-shadow:var(--sh-glow)}
/* The selected state paints a cream panel. In dark mode the surrounding ink
   is near-white, so it would land light-on-light; pin the ink to navy for
   this panel only rather than re-tinting the whole component. */
:root[data-theme="dark"] .pack:has(input:checked),
:root[data-theme="dark"] .pack:has(input:checked) .pack__name,
:root[data-theme="dark"] .pack:has(input:checked) .pack__price,
:root[data-theme="dark"] .pack:has(input:checked) .pack__unit,
:root[data-theme="dark"] .pack:has(input:checked) .pack__check{color:var(--navy-800)}
:root[data-theme="dark"] .pack:has(input:checked){border-color:var(--amber-400)}
.pack:has(input:focus-visible){box-shadow:var(--sh-focus)}
.pack.is-oos{opacity:.55;cursor:not-allowed}
.pack__name{font-size:var(--fs-0);font-weight:var(--fw-semibold)}
.pack__price{font-size:var(--fs-1);font-weight:var(--fw-bold);font-variant-numeric:tabular-nums}
.pack__unit{font-size:var(--fs--1);color:var(--ink-2);font-variant-numeric:tabular-nums}
.pack__save{display:inline-block;margin-block-start:var(--sp-1);padding:2px 8px;
  border-radius:var(--r-sm);background:var(--orange-50);color:var(--orange-600);
  font-size:var(--fs--2);font-weight:var(--fw-semibold)}
.pack__oos{font-size:var(--fs--2);color:var(--ink-3);font-weight:var(--fw-semibold)}
.pack__ribbon{position:absolute;top:-11px;left:50%;transform:translateX(-50%);
  padding:2px 9px;border-radius:var(--r-sm);font-size:10px;font-weight:var(--fw-bold);
  text-transform:uppercase;letter-spacing:var(--ls-caps);white-space:nowrap}
.pack__ribbon--popular{background:var(--amber-400);color:var(--navy-800)}
.pack__ribbon--best{background:var(--navy-800);color:var(--amber-400)}
.pack__check{position:absolute;top:6px;right:6px;opacity:0;color:var(--navy-800)}
.pack:has(input:checked) .pack__check{opacity:1}
.pack__check svg{stroke:currentColor;stroke-width:3;fill:none}

/* ---------- A+ content ---------- */
.aplus{margin-block-start:var(--sp-16);display:flex;flex-direction:column;gap:var(--sp-16)}
.aplus__eyebrow{font-size:var(--fs--1);font-weight:var(--fw-semibold);text-transform:uppercase;
  letter-spacing:var(--ls-caps);color:var(--accent-text);margin-block-end:var(--sp-2)}
.aplus__title{text-align:center;margin-block-end:var(--sp-8)}

.aplus-banner{position:relative;isolation:isolate;border-radius:var(--r-lg);overflow:hidden;
  background:var(--navy-800)}
.aplus-banner__media{border-radius:0}
.aplus-banner__content{padding:var(--sp-8) var(--sp-6)}
@media (min-width:768px){
  .aplus-banner__media{position:absolute;inset:0;z-index:-2}
  .aplus-banner::after{content:"";position:absolute;inset:0;z-index:-1;
    background:linear-gradient(to right,rgb(14 35 64/.9),rgb(14 35 64/.35) 65%,transparent)}
  .aplus-banner__content{max-width:540px;padding:var(--sp-16) var(--sp-10);min-height:360px;
    display:flex;flex-direction:column;justify-content:center}
}
.aplus-banner__content h2{color:#fff}
.aplus-banner__content p{color:var(--navy-100);margin-block-start:var(--sp-3)}
.aplus-banner .aplus__eyebrow{color:var(--amber-400)}

/* Two up from the narrowest phone. One per row turned six short benefits into
   a column of isolated icons three screens tall. */
.aplus-benefits__grid{display:grid;gap:var(--sp-5) var(--sp-4);list-style:none;margin:0;padding:0;
  grid-template-columns:repeat(2,minmax(0,1fr))}
@media (min-width:768px){ .aplus-benefits__grid{grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--sp-8)} }
@media (min-width:1024px){ .aplus-benefits__grid{grid-template-columns:repeat(4,minmax(0,1fr))} }
.aplus-benefits__icon{width:40px;height:40px;margin-block-end:var(--sp-2)}
.aplus-benefits__icon svg{width:20px;height:20px}
.aplus-benefits h3{font-size:var(--fs-0);line-height:1.3}
.aplus-benefits p{font-size:var(--fs--1)}
@media (min-width:768px){
  .aplus-benefits__icon{width:48px;height:48px}
  .aplus-benefits__icon svg{width:24px;height:24px}
  .aplus-benefits h3{font-size:var(--fs-1)}
  .aplus-benefits p{font-size:var(--fs-0)}
}
.aplus-benefits__icon{display:inline-grid;place-items:center;width:48px;height:48px;
  border-radius:var(--r-pill);background:var(--navy-800);margin-block-end:var(--sp-3)}
.aplus-benefits__icon svg{stroke:var(--amber-400);fill:none;stroke-width:1.75}
.aplus-benefits h3{font-size:var(--fs-1);margin-block-end:var(--sp-2)}
.aplus-benefits p{color:var(--ink-2);font-size:var(--fs-0)}

.aplus-zigzag{display:grid;gap:var(--sp-6);align-items:center}
@media (min-width:768px){
  .aplus-zigzag{grid-template-columns:1fr 1fr;gap:var(--sp-10)}
  .aplus-zigzag.is-flipped .aplus-zigzag__media{order:2}
}
.aplus-zigzag h2{margin-block-end:var(--sp-3)}
.aplus-zigzag p{color:var(--ink-2)}

.aplus-daynight{display:grid;gap:var(--sp-4)}
@media (min-width:480px){ .aplus-daynight{grid-template-columns:1fr 1fr} }
.aplus-daynight figcaption{display:flex;align-items:center;justify-content:center;gap:var(--sp-2);
  margin-block-start:var(--sp-3);font-weight:var(--fw-semibold);color:var(--ink-2)}
.aplus-daynight figcaption svg{stroke:var(--accent2);fill:none;stroke-width:1.75}

.spec-table,.compare-table{width:100%;border-collapse:collapse;font-size:var(--fs-0)}
.spec-table th,.spec-table td{padding:var(--sp-3) var(--sp-4);text-align:start;
  border-block-end:1px solid var(--border)}
.spec-table th{width:40%;font-weight:var(--fw-medium);color:var(--ink-2)}
.spec-table td{font-variant-numeric:tabular-nums}
.spec-table tr:nth-child(odd){background:var(--surface-2)}

.aplus-compare__scroll{overflow-x:auto}
.compare-table th,.compare-table td{padding:var(--sp-3) var(--sp-4);text-align:center;
  border:1px solid var(--border);min-width:140px}
.compare-table th[scope=row]{text-align:start;position:sticky;left:0;
  background:var(--surface);font-weight:var(--fw-medium);color:var(--ink-2)}
.compare-table .is-this{background:var(--amber-50)}
.compare-table__chip{display:block;margin-block-start:4px;font-size:var(--fs--2);
  font-weight:var(--fw-semibold);color:var(--accent-text)}

/* ---------- tabs & reviews ---------- */
.woocommerce-tabs{margin-block-start:var(--sp-16)}
.woocommerce-tabs ul.tabs{display:flex;gap:var(--sp-4);list-style:none;margin:0 0 var(--sp-6);
  padding:0;border-block-end:1px solid var(--border);overflow-x:auto}
.woocommerce-tabs ul.tabs li{flex:0 0 auto}
.woocommerce-tabs ul.tabs a{display:block;padding:var(--sp-3) var(--sp-1);text-decoration:none;
  font-weight:var(--fw-medium);color:var(--ink-2);border-block-end:2px solid transparent}
.woocommerce-tabs ul.tabs li.active a{color:var(--ink);font-weight:var(--fw-semibold);
  border-block-end-color:var(--amber-400)}
.woocommerce-Tabs-panel h2{font-size:var(--fs-2);margin-block-end:var(--sp-4)}

.related h2,.upsells h2{margin-block:var(--sp-16) var(--sp-8)}


/* ---------- A+ gallery strip ---------- */
.aplus-strip ul{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(150px,1fr);
  gap:var(--sp-3);list-style:none;margin:0;padding:0 0 var(--sp-2);
  overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:thin;
  overscroll-behavior-inline:contain}
.aplus-strip li{scroll-snap-align:start}
@media (min-width:768px){
  .aplus-strip ul{grid-auto-flow:row;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));overflow:visible}
}

/* The banner image is a real product photo on most products, so it must not
   be cropped to a letterbox on phones where the subject is centred. */
@media (max-width:767px){
  .aplus-banner__media{--ratio:4 / 3 !important}
}


/* Stripe's Express Checkout renders grey skeleton placeholders and replaces
   them once Apple Pay / Google Pay report as available. When they are not —
   for instance while the Apple Pay domain registration still points at the
   old domain — the skeletons never resolve and sit under the Add to cart
   button as two dead grey bars. `:empty` hides them only while they hold
   nothing, so the moment Stripe injects a real button they come back. */
/* Each express-checkout row reserves --wc-stripe-express-btn-h (50px) whether
   or not a button ever arrives, so two empty rows left a ~120px hole under
   Add to cart. Hide the ROW while its button container is still empty —
   Stripe injecting a button un-hides it automatically, so a slow load costs
   no layout shift and a working Apple Pay button is never suppressed. */
/* `:empty` was the wrong test: Woo prints a newline inside the Apple Pay
   button div, and whitespace is content, so the rule never matched and the
   skeleton kept its 50px. Test for a CHILD ELEMENT instead — Stripe injects
   an iframe or a button, never a bare text node. */
.wc-stripe-express-skeleton:empty{display:none}
li.payment_method_stripe_applepay:not(:has(.wc-stripe_applepay-product-button > *)),
li.payment_method_stripe_googlepay:not(:has(.wc-stripe_googlepay-product-button > *)){display:none}

/* With every row hidden the container is a zero-height grid item that still
   costs a gap under Buy it now. Hide it too, until one of the buttons fills.
   Stripe injecting a button reverses both rules on its own, so a slow express
   load costs nothing and a working Apple Pay button is never suppressed. */
.wc-stripe-product-checkout-container:not(:has(.wc-stripe_applepay-product-button > *)):not(:has(.wc-stripe_googlepay-product-button > *)){display:none}
.wc_stripe_product_payment_methods{margin:0;padding:0}
.wc-stripe-product-checkout-container{margin:0}
.wc-stripe-clear{display:none}

/* One tab left (the Description tab is removed once its content has been
   laid out as A+ content), and Woo prints the tab label AND an identical <h2>
   inside the panel. Two identical headings, 40px apart. */
.woocommerce-tabs .tabs:has(li:only-child){display:none}


/* ---------- coupon strip (product summary) ---------- */
/* The old strip let the Copy button wrap to a second line under the code,
   which read as a broken layout. It is now a grid: icon, text, action — the
   action holds its own column and the text wraps inside its own. */
.summary .coupon{display:grid;grid-template-columns:auto 1fr auto;align-items:center;
  gap:var(--sp-2) var(--sp-3);padding:var(--sp-3) var(--sp-4);margin:0;
  border:1.5px dashed var(--amber-400);background:var(--amber-50);
  border-radius:var(--r-md)}
.summary .coupon__text{font-size:var(--fs--1);line-height:1.45;min-width:0}
.summary .coupon__code{display:inline-block;margin-inline-start:4px}
.summary .coupon__copy{grid-column:3;min-height:36px;padding:0 var(--sp-4);white-space:nowrap}
@media (max-width:399px){
  .summary .coupon{grid-template-columns:auto 1fr}
  .summary .coupon__copy{grid-column:2;justify-self:start}
}

/* ---------- trust + meta ---------- */
.trust-row{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp-2) var(--sp-4);
  list-style:none;margin:0;padding:var(--sp-4) 0 0;border-block-start:1px solid var(--border)}
.trust-row li{display:flex;align-items:center;gap:var(--sp-2);
  font-size:var(--fs--1);color:var(--ink-2);min-width:0}
.trust-row svg{flex:0 0 auto;stroke:var(--accent2);fill:none;stroke-width:1.75}
.product_meta{font-size:var(--fs--1);color:var(--ink-3);display:flex;flex-wrap:wrap;
  gap:var(--sp-1) var(--sp-4)}
.product_meta>span{display:inline-flex;gap:6px}
.product_meta a{color:var(--ink-2)}


/* ---------- accepted payment methods ---------- */
.pay-icons{display:flex;align-items:center;gap:var(--sp-3);flex-wrap:wrap;
  padding-block-start:var(--sp-3)}
.pay-icons__label{font-size:var(--fs--2);color:var(--ink-3);text-transform:uppercase;
  letter-spacing:var(--ls-caps);font-weight:var(--fw-semibold)}
.pay-icons ul{display:flex;gap:6px;list-style:none;margin:0;padding:0;flex-wrap:wrap}
.pay-icons svg{display:block;border-radius:3px;box-shadow:0 0 0 1px rgb(14 35 64/.10)}


/* ---------- spec grid ---------- */
/* Uniform cells with the label above the value. Every cell has exactly the
   same shape, so the block reads as a spec sheet rather than six cards of
   different heights. */
/* `grid-auto-rows:1fr` makes EVERY row the height of the tallest cell in the
   whole grid, not just the tallest in its own row. Without it a spec whose
   value wraps to three lines makes its row 5px taller than its neighbours,
   and a table of near-equal rows reads as a misaligned one — which is exactly
   the unevenness this block was rebuilt to remove. */
.specgrid{display:grid;gap:1px;list-style:none;margin:0;padding:0;
  grid-template-columns:repeat(2,minmax(0,1fr));grid-auto-rows:1fr;
  background:var(--border);border:1px solid var(--border);border-radius:var(--r-lg);
  overflow:hidden}
/* The container's background IS the 1px rule between cells, so any cell the
   items do not fill shows as a grey stub at the end of the last row. The last
   item stretches across whatever is left, which depends on both the column
   count and how many items there are — hence one rule per remainder, reset at
   each breakpoint so a wider grid never inherits a narrower grid's span. */
.specgrid > li:last-child:nth-child(odd){grid-column:span 2}
@media (min-width:768px){
  .specgrid > li:last-child{grid-column:auto}
  .specgrid > li:last-child:nth-child(3n+1){grid-column:span 3}
  .specgrid > li:last-child:nth-child(3n+2){grid-column:span 2}
}
@media (min-width:1024px){
  .specgrid > li:last-child{grid-column:auto}
  .specgrid > li:last-child:nth-child(4n+1){grid-column:span 4}
  .specgrid > li:last-child:nth-child(4n+2){grid-column:span 3}
  .specgrid > li:last-child:nth-child(4n+3){grid-column:span 2}
}
@media (min-width:768px){ .specgrid{grid-template-columns:repeat(3,minmax(0,1fr))} }
@media (min-width:1024px){ .specgrid{grid-template-columns:repeat(4,minmax(0,1fr))} }
.specgrid li{display:flex;flex-direction:column;gap:4px;justify-content:center;
  background:var(--surface);padding:var(--sp-4) var(--sp-4);min-height:92px}
.specgrid__k{font-size:var(--fs--2);text-transform:uppercase;letter-spacing:var(--ls-caps);
  font-weight:var(--fw-semibold);color:var(--ink-3)}
.specgrid__v{font-size:var(--fs-0);font-weight:var(--fw-semibold);color:var(--ink);
  line-height:1.3;font-variant-numeric:tabular-nums}

/* Benefit cards get a card treatment so unequal text still looks deliberate:
   equal-height cells with the icon and title pinned to the top. */
.aplus-benefits__grid li{display:flex;flex-direction:column;align-items:flex-start;
  gap:var(--sp-2);padding:var(--sp-5) var(--sp-4);height:100%;
  border:1px solid var(--border);border-radius:var(--r-lg);background:var(--surface)}
.aplus-benefits__grid{align-items:stretch}
.aplus-benefits__icon{margin-block-end:0}
